@fr0st/ui-sortable 2.0.5 → 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/LICENSE +0 -0
- package/README.md +388 -37
- package/dist/frost-ui-sortable.esm.js +370 -0
- package/dist/frost-ui-sortable.esm.js.map +1 -0
- package/dist/frost-ui-sortable.esm.min.js +2 -0
- package/dist/frost-ui-sortable.esm.min.js.map +1 -0
- package/dist/frost-ui-sortable.js +403 -323
- package/dist/frost-ui-sortable.js.map +1 -1
- package/dist/frost-ui-sortable.min.js +2 -1
- package/dist/frost-ui-sortable.min.js.map +1 -1
- package/package.json +56 -24
- package/src/{wrapper.js → browser.js} +0 -0
- package/src/helpers.js +53 -0
- package/src/index.js +0 -28
- package/src/sortable.js +485 -27
- package/src/prototype/events.js +0 -150
- package/src/prototype/helpers.js +0 -80
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -1,37 +1,388 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
# Frost UI Sortable
|
|
2
|
+
|
|
3
|
+
[](https://github.com/frost-js/ui-sortable/actions/workflows/ci.yml)
|
|
4
|
+
[](https://codecov.io/gh/frost-js/ui-sortable)
|
|
5
|
+
[](https://www.npmjs.com/package/@fr0st/ui-sortable)
|
|
6
|
+
[](https://www.npmjs.com/package/@fr0st/ui-sortable)
|
|
7
|
+
[](https://github.com/frost-js/ui-sortable/blob/main/dist/frost-ui-sortable.min.js)
|
|
8
|
+
[](./LICENSE)
|
|
9
|
+
|
|
10
|
+
Drag-and-drop sorting for Frost UI with handles, connected containers, axis control, lifecycle events, and automatic window scrolling.
|
|
11
|
+
|
|
12
|
+
## Highlights
|
|
13
|
+
|
|
14
|
+
- Reorder vertical, horizontal, and free-form collections
|
|
15
|
+
- Restrict dragging to a handle and exclude interactive controls
|
|
16
|
+
- Move items between connected containers, including empty lists
|
|
17
|
+
- Disable individual source or destination instances
|
|
18
|
+
- Automatic window scrolling near viewport edges
|
|
19
|
+
- Configurable, direction-aware item swap threshold
|
|
20
|
+
- Normalized item, container, and index data on lifecycle events
|
|
21
|
+
- Native `Sortable` class and `sortable` fQuery plugin
|
|
22
|
+
- Existing-instance reuse with frozen resolved options
|
|
23
|
+
- Prebuilt ESM and UMD bundles with source maps
|
|
24
|
+
- No component-specific CSS or Sass
|
|
25
|
+
- JSDoc-powered IntelliSense
|
|
26
|
+
|
|
27
|
+
Explore [the demo](./demo/index.html) for interactive examples.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
### Browser projects / bundlers
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm i @fr0st/ui-sortable
|
|
35
|
+
```
|
|
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.
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
import '@fr0st/ui/dist/frost-ui.min.css';
|
|
41
|
+
import Sortable from '@fr0st/ui-sortable';
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`@fr0st/ui` and `@fr0st/query` are peer dependencies so the component shares the application's instances.
|
|
45
|
+
|
|
46
|
+
### Browser (ESM)
|
|
47
|
+
|
|
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:
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<link
|
|
52
|
+
rel="stylesheet"
|
|
53
|
+
href="https://cdn.jsdelivr.net/npm/@fr0st/ui@latest/dist/frost-ui.min.css">
|
|
54
|
+
<script type="importmap">
|
|
55
|
+
{
|
|
56
|
+
"imports": {
|
|
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"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
</script>
|
|
63
|
+
<script type="module">
|
|
64
|
+
import Sortable from 'https://cdn.jsdelivr.net/npm/@fr0st/ui-sortable@latest/dist/frost-ui-sortable.esm.min.js';
|
|
65
|
+
</script>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Browser (UMD)
|
|
69
|
+
|
|
70
|
+
Load the bundles from your own copy or a CDN:
|
|
71
|
+
|
|
72
|
+
```html
|
|
73
|
+
<link
|
|
74
|
+
rel="stylesheet"
|
|
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>
|
|
84
|
+
<script>
|
|
85
|
+
const { Sortable } = globalThis.UI;
|
|
86
|
+
</script>
|
|
87
|
+
```
|
|
88
|
+
|
|
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.
|
|
90
|
+
|
|
91
|
+
The package root resolves to the prebuilt ESM bundle. Published files under `dist/` and `src/` are also available through matching package subpaths.
|
|
92
|
+
|
|
93
|
+
## Usage
|
|
94
|
+
|
|
95
|
+
Sortable targets direct `<li>` children by default:
|
|
96
|
+
|
|
97
|
+
```html
|
|
98
|
+
<ul class="list-group" id="tasks">
|
|
99
|
+
<li class="list-group-item">Research</li>
|
|
100
|
+
<li class="list-group-item">Design</li>
|
|
101
|
+
<li class="list-group-item">Build</li>
|
|
102
|
+
</ul>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
import $ from '@fr0st/query';
|
|
107
|
+
import Sortable from '@fr0st/ui-sortable';
|
|
108
|
+
|
|
109
|
+
const sortable = Sortable.init(
|
|
110
|
+
$.findOne('#tasks'),
|
|
111
|
+
{ cursor: 'grab' },
|
|
112
|
+
);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Calling `Sortable.init()` again for the same container returns its existing instance. Dispose the current instance before reinitializing the container with different options.
|
|
116
|
+
|
|
117
|
+
### Handles and cancel controls
|
|
118
|
+
|
|
119
|
+
Use `handle` when only part of an item should begin a drag. Inputs, text areas, buttons, selects, and options are excluded by the default `cancel` selector, including nested content inside those controls.
|
|
120
|
+
|
|
121
|
+
Cancel checks include ancestors of the handle up to, but not including, the sortable container. A handle inside a button is therefore excluded too. Use `cancel: null` to disable these exclusions, or supply a custom selector.
|
|
122
|
+
|
|
123
|
+
```html
|
|
124
|
+
<ul class="list-group" id="tasks">
|
|
125
|
+
<li class="list-group-item d-flex align-items-center gap-3">
|
|
126
|
+
<span class="drag-handle badge bg-secondary">Drag</span>
|
|
127
|
+
<span class="flex-grow-1">Review pull request</span>
|
|
128
|
+
<button class="btn btn-sm btn-outline-danger" type="button">Delete</button>
|
|
129
|
+
</li>
|
|
130
|
+
</ul>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
Sortable.init($.findOne('#tasks'), {
|
|
135
|
+
cursor: 'grab',
|
|
136
|
+
handle: '.drag-handle',
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Both `items` and `handle` accept comma-separated selectors. For example, `items: ':scope > .task, :scope > .note'` with `handle: '.drag-handle, .grip'` allows either handle inside either item type.
|
|
141
|
+
|
|
142
|
+
### Connected containers
|
|
143
|
+
|
|
144
|
+
Initialize each container with a shared `connectWith` selector. Give empty containers a visible size so pointer proximity can select them.
|
|
145
|
+
|
|
146
|
+
```html
|
|
147
|
+
<div class="row">
|
|
148
|
+
<div class="col">
|
|
149
|
+
<ul class="connected list-group" id="available">
|
|
150
|
+
<li class="list-group-item">Alpha</li>
|
|
151
|
+
<li class="list-group-item">Bravo</li>
|
|
152
|
+
</ul>
|
|
153
|
+
</div>
|
|
154
|
+
<div class="col">
|
|
155
|
+
<ul class="connected list-group" id="selected" style="min-height: 3rem"></ul>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
```js
|
|
161
|
+
$.find('.connected').forEach((node) => {
|
|
162
|
+
Sortable.init(node, {
|
|
163
|
+
connectWith: '.connected',
|
|
164
|
+
cursor: 'grab',
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The receiving instance controls `dropOnEmpty` and `disabled`. Moving between containers triggers `send` on the previous container and `receive` on the new container.
|
|
170
|
+
|
|
171
|
+
Containers can use different `cursor` and `handle` settings. On transfer, Sortable restores the previous container's cursor targets before `send`, then applies the receiving container's cursor to its items or handles during `receive`.
|
|
172
|
+
|
|
173
|
+
## Options
|
|
174
|
+
|
|
175
|
+
Options are resolved in this order:
|
|
176
|
+
|
|
177
|
+
1. Component defaults
|
|
178
|
+
2. The element's `data-ui-*` attributes
|
|
179
|
+
3. Options passed to `Sortable.init()`
|
|
180
|
+
|
|
181
|
+
Resolved `instance.options` are shallow-frozen.
|
|
182
|
+
|
|
183
|
+
| Option | Type | Default | Description |
|
|
184
|
+
| --- | --- | --- | --- |
|
|
185
|
+
| `axis` | `'x' \| 'y' \| null` | `null` | Constrain item placement decisions to one axis. |
|
|
186
|
+
| `cancel` | `string \| null` | `'input, textarea, button, select, option'` | Prevent matching controls or their nested content from starting a sort. |
|
|
187
|
+
| `connectWith` | `string \| null` | `null` | Select other Sortable containers that can exchange items. |
|
|
188
|
+
| `cursor` | `string` | `'auto'` | Set the cursor on sortable items or configured handles. |
|
|
189
|
+
| `disabled` | `boolean` | `false` | Disable sorting and connected-list receiving initially. |
|
|
190
|
+
| `dropOnEmpty` | `boolean` | `true` | Allow this container to receive items while empty. |
|
|
191
|
+
| `handle` | `string \| null` | `null` | Select the drag handle inside each sortable item. |
|
|
192
|
+
| `helperClass` | `string \| null` | `'bg-body-tertiary'` | Add one or more classes to the active item during a drag. |
|
|
193
|
+
| `items` | `string` | `':scope > li'` | Select sortable items relative to the container. |
|
|
194
|
+
| `scroll` | `boolean` | `true` | Scroll the window while dragging near a viewport edge. |
|
|
195
|
+
| `scrollSensitivity` | `number` | `20` | Start auto-scrolling within this distance of an edge, in pixels. |
|
|
196
|
+
| `scrollSpeed` | `number` | `5` | Scroll this many pixels per animation frame. |
|
|
197
|
+
| `swapThreshold` | `number` | `0.25` | Swap after crossing this fraction of the next item, from `0` to `1`. The threshold is mirrored when reversing direction. |
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
const sortable = Sortable.init(node, {
|
|
201
|
+
axis: 'y',
|
|
202
|
+
cancel: 'input, textarea, button, select, option, [data-no-sort]',
|
|
203
|
+
connectWith: '.task-list',
|
|
204
|
+
cursor: 'grab',
|
|
205
|
+
disabled: false,
|
|
206
|
+
dropOnEmpty: true,
|
|
207
|
+
handle: '.drag-handle',
|
|
208
|
+
helperClass: 'bg-primary-subtle shadow-sm',
|
|
209
|
+
items: ':scope > .task',
|
|
210
|
+
scroll: true,
|
|
211
|
+
scrollSensitivity: 32,
|
|
212
|
+
scrollSpeed: 8,
|
|
213
|
+
swapThreshold: 0.25,
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Auto-scrolling updates item placement and sorting events even while the pointer remains stationary near an edge. Scroll steps are instant regardless of the page's CSS `scroll-behavior`; Sortable does not modify that style.
|
|
218
|
+
|
|
219
|
+
## Data attributes
|
|
220
|
+
|
|
221
|
+
Use kebab-case `data-ui-*` attributes for serializable options. fQuery normalizes boolean, numeric, array, object, and `null` values.
|
|
222
|
+
|
|
223
|
+
```html
|
|
224
|
+
<ul
|
|
225
|
+
id="tasks"
|
|
226
|
+
data-ui-toggle="sortable"
|
|
227
|
+
data-ui-axis="y"
|
|
228
|
+
data-ui-connect-with=".task-list"
|
|
229
|
+
data-ui-cursor="grab"
|
|
230
|
+
data-ui-drop-on-empty="true"
|
|
231
|
+
data-ui-handle=".drag-handle"
|
|
232
|
+
data-ui-helper-class="bg-primary-subtle shadow-sm"
|
|
233
|
+
data-ui-items=":scope > .task"
|
|
234
|
+
data-ui-scroll="true"
|
|
235
|
+
data-ui-scroll-sensitivity="32"
|
|
236
|
+
data-ui-scroll-speed="8"
|
|
237
|
+
data-ui-swap-threshold="0.25">
|
|
238
|
+
</ul>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
```js
|
|
242
|
+
import $ from '@fr0st/query';
|
|
243
|
+
import '@fr0st/ui-sortable';
|
|
244
|
+
|
|
245
|
+
$('[data-ui-toggle="sortable"]').sortable();
|
|
246
|
+
```
|
|
247
|
+
|
|
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.
|
|
249
|
+
|
|
250
|
+
## Methods
|
|
251
|
+
|
|
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. |
|
|
259
|
+
|
|
260
|
+
```js
|
|
261
|
+
const items = sortable.items();
|
|
262
|
+
sortable.disable();
|
|
263
|
+
sortable.enable();
|
|
264
|
+
sortable.dispose();
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Disposal restores original inline cursor declarations, including `!important` priority, and releases cursor style locks.
|
|
268
|
+
|
|
269
|
+
## Lifecycle
|
|
270
|
+
|
|
271
|
+
Calling `Sortable.init()` again for the same element returns its existing instance. Dispose the current instance before reinitializing with different options.
|
|
272
|
+
|
|
273
|
+
An instance exposes its original element as `instance.node` and its shallow-frozen resolved configuration as `instance.options`. Both become `null` after disposal.
|
|
274
|
+
|
|
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.
|
|
276
|
+
|
|
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.
|
|
278
|
+
|
|
279
|
+
## Events
|
|
280
|
+
|
|
281
|
+
Listen with fQuery's namespaced event API:
|
|
282
|
+
|
|
283
|
+
```js
|
|
284
|
+
import $ from '@fr0st/query';
|
|
285
|
+
|
|
286
|
+
$.addEvent(
|
|
287
|
+
'#tasks',
|
|
288
|
+
'sort.ui.sortable sorting.ui.sortable sorted.ui.sortable update.ui.sortable',
|
|
289
|
+
(event) => {
|
|
290
|
+
console.log({
|
|
291
|
+
item: event.item,
|
|
292
|
+
from: event.from,
|
|
293
|
+
to: event.to,
|
|
294
|
+
oldIndex: event.oldIndex,
|
|
295
|
+
newIndex: event.newIndex,
|
|
296
|
+
});
|
|
297
|
+
},
|
|
298
|
+
);
|
|
299
|
+
```
|
|
300
|
+
|
|
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. |
|
|
309
|
+
|
|
310
|
+
Every event exposes the same normalized fields directly and through `event.detail`:
|
|
311
|
+
|
|
312
|
+
| Field | Type | Description |
|
|
313
|
+
| --- | --- | --- |
|
|
314
|
+
| `item` | `HTMLElement` | Item being sorted. |
|
|
315
|
+
| `from` | `HTMLElement` | Source for `sort`, current container for `sorting`, previous container for `send`/`receive`, and original source for `sorted`/`update`. |
|
|
316
|
+
| `to` | `HTMLElement` | Source for `sort`, current container for `sorting`, new container for `send`/`receive`, and final destination for `sorted`/`update`. |
|
|
317
|
+
| `oldIndex` | `number` | Previous index for movement events, otherwise the original index. |
|
|
318
|
+
| `newIndex` | `number` | New index for movement events, otherwise the final index. |
|
|
319
|
+
| `detail.target` | `HTMLElement` | Alias of the active `item` retained for Frost UI event compatibility. |
|
|
320
|
+
|
|
321
|
+
Indices are calculated among elements matching the container's configured `items` selector; unrelated child elements are not counted.
|
|
322
|
+
|
|
323
|
+
## fQuery API
|
|
324
|
+
|
|
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
|
|
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.
|
|
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
|
+
|
|
349
|
+
For touch interfaces, applying `touch-action: none` to sortable items or handles prevents browser gestures from competing with dragging:
|
|
350
|
+
|
|
351
|
+
```css
|
|
352
|
+
.drag-handle {
|
|
353
|
+
touch-action: none;
|
|
354
|
+
user-select: none;
|
|
355
|
+
}
|
|
356
|
+
```
|
|
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
|
+
|
|
364
|
+
## Browser support
|
|
365
|
+
|
|
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.
|
|
367
|
+
|
|
368
|
+
## Development
|
|
369
|
+
|
|
370
|
+
Install dependencies with `npm ci`, then install Playwright browsers with `npx playwright install --with-deps`.
|
|
371
|
+
|
|
372
|
+
```bash
|
|
373
|
+
npm test
|
|
374
|
+
npm run lint
|
|
375
|
+
npm run build
|
|
376
|
+
```
|
|
377
|
+
|
|
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.
|
|
379
|
+
|
|
380
|
+
After building, `npm run test:coverage` runs Chromium tests and writes coverage reports to `coverage/`.
|
|
381
|
+
|
|
382
|
+
`npm run test:headed` and `npm run test:ui` also use the existing bundles and open headed browsers or the Playwright UI.
|
|
383
|
+
|
|
384
|
+
To view the demo, open `demo/index.html` in your browser after building.
|
|
385
|
+
|
|
386
|
+
## License
|
|
387
|
+
|
|
388
|
+
Frost UI Sortable is released under the [MIT License](./LICENSE).
|