@get-set/gs-sortable 0.0.36 → 0.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -1
- package/actions/afterAllImagesLoad.ts +36 -0
- package/actions/calculate.ts +155 -0
- package/actions/calculateOnSort.ts +270 -0
- package/actions/checkItemInContainer.ts +22 -0
- package/actions/destroy.ts +30 -0
- package/actions/general.ts +72 -0
- package/actions/getCurrentParams.ts +32 -0
- package/actions/init.ts +31 -0
- package/actions/initDraggable.ts +85 -0
- package/actions/initMouseMove.ts +120 -0
- package/actions/initScroll.ts +21 -0
- package/actions/initSortEnd.ts +87 -0
- package/components/GSSortable.tsx +160 -0
- package/components/styles/GSSortable.css +39 -0
- package/components/styles/GSSortable.scss +38 -0
- package/components/styles/GSSortableCSS.ts +41 -0
- package/constants/constParams.ts +5 -0
- package/constants/defaultParams.ts +20 -0
- package/constants/types.ts +7 -0
- package/dist/GSSortable.d.ts +2 -0
- package/dist/actions/afterAllImagesLoad.d.ts +4 -0
- package/dist/actions/afterAllImagesLoad.d.ts.map +1 -0
- package/dist/actions/afterAllImagesLoad.js +35 -0
- package/dist/actions/afterAllImagesLoad.js.map +1 -0
- package/dist/actions/calculate.d.ts +3 -2
- package/dist/actions/calculate.d.ts.map +1 -0
- package/dist/actions/calculate.js +13 -18
- package/dist/actions/calculate.js.map +1 -1
- package/dist/actions/calculateOnSort.d.ts +3 -2
- package/dist/actions/calculateOnSort.d.ts.map +1 -0
- package/dist/actions/calculateOnSort.js +51 -70
- package/dist/actions/calculateOnSort.js.map +1 -1
- package/dist/actions/checkItemInContainer.d.ts +1 -0
- package/dist/actions/checkItemInContainer.d.ts.map +1 -0
- package/dist/actions/checkItemInContainer.js +8 -17
- package/dist/actions/checkItemInContainer.js.map +1 -1
- package/dist/actions/destroy.d.ts +3 -8
- package/dist/actions/destroy.d.ts.map +1 -0
- package/dist/actions/destroy.js +7 -9
- package/dist/actions/destroy.js.map +1 -1
- package/dist/actions/general.d.ts +1 -0
- package/dist/actions/general.d.ts.map +1 -0
- package/dist/actions/general.js +5 -12
- package/dist/actions/general.js.map +1 -1
- package/dist/actions/getCurrentParams.d.ts +4 -9
- package/dist/actions/getCurrentParams.d.ts.map +1 -0
- package/dist/actions/getCurrentParams.js +15 -18
- package/dist/actions/getCurrentParams.js.map +1 -1
- package/dist/actions/init.d.ts +3 -2
- package/dist/actions/init.d.ts.map +1 -0
- package/dist/actions/init.js +13 -16
- package/dist/actions/init.js.map +1 -1
- package/dist/actions/initDraggable.d.ts +3 -2
- package/dist/actions/initDraggable.d.ts.map +1 -0
- package/dist/actions/initDraggable.js +14 -22
- package/dist/actions/initDraggable.js.map +1 -1
- package/dist/actions/initMouseMove.d.ts +1 -0
- package/dist/actions/initMouseMove.d.ts.map +1 -0
- package/dist/actions/initMouseMove.js +40 -53
- package/dist/actions/initMouseMove.js.map +1 -1
- package/dist/actions/initScroll.d.ts +1 -0
- package/dist/actions/initScroll.d.ts.map +1 -0
- package/dist/actions/initScroll.js +7 -15
- package/dist/actions/initScroll.js.map +1 -1
- package/dist/actions/initSortEnd.d.ts +2 -1
- package/dist/actions/initSortEnd.d.ts.map +1 -0
- package/dist/actions/initSortEnd.js +62 -71
- package/dist/actions/initSortEnd.js.map +1 -1
- package/dist/components/GSSortable.d.ts +4 -19
- package/dist/components/GSSortable.d.ts.map +1 -0
- package/dist/components/GSSortable.js +72 -105
- package/dist/components/GSSortable.js.map +1 -1
- package/dist/components/styles/GSSortableCSS.d.ts +2 -1
- package/dist/components/styles/GSSortableCSS.d.ts.map +1 -0
- package/dist/components/styles/GSSortableCSS.js +3 -4
- package/dist/components/styles/GSSortableCSS.js.map +1 -1
- package/dist/constants/constParams.d.ts +4 -3
- package/dist/constants/constParams.d.ts.map +1 -0
- package/dist/constants/constParams.js +2 -4
- package/dist/constants/constParams.js.map +1 -1
- package/dist/constants/defaultParams.d.ts +3 -2
- package/dist/constants/defaultParams.d.ts.map +1 -0
- package/dist/constants/defaultParams.js +3 -8
- package/dist/constants/defaultParams.js.map +1 -1
- package/dist/constants/types.d.ts +1 -0
- package/dist/constants/types.d.ts.map +1 -0
- package/dist/constants/types.js +1 -3
- package/dist/constants/types.js.map +1 -1
- package/dist/helpers/uihelpers.d.ts +2 -1
- package/dist/helpers/uihelpers.d.ts.map +1 -0
- package/dist/helpers/uihelpers.js +9 -23
- package/dist/helpers/uihelpers.js.map +1 -1
- package/dist/types/params.d.ts +23 -0
- package/dist/types/params.d.ts.map +1 -0
- package/dist/types/params.js +2 -0
- package/dist/types/params.js.map +1 -0
- package/dist/types/ref.d.ts +41 -0
- package/dist/types/ref.d.ts.map +1 -0
- package/dist/types/ref.js +2 -0
- package/dist/types/ref.js.map +1 -0
- package/dist-js/bundle.js +1181 -0
- package/helpers/uihelpers.ts +44 -0
- package/package.json +71 -43
- package/styles/GSSortable.css +39 -0
- package/styles/GSSortable.scss +38 -0
- package/types/global.d.ts +19 -0
- package/types/params.ts +24 -0
- package/types/ref.ts +41 -0
- package/index.js +0 -3
package/README.md
CHANGED
|
@@ -1 +1,99 @@
|
|
|
1
|
-
# Get-Set Sortable
|
|
1
|
+
# Get-Set Sortable
|
|
2
|
+
|
|
3
|
+
A drag-and-drop sortable grid plugin with column, row and grid layout support.
|
|
4
|
+
One codebase — builds both a **vanilla JS bundle** and a **React component**.
|
|
5
|
+
CSS is injected automatically — no stylesheet import needed.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Build
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install
|
|
13
|
+
npm run build
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
| Command | Output | Use for |
|
|
17
|
+
|----------------------|----------------------------------|------------------|
|
|
18
|
+
| `npm run build` | both outputs below | everything |
|
|
19
|
+
| `npm run build:js` | `dist-js/bundle.js` | vanilla JS / CDN |
|
|
20
|
+
| `npm run build:react`| `dist/components/GSSortable.js` | React / npm |
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Vanilla JS
|
|
25
|
+
|
|
26
|
+
```html
|
|
27
|
+
<script src="dist-js/bundle.js"></script>
|
|
28
|
+
|
|
29
|
+
<div class="list">
|
|
30
|
+
<div>Item 1</div>
|
|
31
|
+
<div>Item 2</div>
|
|
32
|
+
<div>Item 3</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<script>
|
|
36
|
+
new GSSortable(document.querySelector('.list'), {
|
|
37
|
+
type: 'column',
|
|
38
|
+
gap: '10px',
|
|
39
|
+
afterSort: (items) => console.log('sorted', items),
|
|
40
|
+
});
|
|
41
|
+
</script>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
jQuery and `HTMLElement.prototype` shortcuts are also available:
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
$('.list').GSSortable({ type: 'grid', count: 3 });
|
|
48
|
+
document.querySelector('.list').GSSortable({ type: 'row' });
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## React
|
|
54
|
+
|
|
55
|
+
CSS is injected automatically when the component mounts.
|
|
56
|
+
|
|
57
|
+
```jsx
|
|
58
|
+
import GSSortable from '@get-set/gs-sortable';
|
|
59
|
+
|
|
60
|
+
<GSSortable type="column" gap="10px" afterSort={(items) => console.log(items)}>
|
|
61
|
+
<div>Item 1</div>
|
|
62
|
+
<div>Item 2</div>
|
|
63
|
+
<div>Item 3</div>
|
|
64
|
+
</GSSortable>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Cross-container drag (acceptFrom)
|
|
68
|
+
|
|
69
|
+
```jsx
|
|
70
|
+
<GSSortable reference="list-a" type="column">
|
|
71
|
+
<div>A1</div>
|
|
72
|
+
<div>A2</div>
|
|
73
|
+
</GSSortable>
|
|
74
|
+
|
|
75
|
+
<GSSortable reference="list-b" type="column" acceptFrom={['list-a']}>
|
|
76
|
+
<div>B1</div>
|
|
77
|
+
<div>B2</div>
|
|
78
|
+
</GSSortable>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Parameters
|
|
84
|
+
|
|
85
|
+
| Param | Type | Default | Description |
|
|
86
|
+
|-----------------|-------------------------------------|-------------|--------------------------------------------------------------|
|
|
87
|
+
| `reference` | `string` | auto | Unique key. Auto-generated if omitted. |
|
|
88
|
+
| `type` | `'column' \| 'row' \| 'grid'` | `'column'` | Layout direction. |
|
|
89
|
+
| `count` | `number` | `3` | Columns (grid mode only). |
|
|
90
|
+
| `gap` | `string` | `''` | CSS gap, e.g. `'10px'` or `'10px 20px'`. |
|
|
91
|
+
| `handler` | `string` | `''` | CSS selector for drag handle inside each item. |
|
|
92
|
+
| `width` | `string` | `'auto'` | Item width override. |
|
|
93
|
+
| `takeClone` | `boolean` | `false` | Drag a clone; original stays in place. |
|
|
94
|
+
| `allowOutOfBox` | `boolean` | `true` | Allow dragging beyond container bounds. |
|
|
95
|
+
| `acceptFrom` | `string[]` | `[]` | Reference keys of other instances that may drop items here. |
|
|
96
|
+
| `gsx` | `object` | — | Inline CSS-in-JS styles (React only). |
|
|
97
|
+
| `responsive` | `ResponsiveOption[]` | `[]` | Breakpoint overrides (sorted automatically). |
|
|
98
|
+
| `beforeInit` | `() => void` | — | Callback before each layout calculation. |
|
|
99
|
+
| `afterSort` | `(items: NodeListOf<Element>) => void` | `() => {}` | Callback after a sort completes. |
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import calculate from './calculate';
|
|
2
|
+
import { Ref } from '../types/ref';
|
|
3
|
+
|
|
4
|
+
const afterAllImagesLoad = (ref: Ref): void => {
|
|
5
|
+
const $images = [...ref.grid.querySelectorAll<HTMLImageElement>('img')];
|
|
6
|
+
const count = $images.length;
|
|
7
|
+
|
|
8
|
+
if (count > 0) {
|
|
9
|
+
let alreadyLoaded = 0;
|
|
10
|
+
$images.forEach((img) => {
|
|
11
|
+
if (img.complete) {
|
|
12
|
+
alreadyLoaded++;
|
|
13
|
+
if (alreadyLoaded === count) {
|
|
14
|
+
setTimeout(() => calculate(ref), 500);
|
|
15
|
+
}
|
|
16
|
+
} else {
|
|
17
|
+
img.onload = () => {
|
|
18
|
+
alreadyLoaded++;
|
|
19
|
+
if (alreadyLoaded === count) {
|
|
20
|
+
setTimeout(() => calculate(ref), 500);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
img.onerror = () => {
|
|
24
|
+
alreadyLoaded++;
|
|
25
|
+
if (alreadyLoaded === count) {
|
|
26
|
+
setTimeout(() => calculate(ref), 500);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
} else {
|
|
32
|
+
setTimeout(() => calculate(ref), 500);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default afterAllImagesLoad;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import types from '../constants/types';
|
|
2
|
+
import { Ref } from '../types/ref';
|
|
3
|
+
|
|
4
|
+
const calculate = (ref: Ref): void => {
|
|
5
|
+
const params = ref.currentParams;
|
|
6
|
+
|
|
7
|
+
if (typeof params.beforeInit === 'function') {
|
|
8
|
+
params.beforeInit();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const $items = Array.from(ref.grid.children).filter(
|
|
12
|
+
(x) => !(x as HTMLElement).classList.contains('gs-sortable-item-inmove'),
|
|
13
|
+
) as HTMLElement[];
|
|
14
|
+
const itemsCount = $items.length;
|
|
15
|
+
|
|
16
|
+
ref.grid.style.position = 'relative';
|
|
17
|
+
if (params.gap !== '') {
|
|
18
|
+
ref.grid.style.gap = params.gap!;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const gridStyles = getComputedStyle(ref.grid);
|
|
22
|
+
const cssGap = gridStyles.gap;
|
|
23
|
+
let gapX = 0;
|
|
24
|
+
let gapY = 0;
|
|
25
|
+
|
|
26
|
+
if (cssGap) {
|
|
27
|
+
const [cssGapYValue, cssGapXValue] = cssGap.includes(' ')
|
|
28
|
+
? cssGap.split(' ')
|
|
29
|
+
: [cssGap, cssGap];
|
|
30
|
+
|
|
31
|
+
const gapYSize = parseInt(cssGapYValue);
|
|
32
|
+
const gapXSize = parseInt(cssGapXValue);
|
|
33
|
+
if (!Number.isNaN(gapYSize)) gapY = gapYSize;
|
|
34
|
+
if (!Number.isNaN(gapXSize)) gapX = gapXSize;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const borderBottomWidth = parseFloat(gridStyles.borderBottomWidth);
|
|
38
|
+
const borderTopWidth = parseFloat(gridStyles.borderTopWidth);
|
|
39
|
+
const borderLeftWidth = parseFloat(gridStyles.borderLeftWidth);
|
|
40
|
+
const borderRightWidth = parseFloat(gridStyles.borderRightWidth);
|
|
41
|
+
const containerPT = parseFloat(gridStyles.paddingTop);
|
|
42
|
+
const containerPR = parseFloat(gridStyles.paddingRight);
|
|
43
|
+
const containerPB = parseFloat(gridStyles.paddingBottom);
|
|
44
|
+
const containerPL = parseFloat(gridStyles.paddingLeft);
|
|
45
|
+
|
|
46
|
+
const containerWidth = ref.grid.clientWidth - containerPR - containerPL;
|
|
47
|
+
let itemWidth = 0;
|
|
48
|
+
let strItemWidth = 'max-content';
|
|
49
|
+
|
|
50
|
+
if (params.type === types.grid) {
|
|
51
|
+
itemWidth = (containerWidth - (params.count! - 1) * gapX) / params.count!;
|
|
52
|
+
strItemWidth = `${itemWidth}px`;
|
|
53
|
+
} else if (params.type === types.column) {
|
|
54
|
+
itemWidth = containerWidth;
|
|
55
|
+
strItemWidth = `${itemWidth}px`;
|
|
56
|
+
}
|
|
57
|
+
ref.itemWidth = strItemWidth;
|
|
58
|
+
|
|
59
|
+
let currentLeft = containerPL;
|
|
60
|
+
let currentTop = containerPT;
|
|
61
|
+
let currentHeight =
|
|
62
|
+
containerPT + containerPB + borderBottomWidth + borderTopWidth;
|
|
63
|
+
let currentWidth =
|
|
64
|
+
containerPL + containerPR + borderLeftWidth + borderRightWidth;
|
|
65
|
+
let maxHeight = 0;
|
|
66
|
+
|
|
67
|
+
$items.forEach((el) => {
|
|
68
|
+
if (
|
|
69
|
+
params.type !== types.row ||
|
|
70
|
+
!el.classList.contains('gs-sortable-placeholder')
|
|
71
|
+
) {
|
|
72
|
+
el.style.width = strItemWidth;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
ref.uiData = {
|
|
77
|
+
containerPT,
|
|
78
|
+
containerPR,
|
|
79
|
+
containerPB,
|
|
80
|
+
containerPL,
|
|
81
|
+
containerWidth,
|
|
82
|
+
currentHeight,
|
|
83
|
+
currentWidth,
|
|
84
|
+
itemWidth,
|
|
85
|
+
gapX,
|
|
86
|
+
gapY,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
let colHeight = 0;
|
|
90
|
+
|
|
91
|
+
$items.forEach((el, index) => {
|
|
92
|
+
const height = el.offsetHeight;
|
|
93
|
+
const width = el.offsetWidth;
|
|
94
|
+
|
|
95
|
+
if (params.type === types.column) {
|
|
96
|
+
el.style.left = `${containerPL}px`;
|
|
97
|
+
if (currentTop === containerPT) {
|
|
98
|
+
el.style.top = `${containerPT}px`;
|
|
99
|
+
currentTop += height;
|
|
100
|
+
currentHeight += height;
|
|
101
|
+
} else {
|
|
102
|
+
el.style.top = `${currentTop + gapY}px`;
|
|
103
|
+
currentTop += gapY + height;
|
|
104
|
+
currentHeight += height + gapY;
|
|
105
|
+
}
|
|
106
|
+
} else if (params.type === types.row) {
|
|
107
|
+
el.style.top = `${containerPT}px`;
|
|
108
|
+
if (currentLeft === containerPL) {
|
|
109
|
+
el.style.left = `${containerPL}px`;
|
|
110
|
+
currentLeft += width;
|
|
111
|
+
currentWidth += width;
|
|
112
|
+
} else {
|
|
113
|
+
el.style.left = `${currentLeft + gapX}px`;
|
|
114
|
+
currentLeft += gapX + width;
|
|
115
|
+
currentWidth += width + gapX;
|
|
116
|
+
}
|
|
117
|
+
if (height > maxHeight) {
|
|
118
|
+
maxHeight = height;
|
|
119
|
+
}
|
|
120
|
+
} else if (params.type === types.grid) {
|
|
121
|
+
const left =
|
|
122
|
+
index % params.count! === 0
|
|
123
|
+
? containerPL
|
|
124
|
+
: containerPL + (index % params.count!) * (itemWidth + gapX);
|
|
125
|
+
const top = currentTop;
|
|
126
|
+
|
|
127
|
+
if (height > colHeight) {
|
|
128
|
+
colHeight = height;
|
|
129
|
+
}
|
|
130
|
+
if (
|
|
131
|
+
index % params.count! === params.count! - 1 ||
|
|
132
|
+
index === itemsCount - 1
|
|
133
|
+
) {
|
|
134
|
+
if (top === containerPT) {
|
|
135
|
+
currentHeight += colHeight;
|
|
136
|
+
} else {
|
|
137
|
+
currentHeight += colHeight + gapY;
|
|
138
|
+
}
|
|
139
|
+
currentTop += colHeight + gapY;
|
|
140
|
+
colHeight = 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
el.style.left = `${left}px`;
|
|
144
|
+
el.style.top = `${top}px`;
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
ref.grid.style.height = `${currentHeight}px`;
|
|
149
|
+
if (params.type === types.row) {
|
|
150
|
+
ref.grid.style.height = `${currentHeight + maxHeight}px`;
|
|
151
|
+
ref.grid.style.width = `${currentWidth}px`;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
export default calculate;
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import types from '../constants/types';
|
|
2
|
+
import { getOffsetFromWindow } from './general';
|
|
3
|
+
import { Ref, DraggableInfo } from '../types/ref';
|
|
4
|
+
|
|
5
|
+
const calculateOnSort = (ref: Ref): void => {
|
|
6
|
+
const params = ref.currentParams;
|
|
7
|
+
if (!params.takeClone) {
|
|
8
|
+
const $items = Array.from(ref.grid.children) as HTMLElement[];
|
|
9
|
+
const itemsCount = $items.filter(
|
|
10
|
+
(x) => !x.classList.contains('gs-sortable-item-inmove'),
|
|
11
|
+
).length;
|
|
12
|
+
|
|
13
|
+
const info = window.GSSortableConfigue!.draggableInfo as DraggableInfo;
|
|
14
|
+
let {
|
|
15
|
+
containerPT,
|
|
16
|
+
containerPL,
|
|
17
|
+
currentHeight,
|
|
18
|
+
currentWidth,
|
|
19
|
+
itemWidth,
|
|
20
|
+
gapX,
|
|
21
|
+
gapY,
|
|
22
|
+
} = ref.uiData!;
|
|
23
|
+
|
|
24
|
+
let currentLeft = containerPL;
|
|
25
|
+
let currentTop = containerPT;
|
|
26
|
+
let maxHeight = 0;
|
|
27
|
+
|
|
28
|
+
let placeholderSeted = info === undefined;
|
|
29
|
+
let inProcessEl: { height: number; width: number; top: number; left: number } | undefined;
|
|
30
|
+
|
|
31
|
+
const containerCoord = getOffsetFromWindow(info?.ref.grid!);
|
|
32
|
+
if (info !== undefined) {
|
|
33
|
+
const $el = info.$el;
|
|
34
|
+
const elCoord = getOffsetFromWindow($el);
|
|
35
|
+
inProcessEl = {
|
|
36
|
+
height: $el.offsetHeight,
|
|
37
|
+
width: $el.offsetWidth,
|
|
38
|
+
top: elCoord.top - containerCoord.top,
|
|
39
|
+
left: elCoord.left - containerCoord.left,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let plIndex = info?.index ?? 0;
|
|
44
|
+
let colHeight = 0;
|
|
45
|
+
let itIndex = 0;
|
|
46
|
+
|
|
47
|
+
// Pass 1 — find where the placeholder should land
|
|
48
|
+
$items.forEach((el) => {
|
|
49
|
+
if (!el.classList.contains('gs-sortable-item-inmove')) {
|
|
50
|
+
const height = el.offsetHeight;
|
|
51
|
+
const width = el.offsetWidth;
|
|
52
|
+
|
|
53
|
+
if (params.type === types.column) {
|
|
54
|
+
if (!placeholderSeted) {
|
|
55
|
+
const placeholderTop =
|
|
56
|
+
currentTop === containerPT ? containerPT : currentTop + gapY;
|
|
57
|
+
const placeholderLeft = containerPL;
|
|
58
|
+
if (
|
|
59
|
+
Math.abs(placeholderTop - inProcessEl!.top) < inProcessEl!.height / 2 &&
|
|
60
|
+
Math.abs(placeholderLeft - inProcessEl!.left) < inProcessEl!.width / 2
|
|
61
|
+
) {
|
|
62
|
+
info!.newTop = placeholderTop;
|
|
63
|
+
info!.newLeft = placeholderLeft;
|
|
64
|
+
placeholderSeted = true;
|
|
65
|
+
plIndex = itIndex;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (!el.classList.contains('gs-sortable-placeholder')) {
|
|
69
|
+
if (currentTop === containerPT) {
|
|
70
|
+
currentTop = containerPT + height;
|
|
71
|
+
currentHeight += height;
|
|
72
|
+
} else {
|
|
73
|
+
currentTop = currentTop + gapY + height;
|
|
74
|
+
currentHeight += height + gapY;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} else if (params.type === types.row) {
|
|
78
|
+
if (!placeholderSeted) {
|
|
79
|
+
const placeholderLeft =
|
|
80
|
+
currentLeft === containerPL ? containerPL : currentLeft + gapX;
|
|
81
|
+
const placeholderTop = containerPT;
|
|
82
|
+
if (
|
|
83
|
+
Math.abs(placeholderTop - inProcessEl!.top) < inProcessEl!.height / 2 &&
|
|
84
|
+
Math.abs(placeholderLeft - inProcessEl!.left) < inProcessEl!.width / 2
|
|
85
|
+
) {
|
|
86
|
+
info!.newTop = placeholderTop;
|
|
87
|
+
info!.newLeft = placeholderLeft;
|
|
88
|
+
placeholderSeted = true;
|
|
89
|
+
plIndex = itIndex;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (!el.classList.contains('gs-sortable-placeholder')) {
|
|
93
|
+
if (currentLeft === containerPL) {
|
|
94
|
+
currentLeft = containerPL + width;
|
|
95
|
+
currentWidth += width;
|
|
96
|
+
} else {
|
|
97
|
+
currentLeft = currentLeft + gapX + width;
|
|
98
|
+
currentWidth += width + gapX;
|
|
99
|
+
}
|
|
100
|
+
if (height > maxHeight) maxHeight = height;
|
|
101
|
+
}
|
|
102
|
+
} else if (params.type === types.grid) {
|
|
103
|
+
const placeholderLeft =
|
|
104
|
+
itIndex % params.count! === 0
|
|
105
|
+
? containerPL
|
|
106
|
+
: containerPL + (itIndex % params.count!) * (itemWidth + gapX);
|
|
107
|
+
const placeholderTop = currentTop;
|
|
108
|
+
if (
|
|
109
|
+
Math.abs(placeholderTop - inProcessEl!.top) < inProcessEl!.height / 2 &&
|
|
110
|
+
Math.abs(placeholderLeft - inProcessEl!.left) < inProcessEl!.width / 2
|
|
111
|
+
) {
|
|
112
|
+
info!.newTop = placeholderTop;
|
|
113
|
+
info!.newLeft = placeholderLeft;
|
|
114
|
+
placeholderSeted = true;
|
|
115
|
+
plIndex = itIndex;
|
|
116
|
+
}
|
|
117
|
+
if (!el.classList.contains('gs-sortable-placeholder')) {
|
|
118
|
+
const top = currentTop;
|
|
119
|
+
if (height > colHeight) colHeight = height;
|
|
120
|
+
if (
|
|
121
|
+
itIndex % params.count! === params.count! - 1 ||
|
|
122
|
+
itIndex === itemsCount - 1
|
|
123
|
+
) {
|
|
124
|
+
if (top === containerPT) {
|
|
125
|
+
currentHeight += colHeight;
|
|
126
|
+
} else {
|
|
127
|
+
currentHeight += colHeight + gapY;
|
|
128
|
+
}
|
|
129
|
+
currentTop += colHeight + gapY;
|
|
130
|
+
colHeight = 0;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
itIndex += 1;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Pass 2 — reposition everything including the placeholder
|
|
139
|
+
{
|
|
140
|
+
info!.index = plIndex;
|
|
141
|
+
({
|
|
142
|
+
containerPT,
|
|
143
|
+
containerPL,
|
|
144
|
+
currentHeight,
|
|
145
|
+
currentWidth,
|
|
146
|
+
itemWidth,
|
|
147
|
+
gapX,
|
|
148
|
+
gapY,
|
|
149
|
+
} = ref.uiData!);
|
|
150
|
+
|
|
151
|
+
currentLeft = containerPL;
|
|
152
|
+
currentTop = containerPT;
|
|
153
|
+
itIndex = 0;
|
|
154
|
+
|
|
155
|
+
$items.forEach((el) => {
|
|
156
|
+
if (!el.classList.contains('gs-sortable-item-inmove')) {
|
|
157
|
+
const height = el.offsetHeight;
|
|
158
|
+
const width = el.offsetWidth;
|
|
159
|
+
|
|
160
|
+
if (params.type === types.column) {
|
|
161
|
+
if (itIndex === plIndex) {
|
|
162
|
+
info!.placeholder!.style.left = `${containerPL}px`;
|
|
163
|
+
info!.newLeft = containerPL;
|
|
164
|
+
if (currentTop === containerPT) {
|
|
165
|
+
info!.newTop = containerPT;
|
|
166
|
+
info!.placeholder!.style.top = `${containerPT}px`;
|
|
167
|
+
currentTop = containerPT + inProcessEl!.height;
|
|
168
|
+
} else {
|
|
169
|
+
info!.newTop = currentTop + gapY;
|
|
170
|
+
info!.placeholder!.style.top = `${currentTop + gapY}px`;
|
|
171
|
+
currentTop = currentTop + gapY + inProcessEl!.height;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (!el.classList.contains('gs-sortable-placeholder')) {
|
|
175
|
+
el.style.left = `${containerPL}px`;
|
|
176
|
+
if (currentTop === containerPT) {
|
|
177
|
+
el.style.top = `${containerPT}px`;
|
|
178
|
+
currentTop = containerPT + height;
|
|
179
|
+
currentHeight += height;
|
|
180
|
+
} else {
|
|
181
|
+
el.style.top = `${currentTop + gapY}px`;
|
|
182
|
+
currentTop = currentTop + gapY + height;
|
|
183
|
+
currentHeight += height + gapY;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
} else if (params.type === types.row) {
|
|
187
|
+
if (itIndex === plIndex) {
|
|
188
|
+
info!.placeholder!.style.top = `${containerPT}px`;
|
|
189
|
+
info!.newTop = containerPT;
|
|
190
|
+
if (currentLeft === containerPL) {
|
|
191
|
+
info!.newLeft = containerPL;
|
|
192
|
+
info!.placeholder!.style.left = `${containerPL}px`;
|
|
193
|
+
currentLeft = containerPL + inProcessEl!.width;
|
|
194
|
+
} else {
|
|
195
|
+
info!.newLeft = currentLeft + gapX;
|
|
196
|
+
info!.placeholder!.style.left = `${currentLeft + gapX}px`;
|
|
197
|
+
currentLeft = currentLeft + gapX + inProcessEl!.width;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (!el.classList.contains('gs-sortable-placeholder')) {
|
|
201
|
+
el.style.top = `${containerPT}px`;
|
|
202
|
+
if (currentLeft === containerPL) {
|
|
203
|
+
el.style.left = `${containerPL}px`;
|
|
204
|
+
currentLeft = containerPL + width;
|
|
205
|
+
currentWidth += width;
|
|
206
|
+
} else {
|
|
207
|
+
el.style.left = `${currentLeft + gapX}px`;
|
|
208
|
+
currentLeft = currentLeft + gapX + width;
|
|
209
|
+
currentWidth += width + gapX;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} else if (params.type === types.grid) {
|
|
213
|
+
if (itIndex === plIndex) {
|
|
214
|
+
const left =
|
|
215
|
+
itIndex % params.count! === 0
|
|
216
|
+
? containerPL
|
|
217
|
+
: containerPL + (itIndex % params.count!) * (itemWidth + gapX);
|
|
218
|
+
const top = currentTop;
|
|
219
|
+
if (inProcessEl!.height > colHeight) colHeight = inProcessEl!.height;
|
|
220
|
+
if (
|
|
221
|
+
itIndex % params.count! === params.count! - 1 ||
|
|
222
|
+
itIndex === itemsCount - 1
|
|
223
|
+
) {
|
|
224
|
+
if (top === containerPT) {
|
|
225
|
+
currentHeight += colHeight;
|
|
226
|
+
} else {
|
|
227
|
+
currentHeight += colHeight + gapY;
|
|
228
|
+
}
|
|
229
|
+
currentTop += colHeight + gapY;
|
|
230
|
+
colHeight = 0;
|
|
231
|
+
ref.grid.style.height = `${currentHeight}px`;
|
|
232
|
+
}
|
|
233
|
+
itIndex += 1;
|
|
234
|
+
info!.newTop = top;
|
|
235
|
+
info!.newLeft = left;
|
|
236
|
+
info!.placeholder!.style.left = `${left}px`;
|
|
237
|
+
info!.placeholder!.style.top = `${top}px`;
|
|
238
|
+
}
|
|
239
|
+
if (!el.classList.contains('gs-sortable-placeholder')) {
|
|
240
|
+
const left =
|
|
241
|
+
itIndex % params.count! === 0
|
|
242
|
+
? containerPL
|
|
243
|
+
: containerPL + (itIndex % params.count!) * (itemWidth + gapX);
|
|
244
|
+
const top = currentTop;
|
|
245
|
+
if (height > colHeight) colHeight = height;
|
|
246
|
+
if (
|
|
247
|
+
itIndex % params.count! === params.count! - 1 ||
|
|
248
|
+
itIndex === itemsCount - 1
|
|
249
|
+
) {
|
|
250
|
+
if (top === containerPT) {
|
|
251
|
+
currentHeight += colHeight;
|
|
252
|
+
} else {
|
|
253
|
+
currentHeight += colHeight + gapY;
|
|
254
|
+
}
|
|
255
|
+
currentTop += colHeight + gapY;
|
|
256
|
+
colHeight = 0;
|
|
257
|
+
ref.grid.style.height = `${currentHeight}px`;
|
|
258
|
+
}
|
|
259
|
+
el.style.left = `${left}px`;
|
|
260
|
+
el.style.top = `${top}px`;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
itIndex += 1;
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
export default calculateOnSort;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { getOffsetFromWindow } from './general';
|
|
2
|
+
|
|
3
|
+
const checkItemInContainer = (grid: HTMLElement, el: HTMLElement): boolean => {
|
|
4
|
+
const gridOffset = getOffsetFromWindow(grid);
|
|
5
|
+
const elOffset = getOffsetFromWindow(el);
|
|
6
|
+
|
|
7
|
+
const offsetTopFromGrid = elOffset.top - gridOffset.top;
|
|
8
|
+
const offsetLeftFromGrid = elOffset.left - gridOffset.left;
|
|
9
|
+
const elHeight = el.offsetHeight;
|
|
10
|
+
const elWidth = el.offsetWidth;
|
|
11
|
+
const gridHeight = grid.offsetHeight;
|
|
12
|
+
const gridWidth = grid.offsetWidth;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
offsetTopFromGrid >= (-1 * elHeight) / 2 &&
|
|
16
|
+
offsetLeftFromGrid >= (-1 * elWidth) / 2 &&
|
|
17
|
+
offsetTopFromGrid <= gridHeight - elHeight / 2 &&
|
|
18
|
+
offsetLeftFromGrid <= gridWidth - elWidth / 2
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default checkItemInContainer;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import types from '../constants/types';
|
|
2
|
+
import { Ref } from '../types/ref';
|
|
3
|
+
|
|
4
|
+
const destroy = (ref: Ref): void => {
|
|
5
|
+
// Disconnect per-item resize observers to prevent leaks
|
|
6
|
+
ref.itemResizeObservers?.forEach((obs) => obs.disconnect());
|
|
7
|
+
ref.itemResizeObservers = [];
|
|
8
|
+
|
|
9
|
+
ref.grid.classList.remove('gs-sortable-instance');
|
|
10
|
+
ref.grid.classList.remove(`gs-sortable-${ref.currentParams.type}`);
|
|
11
|
+
ref.grid.style.removeProperty('position');
|
|
12
|
+
ref.grid.style.removeProperty('gap');
|
|
13
|
+
ref.grid.style.removeProperty('height');
|
|
14
|
+
|
|
15
|
+
if (ref.currentParams.type === types.row) {
|
|
16
|
+
ref.grid.style.removeProperty('width');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
Array.from(ref.grid.children).forEach((el) => {
|
|
20
|
+
const element = el as HTMLElement;
|
|
21
|
+
element.classList.remove('gs-sortable-item');
|
|
22
|
+
element.style.removeProperty('position');
|
|
23
|
+
element.style.removeProperty('width');
|
|
24
|
+
element.style.removeProperty('left');
|
|
25
|
+
element.style.removeProperty('top');
|
|
26
|
+
element.style.removeProperty('transition');
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default destroy;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export const getTranslateCoord = (element: HTMLElement): { x: number; y: number } => {
|
|
2
|
+
const style = window.getComputedStyle(element);
|
|
3
|
+
const matrix = new DOMMatrix(style.transform);
|
|
4
|
+
return {
|
|
5
|
+
x: matrix.e,
|
|
6
|
+
y: matrix.f,
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const getOffsetFromBody = (el: HTMLElement | null): { top: number; left: number } => {
|
|
11
|
+
let top = 0, left = 0;
|
|
12
|
+
|
|
13
|
+
while (el && el !== document.body) {
|
|
14
|
+
top += el.offsetTop || 0;
|
|
15
|
+
left += el.offsetLeft || 0;
|
|
16
|
+
|
|
17
|
+
const transform = window.getComputedStyle(el).transform;
|
|
18
|
+
if (transform !== 'none') {
|
|
19
|
+
const matrix = new DOMMatrix(transform);
|
|
20
|
+
top += matrix.m42 || 0;
|
|
21
|
+
left += matrix.m41 || 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
el = el.offsetParent as HTMLElement | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
top += document.body.scrollTop || document.documentElement.scrollTop || 0;
|
|
28
|
+
left += document.body.scrollLeft || document.documentElement.scrollLeft || 0;
|
|
29
|
+
|
|
30
|
+
return { top, left };
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const getOffsetFromWindow = (el: HTMLElement | null): { top: number; left: number } => {
|
|
34
|
+
let top = 0, left = 0;
|
|
35
|
+
|
|
36
|
+
while (el) {
|
|
37
|
+
top += el.offsetTop || 0;
|
|
38
|
+
left += el.offsetLeft || 0;
|
|
39
|
+
|
|
40
|
+
const transform = window.getComputedStyle(el).transform;
|
|
41
|
+
if (transform !== 'none') {
|
|
42
|
+
const matrix = new DOMMatrix(transform);
|
|
43
|
+
top += matrix.m42 || 0;
|
|
44
|
+
left += matrix.m41 || 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
el = el.offsetParent as HTMLElement | null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
top -= window.scrollY || 0;
|
|
51
|
+
left -= window.scrollX || 0;
|
|
52
|
+
|
|
53
|
+
return { top, left };
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const moveChildToIndex = (
|
|
57
|
+
parent: HTMLElement,
|
|
58
|
+
child: HTMLElement,
|
|
59
|
+
newIndex: number,
|
|
60
|
+
): void => {
|
|
61
|
+
const children = Array.from(parent.children) as HTMLElement[];
|
|
62
|
+
const oldIndex = children.indexOf(child);
|
|
63
|
+
|
|
64
|
+
if (oldIndex !== newIndex) {
|
|
65
|
+
newIndex = Math.max(0, Math.min(newIndex, children.length - 1));
|
|
66
|
+
if (newIndex > oldIndex && oldIndex !== -1) {
|
|
67
|
+
parent.insertBefore(child, children[newIndex].nextSibling);
|
|
68
|
+
} else {
|
|
69
|
+
parent.insertBefore(child, children[newIndex]);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|