@fr0st/ui-sortable 3.0.1 → 3.0.3

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.
@@ -1,7 +1,7 @@
1
1
  import { BaseComponent, getPosition, initComponent } from "@fr0st/ui";
2
2
  import $ from "@fr0st/query";
3
3
 
4
- //#region src/helpers.js
4
+ // src/helpers.js
5
5
  /** @import { SortableEventData } from './sortable.js'; */
6
6
  var cursorLocks = /* @__PURE__ */ new WeakMap();
7
7
  /**
@@ -41,8 +41,7 @@ function triggerSortableEvent(node, name, data) {
41
41
  });
42
42
  }
43
43
 
44
- //#endregion
45
- //#region src/sortable.js
44
+ // src/sortable.js
46
45
  var document = $.getContext();
47
46
  var window = $.getWindow();
48
47
  /** @typedef {'x'|'y'} SortableAxis */
@@ -92,15 +91,15 @@ var Sortable = class extends BaseComponent {
92
91
  swapThreshold: .25
93
92
  };
94
93
  #currentIndex;
95
- #currentSortable;
94
+ #currentSortable = null;
96
95
  #dragging;
97
96
  #enabled;
98
97
  #initialCursorNodes = [];
99
- #pos;
100
- #scrollFrame;
98
+ #pos = null;
99
+ #scrollFrame = null;
101
100
  #selector;
102
101
  #startIndex;
103
- #target;
102
+ #target = null;
104
103
  /**
105
104
  * Creates a Sortable.
106
105
  * @param {HTMLElement} node The sortable container.
@@ -130,8 +129,6 @@ var Sortable = class extends BaseComponent {
130
129
  /** @inheritdoc */
