@get-set/gs-sortable 0.0.35 → 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.
Files changed (110) hide show
  1. package/README.md +99 -1
  2. package/actions/afterAllImagesLoad.ts +36 -0
  3. package/actions/calculate.ts +155 -0
  4. package/actions/calculateOnSort.ts +270 -0
  5. package/actions/checkItemInContainer.ts +22 -0
  6. package/actions/destroy.ts +30 -0
  7. package/actions/general.ts +72 -0
  8. package/actions/getCurrentParams.ts +32 -0
  9. package/actions/init.ts +31 -0
  10. package/actions/initDraggable.ts +85 -0
  11. package/actions/initMouseMove.ts +120 -0
  12. package/actions/initScroll.ts +21 -0
  13. package/actions/initSortEnd.ts +87 -0
  14. package/components/GSSortable.tsx +160 -0
  15. package/components/styles/GSSortable.css +39 -0
  16. package/components/styles/GSSortable.scss +38 -0
  17. package/components/styles/GSSortableCSS.ts +41 -0
  18. package/constants/constParams.ts +5 -0
  19. package/constants/defaultParams.ts +20 -0
  20. package/constants/types.ts +7 -0
  21. package/dist/GSSortable.d.ts +2 -0
  22. package/dist/actions/afterAllImagesLoad.d.ts +4 -0
  23. package/dist/actions/afterAllImagesLoad.d.ts.map +1 -0
  24. package/dist/actions/afterAllImagesLoad.js +35 -0
  25. package/dist/actions/afterAllImagesLoad.js.map +1 -0
  26. package/dist/actions/calculate.d.ts +3 -2
  27. package/dist/actions/calculate.d.ts.map +1 -0
  28. package/dist/actions/calculate.js +13 -18
  29. package/dist/actions/calculate.js.map +1 -1
  30. package/dist/actions/calculateOnSort.d.ts +3 -2
  31. package/dist/actions/calculateOnSort.d.ts.map +1 -0
  32. package/dist/actions/calculateOnSort.js +164 -58
  33. package/dist/actions/calculateOnSort.js.map +1 -1
  34. package/dist/actions/checkItemInContainer.d.ts +1 -0
  35. package/dist/actions/checkItemInContainer.d.ts.map +1 -0
  36. package/dist/actions/checkItemInContainer.js +8 -17
  37. package/dist/actions/checkItemInContainer.js.map +1 -1
  38. package/dist/actions/destroy.d.ts +3 -8
  39. package/dist/actions/destroy.d.ts.map +1 -0
  40. package/dist/actions/destroy.js +7 -9
  41. package/dist/actions/destroy.js.map +1 -1
  42. package/dist/actions/general.d.ts +1 -0
  43. package/dist/actions/general.d.ts.map +1 -0
  44. package/dist/actions/general.js +5 -12
  45. package/dist/actions/general.js.map +1 -1
  46. package/dist/actions/getCurrentParams.d.ts +4 -9
  47. package/dist/actions/getCurrentParams.d.ts.map +1 -0
  48. package/dist/actions/getCurrentParams.js +15 -18
  49. package/dist/actions/getCurrentParams.js.map +1 -1
  50. package/dist/actions/init.d.ts +3 -2
  51. package/dist/actions/init.d.ts.map +1 -0
  52. package/dist/actions/init.js +13 -16
  53. package/dist/actions/init.js.map +1 -1
  54. package/dist/actions/initDraggable.d.ts +3 -2
  55. package/dist/actions/initDraggable.d.ts.map +1 -0
  56. package/dist/actions/initDraggable.js +14 -22
  57. package/dist/actions/initDraggable.js.map +1 -1
  58. package/dist/actions/initMouseMove.d.ts +1 -0
  59. package/dist/actions/initMouseMove.d.ts.map +1 -0
  60. package/dist/actions/initMouseMove.js +40 -53
  61. package/dist/actions/initMouseMove.js.map +1 -1
  62. package/dist/actions/initScroll.d.ts +1 -0
  63. package/dist/actions/initScroll.d.ts.map +1 -0
  64. package/dist/actions/initScroll.js +7 -15
  65. package/dist/actions/initScroll.js.map +1 -1
  66. package/dist/actions/initSortEnd.d.ts +2 -1
  67. package/dist/actions/initSortEnd.d.ts.map +1 -0
  68. package/dist/actions/initSortEnd.js +62 -71
  69. package/dist/actions/initSortEnd.js.map +1 -1
  70. package/dist/components/GSSortable.d.ts +4 -19
  71. package/dist/components/GSSortable.d.ts.map +1 -0
  72. package/dist/components/GSSortable.js +72 -105
  73. package/dist/components/GSSortable.js.map +1 -1
  74. package/dist/components/styles/GSSortableCSS.d.ts +2 -1
  75. package/dist/components/styles/GSSortableCSS.d.ts.map +1 -0
  76. package/dist/components/styles/GSSortableCSS.js +3 -4
  77. package/dist/components/styles/GSSortableCSS.js.map +1 -1
  78. package/dist/constants/constParams.d.ts +4 -3
  79. package/dist/constants/constParams.d.ts.map +1 -0
  80. package/dist/constants/constParams.js +2 -4
  81. package/dist/constants/constParams.js.map +1 -1
  82. package/dist/constants/defaultParams.d.ts +3 -2
  83. package/dist/constants/defaultParams.d.ts.map +1 -0
  84. package/dist/constants/defaultParams.js +3 -8
  85. package/dist/constants/defaultParams.js.map +1 -1
  86. package/dist/constants/types.d.ts +1 -0
  87. package/dist/constants/types.d.ts.map +1 -0
  88. package/dist/constants/types.js +1 -3
  89. package/dist/constants/types.js.map +1 -1
  90. package/dist/helpers/uihelpers.d.ts +2 -1
  91. package/dist/helpers/uihelpers.d.ts.map +1 -0
  92. package/dist/helpers/uihelpers.js +9 -23
  93. package/dist/helpers/uihelpers.js.map +1 -1
  94. package/dist/types/params.d.ts +23 -0
  95. package/dist/types/params.d.ts.map +1 -0
  96. package/dist/types/params.js +2 -0
  97. package/dist/types/params.js.map +1 -0
  98. package/dist/types/ref.d.ts +41 -0
  99. package/dist/types/ref.d.ts.map +1 -0
  100. package/dist/types/ref.js +2 -0
  101. package/dist/types/ref.js.map +1 -0
  102. package/dist-js/bundle.js +1181 -0
  103. package/helpers/uihelpers.ts +44 -0
  104. package/package.json +71 -43
  105. package/styles/GSSortable.css +39 -0
  106. package/styles/GSSortable.scss +38 -0
  107. package/types/global.d.ts +19 -0
  108. package/types/params.ts +24 -0
  109. package/types/ref.ts +41 -0
  110. 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
+ };