@fr0st/ui-sortable 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -83
- package/dist/frost-ui-sortable.esm.js +25 -16
- package/dist/frost-ui-sortable.esm.js.map +1 -1
- package/dist/frost-ui-sortable.esm.min.js +1 -1
- package/dist/frost-ui-sortable.esm.min.js.map +1 -1
- package/dist/frost-ui-sortable.js +25 -16
- package/dist/frost-ui-sortable.js.map +1 -1
- package/dist/frost-ui-sortable.min.js +1 -1
- package/dist/frost-ui-sortable.min.js.map +1 -1
- package/package.json +7 -7
- package/src/helpers.js +3 -3
- package/src/sortable.js +34 -24
package/README.md
CHANGED
|
@@ -19,85 +19,76 @@ Drag-and-drop sorting for Frost UI with handles, connected containers, axis cont
|
|
|
19
19
|
- Configurable, direction-aware item swap threshold
|
|
20
20
|
- Normalized item, container, and index data on lifecycle events
|
|
21
21
|
- Native `Sortable` class and `sortable` fQuery plugin
|
|
22
|
+
- Existing-instance reuse with frozen resolved options
|
|
22
23
|
- Prebuilt ESM and UMD bundles with source maps
|
|
23
24
|
- No component-specific CSS or Sass
|
|
24
25
|
- JSDoc-powered IntelliSense
|
|
25
26
|
|
|
27
|
+
Explore [the demo](./demo/index.html) for interactive examples.
|
|
28
|
+
|
|
26
29
|
## Installation
|
|
27
30
|
|
|
28
31
|
### Browser projects / bundlers
|
|
29
32
|
|
|
30
|
-
Install Sortable with its Frost UI v4 and fQuery v5 peers:
|
|
31
|
-
|
|
32
33
|
```bash
|
|
33
|
-
npm i @fr0st/ui-sortable
|
|
34
|
+
npm i @fr0st/ui-sortable
|
|
34
35
|
```
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
Frost UI Sortable's package entry point is ESM-only and requires a browser DOM. Import the default `Sortable` export and the stylesheets in browser projects and bundlers.
|
|
37
38
|
|
|
38
39
|
```js
|
|
39
40
|
import '@fr0st/ui/dist/frost-ui.min.css';
|
|
40
41
|
import Sortable from '@fr0st/ui-sortable';
|
|
41
|
-
|
|
42
|
-
const sortable = Sortable.init(
|
|
43
|
-
document.querySelector('#tasks'),
|
|
44
|
-
{
|
|
45
|
-
cursor: 'grab',
|
|
46
|
-
handle: '.drag-handle',
|
|
47
|
-
},
|
|
48
|
-
);
|
|
49
42
|
```
|
|
50
43
|
|
|
51
|
-
`@fr0st/ui` and `@fr0st/query` are peer dependencies so the component shares the application's
|
|
52
|
-
|
|
53
|
-
Sortable requires a browser DOM or a compatible DOM environment configured through fQuery. Server-rendered applications should load the component on the client.
|
|
44
|
+
`@fr0st/ui` and `@fr0st/query` are peer dependencies so the component shares the application's instances.
|
|
54
45
|
|
|
55
46
|
### Browser (ESM)
|
|
56
47
|
|
|
57
|
-
The ESM bundle imports `@fr0st/ui` and `@fr0st/query`.
|
|
48
|
+
The ESM bundle imports `@fr0st/ui` and `@fr0st/query`. fQuery also imports `@fr0st/core`, so map all three dependencies when loading the bundle directly in a browser:
|
|
58
49
|
|
|
59
50
|
```html
|
|
60
51
|
<link
|
|
61
52
|
rel="stylesheet"
|
|
62
|
-
href="https://cdn.jsdelivr.net/npm/@fr0st/ui@
|
|
63
|
-
|
|
53
|
+
href="https://cdn.jsdelivr.net/npm/@fr0st/ui@latest/dist/frost-ui.min.css">
|
|
64
54
|
<script type="importmap">
|
|
65
55
|
{
|
|
66
56
|
"imports": {
|
|
67
|
-
"@fr0st/core": "https://cdn.jsdelivr.net/npm/@fr0st/core@
|
|
68
|
-
"@fr0st/query": "https://cdn.jsdelivr.net/npm/@fr0st/query@
|
|
69
|
-
"@fr0st/ui": "https://cdn.jsdelivr.net/npm/@fr0st/ui@
|
|
57
|
+
"@fr0st/core": "https://cdn.jsdelivr.net/npm/@fr0st/core@latest/dist/frost-core.esm.min.js",
|
|
58
|
+
"@fr0st/query": "https://cdn.jsdelivr.net/npm/@fr0st/query@latest/dist/fquery.esm.min.js",
|
|
59
|
+
"@fr0st/ui": "https://cdn.jsdelivr.net/npm/@fr0st/ui@latest/dist/frost-ui.esm.min.js"
|
|
70
60
|
}
|
|
71
61
|
}
|
|
72
62
|
</script>
|
|
73
63
|
<script type="module">
|
|
74
|
-
import Sortable from 'https://cdn.jsdelivr.net/npm/@fr0st/ui-sortable@
|
|
75
|
-
|
|
76
|
-
Sortable.init(document.querySelector('#tasks'));
|
|
64
|
+
import Sortable from 'https://cdn.jsdelivr.net/npm/@fr0st/ui-sortable@latest/dist/frost-ui-sortable.esm.min.js';
|
|
77
65
|
</script>
|
|
78
66
|
```
|
|
79
67
|
|
|
80
68
|
### Browser (UMD)
|
|
81
69
|
|
|
82
|
-
Load
|
|
70
|
+
Load the bundles from your own copy or a CDN:
|
|
83
71
|
|
|
84
72
|
```html
|
|
85
73
|
<link
|
|
86
74
|
rel="stylesheet"
|
|
87
|
-
href="
|
|
88
|
-
|
|
89
|
-
<script src="
|
|
90
|
-
|
|
75
|
+
href="/path/to/dist/frost-ui.min.css">
|
|
76
|
+
<script src="/path/to/dist/frost-ui-bundle.min.js"></script>
|
|
77
|
+
<script src="/path/to/dist/frost-ui-sortable.min.js"></script>
|
|
78
|
+
<!-- or -->
|
|
79
|
+
<link
|
|
80
|
+
rel="stylesheet"
|
|
81
|
+
href="https://cdn.jsdelivr.net/npm/@fr0st/ui@latest/dist/frost-ui.min.css">
|
|
82
|
+
<script src="https://cdn.jsdelivr.net/npm/@fr0st/ui@latest/dist/frost-ui-bundle.min.js"></script>
|
|
83
|
+
<script src="https://cdn.jsdelivr.net/npm/@fr0st/ui-sortable@latest/dist/frost-ui-sortable.min.js"></script>
|
|
91
84
|
<script>
|
|
92
|
-
const
|
|
93
|
-
document.querySelector('#tasks'),
|
|
94
|
-
);
|
|
85
|
+
const { Sortable } = globalThis.UI;
|
|
95
86
|
</script>
|
|
96
87
|
```
|
|
97
88
|
|
|
98
|
-
The UMD bundle adds `Sortable` to the existing `globalThis.UI` object.
|
|
89
|
+
The UMD bundle adds `Sortable` to the existing `globalThis.UI` object. Load Frost UI's all-in-one bundle first; it supplies the `UI` and `fQuery` globals.
|
|
99
90
|
|
|
100
|
-
|
|
91
|
+
The package root resolves to the prebuilt ESM bundle. Published files under `dist/` and `src/` are also available through matching package subpaths.
|
|
101
92
|
|
|
102
93
|
## Usage
|
|
103
94
|
|
|
@@ -112,10 +103,11 @@ Sortable targets direct `<li>` children by default:
|
|
|
112
103
|
```
|
|
113
104
|
|
|
114
105
|
```js
|
|
106
|
+
import $ from '@fr0st/query';
|
|
115
107
|
import Sortable from '@fr0st/ui-sortable';
|
|
116
108
|
|
|
117
109
|
const sortable = Sortable.init(
|
|
118
|
-
|
|
110
|
+
$.findOne('#tasks'),
|
|
119
111
|
{ cursor: 'grab' },
|
|
120
112
|
);
|
|
121
113
|
```
|
|
@@ -139,7 +131,7 @@ Cancel checks include ancestors of the handle up to, but not including, the sort
|
|
|
139
131
|
```
|
|
140
132
|
|
|
141
133
|
```js
|
|
142
|
-
Sortable.init(
|
|
134
|
+
Sortable.init($.findOne('#tasks'), {
|
|
143
135
|
cursor: 'grab',
|
|
144
136
|
handle: '.drag-handle',
|
|
145
137
|
});
|
|
@@ -166,7 +158,7 @@ Initialize each container with a shared `connectWith` selector. Give empty conta
|
|
|
166
158
|
```
|
|
167
159
|
|
|
168
160
|
```js
|
|
169
|
-
|
|
161
|
+
$.find('.connected').forEach((node) => {
|
|
170
162
|
Sortable.init(node, {
|
|
171
163
|
connectWith: '.connected',
|
|
172
164
|
cursor: 'grab',
|
|
@@ -183,10 +175,10 @@ Containers can use different `cursor` and `handle` settings. On transfer, Sortab
|
|
|
183
175
|
Options are resolved in this order:
|
|
184
176
|
|
|
185
177
|
1. Component defaults
|
|
186
|
-
2. The
|
|
178
|
+
2. The element's `data-ui-*` attributes
|
|
187
179
|
3. Options passed to `Sortable.init()`
|
|
188
180
|
|
|
189
|
-
Resolved `instance.options` are frozen.
|
|
181
|
+
Resolved `instance.options` are shallow-frozen.
|
|
190
182
|
|
|
191
183
|
| Option | Type | Default | Description |
|
|
192
184
|
| --- | --- | --- | --- |
|
|
@@ -226,7 +218,7 @@ Auto-scrolling updates item placement and sorting events even while the pointer
|
|
|
226
218
|
|
|
227
219
|
## Data attributes
|
|
228
220
|
|
|
229
|
-
|
|
221
|
+
Use kebab-case `data-ui-*` attributes for serializable options. fQuery normalizes boolean, numeric, array, object, and `null` values.
|
|
230
222
|
|
|
231
223
|
```html
|
|
232
224
|
<ul
|
|
@@ -246,58 +238,51 @@ Every option can be supplied through a `data-ui-*` attribute. fQuery normalizes
|
|
|
246
238
|
</ul>
|
|
247
239
|
```
|
|
248
240
|
|
|
249
|
-
Data attributes do not initialize the component automatically. Initialize matching elements directly or through the fQuery plugin:
|
|
250
|
-
|
|
251
241
|
```js
|
|
242
|
+
import $ from '@fr0st/query';
|
|
243
|
+
import '@fr0st/ui-sortable';
|
|
244
|
+
|
|
252
245
|
$('[data-ui-toggle="sortable"]').sortable();
|
|
253
246
|
```
|
|
254
247
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
### `Sortable.init(node, options?)`
|
|
258
|
-
|
|
259
|
-
Return the existing instance for `node`, or create one with the supplied options.
|
|
248
|
+
Data attributes configure options; they do not initialize Sortable by themselves. Initialize the component through the class or fQuery plugin. Changing an option's data attribute after initialization does not reconfigure the existing instance.
|
|
260
249
|
|
|
261
|
-
|
|
250
|
+
## Methods
|
|
262
251
|
|
|
263
|
-
|
|
252
|
+
| Method | Returns | Description |
|
|
253
|
+
| --- | --- | --- |
|
|
254
|
+
| `Sortable.init(node, options?)` | `Sortable` | Return the existing instance for an element or create one. |
|
|
255
|
+
| `disable()` | `void` | Stop the instance from starting sorts or receiving connected items. |
|
|
256
|
+
| `dispose()` | `void` | Remove owned events and registered state, release cursor locks, and cancel scrolling and active drag state. |
|
|
257
|
+
| `enable()` | `void` | Allow the instance to start and receive sorts. |
|
|
258
|
+
| `items()` | `HTMLElement[]` | Return a fresh array of elements matching the configured `items` selector. |
|
|
264
259
|
|
|
265
260
|
```js
|
|
266
261
|
const items = sortable.items();
|
|
262
|
+
sortable.disable();
|
|
263
|
+
sortable.enable();
|
|
264
|
+
sortable.dispose();
|
|
267
265
|
```
|
|
268
266
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
Stop the instance from starting sorts or receiving connected items.
|
|
267
|
+
Disposal restores original inline cursor declarations, including `!important` priority, and releases cursor style locks.
|
|
272
268
|
|
|
273
|
-
|
|
269
|
+
## Lifecycle
|
|
274
270
|
|
|
275
|
-
|
|
271
|
+
Calling `Sortable.init()` again for the same element returns its existing instance. Dispose the current instance before reinitializing with different options.
|
|
276
272
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
Detach Sortable events, restore original inline cursor declarations (including `!important` priority), release cursor style locks, cancel active auto-scrolling, clear active drag state, remove stored component data, and set `node` and `options` to `null`. Calling `dispose()` again has no effect.
|
|
280
|
-
|
|
281
|
-
## fQuery plugin
|
|
282
|
-
|
|
283
|
-
Registration adds `sortable` to `fQuery.QuerySet.prototype`:
|
|
284
|
-
|
|
285
|
-
```js
|
|
286
|
-
const sortable = $('#tasks').sortable({ cursor: 'grab' });
|
|
273
|
+
An instance exposes its original element as `instance.node` and its shallow-frozen resolved configuration as `instance.options`. Both become `null` after disposal.
|
|
287
274
|
|
|
288
|
-
|
|
289
|
-
$('#tasks').sortable('enable');
|
|
290
|
-
const items = $('#tasks').sortable('items');
|
|
291
|
-
$('#tasks').sortable('dispose');
|
|
292
|
-
```
|
|
275
|
+
`dispose()` releases resources owned by the component and removes its registered instance. Repeated disposal is safe and does not affect a new instance initialized on the same element. Use a new instance before calling other methods after disposal.
|
|
293
276
|
|
|
294
|
-
|
|
277
|
+
If initialization fails, the component releases resources it created and removes its registered instance before rethrowing the error. The element can then be initialized again.
|
|
295
278
|
|
|
296
279
|
## Events
|
|
297
280
|
|
|
298
281
|
Listen with fQuery's namespaced event API:
|
|
299
282
|
|
|
300
283
|
```js
|
|
284
|
+
import $ from '@fr0st/query';
|
|
285
|
+
|
|
301
286
|
$.addEvent(
|
|
302
287
|
'#tasks',
|
|
303
288
|
'sort.ui.sortable sorting.ui.sortable sorted.ui.sortable update.ui.sortable',
|
|
@@ -313,14 +298,14 @@ $.addEvent(
|
|
|
313
298
|
);
|
|
314
299
|
```
|
|
315
300
|
|
|
316
|
-
| Event |
|
|
317
|
-
| --- | --- |
|
|
318
|
-
| `sort.ui.sortable` |
|
|
319
|
-
| `sorting.ui.sortable` |
|
|
320
|
-
| `send.ui.sortable` |
|
|
321
|
-
| `receive.ui.sortable` |
|
|
322
|
-
| `sorted.ui.sortable` |
|
|
323
|
-
| `update.ui.sortable` |
|
|
301
|
+
| Event | Description |
|
|
302
|
+
| --- | --- |
|
|
303
|
+
| `sort.ui.sortable` | The first movement begins an active sort. Emitted on the source container. |
|
|
304
|
+
| `sorting.ui.sortable` | The item changes index within the same container. Emitted on the current container. |
|
|
305
|
+
| `send.ui.sortable` | The item moves out to a connected container. Emitted on the previous container. |
|
|
306
|
+
| `receive.ui.sortable` | The item enters from a connected container. Emitted on the new container. |
|
|
307
|
+
| `sorted.ui.sortable` | The pointer or touch is released, or the touch sequence is cancelled, after an active sort. Emitted on the final container. |
|
|
308
|
+
| `update.ui.sortable` | The final order changes. Cross-container moves update both source and destination. Emitted on each container whose order changed. |
|
|
324
309
|
|
|
325
310
|
Every event exposes the same normalized fields directly and through `event.detail`:
|
|
326
311
|
|
|
@@ -335,12 +320,32 @@ Every event exposes the same normalized fields directly and through `event.detai
|
|
|
335
320
|
|
|
336
321
|
Indices are calculated among elements matching the container's configured `items` selector; unrelated child elements are not counted.
|
|
337
322
|
|
|
338
|
-
##
|
|
323
|
+
## fQuery API
|
|
339
324
|
|
|
340
|
-
Sortable
|
|
325
|
+
Importing Sortable registers `sortable` on `fQuery.QuerySet`:
|
|
326
|
+
|
|
327
|
+
```js
|
|
328
|
+
import $ from '@fr0st/query';
|
|
329
|
+
import '@fr0st/ui-sortable';
|
|
330
|
+
|
|
331
|
+
const sortable = $('#tasks').sortable({ cursor: 'grab' });
|
|
332
|
+
|
|
333
|
+
$('#tasks').sortable('disable');
|
|
334
|
+
$('#tasks').sortable('enable');
|
|
335
|
+
const items = $('#tasks').sortable('items');
|
|
336
|
+
$('#tasks').sortable('dispose');
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Pass an options object to initialize every matched element, or pass a public method name followed by its arguments. The first component or method result is returned.
|
|
340
|
+
|
|
341
|
+
## Accessibility
|
|
341
342
|
|
|
342
343
|
Pointer sorting does not replace keyboard-accessible ordering controls. For workflows where order is essential, provide buttons or another keyboard mechanism that performs the same move and communicates the updated position to assistive technology. A visible drag handle should have an accessible label that describes its purpose.
|
|
343
344
|
|
|
345
|
+
## Customization
|
|
346
|
+
|
|
347
|
+
Sortable does not ship component-specific CSS or Sass. It composes existing Frost UI classes and leaves collection layout to the application. The default helper class, `bg-body-tertiary`, comes from Frost UI and can be replaced or disabled with `helperClass: null`.
|
|
348
|
+
|
|
344
349
|
For touch interfaces, applying `touch-action: none` to sortable items or handles prevents browser gestures from competing with dragging:
|
|
345
350
|
|
|
346
351
|
```css
|
|
@@ -350,13 +355,19 @@ For touch interfaces, applying `touch-action: none` to sortable items or handles
|
|
|
350
355
|
}
|
|
351
356
|
```
|
|
352
357
|
|
|
358
|
+
## Themes and RTL
|
|
359
|
+
|
|
360
|
+
Frost UI follows the user's preferred color scheme by default. Set `data-ui-theme="light"` or `data-ui-theme="dark"` on the document or an ancestor to select a theme explicitly.
|
|
361
|
+
|
|
362
|
+
Sortable uses Frost UI utilities for helper styling. The application's CSS controls list layout and item presentation; sorting follows the rendered item geometry.
|
|
363
|
+
|
|
353
364
|
## Browser support
|
|
354
365
|
|
|
355
366
|
Bundles are built with Vite's `baseline-widely-available` target. The automated browser suite is configured for the Chromium, Firefox, and WebKit versions supplied by the installed Playwright release.
|
|
356
367
|
|
|
357
368
|
## Development
|
|
358
369
|
|
|
359
|
-
|
|
370
|
+
Install dependencies with `npm ci`, then install Playwright browsers with `npx playwright install --with-deps`.
|
|
360
371
|
|
|
361
372
|
```bash
|
|
362
373
|
npm test
|
|
@@ -364,12 +375,14 @@ npm run lint
|
|
|
364
375
|
npm run build
|
|
365
376
|
```
|
|
366
377
|
|
|
367
|
-
`npm test` rebuilds
|
|
378
|
+
`npm test` rebuilds the bundles, then runs the Playwright suite in Chromium, Firefox, and WebKit. `npm run test:browser` runs the suite against the existing bundles, so rebuild after changing source files.
|
|
368
379
|
|
|
369
|
-
After building, `npm run test:coverage` runs Chromium tests and writes coverage reports to `coverage
|
|
380
|
+
After building, `npm run test:coverage` runs Chromium tests and writes coverage reports to `coverage/`.
|
|
370
381
|
|
|
371
382
|
`npm run test:headed` and `npm run test:ui` also use the existing bundles and open headed browsers or the Playwright UI.
|
|
372
383
|
|
|
384
|
+
To view the demo, open `demo/index.html` in your browser after building.
|
|
385
|
+
|
|
373
386
|
## License
|
|
374
387
|
|
|
375
388
|
Frost UI Sortable is released under the [MIT License](./LICENSE).
|
|
@@ -95,6 +95,7 @@ var Sortable = class extends BaseComponent {
|
|
|
95
95
|
#currentSortable;
|
|
96
96
|
#dragging;
|
|
97
97
|
#enabled;
|
|
98
|
+
#initialCursorNodes = [];
|
|
98
99
|
#pos;
|
|
99
100
|
#scrollFrame;
|
|
100
101
|
#selector;
|
|
@@ -107,11 +108,18 @@ var Sortable = class extends BaseComponent {
|
|
|
107
108
|
*/
|
|
108
109
|
constructor(node, options) {
|
|
109
110
|
super(node, options);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
try {
|
|
112
|
+
this.#selector = this.options.handle ? `:is(${this.options.items}) :is(${this.options.handle})` : this.options.items;
|
|
113
|
+
this.#dragging = false;
|
|
114
|
+
this.#enabled = !this.options.disabled;
|
|
115
|
+
this.#initialCursorNodes = $.find(this.#selector, this.node);
|
|
116
|
+
setCursor(this.#initialCursorNodes, this.options.cursor);
|
|
117
|
+
this.#events();
|
|
118
|
+
this.#initialCursorNodes = null;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
this.dispose();
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
115
123
|
}
|
|
116
124
|
/**
|
|
117
125
|
* Disables the Sortable.
|
|
@@ -124,9 +132,10 @@ var Sortable = class extends BaseComponent {
|
|
|
124
132
|
if (!this.node) return;
|
|
125
133
|
$.removeEventDelegate(this.node, "mousedown.ui.sortable touchstart.ui.sortable");
|
|
126
134
|
$.removeEvent(this.node, "receive.ui.sortable");
|
|
127
|
-
resetCursor($.find(this.#selector, this.node));
|
|
135
|
+
resetCursor(this.#initialCursorNodes ?? $.find(this.#selector, this.node));
|
|
128
136
|
if (this.#target && this.options.helperClass) $.removeClass(this.#target, this.options.helperClass);
|
|
129
137
|
this.#resetDrag();
|
|
138
|
+
this.#initialCursorNodes = null;
|
|
130
139
|
super.dispose();
|
|
131
140
|
}
|
|
132
141
|
/**
|
|
@@ -183,16 +192,16 @@ var Sortable = class extends BaseComponent {
|
|
|
183
192
|
* Attaches events for the Sortable.
|
|
184
193
|
*/
|
|
185
194
|
#events() {
|
|
186
|
-
const downEvent = (
|
|
187
|
-
const cancelled = this.options.cancel && ($.is(
|
|
188
|
-
if (
|
|
189
|
-
this.#target = this.options.handle ? this.items().find((node) => $.hasDescendent(node,
|
|
195
|
+
const downEvent = (event) => {
|
|
196
|
+
const cancelled = this.options.cancel && ($.is(event.target, this.options.cancel) || $.is(event.currentTarget, this.options.cancel) || $.closest(event.target, this.options.cancel, this.node).length);
|
|
197
|
+
if (event.button || !this.#enabled || cancelled || $.getDataset(this.node, "uiDragging")) return false;
|
|
198
|
+
this.#target = this.options.handle ? this.items().find((node) => $.hasDescendent(node, event.currentTarget)) : event.currentTarget;
|
|
190
199
|
if (!this.#target) return false;
|
|
191
200
|
};
|
|
192
|
-
const moveEvent = (
|
|
201
|
+
const moveEvent = (event) => {
|
|
193
202
|
if (!this.node || !this.#target) return;
|
|
194
203
|
const previousPos = this.#pos;
|
|
195
|
-
this.#pos = getPosition(
|
|
204
|
+
this.#pos = getPosition(event);
|
|
196
205
|
const deltaX = previousPos ? this.#pos.x - previousPos.x : 0;
|
|
197
206
|
const deltaY = previousPos ? this.#pos.y - previousPos.y : 0;
|
|
198
207
|
if (!this.#dragging) {
|
|
@@ -216,13 +225,13 @@ var Sortable = class extends BaseComponent {
|
|
|
216
225
|
this.#updatePlacement(deltaX, deltaY);
|
|
217
226
|
this.#scheduleScroll();
|
|
218
227
|
};
|
|
219
|
-
const upEvent = (
|
|
228
|
+
const upEvent = (event) => {
|
|
220
229
|
if (!this.node) return;
|
|
221
230
|
if (!this.#dragging) {
|
|
222
231
|
this.#target = null;
|
|
223
232
|
return;
|
|
224
233
|
}
|
|
225
|
-
if (
|
|
234
|
+
if (event.type === "mouseup") event.preventDefault();
|
|
226
235
|
const source = this.node;
|
|
227
236
|
const destination = this.#currentSortable;
|
|
228
237
|
/** @type {SortableEventData} */
|
|
@@ -244,7 +253,7 @@ var Sortable = class extends BaseComponent {
|
|
|
244
253
|
};
|
|
245
254
|
const dragEvent = $.mouseDragFactory(downEvent, moveEvent, upEvent);
|
|
246
255
|
$.addEventDelegate(this.node, "mousedown.ui.sortable touchstart.ui.sortable", this.#selector, dragEvent);
|
|
247
|
-
$.addEvent(this.node, "receive.ui.sortable", (
|
|
256
|
+
$.addEvent(this.node, "receive.ui.sortable", () => {
|
|
248
257
|
setCursor($.find(this.#selector, this.node), this.options.cursor);
|
|
249
258
|
});
|
|
250
259
|
}
|
|
@@ -267,7 +276,7 @@ var Sortable = class extends BaseComponent {
|
|
|
267
276
|
*/
|
|
268
277
|
#scheduleScroll() {
|
|
269
278
|
if (!this.node || !this.options.scroll || !this.#dragging || this.#scrollFrame !== null && this.#scrollFrame !== void 0) return;
|
|
270
|
-
this.#scrollFrame = window.requestAnimationFrame((
|
|
279
|
+
this.#scrollFrame = window.requestAnimationFrame(() => {
|
|
271
280
|
this.#checkScroll();
|
|
272
281
|
});
|
|
273
282
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frost-ui-sortable.esm.js","names":[],"sources":["../src/helpers.js","../src/sortable.js","../src/index.js"],"sourcesContent":["/** @import { SortableEventData } from './sortable.js'; */\n\nimport $ from '@fr0st/query';\n\nconst cursorLocks = new WeakMap();\n\n/**\n * Resets the cursor style for a collection of elements.\n * @param {Iterable<HTMLElement>} nodes The elements to restore.\n */\nexport function resetCursor(nodes) {\n for (const node of nodes) {\n const release = cursorLocks.get(node);\n\n if (!release) {\n continue;\n }\n\n release();\n cursorLocks.delete(node);\n }\n};\n\n/**\n * Sets the cursor style for a collection of elements.\n * @param {Iterable<HTMLElement>} nodes The elements to update.\n * @param {string} cursor The cursor style.\n */\nexport function setCursor(nodes, cursor) {\n for (const node of nodes) {\n if (cursorLocks.has(node)) {\n $.setStyle(node, { cursor });\n } else {\n cursorLocks.set(node, $.setStyleLock(node, 'cursor', cursor));\n }\n }\n};\n\n/**\n * Triggers a Sortable event with its data and detail payloads.\n * @param {HTMLElement} node The event target.\n * @param {string} name The event name without its namespace.\n * @param {SortableEventData} data The sorting event data.\n */\nexport function triggerSortableEvent(node, name, data) {\n $.triggerEvent(node, `${name}.ui.sortable`, {\n data,\n detail: {\n target: data.item,\n ...data,\n },\n });\n};\n","import $ from '@fr0st/query';\nimport { BaseComponent, getPosition } from '@fr0st/ui';\nimport { resetCursor, setCursor, triggerSortableEvent } from './helpers.js';\n\nconst document = $.getContext();\nconst window = $.getWindow();\n\n/** @typedef {'x'|'y'} SortableAxis */\n\n/**\n * @typedef {object} SortableOptions\n * @property {SortableAxis|null} [axis=null] The axis used to determine item placement.\n * @property {string} [cancel='input, textarea, button, select, option'] The selector for elements that cannot start a sort.\n * @property {string|null} [connectWith=null] The selector for connected Sortable containers.\n * @property {string} [cursor='auto'] The cursor applied to sortable items or handles.\n * @property {boolean} [disabled=false] Whether sorting is initially disabled.\n * @property {boolean} [dropOnEmpty=true] Whether connected empty containers accept items.\n * @property {string|null} [handle=null] The handle selector within each sortable item.\n * @property {string|null} [helperClass='bg-body-tertiary'] The class applied to an item while it is being sorted.\n * @property {string} [items=':scope > li'] The selector for sortable items.\n * @property {boolean} [scroll=true] Whether to scroll the window while sorting near an edge.\n * @property {number} [scrollSensitivity=20] The distance from a window edge that starts scrolling, in pixels.\n * @property {number} [scrollSpeed=5] The scroll distance applied per animation frame, in pixels.\n * @property {number} [swapThreshold=0.25] The fraction of an item crossed before swapping, from `0` to `1`.\n */\n\n/**\n * @typedef {object} SortableEventData\n * @property {HTMLElement} item The item being sorted.\n * @property {HTMLElement} from The previous or original Sortable container.\n * @property {HTMLElement} to The next or final Sortable container.\n * @property {number} oldIndex The previous or original item index.\n * @property {number} newIndex The next or final item index.\n */\n\n/**\n * Controls a sortable collection of elements.\n * @augments {BaseComponent<SortableOptions>}\n */\nexport default class Sortable extends BaseComponent {\n /** @type {SortableOptions} */\n static defaults = {\n axis: null,\n cancel: 'input, textarea, button, select, option',\n connectWith: null,\n cursor: 'auto',\n disabled: false,\n dropOnEmpty: true,\n handle: null,\n helperClass: 'bg-body-tertiary',\n items: ':scope > li',\n scroll: true,\n scrollSensitivity: 20,\n scrollSpeed: 5,\n swapThreshold: 0.25,\n };\n\n #currentIndex;\n #currentSortable;\n #dragging;\n #enabled;\n #pos;\n #scrollFrame;\n #selector;\n #startIndex;\n #target;\n\n /**\n * Creates a Sortable.\n * @param {HTMLElement} node The sortable container.\n * @param {SortableOptions} [options] The Sortable options.\n */\n constructor(node, options) {\n super(node, options);\n\n this.#selector = this.options.handle ?\n `:is(${this.options.items}) :is(${this.options.handle})` :\n this.options.items;\n\n this.#dragging = false;\n this.#enabled = !this.options.disabled;\n\n setCursor($.find(this.#selector, this.node), this.options.cursor);\n this.#events();\n }\n\n /**\n * Disables the Sortable.\n */\n disable() {\n this.#enabled = false;\n }\n\n /** @inheritdoc */\n dispose() {\n if (!this.node) {\n return;\n }\n\n $.removeEventDelegate(this.node, 'mousedown.ui.sortable touchstart.ui.sortable');\n $.removeEvent(this.node, 'receive.ui.sortable');\n resetCursor($.find(this.#selector, this.node));\n\n if (this.#target && this.options.helperClass) {\n $.removeClass(this.#target, this.options.helperClass);\n }\n\n this.#resetDrag();\n\n super.dispose();\n }\n\n /**\n * Enables the Sortable.\n */\n enable() {\n this.#enabled = true;\n }\n\n /**\n * Gets the Sortable item elements.\n * @returns {HTMLElement[]} The Sortable item elements.\n */\n items() {\n return $.find(this.options.items, this.node);\n }\n\n /**\n * Checks whether the window should scroll while sorting.\n */\n #checkScroll() {\n this.#scrollFrame = null;\n\n if (!this.node || !this.#dragging || !this.#target || !this.#pos) {\n return;\n }\n\n const originalX = $.getScrollX(window);\n const originalY = $.getScrollY(window);\n const windowHeight = $.height(window);\n const windowWidth = $.width(window);\n\n let offsetX = originalX;\n let offsetY = originalY;\n\n if (this.#pos.y < originalY + this.options.scrollSensitivity) {\n offsetY = Math.max(0, originalY - this.options.scrollSpeed);\n } else if (this.#pos.y > originalY + windowHeight - this.options.scrollSensitivity) {\n const docHeight = $.height(document, { boxSize: $.SCROLL_BOX });\n const maxY = Math.max(0, docHeight - windowHeight);\n offsetY = Math.min(maxY, originalY + this.options.scrollSpeed);\n }\n\n if (this.#pos.x < originalX + this.options.scrollSensitivity) {\n offsetX = Math.max(0, originalX - this.options.scrollSpeed);\n } else if (this.#pos.x > originalX + windowWidth - this.options.scrollSensitivity) {\n const docWidth = $.width(document, { boxSize: $.SCROLL_BOX });\n const maxX = Math.max(0, docWidth - windowWidth);\n offsetX = Math.min(maxX, originalX + this.options.scrollSpeed);\n }\n\n if (offsetX === originalX && offsetY === originalY) {\n return;\n }\n\n window.scrollTo({\n left: offsetX,\n top: offsetY,\n behavior: 'instant',\n });\n\n const deltaX = offsetX - originalX;\n const deltaY = offsetY - originalY;\n\n this.#pos.x += deltaX;\n this.#pos.y += deltaY;\n\n this.#updatePlacement(deltaX, deltaY);\n this.#scheduleScroll();\n }\n\n /**\n * Attaches events for the Sortable.\n */\n #events() {\n const downEvent = (e) => {\n const cancelled = this.options.cancel &&\n (\n $.is(e.target, this.options.cancel) ||\n $.is(e.currentTarget, this.options.cancel) ||\n $.closest(e.target, this.options.cancel, this.node).length\n );\n\n if (\n e.button ||\n !this.#enabled ||\n cancelled ||\n $.getDataset(this.node, 'uiDragging')\n ) {\n return false;\n }\n\n this.#target = this.options.handle ?\n this.items().find((node) => $.hasDescendent(node, e.currentTarget)) :\n e.currentTarget;\n\n if (!this.#target) {\n return false;\n }\n };\n\n const moveEvent = (e) => {\n if (!this.node || !this.#target) {\n return;\n }\n\n const previousPos = this.#pos;\n this.#pos = getPosition(e);\n const deltaX = previousPos ?\n this.#pos.x - previousPos.x :\n 0;\n const deltaY = previousPos ?\n this.#pos.y - previousPos.y :\n 0;\n\n if (!this.#dragging) {\n this.#dragging = true;\n this.#currentSortable = this.node;\n this.#startIndex = this.items().indexOf(this.#target);\n this.#currentIndex = this.#startIndex;\n\n $.setDataset(this.node, { uiDragging: true });\n\n /** @type {SortableEventData} */\n const eventData = {\n item: this.#target,\n from: this.node,\n to: this.node,\n oldIndex: this.#startIndex,\n newIndex: this.#startIndex,\n };\n\n triggerSortableEvent(this.node, 'sort', eventData);\n\n if (!this.node) {\n return;\n }\n\n if (this.options.helperClass) {\n $.addClass(this.#target, this.options.helperClass);\n }\n }\n\n this.#updatePlacement(deltaX, deltaY);\n this.#scheduleScroll();\n };\n\n const upEvent = (e) => {\n if (!this.node) {\n return;\n }\n\n if (!this.#dragging) {\n this.#target = null;\n return;\n }\n\n if (e.type === 'mouseup') {\n e.preventDefault();\n }\n\n const source = this.node;\n const destination = this.#currentSortable;\n /** @type {SortableEventData} */\n const eventData = {\n item: this.#target,\n from: source,\n to: destination,\n oldIndex: this.#startIndex,\n newIndex: this.#currentIndex,\n };\n\n triggerSortableEvent(destination, 'sorted', eventData);\n\n if (!this.node) {\n return;\n }\n\n if (this.options.helperClass) {\n $.removeClass(this.#target, this.options.helperClass);\n }\n\n if (source !== destination) {\n triggerSortableEvent(source, 'update', eventData);\n\n if (this.node) {\n triggerSortableEvent(destination, 'update', eventData);\n }\n } else if (this.#currentIndex !== this.#startIndex) {\n triggerSortableEvent(destination, 'update', eventData);\n }\n\n if (this.node) {\n this.#resetDrag();\n }\n };\n\n const dragEvent = $.mouseDragFactory(downEvent, moveEvent, upEvent);\n\n $.addEventDelegate(\n this.node,\n 'mousedown.ui.sortable touchstart.ui.sortable',\n this.#selector,\n dragEvent,\n );\n\n $.addEvent(this.node, 'receive.ui.sortable', (_) => {\n setCursor($.find(this.#selector, this.node), this.options.cursor);\n });\n }\n\n /**\n * Resets the active drag state.\n */\n #resetDrag() {\n if (this.#scrollFrame !== null && this.#scrollFrame !== undefined) {\n window.cancelAnimationFrame(this.#scrollFrame);\n }\n\n if (this.#dragging && this.node) {\n $.removeDataset(this.node, 'uiDragging');\n }\n\n this.#currentIndex = null;\n this.#currentSortable = null;\n this.#dragging = false;\n this.#pos = null;\n this.#scrollFrame = null;\n this.#startIndex = null;\n this.#target = null;\n }\n\n /**\n * Schedules the next auto-scroll update.\n */\n #scheduleScroll() {\n if (\n !this.node ||\n !this.options.scroll ||\n !this.#dragging ||\n this.#scrollFrame !== null && this.#scrollFrame !== undefined\n ) {\n return;\n }\n\n this.#scrollFrame = window.requestAnimationFrame((_) => {\n this.#checkScroll();\n });\n }\n\n /**\n * Updates item placement and sorting events for the current pointer position.\n * @param {number} deltaX The horizontal pointer movement.\n * @param {number} deltaY The vertical pointer movement.\n */\n #updatePlacement(deltaX, deltaY) {\n let nearestSortable = this.node;\n\n if (this.options.connectWith) {\n const connected = $.find(this.options.connectWith)\n .filter((node) => node !== this.node)\n .filter((node) => {\n const sortable = this.constructor.init(node);\n\n return sortable.#enabled &&\n (sortable.options.dropOnEmpty || sortable.items().length);\n });\n\n if (connected.length) {\n nearestSortable = $.nearestTo(\n [this.node, ...connected],\n this.#pos.x,\n this.#pos.y,\n { offset: true },\n );\n }\n }\n\n const nearestInstance = this.constructor.init(nearestSortable);\n const nearestItems = nearestInstance.items()\n .filter((node) => node !== this.#target);\n const nearestItem = $.nearestTo(\n nearestItems,\n this.#pos.x,\n this.#pos.y,\n { offset: true },\n );\n\n if (nearestItem) {\n this.#updateTarget(\n nearestItem,\n this.#pos.x,\n this.#pos.y,\n deltaX,\n deltaY,\n );\n } else if (nearestSortable !== this.#currentSortable) {\n $.append(nearestSortable, this.#target);\n } else {\n return;\n }\n\n const newIndex = nearestInstance.items().indexOf(this.#target);\n\n if (nearestSortable !== this.#currentSortable) {\n const previousSortable = this.#currentSortable;\n const previousInstance = this.constructor.init(previousSortable);\n const { handle } = previousInstance.options;\n\n resetCursor(handle ?\n $.find(handle, this.#target) :\n [this.#target]);\n\n /** @type {SortableEventData} */\n const eventData = {\n item: this.#target,\n from: previousSortable,\n to: nearestSortable,\n oldIndex: this.#currentIndex,\n newIndex,\n };\n\n triggerSortableEvent(previousSortable, 'send', eventData);\n\n if (!this.node) {\n return;\n }\n\n triggerSortableEvent(nearestSortable, 'receive', eventData);\n } else if (this.#currentIndex !== newIndex) {\n /** @type {SortableEventData} */\n const eventData = {\n item: this.#target,\n from: nearestSortable,\n to: nearestSortable,\n oldIndex: this.#currentIndex,\n newIndex,\n };\n\n triggerSortableEvent(nearestSortable, 'sorting', eventData);\n }\n\n if (!this.node) {\n return;\n }\n\n this.#currentIndex = newIndex;\n this.#currentSortable = nearestSortable;\n }\n\n /**\n * Moves the target relative to the nearest item.\n * @param {HTMLElement} nearestItem The nearest item.\n * @param {number} x The mouse X position.\n * @param {number} y The mouse Y position.\n * @param {number} deltaX The horizontal pointer movement.\n * @param {number} deltaY The vertical pointer movement.\n */\n #updateTarget(nearestItem, x, y, deltaX, deltaY) {\n const nearestCenter = $.center(nearestItem, { offset: true });\n const nearestRect = $.rect(nearestItem, { offset: true });\n const targetCenter = $.center(this.#target, { offset: true });\n const threshold = Math.min(1, Math.max(0, this.options.swapThreshold));\n let thresholdX = 0.5;\n let thresholdY = 0.5;\n\n if (deltaX) {\n thresholdX = deltaX > 0 ?\n threshold :\n 1 - threshold;\n }\n\n if (deltaY) {\n thresholdY = deltaY > 0 ?\n threshold :\n 1 - threshold;\n }\n\n let method;\n if (this.options.axis === 'y' || nearestCenter.x === targetCenter.x) {\n const swapY = nearestRect.top + nearestRect.height * thresholdY;\n method = y < swapY ?\n 'before' :\n 'after';\n } else if (this.options.axis === 'x' || nearestCenter.y === targetCenter.y) {\n const swapX = nearestRect.left + nearestRect.width * thresholdX;\n method = x < swapX ?\n 'before' :\n 'after';\n } else {\n const swapX = nearestRect.left + nearestRect.width * thresholdX;\n const swapY = nearestRect.top + nearestRect.height * thresholdY;\n method = x < swapX && y < swapY ?\n 'before' :\n 'after';\n }\n\n $[method](nearestItem, this.#target);\n }\n}\n","import { initComponent } from '@fr0st/ui';\nimport Sortable from './sortable.js';\n\ninitComponent('sortable', Sortable);\n\nexport default Sortable;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"frost-ui-sortable.esm.js","names":[],"sources":["../src/helpers.js","../src/sortable.js","../src/index.js"],"sourcesContent":["/** @import { SortableEventData } from './sortable.js'; */\n\nimport $ from '@fr0st/query';\n\nconst cursorLocks = new WeakMap();\n\n/**\n * Resets the cursor style for a collection of elements.\n * @param {Iterable<HTMLElement>} nodes The elements to restore.\n */\nexport function resetCursor(nodes) {\n for (const node of nodes) {\n const release = cursorLocks.get(node);\n\n if (!release) {\n continue;\n }\n\n release();\n cursorLocks.delete(node);\n }\n}\n\n/**\n * Sets the cursor style for a collection of elements.\n * @param {Iterable<HTMLElement>} nodes The elements to update.\n * @param {string} cursor The cursor style.\n */\nexport function setCursor(nodes, cursor) {\n for (const node of nodes) {\n if (cursorLocks.has(node)) {\n $.setStyle(node, { cursor });\n } else {\n cursorLocks.set(node, $.setStyleLock(node, 'cursor', cursor));\n }\n }\n}\n\n/**\n * Triggers a Sortable event with its data and detail payloads.\n * @param {HTMLElement} node The event target.\n * @param {string} name The event name without its namespace.\n * @param {SortableEventData} data The sorting event data.\n */\nexport function triggerSortableEvent(node, name, data) {\n $.triggerEvent(node, `${name}.ui.sortable`, {\n data,\n detail: {\n target: data.item,\n ...data,\n },\n });\n}\n","import $ from '@fr0st/query';\nimport { BaseComponent, getPosition } from '@fr0st/ui';\nimport { resetCursor, setCursor, triggerSortableEvent } from './helpers.js';\n\nconst document = $.getContext();\nconst window = $.getWindow();\n\n/** @typedef {'x'|'y'} SortableAxis */\n\n/**\n * @typedef {object} SortableOptions\n * @property {SortableAxis|null} [axis=null] The axis used to determine item placement.\n * @property {string} [cancel='input, textarea, button, select, option'] The selector for elements that cannot start a sort.\n * @property {string|null} [connectWith=null] The selector for connected Sortable containers.\n * @property {string} [cursor='auto'] The cursor applied to sortable items or handles.\n * @property {boolean} [disabled=false] Whether sorting is initially disabled.\n * @property {boolean} [dropOnEmpty=true] Whether connected empty containers accept items.\n * @property {string|null} [handle=null] The handle selector within each sortable item.\n * @property {string|null} [helperClass='bg-body-tertiary'] The class applied to an item while it is being sorted.\n * @property {string} [items=':scope > li'] The selector for sortable items.\n * @property {boolean} [scroll=true] Whether to scroll the window while sorting near an edge.\n * @property {number} [scrollSensitivity=20] The distance from a window edge that starts scrolling, in pixels.\n * @property {number} [scrollSpeed=5] The scroll distance applied per animation frame, in pixels.\n * @property {number} [swapThreshold=0.25] The fraction of an item crossed before swapping, from `0` to `1`.\n */\n\n/**\n * @typedef {object} SortableEventData\n * @property {HTMLElement} item The item being sorted.\n * @property {HTMLElement} from The previous or original Sortable container.\n * @property {HTMLElement} to The next or final Sortable container.\n * @property {number} oldIndex The previous or original item index.\n * @property {number} newIndex The next or final item index.\n */\n\n/**\n * Controls a sortable collection of elements.\n * @augments {BaseComponent<SortableOptions>}\n */\nexport default class Sortable extends BaseComponent {\n /** @type {SortableOptions} */\n static defaults = {\n axis: null,\n cancel: 'input, textarea, button, select, option',\n connectWith: null,\n cursor: 'auto',\n disabled: false,\n dropOnEmpty: true,\n handle: null,\n helperClass: 'bg-body-tertiary',\n items: ':scope > li',\n scroll: true,\n scrollSensitivity: 20,\n scrollSpeed: 5,\n swapThreshold: 0.25,\n };\n\n #currentIndex;\n #currentSortable;\n #dragging;\n #enabled;\n #initialCursorNodes = [];\n #pos;\n #scrollFrame;\n #selector;\n #startIndex;\n #target;\n\n /**\n * Creates a Sortable.\n * @param {HTMLElement} node The sortable container.\n * @param {SortableOptions} [options] The Sortable options.\n */\n constructor(node, options) {\n super(node, options);\n\n try {\n this.#selector = this.options.handle ?\n `:is(${this.options.items}) :is(${this.options.handle})` :\n this.options.items;\n\n this.#dragging = false;\n this.#enabled = !this.options.disabled;\n\n this.#initialCursorNodes = $.find(this.#selector, this.node);\n setCursor(this.#initialCursorNodes, this.options.cursor);\n this.#events();\n this.#initialCursorNodes = null;\n } catch (error) {\n this.dispose();\n throw error;\n }\n }\n\n /**\n * Disables the Sortable.\n */\n disable() {\n this.#enabled = false;\n }\n\n /** @inheritdoc */\n dispose() {\n if (!this.node) {\n return;\n }\n\n $.removeEventDelegate(this.node, 'mousedown.ui.sortable touchstart.ui.sortable');\n $.removeEvent(this.node, 'receive.ui.sortable');\n resetCursor(this.#initialCursorNodes ?? $.find(this.#selector, this.node));\n\n if (this.#target && this.options.helperClass) {\n $.removeClass(this.#target, this.options.helperClass);\n }\n\n this.#resetDrag();\n\n this.#initialCursorNodes = null;\n\n super.dispose();\n }\n\n /**\n * Enables the Sortable.\n */\n enable() {\n this.#enabled = true;\n }\n\n /**\n * Gets the Sortable item elements.\n * @returns {HTMLElement[]} The Sortable item elements.\n */\n items() {\n return $.find(this.options.items, this.node);\n }\n\n /**\n * Checks whether the window should scroll while sorting.\n */\n #checkScroll() {\n this.#scrollFrame = null;\n\n if (!this.node || !this.#dragging || !this.#target || !this.#pos) {\n return;\n }\n\n const originalX = $.getScrollX(window);\n const originalY = $.getScrollY(window);\n const windowHeight = $.height(window);\n const windowWidth = $.width(window);\n\n let offsetX = originalX;\n let offsetY = originalY;\n\n if (this.#pos.y < originalY + this.options.scrollSensitivity) {\n offsetY = Math.max(0, originalY - this.options.scrollSpeed);\n } else if (this.#pos.y > originalY + windowHeight - this.options.scrollSensitivity) {\n const docHeight = $.height(document, { boxSize: $.SCROLL_BOX });\n const maxY = Math.max(0, docHeight - windowHeight);\n offsetY = Math.min(maxY, originalY + this.options.scrollSpeed);\n }\n\n if (this.#pos.x < originalX + this.options.scrollSensitivity) {\n offsetX = Math.max(0, originalX - this.options.scrollSpeed);\n } else if (this.#pos.x > originalX + windowWidth - this.options.scrollSensitivity) {\n const docWidth = $.width(document, { boxSize: $.SCROLL_BOX });\n const maxX = Math.max(0, docWidth - windowWidth);\n offsetX = Math.min(maxX, originalX + this.options.scrollSpeed);\n }\n\n if (offsetX === originalX && offsetY === originalY) {\n return;\n }\n\n window.scrollTo({\n left: offsetX,\n top: offsetY,\n behavior: 'instant',\n });\n\n const deltaX = offsetX - originalX;\n const deltaY = offsetY - originalY;\n\n this.#pos.x += deltaX;\n this.#pos.y += deltaY;\n\n this.#updatePlacement(deltaX, deltaY);\n this.#scheduleScroll();\n }\n\n /**\n * Attaches events for the Sortable.\n */\n #events() {\n const downEvent = (event) => {\n const cancelled = this.options.cancel &&\n (\n $.is(event.target, this.options.cancel) ||\n $.is(event.currentTarget, this.options.cancel) ||\n $.closest(event.target, this.options.cancel, this.node).length\n );\n\n if (\n event.button ||\n !this.#enabled ||\n cancelled ||\n $.getDataset(this.node, 'uiDragging')\n ) {\n return false;\n }\n\n this.#target = this.options.handle ?\n this.items().find((node) => $.hasDescendent(node, event.currentTarget)) :\n event.currentTarget;\n\n if (!this.#target) {\n return false;\n }\n };\n\n const moveEvent = (event) => {\n if (!this.node || !this.#target) {\n return;\n }\n\n const previousPos = this.#pos;\n this.#pos = getPosition(event);\n const deltaX = previousPos ?\n this.#pos.x - previousPos.x :\n 0;\n const deltaY = previousPos ?\n this.#pos.y - previousPos.y :\n 0;\n\n if (!this.#dragging) {\n this.#dragging = true;\n this.#currentSortable = this.node;\n this.#startIndex = this.items().indexOf(this.#target);\n this.#currentIndex = this.#startIndex;\n\n $.setDataset(this.node, { uiDragging: true });\n\n /** @type {SortableEventData} */\n const eventData = {\n item: this.#target,\n from: this.node,\n to: this.node,\n oldIndex: this.#startIndex,\n newIndex: this.#startIndex,\n };\n\n triggerSortableEvent(this.node, 'sort', eventData);\n\n if (!this.node) {\n return;\n }\n\n if (this.options.helperClass) {\n $.addClass(this.#target, this.options.helperClass);\n }\n }\n\n this.#updatePlacement(deltaX, deltaY);\n this.#scheduleScroll();\n };\n\n const upEvent = (event) => {\n if (!this.node) {\n return;\n }\n\n if (!this.#dragging) {\n this.#target = null;\n return;\n }\n\n if (event.type === 'mouseup') {\n event.preventDefault();\n }\n\n const source = this.node;\n const destination = this.#currentSortable;\n /** @type {SortableEventData} */\n const eventData = {\n item: this.#target,\n from: source,\n to: destination,\n oldIndex: this.#startIndex,\n newIndex: this.#currentIndex,\n };\n\n triggerSortableEvent(destination, 'sorted', eventData);\n\n if (!this.node) {\n return;\n }\n\n if (this.options.helperClass) {\n $.removeClass(this.#target, this.options.helperClass);\n }\n\n if (source !== destination) {\n triggerSortableEvent(source, 'update', eventData);\n\n if (this.node) {\n triggerSortableEvent(destination, 'update', eventData);\n }\n } else if (this.#currentIndex !== this.#startIndex) {\n triggerSortableEvent(destination, 'update', eventData);\n }\n\n if (this.node) {\n this.#resetDrag();\n }\n };\n\n const dragEvent = $.mouseDragFactory(downEvent, moveEvent, upEvent);\n\n $.addEventDelegate(\n this.node,\n 'mousedown.ui.sortable touchstart.ui.sortable',\n this.#selector,\n dragEvent,\n );\n\n $.addEvent(this.node, 'receive.ui.sortable', () => {\n setCursor($.find(this.#selector, this.node), this.options.cursor);\n });\n }\n\n /**\n * Resets the active drag state.\n */\n #resetDrag() {\n if (this.#scrollFrame !== null && this.#scrollFrame !== undefined) {\n window.cancelAnimationFrame(this.#scrollFrame);\n }\n\n if (this.#dragging && this.node) {\n $.removeDataset(this.node, 'uiDragging');\n }\n\n this.#currentIndex = null;\n this.#currentSortable = null;\n this.#dragging = false;\n this.#pos = null;\n this.#scrollFrame = null;\n this.#startIndex = null;\n this.#target = null;\n }\n\n /**\n * Schedules the next auto-scroll update.\n */\n #scheduleScroll() {\n if (\n !this.node ||\n !this.options.scroll ||\n !this.#dragging ||\n this.#scrollFrame !== null && this.#scrollFrame !== undefined\n ) {\n return;\n }\n\n this.#scrollFrame = window.requestAnimationFrame(() => {\n this.#checkScroll();\n });\n }\n\n /**\n * Updates item placement and sorting events for the current pointer position.\n * @param {number} deltaX The horizontal pointer movement.\n * @param {number} deltaY The vertical pointer movement.\n */\n #updatePlacement(deltaX, deltaY) {\n let nearestSortable = this.node;\n\n if (this.options.connectWith) {\n const connected = $.find(this.options.connectWith)\n .filter((node) => node !== this.node)\n .filter((node) => {\n const sortable = this.constructor.init(node);\n\n return sortable.#enabled &&\n (sortable.options.dropOnEmpty || sortable.items().length);\n });\n\n if (connected.length) {\n nearestSortable = $.nearestTo(\n [this.node, ...connected],\n this.#pos.x,\n this.#pos.y,\n { offset: true },\n );\n }\n }\n\n const nearestInstance = this.constructor.init(nearestSortable);\n const nearestItems = nearestInstance.items()\n .filter((node) => node !== this.#target);\n const nearestItem = $.nearestTo(\n nearestItems,\n this.#pos.x,\n this.#pos.y,\n { offset: true },\n );\n\n if (nearestItem) {\n this.#updateTarget(\n nearestItem,\n this.#pos.x,\n this.#pos.y,\n deltaX,\n deltaY,\n );\n } else if (nearestSortable !== this.#currentSortable) {\n $.append(nearestSortable, this.#target);\n } else {\n return;\n }\n\n const newIndex = nearestInstance.items().indexOf(this.#target);\n\n if (nearestSortable !== this.#currentSortable) {\n const previousSortable = this.#currentSortable;\n const previousInstance = this.constructor.init(previousSortable);\n const { handle } = previousInstance.options;\n\n resetCursor(handle ?\n $.find(handle, this.#target) :\n [this.#target]);\n\n /** @type {SortableEventData} */\n const eventData = {\n item: this.#target,\n from: previousSortable,\n to: nearestSortable,\n oldIndex: this.#currentIndex,\n newIndex,\n };\n\n triggerSortableEvent(previousSortable, 'send', eventData);\n\n if (!this.node) {\n return;\n }\n\n triggerSortableEvent(nearestSortable, 'receive', eventData);\n } else if (this.#currentIndex !== newIndex) {\n /** @type {SortableEventData} */\n const eventData = {\n item: this.#target,\n from: nearestSortable,\n to: nearestSortable,\n oldIndex: this.#currentIndex,\n newIndex,\n };\n\n triggerSortableEvent(nearestSortable, 'sorting', eventData);\n }\n\n if (!this.node) {\n return;\n }\n\n this.#currentIndex = newIndex;\n this.#currentSortable = nearestSortable;\n }\n\n /**\n * Moves the target relative to the nearest item.\n * @param {HTMLElement} nearestItem The nearest item.\n * @param {number} x The mouse X position.\n * @param {number} y The mouse Y position.\n * @param {number} deltaX The horizontal pointer movement.\n * @param {number} deltaY The vertical pointer movement.\n */\n #updateTarget(nearestItem, x, y, deltaX, deltaY) {\n const nearestCenter = $.center(nearestItem, { offset: true });\n const nearestRect = $.rect(nearestItem, { offset: true });\n const targetCenter = $.center(this.#target, { offset: true });\n const threshold = Math.min(1, Math.max(0, this.options.swapThreshold));\n let thresholdX = 0.5;\n let thresholdY = 0.5;\n\n if (deltaX) {\n thresholdX = deltaX > 0 ?\n threshold :\n 1 - threshold;\n }\n\n if (deltaY) {\n thresholdY = deltaY > 0 ?\n threshold :\n 1 - threshold;\n }\n\n let method;\n if (this.options.axis === 'y' || nearestCenter.x === targetCenter.x) {\n const swapY = nearestRect.top + nearestRect.height * thresholdY;\n method = y < swapY ?\n 'before' :\n 'after';\n } else if (this.options.axis === 'x' || nearestCenter.y === targetCenter.y) {\n const swapX = nearestRect.left + nearestRect.width * thresholdX;\n method = x < swapX ?\n 'before' :\n 'after';\n } else {\n const swapX = nearestRect.left + nearestRect.width * thresholdX;\n const swapY = nearestRect.top + nearestRect.height * thresholdY;\n method = x < swapX && y < swapY ?\n 'before' :\n 'after';\n }\n\n $[method](nearestItem, this.#target);\n }\n}\n","import { initComponent } from '@fr0st/ui';\nimport Sortable from './sortable.js';\n\ninitComponent('sortable', Sortable);\n\nexport default Sortable;\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{BaseComponent as e,getPosition as t,initComponent as n}from"@fr0st/ui";import r from"@fr0st/query";var i
|
|
1
|
+
import{BaseComponent as e,getPosition as t,initComponent as n}from"@fr0st/ui";import r from"@fr0st/query";var i=/* @__PURE__ */ new WeakMap;function a(e){for(let t of e){let e=i.get(t);e&&(e(),i.delete(t))}}function o(e,t){for(let n of e)i.has(n)?r.setStyle(n,{cursor:t}):i.set(n,r.setStyleLock(n,`cursor`,t))}function s(e,t,n){r.triggerEvent(e,`${t}.ui.sortable`,{data:n,detail:{target:n.item,...n}})}var c=r.getContext(),l=r.getWindow(),u=class extends e{static defaults={axis:null,cancel:`input, textarea, button, select, option`,connectWith:null,cursor:`auto`,disabled:!1,dropOnEmpty:!0,handle:null,helperClass:`bg-body-tertiary`,items:`:scope > li`,scroll:!0,scrollSensitivity:20,scrollSpeed:5,swapThreshold:.25};#e;#t;#n;#r;#i=[];#a;#o;#s;#c;#l;constructor(e,t){super(e,t);try{this.#s=this.options.handle?`:is(${this.options.items}) :is(${this.options.handle})`:this.options.items,this.#n=!1,this.#r=!this.options.disabled,this.#i=r.find(this.#s,this.node),o(this.#i,this.options.cursor),this.#d(),this.#i=null}catch(e){throw this.dispose(),e}}disable(){this.#r=!1}dispose(){this.node&&(r.removeEventDelegate(this.node,`mousedown.ui.sortable touchstart.ui.sortable`),r.removeEvent(this.node,`receive.ui.sortable`),a(this.#i??r.find(this.#s,this.node)),this.#l&&this.options.helperClass&&r.removeClass(this.#l,this.options.helperClass),this.#f(),this.#i=null,super.dispose())}enable(){this.#r=!0}items(){return r.find(this.options.items,this.node)}#u(){if(this.#o=null,!this.node||!this.#n||!this.#l||!this.#a)return;let e=r.getScrollX(l),t=r.getScrollY(l),n=r.height(l),i=r.width(l),a=e,o=t;if(this.#a.y<t+this.options.scrollSensitivity)o=Math.max(0,t-this.options.scrollSpeed);else if(this.#a.y>t+n-this.options.scrollSensitivity){let e=r.height(c,{boxSize:r.SCROLL_BOX}),i=Math.max(0,e-n);o=Math.min(i,t+this.options.scrollSpeed)}if(this.#a.x<e+this.options.scrollSensitivity)a=Math.max(0,e-this.options.scrollSpeed);else if(this.#a.x>e+i-this.options.scrollSensitivity){let t=r.width(c,{boxSize:r.SCROLL_BOX}),n=Math.max(0,t-i);a=Math.min(n,e+this.options.scrollSpeed)}if(a===e&&o===t)return;l.scrollTo({left:a,top:o,behavior:`instant`});let s=a-e,u=o-t;this.#a.x+=s,this.#a.y+=u,this.#m(s,u),this.#p()}#d(){let e=r.mouseDragFactory(e=>{let t=this.options.cancel&&(r.is(e.target,this.options.cancel)||r.is(e.currentTarget,this.options.cancel)||r.closest(e.target,this.options.cancel,this.node).length);if(e.button||!this.#r||t||r.getDataset(this.node,`uiDragging`)||(this.#l=this.options.handle?this.items().find(t=>r.hasDescendent(t,e.currentTarget)):e.currentTarget,!this.#l))return!1},e=>{if(!this.node||!this.#l)return;let n=this.#a;this.#a=t(e);let i=n?this.#a.x-n.x:0,a=n?this.#a.y-n.y:0;if(!this.#n){this.#n=!0,this.#t=this.node,this.#c=this.items().indexOf(this.#l),this.#e=this.#c,r.setDataset(this.node,{uiDragging:!0});let e={item:this.#l,from:this.node,to:this.node,oldIndex:this.#c,newIndex:this.#c};if(s(this.node,`sort`,e),!this.node)return;this.options.helperClass&&r.addClass(this.#l,this.options.helperClass)}this.#m(i,a),this.#p()},e=>{if(!this.node)return;if(!this.#n){this.#l=null;return}e.type===`mouseup`&&e.preventDefault();let t=this.node,n=this.#t,i={item:this.#l,from:t,to:n,oldIndex:this.#c,newIndex:this.#e};s(n,`sorted`,i),this.node&&(this.options.helperClass&&r.removeClass(this.#l,this.options.helperClass),t===n?this.#e!==this.#c&&s(n,`update`,i):(s(t,`update`,i),this.node&&s(n,`update`,i)),this.node&&this.#f())});r.addEventDelegate(this.node,`mousedown.ui.sortable touchstart.ui.sortable`,this.#s,e),r.addEvent(this.node,`receive.ui.sortable`,()=>{o(r.find(this.#s,this.node),this.options.cursor)})}#f(){this.#o!==null&&this.#o!==void 0&&l.cancelAnimationFrame(this.#o),this.#n&&this.node&&r.removeDataset(this.node,`uiDragging`),this.#e=null,this.#t=null,this.#n=!1,this.#a=null,this.#o=null,this.#c=null,this.#l=null}#p(){this.node&&this.options.scroll&&this.#n&&(this.#o===null||this.#o===void 0)&&(this.#o=l.requestAnimationFrame(()=>{this.#u()}))}#m(e,t){let n=this.node;if(this.options.connectWith){let e=r.find(this.options.connectWith).filter(e=>e!==this.node).filter(e=>{let t=this.constructor.init(e);return t.#r&&(t.options.dropOnEmpty||t.items().length)});e.length&&(n=r.nearestTo([this.node,...e],this.#a.x,this.#a.y,{offset:!0}))}let i=this.constructor.init(n),o=i.items().filter(e=>e!==this.#l),c=r.nearestTo(o,this.#a.x,this.#a.y,{offset:!0});if(c)this.#h(c,this.#a.x,this.#a.y,e,t);else if(n!==this.#t)r.append(n,this.#l);else return;let l=i.items().indexOf(this.#l);if(n!==this.#t){let e=this.#t,{handle:t}=this.constructor.init(e).options;a(t?r.find(t,this.#l):[this.#l]);let i={item:this.#l,from:e,to:n,oldIndex:this.#e,newIndex:l};if(s(e,`send`,i),!this.node)return;s(n,`receive`,i)}else if(this.#e!==l){let e={item:this.#l,from:n,to:n,oldIndex:this.#e,newIndex:l};s(n,`sorting`,e)}this.node&&(this.#e=l,this.#t=n)}#h(e,t,n,i,a){let o=r.center(e,{offset:!0}),s=r.rect(e,{offset:!0}),c=r.center(this.#l,{offset:!0}),l=Math.min(1,Math.max(0,this.options.swapThreshold)),u=.5,d=.5;i&&(u=i>0?l:1-l),a&&(d=a>0?l:1-l);let f;if(this.options.axis===`y`||o.x===c.x)f=n<s.top+s.height*d?`before`:`after`;else if(this.options.axis===`x`||o.y===c.y)f=t<s.left+s.width*u?`before`:`after`;else{let e=s.left+s.width*u,r=s.top+s.height*d;f=t<e&&n<r?`before`:`after`}r[f](e,this.#l)}};n(`sortable`,u);var d=u;export{d as default};
|
|
2
2
|
//# sourceMappingURL=frost-ui-sortable.esm.min.js.map
|