131
130
  dispose() {
132
131
  if (!this.node) return;
133
- $.removeEventDelegate(this.node, "mousedown.ui.sortable touchstart.ui.sortable");
134
- $.removeEvent(this.node, "receive.ui.sortable");
135
132
  resetCursor(this.#initialCursorNodes ?? $.find(this.#selector, this.node));
136
133
  if (this.#target && this.options.helperClass) $.removeClass(this.#target, this.options.helperClass);
137
134
  this.#resetDrag();
@@ -192,13 +189,13 @@ var Sortable = class extends BaseComponent {
192
189
  * Attaches events for the Sortable.
193
190
  */
194
191
  #events() {
195
- const downEvent = (event) => {
192
+ const downHandler = (event) => {
196
193
  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
194
  if (event.button || !this.#enabled || cancelled || $.getDataset(this.node, "uiDragging")) return false;
198
195
  this.#target = this.options.handle ? this.items().find((node) => $.hasDescendent(node, event.currentTarget)) : event.currentTarget;
199
196
  if (!this.#target) return false;
200
197
  };
201
- const moveEvent = (event) => {
198
+ const moveHandler = (event) => {
202
199
  if (!this.node || !this.#target) return;
203
200
  const previousPos = this.#pos;
204
201
  this.#pos = getPosition(event);
@@ -225,7 +222,7 @@ var Sortable = class extends BaseComponent {
225
222
  this.#updatePlacement(deltaX, deltaY);
226
223
  this.#scheduleScroll();
227
224
  };
228
- const upEvent = (event) => {
225
+ const upHandler = (event) => {
229
226
  if (!this.node) return;
230
227
  if (!this.#dragging) {
231
228
  this.#target = null;
@@ -251,9 +248,9 @@ var Sortable = class extends BaseComponent {
251
248
  } else if (this.#currentIndex !== this.#startIndex) triggerSortableEvent(destination, "update", eventData);
252
249
  if (this.node) this.#resetDrag();
253
250
  };
254
- const dragEvent = $.mouseDragFactory(downEvent, moveEvent, upEvent);
255
- $.addEventDelegate(this.node, "mousedown.ui.sortable touchstart.ui.sortable", this.#selector, dragEvent);
256
- $.addEvent(this.node, "receive.ui.sortable", () => {
251
+ const dragHandler = $.mouseDragFactory(downHandler, moveHandler, upHandler);
252
+ this.listen(this.node, "mousedown.ui.sortable touchstart.ui.sortable", dragHandler, { delegate: this.#selector });
253
+ this.listen(this.node, "receive.ui.sortable", () => {
257
254
  setCursor($.find(this.#selector, this.node), this.options.cursor);
258
255
  });
259
256
  }
@@ -261,7 +258,7 @@ var Sortable = class extends BaseComponent {
261
258
  * Resets the active drag state.
262
259
  */
263
260
  #resetDrag() {
264
- if (this.#scrollFrame !== null && this.#scrollFrame !== void 0) window.cancelAnimationFrame(this.#scrollFrame);
261
+ if (this.#scrollFrame !== null) window.cancelAnimationFrame(this.#scrollFrame);
265
262
  if (this.#dragging && this.node) $.removeDataset(this.node, "uiDragging");
266
263
  this.#currentIndex = null;
267
264
  this.#currentSortable = null;
@@ -275,7 +272,7 @@ var Sortable = class extends BaseComponent {
275
272
  * Schedules the next auto-scroll update.
276
273
  */
277
274
  #scheduleScroll() {
278
- if (!this.node || !this.options.scroll || !this.#dragging || this.#scrollFrame !== null && this.#scrollFrame !== void 0) return;
275
+ if (!this.node || !this.options.scroll || !this.#dragging || this.#scrollFrame !== null) return;
279
276
  this.#scrollFrame = window.requestAnimationFrame(() => {
280
277
  this.#checkScroll();
281
278
  });
@@ -360,11 +357,9 @@ var Sortable = class extends BaseComponent {
360
357
  }
361
358
  };
362
359
 
363
- //#endregion
364
- //#region src/index.js
360
+ // src/index.js
365
361
  initComponent("sortable", Sortable);
366
362
  var src_default = Sortable;
367
363
 
368
- //#endregion
369
364
  export { src_default as default };
370
365
  //# sourceMappingURL=frost-ui-sortable.esm.js.map
@@ -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 #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
+ {"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 = null;\n #dragging;\n #enabled;\n #initialCursorNodes = [];\n #pos = null;\n #scrollFrame = null;\n #selector;\n #startIndex;\n #target = null;\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 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 downHandler = (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 moveHandler = (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 upHandler = (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 dragHandler = $.mouseDragFactory(downHandler, moveHandler, upHandler);\n\n this.listen(\n this.node,\n 'mousedown.ui.sortable touchstart.ui.sortable',\n dragHandler,\n { delegate: this.#selector },\n );\n\n this.listen(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) {\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\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":";;;;;AAIA,IAAM,8BAAc,IAAI,QAAQ;;;;;AAMhC,SAAgB,YAAY,OAAO;CAC/B,KAAK,MAAM,QAAQ,OAAO;EACtB,MAAM,UAAU,YAAY,IAAI,IAAI;EAEpC,IAAI,CAAC,SACD;EAGJ,QAAQ;EACR,YAAY,OAAO,IAAI;CAC3B;AACJ;;;;;;AAOA,SAAgB,UAAU,OAAO,QAAQ;CACrC,KAAK,MAAM,QAAQ,OACf,IAAI,YAAY,IAAI,IAAI,GACpB,EAAE,SAAS,MAAM,EAAE,OAAO,CAAC;MAE3B,YAAY,IAAI,MAAM,EAAE,aAAa,MAAM,UAAU,MAAM,CAAC;AAGxE;;;;;;;AAQA,SAAgB,qBAAqB,MAAM,MAAM,MAAM;CACnD,EAAE,aAAa,MAAM,GAAG,KAAK,eAAe;EACxC;EACA,QAAQ;GACJ,QAAQ,KAAK;GACb,GAAG;EACP;CACJ,CAAC;AACL;;;AChDA,IAAM,WAAW,EAAE,WAAW;AAC9B,IAAM,SAAS,EAAE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkC3B,IAAqB,WAArB,cAAsC,cAAc;;CAEhD,OAAO,WAAW;EACd,MAAM;EACN,QAAQ;EACR,aAAa;EACb,QAAQ;EACR,UAAU;EACV,aAAa;EACb,QAAQ;EACR,aAAa;EACb,OAAO;EACP,QAAQ;EACR,mBAAmB;EACnB,aAAa;EACb,eAAe;CACnB;CAEA;CACA,mBAAmB;CACnB;CACA;CACA,sBAAsB,CAAC;CACvB,OAAO;CACP,eAAe;CACf;CACA;CACA,UAAU;;;;;;CAOV,YAAY,MAAM,SAAS;EACvB,MAAM,MAAM,OAAO;EAEnB,IAAI;GACA,KAAK,YAAY,KAAK,QAAQ,SAC1B,OAAO,KAAK,QAAQ,MAAM,QAAQ,KAAK,QAAQ,OAAO,KACtD,KAAK,QAAQ;GAEjB,KAAK,YAAY;GACjB,KAAK,WAAW,CAAC,KAAK,QAAQ;GAE9B,KAAK,sBAAsB,EAAE,KAAK,KAAK,WAAW,KAAK,IAAI;GAC3D,UAAU,KAAK,qBAAqB,KAAK,QAAQ,MAAM;GACvD,KAAK,QAAQ;GACb,KAAK,sBAAsB;EAC/B,SAAS,OAAO;GACZ,KAAK,QAAQ;GACb,MAAM;EACV;CACJ;;;;CAKA,UAAU;EACN,KAAK,WAAW;CACpB;;CAGA,UAAU;EACN,IAAI,CAAC,KAAK,MACN;EAGJ,YAAY,KAAK,uBAAuB,EAAE,KAAK,KAAK,WAAW,KAAK,IAAI,CAAC;EAEzE,IAAI,KAAK,WAAW,KAAK,QAAQ,aAC7B,EAAE,YAAY,KAAK,SAAS,KAAK,QAAQ,WAAW;EAGxD,KAAK,WAAW;EAEhB,KAAK,sBAAsB;EAE3B,MAAM,QAAQ;CAClB;;;;CAKA,SAAS;EACL,KAAK,WAAW;CACpB;;;;;CAMA,QAAQ;EACJ,OAAO,EAAE,KAAK,KAAK,QAAQ,OAAO,KAAK,IAAI;CAC/C;;;;CAKA,eAAe;EACX,KAAK,eAAe;EAEpB,IAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,aAAa,CAAC,KAAK,WAAW,CAAC,KAAK,MACxD;EAGJ,MAAM,YAAY,EAAE,WAAW,MAAM;EACrC,MAAM,YAAY,EAAE,WAAW,MAAM;EACrC,MAAM,eAAe,EAAE,OAAO,MAAM;EACpC,MAAM,cAAc,EAAE,MAAM,MAAM;EAElC,IAAI,UAAU;EACd,IAAI,UAAU;EAEd,IAAI,KAAK,KAAK,IAAI,YAAY,KAAK,QAAQ,mBACvC,UAAU,KAAK,IAAI,GAAG,YAAY,KAAK,QAAQ,WAAW;OACvD,IAAI,KAAK,KAAK,IAAI,YAAY,eAAe,KAAK,QAAQ,mBAAmB;GAChF,MAAM,YAAY,EAAE,OAAO,UAAU,EAAE,SAAS,EAAE,WAAW,CAAC;GAC9D,MAAM,OAAO,KAAK,IAAI,GAAG,YAAY,YAAY;GACjD,UAAU,KAAK,IAAI,MAAM,YAAY,KAAK,QAAQ,WAAW;EACjE;EAEA,IAAI,KAAK,KAAK,IAAI,YAAY,KAAK,QAAQ,mBACvC,UAAU,KAAK,IAAI,GAAG,YAAY,KAAK,QAAQ,WAAW;OACvD,IAAI,KAAK,KAAK,IAAI,YAAY,cAAc,KAAK,QAAQ,mBAAmB;GAC/E,MAAM,WAAW,EAAE,MAAM,UAAU,EAAE,SAAS,EAAE,WAAW,CAAC;GAC5D,MAAM,OAAO,KAAK,IAAI,GAAG,WAAW,WAAW;GAC/C,UAAU,KAAK,IAAI,MAAM,YAAY,KAAK,QAAQ,WAAW;EACjE;EAEA,IAAI,YAAY,aAAa,YAAY,WACrC;EAGJ,OAAO,SAAS;GACZ,MAAM;GACN,KAAK;GACL,UAAU;EACd,CAAC;EAED,MAAM,SAAS,UAAU;EACzB,MAAM,SAAS,UAAU;EAEzB,KAAK,KAAK,KAAK;EACf,KAAK,KAAK,KAAK;EAEf,KAAK,iBAAiB,QAAQ,MAAM;EACpC,KAAK,gBAAgB;CACzB;;;;CAKA,UAAU;EACN,MAAM,eAAe,UAAU;GAC3B,MAAM,YAAY,KAAK,QAAQ,WAEvB,EAAE,GAAG,MAAM,QAAQ,KAAK,QAAQ,MAAM,KACtC,EAAE,GAAG,MAAM,eAAe,KAAK,QAAQ,MAAM,KAC7C,EAAE,QAAQ,MAAM,QAAQ,KAAK,QAAQ,QAAQ,KAAK,IAAI,CAAC,CAAC;GAGhE,IACI,MAAM,UACN,CAAC,KAAK,YACN,aACA,EAAE,WAAW,KAAK,MAAM,YAAY,GAEpC,OAAO;GAGX,KAAK,UAAU,KAAK,QAAQ,SACxB,KAAK,MAAM,CAAC,CAAC,MAAM,SAAS,EAAE,cAAc,MAAM,MAAM,aAAa,CAAC,IACtE,MAAM;GAEV,IAAI,CAAC,KAAK,SACN,OAAO;EAEf;EAEA,MAAM,eAAe,UAAU;GAC3B,IAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,SACpB;GAGJ,MAAM,cAAc,KAAK;GACzB,KAAK,OAAO,YAAY,KAAK;GAC7B,MAAM,SAAS,cACX,KAAK,KAAK,IAAI,YAAY,IAC1B;GACJ,MAAM,SAAS,cACX,KAAK,KAAK,IAAI,YAAY,IAC1B;GAEJ,IAAI,CAAC,KAAK,WAAW;IACjB,KAAK,YAAY;IACjB,KAAK,mBAAmB,KAAK;IAC7B,KAAK,cAAc,KAAK,MAAM,CAAC,CAAC,QAAQ,KAAK,OAAO;IACpD,KAAK,gBAAgB,KAAK;IAE1B,EAAE,WAAW,KAAK,MAAM,EAAE,YAAY,KAAK,CAAC;;IAG5C,MAAM,YAAY;KACd,MAAM,KAAK;KACX,MAAM,KAAK;KACX,IAAI,KAAK;KACT,UAAU,KAAK;KACf,UAAU,KAAK;IACnB;IAEA,qBAAqB,KAAK,MAAM,QAAQ,SAAS;IAEjD,IAAI,CAAC,KAAK,MACN;IAGJ,IAAI,KAAK,QAAQ,aACb,EAAE,SAAS,KAAK,SAAS,KAAK,QAAQ,WAAW;GAEzD;GAEA,KAAK,iBAAiB,QAAQ,MAAM;GACpC,KAAK,gBAAgB;EACzB;EAEA,MAAM,aAAa,UAAU;GACzB,IAAI,CAAC,KAAK,MACN;GAGJ,IAAI,CAAC,KAAK,WAAW;IACjB,KAAK,UAAU;IACf;GACJ;GAEA,IAAI,MAAM,SAAS,WACf,MAAM,eAAe;GAGzB,MAAM,SAAS,KAAK;GACpB,MAAM,cAAc,KAAK;;GAEzB,MAAM,YAAY;IACd,MAAM,KAAK;IACX,MAAM;IACN,IAAI;IACJ,UAAU,KAAK;IACf,UAAU,KAAK;GACnB;GAEA,qBAAqB,aAAa,UAAU,SAAS;GAErD,IAAI,CAAC,KAAK,MACN;GAGJ,IAAI,KAAK,QAAQ,aACb,EAAE,YAAY,KAAK,SAAS,KAAK,QAAQ,WAAW;GAGxD,IAAI,WAAW,aAAa;IACxB,qBAAqB,QAAQ,UAAU,SAAS;IAEhD,IAAI,KAAK,MACL,qBAAqB,aAAa,UAAU,SAAS;GAE7D,OAAO,IAAI,KAAK,kBAAkB,KAAK,aACnC,qBAAqB,aAAa,UAAU,SAAS;GAGzD,IAAI,KAAK,MACL,KAAK,WAAW;EAExB;EAEA,MAAM,cAAc,EAAE,iBAAiB,aAAa,aAAa,SAAS;EAE1E,KAAK,OACD,KAAK,MACL,gDACA,aACA,EAAE,UAAU,KAAK,UAAU,CAC/B;EAEA,KAAK,OAAO,KAAK,MAAM,6BAA6B;GAChD,UAAU,EAAE,KAAK,KAAK,WAAW,KAAK,IAAI,GAAG,KAAK,QAAQ,MAAM;EACpE,CAAC;CACL;;;;CAKA,aAAa;EACT,IAAI,KAAK,iBAAiB,MACtB,OAAO,qBAAqB,KAAK,YAAY;EAGjD,IAAI,KAAK,aAAa,KAAK,MACvB,EAAE,cAAc,KAAK,MAAM,YAAY;EAG3C,KAAK,gBAAgB;EACrB,KAAK,mBAAmB;EACxB,KAAK,YAAY;EACjB,KAAK,OAAO;EACZ,KAAK,eAAe;EACpB,KAAK,cAAc;EACnB,KAAK,UAAU;CACnB;;;;CAKA,kBAAkB;EACd,IACI,CAAC,KAAK,QACN,CAAC,KAAK,QAAQ,UACd,CAAC,KAAK,aACN,KAAK,iBAAiB,MAEtB;EAGJ,KAAK,eAAe,OAAO,4BAA4B;GACnD,KAAK,aAAa;EACtB,CAAC;CACL;;;;;;CAOA,iBAAiB,QAAQ,QAAQ;EAC7B,IAAI,kBAAkB,KAAK;EAE3B,IAAI,KAAK,QAAQ,aAAa;GAC1B,MAAM,YAAY,EAAE,KAAK,KAAK,QAAQ,WAAW,CAAC,CAC7C,QAAQ,SAAS,SAAS,KAAK,IAAI,CAAC,CACpC,QAAQ,SAAS;IACd,MAAM,WAAW,KAAK,YAAY,KAAK,IAAI;IAE3C,OAAO,SAAS,aACX,SAAS,QAAQ,eAAe,SAAS,MAAM,CAAC,CAAC;GAC1D,CAAC;GAEL,IAAI,UAAU,QACV,kBAAkB,EAAE,UAChB,CAAC,KAAK,MAAM,GAAG,SAAS,GACxB,KAAK,KAAK,GACV,KAAK,KAAK,GACV,EAAE,QAAQ,KAAK,CACnB;EAER;EAEA,MAAM,kBAAkB,KAAK,YAAY,KAAK,eAAe;EAC7D,MAAM,eAAe,gBAAgB,MAAM,CAAC,CACvC,QAAQ,SAAS,SAAS,KAAK,OAAO;EAC3C,MAAM,cAAc,EAAE,UAClB,cACA,KAAK,KAAK,GACV,KAAK,KAAK,GACV,EAAE,QAAQ,KAAK,CACnB;EAEA,IAAI,aACA,KAAK,cACD,aACA,KAAK,KAAK,GACV,KAAK,KAAK,GACV,QACA,MACJ;OACG,IAAI,oBAAoB,KAAK,kBAChC,EAAE,OAAO,iBAAiB,KAAK,OAAO;OAEtC;EAGJ,MAAM,WAAW,gBAAgB,MAAM,CAAC,CAAC,QAAQ,KAAK,OAAO;EAE7D,IAAI,oBAAoB,KAAK,kBAAkB;GAC3C,MAAM,mBAAmB,KAAK;GAE9B,MAAM,EAAE,WADiB,KAAK,YAAY,KAAK,gBACb,CAAC,CAAC;GAEpC,YAAY,SACR,EAAE,KAAK,QAAQ,KAAK,OAAO,IAC3B,CAAC,KAAK,OAAO,CAAC;;GAGlB,MAAM,YAAY;IACd,MAAM,KAAK;IACX,MAAM;IACN,IAAI;IACJ,UAAU,KAAK;IACf;GACJ;GAEA,qBAAqB,kBAAkB,QAAQ,SAAS;GAExD,IAAI,CAAC,KAAK,MACN;GAGJ,qBAAqB,iBAAiB,WAAW,SAAS;EAC9D,OAAO,IAAI,KAAK,kBAAkB,UAAU;;GAExC,MAAM,YAAY;IACd,MAAM,KAAK;IACX,MAAM;IACN,IAAI;IACJ,UAAU,KAAK;IACf;GACJ;GAEA,qBAAqB,iBAAiB,WAAW,SAAS;EAC9D;EAEA,IAAI,CAAC,KAAK,MACN;EAGJ,KAAK,gBAAgB;EACrB,KAAK,mBAAmB;CAC5B;;;;;;;;;CAUA,cAAc,aAAa,GAAG,GAAG,QAAQ,QAAQ;EAC7C,MAAM,gBAAgB,EAAE,OAAO,aAAa,EAAE,QAAQ,KAAK,CAAC;EAC5D,MAAM,cAAc,EAAE,KAAK,aAAa,EAAE,QAAQ,KAAK,CAAC;EACxD,MAAM,eAAe,EAAE,OAAO,KAAK,SAAS,EAAE,QAAQ,KAAK,CAAC;EAC5D,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,QAAQ,aAAa,CAAC;EACrE,IAAI,aAAa;EACjB,IAAI,aAAa;EAEjB,IAAI,QACA,aAAa,SAAS,IAClB,YACA,IAAI;EAGZ,IAAI,QACA,aAAa,SAAS,IAClB,YACA,IAAI;EAGZ,IAAI;EACJ,IAAI,KAAK,QAAQ,SAAS,OAAO,cAAc,MAAM,aAAa,GAE9D,SAAS,IADK,YAAY,MAAM,YAAY,SAAS,aAEjD,WACA;OACD,IAAI,KAAK,QAAQ,SAAS,OAAO,cAAc,MAAM,aAAa,GAErE,SAAS,IADK,YAAY,OAAO,YAAY,QAAQ,aAEjD,WACA;OACD;GACH,MAAM,QAAQ,YAAY,OAAO,YAAY,QAAQ;GACrD,MAAM,QAAQ,YAAY,MAAM,YAAY,SAAS;GACrD,SAAS,IAAI,SAAS,IAAI,QACtB,WACA;EACR;EAEA,EAAE,OAAO,CAAC,aAAa,KAAK,OAAO;CACvC;AACJ;;;AClgBA,cAAc,YAAY,QAAQ;AAElC,kBAAe"}
@@ -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=/* @__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};
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=null;#n;#r;#i=[];#a=null;#o=null;#s;#c;#l=null;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&&(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())});this.listen(this.node,`mousedown.ui.sortable touchstart.ui.sortable`,e,{delegate:this.#s}),this.listen(this.node,`receive.ui.sortable`,()=>{o(r.find(this.#s,this.node),this.options.cursor)})}#f(){this.#o!==null&&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=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
@@ -1 +1 @@
1
- {"version":3,"file":"frost-ui-sortable.esm.min.js","names":["$","cursorLocks","resetCursor","node","nodes","release","setCursor","cursor","triggerSortableEvent","name","data","document","window","Sortable","BaseComponent","options","#selector","#dragging","#enabled","#initialCursorNodes","#events","error","#target","#resetDrag","#scrollFrame","#pos","originalX","originalY","windowHeight","windowWidth","offsetX","offsetY","docHeight","maxY","docWidth","maxX","deltaX","deltaY","#updatePlacement","#scheduleScroll","dragEvent","cancelled","event","previousPos","getPosition","#currentSortable","#startIndex","#currentIndex","eventData","source","destination","#checkScroll","nearestSortable","connected","sortable","nearestInstance","nearestItems","nearestItem","#updateTarget","newIndex","previousSortable","handle","nearestCenter","nearestRect","targetCenter","threshold","thresholdX","thresholdY","method","y","x","swapX","swapY","initComponent","src_default"],"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
+ {"version":3,"file":"frost-ui-sortable.esm.min.js","names":["$","cursorLocks","resetCursor","node","nodes","release","setCursor","cursor","triggerSortableEvent","name","data","document","window","Sortable","BaseComponent","options","#selector","#dragging","#enabled","#initialCursorNodes","#events","error","#target","#resetDrag","#scrollFrame","#pos","originalX","originalY","windowHeight","windowWidth","offsetX","offsetY","docHeight","maxY","docWidth","maxX","deltaX","deltaY","#updatePlacement","#scheduleScroll","dragHandler","cancelled","event","previousPos","getPosition","#currentSortable","#startIndex","#currentIndex","eventData","source","destination","#checkScroll","nearestSortable","connected","sortable","nearestInstance","nearestItems","nearestItem","#updateTarget","newIndex","previousSortable","handle","nearestCenter","nearestRect","targetCenter","threshold","thresholdX","thresholdY","method","y","x","swapX","swapY","initComponent","src_default"],"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 = null;\n #dragging;\n #enabled;\n #initialCursorNodes = [];\n #pos = null;\n #scrollFrame = null;\n #selector;\n #startIndex;\n #target = null;\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 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 downHandler = (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 moveHandler = (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 upHandler = (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 dragHandler = $.mouseDragFactory(downHandler, moveHandler, upHandler);\n\n this.listen(\n this.node,\n 'mousedown.ui.sortable touchstart.ui.sortable',\n dragHandler,\n { delegate: this.#selector },\n );\n\n this.listen(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) {\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\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,10 +1,10 @@
1
1
  (function(global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fr0st/ui'), require('@fr0st/query')) :
3
- typeof define === 'function' && define.amd ? define(['exports', '@fr0st/ui', '@fr0st/query'], factory) :
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require("@fr0st/ui"), require("@fr0st/query")) :
3
+ typeof define === 'function' && define.amd ? define(['exports', "@fr0st/ui", "@fr0st/query"], factory) :
4
4
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.UI = global.UI || {}), global.UI,global.fQuery));
5
5
  })(this, function(exports, _fr0st_ui, _fr0st_query) {
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
7
- //#region \0rolldown/runtime.js
7
+ // \0rolldown/runtime.js
8
8
  var __create = Object.create;
9
9
  var __defProp = Object.defineProperty;
10
10
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -30,10 +30,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
30
30
  enumerable: true
31
31
  }) : target, mod));
32
32
 
33
- //#endregion
34
33
  _fr0st_query = __toESM(_fr0st_query, 1);
35
34
 
36
- //#region src/helpers.js
35
+ // src/helpers.js
37
36
  /** @import { SortableEventData } from './sortable.js'; */
38
37
  var cursorLocks = /* @__PURE__ */ new WeakMap();
39
38
  /**
@@ -73,8 +72,7 @@ _fr0st_query = __toESM(_fr0st_query, 1);
73
72
  });
74
73
  }
75
74
 
76
- //#endregion
77
- //#region src/sortable.js
75
+ // src/sortable.js
78
76
  var document = _fr0st_query.default.getContext();
79
77
  var window = _fr0st_query.default.getWindow();
80
78
  /** @typedef {'x'|'y'} SortableAxis */
@@ -124,15 +122,15 @@ _fr0st_query = __toESM(_fr0st_query, 1);
124
122
  swapThreshold: .25
125
123
  };
126
124
  #currentIndex;
127
- #currentSortable;
125
+ #currentSortable = null;
128
126
  #dragging;
129
127
  #enabled;
130
128
  #initialCursorNodes = [];
131
- #pos;
132
- #scrollFrame;
129
+ #pos = null;
130
+ #scrollFrame = null;
133
131
  #selector;
134
132
  #startIndex;
135
- #target;
133
+ #target = null;
136
134
  /**
137
135
  * Creates a Sortable.
138
136
  * @param {HTMLElement} node The sortable container.
@@ -162,8 +160,6 @@ _fr0st_query = __toESM(_fr0st_query, 1);
162
160
  /** @inheritdoc */
163
161
  dispose() {
164
162
  if (!this.node) return;
165
- _fr0st_query.default.removeEventDelegate(this.node, "mousedown.ui.sortable touchstart.ui.sortable");
166
- _fr0st_query.default.removeEvent(this.node, "receive.ui.sortable");
167
163
  resetCursor(this.#initialCursorNodes ?? _fr0st_query.default.find(this.#selector, this.node));
168
164
  if (this.#target && this.options.helperClass) _fr0st_query.default.removeClass(this.#target, this.options.helperClass);
169
165
  this.#resetDrag();
@@ -224,13 +220,13 @@ _fr0st_query = __toESM(_fr0st_query, 1);
224
220
  * Attaches events for the Sortable.
225
221
  */
226
222
  #events() {
227
- const downEvent = (event) => {
223
+ const downHandler = (event) => {
228
224
  const cancelled = this.options.cancel && (_fr0st_query.default.is(event.target, this.options.cancel) || _fr0st_query.default.is(event.currentTarget, this.options.cancel) || _fr0st_query.default.closest(event.target, this.options.cancel, this.node).length);
229
225
  if (event.button || !this.#enabled || cancelled || _fr0st_query.default.getDataset(this.node, "uiDragging")) return false;
230
226
  this.#target = this.options.handle ? this.items().find((node) => _fr0st_query.default.hasDescendent(node, event.currentTarget)) : event.currentTarget;
231
227
  if (!this.#target) return false;
232
228
  };
233
- const moveEvent = (event) => {
229
+ const moveHandler = (event) => {
234
230
  if (!this.node || !this.#target) return;
235
231
  const previousPos = this.#pos;
236
232
  this.#pos = (0, _fr0st_ui.getPosition)(event);
@@ -257,7 +253,7 @@ _fr0st_query = __toESM(_fr0st_query, 1);
257
253
  this.#updatePlacement(deltaX, deltaY);
258
254
  this.#scheduleScroll();
259
255
  };
260
- const upEvent = (event) => {
256
+ const upHandler = (event) => {
261
257
  if (!this.node) return;
262
258
  if (!this.#dragging) {
263
259
  this.#target = null;
@@ -283,9 +279,9 @@ _fr0st_query = __toESM(_fr0st_query, 1);
283
279
  } else if (this.#currentIndex !== this.#startIndex) triggerSortableEvent(destination, "update", eventData);
284
280
  if (this.node) this.#resetDrag();
285
281
  };
286
- const dragEvent = _fr0st_query.default.mouseDragFactory(downEvent, moveEvent, upEvent);
287
- _fr0st_query.default.addEventDelegate(this.node, "mousedown.ui.sortable touchstart.ui.sortable", this.#selector, dragEvent);
288
- _fr0st_query.default.addEvent(this.node, "receive.ui.sortable", () => {
282
+ const dragHandler = _fr0st_query.default.mouseDragFactory(downHandler, moveHandler, upHandler);
283
+ this.listen(this.node, "mousedown.ui.sortable touchstart.ui.sortable", dragHandler, { delegate: this.#selector });
284
+ this.listen(this.node, "receive.ui.sortable", () => {
289
285
  setCursor(_fr0st_query.default.find(this.#selector, this.node), this.options.cursor);
290
286
  });
291
287
  }
@@ -293,7 +289,7 @@ _fr0st_query = __toESM(_fr0st_query, 1);
293
289
  * Resets the active drag state.
294
290
  */
295
291
  #resetDrag() {
296
- if (this.#scrollFrame !== null && this.#scrollFrame !== void 0) window.cancelAnimationFrame(this.#scrollFrame);
292
+ if (this.#scrollFrame !== null) window.cancelAnimationFrame(this.#scrollFrame);
297
293
  if (this.#dragging && this.node) _fr0st_query.default.removeDataset(this.node, "uiDragging");
298
294
  this.#currentIndex = null;
299
295
  this.#currentSortable = null;
@@ -307,7 +303,7 @@ _fr0st_query = __toESM(_fr0st_query, 1);
307
303
  * Schedules the next auto-scroll update.
308
304
  */
309
305
  #scheduleScroll() {
310
- if (!this.node || !this.options.scroll || !this.#dragging || this.#scrollFrame !== null && this.#scrollFrame !== void 0) return;
306
+ if (!this.node || !this.options.scroll || !this.#dragging || this.#scrollFrame !== null) return;
311
307
  this.#scrollFrame = window.requestAnimationFrame(() => {
312
308
  this.#checkScroll();
313
309
  });
@@ -392,12 +388,10 @@ _fr0st_query = __toESM(_fr0st_query, 1);
392
388
  }
393
389
  };
394
390
 
395
- //#endregion
396
- //#region src/index.js
391
+ // src/index.js
397
392
  (0, _fr0st_ui.initComponent)("sortable", Sortable);
398
393
  var src_default = Sortable;
399
394
 
400
- //#endregion
401
395
  exports.Sortable = src_default;
402
396
  });
403
397
  //# sourceMappingURL=frost-ui-sortable.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"frost-ui-sortable.js","names":["$","$","BaseComponent","getPosition"],"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
+ {"version":3,"file":"frost-ui-sortable.js","names":["$","$","BaseComponent","getPosition"],"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 = null;\n #dragging;\n #enabled;\n #initialCursorNodes = [];\n #pos = null;\n #scrollFrame = null;\n #selector;\n #startIndex;\n #target = null;\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 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 downHandler = (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 moveHandler = (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 upHandler = (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 dragHandler = $.mouseDragFactory(downHandler, moveHandler, upHandler);\n\n this.listen(\n this.node,\n 'mousedown.ui.sortable touchstart.ui.sortable',\n dragHandler,\n { delegate: this.#selector },\n );\n\n this.listen(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) {\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\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
- (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("@fr0st/ui"),require("@fr0st/query")):typeof define==`function`&&define.amd?define([`exports`,`@fr0st/ui`,`@fr0st/query`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.UI=e.UI||{},e.UI,e.fQuery))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r=Object.create,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,s=Object.getPrototypeOf,c=Object.prototype.hasOwnProperty,l=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var s=o(t),l=0,u=s.length,d;l<u;l++)d=s[l],!c.call(e,d)&&d!==n&&i(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=a(t,d))||r.enumerable});return e};n=((e,t,n)=>(n=e==null?{}:r(s(e)),l(t||!e||!e.__esModule||!c.call(e,`default`)?i(n,`default`,{value:e,enumerable:!0}):n,e)))(n,1);var u=/* @__PURE__ */ new WeakMap;function d(e){for(let t of e){let e=u.get(t);e&&(e(),u.delete(t))}}function f(e,t){for(let r of e)u.has(r)?n.default.setStyle(r,{cursor:t}):u.set(r,n.default.setStyleLock(r,`cursor`,t))}function p(e,t,r){n.default.triggerEvent(e,`${t}.ui.sortable`,{data:r,detail:{target:r.item,...r}})}var m=n.default.getContext(),h=n.default.getWindow(),g=class extends t.BaseComponent{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=n.default.find(this.#s,this.node),f(this.#i,this.options.cursor),this.#d(),this.#i=null}catch(e){throw this.dispose(),e}}disable(){this.#r=!1}dispose(){this.node&&(n.default.removeEventDelegate(this.node,`mousedown.ui.sortable touchstart.ui.sortable`),n.default.removeEvent(this.node,`receive.ui.sortable`),d(this.#i??n.default.find(this.#s,this.node)),this.#l&&this.options.helperClass&&n.default.removeClass(this.#l,this.options.helperClass),this.#f(),this.#i=null,super.dispose())}enable(){this.#r=!0}items(){return n.default.find(this.options.items,this.node)}#u(){if(this.#o=null,!this.node||!this.#n||!this.#l||!this.#a)return;let e=n.default.getScrollX(h),t=n.default.getScrollY(h),r=n.default.height(h),i=n.default.width(h),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+r-this.options.scrollSensitivity){let e=n.default.height(m,{boxSize:n.default.SCROLL_BOX}),i=Math.max(0,e-r);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=n.default.width(m,{boxSize:n.default.SCROLL_BOX}),r=Math.max(0,t-i);a=Math.min(r,e+this.options.scrollSpeed)}if(a===e&&o===t)return;h.scrollTo({left:a,top:o,behavior:`instant`});let s=a-e,c=o-t;this.#a.x+=s,this.#a.y+=c,this.#m(s,c),this.#p()}#d(){let e=n.default.mouseDragFactory(e=>{let t=this.options.cancel&&(n.default.is(e.target,this.options.cancel)||n.default.is(e.currentTarget,this.options.cancel)||n.default.closest(e.target,this.options.cancel,this.node).length);if(e.button||!this.#r||t||n.default.getDataset(this.node,`uiDragging`)||(this.#l=this.options.handle?this.items().find(t=>n.default.hasDescendent(t,e.currentTarget)):e.currentTarget,!this.#l))return!1},e=>{if(!this.node||!this.#l)return;let r=this.#a;this.#a=(0,t.getPosition)(e);let i=r?this.#a.x-r.x:0,a=r?this.#a.y-r.y:0;if(!this.#n){this.#n=!0,this.#t=this.node,this.#c=this.items().indexOf(this.#l),this.#e=this.#c,n.default.setDataset(this.node,{uiDragging:!0});let e={item:this.#l,from:this.node,to:this.node,oldIndex:this.#c,newIndex:this.#c};if(p(this.node,`sort`,e),!this.node)return;this.options.helperClass&&n.default.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,r=this.#t,i={item:this.#l,from:t,to:r,oldIndex:this.#c,newIndex:this.#e};p(r,`sorted`,i),this.node&&(this.options.helperClass&&n.default.removeClass(this.#l,this.options.helperClass),t===r?this.#e!==this.#c&&p(r,`update`,i):(p(t,`update`,i),this.node&&p(r,`update`,i)),this.node&&this.#f())});n.default.addEventDelegate(this.node,`mousedown.ui.sortable touchstart.ui.sortable`,this.#s,e),n.default.addEvent(this.node,`receive.ui.sortable`,()=>{f(n.default.find(this.#s,this.node),this.options.cursor)})}#f(){this.#o!==null&&this.#o!==void 0&&h.cancelAnimationFrame(this.#o),this.#n&&this.node&&n.default.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=h.requestAnimationFrame(()=>{this.#u()}))}#m(e,t){let r=this.node;if(this.options.connectWith){let e=n.default.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&&(r=n.default.nearestTo([this.node,...e],this.#a.x,this.#a.y,{offset:!0}))}let i=this.constructor.init(r),a=i.items().filter(e=>e!==this.#l),o=n.default.nearestTo(a,this.#a.x,this.#a.y,{offset:!0});if(o)this.#h(o,this.#a.x,this.#a.y,e,t);else if(r!==this.#t)n.default.append(r,this.#l);else return;let s=i.items().indexOf(this.#l);if(r!==this.#t){let e=this.#t,{handle:t}=this.constructor.init(e).options;d(t?n.default.find(t,this.#l):[this.#l]);let i={item:this.#l,from:e,to:r,oldIndex:this.#e,newIndex:s};if(p(e,`send`,i),!this.node)return;p(r,`receive`,i)}else if(this.#e!==s){let e={item:this.#l,from:r,to:r,oldIndex:this.#e,newIndex:s};p(r,`sorting`,e)}this.node&&(this.#e=s,this.#t=r)}#h(e,t,r,i,a){let o=n.default.center(e,{offset:!0}),s=n.default.rect(e,{offset:!0}),c=n.default.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=r<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,n=s.top+s.height*d;f=t<e&&r<n?`before`:`after`}n.default[f](e,this.#l)}};(0,t.initComponent)(`sortable`,g),e.Sortable=g});
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("@fr0st/ui"),require("@fr0st/query")):typeof define==`function`&&define.amd?define([`exports`,`@fr0st/ui`,`@fr0st/query`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.UI=e.UI||{},e.UI,e.fQuery))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r=Object.create,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,s=Object.getPrototypeOf,c=Object.prototype.hasOwnProperty,l=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var s=o(t),l=0,u=s.length,d;l<u;l++)d=s[l],!c.call(e,d)&&d!==n&&i(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=a(t,d))||r.enumerable});return e};n=((e,t,n)=>(n=e==null?{}:r(s(e)),l(i(n,`default`,{value:e,enumerable:!0}),e)))(n,1);var u=/* @__PURE__ */ new WeakMap;function d(e){for(let t of e){let e=u.get(t);e&&(e(),u.delete(t))}}function f(e,t){for(let r of e)u.has(r)?n.default.setStyle(r,{cursor:t}):u.set(r,n.default.setStyleLock(r,`cursor`,t))}function p(e,t,r){n.default.triggerEvent(e,`${t}.ui.sortable`,{data:r,detail:{target:r.item,...r}})}var m=n.default.getContext(),h=n.default.getWindow(),g=class extends t.BaseComponent{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=null;#n;#r;#i=[];#a=null;#o=null;#s;#c;#l=null;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=n.default.find(this.#s,this.node),f(this.#i,this.options.cursor),this.#d(),this.#i=null}catch(e){throw this.dispose(),e}}disable(){this.#r=!1}dispose(){this.node&&(d(this.#i??n.default.find(this.#s,this.node)),this.#l&&this.options.helperClass&&n.default.removeClass(this.#l,this.options.helperClass),this.#f(),this.#i=null,super.dispose())}enable(){this.#r=!0}items(){return n.default.find(this.options.items,this.node)}#u(){if(this.#o=null,!this.node||!this.#n||!this.#l||!this.#a)return;let e=n.default.getScrollX(h),t=n.default.getScrollY(h),r=n.default.height(h),i=n.default.width(h),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+r-this.options.scrollSensitivity){let e=n.default.height(m,{boxSize:n.default.SCROLL_BOX}),i=Math.max(0,e-r);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=n.default.width(m,{boxSize:n.default.SCROLL_BOX}),r=Math.max(0,t-i);a=Math.min(r,e+this.options.scrollSpeed)}if(a===e&&o===t)return;h.scrollTo({left:a,top:o,behavior:`instant`});let s=a-e,c=o-t;this.#a.x+=s,this.#a.y+=c,this.#m(s,c),this.#p()}#d(){let e=n.default.mouseDragFactory(e=>{let t=this.options.cancel&&(n.default.is(e.target,this.options.cancel)||n.default.is(e.currentTarget,this.options.cancel)||n.default.closest(e.target,this.options.cancel,this.node).length);if(e.button||!this.#r||t||n.default.getDataset(this.node,`uiDragging`)||(this.#l=this.options.handle?this.items().find(t=>n.default.hasDescendent(t,e.currentTarget)):e.currentTarget,!this.#l))return!1},e=>{if(!this.node||!this.#l)return;let r=this.#a;this.#a=(0,t.getPosition)(e);let i=r?this.#a.x-r.x:0,a=r?this.#a.y-r.y:0;if(!this.#n){this.#n=!0,this.#t=this.node,this.#c=this.items().indexOf(this.#l),this.#e=this.#c,n.default.setDataset(this.node,{uiDragging:!0});let e={item:this.#l,from:this.node,to:this.node,oldIndex:this.#c,newIndex:this.#c};if(p(this.node,`sort`,e),!this.node)return;this.options.helperClass&&n.default.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,r=this.#t,i={item:this.#l,from:t,to:r,oldIndex:this.#c,newIndex:this.#e};p(r,`sorted`,i),this.node&&(this.options.helperClass&&n.default.removeClass(this.#l,this.options.helperClass),t===r?this.#e!==this.#c&&p(r,`update`,i):(p(t,`update`,i),this.node&&p(r,`update`,i)),this.node&&this.#f())});this.listen(this.node,`mousedown.ui.sortable touchstart.ui.sortable`,e,{delegate:this.#s}),this.listen(this.node,`receive.ui.sortable`,()=>{f(n.default.find(this.#s,this.node),this.options.cursor)})}#f(){this.#o!==null&&h.cancelAnimationFrame(this.#o),this.#n&&this.node&&n.default.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=h.requestAnimationFrame(()=>{this.#u()}))}#m(e,t){let r=this.node;if(this.options.connectWith){let e=n.default.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&&(r=n.default.nearestTo([this.node,...e],this.#a.x,this.#a.y,{offset:!0}))}let i=this.constructor.init(r),a=i.items().filter(e=>e!==this.#l),o=n.default.nearestTo(a,this.#a.x,this.#a.y,{offset:!0});if(o)this.#h(o,this.#a.x,this.#a.y,e,t);else if(r!==this.#t)n.default.append(r,this.#l);else return;let s=i.items().indexOf(this.#l);if(r!==this.#t){let e=this.#t,{handle:t}=this.constructor.init(e).options;d(t?n.default.find(t,this.#l):[this.#l]);let i={item:this.#l,from:e,to:r,oldIndex:this.#e,newIndex:s};if(p(e,`send`,i),!this.node)return;p(r,`receive`,i)}else if(this.#e!==s){let e={item:this.#l,from:r,to:r,oldIndex:this.#e,newIndex:s};p(r,`sorting`,e)}this.node&&(this.#e=s,this.#t=r)}#h(e,t,r,i,a){let o=n.default.center(e,{offset:!0}),s=n.default.rect(e,{offset:!0}),c=n.default.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=r<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,n=s.top+s.height*d;f=t<e&&r<n?`before`:`after`}n.default[f](e,this.#l)}};(0,t.initComponent)(`sortable`,g),e.Sortable=g});
2
2
  //# sourceMappingURL=frost-ui-sortable.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"frost-ui-sortable.min.js","names":["$","$","BaseComponent","getPosition","factory","global","exports","__create","__defProp","__getOwnPropDesc","__getOwnPropNames","__getProtoOf","__hasOwnProp","__copyProps","from","keys","i","n","key","to","except","k","desc","mod","isNodeMode","target","_fr0st_query","cursorLocks","resetCursor","node","nodes","release","setCursor","cursor","triggerSortableEvent","name","data","document","window","Sortable","_fr0st_ui","options","#selector","#dragging","#enabled","#initialCursorNodes","#events","error","#target","#resetDrag","#scrollFrame","#pos","originalX","originalY","windowHeight","windowWidth","offsetX","offsetY","docHeight","maxY","docWidth","maxX","deltaX","deltaY","#updatePlacement","#scheduleScroll","dragEvent","cancelled","event","previousPos","#currentSortable","#startIndex","#currentIndex","eventData","source","destination","#checkScroll","nearestSortable","connected","sortable","nearestInstance","nearestItems","nearestItem","#updateTarget","newIndex","previousSortable","handle","nearestCenter","nearestRect","targetCenter","threshold","thresholdX","thresholdY","method","y","x","swapX","swapY","src_default"],"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":"q2BAIA,IAAM2B,kBAAc,IAAI,QAMxB,SAAgBC,EAAY,EAAO,CAC/B,IAAK,IAAMC,KAAQC,EAAO,CACtB,IAAMC,EAAUJ,EAAY,IAAIE,CAAI,EAE/BE,IAILA,EAAQ,EACRJ,EAAY,OAAOE,CAAI,EAC3B,CACJ,CAOA,SAAgBG,EAAU,EAAO,EAAQ,CACrC,IAAK,IAAMH,KAAQC,EACXH,EAAY,IAAIE,CAAI,EACpBH,EAAA,QAAE,SAASG,EAAM,CAAE,QAAO,CAAC,EAE3BF,EAAY,IAAIE,EAAM7B,EAAAA,QAAE,aAAa6B,EAAM,SAAUI,CAAM,CAAC,CAGxE,CAQA,SAAgBC,EAAqB,EAAM,EAAM,EAAM,CACnDR,EAAA,QAAE,aAAaG,EAAM,GAAGM,EAAK,cAAe,CACxC,OACA,OAAQ,CACJ,OAAQC,EAAK,KACb,GAAGA,CACP,CACJ,CAAC,CACL,CChDA,IAAMC,EAAWpC,EAAAA,QAAE,WAAW,EACxBqC,EAASrC,EAAAA,QAAE,UAAU,EAkCNsC,EAArB,cAAsCrC,EAAAA,aAAc,CAEhD,OAAO,SAAW,CACd,KAAM,KACN,OAAQ,0CACR,YAAa,KACb,OAAQ,OACR,SAAU,GACV,YAAa,GACb,OAAQ,KACR,YAAa,mBACb,MAAO,cACP,OAAQ,GACR,kBAAmB,GACnB,YAAa,EACb,cAAe,GACnB,EAEA,GACA,GACA,GACA,GACA,GAAsB,CAAC,EACvB,GACA,GACA,GACA,GACA,GAOA,YAAY,EAAM,EAAS,CACvB,MAAM2B,EAAMY,CAAO,EAEnB,GAAI,CACA,KAAKC,GAAY,KAAK,QAAQ,OAC1B,OAAO,KAAK,QAAQ,MAAM,QAAQ,KAAK,QAAQ,OAAO,GACtD,KAAK,QAAQ,MAEjB,KAAKC,GAAY,GACjB,KAAKC,GAAW,CAAC,KAAK,QAAQ,SAE9B,KAAKC,GAAsB5C,EAAAA,QAAE,KAAK,KAAKyC,GAAW,KAAK,IAAI,EAC3DV,EAAU,KAAKa,GAAqB,KAAK,QAAQ,MAAM,EACvD,KAAKC,GAAQ,EACb,KAAKD,GAAsB,IAC/B,OAASE,EAAO,CAEZ,MADA,KAAK,QAAQ,EACPA,CACV,CACJ,CAKA,SAAU,CACN,KAAKH,GAAW,EACpB,CAGA,SAAU,CACD,KAAK,OAIVlB,EAAA,QAAE,oBAAoB,KAAK,KAAM,8CAA8C,EAC/EA,EAAA,QAAE,YAAY,KAAK,KAAM,qBAAqB,EAC9CE,EAAY,KAAKiB,IAAuB5C,EAAAA,QAAE,KAAK,KAAKyC,GAAW,KAAK,IAAI,CAAC,EAErE,KAAKM,IAAW,KAAK,QAAQ,aAC7BtB,EAAA,QAAE,YAAY,KAAKsB,GAAS,KAAK,QAAQ,WAAW,EAGxD,KAAKC,GAAW,EAEhB,KAAKJ,GAAsB,KAE3B,MAAM,QAAQ,EAClB,CAKA,QAAS,CACL,KAAKD,GAAW,EACpB,CAMA,OAAQ,CACJ,OAAO3C,EAAAA,QAAE,KAAK,KAAK,QAAQ,MAAO,KAAK,IAAI,CAC/C,CAKA,IAAe,CAGX,GAFA,KAAKiD,GAAe,KAEhB,CAAC,KAAK,MAAQ,CAAC,KAAKP,IAAa,CAAC,KAAKK,IAAW,CAAC,KAAKG,GACxD,OAGJ,IAAMC,EAAYnD,EAAAA,QAAE,WAAWqC,CAAM,EAC/Be,EAAYpD,EAAAA,QAAE,WAAWqC,CAAM,EAC/BgB,EAAerD,EAAAA,QAAE,OAAOqC,CAAM,EAC9BiB,EAActD,EAAAA,QAAE,MAAMqC,CAAM,EAE9BkB,EAAUJ,EACVK,EAAUJ,EAEd,GAAI,KAAKF,GAAK,EAAIE,EAAY,KAAK,QAAQ,kBACvC,EAAU,KAAK,IAAI,EAAGA,EAAY,KAAK,QAAQ,WAAW,OACvD,GAAI,KAAKF,GAAK,EAAIE,EAAYC,EAAe,KAAK,QAAQ,kBAAmB,CAChF,IAAMI,EAAYzD,EAAAA,QAAE,OAAOoC,EAAU,CAAE,QAASpC,EAAAA,QAAE,UAAW,CAAC,EACxD0D,EAAO,KAAK,IAAI,EAAGD,EAAYJ,CAAY,EACjD,EAAU,KAAK,IAAIK,EAAMN,EAAY,KAAK,QAAQ,WAAW,CACjE,CAEA,GAAI,KAAKF,GAAK,EAAIC,EAAY,KAAK,QAAQ,kBACvC,EAAU,KAAK,IAAI,EAAGA,EAAY,KAAK,QAAQ,WAAW,OACvD,GAAI,KAAKD,GAAK,EAAIC,EAAYG,EAAc,KAAK,QAAQ,kBAAmB,CAC/E,IAAMK,EAAW3D,EAAAA,QAAE,MAAMoC,EAAU,CAAE,QAASpC,EAAAA,QAAE,UAAW,CAAC,EACtD4D,EAAO,KAAK,IAAI,EAAGD,EAAWL,CAAW,EAC/C,EAAU,KAAK,IAAIM,EAAMT,EAAY,KAAK,QAAQ,WAAW,CACjE,CAEA,GAAII,IAAYJ,GAAaK,IAAYJ,EACrC,OAGJf,EAAO,SAAS,CACZ,KAAMkB,EACN,IAAKC,EACL,SAAU,SACd,CAAC,EAED,IAAMK,EAASN,EAAUJ,EACnBW,EAASN,EAAUJ,EAEzB,KAAKF,GAAK,GAAKW,EACf,KAAKX,GAAK,GAAKY,EAEf,KAAKC,GAAiBF,EAAQC,CAAM,EACpC,KAAKE,GAAgB,CACzB,CAKA,IAAU,CA2HN,IAAMC,EAAYjE,EAAAA,QAAE,iBA1HD,GAAU,CACzB,IAAMkE,EAAY,KAAK,QAAQ,SAEvBlE,EAAAA,QAAE,GAAGmE,EAAM,OAAQ,KAAK,QAAQ,MAAM,GACtCnE,EAAAA,QAAE,GAAGmE,EAAM,cAAe,KAAK,QAAQ,MAAM,GAC7CnE,EAAAA,QAAE,QAAQmE,EAAM,OAAQ,KAAK,QAAQ,OAAQ,KAAK,IAAI,CAAC,CAAC,QAgBhE,GAZIA,EAAM,QACN,CAAC,KAAKxB,IACNuB,GACAlE,EAAAA,QAAE,WAAW,KAAK,KAAM,YAAY,IAKxC,KAAK+C,GAAU,KAAK,QAAQ,OACxB,KAAK,MAAM,CAAC,CAAC,KAAM,GAAS/C,EAAAA,QAAE,cAAc4B,EAAMuC,EAAM,aAAa,CAAC,EACtEA,EAAM,cAEN,CAAC,KAAKpB,IACN,MAAO,EAEf,EAEmB,GAAU,CACzB,GAAI,CAAC,KAAK,MAAQ,CAAC,KAAKA,GACpB,OAGJ,IAAMqB,EAAc,KAAKlB,GACzB,KAAKA,IAAA,EAAOhD,EAAAA,YAAAA,CAAYiE,CAAK,EAC7B,IAAMN,EAASO,EACX,KAAKlB,GAAK,EAAIkB,EAAY,EAC1B,EACEN,EAASM,EACX,KAAKlB,GAAK,EAAIkB,EAAY,EAC1B,EAEJ,GAAI,CAAC,KAAK1B,GAAW,CACjB,KAAKA,GAAY,GACjB,KAAK2B,GAAmB,KAAK,KAC7B,KAAKC,GAAc,KAAK,MAAM,CAAC,CAAC,QAAQ,KAAKvB,EAAO,EACpD,KAAKwB,GAAgB,KAAKD,GAE1B7C,EAAA,QAAE,WAAW,KAAK,KAAM,CAAE,WAAY,EAAK,CAAC,EAG5C,IAAM+C,EAAY,CACd,KAAM,KAAKzB,GACX,KAAM,KAAK,KACX,GAAI,KAAK,KACT,SAAU,KAAKuB,GACf,SAAU,KAAKA,EACnB,EAIA,GAFArC,EAAqB,KAAK,KAAM,OAAQuC,CAAS,EAE7C,CAAC,KAAK,KACN,OAGA,KAAK,QAAQ,aACb/C,EAAA,QAAE,SAAS,KAAKsB,GAAS,KAAK,QAAQ,WAAW,CAEzD,CAEA,KAAKgB,GAAiBF,EAAQC,CAAM,EACpC,KAAKE,GAAgB,CACzB,EAEiB,GAAU,CACvB,GAAI,CAAC,KAAK,KACN,OAGJ,GAAI,CAAC,KAAKtB,GAAW,CACjB,KAAKK,GAAU,KACf,MACJ,CAEIoB,EAAM,OAAS,WACfA,EAAM,eAAe,EAGzB,IAAMM,EAAS,KAAK,KACdC,EAAc,KAAKL,GAEnBG,EAAY,CACd,KAAM,KAAKzB,GACX,KAAM0B,EACN,GAAIC,EACJ,SAAU,KAAKJ,GACf,SAAU,KAAKC,EACnB,EAEAtC,EAAqByC,EAAa,SAAUF,CAAS,EAEhD,KAAK,OAIN,KAAK,QAAQ,aACb/C,EAAA,QAAE,YAAY,KAAKsB,GAAS,KAAK,QAAQ,WAAW,EAGpD0B,IAAWC,EAMJ,KAAKH,KAAkB,KAAKD,IACnCrC,EAAqByC,EAAa,SAAUF,CAAS,GANrDvC,EAAqBwC,EAAQ,SAAUD,CAAS,EAE5C,KAAK,MACLvC,EAAqByC,EAAa,SAAUF,CAAS,GAMzD,KAAK,MACL,KAAKxB,GAAW,EAExB,CAEkE,EAElEvB,EAAA,QAAE,iBACE,KAAK,KACL,+CACA,KAAKgB,GACLwB,CACJ,EAEAxC,EAAA,QAAE,SAAS,KAAK,KAAM,0BAA6B,CAC/CM,EAAU/B,EAAAA,QAAE,KAAK,KAAKyC,GAAW,KAAK,IAAI,EAAG,KAAK,QAAQ,MAAM,CACpE,CAAC,CACL,CAKA,IAAa,CACL,KAAKQ,KAAiB,MAAQ,KAAKA,KAAiB,IAAA,IACpDZ,EAAO,qBAAqB,KAAKY,EAAY,EAG7C,KAAKP,IAAa,KAAK,MACvBjB,EAAA,QAAE,cAAc,KAAK,KAAM,YAAY,EAG3C,KAAK8C,GAAgB,KACrB,KAAKF,GAAmB,KACxB,KAAK3B,GAAY,GACjB,KAAKQ,GAAO,KACZ,KAAKD,GAAe,KACpB,KAAKqB,GAAc,KACnB,KAAKvB,GAAU,IACnB,CAKA,IAAkB,CAET,KAAK,MACL,KAAK,QAAQ,QACb,KAAKL,KACN,KAAKO,KAAiB,MAAQ,KAAKA,KAAiB,IAAA,MAKxD,KAAKA,GAAeZ,EAAO,0BAA4B,CACnD,KAAKsC,GAAa,CACtB,CAAC,EACL,CAOA,GAAiB,EAAQ,EAAQ,CAC7B,IAAIC,EAAkB,KAAK,KAE3B,GAAI,KAAK,QAAQ,YAAa,CAC1B,IAAMC,EAAY7E,EAAAA,QAAE,KAAK,KAAK,QAAQ,WAAW,CAAC,CAC7C,OAAQ,GAAS4B,IAAS,KAAK,IAAI,CAAC,CACpC,OAAQ,GAAS,CACd,IAAMkD,EAAW,KAAK,YAAY,KAAKlD,CAAI,EAE3C,OAAOkD,EAASnC,KACXmC,EAAS,QAAQ,aAAeA,EAAS,MAAM,CAAC,CAAC,OAC1D,CAAC,EAEDD,EAAU,SACV,EAAkB7E,EAAAA,QAAE,UAChB,CAAC,KAAK,KAAM,GAAG6E,CAAS,EACxB,KAAK3B,GAAK,EACV,KAAKA,GAAK,EACV,CAAE,OAAQ,EAAK,CACnB,EAER,CAEA,IAAM6B,EAAkB,KAAK,YAAY,KAAKH,CAAe,EACvDI,EAAeD,EAAgB,MAAM,CAAC,CACvC,OAAQ,GAASnD,IAAS,KAAKmB,EAAO,EACrCkC,EAAcjF,EAAAA,QAAE,UAClBgF,EACA,KAAK9B,GAAK,EACV,KAAKA,GAAK,EACV,CAAE,OAAQ,EAAK,CACnB,EAEA,GAAI+B,EACA,KAAKC,GACDD,EACA,KAAK/B,GAAK,EACV,KAAKA,GAAK,EACVW,EACAC,CACJ,OACG,GAAIc,IAAoB,KAAKP,GAChC5C,EAAA,QAAE,OAAOmD,EAAiB,KAAK7B,EAAO,OAEtC,OAGJ,IAAMoC,EAAWJ,EAAgB,MAAM,CAAC,CAAC,QAAQ,KAAKhC,EAAO,EAE7D,GAAI6B,IAAoB,KAAKP,GAAkB,CAC3C,IAAMe,EAAmB,KAAKf,GAExB,CAAE,UADiB,KAAK,YAAY,KAAKe,CACb,CAAC,CAAC,QAEpCzD,EAAY0D,EACRrF,EAAAA,QAAE,KAAKqF,EAAQ,KAAKtC,EAAO,EAC3B,CAAC,KAAKA,EAAO,CAAC,EAGlB,IAAMyB,EAAY,CACd,KAAM,KAAKzB,GACX,KAAMqC,EACN,GAAIR,EACJ,SAAU,KAAKL,GACf,UACJ,EAIA,GAFAtC,EAAqBmD,EAAkB,OAAQZ,CAAS,EAEpD,CAAC,KAAK,KACN,OAGJvC,EAAqB2C,EAAiB,UAAWJ,CAAS,CAC9D,MAAO,GAAI,KAAKD,KAAkBY,EAAU,CAExC,IAAMX,EAAY,CACd,KAAM,KAAKzB,GACX,KAAM6B,EACN,GAAIA,EACJ,SAAU,KAAKL,GACf,UACJ,EAEAtC,EAAqB2C,EAAiB,UAAWJ,CAAS,CAC9D,CAEK,KAAK,OAIV,KAAKD,GAAgBY,EACrB,KAAKd,GAAmBO,EAC5B,CAUA,GAAc,EAAa,EAAG,EAAG,EAAQ,EAAQ,CAC7C,IAAMU,EAAgBtF,EAAAA,QAAE,OAAOiF,EAAa,CAAE,OAAQ,EAAK,CAAC,EACtDM,EAAcvF,EAAAA,QAAE,KAAKiF,EAAa,CAAE,OAAQ,EAAK,CAAC,EAClDO,EAAexF,EAAAA,QAAE,OAAO,KAAK+C,GAAS,CAAE,OAAQ,EAAK,CAAC,EACtD0C,EAAY,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,KAAK,QAAQ,aAAa,CAAC,EACjEC,EAAa,GACbC,EAAa,GAEb9B,IACA,EAAaA,EAAS,EAClB4B,EACA,EAAIA,GAGR3B,IACA,EAAaA,EAAS,EAClB2B,EACA,EAAIA,GAGZ,IAAIG,EACJ,GAAI,KAAK,QAAQ,OAAS,KAAON,EAAc,IAAME,EAAa,EAE9D,EAASK,EADKN,EAAY,IAAMA,EAAY,OAASI,EAEjD,SACA,aACD,GAAI,KAAK,QAAQ,OAAS,KAAOL,EAAc,IAAME,EAAa,EAErE,EAASM,EADKP,EAAY,KAAOA,EAAY,MAAQG,EAEjD,SACA,YACD,CACH,IAAMK,EAAQR,EAAY,KAAOA,EAAY,MAAQG,EAC/CM,EAAQT,EAAY,IAAMA,EAAY,OAASI,EACrD,EAASG,EAAIC,GAASF,EAAIG,EACtB,SACA,OACR,CAEAvE,EAAA,QAAEmE,EAAO,CAACX,EAAa,KAAKlC,EAAO,CACvC,CACJ,GCpgBA,EAAAR,EAAA,cAAA,CAAc,WAAYD,CAAQ"}
1
+ {"version":3,"file":"frost-ui-sortable.min.js","names":["$","$","BaseComponent","getPosition","factory","global","exports","__create","__defProp","__getOwnPropDesc","__getOwnPropNames","__getProtoOf","__hasOwnProp","__copyProps","from","keys","i","n","key","to","except","k","desc","mod","target","_fr0st_query","cursorLocks","resetCursor","node","nodes","release","setCursor","cursor","triggerSortableEvent","name","data","document","window","Sortable","_fr0st_ui","options","#selector","#dragging","#enabled","#initialCursorNodes","#events","error","#target","#resetDrag","#scrollFrame","#pos","originalX","originalY","windowHeight","windowWidth","offsetX","offsetY","docHeight","maxY","docWidth","maxX","deltaX","deltaY","#updatePlacement","#scheduleScroll","dragHandler","cancelled","event","previousPos","#currentSortable","#startIndex","#currentIndex","eventData","source","destination","#checkScroll","nearestSortable","connected","sortable","nearestInstance","nearestItems","nearestItem","#updateTarget","newIndex","previousSortable","handle","nearestCenter","nearestRect","targetCenter","threshold","thresholdX","thresholdY","method","y","x","swapX","swapY","src_default"],"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 = null;\n #dragging;\n #enabled;\n #initialCursorNodes = [];\n #pos = null;\n #scrollFrame = null;\n #selector;\n #startIndex;\n #target = null;\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 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 downHandler = (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 moveHandler = (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 upHandler = (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 dragHandler = $.mouseDragFactory(downHandler, moveHandler, upHandler);\n\n this.listen(\n this.node,\n 'mousedown.ui.sortable touchstart.ui.sortable',\n dragHandler,\n { delegate: this.#selector },\n );\n\n this.listen(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) {\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\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":"C,uzBAIA,IAAM0B,kBAAc,IAAI,QAMxB,SAAgBC,EAAY,EAAO,CAC/B,IAAK,IAAMC,KAAQC,EAAO,CACtB,IAAMC,EAAUJ,EAAY,IAAIE,CAAI,EAE/BE,IAILA,EAAQ,EACRJ,EAAY,OAAOE,CAAI,EAC3B,CACJ,CAOA,SAAgBG,EAAU,EAAO,EAAQ,CACrC,IAAK,IAAMH,KAAQC,EACXH,EAAY,IAAIE,CAAI,EACpBH,EAAA,QAAE,SAASG,EAAM,CAAE,QAAO,CAAC,EAE3BF,EAAY,IAAIE,EAAM5B,EAAAA,QAAE,aAAa4B,EAAM,SAAUI,CAAM,CAAC,CAGxE,CAQA,SAAgBC,EAAqB,EAAM,EAAM,EAAM,CACnDR,EAAA,QAAE,aAAaG,EAAM,GAAGM,EAAK,cAAe,CACxC,OACA,OAAQ,CACJ,OAAQC,EAAK,KACb,GAAGA,CACP,CACJ,CAAC,CACL,CChDA,IAAMC,EAAWnC,EAAAA,QAAE,WAAW,EACxBoC,EAASpC,EAAAA,QAAE,UAAU,EAkCNqC,EAArB,cAAsCpC,EAAAA,aAAc,CAEhD,OAAO,SAAW,CACd,KAAM,KACN,OAAQ,0CACR,YAAa,KACb,OAAQ,OACR,SAAU,GACV,YAAa,GACb,OAAQ,KACR,YAAa,mBACb,MAAO,cACP,OAAQ,GACR,kBAAmB,GACnB,YAAa,EACb,cAAe,GACnB,EAEA,GACA,GAAmB,KACnB,GACA,GACA,GAAsB,CAAC,EACvB,GAAO,KACP,GAAe,KACf,GACA,GACA,GAAU,KAOV,YAAY,EAAM,EAAS,CACvB,MAAM0B,EAAMY,CAAO,EAEnB,GAAI,CACA,KAAKC,GAAY,KAAK,QAAQ,OAC1B,OAAO,KAAK,QAAQ,MAAM,QAAQ,KAAK,QAAQ,OAAO,GACtD,KAAK,QAAQ,MAEjB,KAAKC,GAAY,GACjB,KAAKC,GAAW,CAAC,KAAK,QAAQ,SAE9B,KAAKC,GAAsB3C,EAAAA,QAAE,KAAK,KAAKwC,GAAW,KAAK,IAAI,EAC3DV,EAAU,KAAKa,GAAqB,KAAK,QAAQ,MAAM,EACvD,KAAKC,GAAQ,EACb,KAAKD,GAAsB,IAC/B,OAASE,EAAO,CAEZ,MADA,KAAK,QAAQ,EACPA,CACV,CACJ,CAKA,SAAU,CACN,KAAKH,GAAW,EACpB,CAGA,SAAU,CACD,KAAK,OAIVhB,EAAY,KAAKiB,IAAuB3C,EAAAA,QAAE,KAAK,KAAKwC,GAAW,KAAK,IAAI,CAAC,EAErE,KAAKM,IAAW,KAAK,QAAQ,aAC7BtB,EAAA,QAAE,YAAY,KAAKsB,GAAS,KAAK,QAAQ,WAAW,EAGxD,KAAKC,GAAW,EAEhB,KAAKJ,GAAsB,KAE3B,MAAM,QAAQ,EAClB,CAKA,QAAS,CACL,KAAKD,GAAW,EACpB,CAMA,OAAQ,CACJ,OAAO1C,EAAAA,QAAE,KAAK,KAAK,QAAQ,MAAO,KAAK,IAAI,CAC/C,CAKA,IAAe,CAGX,GAFA,KAAKgD,GAAe,KAEhB,CAAC,KAAK,MAAQ,CAAC,KAAKP,IAAa,CAAC,KAAKK,IAAW,CAAC,KAAKG,GACxD,OAGJ,IAAMC,EAAYlD,EAAAA,QAAE,WAAWoC,CAAM,EAC/Be,EAAYnD,EAAAA,QAAE,WAAWoC,CAAM,EAC/BgB,EAAepD,EAAAA,QAAE,OAAOoC,CAAM,EAC9BiB,EAAcrD,EAAAA,QAAE,MAAMoC,CAAM,EAE9BkB,EAAUJ,EACVK,EAAUJ,EAEd,GAAI,KAAKF,GAAK,EAAIE,EAAY,KAAK,QAAQ,kBACvC,EAAU,KAAK,IAAI,EAAGA,EAAY,KAAK,QAAQ,WAAW,OACvD,GAAI,KAAKF,GAAK,EAAIE,EAAYC,EAAe,KAAK,QAAQ,kBAAmB,CAChF,IAAMI,EAAYxD,EAAAA,QAAE,OAAOmC,EAAU,CAAE,QAASnC,EAAAA,QAAE,UAAW,CAAC,EACxDyD,EAAO,KAAK,IAAI,EAAGD,EAAYJ,CAAY,EACjD,EAAU,KAAK,IAAIK,EAAMN,EAAY,KAAK,QAAQ,WAAW,CACjE,CAEA,GAAI,KAAKF,GAAK,EAAIC,EAAY,KAAK,QAAQ,kBACvC,EAAU,KAAK,IAAI,EAAGA,EAAY,KAAK,QAAQ,WAAW,OACvD,GAAI,KAAKD,GAAK,EAAIC,EAAYG,EAAc,KAAK,QAAQ,kBAAmB,CAC/E,IAAMK,EAAW1D,EAAAA,QAAE,MAAMmC,EAAU,CAAE,QAASnC,EAAAA,QAAE,UAAW,CAAC,EACtD2D,EAAO,KAAK,IAAI,EAAGD,EAAWL,CAAW,EAC/C,EAAU,KAAK,IAAIM,EAAMT,EAAY,KAAK,QAAQ,WAAW,CACjE,CAEA,GAAII,IAAYJ,GAAaK,IAAYJ,EACrC,OAGJf,EAAO,SAAS,CACZ,KAAMkB,EACN,IAAKC,EACL,SAAU,SACd,CAAC,EAED,IAAMK,EAASN,EAAUJ,EACnBW,EAASN,EAAUJ,EAEzB,KAAKF,GAAK,GAAKW,EACf,KAAKX,GAAK,GAAKY,EAEf,KAAKC,GAAiBF,EAAQC,CAAM,EACpC,KAAKE,GAAgB,CACzB,CAKA,IAAU,CA2HN,IAAMC,EAAchE,EAAAA,QAAE,iBA1HD,GAAU,CAC3B,IAAMiE,EAAY,KAAK,QAAQ,SAEvBjE,EAAAA,QAAE,GAAGkE,EAAM,OAAQ,KAAK,QAAQ,MAAM,GACtClE,EAAAA,QAAE,GAAGkE,EAAM,cAAe,KAAK,QAAQ,MAAM,GAC7ClE,EAAAA,QAAE,QAAQkE,EAAM,OAAQ,KAAK,QAAQ,OAAQ,KAAK,IAAI,CAAC,CAAC,QAgBhE,GAZIA,EAAM,QACN,CAAC,KAAKxB,IACNuB,GACAjE,EAAAA,QAAE,WAAW,KAAK,KAAM,YAAY,IAKxC,KAAK8C,GAAU,KAAK,QAAQ,OACxB,KAAK,MAAM,CAAC,CAAC,KAAM,GAAS9C,EAAAA,QAAE,cAAc2B,EAAMuC,EAAM,aAAa,CAAC,EACtEA,EAAM,cAEN,CAAC,KAAKpB,IACN,MAAO,EAEf,EAEqB,GAAU,CAC3B,GAAI,CAAC,KAAK,MAAQ,CAAC,KAAKA,GACpB,OAGJ,IAAMqB,EAAc,KAAKlB,GACzB,KAAKA,IAAA,EAAO/C,EAAAA,YAAAA,CAAYgE,CAAK,EAC7B,IAAMN,EAASO,EACX,KAAKlB,GAAK,EAAIkB,EAAY,EAC1B,EACEN,EAASM,EACX,KAAKlB,GAAK,EAAIkB,EAAY,EAC1B,EAEJ,GAAI,CAAC,KAAK1B,GAAW,CACjB,KAAKA,GAAY,GACjB,KAAK2B,GAAmB,KAAK,KAC7B,KAAKC,GAAc,KAAK,MAAM,CAAC,CAAC,QAAQ,KAAKvB,EAAO,EACpD,KAAKwB,GAAgB,KAAKD,GAE1B7C,EAAA,QAAE,WAAW,KAAK,KAAM,CAAE,WAAY,EAAK,CAAC,EAG5C,IAAM+C,EAAY,CACd,KAAM,KAAKzB,GACX,KAAM,KAAK,KACX,GAAI,KAAK,KACT,SAAU,KAAKuB,GACf,SAAU,KAAKA,EACnB,EAIA,GAFArC,EAAqB,KAAK,KAAM,OAAQuC,CAAS,EAE7C,CAAC,KAAK,KACN,OAGA,KAAK,QAAQ,aACb/C,EAAA,QAAE,SAAS,KAAKsB,GAAS,KAAK,QAAQ,WAAW,CAEzD,CAEA,KAAKgB,GAAiBF,EAAQC,CAAM,EACpC,KAAKE,GAAgB,CACzB,EAEmB,GAAU,CACzB,GAAI,CAAC,KAAK,KACN,OAGJ,GAAI,CAAC,KAAKtB,GAAW,CACjB,KAAKK,GAAU,KACf,MACJ,CAEIoB,EAAM,OAAS,WACfA,EAAM,eAAe,EAGzB,IAAMM,EAAS,KAAK,KACdC,EAAc,KAAKL,GAEnBG,EAAY,CACd,KAAM,KAAKzB,GACX,KAAM0B,EACN,GAAIC,EACJ,SAAU,KAAKJ,GACf,SAAU,KAAKC,EACnB,EAEAtC,EAAqByC,EAAa,SAAUF,CAAS,EAEhD,KAAK,OAIN,KAAK,QAAQ,aACb/C,EAAA,QAAE,YAAY,KAAKsB,GAAS,KAAK,QAAQ,WAAW,EAGpD0B,IAAWC,EAMJ,KAAKH,KAAkB,KAAKD,IACnCrC,EAAqByC,EAAa,SAAUF,CAAS,GANrDvC,EAAqBwC,EAAQ,SAAUD,CAAS,EAE5C,KAAK,MACLvC,EAAqByC,EAAa,SAAUF,CAAS,GAMzD,KAAK,MACL,KAAKxB,GAAW,EAExB,CAE0E,EAE1E,KAAK,OACD,KAAK,KACL,+CACAiB,EACA,CAAE,SAAU,KAAKxB,EAAU,CAC/B,EAEA,KAAK,OAAO,KAAK,KAAM,0BAA6B,CAChDV,EAAU9B,EAAAA,QAAE,KAAK,KAAKwC,GAAW,KAAK,IAAI,EAAG,KAAK,QAAQ,MAAM,CACpE,CAAC,CACL,CAKA,IAAa,CACL,KAAKQ,KAAiB,MACtBZ,EAAO,qBAAqB,KAAKY,EAAY,EAG7C,KAAKP,IAAa,KAAK,MACvBjB,EAAA,QAAE,cAAc,KAAK,KAAM,YAAY,EAG3C,KAAK8C,GAAgB,KACrB,KAAKF,GAAmB,KACxB,KAAK3B,GAAY,GACjB,KAAKQ,GAAO,KACZ,KAAKD,GAAe,KACpB,KAAKqB,GAAc,KACnB,KAAKvB,GAAU,IACnB,CAKA,IAAkB,CAET,KAAK,MACL,KAAK,QAAQ,QACb,KAAKL,IACN,KAAKO,KAAiB,OAK1B,KAAKA,GAAeZ,EAAO,0BAA4B,CACnD,KAAKsC,GAAa,CACtB,CAAC,EACL,CAOA,GAAiB,EAAQ,EAAQ,CAC7B,IAAIC,EAAkB,KAAK,KAE3B,GAAI,KAAK,QAAQ,YAAa,CAC1B,IAAMC,EAAY5E,EAAAA,QAAE,KAAK,KAAK,QAAQ,WAAW,CAAC,CAC7C,OAAQ,GAAS2B,IAAS,KAAK,IAAI,CAAC,CACpC,OAAQ,GAAS,CACd,IAAMkD,EAAW,KAAK,YAAY,KAAKlD,CAAI,EAE3C,OAAOkD,EAASnC,KACXmC,EAAS,QAAQ,aAAeA,EAAS,MAAM,CAAC,CAAC,OAC1D,CAAC,EAEDD,EAAU,SACV,EAAkB5E,EAAAA,QAAE,UAChB,CAAC,KAAK,KAAM,GAAG4E,CAAS,EACxB,KAAK3B,GAAK,EACV,KAAKA,GAAK,EACV,CAAE,OAAQ,EAAK,CACnB,EAER,CAEA,IAAM6B,EAAkB,KAAK,YAAY,KAAKH,CAAe,EACvDI,EAAeD,EAAgB,MAAM,CAAC,CACvC,OAAQ,GAASnD,IAAS,KAAKmB,EAAO,EACrCkC,EAAchF,EAAAA,QAAE,UAClB+E,EACA,KAAK9B,GAAK,EACV,KAAKA,GAAK,EACV,CAAE,OAAQ,EAAK,CACnB,EAEA,GAAI+B,EACA,KAAKC,GACDD,EACA,KAAK/B,GAAK,EACV,KAAKA,GAAK,EACVW,EACAC,CACJ,OACG,GAAIc,IAAoB,KAAKP,GAChC5C,EAAA,QAAE,OAAOmD,EAAiB,KAAK7B,EAAO,OAEtC,OAGJ,IAAMoC,EAAWJ,EAAgB,MAAM,CAAC,CAAC,QAAQ,KAAKhC,EAAO,EAE7D,GAAI6B,IAAoB,KAAKP,GAAkB,CAC3C,IAAMe,EAAmB,KAAKf,GAExB,CAAE,UADiB,KAAK,YAAY,KAAKe,CACb,CAAC,CAAC,QAEpCzD,EAAY0D,EACRpF,EAAAA,QAAE,KAAKoF,EAAQ,KAAKtC,EAAO,EAC3B,CAAC,KAAKA,EAAO,CAAC,EAGlB,IAAMyB,EAAY,CACd,KAAM,KAAKzB,GACX,KAAMqC,EACN,GAAIR,EACJ,SAAU,KAAKL,GACf,UACJ,EAIA,GAFAtC,EAAqBmD,EAAkB,OAAQZ,CAAS,EAEpD,CAAC,KAAK,KACN,OAGJvC,EAAqB2C,EAAiB,UAAWJ,CAAS,CAC9D,MAAO,GAAI,KAAKD,KAAkBY,EAAU,CAExC,IAAMX,EAAY,CACd,KAAM,KAAKzB,GACX,KAAM6B,EACN,GAAIA,EACJ,SAAU,KAAKL,GACf,UACJ,EAEAtC,EAAqB2C,EAAiB,UAAWJ,CAAS,CAC9D,CAEK,KAAK,OAIV,KAAKD,GAAgBY,EACrB,KAAKd,GAAmBO,EAC5B,CAUA,GAAc,EAAa,EAAG,EAAG,EAAQ,EAAQ,CAC7C,IAAMU,EAAgBrF,EAAAA,QAAE,OAAOgF,EAAa,CAAE,OAAQ,EAAK,CAAC,EACtDM,EAActF,EAAAA,QAAE,KAAKgF,EAAa,CAAE,OAAQ,EAAK,CAAC,EAClDO,EAAevF,EAAAA,QAAE,OAAO,KAAK8C,GAAS,CAAE,OAAQ,EAAK,CAAC,EACtD0C,EAAY,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,KAAK,QAAQ,aAAa,CAAC,EACjEC,EAAa,GACbC,EAAa,GAEb9B,IACA,EAAaA,EAAS,EAClB4B,EACA,EAAIA,GAGR3B,IACA,EAAaA,EAAS,EAClB2B,EACA,EAAIA,GAGZ,IAAIG,EACJ,GAAI,KAAK,QAAQ,OAAS,KAAON,EAAc,IAAME,EAAa,EAE9D,EAASK,EADKN,EAAY,IAAMA,EAAY,OAASI,EAEjD,SACA,aACD,GAAI,KAAK,QAAQ,OAAS,KAAOL,EAAc,IAAME,EAAa,EAErE,EAASM,EADKP,EAAY,KAAOA,EAAY,MAAQG,EAEjD,SACA,YACD,CACH,IAAMK,EAAQR,EAAY,KAAOA,EAAY,MAAQG,EAC/CM,EAAQT,EAAY,IAAMA,EAAY,OAASI,EACrD,EAASG,EAAIC,GAASF,EAAIG,EACtB,SACA,OACR,CAEAvE,EAAA,QAAEmE,EAAO,CAACX,EAAa,KAAKlC,EAAO,CACvC,CACJ,GClgBA,EAAAR,EAAA,cAAA,CAAc,WAAYD,CAAQ,E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fr0st/ui-sortable",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "private": false,
5
5
  "description": "Drag-and-drop sortable lists for Frost UI with handles, connected containers, axis control, and automatic scrolling.",
6
6
  "keywords": [
@@ -56,12 +56,17 @@
56
56
  ],
57
57
  "devDependencies": {
58
58
  "@fr0st/eslint-config": "^6.0.1",
59
- "@fr0st/query": "^5.0.1",
60
- "@fr0st/ui": "^4.0.1",
61
- "@playwright/test": "^1.63.0",
62
- "eslint": "^10.11.0",
63
- "monocart-reporter": "^2.14.0",
64
- "vite": "^8.3.1"
59
+ "@fr0st/query": "^5.0.2",
60
+ "@fr0st/ui": "^4.0.3",
61
+ "@playwright/test": "^1.64.1",
62
+ "eslint": "^10.13.0",
63
+ "monocart-reporter": "2.14.0",
64
+ "vite": "^8.3.5"
65
+ },
66
+ "overrides": {
67
+ "monocart-reporter": {
68
+ "monocart-coverage-reports": "2.13.0"
69
+ }
65
70
  },
66
71
  "peerDependencies": {
67
72
  "@fr0st/query": "^5.0.0",
package/src/sortable.js CHANGED
@@ -56,15 +56,15 @@ export default class Sortable extends BaseComponent {
56
56
  };
57
57
 
58
58
  #currentIndex;
59
- #currentSortable;
59
+ #currentSortable = null;
60
60
  #dragging;
61
61
  #enabled;
62
62
  #initialCursorNodes = [];
63
- #pos;
64
- #scrollFrame;
63
+ #pos = null;
64
+ #scrollFrame = null;
65
65
  #selector;
66
66
  #startIndex;
67
- #target;
67
+ #target = null;
68
68
 
69
69
  /**
70
70
  * Creates a Sortable.
@@ -105,8 +105,6 @@ export default class Sortable extends BaseComponent {
105
105
  return;
106
106
  }
107
107
 
108
- $.removeEventDelegate(this.node, 'mousedown.ui.sortable touchstart.ui.sortable');
109
- $.removeEvent(this.node, 'receive.ui.sortable');
110
108
  resetCursor(this.#initialCursorNodes ?? $.find(this.#selector, this.node));
111
109
 
112
110
  if (this.#target && this.options.helperClass) {
@@ -193,7 +191,7 @@ export default class Sortable extends BaseComponent {
193
191
  * Attaches events for the Sortable.
194
192
  */
195
193
  #events() {
196
- const downEvent = (event) => {
194
+ const downHandler = (event) => {
197
195
  const cancelled = this.options.cancel &&
198
196
  (
199
197
  $.is(event.target, this.options.cancel) ||
@@ -219,7 +217,7 @@ export default class Sortable extends BaseComponent {
219
217
  }
220
218
  };
221
219
 
222
- const moveEvent = (event) => {
220
+ const moveHandler = (event) => {
223
221
  if (!this.node || !this.#target) {
224
222
  return;
225
223
  }
@@ -265,7 +263,7 @@ export default class Sortable extends BaseComponent {
265
263
  this.#scheduleScroll();
266
264
  };
267
265
 
268
- const upEvent = (event) => {
266
+ const upHandler = (event) => {
269
267
  if (!this.node) {
270
268
  return;
271
269
  }
@@ -315,16 +313,16 @@ export default class Sortable extends BaseComponent {
315
313
  }
316
314
  };
317
315
 
318
- const dragEvent = $.mouseDragFactory(downEvent, moveEvent, upEvent);
316
+ const dragHandler = $.mouseDragFactory(downHandler, moveHandler, upHandler);
319
317
 
320
- $.addEventDelegate(
318
+ this.listen(
321
319
  this.node,
322
320
  'mousedown.ui.sortable touchstart.ui.sortable',
323
- this.#selector,
324
- dragEvent,
321
+ dragHandler,
322
+ { delegate: this.#selector },
325
323
  );
326
324
 
327
- $.addEvent(this.node, 'receive.ui.sortable', () => {
325
+ this.listen(this.node, 'receive.ui.sortable', () => {
328
326
  setCursor($.find(this.#selector, this.node), this.options.cursor);
329
327
  });
330
328
  }
@@ -333,7 +331,7 @@ export default class Sortable extends BaseComponent {
333
331
  * Resets the active drag state.
334
332
  */
335
333
  #resetDrag() {
336
- if (this.#scrollFrame !== null && this.#scrollFrame !== undefined) {
334
+ if (this.#scrollFrame !== null) {
337
335
  window.cancelAnimationFrame(this.#scrollFrame);
338
336
  }
339
337
 
@@ -358,7 +356,7 @@ export default class Sortable extends BaseComponent {
358
356
  !this.node ||
359
357
  !this.options.scroll ||
360
358
  !this.#dragging ||
361
- this.#scrollFrame !== null && this.#scrollFrame !== undefined
359
+ this.#scrollFrame !== null
362
360
  ) {
363
361
  return;
364
362
  }