mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 23:44:11 +01:00
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:
21
node_modules/gridstack/LICENSE
generated
vendored
Normal file
21
node_modules/gridstack/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2025 Alain Dumesny. v0.4.0 and older (c) 2014-2018 Pavel Reznikov, Dylan Weiss
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
565
node_modules/gridstack/README.md
generated
vendored
Normal file
565
node_modules/gridstack/README.md
generated
vendored
Normal file
@@ -0,0 +1,565 @@
|
||||
# gridstack.js
|
||||
|
||||
[](https://www.npmjs.com/package/gridstack)
|
||||
[](https://coveralls.io/github/gridstack/gridstack.js?branch=develop)
|
||||
[](https://www.npmjs.com/package/gridstack)
|
||||
|
||||
Mobile-friendly modern Typescript library for dashboard layout and creation. Making a drag-and-drop, multi-column responsive dashboard has never been easier. Has multiple bindings and works great with [Angular](https://angular.io/) (included), [React](https://reactjs.org/), [Vue](https://vuejs.org/), [Knockout.js](http://knockoutjs.com), [Ember](https://www.emberjs.com/) and others (see [frameworks](#specific-frameworks) section).
|
||||
|
||||
Inspired by no-longer maintained gridster, built with love.
|
||||
|
||||
Check http://gridstackjs.com and [these demos](http://gridstackjs.com/demo/).
|
||||
|
||||
If you find this lib useful, please donate [PayPal](https://www.paypal.me/alaind831) (use **“send to a friend”** to avoid 3% fee) or [Venmo](https://www.venmo.com/adumesny) (adumesny) and help support it!
|
||||
|
||||
[](https://www.paypal.me/alaind831)
|
||||
[](https://www.venmo.com/adumesny)
|
||||
|
||||
Join us on Slack: [https://gridstackjs.slack.com](https://join.slack.com/t/gridstackjs/shared_invite/zt-3978nsff6-HDNE_N45DydP36NBSV9JFQ)
|
||||
|
||||
<!-- [](https://gridstackjs.slack.com) -->
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)*
|
||||
|
||||
- [Demo and API Documentation](#demo-and-api-documentation)
|
||||
- [Usage](#usage)
|
||||
- [Install](#install)
|
||||
- [Include](#include)
|
||||
- [Basic usage](#basic-usage)
|
||||
- [Requirements](#requirements)
|
||||
- [Specific frameworks](#specific-frameworks)
|
||||
- [Extend Library](#extend-library)
|
||||
- [Extend Engine](#extend-engine)
|
||||
- [Change grid columns](#change-grid-columns)
|
||||
- [Custom columns CSS (OLD, not needed with v12+)](#custom-columns-css-old-not-needed-with-v12)
|
||||
- [Override resizable/draggable options](#override-resizabledraggable-options)
|
||||
- [Touch devices support](#touch-devices-support)
|
||||
- [Migrating](#migrating)
|
||||
- [Migrating to v0.6](#migrating-to-v06)
|
||||
- [Migrating to v1](#migrating-to-v1)
|
||||
- [Migrating to v2](#migrating-to-v2)
|
||||
- [Migrating to v3](#migrating-to-v3)
|
||||
- [Migrating to v4](#migrating-to-v4)
|
||||
- [Migrating to v5](#migrating-to-v5)
|
||||
- [Migrating to v6](#migrating-to-v6)
|
||||
- [Migrating to v7](#migrating-to-v7)
|
||||
- [Migrating to v8](#migrating-to-v8)
|
||||
- [Migrating to v9](#migrating-to-v9)
|
||||
- [Migrating to v10](#migrating-to-v10)
|
||||
- [Migrating to v11](#migrating-to-v11)
|
||||
- [Migrating to v12](#migrating-to-v12)
|
||||
- [jQuery Application](#jquery-application)
|
||||
- [Changes](#changes)
|
||||
- [Usage Trend](#usage-trend)
|
||||
- [The Team](#the-team)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
|
||||
# Demo and API Documentation
|
||||
|
||||
Please visit http://gridstackjs.com and [these demos](http://gridstackjs.com/demo/), and complete [API documentation](https://gridstack.github.io/gridstack.js/doc/html/) ([markdown](https://github.com/gridstack/gridstack.js/tree/master/doc/API.md))
|
||||
|
||||
# Usage
|
||||
|
||||
## Install
|
||||
[](https://www.npmjs.com/package/gridstack)
|
||||
|
||||
```js
|
||||
yarn add gridstack
|
||||
// or
|
||||
npm install --save gridstack
|
||||
```
|
||||
|
||||
## Include
|
||||
|
||||
ES6 or Typescript
|
||||
|
||||
```js
|
||||
import 'gridstack/dist/gridstack.min.css';
|
||||
import { GridStack } from 'gridstack';
|
||||
```
|
||||
|
||||
Alternatively (single combined file, notice the -all.js) in html
|
||||
|
||||
```html
|
||||
<link href="node_modules/gridstack/dist/gridstack.min.css" rel="stylesheet"/>
|
||||
<script src="node_modules/gridstack/dist/gridstack-all.js"></script>
|
||||
```
|
||||
|
||||
**Note**: IE support was dropped in v2, but restored in v4.4 by an external contributor (I have no interest in testing+supporting obsolete browser so this likely will break again in the future) and DROPPED again in v12 (css variable needed).
|
||||
You can use the es5 files and polyfill (larger) for older browser instead. For example:
|
||||
```html
|
||||
<link href="node_modules/gridstack/dist/gridstack.min.css" rel="stylesheet"/>
|
||||
<script src="node_modules/gridstack/dist/es5/gridstack-poly.js"></script>
|
||||
<script src="node_modules/gridstack/dist/es5/gridstack-all.js"></script>
|
||||
```
|
||||
|
||||
|
||||
## Basic usage
|
||||
|
||||
creating items dynamically...
|
||||
|
||||
```js
|
||||
// ...in your HTML
|
||||
<div class="grid-stack"></div>
|
||||
|
||||
// ...in your script
|
||||
var grid = GridStack.init();
|
||||
grid.addWidget({w: 2, content: 'item 1'});
|
||||
```
|
||||
|
||||
... or creating from list
|
||||
|
||||
```js
|
||||
// using serialize data instead of .addWidget()
|
||||
const serializedData = [
|
||||
{x: 0, y: 0, w: 2, h: 2},
|
||||
{x: 2, y: 3, w: 3, content: 'item 2'},
|
||||
{x: 1, y: 3}
|
||||
];
|
||||
|
||||
grid.load(serializedData);
|
||||
```
|
||||
|
||||
... or DOM created items
|
||||
|
||||
```js
|
||||
// ...in your HTML
|
||||
<div class="grid-stack">
|
||||
<div class="grid-stack-item">
|
||||
<div class="grid-stack-item-content">Item 1</div>
|
||||
</div>
|
||||
<div class="grid-stack-item" gs-w="2">
|
||||
<div class="grid-stack-item-content">Item 2 wider</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
// ...in your script
|
||||
GridStack.init();
|
||||
```
|
||||
|
||||
...or see list of all [API and options](https://github.com/gridstack/gridstack.js/tree/master/doc) available.
|
||||
|
||||
see [stackblitz sample](https://stackblitz.com/edit/gridstack-demo) as running example too.
|
||||
|
||||
## Requirements
|
||||
|
||||
GridStack no longer requires external dependencies as of v1 (lodash was removed in v0.5 and jquery API in v1). v3 is a complete HTML5 re-write removing need for jquery. v6 is native mouse and touch event for mobile support, and no longer have jquery-ui version. All you need to include now is `gridstack-all.js` and `gridstack.min.css` (layouts are done using CSS column based %).
|
||||
|
||||
## Specific frameworks
|
||||
|
||||
search for ['gridstack' under NPM](https://www.npmjs.com/search?q=gridstack&ranking=popularity) for latest, more to come...
|
||||
|
||||
- **Angular**: we ship out of the box an Angular wrapper - see <a href="https://github.com/gridstack/gridstack.js/tree/master/angular" target="_blank">Angular Component</a>.
|
||||
- **Angular9**: [lb-gridstack](https://github.com/pfms84/lb-gridstack) Note: very old v0.3 gridstack instance so recommend for **concept ONLY if you wish to use directive instead**. Code has **not been vented** at as I use components.
|
||||
- **AngularJS**: [gridstack-angular](https://github.com/kdietrich/gridstack-angular)
|
||||
- **Ember**: [ember-gridstack](https://github.com/yahoo/ember-gridstack)
|
||||
- **knockout**: see [demo](https://gridstackjs.com/demo/knockout.html) using component, but check [custom bindings ticket](https://github.com/gridstack/gridstack.js/issues/465) which is likely better approach.
|
||||
- **Rails**: [gridstack-js-rails](https://github.com/randoum/gridstack-js-rails)
|
||||
- **React**: work in progress to have wrapper code: see <a href="https://github.com/gridstack/gridstack.js/tree/master/react" target="_blank">React Component</a>. But also see [demo](https://gridstackjs.com/demo/react.html) with [src](https://github.com/gridstack/gridstack.js/tree/master/demo/react.html), or [react-gridstack-example](https://github.com/Inder2108/react-gridstack-example/tree/master/src/App.js), or read on what [hooks to use](https://github.com/gridstack/gridstack.js/issues/735#issuecomment-329888796)
|
||||
- **Vue**: see [demo](https://gridstackjs.com/demo/vue3js.html) with [v3 src](https://github.com/gridstack/gridstack.js/tree/master/demo/vue3js.html) or [v2 src](https://github.com/gridstack/gridstack.js/tree/master/demo/vue2js.html)
|
||||
- **Aurelia**: [aurelia-gridstack](https://github.com/aurelia-ui-toolkits/aurelia-gridstack), see [demo](https://aurelia-ui-toolkits.github.io/aurelia-gridstack/)
|
||||
|
||||
## Extend Library
|
||||
|
||||
You can easily extend or patch gridstack with code like this:
|
||||
|
||||
```js
|
||||
// extend gridstack with our own custom method
|
||||
GridStack.prototype.printCount = function() {
|
||||
console.log('grid has ' + this.engine.nodes.length + ' items');
|
||||
};
|
||||
|
||||
let grid = GridStack.init();
|
||||
|
||||
// you can now call
|
||||
grid.printCount();
|
||||
```
|
||||
|
||||
## Extend Engine
|
||||
|
||||
You can now (5.1+) easily create your own layout engine to further customize your usage. Here is a typescript example
|
||||
|
||||
```ts
|
||||
import { GridStack, GridStackEngine, GridStackNode, GridStackMoveOpts } from 'gridstack';
|
||||
|
||||
class CustomEngine extends GridStackEngine {
|
||||
|
||||
/** refined this to move the node to the given new location */
|
||||
public override moveNode(node: GridStackNode, o: GridStackMoveOpts): boolean {
|
||||
// keep the same original X and Width and let base do it all...
|
||||
o.x = node.x;
|
||||
o.w = node.w;
|
||||
return super.moveNode(node, o);
|
||||
}
|
||||
}
|
||||
|
||||
GridStack.registerEngine(CustomEngine); // globally set our custom class
|
||||
```
|
||||
|
||||
## Change grid columns
|
||||
|
||||
GridStack makes it very easy if you need [1-12] columns out of the box (default is 12), but you always need **2 things** if you need to customize this:
|
||||
|
||||
1) Change the `column` grid option when creating a grid to your number N
|
||||
```js
|
||||
GridStack.init( {column: N} );
|
||||
```
|
||||
|
||||
NOTE: step 2 is OLD and not needed with v12+ which uses CSS variables instead of classes
|
||||
|
||||
2) also include `gridstack-extra.css` if **N < 12** (else custom CSS - see next). Without these, things will not render/work correctly.
|
||||
```html
|
||||
<link href="node_modules/gridstack/dist/gridstack.min.css" rel="stylesheet"/>
|
||||
<link href="node_modules/gridstack/dist/gridstack-extra.min.css" rel="stylesheet"/>
|
||||
|
||||
<div class="grid-stack">...</div>
|
||||
```
|
||||
|
||||
Note: class `.grid-stack-N` will automatically be added and we include `gridstack-extra.min.css` which defines CSS for grids with custom [2-11] columns. Anything more and you'll need to generate the SASS/CSS yourself (see next).
|
||||
|
||||
See example: [2 grids demo](http://gridstack.github.io/gridstack.js/demo/two.html) with 6 columns
|
||||
|
||||
## Custom columns CSS (OLD, not needed with v12+)
|
||||
|
||||
NOTE: step is OLD and not needed with v12+ which uses CSS variables instead of classes
|
||||
|
||||
If you need > 12 columns or want to generate the CSS manually you will need to generate CSS rules for `.grid-stack-item[gs-w="X"]` and `.grid-stack-item[gs-x="X"]`.
|
||||
|
||||
For instance for 4-column grid you need CSS to be:
|
||||
|
||||
```css
|
||||
.gs-4 > .grid-stack-item[gs-x="1"] { left: 25% }
|
||||
.gs-4 > .grid-stack-item[gs-x="2"] { left: 50% }
|
||||
.gs-4 > .grid-stack-item[gs-x="3"] { left: 75% }
|
||||
|
||||
.gs-4 > .grid-stack-item { width: 25% }
|
||||
.gs-4 > .grid-stack-item[gs-w="2"] { width: 50% }
|
||||
.gs-4 > .grid-stack-item[gs-w="3"] { width: 75% }
|
||||
.gs-4 > .grid-stack-item[gs-w="4"] { width: 100% }
|
||||
```
|
||||
|
||||
Better yet, here is a SCSS code snippet, you can use sites like [sassmeister.com](https://www.sassmeister.com/) to generate the CSS for you instead:
|
||||
|
||||
```scss
|
||||
$columns: 20;
|
||||
@function fixed($float) {
|
||||
@return round($float * 1000) / 1000; // total 2+3 digits being %
|
||||
}
|
||||
.gs-#{$columns} > .grid-stack-item {
|
||||
|
||||
width: fixed(100% / $columns);
|
||||
|
||||
@for $i from 1 through $columns - 1 {
|
||||
&[gs-x='#{$i}'] { left: fixed((100% / $columns) * $i); }
|
||||
&[gs-w='#{$i+1}'] { width: fixed((100% / $columns) * ($i+1)); }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
you can also use the SCSS [src/gridstack-extra.scss](https://github.com/gridstack/gridstack.js/tree/master/src/gridstack-extra.scss) included in NPM package and modify to add more columns.
|
||||
|
||||
Sample gulp command for 30 columns:
|
||||
```js
|
||||
gulp.src('node_modules/gridstack/dist/src/gridstack-extra.scss')
|
||||
.pipe(replace('$start: 2 !default;','$start: 30;'))
|
||||
.pipe(replace('$end: 11 !default;','$end: 30;'))
|
||||
.pipe(sass({outputStyle: 'compressed'}))
|
||||
.pipe(rename({extname: '.min.css'}))
|
||||
.pipe(gulp.dest('dist/css'))
|
||||
```
|
||||
|
||||
## Override resizable/draggable options
|
||||
|
||||
You can override default `resizable`/`draggable` options. For instance to enable other then bottom right resizing handle
|
||||
you can init gridstack like:
|
||||
|
||||
```js
|
||||
GridStack.init({
|
||||
resizable: {
|
||||
handles: 'e,se,s,sw,w'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Touch devices support
|
||||
|
||||
gridstack v6+ now support mobile out of the box, with the addition of native touch event (along with mouse event) for drag&drop and resize.
|
||||
Older versions (3.2+) required the jq version with added touch punch, but doesn't work well with nested grids.
|
||||
|
||||
This option is now the default:
|
||||
|
||||
```js
|
||||
let options = {
|
||||
alwaysShowResizeHandle: 'mobile' // true if we're on mobile devices
|
||||
};
|
||||
GridStack.init(options);
|
||||
```
|
||||
|
||||
See [example](http://gridstack.github.io/gridstack.js/demo/mobile.html).
|
||||
|
||||
# Migrating
|
||||
## Migrating to v0.6
|
||||
|
||||
starting in 0.6.x `change` event are no longer sent (for pretty much most nodes!) when an item is just added/deleted unless it also changes other nodes (was incorrect and causing inefficiencies). You may need to track `added|removed` [events](https://github.com/gridstack/gridstack.js/tree/master/doc#events) if you didn't and relied on the old broken behavior.
|
||||
|
||||
## Migrating to v1
|
||||
|
||||
v1.0.0 removed Jquery from the API and external dependencies, which will require some code changes. Here is a list of the changes:
|
||||
|
||||
0. see previous step if not on v0.6 already
|
||||
|
||||
1. your code only needs to `import GridStack from 'gridstack'` or include `gridstack.all.js` and `gristack.css` (don't include other JS) and is recommended you do that as internal dependencies will change over time. If you are jquery based, see [jquery app](#jquery-application) section.
|
||||
|
||||
2. code change:
|
||||
|
||||
**OLD** initializing code + adding a widget + adding an event:
|
||||
```js
|
||||
// initialization returned Jquery element, requiring second call to get GridStack var
|
||||
var grid = $('.grid-stack').gridstack(opts?).data('gridstack');
|
||||
|
||||
// returned Jquery element
|
||||
grid.addWidget($('<div><div class="grid-stack-item-content"> test </div></div>'), undefined, undefined, 2, undefined, true);
|
||||
|
||||
// jquery event handler
|
||||
$('.grid-stack').on('added', function(e, items) {/* items contains info */});
|
||||
|
||||
// grid access after init
|
||||
var grid = $('.grid-stack').data('gridstack');
|
||||
```
|
||||
**NEW**
|
||||
```js
|
||||
// element identifier defaults to '.grid-stack', returns the grid
|
||||
// Note: for Typescript use window.GridStack.init() until next native 2.x TS version
|
||||
var grid = GridStack.init(opts?, element?);
|
||||
|
||||
// returns DOM element
|
||||
grid.addWidget('<div><div class="grid-stack-item-content"> test </div></div>', {width: 2});
|
||||
// Note: in 3.x it's ever simpler
|
||||
// grid.addWidget({w:2, content: 'test'})
|
||||
|
||||
// event handler
|
||||
grid.on('added', function(e, items) {/* items contains info */});
|
||||
|
||||
// grid access after init
|
||||
var grid = el.gridstack; // where el = document.querySelector('.grid-stack') or other ways...
|
||||
```
|
||||
Other rename changes
|
||||
|
||||
```js
|
||||
`GridStackUI` --> `GridStack`
|
||||
`GridStackUI.GridStackEngine` --> `GridStack.Engine`
|
||||
`grid.container` (jquery grid wrapper) --> `grid.el` // (grid DOM element)
|
||||
`grid.grid` (GridStackEngine) --> `grid.engine`
|
||||
`grid.setColumn(N)` --> `grid.column(N)` and `grid.column()` // to get value, old API still supported though
|
||||
```
|
||||
|
||||
Recommend looking at the [many samples](./demo) for more code examples.
|
||||
|
||||
## Migrating to v2
|
||||
|
||||
make sure to read v1 migration first!
|
||||
|
||||
v2 is a Typescript rewrite of 1.x, removing all jquery events, using classes and overall code cleanup to support ES6 modules. Your code might need to change from 1.x
|
||||
|
||||
1. In general methods that used no args (getter) vs setter can't be used in TS when the arguments differ (set/get are also not function calls so API would have changed). Instead we decided to have <b>all set methods return</b> `GridStack` to they can be chain-able (ex: `grid.float(true).cellHeight(10).column(6)`). Also legacy methods that used to take many parameters will now take a single object (typically `GridStackOptions` or `GridStackWidget`).
|
||||
|
||||
```js
|
||||
`addWidget(el, x, y, width, height)` --> `addWidget(el, {with: 2})`
|
||||
// Note: in 2.1.x you can now just do addWidget({with: 2, content: "text"})
|
||||
`float()` --> `getFloat()` // to get value
|
||||
`cellHeight()` --> `getCellHeight()` // to get value
|
||||
`verticalMargin` --> `margin` // grid options and API that applies to all 4 sides.
|
||||
`verticalMargin()` --> `getMargin()` // to get value
|
||||
```
|
||||
|
||||
2. event signatures are generic and not jquery-ui dependent anymore. `gsresizestop` has been removed as `resizestop|dragstop` are now called **after** the DOM attributes have been updated.
|
||||
|
||||
3. `oneColumnMode` would trigger when `window.width` < 768px by default. We now check for grid width instead (more correct and supports nesting). You might need to adjust grid `oneColumnSize` or `disableOneColumnMode`.
|
||||
|
||||
**Note:** 2.x no longer support legacy IE11 and older due to using more compact ES6 output and typecsript native code. You will need to stay at 1.x
|
||||
|
||||
## Migrating to v3
|
||||
|
||||
make sure to read v2 migration first!
|
||||
|
||||
v3 has a new HTML5 drag&drop plugging (63k total, all native code), while still allowing you to use the legacy jquery-ui version instead (188k), or a new static grid version (34k, no user drag&drop but full API support). You will need to decide which version to use as `gridstack.all.js` no longer exist (same is now `gridstack-jq.js`) - see [include info](#include).
|
||||
|
||||
**NOTE**: HTML5 version is almost on parity with the old jquery-ui based drag&drop. the `containment` (prevent a child from being dragged outside it's parent) and `revert` (not clear what it is for yet) are not yet implemented in initial release of v3.0.0.<br>
|
||||
Also mobile devices don't support h5 `drag` events (will need to handle `touch`) whereas v3.2 jq version now now supports out of the box (see [v3.2 release](https://github.com/gridstack/gridstack.js/releases/tag/v3.2.0))
|
||||
|
||||
Breaking changes:
|
||||
|
||||
1. include (as mentioned) need to change
|
||||
|
||||
2. `GridStack.update(el, opt)` now takes single `GridStackWidget` options instead of only supporting (x,y,w,h) BUT legacy call in JS will continue working the same for now. That method is a complete re-write and does the right constrain and updates now for all the available params.
|
||||
|
||||
3. `locked()`, `move()`, `resize()`, `minWidth()`, `minHeight()`, `maxWidth()`, `maxHeight()` methods are hidden from Typescript (JS can still call for now) as they are just 1 liner wrapper around `update(el, opt)` anyway and will go away soon. (ex: `move(el, x, y)` => `update(el, {x, y})`)
|
||||
|
||||
4. item attribute like `data-gs-min-width` is now `gs-min-w`. We removed 'data-' from all attributes, and shorten 'width|height' to just 'w|h' to require less typing and more efficient (2k saved in .js alone!).
|
||||
|
||||
5. `GridStackWidget` used in most API `width|height|minWidth|minHeight|maxWidth|maxHeight` are now shorter `w|h|minW|minH|maxW|maxH` as well
|
||||
|
||||
## Migrating to v4
|
||||
|
||||
make sure to read v3 migration first!
|
||||
|
||||
v4 is a complete re-write of the collision and drag in/out heuristics to fix some very long standing request & bugs. It also greatly improved usability. Read the release notes for more detail.
|
||||
|
||||
**Unlikely** Breaking Changes (internal usage):
|
||||
|
||||
1. `removeTimeout` was removed (feedback over trash will be immediate - actual removal still on mouse up)
|
||||
|
||||
2. the following `GridStackEngine` methods changed (used internally, doesn't affect `GridStack` public API)
|
||||
|
||||
```js
|
||||
// moved to 3 methods with new option params to support new code and pixel coverage check
|
||||
`collision()` -> `collide(), collideAll(), collideCoverage()`
|
||||
`moveNodeCheck(node, x, y, w, h)` -> `moveNodeCheck(node, opt: GridStackMoveOpts)`
|
||||
`isNodeChangedPosition(node, x, y, w, h)` -> `changedPosConstrain(node, opt: GridStackMoveOpts)`
|
||||
`moveNode(node, x, y, w, h, noPack)` -> `moveNode(node, opt: GridStackMoveOpts)`
|
||||
```
|
||||
|
||||
3. removed old obsolete (v0.6-v1 methods/attrs) `getGridHeight()`, `verticalMargin`, `data-gs-current-height`,
|
||||
`locked()`, `maxWidth()`, `minWidth()`, `maxHeight()`, `minHeight()`, `move()`, `resize()`
|
||||
|
||||
|
||||
## Migrating to v5
|
||||
|
||||
make sure to read v4 migration first!
|
||||
|
||||
v5 does not have any breaking changes from v4, but a focus on nested grids in h5 mode:
|
||||
You can now drag in/out of parent into nested child, with new API parameters values. See the release notes.
|
||||
|
||||
## Migrating to v6
|
||||
|
||||
the API did not really change from v5, but a complete re-write of Drag&Drop to use native `mouseevent` (instead of HTML draggable=true which is buggy on Mac Safari, and doesn't work on mobile devices) and `touchevent` (mobile), and we no longer have jquery ui option (wasn't working well for nested grids, didn't want to maintain legacy lib).
|
||||
|
||||
The main difference is you only need to include gridstack.js and get D&D (desktop and mobile) out of the box for the same size as h5 version.
|
||||
|
||||
## Migrating to v7
|
||||
|
||||
New addition, no API breakage per say. See release notes about creating sub-grids on the fly.
|
||||
|
||||
## Migrating to v8
|
||||
|
||||
Possible breaking change if you use nested grid JSON format, or original Angular wrapper, or relied on specific CSS paths. Also target is now ES2020 (see release notes).
|
||||
* `GridStackOptions.subGrid` -> `GridStackOptions.subGridOpts` rename. We now have `GridStackWidget.subGridOpts` vs `GridStackNode.subGrid` (was both types which is error prone)
|
||||
* `GridStackOptions.addRemoveCB` -> `GridStack.addRemoveCB` is now global instead of grid option
|
||||
* removed `GridStackOptions.dragInOptions` since `GridStack.setupDragIn()` has it replaced since 4.0
|
||||
* remove `GridStackOptions.minWidth` obsolete since 5.1, use `oneColumnSize` instead
|
||||
* CSS rules removed `.grid-stack` prefix for anything already gs based, 12 column (default) now uses `.gs-12`, extra.css is less than 1/4th it original size!, `gs-min|max_w|h` attribute no longer written (but read)
|
||||
|
||||
## Migrating to v9
|
||||
|
||||
New addition - see release notes about `sizeToContent` feature.
|
||||
Possible break:
|
||||
* `GridStack.onParentResize()` is now called `onResize()` as grid now directly track size change, no longer involving parent per say to tell us anything. Note sure why it was public.
|
||||
|
||||
## Migrating to v10
|
||||
|
||||
we now support much richer responsive behavior with `GridStackOptions.columnOpts` including any breakpoint width:column pairs, or automatic column sizing.
|
||||
|
||||
breaking change:
|
||||
* `disableOneColumnMode`, `oneColumnSize` have been removed (thought we temporary convert if you have them). use `columnOpts: { breakpoints: [{w:768, c:1}] }` for the same behavior.
|
||||
* 1 column mode switch is no longer by default (`columnOpts` is not defined) as too many new users had issues. Instead set it explicitly (see above).
|
||||
* `oneColumnModeDomSort` has been removed. Planning to support per column layouts at some future times. TBD
|
||||
|
||||
## Migrating to v11
|
||||
|
||||
* All instances of `el.innerHTML = 'some content'` have been removed for security reason as it opens up some potential for accidental XSS.
|
||||
|
||||
* Side panel drag&drop complete rewrite.
|
||||
|
||||
* new lazy loading option
|
||||
|
||||
**Breaking change:**
|
||||
|
||||
* V11 add new `GridStack.renderCB` that is called for you to create the widget content (entire GridStackWidget is passed so you can use id or some other field as logic) while GS creates the 2 needed parent divs + classes, unlike `GridStack.addRemoveCB` which doesn't create anything for you. Both can be handy for Angular/React/Vue frameworks.
|
||||
* `addWidget(w: GridStackWidget)` is now the only supported format, no more string content passing. You will need to create content yourself as shown below, OR use `GridStack.createWidgetDivs()` to create parent divs, do the innerHtml, then call `makeWidget(el)` instead.
|
||||
* if your code relies on `GridStackWidget.content` with real HTML (like a few demos) it is up to you to do this:
|
||||
```ts
|
||||
// NOTE: REAL apps would sanitize-html or DOMPurify before blinding setting innerHTML. see #2736
|
||||
GridStack.renderCB = function(el: HTMLElement, w: GridStackNode) {
|
||||
el.innerHTML = w.content;
|
||||
};
|
||||
|
||||
// now you can create widgets like this again
|
||||
let gridWidget = grid.addWidget({x, y, w, h, content: '<div>My html content</div>'});
|
||||
```
|
||||
|
||||
**Potential breaking change:**
|
||||
|
||||
* BIG overall to how sidepanel helper drag&drop is done:
|
||||
1. `clone()` helper is now passed full HTML element dragged, not an event on `grid-stack-item-content` so you can clone or set attr at the top.
|
||||
2. use any class/structure you want for side panel items (see two.html)
|
||||
3. `GridStack.setupDragIn()` now support associating a `GridStackWidget` for each sidepanel that will be used to define what to create on drop!
|
||||
4. if no `GridStackWidget` is defined, the helper will now be inserted as is, and NOT original sidepanel item.
|
||||
5. support DOM gs- attr as well as gridstacknode JSON (see two.html) alternatives.
|
||||
|
||||
## Migrating to v12
|
||||
|
||||
* column and cell height code has been re-writen to use browser CSS variables, and we no longer need a tons of custom CSS classes!
|
||||
this fixes a long standing issue where people forget to include the right CSS for non 12 columns layouts, and a big speedup in many cases (many columns, or small cellHeight values).
|
||||
|
||||
**Potential breaking change:**
|
||||
* `gridstack-extra.min.css` no longer exist, nor is custom column CSS classes needed. API/options hasn't changed.
|
||||
* (v12.1) `ES5` folder content has been removed - was for IE support, which has been dropped.
|
||||
* (v12.1) nested grid events are now sent to the main grid. You might have to adjust your workaround of this missing feature. nested.html demo has been adjusted.
|
||||
|
||||
# jQuery Application
|
||||
|
||||
This is **old and no longer apply to v6+**. You'll need to use v5.1.1 and before
|
||||
|
||||
```js
|
||||
import 'gridstack/dist/gridstack.min.css';
|
||||
import { GridStack } from 'gridstack';
|
||||
import 'gridstack/dist/jq/gridstack-dd-jqueryui';
|
||||
```
|
||||
**Note**: `jquery` & `jquery-ui` are imported by name, so you will have to specify their location in your webpack (or equivalent) config file,
|
||||
which means you can possibly bring your own version
|
||||
```js
|
||||
alias: {
|
||||
'jquery': 'gridstack/dist/jq/jquery.js',
|
||||
'jquery-ui': 'gridstack/dist/jq/jquery-ui.js',
|
||||
'jquery.ui': 'gridstack/dist/jq/jquery-ui.js',
|
||||
'jquery.ui.touch-punch': 'gridstack/dist/jq/jquery.ui.touch-punch.js',
|
||||
},
|
||||
```
|
||||
Alternatively (single combined file) in html
|
||||
|
||||
```html
|
||||
<link href="node_modules/gridstack/dist/gridstack.min.css" rel="stylesheet"/>
|
||||
<!-- HTML5 drag&drop (70k) -->
|
||||
<script src="node_modules/gridstack/dist/gridstack-h5.js"></script>
|
||||
<!-- OR jquery-ui drag&drop (195k) -->
|
||||
<script src="node_modules/gridstack/dist/gridstack-jq.js"></script>
|
||||
<!-- OR static grid (40k) -->
|
||||
<script src="node_modules/gridstack/dist/gridstack-static.js"></script>
|
||||
```
|
||||
|
||||
We have a native HTML5 drag'n'drop through the plugin system (default), but the jquery-ui version can be used instead. It will bundle `jquery` (3.5.1) + `jquery-ui` (1.13.1 minimal drag|drop|resize) + `jquery-ui-touch-punch` (1.0.8 for mobile support) in `gridstack-jq.js`.
|
||||
|
||||
**NOTE: in v4, v3**: we ES6 module import jquery & jquery-ui by name, so you need to specify location of those .js files, which means you might be able to bring your own version as well. See the include instructions.
|
||||
|
||||
**NOTE: in v1.x** IFF you want to use gridstack-jq instead and your app needs to bring your own JQ version, you should **instead** include `gridstack-poly.min.js` (optional IE support) + `gridstack.min.js` + `gridstack.jQueryUI.min.js` after you import your JQ libs. But note that there are issue with jQuery and ES6 import (see [1306](https://github.com/gridstack/gridstack.js/issues/1306)).
|
||||
|
||||
As for events, you can still use `$(".grid-stack").on(...)` for the version that uses jquery-ui for things we don't support.
|
||||
|
||||
# Changes
|
||||
|
||||
View our change log [here](https://github.com/gridstack/gridstack.js/tree/master/doc/CHANGES.md).
|
||||
|
||||
# Usage Trend
|
||||
|
||||
[Usage Trend of gridstack](https://npm-compare.com/gridstack#timeRange=THREE_YEARS)
|
||||
|
||||
<a href="https://npm-compare.com/gridstack#timeRange=THREE_YEARS" target="_blank">
|
||||
<img src="https://npm-compare.com/img/npm-trend/THREE_YEARS/gridstack.png" width="70%" alt="NPM Usage Trend of gridstack" />
|
||||
</a>
|
||||
|
||||
# The Team
|
||||
|
||||
gridstack.js is currently maintained by [Alain Dumesny](https://github.com/adumesny), before that [Dylan Weiss](https://github.com/radiolips), originally created by [Pavel Reznikov](https://github.com/troolee). We appreciate [all contributors](https://github.com/gridstack/gridstack.js/graphs/contributors) for help.
|
||||
211
node_modules/gridstack/dist/angular/README.md
generated
vendored
Normal file
211
node_modules/gridstack/dist/angular/README.md
generated
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
# Angular wrapper
|
||||
|
||||
The Angular [wrapper component](projects/lib/src/lib/gridstack.component.ts) <gridstack> is a <b>better way to use Gridstack</b>, but alternative raw [ngFor](projects/demo/src/app/ngFor.ts) or [simple](projects/demo/src/app/simple.ts) demos are also given.
|
||||
|
||||
Running version can be seen here https://stackblitz.com/edit/gridstack-angular
|
||||
|
||||
# Dynamic grid items
|
||||
|
||||
this is the recommended way if you are going to have multiple grids (alow drag&drop between) or drag from toolbar to create items, or drag to remove items, etc...
|
||||
|
||||
I.E. don't use Angular templating to create grid items as that is harder to sync when gridstack will also add/remove items.
|
||||
|
||||
MyComponent HTML
|
||||
|
||||
```html
|
||||
<gridstack [options]="gridOptions"></gridstack>
|
||||
```
|
||||
|
||||
MyComponent CSS
|
||||
|
||||
```css
|
||||
@import "gridstack/dist/gridstack.min.css";
|
||||
|
||||
.grid-stack {
|
||||
background: #fafad2;
|
||||
}
|
||||
.grid-stack-item-content {
|
||||
text-align: center;
|
||||
background-color: #18bc9c;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Standalone MyComponent Code
|
||||
|
||||
```ts
|
||||
import { GridStackOptions } from 'gridstack';
|
||||
import { GridstackComponent, GridstackItemComponent } from 'gridstack/dist/angular';
|
||||
|
||||
@Component({
|
||||
imports: [ // SKIP if doing module import instead (next)
|
||||
GridstackComponent,
|
||||
GridstackItemComponent
|
||||
]
|
||||
...
|
||||
})
|
||||
export class MyComponent {
|
||||
// sample grid options + items to load...
|
||||
public gridOptions: GridStackOptions = {
|
||||
margin: 5,
|
||||
children: [ // or call load(children) or addWidget(children[0]) with same data
|
||||
{x:0, y:0, minW:2, content:'Item 1'},
|
||||
{x:1, y:0, content:'Item 2'},
|
||||
{x:0, y:1, content:'Item 3'},
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
IF doing module import instead of standalone, you will also need this:
|
||||
|
||||
```ts
|
||||
import { GridstackModule } from 'gridstack/dist/angular';
|
||||
|
||||
@NgModule({
|
||||
imports: [GridstackModule, ...]
|
||||
...
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
```
|
||||
|
||||
# More Complete example
|
||||
|
||||
In this example (build on previous one) will use your actual custom angular components inside each grid item (instead of dummy html content) and have per component saved settings as well (using BaseWidget).
|
||||
|
||||
HTML
|
||||
|
||||
```html
|
||||
<gridstack [options]="gridOptions" (changeCB)="onChange($event)">
|
||||
<div empty-content>message when grid is empty</div>
|
||||
</gridstack>
|
||||
```
|
||||
|
||||
Code
|
||||
|
||||
```ts
|
||||
import { Component } from '@angular/core';
|
||||
import { GridStack, GridStackOptions } from 'gridstack';
|
||||
import { GridstackComponent, gsCreateNgComponents, NgGridStackWidget, nodesCB, BaseWidget } from 'gridstack/dist/angular';
|
||||
|
||||
// some custom components
|
||||
@Component({
|
||||
selector: 'app-a',
|
||||
template: 'Comp A {{text}}',
|
||||
})
|
||||
export class AComponent extends BaseWidget implements OnDestroy {
|
||||
@Input() text: string = 'foo'; // test custom input data
|
||||
public override serialize(): NgCompInputs | undefined { return this.text ? {text: this.text} : undefined; }
|
||||
ngOnDestroy() {
|
||||
console.log('Comp A destroyed'); // test to make sure cleanup happens
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-b',
|
||||
template: 'Comp B',
|
||||
})
|
||||
export class BComponent extends BaseWidget {
|
||||
}
|
||||
|
||||
// ...in your module (classic), OR your ng19 app.config provideEnvironmentInitializer call this:
|
||||
constructor() {
|
||||
// register all our dynamic components types created by the grid
|
||||
GridstackComponent.addComponentToSelectorType([AComponent, BComponent]) ;
|
||||
}
|
||||
|
||||
// now our content will use Components instead of dummy html content
|
||||
public gridOptions: NgGridStackOptions = {
|
||||
margin: 5,
|
||||
minRow: 1, // make space for empty message
|
||||
children: [ // or call load()/addWidget() with same data
|
||||
{x:0, y:0, minW:2, selector:'app-a'},
|
||||
{x:1, y:0, minW:2, selector:'app-a', input: { text: 'bar' }}, // custom input that works using BaseWidget.deserialize() Object.assign(this, w.input)
|
||||
{x:2, y:0, selector:'app-b'},
|
||||
{x:3, y:0, content:'plain html'},
|
||||
]
|
||||
}
|
||||
|
||||
// called whenever items change size/position/etc.. see other events
|
||||
public onChange(data: nodesCB) {
|
||||
console.log('change ', data.nodes.length > 1 ? data.nodes : data.nodes[0]);
|
||||
}
|
||||
```
|
||||
|
||||
# ngFor with wrapper
|
||||
|
||||
For simple case where you control the children creation (gridstack doesn't do create or re-parenting)
|
||||
|
||||
HTML
|
||||
|
||||
```html
|
||||
<gridstack [options]="gridOptions" (changeCB)="onChange($event)">
|
||||
<!-- Angular 17+ -->
|
||||
@for (n of items; track n.id) {
|
||||
<gridstack-item [options]="n">Item {{n.id}}</gridstack-item>
|
||||
}
|
||||
<!-- Angular 16 -->
|
||||
<gridstack-item *ngFor="let n of items; trackBy: identify" [options]="n"> Item {{n.id}} </gridstack-item>
|
||||
</gridstack>
|
||||
```
|
||||
|
||||
Code
|
||||
|
||||
```javascript
|
||||
import { GridStackOptions, GridStackWidget } from 'gridstack';
|
||||
import { nodesCB } from 'gridstack/dist/angular';
|
||||
|
||||
/** sample grid options and items to load... */
|
||||
public gridOptions: GridStackOptions = { margin: 5 }
|
||||
public items: GridStackWidget[] = [
|
||||
{x:0, y:0, minW:2, id:'1'}, // must have unique id used for trackBy
|
||||
{x:1, y:0, id:'2'},
|
||||
{x:0, y:1, id:'3'},
|
||||
];
|
||||
|
||||
// called whenever items change size/position/etc..
|
||||
public onChange(data: nodesCB) {
|
||||
console.log('change ', data.nodes.length > 1 ? data.nodes : data.nodes[0]);
|
||||
}
|
||||
|
||||
// ngFor unique node id to have correct match between our items used and GS
|
||||
public identify(index: number, w: GridStackWidget) {
|
||||
return w.id; // or use index if no id is set and you only modify at the end...
|
||||
}
|
||||
```
|
||||
|
||||
## Demo
|
||||
|
||||
You can see a fuller example at [app.component.ts](projects/demo/src/app/app.component.ts)
|
||||
|
||||
to build the demo, go to [angular/projects/demo](projects/demo/) and run `yarn` + `yarn start` and navigate to `http://localhost:4200/`
|
||||
|
||||
Code started shipping with v8.1.2+ in `dist/angular` for people to use directly and is an angular module! (source code under `dist/angular/src`)
|
||||
|
||||
## Caveats
|
||||
|
||||
- This wrapper needs:
|
||||
- gridstack v8+ to run as it needs the latest changes (use older version that matches GS versions)
|
||||
- <b>Angular 14+</b> for dynamic `createComponent()` API and Standalone Components (verified against 19+)
|
||||
|
||||
NOTE: if you are on Angular 13 or below: copy the wrapper code over (or patch it - see main page example) and change `createComponent()` calls to use old API instead:
|
||||
NOTE2: now that we're using standalone, you will also need to remove `standalone: true` and `imports` on each component so you will to copy those locally (or use <11.1.2 version)
|
||||
```ts
|
||||
protected resolver: ComponentFactoryResolver,
|
||||
...
|
||||
const factory = this.resolver.resolveComponentFactory(GridItemComponent);
|
||||
const gridItemRef = grid.container.createComponent(factory) as ComponentRef<GridItemComponent>;
|
||||
// ...do the same for widget selector...
|
||||
```
|
||||
|
||||
## ngFor Caveats
|
||||
|
||||
- This wrapper handles well ngFor loops, but if you're using a trackBy function (as I would recommend) and no element id change after an update,
|
||||
you must manually update the `GridstackItemComponent.option` directly - see [modifyNgFor()](./projects/demo/src/app/app.component.ts#L202) example.
|
||||
- The original client list of items is not updated to match **content** changes made by gridstack (TBD later), but adding new item or removing (as shown in demo) will update those new items. Client could use change/added/removed events to sync that list if they wish to do so.
|
||||
|
||||
Would appreciate getting help doing the same for React and Vue (2 other popular frameworks)
|
||||
|
||||
-Alain
|
||||
5
node_modules/gridstack/dist/angular/esm2020/gridstack-angular.mjs
generated
vendored
Normal file
5
node_modules/gridstack/dist/angular/esm2020/gridstack-angular.mjs
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Generated bundle index. Do not edit.
|
||||
*/
|
||||
export * from './index';
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JpZHN0YWNrLWFuZ3VsYXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9hbmd1bGFyL3Byb2plY3RzL2xpYi9zcmMvZ3JpZHN0YWNrLWFuZ3VsYXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLFNBQVMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9pbmRleCc7XG4iXX0=
|
||||
9
node_modules/gridstack/dist/angular/esm2020/index.mjs
generated
vendored
Normal file
9
node_modules/gridstack/dist/angular/esm2020/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Public API Surface of gridstack-angular
|
||||
*/
|
||||
export * from './lib/types';
|
||||
export * from './lib/base-widget';
|
||||
export * from './lib/gridstack-item.component';
|
||||
export * from './lib/gridstack.component';
|
||||
export * from './lib/gridstack.module';
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9hbmd1bGFyL3Byb2plY3RzL2xpYi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLG1CQUFtQixDQUFDO0FBQ2xDLGNBQWMsZ0NBQWdDLENBQUM7QUFDL0MsY0FBYywyQkFBMkIsQ0FBQztBQUMxQyxjQUFjLHdCQUF3QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIFB1YmxpYyBBUEkgU3VyZmFjZSBvZiBncmlkc3RhY2stYW5ndWxhclxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vbGliL3R5cGVzJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL2Jhc2Utd2lkZ2V0JztcbmV4cG9ydCAqIGZyb20gJy4vbGliL2dyaWRzdGFjay1pdGVtLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9ncmlkc3RhY2suY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vbGliL2dyaWRzdGFjay5tb2R1bGUnO1xuIl19
|
||||
90
node_modules/gridstack/dist/angular/esm2020/lib/base-widget.mjs
generated
vendored
Normal file
90
node_modules/gridstack/dist/angular/esm2020/lib/base-widget.mjs
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* gridstack-item.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
/**
|
||||
* Abstract base class that all custom widgets should extend.
|
||||
*
|
||||
* This class provides the interface needed for GridstackItemComponent to:
|
||||
* - Serialize/deserialize widget data
|
||||
* - Save/restore widget state
|
||||
* - Integrate with Angular lifecycle
|
||||
*
|
||||
* Extend this class when creating custom widgets for dynamic grids.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* selector: 'my-custom-widget',
|
||||
* template: '<div>{{data}}</div>'
|
||||
* })
|
||||
* export class MyCustomWidget extends BaseWidget {
|
||||
* @Input() data: string = '';
|
||||
*
|
||||
* serialize() {
|
||||
* return { data: this.data };
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
import { Injectable } from '@angular/core';
|
||||
import * as i0 from "@angular/core";
|
||||
/**
|
||||
* Base widget class for GridStack Angular integration.
|
||||
*/
|
||||
export class BaseWidget {
|
||||
/**
|
||||
* Override this method to return serializable data for this widget.
|
||||
*
|
||||
* Return an object with properties that map to your component's @Input() fields.
|
||||
* The selector is handled automatically, so only include component-specific data.
|
||||
*
|
||||
* @returns Object containing serializable component data
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* serialize() {
|
||||
* return {
|
||||
* title: this.title,
|
||||
* value: this.value,
|
||||
* settings: this.settings
|
||||
* };
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
serialize() { return; }
|
||||
/**
|
||||
* Override this method to handle widget restoration from saved data.
|
||||
*
|
||||
* Use this for complex initialization that goes beyond simple @Input() mapping.
|
||||
* The default implementation automatically assigns input data to component properties.
|
||||
*
|
||||
* @param w The saved widget data including input properties
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* deserialize(w: NgGridStackWidget) {
|
||||
* super.deserialize(w); // Call parent for basic setup
|
||||
*
|
||||
* // Custom initialization logic
|
||||
* if (w.input?.complexData) {
|
||||
* this.processComplexData(w.input.complexData);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
deserialize(w) {
|
||||
// save full description for meta data
|
||||
this.widgetItem = w;
|
||||
if (!w)
|
||||
return;
|
||||
if (w.input)
|
||||
Object.assign(this, w.input);
|
||||
}
|
||||
}
|
||||
BaseWidget.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseWidget, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
||||
BaseWidget.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseWidget });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseWidget, decorators: [{
|
||||
type: Injectable
|
||||
}] });
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS13aWRnZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9hbmd1bGFyL3Byb2plY3RzL2xpYi9zcmMvbGliL2Jhc2Utd2lkZ2V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQUVIOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F3Qkc7QUFFSCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDOztBQUczQzs7R0FFRztBQUVILE1BQU0sT0FBZ0IsVUFBVTtJQVE5Qjs7Ozs7Ozs7Ozs7Ozs7Ozs7O09Ba0JHO0lBQ0ksU0FBUyxLQUFnQyxPQUFPLENBQUMsQ0FBQztJQUV6RDs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQW1CRztJQUNJLFdBQVcsQ0FBQyxDQUFvQjtRQUNyQyxzQ0FBc0M7UUFDdEMsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUM7UUFDcEIsSUFBSSxDQUFDLENBQUM7WUFBRSxPQUFPO1FBRWYsSUFBSSxDQUFDLENBQUMsS0FBSztZQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM3QyxDQUFDOzt1R0F2RG1CLFVBQVU7MkdBQVYsVUFBVTsyRkFBVixVQUFVO2tCQUQvQixVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXHJcbiAqIGdyaWRzdGFjay1pdGVtLmNvbXBvbmVudC50cyAxMi4zLjNcclxuICogQ29weXJpZ2h0IChjKSAyMDIyLTIwMjQgQWxhaW4gRHVtZXNueSAtIHNlZSBHcmlkU3RhY2sgcm9vdCBsaWNlbnNlXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIEFic3RyYWN0IGJhc2UgY2xhc3MgdGhhdCBhbGwgY3VzdG9tIHdpZGdldHMgc2hvdWxkIGV4dGVuZC5cclxuICogXHJcbiAqIFRoaXMgY2xhc3MgcHJvdmlkZXMgdGhlIGludGVyZmFjZSBuZWVkZWQgZm9yIEdyaWRzdGFja0l0ZW1Db21wb25lbnQgdG86XHJcbiAqIC0gU2VyaWFsaXplL2Rlc2VyaWFsaXplIHdpZGdldCBkYXRhXHJcbiAqIC0gU2F2ZS9yZXN0b3JlIHdpZGdldCBzdGF0ZVxyXG4gKiAtIEludGVncmF0ZSB3aXRoIEFuZ3VsYXIgbGlmZWN5Y2xlXHJcbiAqIFxyXG4gKiBFeHRlbmQgdGhpcyBjbGFzcyB3aGVuIGNyZWF0aW5nIGN1c3RvbSB3aWRnZXRzIGZvciBkeW5hbWljIGdyaWRzLlxyXG4gKiBcclxuICogQGV4YW1wbGVcclxuICogYGBgdHlwZXNjcmlwdFxyXG4gKiBAQ29tcG9uZW50KHtcclxuICogICBzZWxlY3RvcjogJ215LWN1c3RvbS13aWRnZXQnLFxyXG4gKiAgIHRlbXBsYXRlOiAnPGRpdj57e2RhdGF9fTwvZGl2PidcclxuICogfSlcclxuICogZXhwb3J0IGNsYXNzIE15Q3VzdG9tV2lkZ2V0IGV4dGVuZHMgQmFzZVdpZGdldCB7XHJcbiAqICAgQElucHV0KCkgZGF0YTogc3RyaW5nID0gJyc7XHJcbiAqICAgXHJcbiAqICAgc2VyaWFsaXplKCkge1xyXG4gKiAgICAgcmV0dXJuIHsgZGF0YTogdGhpcy5kYXRhIH07XHJcbiAqICAgfVxyXG4gKiB9XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcbmltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgTmdDb21wSW5wdXRzLCBOZ0dyaWRTdGFja1dpZGdldCB9IGZyb20gJy4vdHlwZXMnO1xyXG5cclxuLyoqXHJcbiAqIEJhc2Ugd2lkZ2V0IGNsYXNzIGZvciBHcmlkU3RhY2sgQW5ndWxhciBpbnRlZ3JhdGlvbi5cclxuICovXHJcbkBJbmplY3RhYmxlKClcclxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEJhc2VXaWRnZXQge1xyXG5cclxuICAvKipcclxuICAgKiBDb21wbGV0ZSB3aWRnZXQgZGVmaW5pdGlvbiBpbmNsdWRpbmcgcG9zaXRpb24sIHNpemUsIGFuZCBBbmd1bGFyLXNwZWNpZmljIGRhdGEuXHJcbiAgICogUG9wdWxhdGVkIGF1dG9tYXRpY2FsbHkgd2hlbiB0aGUgd2lkZ2V0IGlzIGxvYWRlZCBvciBzYXZlZC5cclxuICAgKi9cclxuICBwdWJsaWMgd2lkZ2V0SXRlbT86IE5nR3JpZFN0YWNrV2lkZ2V0O1xyXG5cclxuICAvKipcclxuICAgKiBPdmVycmlkZSB0aGlzIG1ldGhvZCB0byByZXR1cm4gc2VyaWFsaXphYmxlIGRhdGEgZm9yIHRoaXMgd2lkZ2V0LlxyXG4gICAqIFxyXG4gICAqIFJldHVybiBhbiBvYmplY3Qgd2l0aCBwcm9wZXJ0aWVzIHRoYXQgbWFwIHRvIHlvdXIgY29tcG9uZW50J3MgQElucHV0KCkgZmllbGRzLlxyXG4gICAqIFRoZSBzZWxlY3RvciBpcyBoYW5kbGVkIGF1dG9tYXRpY2FsbHksIHNvIG9ubHkgaW5jbHVkZSBjb21wb25lbnQtc3BlY2lmaWMgZGF0YS5cclxuICAgKiBcclxuICAgKiBAcmV0dXJucyBPYmplY3QgY29udGFpbmluZyBzZXJpYWxpemFibGUgY29tcG9uZW50IGRhdGFcclxuICAgKiBcclxuICAgKiBAZXhhbXBsZVxyXG4gICAqIGBgYHR5cGVzY3JpcHRcclxuICAgKiBzZXJpYWxpemUoKSB7XHJcbiAgICogICByZXR1cm4ge1xyXG4gICAqICAgICB0aXRsZTogdGhpcy50aXRsZSxcclxuICAgKiAgICAgdmFsdWU6IHRoaXMudmFsdWUsXHJcbiAgICogICAgIHNldHRpbmdzOiB0aGlzLnNldHRpbmdzXHJcbiAgICogICB9O1xyXG4gICAqIH1cclxuICAgKiBgYGBcclxuICAgKi9cclxuICBwdWJsaWMgc2VyaWFsaXplKCk6IE5nQ29tcElucHV0cyB8IHVuZGVmaW5lZCAgeyByZXR1cm47IH1cclxuXHJcbiAgLyoqXHJcbiAgICogT3ZlcnJpZGUgdGhpcyBtZXRob2QgdG8gaGFuZGxlIHdpZGdldCByZXN0b3JhdGlvbiBmcm9tIHNhdmVkIGRhdGEuXHJcbiAgICogXHJcbiAgICogVXNlIHRoaXMgZm9yIGNvbXBsZXggaW5pdGlhbGl6YXRpb24gdGhhdCBnb2VzIGJleW9uZCBzaW1wbGUgQElucHV0KCkgbWFwcGluZy5cclxuICAgKiBUaGUgZGVmYXVsdCBpbXBsZW1lbnRhdGlvbiBhdXRvbWF0aWNhbGx5IGFzc2lnbnMgaW5wdXQgZGF0YSB0byBjb21wb25lbnQgcHJvcGVydGllcy5cclxuICAgKiBcclxuICAgKiBAcGFyYW0gdyBUaGUgc2F2ZWQgd2lkZ2V0IGRhdGEgaW5jbHVkaW5nIGlucHV0IHByb3BlcnRpZXNcclxuICAgKiBcclxuICAgKiBAZXhhbXBsZVxyXG4gICAqIGBgYHR5cGVzY3JpcHRcclxuICAgKiBkZXNlcmlhbGl6ZSh3OiBOZ0dyaWRTdGFja1dpZGdldCkge1xyXG4gICAqICAgc3VwZXIuZGVzZXJpYWxpemUodyk7IC8vIENhbGwgcGFyZW50IGZvciBiYXNpYyBzZXR1cFxyXG4gICAqICAgXHJcbiAgICogICAvLyBDdXN0b20gaW5pdGlhbGl6YXRpb24gbG9naWNcclxuICAgKiAgIGlmICh3LmlucHV0Py5jb21wbGV4RGF0YSkge1xyXG4gICAqICAgICB0aGlzLnByb2Nlc3NDb21wbGV4RGF0YSh3LmlucHV0LmNvbXBsZXhEYXRhKTtcclxuICAgKiAgIH1cclxuICAgKiB9XHJcbiAgICogYGBgXHJcbiAgICovXHJcbiAgcHVibGljIGRlc2VyaWFsaXplKHc6IE5nR3JpZFN0YWNrV2lkZ2V0KSAge1xyXG4gICAgLy8gc2F2ZSBmdWxsIGRlc2NyaXB0aW9uIGZvciBtZXRhIGRhdGFcclxuICAgIHRoaXMud2lkZ2V0SXRlbSA9IHc7XHJcbiAgICBpZiAoIXcpIHJldHVybjtcclxuXHJcbiAgICBpZiAody5pbnB1dCkgIE9iamVjdC5hc3NpZ24odGhpcywgdy5pbnB1dCk7XHJcbiAgfVxyXG4gfVxyXG4iXX0=
|
||||
101
node_modules/gridstack/dist/angular/esm2020/lib/gridstack-item.component.mjs
generated
vendored
Normal file
101
node_modules/gridstack/dist/angular/esm2020/lib/gridstack-item.component.mjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
414
node_modules/gridstack/dist/angular/esm2020/lib/gridstack.component.mjs
generated
vendored
Normal file
414
node_modules/gridstack/dist/angular/esm2020/lib/gridstack.component.mjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
53
node_modules/gridstack/dist/angular/esm2020/lib/gridstack.module.mjs
generated
vendored
Normal file
53
node_modules/gridstack/dist/angular/esm2020/lib/gridstack.module.mjs
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* gridstack.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
import { NgModule } from "@angular/core";
|
||||
import { GridstackItemComponent } from "./gridstack-item.component";
|
||||
import { GridstackComponent } from "./gridstack.component";
|
||||
import * as i0 from "@angular/core";
|
||||
/**
|
||||
* @deprecated Use GridstackComponent and GridstackItemComponent as standalone components instead.
|
||||
*
|
||||
* This NgModule is provided for backward compatibility but is no longer the recommended approach.
|
||||
* Import components directly in your standalone components or use the new Angular module structure.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Preferred approach - standalone components
|
||||
* @Component({
|
||||
* selector: 'my-app',
|
||||
* imports: [GridstackComponent, GridstackItemComponent],
|
||||
* template: '<gridstack></gridstack>'
|
||||
* })
|
||||
* export class AppComponent {}
|
||||
*
|
||||
* // Legacy approach (deprecated)
|
||||
* @NgModule({
|
||||
* imports: [GridstackModule]
|
||||
* })
|
||||
* export class AppModule {}
|
||||
* ```
|
||||
*/
|
||||
export class GridstackModule {
|
||||
}
|
||||
GridstackModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
||||
GridstackModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: GridstackModule, imports: [GridstackItemComponent,
|
||||
GridstackComponent], exports: [GridstackItemComponent,
|
||||
GridstackComponent] });
|
||||
GridstackModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackModule, imports: [GridstackItemComponent,
|
||||
GridstackComponent] });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackModule, decorators: [{
|
||||
type: NgModule,
|
||||
args: [{
|
||||
imports: [
|
||||
GridstackItemComponent,
|
||||
GridstackComponent,
|
||||
],
|
||||
exports: [
|
||||
GridstackItemComponent,
|
||||
GridstackComponent,
|
||||
],
|
||||
}]
|
||||
}] });
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JpZHN0YWNrLm1vZHVsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2FuZ3VsYXIvcHJvamVjdHMvbGliL3NyYy9saWIvZ3JpZHN0YWNrLm1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFFSCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRXpDLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3BFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDOztBQUUzRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQVdILE1BQU0sT0FBTyxlQUFlOzs0R0FBZixlQUFlOzZHQUFmLGVBQWUsWUFSeEIsc0JBQXNCO1FBQ3RCLGtCQUFrQixhQUdsQixzQkFBc0I7UUFDdEIsa0JBQWtCOzZHQUdULGVBQWUsWUFSeEIsc0JBQXNCO1FBQ3RCLGtCQUFrQjsyRkFPVCxlQUFlO2tCQVYzQixRQUFRO21CQUFDO29CQUNSLE9BQU8sRUFBRTt3QkFDUCxzQkFBc0I7d0JBQ3RCLGtCQUFrQjtxQkFDbkI7b0JBQ0QsT0FBTyxFQUFFO3dCQUNQLHNCQUFzQjt3QkFDdEIsa0JBQWtCO3FCQUNuQjtpQkFDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxyXG4gKiBncmlkc3RhY2suY29tcG9uZW50LnRzIDEyLjMuM1xyXG4gKiBDb3B5cmlnaHQgKGMpIDIwMjItMjAyNCBBbGFpbiBEdW1lc255IC0gc2VlIEdyaWRTdGFjayByb290IGxpY2Vuc2VcclxuICovXHJcblxyXG5pbXBvcnQgeyBOZ01vZHVsZSB9IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XHJcblxyXG5pbXBvcnQgeyBHcmlkc3RhY2tJdGVtQ29tcG9uZW50IH0gZnJvbSBcIi4vZ3JpZHN0YWNrLWl0ZW0uY29tcG9uZW50XCI7XHJcbmltcG9ydCB7IEdyaWRzdGFja0NvbXBvbmVudCB9IGZyb20gXCIuL2dyaWRzdGFjay5jb21wb25lbnRcIjtcclxuXHJcbi8qKlxyXG4gKiBAZGVwcmVjYXRlZCBVc2UgR3JpZHN0YWNrQ29tcG9uZW50IGFuZCBHcmlkc3RhY2tJdGVtQ29tcG9uZW50IGFzIHN0YW5kYWxvbmUgY29tcG9uZW50cyBpbnN0ZWFkLlxyXG4gKiBcclxuICogVGhpcyBOZ01vZHVsZSBpcyBwcm92aWRlZCBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eSBidXQgaXMgbm8gbG9uZ2VyIHRoZSByZWNvbW1lbmRlZCBhcHByb2FjaC5cclxuICogSW1wb3J0IGNvbXBvbmVudHMgZGlyZWN0bHkgaW4geW91ciBzdGFuZGFsb25lIGNvbXBvbmVudHMgb3IgdXNlIHRoZSBuZXcgQW5ndWxhciBtb2R1bGUgc3RydWN0dXJlLlxyXG4gKiBcclxuICogQGV4YW1wbGVcclxuICogYGBgdHlwZXNjcmlwdFxyXG4gKiAvLyBQcmVmZXJyZWQgYXBwcm9hY2ggLSBzdGFuZGFsb25lIGNvbXBvbmVudHNcclxuICogQENvbXBvbmVudCh7XHJcbiAqICAgc2VsZWN0b3I6ICdteS1hcHAnLFxyXG4gKiAgIGltcG9ydHM6IFtHcmlkc3RhY2tDb21wb25lbnQsIEdyaWRzdGFja0l0ZW1Db21wb25lbnRdLFxyXG4gKiAgIHRlbXBsYXRlOiAnPGdyaWRzdGFjaz48L2dyaWRzdGFjaz4nXHJcbiAqIH0pXHJcbiAqIGV4cG9ydCBjbGFzcyBBcHBDb21wb25lbnQge31cclxuICogXHJcbiAqIC8vIExlZ2FjeSBhcHByb2FjaCAoZGVwcmVjYXRlZClcclxuICogQE5nTW9kdWxlKHtcclxuICogICBpbXBvcnRzOiBbR3JpZHN0YWNrTW9kdWxlXVxyXG4gKiB9KVxyXG4gKiBleHBvcnQgY2xhc3MgQXBwTW9kdWxlIHt9XHJcbiAqIGBgYFxyXG4gKi9cclxuQE5nTW9kdWxlKHtcclxuICBpbXBvcnRzOiBbXHJcbiAgICBHcmlkc3RhY2tJdGVtQ29tcG9uZW50LFxyXG4gICAgR3JpZHN0YWNrQ29tcG9uZW50LFxyXG4gIF0sXHJcbiAgZXhwb3J0czogW1xyXG4gICAgR3JpZHN0YWNrSXRlbUNvbXBvbmVudCxcclxuICAgIEdyaWRzdGFja0NvbXBvbmVudCxcclxuICBdLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgR3JpZHN0YWNrTW9kdWxlIHt9XHJcbiJdfQ==
|
||||
6
node_modules/gridstack/dist/angular/esm2020/lib/types.mjs
generated
vendored
Normal file
6
node_modules/gridstack/dist/angular/esm2020/lib/types.mjs
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* gridstack-item.component.ts 12.3.3
|
||||
* Copyright (c) 2025 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
export {};
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9hbmd1bGFyL3Byb2plY3RzL2xpYi9zcmMvbGliL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxyXG4gKiBncmlkc3RhY2staXRlbS5jb21wb25lbnQudHMgMTIuMy4zXHJcbiAqIENvcHlyaWdodCAoYykgMjAyNSBBbGFpbiBEdW1lc255IC0gc2VlIEdyaWRTdGFjayByb290IGxpY2Vuc2VcclxuICovXHJcblxyXG5pbXBvcnQgeyBHcmlkU3RhY2tOb2RlLCBHcmlkU3RhY2tPcHRpb25zLCBHcmlkU3RhY2tXaWRnZXQgfSBmcm9tIFwiZ3JpZHN0YWNrXCI7XHJcblxyXG4vKipcclxuICogRXh0ZW5kZWQgR3JpZFN0YWNrV2lkZ2V0IGludGVyZmFjZSBmb3IgQW5ndWxhciBpbnRlZ3JhdGlvbi5cclxuICogQWRkcyBBbmd1bGFyLXNwZWNpZmljIHByb3BlcnRpZXMgZm9yIGR5bmFtaWMgY29tcG9uZW50IGNyZWF0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGludGVyZmFjZSBOZ0dyaWRTdGFja1dpZGdldCBleHRlbmRzIEdyaWRTdGFja1dpZGdldCB7XHJcbiAgLyoqIEFuZ3VsYXIgY29tcG9uZW50IHNlbGVjdG9yIGZvciBkeW5hbWljIGNyZWF0aW9uIChlLmcuLCAnbXktd2lkZ2V0JykgKi9cclxuICBzZWxlY3Rvcj86IHN0cmluZztcclxuICAvKiogU2VyaWFsaXplZCBkYXRhIGZvciBjb21wb25lbnQgQElucHV0KCkgcHJvcGVydGllcyAqL1xyXG4gIGlucHV0PzogTmdDb21wSW5wdXRzO1xyXG4gIC8qKiBDb25maWd1cmF0aW9uIGZvciBuZXN0ZWQgc3ViLWdyaWRzICovXHJcbiAgc3ViR3JpZE9wdHM/OiBOZ0dyaWRTdGFja09wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHRlbmRlZCBHcmlkU3RhY2tOb2RlIGludGVyZmFjZSBmb3IgQW5ndWxhciBpbnRlZ3JhdGlvbi5cclxuICogQWRkcyBjb21wb25lbnQgc2VsZWN0b3IgZm9yIGR5bmFtaWMgY29udGVudCBjcmVhdGlvbi5cclxuICovXHJcbmV4cG9ydCBpbnRlcmZhY2UgTmdHcmlkU3RhY2tOb2RlIGV4dGVuZHMgR3JpZFN0YWNrTm9kZSB7XHJcbiAgLyoqIEFuZ3VsYXIgY29tcG9uZW50IHNlbGVjdG9yIGZvciB0aGlzIG5vZGUncyBjb250ZW50ICovXHJcbiAgc2VsZWN0b3I/OiBzdHJpbmc7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHRlbmRlZCBHcmlkU3RhY2tPcHRpb25zIGludGVyZmFjZSBmb3IgQW5ndWxhciBpbnRlZ3JhdGlvbi5cclxuICogU3VwcG9ydHMgQW5ndWxhci1zcGVjaWZpYyB3aWRnZXQgZGVmaW5pdGlvbnMgYW5kIG5lc3RlZCBncmlkcy5cclxuICovXHJcbmV4cG9ydCBpbnRlcmZhY2UgTmdHcmlkU3RhY2tPcHRpb25zIGV4dGVuZHMgR3JpZFN0YWNrT3B0aW9ucyB7XHJcbiAgLyoqIEFycmF5IG9mIEFuZ3VsYXIgd2lkZ2V0IGRlZmluaXRpb25zIGZvciBpbml0aWFsIGdyaWQgc2V0dXAgKi9cclxuICBjaGlsZHJlbj86IE5nR3JpZFN0YWNrV2lkZ2V0W107XHJcbiAgLyoqIENvbmZpZ3VyYXRpb24gZm9yIG5lc3RlZCBzdWItZ3JpZHMgKEFuZ3VsYXItYXdhcmUpICovXHJcbiAgc3ViR3JpZE9wdHM/OiBOZ0dyaWRTdGFja09wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBUeXBlIGZvciBjb21wb25lbnQgaW5wdXQgZGF0YSBzZXJpYWxpemF0aW9uLlxyXG4gKiBNYXBzIEBJbnB1dCgpIHByb3BlcnR5IG5hbWVzIHRvIHRoZWlyIHZhbHVlcyBmb3Igd2lkZ2V0IHBlcnNpc3RlbmNlLlxyXG4gKiBcclxuICogQGV4YW1wbGVcclxuICogYGBgdHlwZXNjcmlwdFxyXG4gKiBjb25zdCBpbnB1dHM6IE5nQ29tcElucHV0cyA9IHtcclxuICogICB0aXRsZTogJ015IFdpZGdldCcsXHJcbiAqICAgdmFsdWU6IDQyLFxyXG4gKiAgIGNvbmZpZzogeyBlbmFibGVkOiB0cnVlIH1cclxuICogfTtcclxuICogYGBgXHJcbiAqL1xyXG5leHBvcnQgdHlwZSBOZ0NvbXBJbnB1dHMgPSB7W2tleTogc3RyaW5nXTogYW55fTtcclxuIl19
|
||||
647
node_modules/gridstack/dist/angular/fesm2015/gridstack-angular.mjs
generated
vendored
Normal file
647
node_modules/gridstack/dist/angular/fesm2015/gridstack-angular.mjs
generated
vendored
Normal file
@@ -0,0 +1,647 @@
|
||||
import * as i0 from '@angular/core';
|
||||
import { Injectable, ViewContainerRef, Component, ViewChild, Input, EventEmitter, reflectComponentType, ContentChildren, Output, NgModule } from '@angular/core';
|
||||
import { NgIf } from '@angular/common';
|
||||
import { GridStack } from 'gridstack';
|
||||
|
||||
/**
|
||||
* gridstack-item.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
/**
|
||||
* Base widget class for GridStack Angular integration.
|
||||
*/
|
||||
class BaseWidget {
|
||||
/**
|
||||
* Override this method to return serializable data for this widget.
|
||||
*
|
||||
* Return an object with properties that map to your component's @Input() fields.
|
||||
* The selector is handled automatically, so only include component-specific data.
|
||||
*
|
||||
* @returns Object containing serializable component data
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* serialize() {
|
||||
* return {
|
||||
* title: this.title,
|
||||
* value: this.value,
|
||||
* settings: this.settings
|
||||
* };
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
serialize() { return; }
|
||||
/**
|
||||
* Override this method to handle widget restoration from saved data.
|
||||
*
|
||||
* Use this for complex initialization that goes beyond simple @Input() mapping.
|
||||
* The default implementation automatically assigns input data to component properties.
|
||||
*
|
||||
* @param w The saved widget data including input properties
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* deserialize(w: NgGridStackWidget) {
|
||||
* super.deserialize(w); // Call parent for basic setup
|
||||
*
|
||||
* // Custom initialization logic
|
||||
* if (w.input?.complexData) {
|
||||
* this.processComplexData(w.input.complexData);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
deserialize(w) {
|
||||
// save full description for meta data
|
||||
this.widgetItem = w;
|
||||
if (!w)
|
||||
return;
|
||||
if (w.input)
|
||||
Object.assign(this, w.input);
|
||||
}
|
||||
}
|
||||
BaseWidget.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseWidget, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
||||
BaseWidget.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseWidget });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseWidget, decorators: [{
|
||||
type: Injectable
|
||||
}] });
|
||||
|
||||
/**
|
||||
* gridstack-item.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
/**
|
||||
* Angular component wrapper for individual GridStack items.
|
||||
*
|
||||
* This component represents a single grid item and handles:
|
||||
* - Dynamic content creation and management
|
||||
* - Integration with parent GridStack component
|
||||
* - Component lifecycle and cleanup
|
||||
* - Widget options and configuration
|
||||
*
|
||||
* Use in combination with GridstackComponent for the parent grid.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack>
|
||||
* <gridstack-item [options]="{x: 0, y: 0, w: 2, h: 1}">
|
||||
* <my-widget-component></my-widget-component>
|
||||
* </gridstack-item>
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
class GridstackItemComponent {
|
||||
constructor(elementRef) {
|
||||
this.elementRef = elementRef;
|
||||
this.el._gridItemComp = this;
|
||||
}
|
||||
/**
|
||||
* Grid item configuration options.
|
||||
* Defines position, size, and behavior of this grid item.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* itemOptions: GridStackNode = {
|
||||
* x: 0, y: 0, w: 2, h: 1,
|
||||
* noResize: true,
|
||||
* content: 'Item content'
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
set options(val) {
|
||||
var _a;
|
||||
const grid = (_a = this.el.gridstackNode) === null || _a === void 0 ? void 0 : _a.grid;
|
||||
if (grid) {
|
||||
// already built, do an update...
|
||||
grid.update(this.el, val);
|
||||
}
|
||||
else {
|
||||
// store our custom element in options so we can update it and not re-create a generic div!
|
||||
this._options = Object.assign(Object.assign({}, val), { el: this.el });
|
||||
}
|
||||
}
|
||||
/** return the latest grid options (from GS once built, otherwise initial values) */
|
||||
get options() {
|
||||
return this.el.gridstackNode || this._options || { el: this.el };
|
||||
}
|
||||
/** return the native element that contains grid specific fields as well */
|
||||
get el() { return this.elementRef.nativeElement; }
|
||||
/** clears the initial options now that we've built */
|
||||
clearOptions() {
|
||||
delete this._options;
|
||||
}
|
||||
ngOnDestroy() {
|
||||
this.clearOptions();
|
||||
delete this.childWidget;
|
||||
delete this.el._gridItemComp;
|
||||
delete this.container;
|
||||
delete this.ref;
|
||||
}
|
||||
}
|
||||
GridstackItemComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackItemComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
||||
GridstackItemComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: GridstackItemComponent, isStandalone: true, selector: "gridstack-item", inputs: { options: "options" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: `
|
||||
<div class="grid-stack-item-content">
|
||||
<!-- where dynamic items go based on component selector (recommended way), or sub-grids, etc...) -->
|
||||
<ng-template #container></ng-template>
|
||||
<!-- any static (defined in DOM - not recommended) content goes here -->
|
||||
<ng-content></ng-content>
|
||||
<!-- fallback HTML content from GridStackWidget.content if used instead (not recommended) -->
|
||||
{{options.content}}
|
||||
</div>`, isInline: true, styles: [":host{display:block}\n"] });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackItemComponent, decorators: [{
|
||||
type: Component,
|
||||
args: [{ selector: 'gridstack-item', template: `
|
||||
<div class="grid-stack-item-content">
|
||||
<!-- where dynamic items go based on component selector (recommended way), or sub-grids, etc...) -->
|
||||
<ng-template #container></ng-template>
|
||||
<!-- any static (defined in DOM - not recommended) content goes here -->
|
||||
<ng-content></ng-content>
|
||||
<!-- fallback HTML content from GridStackWidget.content if used instead (not recommended) -->
|
||||
{{options.content}}
|
||||
</div>`, standalone: true, styles: [":host{display:block}\n"] }]
|
||||
}], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { container: [{
|
||||
type: ViewChild,
|
||||
args: ['container', { read: ViewContainerRef, static: true }]
|
||||
}], options: [{
|
||||
type: Input
|
||||
}] } });
|
||||
|
||||
/**
|
||||
* gridstack.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
/**
|
||||
* Angular component wrapper for GridStack.
|
||||
*
|
||||
* This component provides Angular integration for GridStack grids, handling:
|
||||
* - Grid initialization and lifecycle
|
||||
* - Dynamic component creation and management
|
||||
* - Event binding and emission
|
||||
* - Integration with Angular change detection
|
||||
*
|
||||
* Use in combination with GridstackItemComponent for individual grid items.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack [options]="gridOptions" (change)="onGridChange($event)">
|
||||
* <div empty-content>Drag widgets here</div>
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
class GridstackComponent {
|
||||
constructor(elementRef) {
|
||||
this.elementRef = elementRef;
|
||||
/**
|
||||
* GridStack event emitters for Angular integration.
|
||||
*
|
||||
* These provide Angular-style event handling for GridStack events.
|
||||
* Alternatively, use `this.grid.on('event1 event2', callback)` for multiple events.
|
||||
*
|
||||
* Note: 'CB' suffix prevents conflicts with native DOM events.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack (changeCB)="onGridChange($event)" (droppedCB)="onItemDropped($event)">
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
/** Emitted when widgets are added to the grid */
|
||||
this.addedCB = new EventEmitter();
|
||||
/** Emitted when grid layout changes */
|
||||
this.changeCB = new EventEmitter();
|
||||
/** Emitted when grid is disabled */
|
||||
this.disableCB = new EventEmitter();
|
||||
/** Emitted during widget drag operations */
|
||||
this.dragCB = new EventEmitter();
|
||||
/** Emitted when widget drag starts */
|
||||
this.dragStartCB = new EventEmitter();
|
||||
/** Emitted when widget drag stops */
|
||||
this.dragStopCB = new EventEmitter();
|
||||
/** Emitted when widget is dropped */
|
||||
this.droppedCB = new EventEmitter();
|
||||
/** Emitted when grid is enabled */
|
||||
this.enableCB = new EventEmitter();
|
||||
/** Emitted when widgets are removed from the grid */
|
||||
this.removedCB = new EventEmitter();
|
||||
/** Emitted during widget resize operations */
|
||||
this.resizeCB = new EventEmitter();
|
||||
/** Emitted when widget resize starts */
|
||||
this.resizeStartCB = new EventEmitter();
|
||||
/** Emitted when widget resize stops */
|
||||
this.resizeStopCB = new EventEmitter();
|
||||
// set globally our method to create the right widget type
|
||||
if (!GridStack.addRemoveCB) {
|
||||
GridStack.addRemoveCB = gsCreateNgComponents;
|
||||
}
|
||||
if (!GridStack.saveCB) {
|
||||
GridStack.saveCB = gsSaveAdditionalNgInfo;
|
||||
}
|
||||
if (!GridStack.updateCB) {
|
||||
GridStack.updateCB = gsUpdateNgComponents;
|
||||
}
|
||||
this.el._gridComp = this;
|
||||
}
|
||||
/**
|
||||
* Grid configuration options.
|
||||
* Can be set before grid initialization or updated after grid is created.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* gridOptions: GridStackOptions = {
|
||||
* column: 12,
|
||||
* cellHeight: 'auto',
|
||||
* animate: true
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
set options(o) {
|
||||
if (this._grid) {
|
||||
this._grid.updateOptions(o);
|
||||
}
|
||||
else {
|
||||
this._options = o;
|
||||
}
|
||||
}
|
||||
/** Get the current running grid options */
|
||||
get options() { var _a; return ((_a = this._grid) === null || _a === void 0 ? void 0 : _a.opts) || this._options || {}; }
|
||||
/**
|
||||
* Get the native DOM element that contains grid-specific fields.
|
||||
* This element has GridStack properties attached to it.
|
||||
*/
|
||||
get el() { return this.elementRef.nativeElement; }
|
||||
/**
|
||||
* Get the underlying GridStack instance.
|
||||
* Use this to access GridStack API methods directly.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* this.gridComponent.grid.addWidget({x: 0, y: 0, w: 2, h: 1});
|
||||
* ```
|
||||
*/
|
||||
get grid() { return this._grid; }
|
||||
/**
|
||||
* Register a list of Angular components for dynamic creation.
|
||||
*
|
||||
* @param typeList Array of component types to register
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* GridstackComponent.addComponentToSelectorType([
|
||||
* MyWidgetComponent,
|
||||
* AnotherWidgetComponent
|
||||
* ]);
|
||||
* ```
|
||||
*/
|
||||
static addComponentToSelectorType(typeList) {
|
||||
typeList.forEach(type => GridstackComponent.selectorToType[GridstackComponent.getSelector(type)] = type);
|
||||
}
|
||||
/**
|
||||
* Extract the selector string from an Angular component type.
|
||||
*
|
||||
* @param type The component type to get selector from
|
||||
* @returns The component's selector string
|
||||
*/
|
||||
static getSelector(type) {
|
||||
return reflectComponentType(type).selector;
|
||||
}
|
||||
ngOnInit() {
|
||||
var _a, _b;
|
||||
// init ourself before any template children are created since we track them below anyway - no need to double create+update widgets
|
||||
this.loaded = !!((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.children) === null || _b === void 0 ? void 0 : _b.length);
|
||||
this._grid = GridStack.init(this._options, this.el);
|
||||
delete this._options; // GS has it now
|
||||
this.checkEmpty();
|
||||
}
|
||||
/** wait until after all DOM is ready to init gridstack children (after angular ngFor and sub-components run first) */
|
||||
ngAfterContentInit() {
|
||||
var _a;
|
||||
// track whenever the children list changes and update the layout...
|
||||
this._sub = (_a = this.gridstackItems) === null || _a === void 0 ? void 0 : _a.changes.subscribe(() => this.updateAll());
|
||||
// ...and do this once at least unless we loaded children already
|
||||
if (!this.loaded)
|
||||
this.updateAll();
|
||||
this.hookEvents(this.grid);
|
||||
}
|
||||
ngOnDestroy() {
|
||||
var _a, _b;
|
||||
this.unhookEvents(this._grid);
|
||||
(_a = this._sub) === null || _a === void 0 ? void 0 : _a.unsubscribe();
|
||||
(_b = this._grid) === null || _b === void 0 ? void 0 : _b.destroy();
|
||||
delete this._grid;
|
||||
delete this.el._gridComp;
|
||||
delete this.container;
|
||||
delete this.ref;
|
||||
}
|
||||
/**
|
||||
* called when the TEMPLATE (not recommended) list of items changes - get a list of nodes and
|
||||
* update the layout accordingly (which will take care of adding/removing items changed by Angular)
|
||||
*/
|
||||
updateAll() {
|
||||
var _a;
|
||||
if (!this.grid)
|
||||
return;
|
||||
const layout = [];
|
||||
(_a = this.gridstackItems) === null || _a === void 0 ? void 0 : _a.forEach(item => {
|
||||
layout.push(item.options);
|
||||
item.clearOptions();
|
||||
});
|
||||
this.grid.load(layout); // efficient that does diffs only
|
||||
}
|
||||
/** check if the grid is empty, if so show alternative content */
|
||||
checkEmpty() {
|
||||
if (!this.grid)
|
||||
return;
|
||||
this.isEmpty = !this.grid.engine.nodes.length;
|
||||
}
|
||||
/** get all known events as easy to use Outputs for convenience */
|
||||
hookEvents(grid) {
|
||||
if (!grid)
|
||||
return;
|
||||
// nested grids don't have events in v12.1+ so skip
|
||||
if (grid.parentGridNode)
|
||||
return;
|
||||
grid
|
||||
.on('added', (event, nodes) => {
|
||||
var _a;
|
||||
const gridComp = ((_a = nodes[0].grid) === null || _a === void 0 ? void 0 : _a.el._gridComp) || this;
|
||||
gridComp.checkEmpty();
|
||||
this.addedCB.emit({ event, nodes });
|
||||
})
|
||||
.on('change', (event, nodes) => this.changeCB.emit({ event, nodes }))
|
||||
.on('disable', (event) => this.disableCB.emit({ event }))
|
||||
.on('drag', (event, el) => this.dragCB.emit({ event, el }))
|
||||
.on('dragstart', (event, el) => this.dragStartCB.emit({ event, el }))
|
||||
.on('dragstop', (event, el) => this.dragStopCB.emit({ event, el }))
|
||||
.on('dropped', (event, previousNode, newNode) => this.droppedCB.emit({ event, previousNode, newNode }))
|
||||
.on('enable', (event) => this.enableCB.emit({ event }))
|
||||
.on('removed', (event, nodes) => {
|
||||
var _a;
|
||||
const gridComp = ((_a = nodes[0].grid) === null || _a === void 0 ? void 0 : _a.el._gridComp) || this;
|
||||
gridComp.checkEmpty();
|
||||
this.removedCB.emit({ event, nodes });
|
||||
})
|
||||
.on('resize', (event, el) => this.resizeCB.emit({ event, el }))
|
||||
.on('resizestart', (event, el) => this.resizeStartCB.emit({ event, el }))
|
||||
.on('resizestop', (event, el) => this.resizeStopCB.emit({ event, el }));
|
||||
}
|
||||
unhookEvents(grid) {
|
||||
if (!grid)
|
||||
return;
|
||||
// nested grids don't have events in v12.1+ so skip
|
||||
if (grid.parentGridNode)
|
||||
return;
|
||||
grid.off('added change disable drag dragstart dragstop dropped enable removed resize resizestart resizestop');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Mapping of component selectors to their types for dynamic creation.
|
||||
*
|
||||
* This enables dynamic component instantiation from string selectors.
|
||||
* Angular doesn't provide public access to this mapping, so we maintain our own.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* GridstackComponent.addComponentToSelectorType([MyWidgetComponent]);
|
||||
* ```
|
||||
*/
|
||||
GridstackComponent.selectorToType = {};
|
||||
GridstackComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
||||
GridstackComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: GridstackComponent, isStandalone: true, selector: "gridstack", inputs: { options: "options", isEmpty: "isEmpty" }, outputs: { addedCB: "addedCB", changeCB: "changeCB", disableCB: "disableCB", dragCB: "dragCB", dragStartCB: "dragStartCB", dragStopCB: "dragStopCB", droppedCB: "droppedCB", enableCB: "enableCB", removedCB: "removedCB", resizeCB: "resizeCB", resizeStartCB: "resizeStartCB", resizeStopCB: "resizeStopCB" }, queries: [{ propertyName: "gridstackItems", predicate: GridstackItemComponent }], viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: `
|
||||
<!-- content to show when when grid is empty, like instructions on how to add widgets -->
|
||||
<ng-content select="[empty-content]" *ngIf="isEmpty"></ng-content>
|
||||
<!-- where dynamic items go -->
|
||||
<ng-template #container></ng-template>
|
||||
<!-- where template items go -->
|
||||
<ng-content></ng-content>
|
||||
`, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackComponent, decorators: [{
|
||||
type: Component,
|
||||
args: [{ selector: 'gridstack', template: `
|
||||
<!-- content to show when when grid is empty, like instructions on how to add widgets -->
|
||||
<ng-content select="[empty-content]" *ngIf="isEmpty"></ng-content>
|
||||
<!-- where dynamic items go -->
|
||||
<ng-template #container></ng-template>
|
||||
<!-- where template items go -->
|
||||
<ng-content></ng-content>
|
||||
`, standalone: true, imports: [NgIf], styles: [":host{display:block}\n"] }]
|
||||
}], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { gridstackItems: [{
|
||||
type: ContentChildren,
|
||||
args: [GridstackItemComponent]
|
||||
}], container: [{
|
||||
type: ViewChild,
|
||||
args: ['container', { read: ViewContainerRef, static: true }]
|
||||
}], options: [{
|
||||
type: Input
|
||||
}], isEmpty: [{
|
||||
type: Input
|
||||
}], addedCB: [{
|
||||
type: Output
|
||||
}], changeCB: [{
|
||||
type: Output
|
||||
}], disableCB: [{
|
||||
type: Output
|
||||
}], dragCB: [{
|
||||
type: Output
|
||||
}], dragStartCB: [{
|
||||
type: Output
|
||||
}], dragStopCB: [{
|
||||
type: Output
|
||||
}], droppedCB: [{
|
||||
type: Output
|
||||
}], enableCB: [{
|
||||
type: Output
|
||||
}], removedCB: [{
|
||||
type: Output
|
||||
}], resizeCB: [{
|
||||
type: Output
|
||||
}], resizeStartCB: [{
|
||||
type: Output
|
||||
}], resizeStopCB: [{
|
||||
type: Output
|
||||
}] } });
|
||||
/**
|
||||
* can be used when a new item needs to be created, which we do as a Angular component, or deleted (skip)
|
||||
**/
|
||||
function gsCreateNgComponents(host, n, add, isGrid) {
|
||||
var _a, _b, _c, _d, _e, _f, _g;
|
||||
if (add) {
|
||||
//
|
||||
// create the component dynamically - see https://angular.io/docs/ts/latest/cookbook/dynamic-component-loader.html
|
||||
//
|
||||
if (!host)
|
||||
return;
|
||||
if (isGrid) {
|
||||
// TODO: figure out how to create ng component inside regular Div. need to access app injectors...
|
||||
// if (!container) {
|
||||
// const hostElement: Element = host;
|
||||
// const environmentInjector: EnvironmentInjector;
|
||||
// grid = createComponent(GridstackComponent, {environmentInjector, hostElement})?.instance;
|
||||
// }
|
||||
const gridItemComp = (_a = host.parentElement) === null || _a === void 0 ? void 0 : _a._gridItemComp;
|
||||
if (!gridItemComp)
|
||||
return;
|
||||
// check if gridItem has a child component with 'container' exposed to create under..
|
||||
const container = ((_b = gridItemComp.childWidget) === null || _b === void 0 ? void 0 : _b.container) || gridItemComp.container;
|
||||
const gridRef = container === null || container === void 0 ? void 0 : container.createComponent(GridstackComponent);
|
||||
const grid = gridRef === null || gridRef === void 0 ? void 0 : gridRef.instance;
|
||||
if (!grid)
|
||||
return;
|
||||
grid.ref = gridRef;
|
||||
grid.options = n;
|
||||
return grid.el;
|
||||
}
|
||||
else {
|
||||
const gridComp = host._gridComp;
|
||||
const gridItemRef = (_c = gridComp === null || gridComp === void 0 ? void 0 : gridComp.container) === null || _c === void 0 ? void 0 : _c.createComponent(GridstackItemComponent);
|
||||
const gridItem = gridItemRef === null || gridItemRef === void 0 ? void 0 : gridItemRef.instance;
|
||||
if (!gridItem)
|
||||
return;
|
||||
gridItem.ref = gridItemRef;
|
||||
// define what type of component to create as child, OR you can do it GridstackItemComponent template, but this is more generic
|
||||
const selector = n.selector;
|
||||
const type = selector ? GridstackComponent.selectorToType[selector] : undefined;
|
||||
if (type) {
|
||||
// shared code to create our selector component
|
||||
const createComp = () => {
|
||||
var _a, _b;
|
||||
const childWidget = (_b = (_a = gridItem.container) === null || _a === void 0 ? void 0 : _a.createComponent(type)) === null || _b === void 0 ? void 0 : _b.instance;
|
||||
// if proper BaseWidget subclass, save it and load additional data
|
||||
if (childWidget && typeof childWidget.serialize === 'function' && typeof childWidget.deserialize === 'function') {
|
||||
gridItem.childWidget = childWidget;
|
||||
childWidget.deserialize(n);
|
||||
}
|
||||
};
|
||||
const lazyLoad = n.lazyLoad || ((_e = (_d = n.grid) === null || _d === void 0 ? void 0 : _d.opts) === null || _e === void 0 ? void 0 : _e.lazyLoad) && n.lazyLoad !== false;
|
||||
if (lazyLoad) {
|
||||
if (!n.visibleObservable) {
|
||||
n.visibleObservable = new IntersectionObserver(([entry]) => {
|
||||
var _a;
|
||||
if (entry.isIntersecting) {
|
||||
(_a = n.visibleObservable) === null || _a === void 0 ? void 0 : _a.disconnect();
|
||||
delete n.visibleObservable;
|
||||
createComp();
|
||||
}
|
||||
});
|
||||
window.setTimeout(() => { var _a; return (_a = n.visibleObservable) === null || _a === void 0 ? void 0 : _a.observe(gridItem.el); }); // wait until callee sets position attributes
|
||||
}
|
||||
}
|
||||
else
|
||||
createComp();
|
||||
}
|
||||
return gridItem.el;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// REMOVE - have to call ComponentRef:destroy() for dynamic objects to correctly remove themselves
|
||||
// Note: this will destroy all children dynamic components as well: gridItem -> childWidget
|
||||
//
|
||||
if (isGrid) {
|
||||
const grid = (_f = n.el) === null || _f === void 0 ? void 0 : _f._gridComp;
|
||||
if (grid === null || grid === void 0 ? void 0 : grid.ref)
|
||||
grid.ref.destroy();
|
||||
else
|
||||
grid === null || grid === void 0 ? void 0 : grid.ngOnDestroy();
|
||||
}
|
||||
else {
|
||||
const gridItem = (_g = n.el) === null || _g === void 0 ? void 0 : _g._gridItemComp;
|
||||
if (gridItem === null || gridItem === void 0 ? void 0 : gridItem.ref)
|
||||
gridItem.ref.destroy();
|
||||
else
|
||||
gridItem === null || gridItem === void 0 ? void 0 : gridItem.ngOnDestroy();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* called for each item in the grid - check if additional information needs to be saved.
|
||||
* Note: since this is options minus gridstack protected members using Utils.removeInternalForSave(),
|
||||
* this typically doesn't need to do anything. However your custom Component @Input() are now supported
|
||||
* using BaseWidget.serialize()
|
||||
*/
|
||||
function gsSaveAdditionalNgInfo(n, w) {
|
||||
var _a, _b, _c;
|
||||
const gridItem = (_a = n.el) === null || _a === void 0 ? void 0 : _a._gridItemComp;
|
||||
if (gridItem) {
|
||||
const input = (_b = gridItem.childWidget) === null || _b === void 0 ? void 0 : _b.serialize();
|
||||
if (input) {
|
||||
w.input = input;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// else check if Grid
|
||||
const grid = (_c = n.el) === null || _c === void 0 ? void 0 : _c._gridComp;
|
||||
if (grid) {
|
||||
//.... save any custom data
|
||||
}
|
||||
}
|
||||
/**
|
||||
* track when widgeta re updated (rather than created) to make sure we de-serialize them as well
|
||||
*/
|
||||
function gsUpdateNgComponents(n) {
|
||||
var _a;
|
||||
const w = n;
|
||||
const gridItem = (_a = n.el) === null || _a === void 0 ? void 0 : _a._gridItemComp;
|
||||
if ((gridItem === null || gridItem === void 0 ? void 0 : gridItem.childWidget) && w.input)
|
||||
gridItem.childWidget.deserialize(w);
|
||||
}
|
||||
|
||||
/**
|
||||
* gridstack.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
/**
|
||||
* @deprecated Use GridstackComponent and GridstackItemComponent as standalone components instead.
|
||||
*
|
||||
* This NgModule is provided for backward compatibility but is no longer the recommended approach.
|
||||
* Import components directly in your standalone components or use the new Angular module structure.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Preferred approach - standalone components
|
||||
* @Component({
|
||||
* selector: 'my-app',
|
||||
* imports: [GridstackComponent, GridstackItemComponent],
|
||||
* template: '<gridstack></gridstack>'
|
||||
* })
|
||||
* export class AppComponent {}
|
||||
*
|
||||
* // Legacy approach (deprecated)
|
||||
* @NgModule({
|
||||
* imports: [GridstackModule]
|
||||
* })
|
||||
* export class AppModule {}
|
||||
* ```
|
||||
*/
|
||||
class GridstackModule {
|
||||
}
|
||||
GridstackModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
||||
GridstackModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: GridstackModule, imports: [GridstackItemComponent,
|
||||
GridstackComponent], exports: [GridstackItemComponent,
|
||||
GridstackComponent] });
|
||||
GridstackModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackModule, imports: [GridstackItemComponent,
|
||||
GridstackComponent] });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackModule, decorators: [{
|
||||
type: NgModule,
|
||||
args: [{
|
||||
imports: [
|
||||
GridstackItemComponent,
|
||||
GridstackComponent,
|
||||
],
|
||||
exports: [
|
||||
GridstackItemComponent,
|
||||
GridstackComponent,
|
||||
],
|
||||
}]
|
||||
}] });
|
||||
|
||||
/*
|
||||
* Public API Surface of gridstack-angular
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generated bundle index. Do not edit.
|
||||
*/
|
||||
|
||||
export { BaseWidget, GridstackComponent, GridstackItemComponent, GridstackModule, gsCreateNgComponents, gsSaveAdditionalNgInfo, gsUpdateNgComponents };
|
||||
//# sourceMappingURL=gridstack-angular.mjs.map
|
||||
1
node_modules/gridstack/dist/angular/fesm2015/gridstack-angular.mjs.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/angular/fesm2015/gridstack-angular.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
640
node_modules/gridstack/dist/angular/fesm2020/gridstack-angular.mjs
generated
vendored
Normal file
640
node_modules/gridstack/dist/angular/fesm2020/gridstack-angular.mjs
generated
vendored
Normal file
@@ -0,0 +1,640 @@
|
||||
import * as i0 from '@angular/core';
|
||||
import { Injectable, ViewContainerRef, Component, ViewChild, Input, EventEmitter, reflectComponentType, ContentChildren, Output, NgModule } from '@angular/core';
|
||||
import { NgIf } from '@angular/common';
|
||||
import { GridStack } from 'gridstack';
|
||||
|
||||
/**
|
||||
* gridstack-item.component.ts 12.3.3
|
||||
* Copyright (c) 2025 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
|
||||
/**
|
||||
* gridstack-item.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
/**
|
||||
* Base widget class for GridStack Angular integration.
|
||||
*/
|
||||
class BaseWidget {
|
||||
/**
|
||||
* Override this method to return serializable data for this widget.
|
||||
*
|
||||
* Return an object with properties that map to your component's @Input() fields.
|
||||
* The selector is handled automatically, so only include component-specific data.
|
||||
*
|
||||
* @returns Object containing serializable component data
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* serialize() {
|
||||
* return {
|
||||
* title: this.title,
|
||||
* value: this.value,
|
||||
* settings: this.settings
|
||||
* };
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
serialize() { return; }
|
||||
/**
|
||||
* Override this method to handle widget restoration from saved data.
|
||||
*
|
||||
* Use this for complex initialization that goes beyond simple @Input() mapping.
|
||||
* The default implementation automatically assigns input data to component properties.
|
||||
*
|
||||
* @param w The saved widget data including input properties
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* deserialize(w: NgGridStackWidget) {
|
||||
* super.deserialize(w); // Call parent for basic setup
|
||||
*
|
||||
* // Custom initialization logic
|
||||
* if (w.input?.complexData) {
|
||||
* this.processComplexData(w.input.complexData);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
deserialize(w) {
|
||||
// save full description for meta data
|
||||
this.widgetItem = w;
|
||||
if (!w)
|
||||
return;
|
||||
if (w.input)
|
||||
Object.assign(this, w.input);
|
||||
}
|
||||
}
|
||||
BaseWidget.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseWidget, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
||||
BaseWidget.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseWidget });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseWidget, decorators: [{
|
||||
type: Injectable
|
||||
}] });
|
||||
|
||||
/**
|
||||
* gridstack-item.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
/**
|
||||
* Angular component wrapper for individual GridStack items.
|
||||
*
|
||||
* This component represents a single grid item and handles:
|
||||
* - Dynamic content creation and management
|
||||
* - Integration with parent GridStack component
|
||||
* - Component lifecycle and cleanup
|
||||
* - Widget options and configuration
|
||||
*
|
||||
* Use in combination with GridstackComponent for the parent grid.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack>
|
||||
* <gridstack-item [options]="{x: 0, y: 0, w: 2, h: 1}">
|
||||
* <my-widget-component></my-widget-component>
|
||||
* </gridstack-item>
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
class GridstackItemComponent {
|
||||
constructor(elementRef) {
|
||||
this.elementRef = elementRef;
|
||||
this.el._gridItemComp = this;
|
||||
}
|
||||
/**
|
||||
* Grid item configuration options.
|
||||
* Defines position, size, and behavior of this grid item.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* itemOptions: GridStackNode = {
|
||||
* x: 0, y: 0, w: 2, h: 1,
|
||||
* noResize: true,
|
||||
* content: 'Item content'
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
set options(val) {
|
||||
const grid = this.el.gridstackNode?.grid;
|
||||
if (grid) {
|
||||
// already built, do an update...
|
||||
grid.update(this.el, val);
|
||||
}
|
||||
else {
|
||||
// store our custom element in options so we can update it and not re-create a generic div!
|
||||
this._options = { ...val, el: this.el };
|
||||
}
|
||||
}
|
||||
/** return the latest grid options (from GS once built, otherwise initial values) */
|
||||
get options() {
|
||||
return this.el.gridstackNode || this._options || { el: this.el };
|
||||
}
|
||||
/** return the native element that contains grid specific fields as well */
|
||||
get el() { return this.elementRef.nativeElement; }
|
||||
/** clears the initial options now that we've built */
|
||||
clearOptions() {
|
||||
delete this._options;
|
||||
}
|
||||
ngOnDestroy() {
|
||||
this.clearOptions();
|
||||
delete this.childWidget;
|
||||
delete this.el._gridItemComp;
|
||||
delete this.container;
|
||||
delete this.ref;
|
||||
}
|
||||
}
|
||||
GridstackItemComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackItemComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
||||
GridstackItemComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: GridstackItemComponent, isStandalone: true, selector: "gridstack-item", inputs: { options: "options" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: `
|
||||
<div class="grid-stack-item-content">
|
||||
<!-- where dynamic items go based on component selector (recommended way), or sub-grids, etc...) -->
|
||||
<ng-template #container></ng-template>
|
||||
<!-- any static (defined in DOM - not recommended) content goes here -->
|
||||
<ng-content></ng-content>
|
||||
<!-- fallback HTML content from GridStackWidget.content if used instead (not recommended) -->
|
||||
{{options.content}}
|
||||
</div>`, isInline: true, styles: [":host{display:block}\n"] });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackItemComponent, decorators: [{
|
||||
type: Component,
|
||||
args: [{ selector: 'gridstack-item', template: `
|
||||
<div class="grid-stack-item-content">
|
||||
<!-- where dynamic items go based on component selector (recommended way), or sub-grids, etc...) -->
|
||||
<ng-template #container></ng-template>
|
||||
<!-- any static (defined in DOM - not recommended) content goes here -->
|
||||
<ng-content></ng-content>
|
||||
<!-- fallback HTML content from GridStackWidget.content if used instead (not recommended) -->
|
||||
{{options.content}}
|
||||
</div>`, standalone: true, styles: [":host{display:block}\n"] }]
|
||||
}], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { container: [{
|
||||
type: ViewChild,
|
||||
args: ['container', { read: ViewContainerRef, static: true }]
|
||||
}], options: [{
|
||||
type: Input
|
||||
}] } });
|
||||
|
||||
/**
|
||||
* gridstack.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
/**
|
||||
* Angular component wrapper for GridStack.
|
||||
*
|
||||
* This component provides Angular integration for GridStack grids, handling:
|
||||
* - Grid initialization and lifecycle
|
||||
* - Dynamic component creation and management
|
||||
* - Event binding and emission
|
||||
* - Integration with Angular change detection
|
||||
*
|
||||
* Use in combination with GridstackItemComponent for individual grid items.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack [options]="gridOptions" (change)="onGridChange($event)">
|
||||
* <div empty-content>Drag widgets here</div>
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
class GridstackComponent {
|
||||
constructor(elementRef) {
|
||||
this.elementRef = elementRef;
|
||||
/**
|
||||
* GridStack event emitters for Angular integration.
|
||||
*
|
||||
* These provide Angular-style event handling for GridStack events.
|
||||
* Alternatively, use `this.grid.on('event1 event2', callback)` for multiple events.
|
||||
*
|
||||
* Note: 'CB' suffix prevents conflicts with native DOM events.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack (changeCB)="onGridChange($event)" (droppedCB)="onItemDropped($event)">
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
/** Emitted when widgets are added to the grid */
|
||||
this.addedCB = new EventEmitter();
|
||||
/** Emitted when grid layout changes */
|
||||
this.changeCB = new EventEmitter();
|
||||
/** Emitted when grid is disabled */
|
||||
this.disableCB = new EventEmitter();
|
||||
/** Emitted during widget drag operations */
|
||||
this.dragCB = new EventEmitter();
|
||||
/** Emitted when widget drag starts */
|
||||
this.dragStartCB = new EventEmitter();
|
||||
/** Emitted when widget drag stops */
|
||||
this.dragStopCB = new EventEmitter();
|
||||
/** Emitted when widget is dropped */
|
||||
this.droppedCB = new EventEmitter();
|
||||
/** Emitted when grid is enabled */
|
||||
this.enableCB = new EventEmitter();
|
||||
/** Emitted when widgets are removed from the grid */
|
||||
this.removedCB = new EventEmitter();
|
||||
/** Emitted during widget resize operations */
|
||||
this.resizeCB = new EventEmitter();
|
||||
/** Emitted when widget resize starts */
|
||||
this.resizeStartCB = new EventEmitter();
|
||||
/** Emitted when widget resize stops */
|
||||
this.resizeStopCB = new EventEmitter();
|
||||
// set globally our method to create the right widget type
|
||||
if (!GridStack.addRemoveCB) {
|
||||
GridStack.addRemoveCB = gsCreateNgComponents;
|
||||
}
|
||||
if (!GridStack.saveCB) {
|
||||
GridStack.saveCB = gsSaveAdditionalNgInfo;
|
||||
}
|
||||
if (!GridStack.updateCB) {
|
||||
GridStack.updateCB = gsUpdateNgComponents;
|
||||
}
|
||||
this.el._gridComp = this;
|
||||
}
|
||||
/**
|
||||
* Grid configuration options.
|
||||
* Can be set before grid initialization or updated after grid is created.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* gridOptions: GridStackOptions = {
|
||||
* column: 12,
|
||||
* cellHeight: 'auto',
|
||||
* animate: true
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
set options(o) {
|
||||
if (this._grid) {
|
||||
this._grid.updateOptions(o);
|
||||
}
|
||||
else {
|
||||
this._options = o;
|
||||
}
|
||||
}
|
||||
/** Get the current running grid options */
|
||||
get options() { return this._grid?.opts || this._options || {}; }
|
||||
/**
|
||||
* Get the native DOM element that contains grid-specific fields.
|
||||
* This element has GridStack properties attached to it.
|
||||
*/
|
||||
get el() { return this.elementRef.nativeElement; }
|
||||
/**
|
||||
* Get the underlying GridStack instance.
|
||||
* Use this to access GridStack API methods directly.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* this.gridComponent.grid.addWidget({x: 0, y: 0, w: 2, h: 1});
|
||||
* ```
|
||||
*/
|
||||
get grid() { return this._grid; }
|
||||
/**
|
||||
* Register a list of Angular components for dynamic creation.
|
||||
*
|
||||
* @param typeList Array of component types to register
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* GridstackComponent.addComponentToSelectorType([
|
||||
* MyWidgetComponent,
|
||||
* AnotherWidgetComponent
|
||||
* ]);
|
||||
* ```
|
||||
*/
|
||||
static addComponentToSelectorType(typeList) {
|
||||
typeList.forEach(type => GridstackComponent.selectorToType[GridstackComponent.getSelector(type)] = type);
|
||||
}
|
||||
/**
|
||||
* Extract the selector string from an Angular component type.
|
||||
*
|
||||
* @param type The component type to get selector from
|
||||
* @returns The component's selector string
|
||||
*/
|
||||
static getSelector(type) {
|
||||
return reflectComponentType(type).selector;
|
||||
}
|
||||
ngOnInit() {
|
||||
// init ourself before any template children are created since we track them below anyway - no need to double create+update widgets
|
||||
this.loaded = !!this.options?.children?.length;
|
||||
this._grid = GridStack.init(this._options, this.el);
|
||||
delete this._options; // GS has it now
|
||||
this.checkEmpty();
|
||||
}
|
||||
/** wait until after all DOM is ready to init gridstack children (after angular ngFor and sub-components run first) */
|
||||
ngAfterContentInit() {
|
||||
// track whenever the children list changes and update the layout...
|
||||
this._sub = this.gridstackItems?.changes.subscribe(() => this.updateAll());
|
||||
// ...and do this once at least unless we loaded children already
|
||||
if (!this.loaded)
|
||||
this.updateAll();
|
||||
this.hookEvents(this.grid);
|
||||
}
|
||||
ngOnDestroy() {
|
||||
this.unhookEvents(this._grid);
|
||||
this._sub?.unsubscribe();
|
||||
this._grid?.destroy();
|
||||
delete this._grid;
|
||||
delete this.el._gridComp;
|
||||
delete this.container;
|
||||
delete this.ref;
|
||||
}
|
||||
/**
|
||||
* called when the TEMPLATE (not recommended) list of items changes - get a list of nodes and
|
||||
* update the layout accordingly (which will take care of adding/removing items changed by Angular)
|
||||
*/
|
||||
updateAll() {
|
||||
if (!this.grid)
|
||||
return;
|
||||
const layout = [];
|
||||
this.gridstackItems?.forEach(item => {
|
||||
layout.push(item.options);
|
||||
item.clearOptions();
|
||||
});
|
||||
this.grid.load(layout); // efficient that does diffs only
|
||||
}
|
||||
/** check if the grid is empty, if so show alternative content */
|
||||
checkEmpty() {
|
||||
if (!this.grid)
|
||||
return;
|
||||
this.isEmpty = !this.grid.engine.nodes.length;
|
||||
}
|
||||
/** get all known events as easy to use Outputs for convenience */
|
||||
hookEvents(grid) {
|
||||
if (!grid)
|
||||
return;
|
||||
// nested grids don't have events in v12.1+ so skip
|
||||
if (grid.parentGridNode)
|
||||
return;
|
||||
grid
|
||||
.on('added', (event, nodes) => {
|
||||
const gridComp = nodes[0].grid?.el._gridComp || this;
|
||||
gridComp.checkEmpty();
|
||||
this.addedCB.emit({ event, nodes });
|
||||
})
|
||||
.on('change', (event, nodes) => this.changeCB.emit({ event, nodes }))
|
||||
.on('disable', (event) => this.disableCB.emit({ event }))
|
||||
.on('drag', (event, el) => this.dragCB.emit({ event, el }))
|
||||
.on('dragstart', (event, el) => this.dragStartCB.emit({ event, el }))
|
||||
.on('dragstop', (event, el) => this.dragStopCB.emit({ event, el }))
|
||||
.on('dropped', (event, previousNode, newNode) => this.droppedCB.emit({ event, previousNode, newNode }))
|
||||
.on('enable', (event) => this.enableCB.emit({ event }))
|
||||
.on('removed', (event, nodes) => {
|
||||
const gridComp = nodes[0].grid?.el._gridComp || this;
|
||||
gridComp.checkEmpty();
|
||||
this.removedCB.emit({ event, nodes });
|
||||
})
|
||||
.on('resize', (event, el) => this.resizeCB.emit({ event, el }))
|
||||
.on('resizestart', (event, el) => this.resizeStartCB.emit({ event, el }))
|
||||
.on('resizestop', (event, el) => this.resizeStopCB.emit({ event, el }));
|
||||
}
|
||||
unhookEvents(grid) {
|
||||
if (!grid)
|
||||
return;
|
||||
// nested grids don't have events in v12.1+ so skip
|
||||
if (grid.parentGridNode)
|
||||
return;
|
||||
grid.off('added change disable drag dragstart dragstop dropped enable removed resize resizestart resizestop');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Mapping of component selectors to their types for dynamic creation.
|
||||
*
|
||||
* This enables dynamic component instantiation from string selectors.
|
||||
* Angular doesn't provide public access to this mapping, so we maintain our own.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* GridstackComponent.addComponentToSelectorType([MyWidgetComponent]);
|
||||
* ```
|
||||
*/
|
||||
GridstackComponent.selectorToType = {};
|
||||
GridstackComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
||||
GridstackComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: GridstackComponent, isStandalone: true, selector: "gridstack", inputs: { options: "options", isEmpty: "isEmpty" }, outputs: { addedCB: "addedCB", changeCB: "changeCB", disableCB: "disableCB", dragCB: "dragCB", dragStartCB: "dragStartCB", dragStopCB: "dragStopCB", droppedCB: "droppedCB", enableCB: "enableCB", removedCB: "removedCB", resizeCB: "resizeCB", resizeStartCB: "resizeStartCB", resizeStopCB: "resizeStopCB" }, queries: [{ propertyName: "gridstackItems", predicate: GridstackItemComponent }], viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: `
|
||||
<!-- content to show when when grid is empty, like instructions on how to add widgets -->
|
||||
<ng-content select="[empty-content]" *ngIf="isEmpty"></ng-content>
|
||||
<!-- where dynamic items go -->
|
||||
<ng-template #container></ng-template>
|
||||
<!-- where template items go -->
|
||||
<ng-content></ng-content>
|
||||
`, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackComponent, decorators: [{
|
||||
type: Component,
|
||||
args: [{ selector: 'gridstack', template: `
|
||||
<!-- content to show when when grid is empty, like instructions on how to add widgets -->
|
||||
<ng-content select="[empty-content]" *ngIf="isEmpty"></ng-content>
|
||||
<!-- where dynamic items go -->
|
||||
<ng-template #container></ng-template>
|
||||
<!-- where template items go -->
|
||||
<ng-content></ng-content>
|
||||
`, standalone: true, imports: [NgIf], styles: [":host{display:block}\n"] }]
|
||||
}], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { gridstackItems: [{
|
||||
type: ContentChildren,
|
||||
args: [GridstackItemComponent]
|
||||
}], container: [{
|
||||
type: ViewChild,
|
||||
args: ['container', { read: ViewContainerRef, static: true }]
|
||||
}], options: [{
|
||||
type: Input
|
||||
}], isEmpty: [{
|
||||
type: Input
|
||||
}], addedCB: [{
|
||||
type: Output
|
||||
}], changeCB: [{
|
||||
type: Output
|
||||
}], disableCB: [{
|
||||
type: Output
|
||||
}], dragCB: [{
|
||||
type: Output
|
||||
}], dragStartCB: [{
|
||||
type: Output
|
||||
}], dragStopCB: [{
|
||||
type: Output
|
||||
}], droppedCB: [{
|
||||
type: Output
|
||||
}], enableCB: [{
|
||||
type: Output
|
||||
}], removedCB: [{
|
||||
type: Output
|
||||
}], resizeCB: [{
|
||||
type: Output
|
||||
}], resizeStartCB: [{
|
||||
type: Output
|
||||
}], resizeStopCB: [{
|
||||
type: Output
|
||||
}] } });
|
||||
/**
|
||||
* can be used when a new item needs to be created, which we do as a Angular component, or deleted (skip)
|
||||
**/
|
||||
function gsCreateNgComponents(host, n, add, isGrid) {
|
||||
if (add) {
|
||||
//
|
||||
// create the component dynamically - see https://angular.io/docs/ts/latest/cookbook/dynamic-component-loader.html
|
||||
//
|
||||
if (!host)
|
||||
return;
|
||||
if (isGrid) {
|
||||
// TODO: figure out how to create ng component inside regular Div. need to access app injectors...
|
||||
// if (!container) {
|
||||
// const hostElement: Element = host;
|
||||
// const environmentInjector: EnvironmentInjector;
|
||||
// grid = createComponent(GridstackComponent, {environmentInjector, hostElement})?.instance;
|
||||
// }
|
||||
const gridItemComp = host.parentElement?._gridItemComp;
|
||||
if (!gridItemComp)
|
||||
return;
|
||||
// check if gridItem has a child component with 'container' exposed to create under..
|
||||
const container = gridItemComp.childWidget?.container || gridItemComp.container;
|
||||
const gridRef = container?.createComponent(GridstackComponent);
|
||||
const grid = gridRef?.instance;
|
||||
if (!grid)
|
||||
return;
|
||||
grid.ref = gridRef;
|
||||
grid.options = n;
|
||||
return grid.el;
|
||||
}
|
||||
else {
|
||||
const gridComp = host._gridComp;
|
||||
const gridItemRef = gridComp?.container?.createComponent(GridstackItemComponent);
|
||||
const gridItem = gridItemRef?.instance;
|
||||
if (!gridItem)
|
||||
return;
|
||||
gridItem.ref = gridItemRef;
|
||||
// define what type of component to create as child, OR you can do it GridstackItemComponent template, but this is more generic
|
||||
const selector = n.selector;
|
||||
const type = selector ? GridstackComponent.selectorToType[selector] : undefined;
|
||||
if (type) {
|
||||
// shared code to create our selector component
|
||||
const createComp = () => {
|
||||
const childWidget = gridItem.container?.createComponent(type)?.instance;
|
||||
// if proper BaseWidget subclass, save it and load additional data
|
||||
if (childWidget && typeof childWidget.serialize === 'function' && typeof childWidget.deserialize === 'function') {
|
||||
gridItem.childWidget = childWidget;
|
||||
childWidget.deserialize(n);
|
||||
}
|
||||
};
|
||||
const lazyLoad = n.lazyLoad || n.grid?.opts?.lazyLoad && n.lazyLoad !== false;
|
||||
if (lazyLoad) {
|
||||
if (!n.visibleObservable) {
|
||||
n.visibleObservable = new IntersectionObserver(([entry]) => {
|
||||
if (entry.isIntersecting) {
|
||||
n.visibleObservable?.disconnect();
|
||||
delete n.visibleObservable;
|
||||
createComp();
|
||||
}
|
||||
});
|
||||
window.setTimeout(() => n.visibleObservable?.observe(gridItem.el)); // wait until callee sets position attributes
|
||||
}
|
||||
}
|
||||
else
|
||||
createComp();
|
||||
}
|
||||
return gridItem.el;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// REMOVE - have to call ComponentRef:destroy() for dynamic objects to correctly remove themselves
|
||||
// Note: this will destroy all children dynamic components as well: gridItem -> childWidget
|
||||
//
|
||||
if (isGrid) {
|
||||
const grid = n.el?._gridComp;
|
||||
if (grid?.ref)
|
||||
grid.ref.destroy();
|
||||
else
|
||||
grid?.ngOnDestroy();
|
||||
}
|
||||
else {
|
||||
const gridItem = n.el?._gridItemComp;
|
||||
if (gridItem?.ref)
|
||||
gridItem.ref.destroy();
|
||||
else
|
||||
gridItem?.ngOnDestroy();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* called for each item in the grid - check if additional information needs to be saved.
|
||||
* Note: since this is options minus gridstack protected members using Utils.removeInternalForSave(),
|
||||
* this typically doesn't need to do anything. However your custom Component @Input() are now supported
|
||||
* using BaseWidget.serialize()
|
||||
*/
|
||||
function gsSaveAdditionalNgInfo(n, w) {
|
||||
const gridItem = n.el?._gridItemComp;
|
||||
if (gridItem) {
|
||||
const input = gridItem.childWidget?.serialize();
|
||||
if (input) {
|
||||
w.input = input;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// else check if Grid
|
||||
const grid = n.el?._gridComp;
|
||||
if (grid) {
|
||||
//.... save any custom data
|
||||
}
|
||||
}
|
||||
/**
|
||||
* track when widgeta re updated (rather than created) to make sure we de-serialize them as well
|
||||
*/
|
||||
function gsUpdateNgComponents(n) {
|
||||
const w = n;
|
||||
const gridItem = n.el?._gridItemComp;
|
||||
if (gridItem?.childWidget && w.input)
|
||||
gridItem.childWidget.deserialize(w);
|
||||
}
|
||||
|
||||
/**
|
||||
* gridstack.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
/**
|
||||
* @deprecated Use GridstackComponent and GridstackItemComponent as standalone components instead.
|
||||
*
|
||||
* This NgModule is provided for backward compatibility but is no longer the recommended approach.
|
||||
* Import components directly in your standalone components or use the new Angular module structure.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Preferred approach - standalone components
|
||||
* @Component({
|
||||
* selector: 'my-app',
|
||||
* imports: [GridstackComponent, GridstackItemComponent],
|
||||
* template: '<gridstack></gridstack>'
|
||||
* })
|
||||
* export class AppComponent {}
|
||||
*
|
||||
* // Legacy approach (deprecated)
|
||||
* @NgModule({
|
||||
* imports: [GridstackModule]
|
||||
* })
|
||||
* export class AppModule {}
|
||||
* ```
|
||||
*/
|
||||
class GridstackModule {
|
||||
}
|
||||
GridstackModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
||||
GridstackModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: GridstackModule, imports: [GridstackItemComponent,
|
||||
GridstackComponent], exports: [GridstackItemComponent,
|
||||
GridstackComponent] });
|
||||
GridstackModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackModule, imports: [GridstackItemComponent,
|
||||
GridstackComponent] });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GridstackModule, decorators: [{
|
||||
type: NgModule,
|
||||
args: [{
|
||||
imports: [
|
||||
GridstackItemComponent,
|
||||
GridstackComponent,
|
||||
],
|
||||
exports: [
|
||||
GridstackItemComponent,
|
||||
GridstackComponent,
|
||||
],
|
||||
}]
|
||||
}] });
|
||||
|
||||
/*
|
||||
* Public API Surface of gridstack-angular
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generated bundle index. Do not edit.
|
||||
*/
|
||||
|
||||
export { BaseWidget, GridstackComponent, GridstackItemComponent, GridstackModule, gsCreateNgComponents, gsSaveAdditionalNgInfo, gsUpdateNgComponents };
|
||||
//# sourceMappingURL=gridstack-angular.mjs.map
|
||||
1
node_modules/gridstack/dist/angular/fesm2020/gridstack-angular.mjs.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/angular/fesm2020/gridstack-angular.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
5
node_modules/gridstack/dist/angular/index.d.ts
generated
vendored
Normal file
5
node_modules/gridstack/dist/angular/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './lib/types';
|
||||
export * from './lib/base-widget';
|
||||
export * from './lib/gridstack-item.component';
|
||||
export * from './lib/gridstack.component';
|
||||
export * from './lib/gridstack.module';
|
||||
55
node_modules/gridstack/dist/angular/lib/base-widget.d.ts
generated
vendored
Normal file
55
node_modules/gridstack/dist/angular/lib/base-widget.d.ts
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
import { NgCompInputs, NgGridStackWidget } from './types';
|
||||
import * as i0 from "@angular/core";
|
||||
/**
|
||||
* Base widget class for GridStack Angular integration.
|
||||
*/
|
||||
export declare abstract class BaseWidget {
|
||||
/**
|
||||
* Complete widget definition including position, size, and Angular-specific data.
|
||||
* Populated automatically when the widget is loaded or saved.
|
||||
*/
|
||||
widgetItem?: NgGridStackWidget;
|
||||
/**
|
||||
* Override this method to return serializable data for this widget.
|
||||
*
|
||||
* Return an object with properties that map to your component's @Input() fields.
|
||||
* The selector is handled automatically, so only include component-specific data.
|
||||
*
|
||||
* @returns Object containing serializable component data
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* serialize() {
|
||||
* return {
|
||||
* title: this.title,
|
||||
* value: this.value,
|
||||
* settings: this.settings
|
||||
* };
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
serialize(): NgCompInputs | undefined;
|
||||
/**
|
||||
* Override this method to handle widget restoration from saved data.
|
||||
*
|
||||
* Use this for complex initialization that goes beyond simple @Input() mapping.
|
||||
* The default implementation automatically assigns input data to component properties.
|
||||
*
|
||||
* @param w The saved widget data including input properties
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* deserialize(w: NgGridStackWidget) {
|
||||
* super.deserialize(w); // Call parent for basic setup
|
||||
*
|
||||
* // Custom initialization logic
|
||||
* if (w.input?.complexData) {
|
||||
* this.processComplexData(w.input.complexData);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
deserialize(w: NgGridStackWidget): void;
|
||||
static ɵfac: i0.ɵɵFactoryDeclaration<BaseWidget, never>;
|
||||
static ɵprov: i0.ɵɵInjectableDeclaration<BaseWidget>;
|
||||
}
|
||||
79
node_modules/gridstack/dist/angular/lib/gridstack-item.component.d.ts
generated
vendored
Normal file
79
node_modules/gridstack/dist/angular/lib/gridstack-item.component.d.ts
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* gridstack-item.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
import { ElementRef, ViewContainerRef, OnDestroy, ComponentRef } from '@angular/core';
|
||||
import { GridItemHTMLElement, GridStackNode } from 'gridstack';
|
||||
import { BaseWidget } from './base-widget';
|
||||
import * as i0 from "@angular/core";
|
||||
/**
|
||||
* Extended HTMLElement interface for grid items.
|
||||
* Stores a back-reference to the Angular component for integration.
|
||||
*/
|
||||
export interface GridItemCompHTMLElement extends GridItemHTMLElement {
|
||||
/** Back-reference to the Angular GridStackItem component */
|
||||
_gridItemComp?: GridstackItemComponent;
|
||||
}
|
||||
/**
|
||||
* Angular component wrapper for individual GridStack items.
|
||||
*
|
||||
* This component represents a single grid item and handles:
|
||||
* - Dynamic content creation and management
|
||||
* - Integration with parent GridStack component
|
||||
* - Component lifecycle and cleanup
|
||||
* - Widget options and configuration
|
||||
*
|
||||
* Use in combination with GridstackComponent for the parent grid.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack>
|
||||
* <gridstack-item [options]="{x: 0, y: 0, w: 2, h: 1}">
|
||||
* <my-widget-component></my-widget-component>
|
||||
* </gridstack-item>
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
export declare class GridstackItemComponent implements OnDestroy {
|
||||
protected readonly elementRef: ElementRef<GridItemCompHTMLElement>;
|
||||
/**
|
||||
* Container for dynamic component creation within this grid item.
|
||||
* Used to append child components programmatically.
|
||||
*/
|
||||
container?: ViewContainerRef;
|
||||
/**
|
||||
* Component reference for dynamic component removal.
|
||||
* Used internally when this component is created dynamically.
|
||||
*/
|
||||
ref: ComponentRef<GridstackItemComponent> | undefined;
|
||||
/**
|
||||
* Reference to child widget component for serialization.
|
||||
* Used to save/restore additional data along with grid position.
|
||||
*/
|
||||
childWidget: BaseWidget | undefined;
|
||||
/**
|
||||
* Grid item configuration options.
|
||||
* Defines position, size, and behavior of this grid item.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* itemOptions: GridStackNode = {
|
||||
* x: 0, y: 0, w: 2, h: 1,
|
||||
* noResize: true,
|
||||
* content: 'Item content'
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
set options(val: GridStackNode);
|
||||
/** return the latest grid options (from GS once built, otherwise initial values) */
|
||||
get options(): GridStackNode;
|
||||
protected _options?: GridStackNode;
|
||||
/** return the native element that contains grid specific fields as well */
|
||||
get el(): GridItemCompHTMLElement;
|
||||
/** clears the initial options now that we've built */
|
||||
clearOptions(): void;
|
||||
constructor(elementRef: ElementRef<GridItemCompHTMLElement>);
|
||||
ngOnDestroy(): void;
|
||||
static ɵfac: i0.ɵɵFactoryDeclaration<GridstackItemComponent, never>;
|
||||
static ɵcmp: i0.ɵɵComponentDeclaration<GridstackItemComponent, "gridstack-item", never, { "options": "options"; }, {}, never, ["*"], true>;
|
||||
}
|
||||
236
node_modules/gridstack/dist/angular/lib/gridstack.component.d.ts
generated
vendored
Normal file
236
node_modules/gridstack/dist/angular/lib/gridstack.component.d.ts
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
* gridstack.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
import { AfterContentInit, ElementRef, EventEmitter, OnDestroy, OnInit, QueryList, Type, ViewContainerRef, ComponentRef } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { GridHTMLElement, GridItemHTMLElement, GridStack, GridStackNode, GridStackOptions } from 'gridstack';
|
||||
import { NgGridStackNode, NgGridStackWidget } from './types';
|
||||
import { GridstackItemComponent } from './gridstack-item.component';
|
||||
import * as i0 from "@angular/core";
|
||||
/**
|
||||
* Event handler callback signatures for different GridStack events.
|
||||
* These types define the structure of data passed to Angular event emitters.
|
||||
*/
|
||||
/** Callback for general events (enable, disable, etc.) */
|
||||
export declare type eventCB = {
|
||||
event: Event;
|
||||
};
|
||||
/** Callback for element-specific events (resize, drag, etc.) */
|
||||
export declare type elementCB = {
|
||||
event: Event;
|
||||
el: GridItemHTMLElement;
|
||||
};
|
||||
/** Callback for events affecting multiple nodes (change, etc.) */
|
||||
export declare type nodesCB = {
|
||||
event: Event;
|
||||
nodes: GridStackNode[];
|
||||
};
|
||||
/** Callback for drop events with before/after node state */
|
||||
export declare type droppedCB = {
|
||||
event: Event;
|
||||
previousNode: GridStackNode;
|
||||
newNode: GridStackNode;
|
||||
};
|
||||
/**
|
||||
* Extended HTMLElement interface for the grid container.
|
||||
* Stores a back-reference to the Angular component for integration purposes.
|
||||
*/
|
||||
export interface GridCompHTMLElement extends GridHTMLElement {
|
||||
/** Back-reference to the Angular GridStack component */
|
||||
_gridComp?: GridstackComponent;
|
||||
}
|
||||
/**
|
||||
* Mapping of selector strings to Angular component types.
|
||||
* Used for dynamic component creation based on widget selectors.
|
||||
*/
|
||||
export declare type SelectorToType = {
|
||||
[key: string]: Type<Object>;
|
||||
};
|
||||
/**
|
||||
* Angular component wrapper for GridStack.
|
||||
*
|
||||
* This component provides Angular integration for GridStack grids, handling:
|
||||
* - Grid initialization and lifecycle
|
||||
* - Dynamic component creation and management
|
||||
* - Event binding and emission
|
||||
* - Integration with Angular change detection
|
||||
*
|
||||
* Use in combination with GridstackItemComponent for individual grid items.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack [options]="gridOptions" (change)="onGridChange($event)">
|
||||
* <div empty-content>Drag widgets here</div>
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
export declare class GridstackComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||
protected readonly elementRef: ElementRef<GridCompHTMLElement>;
|
||||
/**
|
||||
* List of template-based grid items (not recommended approach).
|
||||
* Used to sync between DOM and GridStack internals when items are defined in templates.
|
||||
* Prefer dynamic component creation instead.
|
||||
*/
|
||||
gridstackItems?: QueryList<GridstackItemComponent>;
|
||||
/**
|
||||
* Container for dynamic component creation (recommended approach).
|
||||
* Used to append grid items programmatically at runtime.
|
||||
*/
|
||||
container?: ViewContainerRef;
|
||||
/**
|
||||
* Grid configuration options.
|
||||
* Can be set before grid initialization or updated after grid is created.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* gridOptions: GridStackOptions = {
|
||||
* column: 12,
|
||||
* cellHeight: 'auto',
|
||||
* animate: true
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
set options(o: GridStackOptions);
|
||||
/** Get the current running grid options */
|
||||
get options(): GridStackOptions;
|
||||
/**
|
||||
* Controls whether empty content should be displayed.
|
||||
* Set to true to show ng-content with 'empty-content' selector when grid has no items.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack [isEmpty]="gridItems.length === 0">
|
||||
* <div empty-content>Drag widgets here to get started</div>
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
isEmpty?: boolean;
|
||||
/**
|
||||
* GridStack event emitters for Angular integration.
|
||||
*
|
||||
* These provide Angular-style event handling for GridStack events.
|
||||
* Alternatively, use `this.grid.on('event1 event2', callback)` for multiple events.
|
||||
*
|
||||
* Note: 'CB' suffix prevents conflicts with native DOM events.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack (changeCB)="onGridChange($event)" (droppedCB)="onItemDropped($event)">
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
/** Emitted when widgets are added to the grid */
|
||||
addedCB: EventEmitter<nodesCB>;
|
||||
/** Emitted when grid layout changes */
|
||||
changeCB: EventEmitter<nodesCB>;
|
||||
/** Emitted when grid is disabled */
|
||||
disableCB: EventEmitter<eventCB>;
|
||||
/** Emitted during widget drag operations */
|
||||
dragCB: EventEmitter<elementCB>;
|
||||
/** Emitted when widget drag starts */
|
||||
dragStartCB: EventEmitter<elementCB>;
|
||||
/** Emitted when widget drag stops */
|
||||
dragStopCB: EventEmitter<elementCB>;
|
||||
/** Emitted when widget is dropped */
|
||||
droppedCB: EventEmitter<droppedCB>;
|
||||
/** Emitted when grid is enabled */
|
||||
enableCB: EventEmitter<eventCB>;
|
||||
/** Emitted when widgets are removed from the grid */
|
||||
removedCB: EventEmitter<nodesCB>;
|
||||
/** Emitted during widget resize operations */
|
||||
resizeCB: EventEmitter<elementCB>;
|
||||
/** Emitted when widget resize starts */
|
||||
resizeStartCB: EventEmitter<elementCB>;
|
||||
/** Emitted when widget resize stops */
|
||||
resizeStopCB: EventEmitter<elementCB>;
|
||||
/**
|
||||
* Get the native DOM element that contains grid-specific fields.
|
||||
* This element has GridStack properties attached to it.
|
||||
*/
|
||||
get el(): GridCompHTMLElement;
|
||||
/**
|
||||
* Get the underlying GridStack instance.
|
||||
* Use this to access GridStack API methods directly.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* this.gridComponent.grid.addWidget({x: 0, y: 0, w: 2, h: 1});
|
||||
* ```
|
||||
*/
|
||||
get grid(): GridStack | undefined;
|
||||
/**
|
||||
* Component reference for dynamic component removal.
|
||||
* Used internally when this component is created dynamically.
|
||||
*/
|
||||
ref: ComponentRef<GridstackComponent> | undefined;
|
||||
/**
|
||||
* Mapping of component selectors to their types for dynamic creation.
|
||||
*
|
||||
* This enables dynamic component instantiation from string selectors.
|
||||
* Angular doesn't provide public access to this mapping, so we maintain our own.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* GridstackComponent.addComponentToSelectorType([MyWidgetComponent]);
|
||||
* ```
|
||||
*/
|
||||
static selectorToType: SelectorToType;
|
||||
/**
|
||||
* Register a list of Angular components for dynamic creation.
|
||||
*
|
||||
* @param typeList Array of component types to register
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* GridstackComponent.addComponentToSelectorType([
|
||||
* MyWidgetComponent,
|
||||
* AnotherWidgetComponent
|
||||
* ]);
|
||||
* ```
|
||||
*/
|
||||
static addComponentToSelectorType(typeList: Array<Type<Object>>): void;
|
||||
/**
|
||||
* Extract the selector string from an Angular component type.
|
||||
*
|
||||
* @param type The component type to get selector from
|
||||
* @returns The component's selector string
|
||||
*/
|
||||
static getSelector(type: Type<Object>): string;
|
||||
protected _options?: GridStackOptions;
|
||||
protected _grid?: GridStack;
|
||||
protected _sub: Subscription | undefined;
|
||||
protected loaded?: boolean;
|
||||
constructor(elementRef: ElementRef<GridCompHTMLElement>);
|
||||
ngOnInit(): void;
|
||||
/** wait until after all DOM is ready to init gridstack children (after angular ngFor and sub-components run first) */
|
||||
ngAfterContentInit(): void;
|
||||
ngOnDestroy(): void;
|
||||
/**
|
||||
* called when the TEMPLATE (not recommended) list of items changes - get a list of nodes and
|
||||
* update the layout accordingly (which will take care of adding/removing items changed by Angular)
|
||||
*/
|
||||
updateAll(): void;
|
||||
/** check if the grid is empty, if so show alternative content */
|
||||
checkEmpty(): void;
|
||||
/** get all known events as easy to use Outputs for convenience */
|
||||
protected hookEvents(grid?: GridStack): void;
|
||||
protected unhookEvents(grid?: GridStack): void;
|
||||
static ɵfac: i0.ɵɵFactoryDeclaration<GridstackComponent, never>;
|
||||
static ɵcmp: i0.ɵɵComponentDeclaration<GridstackComponent, "gridstack", never, { "options": "options"; "isEmpty": "isEmpty"; }, { "addedCB": "addedCB"; "changeCB": "changeCB"; "disableCB": "disableCB"; "dragCB": "dragCB"; "dragStartCB": "dragStartCB"; "dragStopCB": "dragStopCB"; "droppedCB": "droppedCB"; "enableCB": "enableCB"; "removedCB": "removedCB"; "resizeCB": "resizeCB"; "resizeStartCB": "resizeStartCB"; "resizeStopCB": "resizeStopCB"; }, ["gridstackItems"], ["[empty-content]", "*"], true>;
|
||||
}
|
||||
/**
|
||||
* can be used when a new item needs to be created, which we do as a Angular component, or deleted (skip)
|
||||
**/
|
||||
export declare function gsCreateNgComponents(host: GridCompHTMLElement | HTMLElement, n: NgGridStackNode, add: boolean, isGrid: boolean): HTMLElement | undefined;
|
||||
/**
|
||||
* called for each item in the grid - check if additional information needs to be saved.
|
||||
* Note: since this is options minus gridstack protected members using Utils.removeInternalForSave(),
|
||||
* this typically doesn't need to do anything. However your custom Component @Input() are now supported
|
||||
* using BaseWidget.serialize()
|
||||
*/
|
||||
export declare function gsSaveAdditionalNgInfo(n: NgGridStackNode, w: NgGridStackWidget): void;
|
||||
/**
|
||||
* track when widgeta re updated (rather than created) to make sure we de-serialize them as well
|
||||
*/
|
||||
export declare function gsUpdateNgComponents(n: NgGridStackNode): void;
|
||||
31
node_modules/gridstack/dist/angular/lib/gridstack.module.d.ts
generated
vendored
Normal file
31
node_modules/gridstack/dist/angular/lib/gridstack.module.d.ts
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
import * as i0 from "@angular/core";
|
||||
import * as i1 from "./gridstack-item.component";
|
||||
import * as i2 from "./gridstack.component";
|
||||
/**
|
||||
* @deprecated Use GridstackComponent and GridstackItemComponent as standalone components instead.
|
||||
*
|
||||
* This NgModule is provided for backward compatibility but is no longer the recommended approach.
|
||||
* Import components directly in your standalone components or use the new Angular module structure.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Preferred approach - standalone components
|
||||
* @Component({
|
||||
* selector: 'my-app',
|
||||
* imports: [GridstackComponent, GridstackItemComponent],
|
||||
* template: '<gridstack></gridstack>'
|
||||
* })
|
||||
* export class AppComponent {}
|
||||
*
|
||||
* // Legacy approach (deprecated)
|
||||
* @NgModule({
|
||||
* imports: [GridstackModule]
|
||||
* })
|
||||
* export class AppModule {}
|
||||
* ```
|
||||
*/
|
||||
export declare class GridstackModule {
|
||||
static ɵfac: i0.ɵɵFactoryDeclaration<GridstackModule, never>;
|
||||
static ɵmod: i0.ɵɵNgModuleDeclaration<GridstackModule, never, [typeof i1.GridstackItemComponent, typeof i2.GridstackComponent], [typeof i1.GridstackItemComponent, typeof i2.GridstackComponent]>;
|
||||
static ɵinj: i0.ɵɵInjectorDeclaration<GridstackModule>;
|
||||
}
|
||||
51
node_modules/gridstack/dist/angular/lib/types.d.ts
generated
vendored
Normal file
51
node_modules/gridstack/dist/angular/lib/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* gridstack-item.component.ts 12.3.3
|
||||
* Copyright (c) 2025 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
import { GridStackNode, GridStackOptions, GridStackWidget } from "gridstack";
|
||||
/**
|
||||
* Extended GridStackWidget interface for Angular integration.
|
||||
* Adds Angular-specific properties for dynamic component creation.
|
||||
*/
|
||||
export interface NgGridStackWidget extends GridStackWidget {
|
||||
/** Angular component selector for dynamic creation (e.g., 'my-widget') */
|
||||
selector?: string;
|
||||
/** Serialized data for component @Input() properties */
|
||||
input?: NgCompInputs;
|
||||
/** Configuration for nested sub-grids */
|
||||
subGridOpts?: NgGridStackOptions;
|
||||
}
|
||||
/**
|
||||
* Extended GridStackNode interface for Angular integration.
|
||||
* Adds component selector for dynamic content creation.
|
||||
*/
|
||||
export interface NgGridStackNode extends GridStackNode {
|
||||
/** Angular component selector for this node's content */
|
||||
selector?: string;
|
||||
}
|
||||
/**
|
||||
* Extended GridStackOptions interface for Angular integration.
|
||||
* Supports Angular-specific widget definitions and nested grids.
|
||||
*/
|
||||
export interface NgGridStackOptions extends GridStackOptions {
|
||||
/** Array of Angular widget definitions for initial grid setup */
|
||||
children?: NgGridStackWidget[];
|
||||
/** Configuration for nested sub-grids (Angular-aware) */
|
||||
subGridOpts?: NgGridStackOptions;
|
||||
}
|
||||
/**
|
||||
* Type for component input data serialization.
|
||||
* Maps @Input() property names to their values for widget persistence.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const inputs: NgCompInputs = {
|
||||
* title: 'My Widget',
|
||||
* value: 42,
|
||||
* config: { enabled: true }
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export declare type NgCompInputs = {
|
||||
[key: string]: any;
|
||||
};
|
||||
31
node_modules/gridstack/dist/angular/package.json
generated
vendored
Normal file
31
node_modules/gridstack/dist/angular/package.json
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "gridstack-angular",
|
||||
"version": "12.3.3",
|
||||
"peerDependencies": {
|
||||
"@angular/common": ">=14",
|
||||
"@angular/core": ">=14"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"module": "fesm2015/gridstack-angular.mjs",
|
||||
"es2020": "fesm2020/gridstack-angular.mjs",
|
||||
"esm2020": "esm2020/gridstack-angular.mjs",
|
||||
"fesm2020": "fesm2020/gridstack-angular.mjs",
|
||||
"fesm2015": "fesm2015/gridstack-angular.mjs",
|
||||
"typings": "index.d.ts",
|
||||
"exports": {
|
||||
"./package.json": {
|
||||
"default": "./package.json"
|
||||
},
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"esm2020": "./esm2020/gridstack-angular.mjs",
|
||||
"es2020": "./fesm2020/gridstack-angular.mjs",
|
||||
"es2015": "./fesm2015/gridstack-angular.mjs",
|
||||
"node": "./fesm2015/gridstack-angular.mjs",
|
||||
"default": "./fesm2020/gridstack-angular.mjs"
|
||||
}
|
||||
},
|
||||
"sideEffects": false
|
||||
}
|
||||
95
node_modules/gridstack/dist/angular/src/base-widget.ts
generated
vendored
Normal file
95
node_modules/gridstack/dist/angular/src/base-widget.ts
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* gridstack-item.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
|
||||
/**
|
||||
* Abstract base class that all custom widgets should extend.
|
||||
*
|
||||
* This class provides the interface needed for GridstackItemComponent to:
|
||||
* - Serialize/deserialize widget data
|
||||
* - Save/restore widget state
|
||||
* - Integrate with Angular lifecycle
|
||||
*
|
||||
* Extend this class when creating custom widgets for dynamic grids.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* selector: 'my-custom-widget',
|
||||
* template: '<div>{{data}}</div>'
|
||||
* })
|
||||
* export class MyCustomWidget extends BaseWidget {
|
||||
* @Input() data: string = '';
|
||||
*
|
||||
* serialize() {
|
||||
* return { data: this.data };
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { NgCompInputs, NgGridStackWidget } from './types';
|
||||
|
||||
/**
|
||||
* Base widget class for GridStack Angular integration.
|
||||
*/
|
||||
@Injectable()
|
||||
export abstract class BaseWidget {
|
||||
|
||||
/**
|
||||
* Complete widget definition including position, size, and Angular-specific data.
|
||||
* Populated automatically when the widget is loaded or saved.
|
||||
*/
|
||||
public widgetItem?: NgGridStackWidget;
|
||||
|
||||
/**
|
||||
* Override this method to return serializable data for this widget.
|
||||
*
|
||||
* Return an object with properties that map to your component's @Input() fields.
|
||||
* The selector is handled automatically, so only include component-specific data.
|
||||
*
|
||||
* @returns Object containing serializable component data
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* serialize() {
|
||||
* return {
|
||||
* title: this.title,
|
||||
* value: this.value,
|
||||
* settings: this.settings
|
||||
* };
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
public serialize(): NgCompInputs | undefined { return; }
|
||||
|
||||
/**
|
||||
* Override this method to handle widget restoration from saved data.
|
||||
*
|
||||
* Use this for complex initialization that goes beyond simple @Input() mapping.
|
||||
* The default implementation automatically assigns input data to component properties.
|
||||
*
|
||||
* @param w The saved widget data including input properties
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* deserialize(w: NgGridStackWidget) {
|
||||
* super.deserialize(w); // Call parent for basic setup
|
||||
*
|
||||
* // Custom initialization logic
|
||||
* if (w.input?.complexData) {
|
||||
* this.processComplexData(w.input.complexData);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
public deserialize(w: NgGridStackWidget) {
|
||||
// save full description for meta data
|
||||
this.widgetItem = w;
|
||||
if (!w) return;
|
||||
|
||||
if (w.input) Object.assign(this, w.input);
|
||||
}
|
||||
}
|
||||
125
node_modules/gridstack/dist/angular/src/gridstack-item.component.ts
generated
vendored
Normal file
125
node_modules/gridstack/dist/angular/src/gridstack-item.component.ts
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* gridstack-item.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
|
||||
import { Component, ElementRef, Input, ViewChild, ViewContainerRef, OnDestroy, ComponentRef } from '@angular/core';
|
||||
import { GridItemHTMLElement, GridStackNode } from 'gridstack';
|
||||
import { BaseWidget } from './base-widget';
|
||||
|
||||
/**
|
||||
* Extended HTMLElement interface for grid items.
|
||||
* Stores a back-reference to the Angular component for integration.
|
||||
*/
|
||||
export interface GridItemCompHTMLElement extends GridItemHTMLElement {
|
||||
/** Back-reference to the Angular GridStackItem component */
|
||||
_gridItemComp?: GridstackItemComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Angular component wrapper for individual GridStack items.
|
||||
*
|
||||
* This component represents a single grid item and handles:
|
||||
* - Dynamic content creation and management
|
||||
* - Integration with parent GridStack component
|
||||
* - Component lifecycle and cleanup
|
||||
* - Widget options and configuration
|
||||
*
|
||||
* Use in combination with GridstackComponent for the parent grid.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack>
|
||||
* <gridstack-item [options]="{x: 0, y: 0, w: 2, h: 1}">
|
||||
* <my-widget-component></my-widget-component>
|
||||
* </gridstack-item>
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
@Component({
|
||||
selector: 'gridstack-item',
|
||||
template: `
|
||||
<div class="grid-stack-item-content">
|
||||
<!-- where dynamic items go based on component selector (recommended way), or sub-grids, etc...) -->
|
||||
<ng-template #container></ng-template>
|
||||
<!-- any static (defined in DOM - not recommended) content goes here -->
|
||||
<ng-content></ng-content>
|
||||
<!-- fallback HTML content from GridStackWidget.content if used instead (not recommended) -->
|
||||
{{options.content}}
|
||||
</div>`,
|
||||
styles: [`
|
||||
:host { display: block; }
|
||||
`],
|
||||
standalone: true,
|
||||
// changeDetection: ChangeDetectionStrategy.OnPush, // IFF you want to optimize and control when ChangeDetection needs to happen...
|
||||
})
|
||||
export class GridstackItemComponent implements OnDestroy {
|
||||
|
||||
/**
|
||||
* Container for dynamic component creation within this grid item.
|
||||
* Used to append child components programmatically.
|
||||
*/
|
||||
@ViewChild('container', { read: ViewContainerRef, static: true}) public container?: ViewContainerRef;
|
||||
|
||||
/**
|
||||
* Component reference for dynamic component removal.
|
||||
* Used internally when this component is created dynamically.
|
||||
*/
|
||||
public ref: ComponentRef<GridstackItemComponent> | undefined;
|
||||
|
||||
/**
|
||||
* Reference to child widget component for serialization.
|
||||
* Used to save/restore additional data along with grid position.
|
||||
*/
|
||||
public childWidget: BaseWidget | undefined;
|
||||
|
||||
/**
|
||||
* Grid item configuration options.
|
||||
* Defines position, size, and behavior of this grid item.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* itemOptions: GridStackNode = {
|
||||
* x: 0, y: 0, w: 2, h: 1,
|
||||
* noResize: true,
|
||||
* content: 'Item content'
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
@Input() public set options(val: GridStackNode) {
|
||||
const grid = this.el.gridstackNode?.grid;
|
||||
if (grid) {
|
||||
// already built, do an update...
|
||||
grid.update(this.el, val);
|
||||
} else {
|
||||
// store our custom element in options so we can update it and not re-create a generic div!
|
||||
this._options = {...val, el: this.el};
|
||||
}
|
||||
}
|
||||
/** return the latest grid options (from GS once built, otherwise initial values) */
|
||||
public get options(): GridStackNode {
|
||||
return this.el.gridstackNode || this._options || {el: this.el};
|
||||
}
|
||||
|
||||
protected _options?: GridStackNode;
|
||||
|
||||
/** return the native element that contains grid specific fields as well */
|
||||
public get el(): GridItemCompHTMLElement { return this.elementRef.nativeElement; }
|
||||
|
||||
/** clears the initial options now that we've built */
|
||||
public clearOptions() {
|
||||
delete this._options;
|
||||
}
|
||||
|
||||
constructor(protected readonly elementRef: ElementRef<GridItemCompHTMLElement>) {
|
||||
this.el._gridItemComp = this;
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.clearOptions();
|
||||
delete this.childWidget
|
||||
delete this.el._gridItemComp;
|
||||
delete this.container;
|
||||
delete this.ref;
|
||||
}
|
||||
}
|
||||
460
node_modules/gridstack/dist/angular/src/gridstack.component.ts
generated
vendored
Normal file
460
node_modules/gridstack/dist/angular/src/gridstack.component.ts
generated
vendored
Normal file
@@ -0,0 +1,460 @@
|
||||
/**
|
||||
* gridstack.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
|
||||
import {
|
||||
AfterContentInit, Component, ContentChildren, ElementRef, EventEmitter, Input,
|
||||
OnDestroy, OnInit, Output, QueryList, Type, ViewChild, ViewContainerRef, reflectComponentType, ComponentRef
|
||||
} from '@angular/core';
|
||||
import { NgIf } from '@angular/common';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { GridHTMLElement, GridItemHTMLElement, GridStack, GridStackNode, GridStackOptions, GridStackWidget } from 'gridstack';
|
||||
|
||||
import { NgGridStackNode, NgGridStackWidget } from './types';
|
||||
import { BaseWidget } from './base-widget';
|
||||
import { GridItemCompHTMLElement, GridstackItemComponent } from './gridstack-item.component';
|
||||
|
||||
/**
|
||||
* Event handler callback signatures for different GridStack events.
|
||||
* These types define the structure of data passed to Angular event emitters.
|
||||
*/
|
||||
|
||||
/** Callback for general events (enable, disable, etc.) */
|
||||
export type eventCB = {event: Event};
|
||||
|
||||
/** Callback for element-specific events (resize, drag, etc.) */
|
||||
export type elementCB = {event: Event, el: GridItemHTMLElement};
|
||||
|
||||
/** Callback for events affecting multiple nodes (change, etc.) */
|
||||
export type nodesCB = {event: Event, nodes: GridStackNode[]};
|
||||
|
||||
/** Callback for drop events with before/after node state */
|
||||
export type droppedCB = {event: Event, previousNode: GridStackNode, newNode: GridStackNode};
|
||||
|
||||
/**
|
||||
* Extended HTMLElement interface for the grid container.
|
||||
* Stores a back-reference to the Angular component for integration purposes.
|
||||
*/
|
||||
export interface GridCompHTMLElement extends GridHTMLElement {
|
||||
/** Back-reference to the Angular GridStack component */
|
||||
_gridComp?: GridstackComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping of selector strings to Angular component types.
|
||||
* Used for dynamic component creation based on widget selectors.
|
||||
*/
|
||||
export type SelectorToType = {[key: string]: Type<Object>};
|
||||
|
||||
/**
|
||||
* Angular component wrapper for GridStack.
|
||||
*
|
||||
* This component provides Angular integration for GridStack grids, handling:
|
||||
* - Grid initialization and lifecycle
|
||||
* - Dynamic component creation and management
|
||||
* - Event binding and emission
|
||||
* - Integration with Angular change detection
|
||||
*
|
||||
* Use in combination with GridstackItemComponent for individual grid items.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack [options]="gridOptions" (change)="onGridChange($event)">
|
||||
* <div empty-content>Drag widgets here</div>
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
@Component({
|
||||
selector: 'gridstack',
|
||||
template: `
|
||||
<!-- content to show when when grid is empty, like instructions on how to add widgets -->
|
||||
<ng-content select="[empty-content]" *ngIf="isEmpty"></ng-content>
|
||||
<!-- where dynamic items go -->
|
||||
<ng-template #container></ng-template>
|
||||
<!-- where template items go -->
|
||||
<ng-content></ng-content>
|
||||
`,
|
||||
styles: [`
|
||||
:host { display: block; }
|
||||
`],
|
||||
standalone: true,
|
||||
imports: [NgIf]
|
||||
// changeDetection: ChangeDetectionStrategy.OnPush, // IFF you want to optimize and control when ChangeDetection needs to happen...
|
||||
})
|
||||
export class GridstackComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||
|
||||
/**
|
||||
* List of template-based grid items (not recommended approach).
|
||||
* Used to sync between DOM and GridStack internals when items are defined in templates.
|
||||
* Prefer dynamic component creation instead.
|
||||
*/
|
||||
@ContentChildren(GridstackItemComponent) public gridstackItems?: QueryList<GridstackItemComponent>;
|
||||
/**
|
||||
* Container for dynamic component creation (recommended approach).
|
||||
* Used to append grid items programmatically at runtime.
|
||||
*/
|
||||
@ViewChild('container', { read: ViewContainerRef, static: true}) public container?: ViewContainerRef;
|
||||
|
||||
/**
|
||||
* Grid configuration options.
|
||||
* Can be set before grid initialization or updated after grid is created.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* gridOptions: GridStackOptions = {
|
||||
* column: 12,
|
||||
* cellHeight: 'auto',
|
||||
* animate: true
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
@Input() public set options(o: GridStackOptions) {
|
||||
if (this._grid) {
|
||||
this._grid.updateOptions(o);
|
||||
} else {
|
||||
this._options = o;
|
||||
}
|
||||
}
|
||||
/** Get the current running grid options */
|
||||
public get options(): GridStackOptions { return this._grid?.opts || this._options || {}; }
|
||||
|
||||
/**
|
||||
* Controls whether empty content should be displayed.
|
||||
* Set to true to show ng-content with 'empty-content' selector when grid has no items.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack [isEmpty]="gridItems.length === 0">
|
||||
* <div empty-content>Drag widgets here to get started</div>
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
@Input() public isEmpty?: boolean;
|
||||
|
||||
/**
|
||||
* GridStack event emitters for Angular integration.
|
||||
*
|
||||
* These provide Angular-style event handling for GridStack events.
|
||||
* Alternatively, use `this.grid.on('event1 event2', callback)` for multiple events.
|
||||
*
|
||||
* Note: 'CB' suffix prevents conflicts with native DOM events.
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <gridstack (changeCB)="onGridChange($event)" (droppedCB)="onItemDropped($event)">
|
||||
* </gridstack>
|
||||
* ```
|
||||
*/
|
||||
|
||||
/** Emitted when widgets are added to the grid */
|
||||
@Output() public addedCB = new EventEmitter<nodesCB>();
|
||||
|
||||
/** Emitted when grid layout changes */
|
||||
@Output() public changeCB = new EventEmitter<nodesCB>();
|
||||
|
||||
/** Emitted when grid is disabled */
|
||||
@Output() public disableCB = new EventEmitter<eventCB>();
|
||||
|
||||
/** Emitted during widget drag operations */
|
||||
@Output() public dragCB = new EventEmitter<elementCB>();
|
||||
|
||||
/** Emitted when widget drag starts */
|
||||
@Output() public dragStartCB = new EventEmitter<elementCB>();
|
||||
|
||||
/** Emitted when widget drag stops */
|
||||
@Output() public dragStopCB = new EventEmitter<elementCB>();
|
||||
|
||||
/** Emitted when widget is dropped */
|
||||
@Output() public droppedCB = new EventEmitter<droppedCB>();
|
||||
|
||||
/** Emitted when grid is enabled */
|
||||
@Output() public enableCB = new EventEmitter<eventCB>();
|
||||
|
||||
/** Emitted when widgets are removed from the grid */
|
||||
@Output() public removedCB = new EventEmitter<nodesCB>();
|
||||
|
||||
/** Emitted during widget resize operations */
|
||||
@Output() public resizeCB = new EventEmitter<elementCB>();
|
||||
|
||||
/** Emitted when widget resize starts */
|
||||
@Output() public resizeStartCB = new EventEmitter<elementCB>();
|
||||
|
||||
/** Emitted when widget resize stops */
|
||||
@Output() public resizeStopCB = new EventEmitter<elementCB>();
|
||||
|
||||
/**
|
||||
* Get the native DOM element that contains grid-specific fields.
|
||||
* This element has GridStack properties attached to it.
|
||||
*/
|
||||
public get el(): GridCompHTMLElement { return this.elementRef.nativeElement; }
|
||||
|
||||
/**
|
||||
* Get the underlying GridStack instance.
|
||||
* Use this to access GridStack API methods directly.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* this.gridComponent.grid.addWidget({x: 0, y: 0, w: 2, h: 1});
|
||||
* ```
|
||||
*/
|
||||
public get grid(): GridStack | undefined { return this._grid; }
|
||||
|
||||
/**
|
||||
* Component reference for dynamic component removal.
|
||||
* Used internally when this component is created dynamically.
|
||||
*/
|
||||
public ref: ComponentRef<GridstackComponent> | undefined;
|
||||
|
||||
/**
|
||||
* Mapping of component selectors to their types for dynamic creation.
|
||||
*
|
||||
* This enables dynamic component instantiation from string selectors.
|
||||
* Angular doesn't provide public access to this mapping, so we maintain our own.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* GridstackComponent.addComponentToSelectorType([MyWidgetComponent]);
|
||||
* ```
|
||||
*/
|
||||
public static selectorToType: SelectorToType = {};
|
||||
/**
|
||||
* Register a list of Angular components for dynamic creation.
|
||||
*
|
||||
* @param typeList Array of component types to register
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* GridstackComponent.addComponentToSelectorType([
|
||||
* MyWidgetComponent,
|
||||
* AnotherWidgetComponent
|
||||
* ]);
|
||||
* ```
|
||||
*/
|
||||
public static addComponentToSelectorType(typeList: Array<Type<Object>>) {
|
||||
typeList.forEach(type => GridstackComponent.selectorToType[ GridstackComponent.getSelector(type) ] = type);
|
||||
}
|
||||
/**
|
||||
* Extract the selector string from an Angular component type.
|
||||
*
|
||||
* @param type The component type to get selector from
|
||||
* @returns The component's selector string
|
||||
*/
|
||||
public static getSelector(type: Type<Object>): string {
|
||||
return reflectComponentType(type)!.selector;
|
||||
}
|
||||
|
||||
protected _options?: GridStackOptions;
|
||||
protected _grid?: GridStack;
|
||||
protected _sub: Subscription | undefined;
|
||||
protected loaded?: boolean;
|
||||
|
||||
constructor(protected readonly elementRef: ElementRef<GridCompHTMLElement>) {
|
||||
// set globally our method to create the right widget type
|
||||
if (!GridStack.addRemoveCB) {
|
||||
GridStack.addRemoveCB = gsCreateNgComponents;
|
||||
}
|
||||
if (!GridStack.saveCB) {
|
||||
GridStack.saveCB = gsSaveAdditionalNgInfo;
|
||||
}
|
||||
if (!GridStack.updateCB) {
|
||||
GridStack.updateCB = gsUpdateNgComponents;
|
||||
}
|
||||
this.el._gridComp = this;
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
// init ourself before any template children are created since we track them below anyway - no need to double create+update widgets
|
||||
this.loaded = !!this.options?.children?.length;
|
||||
this._grid = GridStack.init(this._options, this.el);
|
||||
delete this._options; // GS has it now
|
||||
|
||||
this.checkEmpty();
|
||||
}
|
||||
|
||||
/** wait until after all DOM is ready to init gridstack children (after angular ngFor and sub-components run first) */
|
||||
public ngAfterContentInit(): void {
|
||||
// track whenever the children list changes and update the layout...
|
||||
this._sub = this.gridstackItems?.changes.subscribe(() => this.updateAll());
|
||||
// ...and do this once at least unless we loaded children already
|
||||
if (!this.loaded) this.updateAll();
|
||||
this.hookEvents(this.grid);
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.unhookEvents(this._grid);
|
||||
this._sub?.unsubscribe();
|
||||
this._grid?.destroy();
|
||||
delete this._grid;
|
||||
delete this.el._gridComp;
|
||||
delete this.container;
|
||||
delete this.ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* called when the TEMPLATE (not recommended) list of items changes - get a list of nodes and
|
||||
* update the layout accordingly (which will take care of adding/removing items changed by Angular)
|
||||
*/
|
||||
public updateAll() {
|
||||
if (!this.grid) return;
|
||||
const layout: GridStackWidget[] = [];
|
||||
this.gridstackItems?.forEach(item => {
|
||||
layout.push(item.options);
|
||||
item.clearOptions();
|
||||
});
|
||||
this.grid.load(layout); // efficient that does diffs only
|
||||
}
|
||||
|
||||
/** check if the grid is empty, if so show alternative content */
|
||||
public checkEmpty() {
|
||||
if (!this.grid) return;
|
||||
this.isEmpty = !this.grid.engine.nodes.length;
|
||||
}
|
||||
|
||||
/** get all known events as easy to use Outputs for convenience */
|
||||
protected hookEvents(grid?: GridStack) {
|
||||
if (!grid) return;
|
||||
// nested grids don't have events in v12.1+ so skip
|
||||
if (grid.parentGridNode) return;
|
||||
grid
|
||||
.on('added', (event: Event, nodes: GridStackNode[]) => {
|
||||
const gridComp = (nodes[0].grid?.el as GridCompHTMLElement)._gridComp || this;
|
||||
gridComp.checkEmpty();
|
||||
this.addedCB.emit({event, nodes});
|
||||
})
|
||||
.on('change', (event: Event, nodes: GridStackNode[]) => this.changeCB.emit({event, nodes}))
|
||||
.on('disable', (event: Event) => this.disableCB.emit({event}))
|
||||
.on('drag', (event: Event, el: GridItemHTMLElement) => this.dragCB.emit({event, el}))
|
||||
.on('dragstart', (event: Event, el: GridItemHTMLElement) => this.dragStartCB.emit({event, el}))
|
||||
.on('dragstop', (event: Event, el: GridItemHTMLElement) => this.dragStopCB.emit({event, el}))
|
||||
.on('dropped', (event: Event, previousNode: GridStackNode, newNode: GridStackNode) => this.droppedCB.emit({event, previousNode, newNode}))
|
||||
.on('enable', (event: Event) => this.enableCB.emit({event}))
|
||||
.on('removed', (event: Event, nodes: GridStackNode[]) => {
|
||||
const gridComp = (nodes[0].grid?.el as GridCompHTMLElement)._gridComp || this;
|
||||
gridComp.checkEmpty();
|
||||
this.removedCB.emit({event, nodes});
|
||||
})
|
||||
.on('resize', (event: Event, el: GridItemHTMLElement) => this.resizeCB.emit({event, el}))
|
||||
.on('resizestart', (event: Event, el: GridItemHTMLElement) => this.resizeStartCB.emit({event, el}))
|
||||
.on('resizestop', (event: Event, el: GridItemHTMLElement) => this.resizeStopCB.emit({event, el}))
|
||||
}
|
||||
|
||||
protected unhookEvents(grid?: GridStack) {
|
||||
if (!grid) return;
|
||||
// nested grids don't have events in v12.1+ so skip
|
||||
if (grid.parentGridNode) return;
|
||||
grid.off('added change disable drag dragstart dragstop dropped enable removed resize resizestart resizestop');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* can be used when a new item needs to be created, which we do as a Angular component, or deleted (skip)
|
||||
**/
|
||||
export function gsCreateNgComponents(host: GridCompHTMLElement | HTMLElement, n: NgGridStackNode, add: boolean, isGrid: boolean): HTMLElement | undefined {
|
||||
if (add) {
|
||||
//
|
||||
// create the component dynamically - see https://angular.io/docs/ts/latest/cookbook/dynamic-component-loader.html
|
||||
//
|
||||
if (!host) return;
|
||||
if (isGrid) {
|
||||
// TODO: figure out how to create ng component inside regular Div. need to access app injectors...
|
||||
// if (!container) {
|
||||
// const hostElement: Element = host;
|
||||
// const environmentInjector: EnvironmentInjector;
|
||||
// grid = createComponent(GridstackComponent, {environmentInjector, hostElement})?.instance;
|
||||
// }
|
||||
|
||||
const gridItemComp = (host.parentElement as GridItemCompHTMLElement)?._gridItemComp;
|
||||
if (!gridItemComp) return;
|
||||
// check if gridItem has a child component with 'container' exposed to create under..
|
||||
const container = (gridItemComp.childWidget as any)?.container || gridItemComp.container;
|
||||
const gridRef = container?.createComponent(GridstackComponent);
|
||||
const grid = gridRef?.instance;
|
||||
if (!grid) return;
|
||||
grid.ref = gridRef;
|
||||
grid.options = n;
|
||||
return grid.el;
|
||||
} else {
|
||||
const gridComp = (host as GridCompHTMLElement)._gridComp;
|
||||
const gridItemRef = gridComp?.container?.createComponent(GridstackItemComponent);
|
||||
const gridItem = gridItemRef?.instance;
|
||||
if (!gridItem) return;
|
||||
gridItem.ref = gridItemRef
|
||||
|
||||
// define what type of component to create as child, OR you can do it GridstackItemComponent template, but this is more generic
|
||||
const selector = n.selector;
|
||||
const type = selector ? GridstackComponent.selectorToType[selector] : undefined;
|
||||
if (type) {
|
||||
// shared code to create our selector component
|
||||
const createComp = () => {
|
||||
const childWidget = gridItem.container?.createComponent(type)?.instance as BaseWidget;
|
||||
// if proper BaseWidget subclass, save it and load additional data
|
||||
if (childWidget && typeof childWidget.serialize === 'function' && typeof childWidget.deserialize === 'function') {
|
||||
gridItem.childWidget = childWidget;
|
||||
childWidget.deserialize(n);
|
||||
}
|
||||
}
|
||||
|
||||
const lazyLoad = n.lazyLoad || n.grid?.opts?.lazyLoad && n.lazyLoad !== false;
|
||||
if (lazyLoad) {
|
||||
if (!n.visibleObservable) {
|
||||
n.visibleObservable = new IntersectionObserver(([entry]) => { if (entry.isIntersecting) {
|
||||
n.visibleObservable?.disconnect();
|
||||
delete n.visibleObservable;
|
||||
createComp();
|
||||
}});
|
||||
window.setTimeout(() => n.visibleObservable?.observe(gridItem.el)); // wait until callee sets position attributes
|
||||
}
|
||||
} else createComp();
|
||||
}
|
||||
|
||||
return gridItem.el;
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// REMOVE - have to call ComponentRef:destroy() for dynamic objects to correctly remove themselves
|
||||
// Note: this will destroy all children dynamic components as well: gridItem -> childWidget
|
||||
//
|
||||
if (isGrid) {
|
||||
const grid = (n.el as GridCompHTMLElement)?._gridComp;
|
||||
if (grid?.ref) grid.ref.destroy();
|
||||
else grid?.ngOnDestroy();
|
||||
} else {
|
||||
const gridItem = (n.el as GridItemCompHTMLElement)?._gridItemComp;
|
||||
if (gridItem?.ref) gridItem.ref.destroy();
|
||||
else gridItem?.ngOnDestroy();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* called for each item in the grid - check if additional information needs to be saved.
|
||||
* Note: since this is options minus gridstack protected members using Utils.removeInternalForSave(),
|
||||
* this typically doesn't need to do anything. However your custom Component @Input() are now supported
|
||||
* using BaseWidget.serialize()
|
||||
*/
|
||||
export function gsSaveAdditionalNgInfo(n: NgGridStackNode, w: NgGridStackWidget) {
|
||||
const gridItem = (n.el as GridItemCompHTMLElement)?._gridItemComp;
|
||||
if (gridItem) {
|
||||
const input = gridItem.childWidget?.serialize();
|
||||
if (input) {
|
||||
w.input = input;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// else check if Grid
|
||||
const grid = (n.el as GridCompHTMLElement)?._gridComp;
|
||||
if (grid) {
|
||||
//.... save any custom data
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* track when widgeta re updated (rather than created) to make sure we de-serialize them as well
|
||||
*/
|
||||
export function gsUpdateNgComponents(n: NgGridStackNode) {
|
||||
const w: NgGridStackWidget = n;
|
||||
const gridItem = (n.el as GridItemCompHTMLElement)?._gridItemComp;
|
||||
if (gridItem?.childWidget && w.input) gridItem.childWidget.deserialize(w);
|
||||
}
|
||||
44
node_modules/gridstack/dist/angular/src/gridstack.module.ts
generated
vendored
Normal file
44
node_modules/gridstack/dist/angular/src/gridstack.module.ts
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* gridstack.component.ts 12.3.3
|
||||
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { GridstackItemComponent } from "./gridstack-item.component";
|
||||
import { GridstackComponent } from "./gridstack.component";
|
||||
|
||||
/**
|
||||
* @deprecated Use GridstackComponent and GridstackItemComponent as standalone components instead.
|
||||
*
|
||||
* This NgModule is provided for backward compatibility but is no longer the recommended approach.
|
||||
* Import components directly in your standalone components or use the new Angular module structure.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Preferred approach - standalone components
|
||||
* @Component({
|
||||
* selector: 'my-app',
|
||||
* imports: [GridstackComponent, GridstackItemComponent],
|
||||
* template: '<gridstack></gridstack>'
|
||||
* })
|
||||
* export class AppComponent {}
|
||||
*
|
||||
* // Legacy approach (deprecated)
|
||||
* @NgModule({
|
||||
* imports: [GridstackModule]
|
||||
* })
|
||||
* export class AppModule {}
|
||||
* ```
|
||||
*/
|
||||
@NgModule({
|
||||
imports: [
|
||||
GridstackItemComponent,
|
||||
GridstackComponent,
|
||||
],
|
||||
exports: [
|
||||
GridstackItemComponent,
|
||||
GridstackComponent,
|
||||
],
|
||||
})
|
||||
export class GridstackModule {}
|
||||
54
node_modules/gridstack/dist/angular/src/types.ts
generated
vendored
Normal file
54
node_modules/gridstack/dist/angular/src/types.ts
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* gridstack-item.component.ts 12.3.3
|
||||
* Copyright (c) 2025 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
|
||||
import { GridStackNode, GridStackOptions, GridStackWidget } from "gridstack";
|
||||
|
||||
/**
|
||||
* Extended GridStackWidget interface for Angular integration.
|
||||
* Adds Angular-specific properties for dynamic component creation.
|
||||
*/
|
||||
export interface NgGridStackWidget extends GridStackWidget {
|
||||
/** Angular component selector for dynamic creation (e.g., 'my-widget') */
|
||||
selector?: string;
|
||||
/** Serialized data for component @Input() properties */
|
||||
input?: NgCompInputs;
|
||||
/** Configuration for nested sub-grids */
|
||||
subGridOpts?: NgGridStackOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended GridStackNode interface for Angular integration.
|
||||
* Adds component selector for dynamic content creation.
|
||||
*/
|
||||
export interface NgGridStackNode extends GridStackNode {
|
||||
/** Angular component selector for this node's content */
|
||||
selector?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended GridStackOptions interface for Angular integration.
|
||||
* Supports Angular-specific widget definitions and nested grids.
|
||||
*/
|
||||
export interface NgGridStackOptions extends GridStackOptions {
|
||||
/** Array of Angular widget definitions for initial grid setup */
|
||||
children?: NgGridStackWidget[];
|
||||
/** Configuration for nested sub-grids (Angular-aware) */
|
||||
subGridOpts?: NgGridStackOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type for component input data serialization.
|
||||
* Maps @Input() property names to their values for widget persistence.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const inputs: NgCompInputs = {
|
||||
* title: 'My Widget',
|
||||
* value: 42,
|
||||
* config: { enabled: true }
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export type NgCompInputs = {[key: string]: any};
|
||||
69
node_modules/gridstack/dist/dd-base-impl.d.ts
generated
vendored
Normal file
69
node_modules/gridstack/dist/dd-base-impl.d.ts
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* dd-base-impl.ts 12.3.2
|
||||
* 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/dd-base-impl.js
generated
vendored
Normal file
70
node_modules/gridstack/dist/dd-base-impl.js
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* dd-base-impl.ts 12.3.2
|
||||
* 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/dd-base-impl.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/dd-base-impl.js.map
generated
vendored
Normal 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.2\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/dd-draggable.d.ts
generated
vendored
Normal file
20
node_modules/gridstack/dist/dd-draggable.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* dd-draggable.ts 12.3.2
|
||||
* 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/dd-draggable.js
generated
vendored
Normal file
364
node_modules/gridstack/dist/dd-draggable.js
generated
vendored
Normal file
@@ -0,0 +1,364 @@
|
||||
/**
|
||||
* dd-draggable.ts 12.3.2
|
||||
* 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/dd-draggable.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/dd-draggable.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
26
node_modules/gridstack/dist/dd-droppable.d.ts
generated
vendored
Normal file
26
node_modules/gridstack/dist/dd-droppable.d.ts
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* dd-droppable.ts 12.3.2
|
||||
* 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/dd-droppable.js
generated
vendored
Normal file
149
node_modules/gridstack/dist/dd-droppable.js
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* dd-droppable.ts 12.3.2
|
||||
* 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/dd-droppable.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/dd-droppable.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
27
node_modules/gridstack/dist/dd-element.d.ts
generated
vendored
Normal file
27
node_modules/gridstack/dist/dd-element.d.ts
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* dd-elements.ts 12.3.2
|
||||
* 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/dd-element.js
generated
vendored
Normal file
91
node_modules/gridstack/dist/dd-element.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* dd-elements.ts 12.3.2
|
||||
* 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/dd-element.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/dd-element.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
82
node_modules/gridstack/dist/dd-gridstack.d.ts
generated
vendored
Normal file
82
node_modules/gridstack/dist/dd-gridstack.d.ts
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* dd-gridstack.ts 12.3.2
|
||||
* 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/dd-gridstack.js
generated
vendored
Normal file
165
node_modules/gridstack/dist/dd-gridstack.js
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* dd-gridstack.ts 12.3.2
|
||||
* 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/dd-gridstack.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/dd-gridstack.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
43
node_modules/gridstack/dist/dd-manager.d.ts
generated
vendored
Normal file
43
node_modules/gridstack/dist/dd-manager.d.ts
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* dd-manager.ts 12.3.2
|
||||
* 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/dd-manager.js
generated
vendored
Normal file
14
node_modules/gridstack/dist/dd-manager.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* dd-manager.ts 12.3.2
|
||||
* 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/dd-manager.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/dd-manager.js.map
generated
vendored
Normal 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.2\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"]}
|
||||
18
node_modules/gridstack/dist/dd-resizable-handle.d.ts
generated
vendored
Normal file
18
node_modules/gridstack/dist/dd-resizable-handle.d.ts
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* dd-resizable-handle.ts 12.3.2
|
||||
* 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/dd-resizable-handle.js
generated
vendored
Normal file
113
node_modules/gridstack/dist/dd-resizable-handle.js
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* dd-resizable-handle.ts 12.3.2
|
||||
* 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
|
||||
1
node_modules/gridstack/dist/dd-resizable-handle.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/dd-resizable-handle.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
30
node_modules/gridstack/dist/dd-resizable.d.ts
generated
vendored
Normal file
30
node_modules/gridstack/dist/dd-resizable.d.ts
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* dd-resizable.ts 12.3.2
|
||||
* 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/dd-resizable.js
generated
vendored
Normal file
304
node_modules/gridstack/dist/dd-resizable.js
generated
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
/**
|
||||
* dd-resizable.ts 12.3.2
|
||||
* 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/dd-resizable.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/dd-resizable.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
33
node_modules/gridstack/dist/dd-touch.d.ts
generated
vendored
Normal file
33
node_modules/gridstack/dist/dd-touch.d.ts
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* touch.ts 12.3.2
|
||||
* 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/dd-touch.js
generated
vendored
Normal file
145
node_modules/gridstack/dist/dd-touch.js
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* touch.ts 12.3.2
|
||||
* 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/dd-touch.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/dd-touch.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
3
node_modules/gridstack/dist/gridstack-all.js
generated
vendored
Normal file
3
node_modules/gridstack/dist/gridstack-all.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
7
node_modules/gridstack/dist/gridstack-all.js.LICENSE.txt
generated
vendored
Normal file
7
node_modules/gridstack/dist/gridstack-all.js.LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* 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
|
||||
*/
|
||||
1
node_modules/gridstack/dist/gridstack-all.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/gridstack-all.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
321
node_modules/gridstack/dist/gridstack-engine.d.ts
generated
vendored
Normal file
321
node_modules/gridstack/dist/gridstack-engine.d.ts
generated
vendored
Normal file
@@ -0,0 +1,321 @@
|
||||
/**
|
||||
* gridstack-engine.ts 12.3.2
|
||||
* 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/gridstack-engine.js
generated
vendored
Normal file
1272
node_modules/gridstack/dist/gridstack-engine.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
node_modules/gridstack/dist/gridstack-engine.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/gridstack-engine.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
174
node_modules/gridstack/dist/gridstack.css
generated
vendored
Normal file
174
node_modules/gridstack/dist/gridstack.css
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* gridstack SASS styles 12.3.3
|
||||
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
.grid-stack {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.grid-stack-rtl {
|
||||
direction: ltr;
|
||||
}
|
||||
.grid-stack-rtl > .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;
|
||||
}
|
||||
|
||||
.grid-stack > .grid-stack-item {
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: var(--gs-column-width);
|
||||
height: var(--gs-cell-height);
|
||||
}
|
||||
.grid-stack > .grid-stack-item > .grid-stack-item-content {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
width: auto;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.grid-stack > .grid-stack-item.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 > .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;
|
||||
}
|
||||
.grid-stack-item.ui-resizable-disabled > .ui-resizable-handle, .grid-stack-item.ui-resizable-autohide > .ui-resizable-handle {
|
||||
display: none;
|
||||
}
|
||||
.grid-stack-item > .ui-resizable-ne,
|
||||
.grid-stack-item > .ui-resizable-nw,
|
||||
.grid-stack-item > .ui-resizable-se,
|
||||
.grid-stack-item > .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;
|
||||
}
|
||||
.grid-stack-item > .ui-resizable-ne {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.grid-stack-item > .ui-resizable-sw {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.grid-stack-item > .ui-resizable-nw {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
.grid-stack-item > .ui-resizable-se {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
.grid-stack-item > .ui-resizable-nw {
|
||||
cursor: nw-resize;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
top: var(--gs-item-margin-top);
|
||||
left: var(--gs-item-margin-left);
|
||||
}
|
||||
.grid-stack-item > .ui-resizable-n {
|
||||
cursor: n-resize;
|
||||
height: 10px;
|
||||
top: var(--gs-item-margin-top);
|
||||
left: 25px;
|
||||
right: 25px;
|
||||
}
|
||||
.grid-stack-item > .ui-resizable-ne {
|
||||
cursor: ne-resize;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
top: var(--gs-item-margin-top);
|
||||
right: var(--gs-item-margin-right);
|
||||
}
|
||||
.grid-stack-item > .ui-resizable-e {
|
||||
cursor: e-resize;
|
||||
width: 10px;
|
||||
top: 15px;
|
||||
bottom: 15px;
|
||||
right: var(--gs-item-margin-right);
|
||||
}
|
||||
.grid-stack-item > .ui-resizable-se {
|
||||
cursor: se-resize;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
bottom: var(--gs-item-margin-bottom);
|
||||
right: var(--gs-item-margin-right);
|
||||
}
|
||||
.grid-stack-item > .ui-resizable-s {
|
||||
cursor: s-resize;
|
||||
height: 10px;
|
||||
left: 25px;
|
||||
bottom: var(--gs-item-margin-bottom);
|
||||
right: 25px;
|
||||
}
|
||||
.grid-stack-item > .ui-resizable-sw {
|
||||
cursor: sw-resize;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
bottom: var(--gs-item-margin-bottom);
|
||||
left: var(--gs-item-margin-left);
|
||||
}
|
||||
.grid-stack-item > .ui-resizable-w {
|
||||
cursor: w-resize;
|
||||
width: 10px;
|
||||
top: 15px;
|
||||
bottom: 15px;
|
||||
left: var(--gs-item-margin-left);
|
||||
}
|
||||
.grid-stack-item.ui-draggable-dragging > .ui-resizable-handle {
|
||||
display: none !important;
|
||||
}
|
||||
.grid-stack-item.ui-draggable-dragging {
|
||||
will-change: left, top;
|
||||
}
|
||||
.grid-stack-item.ui-resizable-resizing {
|
||||
will-change: width, height;
|
||||
}
|
||||
|
||||
.ui-draggable-dragging,
|
||||
.ui-resizable-resizing {
|
||||
z-index: 10000;
|
||||
}
|
||||
.ui-draggable-dragging > .grid-stack-item-content,
|
||||
.ui-resizable-resizing > .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 {
|
||||
transition: left 0.3s, top 0.3s, height 0.3s, width 0.3s;
|
||||
}
|
||||
|
||||
.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 {
|
||||
transition: left 0s, top 0s, height 0s, width 0s;
|
||||
}
|
||||
|
||||
.grid-stack > .grid-stack-item[gs-y="0"] {
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.grid-stack > .grid-stack-item[gs-x="0"] {
|
||||
left: 0%;
|
||||
}
|
||||
802
node_modules/gridstack/dist/gridstack.d.ts
generated
vendored
Normal file
802
node_modules/gridstack/dist/gridstack.d.ts
generated
vendored
Normal file
@@ -0,0 +1,802 @@
|
||||
/*!
|
||||
* GridStack 12.3.2
|
||||
* 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/gridstack.js
generated
vendored
Normal file
2872
node_modules/gridstack/dist/gridstack.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
node_modules/gridstack/dist/gridstack.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/gridstack.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/gridstack/dist/gridstack.min.css
generated
vendored
Normal file
1
node_modules/gridstack/dist/gridstack.min.css
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.grid-stack{position:relative}.grid-stack-rtl{direction:ltr}.grid-stack-rtl>.grid-stack-item{direction:rtl}.grid-stack-placeholder>.placeholder-content{background-color:rgba(0,0,0,.1);margin:0;position:absolute;width:auto;z-index:0!important}.grid-stack>.grid-stack-item{position:absolute;padding:0;top:0;left:0;width:var(--gs-column-width);height:var(--gs-cell-height)}.grid-stack>.grid-stack-item>.grid-stack-item-content{margin:0;position:absolute;width:auto;overflow-x:hidden;overflow-y:auto}.grid-stack>.grid-stack-item.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>.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:.1px;display:block;-ms-touch-action:none;touch-action:none}.grid-stack-item.ui-resizable-autohide>.ui-resizable-handle,.grid-stack-item.ui-resizable-disabled>.ui-resizable-handle{display:none}.grid-stack-item>.ui-resizable-ne,.grid-stack-item>.ui-resizable-nw,.grid-stack-item>.ui-resizable-se,.grid-stack-item>.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}.grid-stack-item>.ui-resizable-ne{transform:rotate(45deg)}.grid-stack-item>.ui-resizable-sw{transform:rotate(45deg)}.grid-stack-item>.ui-resizable-nw{transform:rotate(-45deg)}.grid-stack-item>.ui-resizable-se{transform:rotate(-45deg)}.grid-stack-item>.ui-resizable-nw{cursor:nw-resize;width:20px;height:20px;top:var(--gs-item-margin-top);left:var(--gs-item-margin-left)}.grid-stack-item>.ui-resizable-n{cursor:n-resize;height:10px;top:var(--gs-item-margin-top);left:25px;right:25px}.grid-stack-item>.ui-resizable-ne{cursor:ne-resize;width:20px;height:20px;top:var(--gs-item-margin-top);right:var(--gs-item-margin-right)}.grid-stack-item>.ui-resizable-e{cursor:e-resize;width:10px;top:15px;bottom:15px;right:var(--gs-item-margin-right)}.grid-stack-item>.ui-resizable-se{cursor:se-resize;width:20px;height:20px;bottom:var(--gs-item-margin-bottom);right:var(--gs-item-margin-right)}.grid-stack-item>.ui-resizable-s{cursor:s-resize;height:10px;left:25px;bottom:var(--gs-item-margin-bottom);right:25px}.grid-stack-item>.ui-resizable-sw{cursor:sw-resize;width:20px;height:20px;bottom:var(--gs-item-margin-bottom);left:var(--gs-item-margin-left)}.grid-stack-item>.ui-resizable-w{cursor:w-resize;width:10px;top:15px;bottom:15px;left:var(--gs-item-margin-left)}.grid-stack-item.ui-draggable-dragging>.ui-resizable-handle{display:none!important}.grid-stack-item.ui-draggable-dragging{will-change:left,top}.grid-stack-item.ui-resizable-resizing{will-change:width,height}.ui-draggable-dragging,.ui-resizable-resizing{z-index:10000}.ui-draggable-dragging>.grid-stack-item-content,.ui-resizable-resizing>.grid-stack-item-content{box-shadow:1px 4px 6px rgba(0,0,0,.2);opacity:.8}.grid-stack-animate,.grid-stack-animate .grid-stack-item{transition:left .3s,top .3s,height .3s,width .3s}.grid-stack-animate .grid-stack-item.grid-stack-placeholder,.grid-stack-animate .grid-stack-item.ui-draggable-dragging,.grid-stack-animate .grid-stack-item.ui-resizable-resizing{transition:left 0s,top 0s,height 0s,width 0s}.grid-stack>.grid-stack-item[gs-y="0"]{top:0}.grid-stack>.grid-stack-item[gs-x="0"]{left:0}
|
||||
1
node_modules/gridstack/dist/spec/gridstack-engine-spec.d.ts
generated
vendored
Normal file
1
node_modules/gridstack/dist/spec/gridstack-engine-spec.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
358
node_modules/gridstack/dist/spec/gridstack-engine-spec.js
generated
vendored
Normal file
358
node_modules/gridstack/dist/spec/gridstack-engine-spec.js
generated
vendored
Normal file
@@ -0,0 +1,358 @@
|
||||
import { GridStackEngine } from '../src/gridstack-engine';
|
||||
describe('gridstack engine:', () => {
|
||||
'use strict';
|
||||
let e;
|
||||
let ePriv; // cast engine for private vars access
|
||||
let findNode = function (id) {
|
||||
return e.nodes.find(n => n.id === id);
|
||||
};
|
||||
it('should exist setup function.', () => {
|
||||
expect(GridStackEngine).not.toBeNull();
|
||||
expect(typeof GridStackEngine).toBe('function');
|
||||
});
|
||||
describe('test constructor >', () => {
|
||||
it('should be setup properly', () => {
|
||||
ePriv = e = new GridStackEngine();
|
||||
expect(e.column).toEqual(12);
|
||||
expect(e.float).toEqual(false);
|
||||
expect(e.maxRow).toEqual(undefined);
|
||||
expect(e.nodes).toEqual([]);
|
||||
expect(e.batchMode).toEqual(undefined);
|
||||
expect(ePriv.onChange).toEqual(undefined);
|
||||
});
|
||||
it('should set params correctly.', () => {
|
||||
let fkt = () => { };
|
||||
let arr = [1, 2, 3];
|
||||
ePriv = e = new GridStackEngine({ column: 1, onChange: fkt, float: true, maxRow: 2, nodes: arr });
|
||||
expect(e.column).toEqual(1);
|
||||
expect(e.float).toBe(true);
|
||||
expect(e.maxRow).toEqual(2);
|
||||
expect(e.nodes).toEqual(arr);
|
||||
expect(e.batchMode).toEqual(undefined);
|
||||
expect(ePriv.onChange).toEqual(fkt);
|
||||
});
|
||||
});
|
||||
describe('batch update', () => {
|
||||
it('should set float and batchMode when calling batchUpdate.', () => {
|
||||
ePriv = e = new GridStackEngine({ float: true });
|
||||
e.batchUpdate();
|
||||
expect(e.float).toBe(true);
|
||||
expect(e.batchMode).toBe(true);
|
||||
});
|
||||
});
|
||||
describe('test prepareNode >', () => {
|
||||
beforeAll(() => {
|
||||
ePriv = e = new GridStackEngine();
|
||||
});
|
||||
it('should prepare a node', () => {
|
||||
expect(e.prepareNode({}, false)).toEqual(expect.objectContaining({ x: 0, y: 0, h: 1 }));
|
||||
expect(e.prepareNode({ x: 10 }, false)).toEqual(expect.objectContaining({ x: 10, y: 0, h: 1 }));
|
||||
expect(e.prepareNode({ x: -10 }, false)).toEqual(expect.objectContaining({ x: 0, y: 0, h: 1 }));
|
||||
expect(e.prepareNode({ y: 10 }, false)).toEqual(expect.objectContaining({ x: 0, y: 10, h: 1 }));
|
||||
expect(e.prepareNode({ y: -10 }, false)).toEqual(expect.objectContaining({ x: 0, y: 0, h: 1 }));
|
||||
expect(e.prepareNode({ w: 3 }, false)).toEqual(expect.objectContaining({ x: 0, y: 0, w: 3, h: 1 }));
|
||||
expect(e.prepareNode({ w: 100 }, false)).toEqual(expect.objectContaining({ x: 0, y: 0, w: 12, h: 1 }));
|
||||
expect(e.prepareNode({ w: 0 }, false)).toEqual(expect.objectContaining({ x: 0, y: 0, h: 1 }));
|
||||
expect(e.prepareNode({ w: -190 }, false)).toEqual(expect.objectContaining({ x: 0, y: 0, h: 1 }));
|
||||
expect(e.prepareNode({ h: 3 }, false)).toEqual(expect.objectContaining({ x: 0, y: 0, h: 3 }));
|
||||
expect(e.prepareNode({ h: 0 }, false)).toEqual(expect.objectContaining({ x: 0, y: 0, h: 1 }));
|
||||
expect(e.prepareNode({ h: -10 }, false)).toEqual(expect.objectContaining({ x: 0, y: 0, h: 1 }));
|
||||
expect(e.prepareNode({ x: 4, w: 10 }, false)).toEqual(expect.objectContaining({ x: 2, y: 0, w: 10, h: 1 }));
|
||||
expect(e.prepareNode({ x: 4, w: 10 }, true)).toEqual(expect.objectContaining({ x: 4, y: 0, w: 8, h: 1 }));
|
||||
});
|
||||
});
|
||||
describe('sorting of nodes >', () => {
|
||||
beforeAll(() => {
|
||||
ePriv = e = new GridStackEngine();
|
||||
e.nodes = [{ x: 7, y: 0 }, { x: 4, y: 4 }, { x: 9, y: 0 }, { x: 0, y: 1 }];
|
||||
});
|
||||
it('should sort ascending with 12 columns.', () => {
|
||||
e.sortNodes(1);
|
||||
expect(e.nodes).toEqual([{ x: 7, y: 0 }, { x: 9, y: 0 }, { x: 0, y: 1 }, { x: 4, y: 4 }]);
|
||||
});
|
||||
it('should sort descending with 12 columns.', () => {
|
||||
e.sortNodes(-1);
|
||||
expect(e.nodes).toEqual([{ x: 4, y: 4 }, { x: 0, y: 1 }, { x: 9, y: 0 }, { x: 7, y: 0 }]);
|
||||
});
|
||||
it('should sort ascending without columns.', () => {
|
||||
ePriv.column = undefined;
|
||||
e.sortNodes(1);
|
||||
expect(e.nodes).toEqual([{ x: 7, y: 0 }, { x: 9, y: 0 }, { x: 0, y: 1 }, { x: 4, y: 4 }]);
|
||||
});
|
||||
it('should sort descending without columns.', () => {
|
||||
ePriv.column = undefined;
|
||||
e.sortNodes(-1);
|
||||
expect(e.nodes).toEqual([{ x: 4, y: 4 }, { x: 0, y: 1 }, { x: 9, y: 0 }, { x: 7, y: 0 }]);
|
||||
});
|
||||
});
|
||||
describe('test isAreaEmpty >', () => {
|
||||
beforeAll(() => {
|
||||
ePriv = e = new GridStackEngine({ float: true });
|
||||
e.nodes = [
|
||||
e.prepareNode({ x: 3, y: 2, w: 3, h: 2 })
|
||||
];
|
||||
});
|
||||
it('should be true', () => {
|
||||
expect(e.isAreaEmpty(0, 0, 3, 2)).toEqual(true);
|
||||
expect(e.isAreaEmpty(3, 4, 3, 2)).toEqual(true);
|
||||
});
|
||||
it('should be false', () => {
|
||||
expect(e.isAreaEmpty(1, 1, 3, 2)).toEqual(false);
|
||||
expect(e.isAreaEmpty(2, 3, 3, 2)).toEqual(false);
|
||||
});
|
||||
});
|
||||
describe('test cleanNodes/getDirtyNodes >', () => {
|
||||
beforeAll(() => {
|
||||
ePriv = e = new GridStackEngine({ float: true });
|
||||
e.nodes = [
|
||||
e.prepareNode({ x: 0, y: 0, id: '1', _dirty: true }),
|
||||
e.prepareNode({ x: 3, y: 2, w: 3, h: 2, id: '2', _dirty: true }),
|
||||
e.prepareNode({ x: 3, y: 7, w: 3, h: 2, id: '3' })
|
||||
];
|
||||
});
|
||||
beforeEach(() => {
|
||||
delete ePriv.batchMode;
|
||||
});
|
||||
it('should return all dirty nodes', () => {
|
||||
let nodes = e.getDirtyNodes();
|
||||
expect(nodes.length).toEqual(2);
|
||||
expect(nodes[0].id).toEqual('1');
|
||||
expect(nodes[1].id).toEqual('2');
|
||||
});
|
||||
it('should\'n clean nodes if batchMode true', () => {
|
||||
e.batchMode = true;
|
||||
e.cleanNodes();
|
||||
expect(e.getDirtyNodes().length).toBeGreaterThan(0);
|
||||
});
|
||||
it('should clean all dirty nodes', () => {
|
||||
e.cleanNodes();
|
||||
expect(e.getDirtyNodes().length).toEqual(0);
|
||||
});
|
||||
});
|
||||
describe('test batchUpdate/commit >', () => {
|
||||
beforeAll(() => {
|
||||
ePriv = e = new GridStackEngine();
|
||||
});
|
||||
it('should work on not float grids', () => {
|
||||
expect(e.float).toEqual(false);
|
||||
e.batchUpdate();
|
||||
e.batchUpdate(); // double for code coverage
|
||||
expect(e.batchMode).toBe(true);
|
||||
expect(e.float).toEqual(true);
|
||||
e.batchUpdate(false);
|
||||
e.batchUpdate(false);
|
||||
expect(e.batchMode).not.toBe(true);
|
||||
expect(e.float).not.toBe(true);
|
||||
});
|
||||
it('should work on float grids', () => {
|
||||
e.float = true;
|
||||
e.batchUpdate();
|
||||
expect(e.batchMode).toBe(true);
|
||||
expect(e.float).toEqual(true);
|
||||
e.batchUpdate(false);
|
||||
expect(e.batchMode).not.toBe(true);
|
||||
expect(e.float).toEqual(true);
|
||||
});
|
||||
});
|
||||
describe('test batchUpdate/commit >', () => {
|
||||
beforeAll(() => {
|
||||
ePriv = e = new GridStackEngine({ float: true });
|
||||
});
|
||||
it('should work on float grids', () => {
|
||||
expect(e.float).toEqual(true);
|
||||
e.batchUpdate();
|
||||
expect(e.batchMode).toBe(true);
|
||||
expect(e.float).toEqual(true);
|
||||
e.batchUpdate(false);
|
||||
expect(e.batchMode).not.toBe(true);
|
||||
expect(e.float).toEqual(true);
|
||||
});
|
||||
});
|
||||
describe('test _notify >', () => {
|
||||
let spy;
|
||||
beforeEach(() => {
|
||||
spy = {
|
||||
callback: () => { }
|
||||
};
|
||||
vi.spyOn(spy, 'callback');
|
||||
ePriv = e = new GridStackEngine({ float: true, onChange: spy.callback });
|
||||
e.nodes = [
|
||||
e.prepareNode({ x: 0, y: 0, id: '1', _dirty: true }),
|
||||
e.prepareNode({ x: 3, y: 2, w: 3, h: 2, id: '2', _dirty: true }),
|
||||
e.prepareNode({ x: 3, y: 7, w: 3, h: 2, id: '3' })
|
||||
];
|
||||
});
|
||||
it('should\'n be called if batchMode true', () => {
|
||||
e.batchMode = true;
|
||||
ePriv._notify();
|
||||
expect(spy.callback).not.toHaveBeenCalled();
|
||||
});
|
||||
it('should by called with dirty nodes', () => {
|
||||
ePriv._notify();
|
||||
expect(spy.callback).toHaveBeenCalledWith([e.nodes[0], e.nodes[1]]);
|
||||
});
|
||||
it('should by called with extra passed node to be removed', () => {
|
||||
let n1 = { id: -1 };
|
||||
ePriv._notify([n1]);
|
||||
expect(spy.callback).toHaveBeenCalledWith([n1, e.nodes[0], e.nodes[1]]);
|
||||
});
|
||||
});
|
||||
describe('test _packNodes >', () => {
|
||||
describe('using float:false mode >', () => {
|
||||
beforeEach(() => {
|
||||
ePriv = e = new GridStackEngine({ float: false });
|
||||
});
|
||||
it('shouldn\'t pack one node with y coord eq 0', () => {
|
||||
e.nodes = [
|
||||
e.prepareNode({ x: 0, y: 0, w: 1, h: 1, id: '1' }),
|
||||
];
|
||||
ePriv._packNodes();
|
||||
expect(findNode('1')).toEqual(expect.objectContaining({ x: 0, y: 0, h: 1 }));
|
||||
expect(findNode('1')._dirty).toBeFalsy();
|
||||
});
|
||||
it('should pack one node correctly', () => {
|
||||
e.nodes = [
|
||||
e.prepareNode({ x: 0, y: 1, w: 1, h: 1, id: '1' }),
|
||||
];
|
||||
ePriv._packNodes();
|
||||
expect(findNode('1')).toEqual(expect.objectContaining({ x: 0, y: 0, _dirty: true }));
|
||||
});
|
||||
it('should pack nodes correctly', () => {
|
||||
e.nodes = [
|
||||
e.prepareNode({ x: 0, y: 1, w: 1, h: 1, id: '1' }),
|
||||
e.prepareNode({ x: 0, y: 5, w: 1, h: 1, id: '2' }),
|
||||
];
|
||||
ePriv._packNodes();
|
||||
expect(findNode('1')).toEqual(expect.objectContaining({ x: 0, y: 0, _dirty: true }));
|
||||
expect(findNode('2')).toEqual(expect.objectContaining({ x: 0, y: 1, _dirty: true }));
|
||||
});
|
||||
it('should pack reverse nodes correctly', () => {
|
||||
e.nodes = [
|
||||
e.prepareNode({ x: 0, y: 5, w: 1, h: 1, id: '1' }),
|
||||
e.prepareNode({ x: 0, y: 1, w: 1, h: 1, id: '2' }),
|
||||
];
|
||||
ePriv._packNodes();
|
||||
expect(findNode('2')).toEqual(expect.objectContaining({ x: 0, y: 0, _dirty: true }));
|
||||
expect(findNode('1')).toEqual(expect.objectContaining({ x: 0, y: 1, _dirty: true }));
|
||||
});
|
||||
it('should respect locked nodes', () => {
|
||||
e.nodes = [
|
||||
e.prepareNode({ x: 0, y: 1, w: 1, h: 1, id: '1', locked: true }),
|
||||
e.prepareNode({ x: 0, y: 5, w: 1, h: 1, id: '2' }),
|
||||
];
|
||||
ePriv._packNodes();
|
||||
expect(findNode('1')).toEqual(expect.objectContaining({ x: 0, y: 1, h: 1 }));
|
||||
expect(findNode('1')._dirty).toBeFalsy();
|
||||
expect(findNode('2')).toEqual(expect.objectContaining({ x: 0, y: 2, _dirty: true }));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('test changedPos >', () => {
|
||||
beforeAll(() => {
|
||||
ePriv = e = new GridStackEngine();
|
||||
});
|
||||
it('should return true for changed x', () => {
|
||||
let widget = { x: 1, y: 2, w: 3, h: 4 };
|
||||
expect(e.changedPosConstrain(widget, { x: 2, y: 2 })).toEqual(true);
|
||||
});
|
||||
it('should return true for changed y', () => {
|
||||
let widget = { x: 1, y: 2, w: 3, h: 4 };
|
||||
expect(e.changedPosConstrain(widget, { x: 1, y: 1 })).toEqual(true);
|
||||
});
|
||||
it('should return true for changed width', () => {
|
||||
let widget = { x: 1, y: 2, w: 3, h: 4 };
|
||||
expect(e.changedPosConstrain(widget, { x: 2, y: 2, w: 4, h: 4 })).toEqual(true);
|
||||
});
|
||||
it('should return true for changed height', () => {
|
||||
let widget = { x: 1, y: 2, w: 3, h: 4 };
|
||||
expect(e.changedPosConstrain(widget, { x: 1, y: 2, w: 3, h: 3 })).toEqual(true);
|
||||
});
|
||||
it('should return false for unchanged position', () => {
|
||||
let widget = { x: 1, y: 2, w: 3, h: 4 };
|
||||
expect(e.changedPosConstrain(widget, { x: 1, y: 2, w: 3, h: 4 })).toEqual(false);
|
||||
});
|
||||
});
|
||||
describe('test locked widget >', () => {
|
||||
beforeAll(() => {
|
||||
ePriv = e = new GridStackEngine();
|
||||
});
|
||||
it('should add widgets around locked one', () => {
|
||||
let nodes = [
|
||||
{ x: 0, y: 1, w: 12, h: 1, locked: true, noMove: true, noResize: true, id: '0' },
|
||||
{ x: 1, y: 0, w: 2, h: 3, id: '1' }
|
||||
];
|
||||
// add locked item
|
||||
e.addNode(nodes[0]);
|
||||
expect(findNode('0')).toEqual(expect.objectContaining({ x: 0, y: 1, w: 12, h: 1, locked: true }));
|
||||
// add item that moves past locked one
|
||||
e.addNode(nodes[1]);
|
||||
expect(findNode('0')).toEqual(expect.objectContaining({ x: 0, y: 1, w: 12, h: 1, locked: true }));
|
||||
expect(findNode('1')).toEqual(expect.objectContaining({ x: 1, y: 2, h: 3 }));
|
||||
// locked item can still be moved directly (what user does)
|
||||
let node0 = findNode('0');
|
||||
expect(e.moveNode(node0, { y: 6 })).toEqual(true);
|
||||
expect(findNode('0')).toEqual(expect.objectContaining({ x: 0, y: 6, h: 1, locked: true }));
|
||||
// but moves regular one past it
|
||||
let node1 = findNode('1');
|
||||
expect(e.moveNode(node1, { x: 6, y: 6 })).toEqual(true);
|
||||
expect(node1).toEqual(expect.objectContaining({ x: 6, y: 7, w: 2, h: 3 }));
|
||||
// but moves regular one before (gravity ON)
|
||||
e.float = false;
|
||||
expect(e.moveNode(node1, { x: 7, y: 3 })).toEqual(true);
|
||||
expect(node1).toEqual(expect.objectContaining({ x: 7, y: 0, w: 2, h: 3 }));
|
||||
// but moves regular one before (gravity OFF)
|
||||
e.float = true;
|
||||
expect(e.moveNode(node1, { x: 7, y: 3 })).toEqual(true);
|
||||
expect(node1).toEqual(expect.objectContaining({ x: 7, y: 3, w: 2, h: 3 }));
|
||||
});
|
||||
});
|
||||
describe('test columnChanged >', () => {
|
||||
beforeAll(() => {
|
||||
});
|
||||
it('12 to 1 and back', () => {
|
||||
ePriv = e = new GridStackEngine({ column: 12 });
|
||||
// Add two side-by-side components 6+6 = 12 columns
|
||||
const left = e.addNode({ x: 0, y: 0, w: 6, h: 1, id: 'left' });
|
||||
const right = e.addNode({ x: 6, y: 0, w: 6, h: 1, id: 'right' });
|
||||
expect(left).toEqual(expect.objectContaining({ x: 0, y: 0, w: 6, h: 1 }));
|
||||
expect(right).toEqual(expect.objectContaining({ x: 6, y: 0, w: 6, h: 1 }));
|
||||
// Resize to 1 column
|
||||
e.column = 1;
|
||||
e.columnChanged(12, 1);
|
||||
expect(left).toEqual(expect.objectContaining({ x: 0, y: 0, w: 1, h: 1 }));
|
||||
expect(right).toEqual(expect.objectContaining({ x: 0, y: 1, w: 1, h: 1 }));
|
||||
// Resize back to 12 column
|
||||
e.column = 12;
|
||||
e.columnChanged(1, 12);
|
||||
expect(left).toEqual(expect.objectContaining({ x: 0, y: 0, w: 6, h: 1 }));
|
||||
expect(right).toEqual(expect.objectContaining({ x: 6, y: 0, w: 6, h: 1 }));
|
||||
});
|
||||
it('24 column to 1 and back', () => {
|
||||
ePriv = e = new GridStackEngine({ column: 24 });
|
||||
// Add two side-by-side components 12+12 = 24 columns
|
||||
const left = e.addNode({ x: 0, y: 0, w: 12, h: 1, id: 'left' });
|
||||
const right = e.addNode({ x: 12, y: 0, w: 12, h: 1, id: 'right' });
|
||||
expect(left).toEqual(expect.objectContaining({ x: 0, y: 0, w: 12, h: 1 }));
|
||||
expect(right).toEqual(expect.objectContaining({ x: 12, y: 0, w: 12, h: 1 }));
|
||||
// Resize to 1 column
|
||||
e.column = 1;
|
||||
e.columnChanged(24, 1);
|
||||
expect(left).toEqual(expect.objectContaining({ x: 0, y: 0, w: 1, h: 1 }));
|
||||
expect(right).toEqual(expect.objectContaining({ x: 0, y: 1, w: 1, h: 1 }));
|
||||
// Resize back to 24 column
|
||||
e.column = 24;
|
||||
e.columnChanged(1, 24);
|
||||
expect(left).toEqual(expect.objectContaining({ x: 0, y: 0, w: 12, h: 1 }));
|
||||
expect(right).toEqual(expect.objectContaining({ x: 12, y: 0, w: 12, h: 1 }));
|
||||
});
|
||||
});
|
||||
describe('test compact >', () => {
|
||||
beforeAll(() => {
|
||||
ePriv = e = new GridStackEngine();
|
||||
});
|
||||
it('do nothing', () => {
|
||||
e.compact();
|
||||
});
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=gridstack-engine-spec.js.map
|
||||
1
node_modules/gridstack/dist/spec/gridstack-engine-spec.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/spec/gridstack-engine-spec.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/gridstack/dist/spec/gridstack-spec.d.ts
generated
vendored
Normal file
1
node_modules/gridstack/dist/spec/gridstack-spec.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
1780
node_modules/gridstack/dist/spec/gridstack-spec.js
generated
vendored
Normal file
1780
node_modules/gridstack/dist/spec/gridstack-spec.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
node_modules/gridstack/dist/spec/gridstack-spec.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/spec/gridstack-spec.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/gridstack/dist/spec/integration/gridstack-integration.spec.d.ts
generated
vendored
Normal file
1
node_modules/gridstack/dist/spec/integration/gridstack-integration.spec.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
171
node_modules/gridstack/dist/spec/integration/gridstack-integration.spec.js
generated
vendored
Normal file
171
node_modules/gridstack/dist/spec/integration/gridstack-integration.spec.js
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
import { GridStack } from '../../src/gridstack';
|
||||
// Integration tests for GridStack HTML scenarios
|
||||
// These test actual GridStack behavior with DOM manipulation
|
||||
describe('GridStack Integration Tests', () => {
|
||||
beforeEach(() => {
|
||||
// // Clean up DOM before each test
|
||||
// document.body.innerHTML = '';
|
||||
// // Add basic CSS for GridStack to function properly
|
||||
// const style = document.createElement('style');
|
||||
// style.textContent = `
|
||||
// .grid-stack { position: relative; }
|
||||
// .grid-stack-item { position: absolute; }
|
||||
// .grid-stack-item-content { width: 100%; height: 100%; }
|
||||
// `;
|
||||
// document.head.appendChild(style);
|
||||
});
|
||||
afterEach(() => {
|
||||
// // Clean up any GridStack instances
|
||||
// GridStack.removeAll;
|
||||
// // Clean up added styles
|
||||
// const styles = document.head.querySelectorAll('style');
|
||||
// styles.forEach(style => style.remove());
|
||||
});
|
||||
describe('Auto-positioning with no x,y coordinates', () => {
|
||||
it('should position items in order 5,1,2,4,3 based on their constraints', () => {
|
||||
// Create the HTML structure from the test file
|
||||
document.body.innerHTML = `
|
||||
<div class="grid-stack">
|
||||
<div class="grid-stack-item upper" gs-w="2" gs-h="2" gs-id="1">
|
||||
<div class="grid-stack-item-content">item 1</div>
|
||||
</div>
|
||||
<div class="grid-stack-item" gs-w="3" gs-h="2" gs-id="2">
|
||||
<div class="grid-stack-item-content">item 2</div>
|
||||
</div>
|
||||
<div class="grid-stack-item" gs-w="9" gs-h="1" gs-id="3">
|
||||
<div class="grid-stack-item-content">item 3 too big to fit, so next row</div>
|
||||
</div>
|
||||
<div class="grid-stack-item" gs-w="3" gs-h="1" gs-id="4">
|
||||
<div class="grid-stack-item-content">item 4</div>
|
||||
</div>
|
||||
<div class="grid-stack-item" gs-x="1" gs-y="1" gs-w="1" gs-h="1" gs-id="5">
|
||||
<div class="grid-stack-item-content">item 5 first</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
// Initialize GridStack with same options as test
|
||||
const options = {
|
||||
cellHeight: 80,
|
||||
margin: 5,
|
||||
float: true
|
||||
};
|
||||
const grid = GridStack.init(options);
|
||||
// Get all nodes and their positions
|
||||
const nodes = grid.engine.nodes;
|
||||
expect(nodes).toHaveLength(5);
|
||||
// Item 5 should be positioned (has explicit x=1, y=1 in HTML)
|
||||
const item5 = nodes.find(n => n.id === '5');
|
||||
expect(item5).toBeDefined();
|
||||
expect(item5.w).toBe(1);
|
||||
expect(item5.h).toBe(1);
|
||||
// Item 1 should be positioned next (2x2)
|
||||
const item1 = nodes.find(n => n.id === '1');
|
||||
expect(item1).toBeDefined();
|
||||
expect(item1.w).toBe(2);
|
||||
expect(item1.h).toBe(2);
|
||||
// Item 2 should be positioned (3x2)
|
||||
const item2 = nodes.find(n => n.id === '2');
|
||||
expect(item2).toBeDefined();
|
||||
expect(item2.w).toBe(3);
|
||||
expect(item2.h).toBe(2);
|
||||
// Item 4 should be positioned (3x1)
|
||||
const item4 = nodes.find(n => n.id === '4');
|
||||
expect(item4).toBeDefined();
|
||||
expect(item4.w).toBe(3);
|
||||
expect(item4.h).toBe(1);
|
||||
// Item 3 should be on next row (too big to fit - 9x1)
|
||||
const item3 = nodes.find(n => n.id === '3');
|
||||
expect(item3).toBeDefined();
|
||||
expect(item3.w).toBe(9);
|
||||
expect(item3.h).toBe(1);
|
||||
// Verify all items are positioned (have valid coordinates)
|
||||
nodes.forEach(node => {
|
||||
expect(node.x).toBeGreaterThanOrEqual(0);
|
||||
expect(node.y).toBeGreaterThanOrEqual(0);
|
||||
expect(node.w).toBeGreaterThan(0);
|
||||
expect(node.h).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('Grid initialization and basic functionality', () => {
|
||||
it('should initialize GridStack with items and maintain data integrity', () => {
|
||||
document.body.innerHTML = `
|
||||
<div class="grid-stack">
|
||||
<div class="grid-stack-item" gs-x="0" gs-y="0" gs-w="4" gs-h="2" gs-id="item1">
|
||||
<div class="grid-stack-item-content">Item 1</div>
|
||||
</div>
|
||||
<div class="grid-stack-item" gs-x="4" gs-y="0" gs-w="4" gs-h="4" gs-id="item2">
|
||||
<div class="grid-stack-item-content">Item 2</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
const grid = GridStack.init();
|
||||
expect(grid).toBeDefined();
|
||||
expect(grid.engine.nodes).toHaveLength(2);
|
||||
const item1 = grid.engine.nodes.find(n => n.id === 'item1');
|
||||
const item2 = grid.engine.nodes.find(n => n.id === 'item2');
|
||||
expect(item1).toEqual(expect.objectContaining({
|
||||
x: 0, y: 0, w: 4, h: 2, id: 'item1'
|
||||
}));
|
||||
expect(item2).toEqual(expect.objectContaining({
|
||||
x: 4, y: 0, w: 4, h: 4, id: 'item2'
|
||||
}));
|
||||
});
|
||||
it('should handle empty grid initialization', () => {
|
||||
document.body.innerHTML = '<div class="grid-stack"></div>';
|
||||
const grid = GridStack.init();
|
||||
expect(grid).toBeDefined();
|
||||
expect(grid.engine.nodes).toHaveLength(0);
|
||||
});
|
||||
it('should add widgets programmatically', () => {
|
||||
document.body.innerHTML = '<div class="grid-stack"></div>';
|
||||
const grid = GridStack.init();
|
||||
const addedEl = grid.addWidget({
|
||||
x: 0, y: 0, w: 2, h: 2, id: 'new-widget'
|
||||
});
|
||||
expect(addedEl).toBeDefined();
|
||||
expect(grid.engine.nodes).toHaveLength(1);
|
||||
// Check that the widget was added with valid properties
|
||||
const node = grid.engine.nodes[0];
|
||||
expect(node.x).toBe(0);
|
||||
expect(node.y).toBe(0);
|
||||
// Note: w and h might default to 1x1 if not explicitly set in the HTML attributes
|
||||
});
|
||||
});
|
||||
describe('Layout and positioning validation', () => {
|
||||
it('should respect minRow constraints', () => {
|
||||
document.body.innerHTML = '<div class="grid-stack"></div>';
|
||||
const grid = GridStack.init({ minRow: 3 });
|
||||
// Even with no items, grid should maintain minimum rows
|
||||
expect(grid.getRow()).toBeGreaterThanOrEqual(3);
|
||||
});
|
||||
it('should handle widget collision detection', () => {
|
||||
document.body.innerHTML = `
|
||||
<div class="grid-stack">
|
||||
<div class="grid-stack-item" gs-x="0" gs-y="0" gs-w="2" gs-h="2" gs-id="item1">
|
||||
<div class="grid-stack-item-content">Item 1</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
const grid = GridStack.init();
|
||||
// Try to add overlapping widget
|
||||
const widgetEl = grid.addWidget({
|
||||
x: 1, y: 1, w: 2, h: 2, id: 'overlap'
|
||||
});
|
||||
expect(widgetEl).toBeDefined();
|
||||
expect(grid.engine.nodes).toHaveLength(2);
|
||||
// Verify that items don't actually overlap (GridStack should handle collision)
|
||||
// Just verify we have 2 nodes without overlap testing since the API changed
|
||||
const nodes = grid.engine.nodes;
|
||||
expect(nodes).toHaveLength(2);
|
||||
// All nodes should have valid positions
|
||||
nodes.forEach(node => {
|
||||
expect(node.x).toBeGreaterThanOrEqual(0);
|
||||
expect(node.y).toBeGreaterThanOrEqual(0);
|
||||
expect(node.w).toBeGreaterThan(0);
|
||||
expect(node.h).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=gridstack-integration.spec.js.map
|
||||
1
node_modules/gridstack/dist/spec/integration/gridstack-integration.spec.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/spec/integration/gridstack-integration.spec.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/gridstack/dist/spec/regression-spec.d.ts
generated
vendored
Normal file
1
node_modules/gridstack/dist/spec/regression-spec.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
100
node_modules/gridstack/dist/spec/regression-spec.js
generated
vendored
Normal file
100
node_modules/gridstack/dist/spec/regression-spec.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
import { GridStack } from '../src/gridstack';
|
||||
describe('regression >', () => {
|
||||
'use strict';
|
||||
let grid;
|
||||
let findEl = function (id) {
|
||||
return grid.engine.nodes.find(n => n.id === id).el;
|
||||
};
|
||||
let findSubEl = function (id, index = 0) {
|
||||
return grid.engine.nodes[index].subGrid?.engine.nodes.find(n => n.id === id).el;
|
||||
};
|
||||
// empty grid
|
||||
let gridstackEmptyHTML = '<div style="width: 800px; height: 600px" id="gs-cont">' +
|
||||
' <div class="grid-stack"></div>' +
|
||||
'</div>';
|
||||
describe('2492 load() twice >', () => {
|
||||
beforeEach(() => {
|
||||
document.body.insertAdjacentHTML('afterbegin', gridstackEmptyHTML);
|
||||
});
|
||||
afterEach(() => {
|
||||
document.body.removeChild(document.getElementById('gs-cont'));
|
||||
});
|
||||
it('', () => {
|
||||
let items = [
|
||||
{ x: 0, y: 0, w: 2, content: '0 wide' },
|
||||
{ x: 1, y: 0, content: '1 over' },
|
||||
{ x: 2, y: 1, content: '2 float' },
|
||||
];
|
||||
let count = 0;
|
||||
items.forEach(n => n.id = String(count++));
|
||||
grid = GridStack.init({ cellHeight: 70, margin: 5 }).load(items);
|
||||
let el0 = findEl('0');
|
||||
let el1 = findEl('1');
|
||||
let el2 = findEl('2');
|
||||
expect(el0.getAttribute('gs-x')).toBe(null);
|
||||
expect(el0.getAttribute('gs-y')).toBe(null);
|
||||
expect(el0.children[0].innerHTML).toBe(items[0].content);
|
||||
expect(parseInt(el1.getAttribute('gs-x'))).toBe(1);
|
||||
expect(parseInt(el1.getAttribute('gs-y'))).toBe(1);
|
||||
expect(parseInt(el2.getAttribute('gs-x'))).toBe(2);
|
||||
expect(el2.getAttribute('gs-y')).toBe(null);
|
||||
// loading with changed content should be same positions
|
||||
items.forEach(n => n.content += '*');
|
||||
grid.load(items);
|
||||
expect(el0.getAttribute('gs-x')).toBe(null);
|
||||
expect(el0.getAttribute('gs-y')).toBe(null);
|
||||
expect(el0.children[0].innerHTML).toBe(items[0].content);
|
||||
expect(parseInt(el1.getAttribute('gs-x'))).toBe(1);
|
||||
expect(parseInt(el1.getAttribute('gs-y'))).toBe(1);
|
||||
expect(parseInt(el2.getAttribute('gs-x'))).toBe(2);
|
||||
expect(el2.getAttribute('gs-y')).toBe(null);
|
||||
});
|
||||
});
|
||||
describe('2865 nested grid resize >', () => {
|
||||
beforeEach(() => {
|
||||
document.body.insertAdjacentHTML('afterbegin', gridstackEmptyHTML);
|
||||
});
|
||||
afterEach(() => {
|
||||
document.body.removeChild(document.getElementById('gs-cont'));
|
||||
});
|
||||
it('', () => {
|
||||
let children = [{}, {}, {}];
|
||||
let items = [
|
||||
{ x: 0, y: 0, w: 3, h: 5, sizeToContent: true, subGridOpts: { children, column: 'auto' } }
|
||||
];
|
||||
let count = 0;
|
||||
[...items, ...children].forEach(n => n.id = String(count++));
|
||||
grid = GridStack.init({ cellHeight: 70, margin: 5, children: items });
|
||||
let nested = findEl('0');
|
||||
let el1 = findSubEl('1');
|
||||
let el2 = findSubEl('2');
|
||||
let el3 = findSubEl('3');
|
||||
expect(nested.getAttribute('gs-x')).toBe(null);
|
||||
expect(nested.getAttribute('gs-y')).toBe(null);
|
||||
expect(parseInt(nested.getAttribute('gs-w'))).toBe(3);
|
||||
// TODO: sizeToContent doesn't seem to be called in headless mode ??? works in browser.
|
||||
// expect(nested.getAttribute('gs-h')).toBe(null); // sizeToContent 5 -> 1 which is null
|
||||
expect(el1.getAttribute('gs-x')).toBe(null);
|
||||
expect(el1.getAttribute('gs-y')).toBe(null);
|
||||
expect(parseInt(el2.getAttribute('gs-x'))).toBe(1);
|
||||
expect(el2.getAttribute('gs-y')).toBe(null);
|
||||
expect(parseInt(el3.getAttribute('gs-x'))).toBe(2);
|
||||
expect(el3.getAttribute('gs-y')).toBe(null);
|
||||
// now resize the nested grid to 2 -> should reflow el3
|
||||
grid.update(nested, { w: 2 });
|
||||
expect(nested.getAttribute('gs-x')).toBe(null);
|
||||
expect(nested.getAttribute('gs-y')).toBe(null);
|
||||
expect(parseInt(nested.getAttribute('gs-w'))).toBe(2);
|
||||
// TODO: sizeToContent doesn't seem to be called in headless mode ??? works in browser.
|
||||
// expect(parseInt(nested.getAttribute('gs-h'))).toBe(2);
|
||||
expect(el1.getAttribute('gs-x')).toBe(null);
|
||||
expect(el1.getAttribute('gs-y')).toBe(null);
|
||||
expect(parseInt(el2.getAttribute('gs-x'))).toBe(1);
|
||||
expect(el2.getAttribute('gs-y')).toBe(null);
|
||||
// 3rd item pushed to next row
|
||||
expect(el3.getAttribute('gs-x')).toBe(null);
|
||||
expect(parseInt(el3.getAttribute('gs-y'))).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=regression-spec.js.map
|
||||
1
node_modules/gridstack/dist/spec/regression-spec.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/spec/regression-spec.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/gridstack/dist/spec/utils-spec.d.ts
generated
vendored
Normal file
1
node_modules/gridstack/dist/spec/utils-spec.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
243
node_modules/gridstack/dist/spec/utils-spec.js
generated
vendored
Normal file
243
node_modules/gridstack/dist/spec/utils-spec.js
generated
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
import { Utils } from '../src/utils';
|
||||
describe('gridstack utils', () => {
|
||||
describe('setup of utils', () => {
|
||||
it('should set gridstack Utils.', () => {
|
||||
let utils = Utils;
|
||||
expect(utils).not.toBeNull();
|
||||
expect(typeof utils).toBe('function');
|
||||
});
|
||||
});
|
||||
describe('test toBool', () => {
|
||||
it('should return booleans.', () => {
|
||||
expect(Utils.toBool(true)).toEqual(true);
|
||||
expect(Utils.toBool(false)).toEqual(false);
|
||||
});
|
||||
it('should work with integer.', () => {
|
||||
expect(Utils.toBool(1)).toEqual(true);
|
||||
expect(Utils.toBool(0)).toEqual(false);
|
||||
});
|
||||
it('should work with Strings.', () => {
|
||||
expect(Utils.toBool('')).toEqual(false);
|
||||
expect(Utils.toBool('0')).toEqual(false);
|
||||
expect(Utils.toBool('no')).toEqual(false);
|
||||
expect(Utils.toBool('false')).toEqual(false);
|
||||
expect(Utils.toBool('yes')).toEqual(true);
|
||||
expect(Utils.toBool('yadda')).toEqual(true);
|
||||
});
|
||||
});
|
||||
describe('test isIntercepted', () => {
|
||||
let src = { x: 3, y: 2, w: 3, h: 2 };
|
||||
it('should intercept.', () => {
|
||||
expect(Utils.isIntercepted(src, { x: 0, y: 0, w: 4, h: 3 })).toEqual(true);
|
||||
expect(Utils.isIntercepted(src, { x: 0, y: 0, w: 40, h: 30 })).toEqual(true);
|
||||
expect(Utils.isIntercepted(src, { x: 3, y: 2, w: 3, h: 2 })).toEqual(true);
|
||||
expect(Utils.isIntercepted(src, { x: 5, y: 3, w: 3, h: 2 })).toEqual(true);
|
||||
});
|
||||
it('shouldn\'t intercept.', () => {
|
||||
expect(Utils.isIntercepted(src, { x: 0, y: 0, w: 3, h: 2 })).toEqual(false);
|
||||
expect(Utils.isIntercepted(src, { x: 0, y: 0, w: 13, h: 2 })).toEqual(false);
|
||||
expect(Utils.isIntercepted(src, { x: 1, y: 4, w: 13, h: 2 })).toEqual(false);
|
||||
expect(Utils.isIntercepted(src, { x: 0, y: 3, w: 3, h: 2 })).toEqual(false);
|
||||
expect(Utils.isIntercepted(src, { x: 6, y: 3, w: 3, h: 2 })).toEqual(false);
|
||||
});
|
||||
});
|
||||
describe('test parseHeight', () => {
|
||||
it('should parse height value', () => {
|
||||
expect(Utils.parseHeight(12)).toEqual(expect.objectContaining({ h: 12, unit: 'px' }));
|
||||
expect(Utils.parseHeight('12px')).toEqual(expect.objectContaining({ h: 12, unit: 'px' }));
|
||||
expect(Utils.parseHeight('12.3px')).toEqual(expect.objectContaining({ h: 12.3, unit: 'px' }));
|
||||
expect(Utils.parseHeight('12.3em')).toEqual(expect.objectContaining({ h: 12.3, unit: 'em' }));
|
||||
expect(Utils.parseHeight('12.3rem')).toEqual(expect.objectContaining({ h: 12.3, unit: 'rem' }));
|
||||
expect(Utils.parseHeight('12.3vh')).toEqual(expect.objectContaining({ h: 12.3, unit: 'vh' }));
|
||||
expect(Utils.parseHeight('12.3vw')).toEqual(expect.objectContaining({ h: 12.3, unit: 'vw' }));
|
||||
expect(Utils.parseHeight('12.3%')).toEqual(expect.objectContaining({ h: 12.3, unit: '%' }));
|
||||
expect(Utils.parseHeight('12.5cm')).toEqual(expect.objectContaining({ h: 12.5, unit: 'cm' }));
|
||||
expect(Utils.parseHeight('12.5mm')).toEqual(expect.objectContaining({ h: 12.5, unit: 'mm' }));
|
||||
expect(Utils.parseHeight('12.5')).toEqual(expect.objectContaining({ h: 12.5, unit: 'px' }));
|
||||
expect(() => { Utils.parseHeight('12.5 df'); }).toThrow('Invalid height val = 12.5 df');
|
||||
});
|
||||
it('should parse negative height value', () => {
|
||||
expect(Utils.parseHeight(-12)).toEqual(expect.objectContaining({ h: -12, unit: 'px' }));
|
||||
expect(Utils.parseHeight('-12px')).toEqual(expect.objectContaining({ h: -12, unit: 'px' }));
|
||||
expect(Utils.parseHeight('-12.3px')).toEqual(expect.objectContaining({ h: -12.3, unit: 'px' }));
|
||||
expect(Utils.parseHeight('-12.3em')).toEqual(expect.objectContaining({ h: -12.3, unit: 'em' }));
|
||||
expect(Utils.parseHeight('-12.3rem')).toEqual(expect.objectContaining({ h: -12.3, unit: 'rem' }));
|
||||
expect(Utils.parseHeight('-12.3vh')).toEqual(expect.objectContaining({ h: -12.3, unit: 'vh' }));
|
||||
expect(Utils.parseHeight('-12.3vw')).toEqual(expect.objectContaining({ h: -12.3, unit: 'vw' }));
|
||||
expect(Utils.parseHeight('-12.3%')).toEqual(expect.objectContaining({ h: -12.3, unit: '%' }));
|
||||
expect(Utils.parseHeight('-12.3cm')).toEqual(expect.objectContaining({ h: -12.3, unit: 'cm' }));
|
||||
expect(Utils.parseHeight('-12.3mm')).toEqual(expect.objectContaining({ h: -12.3, unit: 'mm' }));
|
||||
expect(Utils.parseHeight('-12.5')).toEqual(expect.objectContaining({ h: -12.5, unit: 'px' }));
|
||||
expect(() => { Utils.parseHeight('-12.5 df'); }).toThrow('Invalid height val = -12.5 df');
|
||||
});
|
||||
});
|
||||
describe('test defaults', () => {
|
||||
it('should assign missing field or undefined', () => {
|
||||
let src = {};
|
||||
expect(src).toEqual({});
|
||||
expect(Utils.defaults(src, { x: 1, y: 2 })).toEqual({ x: 1, y: 2 });
|
||||
expect(Utils.defaults(src, { x: 10 })).toEqual({ x: 1, y: 2 });
|
||||
src.w = undefined;
|
||||
expect(src).toEqual({ x: 1, y: 2, w: undefined });
|
||||
expect(Utils.defaults(src, { x: 10, w: 3 })).toEqual({ x: 1, y: 2, w: 3 });
|
||||
expect(Utils.defaults(src, { h: undefined })).toEqual({ x: 1, y: 2, w: 3, h: undefined });
|
||||
src = { x: 1, y: 2, sub: { foo: 1, two: 2 } };
|
||||
expect(src).toEqual({ x: 1, y: 2, sub: { foo: 1, two: 2 } });
|
||||
expect(Utils.defaults(src, { x: 10, w: 3 })).toEqual({ x: 1, y: 2, w: 3, sub: { foo: 1, two: 2 } });
|
||||
expect(Utils.defaults(src, { sub: { three: 3 } })).toEqual({ x: 1, y: 2, w: 3, sub: { foo: 1, two: 2, three: 3 } });
|
||||
});
|
||||
});
|
||||
describe('removePositioningStyles', () => {
|
||||
it('should remove styles', () => {
|
||||
let doc = document.implementation.createHTMLDocument();
|
||||
doc.body.innerHTML = '<div style="position: absolute; left: 1; top: 2; w: 3; h: 4"></div>';
|
||||
let el = doc.body.children[0];
|
||||
expect(el.style.position).toEqual('absolute');
|
||||
// expect(el.style.left).toEqual('1'); // not working!
|
||||
Utils.removePositioningStyles(el);
|
||||
expect(el.style.position).toEqual('');
|
||||
// bogus test
|
||||
expect(Utils.getScrollElement(el)).not.toBe(null);
|
||||
// bogus test
|
||||
Utils.updateScrollPosition(el, { top: 20 }, 10);
|
||||
});
|
||||
});
|
||||
describe('clone', () => {
|
||||
const a = { first: 1, second: 'text' };
|
||||
const b = { first: 1, second: { third: 3 } };
|
||||
const c = { first: 1, second: [1, 2, 3], third: { fourth: { fifth: 5 } } };
|
||||
it('Should have the same values', () => {
|
||||
const z = Utils.clone(a);
|
||||
expect(z).toEqual({ first: 1, second: 'text' });
|
||||
});
|
||||
it('Should have 2 in first key, and original unchanged', () => {
|
||||
const z = Utils.clone(a);
|
||||
z.first = 2;
|
||||
expect(a).toEqual({ first: 1, second: 'text' });
|
||||
expect(z).toEqual({ first: 2, second: 'text' });
|
||||
});
|
||||
it('Should have new string in second key, and original unchanged', () => {
|
||||
const z = Utils.clone(a);
|
||||
z.second = 2;
|
||||
expect(a).toEqual({ first: 1, second: 'text' });
|
||||
expect(z).toEqual({ first: 1, second: 2 });
|
||||
});
|
||||
it('new string in both cases - use cloneDeep instead', () => {
|
||||
const z = Utils.clone(b);
|
||||
z.second.third = 'share';
|
||||
expect(b).toEqual({ first: 1, second: { third: 'share' } });
|
||||
expect(z).toEqual({ first: 1, second: { third: 'share' } });
|
||||
});
|
||||
it('Array Should match', () => {
|
||||
const z = Utils.clone(c);
|
||||
expect(c).toEqual({ first: 1, second: [1, 2, 3], third: { fourth: { fifth: 5 } } });
|
||||
expect(z).toEqual({ first: 1, second: [1, 2, 3], third: { fourth: { fifth: 5 } } });
|
||||
});
|
||||
it('Array[0] changed in both cases - use cloneDeep instead', () => {
|
||||
const z = Utils.clone(c);
|
||||
z.second[0] = 0;
|
||||
expect(c).toEqual({ first: 1, second: [0, 2, 3], third: { fourth: { fifth: 5 } } });
|
||||
expect(z).toEqual({ first: 1, second: [0, 2, 3], third: { fourth: { fifth: 5 } } });
|
||||
});
|
||||
it('fifth changed in both cases - use cloneDeep instead', () => {
|
||||
const z = Utils.clone(c);
|
||||
z.third.fourth.fifth = 'share';
|
||||
expect(c).toEqual({ first: 1, second: [0, 2, 3], third: { fourth: { fifth: 'share' } } });
|
||||
expect(z).toEqual({ first: 1, second: [0, 2, 3], third: { fourth: { fifth: 'share' } } });
|
||||
});
|
||||
});
|
||||
describe('cloneDeep', () => {
|
||||
// reset our test cases
|
||||
const a = { first: 1, second: 'text' };
|
||||
const b = { first: 1, second: { third: 3 } };
|
||||
const c = { first: 1, second: [1, 2, 3], third: { fourth: { fifth: 5 } } };
|
||||
const d = { first: [1, [2, 3], ['four', 'five', 'six']] };
|
||||
const e = { first: 1, __skip: { second: 2 } };
|
||||
const f = { first: 1, _dontskip: { second: 2 } };
|
||||
it('Should have the same values', () => {
|
||||
const z = Utils.cloneDeep(a);
|
||||
expect(z).toEqual({ first: 1, second: 'text' });
|
||||
});
|
||||
it('Should have 2 in first key, and original unchanged', () => {
|
||||
const z = Utils.cloneDeep(a);
|
||||
z.first = 2;
|
||||
expect(a).toEqual({ first: 1, second: 'text' });
|
||||
expect(z).toEqual({ first: 2, second: 'text' });
|
||||
});
|
||||
it('Should have new string in second key, and original unchanged', () => {
|
||||
const z = Utils.cloneDeep(a);
|
||||
z.second = 2;
|
||||
expect(a).toEqual({ first: 1, second: 'text' });
|
||||
expect(z).toEqual({ first: 1, second: 2 });
|
||||
});
|
||||
it('Should have new string nested object, and original unchanged', () => {
|
||||
const z = Utils.cloneDeep(b);
|
||||
z.second.third = 'diff';
|
||||
expect(b).toEqual({ first: 1, second: { third: 3 } });
|
||||
expect(z).toEqual({ first: 1, second: { third: 'diff' } });
|
||||
});
|
||||
it('Array Should match', () => {
|
||||
const z = Utils.cloneDeep(c);
|
||||
expect(c).toEqual({ first: 1, second: [1, 2, 3], third: { fourth: { fifth: 5 } } });
|
||||
expect(z).toEqual({ first: 1, second: [1, 2, 3], third: { fourth: { fifth: 5 } } });
|
||||
});
|
||||
it('Array[0] changed in z only', () => {
|
||||
const z = Utils.cloneDeep(c);
|
||||
z.second[0] = 0;
|
||||
expect(c).toEqual({ first: 1, second: [1, 2, 3], third: { fourth: { fifth: 5 } } });
|
||||
expect(z).toEqual({ first: 1, second: [0, 2, 3], third: { fourth: { fifth: 5 } } });
|
||||
});
|
||||
it('nested firth element changed only in z', () => {
|
||||
const z = Utils.cloneDeep(c);
|
||||
z.third.fourth.fifth = 'diff';
|
||||
expect(c).toEqual({ first: 1, second: [1, 2, 3], third: { fourth: { fifth: 5 } } });
|
||||
expect(z).toEqual({ first: 1, second: [1, 2, 3], third: { fourth: { fifth: 'diff' } } });
|
||||
});
|
||||
it('nested array only has one item changed', () => {
|
||||
const z = Utils.cloneDeep(d);
|
||||
z.first[1] = 'two';
|
||||
z.first[2][2] = 6;
|
||||
expect(d).toEqual({ first: [1, [2, 3], ['four', 'five', 'six']] });
|
||||
expect(z).toEqual({ first: [1, 'two', ['four', 'five', 6]] });
|
||||
});
|
||||
it('skip __ items so it mods both instance', () => {
|
||||
const z = Utils.cloneDeep(e);
|
||||
z.__skip.second = 'two';
|
||||
expect(e).toEqual({ first: 1, __skip: { second: 'two' } }); // TODO support clone deep of function workaround
|
||||
expect(z).toEqual({ first: 1, __skip: { second: 'two' } });
|
||||
});
|
||||
it('correctly copy _ item', () => {
|
||||
const z = Utils.cloneDeep(f);
|
||||
z._dontskip.second = 'two';
|
||||
expect(f).toEqual({ first: 1, _dontskip: { second: 2 } });
|
||||
expect(z).toEqual({ first: 1, _dontskip: { second: 'two' } });
|
||||
});
|
||||
});
|
||||
describe('removeInternalAndSame', () => {
|
||||
it('should remove internal and same', () => {
|
||||
const a = { first: 1, second: 'text', _skip: { second: 2 }, arr: [1, 'second', 3] };
|
||||
const b = { first: 1, second: 'text' };
|
||||
Utils.removeInternalAndSame(a, b);
|
||||
expect(a).toEqual({ arr: [1, 'second', 3] });
|
||||
});
|
||||
it('should not remove items in an array', () => {
|
||||
const a = { arr: [1, 2, 3] };
|
||||
const b = { arr: [1, 3] };
|
||||
Utils.removeInternalAndSame(a, b);
|
||||
expect(a).toEqual({ arr: [1, 2, 3] });
|
||||
});
|
||||
it('should remove nested object, and make empty', () => {
|
||||
const a = { obj1: { first: 1, nested: { second: 2 } }, obj2: { first: 1, second: 2 } };
|
||||
const b = { obj1: { first: 1, nested: { second: 2 } }, obj2: { first: 1, second: 2 } };
|
||||
Utils.removeInternalAndSame(a, b);
|
||||
expect(a).toEqual({});
|
||||
});
|
||||
it('should remove nested object, and make empty - part 2', () => {
|
||||
const a = { obj1: { first: 1, nested: { second: 2 } }, obj2: { first: 1, second: 2 } };
|
||||
const b = { obj1: { first: 1 }, obj2: { first: 1, second: 2 } };
|
||||
Utils.removeInternalAndSame(a, b);
|
||||
expect(a).toEqual({ obj1: { nested: { second: 2 } } });
|
||||
});
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=utils-spec.js.map
|
||||
1
node_modules/gridstack/dist/spec/utils-spec.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/spec/utils-spec.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
69
node_modules/gridstack/dist/src/dd-base-impl.d.ts
generated
vendored
Normal file
69
node_modules/gridstack/dist/src/dd-base-impl.d.ts
generated
vendored
Normal 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
70
node_modules/gridstack/dist/src/dd-base-impl.js
generated
vendored
Normal 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
1
node_modules/gridstack/dist/src/dd-base-impl.js.map
generated
vendored
Normal 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
20
node_modules/gridstack/dist/src/dd-draggable.d.ts
generated
vendored
Normal 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
364
node_modules/gridstack/dist/src/dd-draggable.js
generated
vendored
Normal 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
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
26
node_modules/gridstack/dist/src/dd-droppable.d.ts
generated
vendored
Normal 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
149
node_modules/gridstack/dist/src/dd-droppable.js
generated
vendored
Normal 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
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
27
node_modules/gridstack/dist/src/dd-element.d.ts
generated
vendored
Normal 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
91
node_modules/gridstack/dist/src/dd-element.js
generated
vendored
Normal 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
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
82
node_modules/gridstack/dist/src/dd-gridstack.d.ts
generated
vendored
Normal 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
165
node_modules/gridstack/dist/src/dd-gridstack.js
generated
vendored
Normal 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
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
43
node_modules/gridstack/dist/src/dd-manager.d.ts
generated
vendored
Normal 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
14
node_modules/gridstack/dist/src/dd-manager.js
generated
vendored
Normal 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
1
node_modules/gridstack/dist/src/dd-manager.js.map
generated
vendored
Normal 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"]}
|
||||
18
node_modules/gridstack/dist/src/dd-resizable-handle.d.ts
generated
vendored
Normal file
18
node_modules/gridstack/dist/src/dd-resizable-handle.d.ts
generated
vendored
Normal 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
113
node_modules/gridstack/dist/src/dd-resizable-handle.js
generated
vendored
Normal 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
|
||||
1
node_modules/gridstack/dist/src/dd-resizable-handle.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/src/dd-resizable-handle.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user