@vielzeug/dnd 3.0.0 → 26.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_dev.cjs +1 -1
- package/dist/_dev.cjs.map +1 -1
- package/dist/_dev.js +1 -5
- package/dist/_dev.js.map +1 -1
- package/dist/_shared.cjs +1 -1
- package/dist/_shared.cjs.map +1 -1
- package/dist/_shared.js +1 -22
- package/dist/_shared.js.map +1 -1
- package/dist/_touch.cjs +1 -1
- package/dist/_touch.cjs.map +1 -1
- package/dist/_touch.js +1 -150
- package/dist/_touch.js.map +1 -1
- package/dist/dnd.cjs +1 -1
- package/dist/dnd.cjs.map +1 -1
- package/dist/dnd.iife.js +1 -1
- package/dist/dnd.iife.js.map +1 -1
- package/dist/dnd.js +1 -1
- package/dist/dnd.js.map +1 -1
- package/dist/drop-zone.cjs +1 -1
- package/dist/drop-zone.cjs.map +1 -1
- package/dist/drop-zone.js +1 -115
- package/dist/drop-zone.js.map +1 -1
- package/dist/drop.js +1 -3
- package/dist/errors.cjs +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +0 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +1 -15
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -4
- package/dist/sortable.cjs +1 -1
- package/dist/sortable.cjs.map +1 -1
- package/dist/sortable.d.ts.map +1 -1
- package/dist/sortable.js +1 -417
- package/dist/sortable.js.map +1 -1
- package/package.json +7 -6
package/dist/drop-zone.js
CHANGED
|
@@ -1,116 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { createDisposable as e, resolveDisabled as t } from "./_shared.js";
|
|
3
|
-
import { DndError as n } from "./errors.js";
|
|
4
|
-
//#region src/drop-zone.ts
|
|
5
|
-
function r(e, t) {
|
|
6
|
-
return !t.length || t.some((t) => {
|
|
7
|
-
let n = t.trim().toLowerCase(), r = e.type.toLowerCase();
|
|
8
|
-
return n ? n.startsWith(".") ? e.name.toLowerCase().endsWith(n) : n.endsWith("/*") ? r.startsWith(n.slice(0, -1)) : r === n : !1;
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
function i(e, t) {
|
|
12
|
-
return !t.length || Array.from(e).some((e) => e.kind === "file" && t.some((t) => {
|
|
13
|
-
let n = t.trim();
|
|
14
|
-
return n.endsWith("/*") ? e.type.startsWith(n.slice(0, -1)) : n.startsWith(".") ? !0 : e.type === n;
|
|
15
|
-
}));
|
|
16
|
-
}
|
|
17
|
-
function a(e, t, n) {
|
|
18
|
-
let i = [], a = [];
|
|
19
|
-
for (let n of e) (r(n, t) ? i : a).push(n);
|
|
20
|
-
return n !== void 0 && i.length > n && a.push(...i.splice(n)), {
|
|
21
|
-
accepted: i,
|
|
22
|
-
rejected: a
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
function o(e) {
|
|
26
|
-
return e.map((e) => {
|
|
27
|
-
let t = e.trim().toLowerCase(), r = /^\.[a-z0-9][a-z0-9._+-]*$/.test(t), i = /^[a-z0-9!#$&^_.+-]+\/(?:\*|[a-z0-9!#$&^_.+-]+)$/.test(t);
|
|
28
|
-
if (!r && !i) throw new n(`Invalid accept pattern: "${e}"`);
|
|
29
|
-
return t;
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
function s(e, t, ...n) {
|
|
33
|
-
if (t) try {
|
|
34
|
-
t(...n);
|
|
35
|
-
} catch {
|
|
36
|
-
`${e}`;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
function c(r) {
|
|
40
|
-
let c = o(r.accept ?? []);
|
|
41
|
-
if (r.maxFiles !== void 0 && (!Number.isSafeInteger(r.maxFiles) || r.maxFiles < 0)) throw new n("maxFiles must be a non-negative safe integer");
|
|
42
|
-
let { dropEffect: l = "copy", element: u, maxFiles: d, onDrop: f, onDropRejected: p, onHoverChange: m, onValidatingChange: h } = r, g = 0, _ = !1, v = !1, y = /* @__PURE__ */ new Set(), b = (e) => {
|
|
43
|
-
v !== e && (v = e, s("onValidatingChange", h, e));
|
|
44
|
-
}, x = (e) => {
|
|
45
|
-
let t = g > 0 && _;
|
|
46
|
-
g = Math.max(0, e), g === 0 && (_ = !1);
|
|
47
|
-
let n = g > 0 && _;
|
|
48
|
-
n !== t && s("onHoverChange", m, n);
|
|
49
|
-
}, S = () => {
|
|
50
|
-
x(0);
|
|
51
|
-
}, C = e(() => {
|
|
52
|
-
for (let e of y) e.abort();
|
|
53
|
-
y.clear(), b(!1), S();
|
|
54
|
-
}), w = (e, t) => {
|
|
55
|
-
e.length > 0 && s("onDrop", f, [...e]), t.length > 0 && s("onDropRejected", p, [...t]);
|
|
56
|
-
}, T = (e, t) => {
|
|
57
|
-
e.length > 0 && (r.onPaste ? s("onPaste", r.onPaste, [...e]) : s("onDrop", f, [...e])), t.length > 0 && s("onDropRejected", p, [...t]);
|
|
58
|
-
}, E = (e, t) => {
|
|
59
|
-
let { accepted: n, rejected: i } = a(e, c, d), o = r.onValidate, s = o && n.length > 0 ? new AbortController() : null;
|
|
60
|
-
s && (y.add(s), b(!0));
|
|
61
|
-
let l = () => {
|
|
62
|
-
s && (y.delete(s), C.disposed || b(y.size > 0));
|
|
63
|
-
}, u;
|
|
64
|
-
try {
|
|
65
|
-
u = s && o ? o([...n], { signal: s.signal }) : !0;
|
|
66
|
-
} catch (e) {
|
|
67
|
-
u = Promise.reject(e);
|
|
68
|
-
}
|
|
69
|
-
Promise.resolve(u).then((e) => {
|
|
70
|
-
l(), !C.disposed && (e === !0 ? t(n, i) : t([], [...i, ...n]));
|
|
71
|
-
}, () => {
|
|
72
|
-
l(), !C.disposed && t([], [...i, ...n]);
|
|
73
|
-
});
|
|
74
|
-
};
|
|
75
|
-
return u.addEventListener("dragenter", (e) => {
|
|
76
|
-
if (!t(r.disabled)) {
|
|
77
|
-
if (e.preventDefault(), g === 0) {
|
|
78
|
-
let t = e.dataTransfer?.items;
|
|
79
|
-
_ = !c.length || !t?.length || i(t, c);
|
|
80
|
-
}
|
|
81
|
-
!_ && e.dataTransfer && (e.dataTransfer.dropEffect = "none"), x(g + 1);
|
|
82
|
-
}
|
|
83
|
-
}, { signal: C.disposalSignal }), u.addEventListener("dragover", (e) => {
|
|
84
|
-
t(r.disabled) || (e.preventDefault(), e.dataTransfer && (e.dataTransfer.dropEffect = _ ? l : "none"));
|
|
85
|
-
}, { signal: C.disposalSignal }), u.addEventListener("dragleave", (e) => {
|
|
86
|
-
x(g - 1);
|
|
87
|
-
}, { signal: C.disposalSignal }), u.addEventListener("drop", (e) => {
|
|
88
|
-
if (S(), t(r.disabled)) return;
|
|
89
|
-
e.preventDefault();
|
|
90
|
-
let n = e.dataTransfer?.files;
|
|
91
|
-
n && E(Array.from(n), w);
|
|
92
|
-
}, { signal: C.disposalSignal }), r.paste && u.addEventListener("paste", (e) => {
|
|
93
|
-
if (t(r.disabled)) return;
|
|
94
|
-
let n = e.clipboardData?.files;
|
|
95
|
-
n?.length && (e.preventDefault(), E(Array.from(n), T));
|
|
96
|
-
}, { signal: C.disposalSignal }), window.addEventListener("dragend", S, { signal: C.disposalSignal }), window.addEventListener("drop", S, { signal: C.disposalSignal }), {
|
|
97
|
-
get disposalSignal() {
|
|
98
|
-
return C.disposalSignal;
|
|
99
|
-
},
|
|
100
|
-
dispose: C.dispose,
|
|
101
|
-
get disposed() {
|
|
102
|
-
return C.disposed;
|
|
103
|
-
},
|
|
104
|
-
get hovered() {
|
|
105
|
-
return g > 0 && _;
|
|
106
|
-
},
|
|
107
|
-
[Symbol.dispose]: C[Symbol.dispose],
|
|
108
|
-
get validating() {
|
|
109
|
-
return v;
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
//#endregion
|
|
114
|
-
export { c as createDropZone, r as matchesAccept };
|
|
115
|
-
|
|
1
|
+
import"./_dev.js";import{createDisposable as e,resolveDisabled as t}from"./_shared.js";import{DndError as n}from"./errors.js";function matchesAccept(e,t){return!t.length||t.some(t=>{let n=t.trim().toLowerCase(),r=e.type.toLowerCase();return n?n.startsWith(`.`)?e.name.toLowerCase().endsWith(n):n.endsWith(`/*`)?r.startsWith(n.slice(0,-1)):r===n:!1})}function itemsMatchAccept(e,t){return!t.length||Array.from(e).some(e=>e.kind===`file`&&t.some(t=>{let n=t.trim();return n.endsWith(`/*`)?e.type.startsWith(n.slice(0,-1)):n.startsWith(`.`)?!0:e.type===n}))}function applyFileFilters(e,t,n){let r=[],i=[];for(let n of e)(matchesAccept(n,t)?r:i).push(n);return n!==void 0&&r.length>n&&i.push(...r.splice(n)),{accepted:r,rejected:i}}function normalizeAccept(e){return e.map(e=>{let t=e.trim().toLowerCase(),r=/^\.[a-z0-9][a-z0-9._+-]*$/.test(t),i=/^[a-z0-9!#$&^_.+-]+\/(?:\*|[a-z0-9!#$&^_.+-]+)$/.test(t);if(!r&&!i)throw new n(`Invalid accept pattern: "${e}"`);return t})}function notify(e,t,...n){if(t)try{t(...n)}catch{`${e}`}}function createDropZone(r){let i=normalizeAccept(r.accept??[]);if(r.maxFiles!==void 0&&(!Number.isSafeInteger(r.maxFiles)||r.maxFiles<0))throw new n(`maxFiles must be a non-negative safe integer`);let{dropEffect:a=`copy`,element:o,maxFiles:s,onDrop:c,onDropRejected:l,onHoverChange:u,onValidatingChange:d}=r,f=0,p=!1,m=!1,h=new Set,setValidating=e=>{m!==e&&(m=e,notify(`onValidatingChange`,d,e))},updateCounter=e=>{let t=f>0&&p;f=Math.max(0,e),f===0&&(p=!1);let n=f>0&&p;n!==t&¬ify(`onHoverChange`,u,n)},resetCounter=()=>{updateCounter(0)},g=e(()=>{for(let e of h)e.abort();h.clear(),setValidating(!1),resetCounter()}),settle=(e,t)=>{e.length>0&¬ify(`onDrop`,c,[...e]),t.length>0&¬ify(`onDropRejected`,l,[...t])},settleForPaste=(e,t)=>{e.length>0&&(r.onPaste?notify(`onPaste`,r.onPaste,[...e]):notify(`onDrop`,c,[...e])),t.length>0&¬ify(`onDropRejected`,l,[...t])},dispatchWithValidation=(e,t)=>{let{accepted:n,rejected:a}=applyFileFilters(e,i,s),o=r.onValidate,c=o&&n.length>0?new AbortController:null;c&&(h.add(c),setValidating(!0));let finishValidation=()=>{c&&(h.delete(c),g.disposed||setValidating(h.size>0))},l;try{l=c&&o?o([...n],{signal:c.signal}):!0}catch(e){l=Promise.reject(e)}Promise.resolve(l).then(e=>{finishValidation(),!g.disposed&&(e===!0?t(n,a):t([],[...a,...n]))},()=>{finishValidation(),!g.disposed&&t([],[...a,...n])})},handleDragEnter=e=>{if(!t(r.disabled)){if(e.preventDefault(),f===0){let t=e.dataTransfer?.items;p=!i.length||!t?.length||itemsMatchAccept(t,i)}!p&&e.dataTransfer&&(e.dataTransfer.dropEffect=`none`),updateCounter(f+1)}},handleDragOver=e=>{t(r.disabled)||(e.preventDefault(),e.dataTransfer&&(e.dataTransfer.dropEffect=p?a:`none`))},handleDragLeave=e=>{updateCounter(f-1)},handleDrop=e=>{if(resetCounter(),t(r.disabled))return;e.preventDefault();let n=e.dataTransfer?.files;n&&dispatchWithValidation(Array.from(n),settle)},handlePaste=e=>{if(t(r.disabled))return;let n=e.clipboardData?.files;n?.length&&(e.preventDefault(),dispatchWithValidation(Array.from(n),settleForPaste))};return o.addEventListener(`dragenter`,handleDragEnter,{signal:g.disposalSignal}),o.addEventListener(`dragover`,handleDragOver,{signal:g.disposalSignal}),o.addEventListener(`dragleave`,handleDragLeave,{signal:g.disposalSignal}),o.addEventListener(`drop`,handleDrop,{signal:g.disposalSignal}),r.paste&&o.addEventListener(`paste`,handlePaste,{signal:g.disposalSignal}),window.addEventListener(`dragend`,resetCounter,{signal:g.disposalSignal}),window.addEventListener(`drop`,resetCounter,{signal:g.disposalSignal}),{get disposalSignal(){return g.disposalSignal},dispose:g.dispose,get disposed(){return g.disposed},get hovered(){return f>0&&p},[Symbol.dispose]:g[Symbol.dispose],get validating(){return m}}}export{createDropZone,matchesAccept};
|
|
116
2
|
//# sourceMappingURL=drop-zone.js.map
|
package/dist/drop-zone.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drop-zone.js","names":[],"sources":["../src/drop-zone.ts"],"sourcesContent":["import { warn } from './_dev.js';\nimport { createDisposable, resolveDisabled } from './_shared.js';\nimport { DndError } from './errors.js';\nimport type { Disposable } from './types.js';\n\n// ─── Accept matching ─────────────────────────────────────────────────────────\n\n/**\n * Test whether a `File` matches an accept pattern list.\n *\n * Each pattern can be:\n * - A MIME type: `'image/png'`\n * - A MIME wildcard: `'image/*'`\n * - A file extension: `'.pdf'`\n *\n * An empty list accepts everything.\n */\nexport function matchesAccept(file: File, accept: readonly string[]): boolean {\n if (!accept.length) return true;\n\n return accept.some((pattern) => {\n const p = pattern.trim().toLowerCase();\n const type = file.type.toLowerCase();\n\n if (!p) return false;\n if (p.startsWith('.')) return file.name.toLowerCase().endsWith(p);\n if (p.endsWith('/*')) return type.startsWith(p.slice(0, -1));\n\n return type === p;\n });\n}\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface DropZoneOptions {\n /**\n * Accepted file types. Each entry may be:\n * - A MIME type: 'image/png'\n * - A MIME wildcard: 'image/*'\n * - A file extension: '.pdf'\n *\n * When empty the zone accepts everything.\n */\n accept?: readonly string[];\n /**\n * When `true`, all drag events are ignored and hover state does not change.\n *\n * Note: a disabled zone does not call `preventDefault` on drag or paste events,\n * so underlying elements (such as text editors) will still receive them.\n */\n disabled?: boolean;\n /**\n * The `dropEffect` to set on `dataTransfer` during `dragover`.\n * @default 'copy'\n */\n dropEffect?: DataTransfer['dropEffect'];\n /** The element to attach drag listeners to. */\n element: HTMLElement;\n /**\n * Maximum number of files accepted per drop. Files beyond this limit are\n * treated as rejected and forwarded to `onDropRejected`.\n *\n * When omitted there is no limit.\n */\n maxFiles?: number;\n /** Called when files are dropped or pasted (when `paste: true` and `onPaste` is omitted). Receives accepted files only. */\n onDrop?: (files: File[]) => void;\n /**\n * Called when dropped or pasted files are rejected by the `accept` filter, `maxFiles` limit, or `onValidate`.\n */\n onDropRejected?: (files: File[]) => void;\n /**\n * Called whenever hover state toggles.\n * Use this for drag-over styling.\n */\n onHoverChange?: (hovered: boolean) => void;\n /**\n * Called when files are pasted via the clipboard. Falls back to `onDrop` when omitted.\n * Only active when `paste: true`.\n */\n onPaste?: (files: File[]) => void;\n /**\n * Optional async file gating. Called after type/extension filtering, before `onDrop`.\n * Return (or resolve) `false` to move all type-accepted files to `onDropRejected`.\n *\n * Only receives type-accepted files (after `accept` and `maxFiles` filtering).\n * Files already rejected by the `accept` filter are forwarded to `onDropRejected`\n * unconditionally and are not passed to this function.\n *\n * While validation is in progress `zone.validating` is `true` and `onValidatingChange`\n * is called with `true`.\n *\n * @example\n * ```ts\n * onValidate: async (files, { signal }) => {\n * const ok = await checkServerQuota(files, { signal });\n * return ok;\n * }\n * ```\n */\n onValidate?: (files: File[], context: DropValidationContext) => boolean | Promise<boolean>;\n /**\n * Called whenever the async validation state changes.\n * Use this to drive loading spinners.\n *\n * @example\n * ```ts\n * onValidatingChange: (v) => { spinnerEl.hidden = !v; }\n * ```\n */\n onValidatingChange?: (validating: boolean) => void;\n /**\n * When `true`, a `paste` event listener is added to the drop-zone element. Pasted files run\n * through the same `accept`, `maxFiles`, and `onValidate` pipeline as dropped files.\n * @default false\n */\n paste?: boolean;\n}\n\nexport interface DropValidationContext {\n /** Aborts when the zone is disposed. Pass this to validation requests. */\n readonly signal: AbortSignal;\n}\n\nexport interface DropZone extends Disposable {\n /** Whether the pointer is currently dragging over the zone. */\n readonly hovered: boolean;\n /** `true` while an `onValidate` promise is pending. */\n readonly validating: boolean;\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\n/**\n * DataTransferItem does not expose file names, so extension patterns (for example\n * `.pdf`) cannot be validated during drag-over. We treat these as a permissive\n * pre-check and perform exact filtering in `handleDrop` when `File` objects exist.\n */\nfunction itemsMatchAccept(items: DataTransferItemList, accept: string[]): boolean {\n if (!accept.length) return true;\n\n return Array.from(items).some(\n (item) =>\n item.kind === 'file' &&\n accept.some((pattern) => {\n const p = pattern.trim();\n\n if (p.endsWith('/*')) return item.type.startsWith(p.slice(0, -1));\n\n if (p.startsWith('.')) return true; // extension cannot be checked from DataTransferItem\n\n return item.type === p;\n }),\n );\n}\n\n/**\n * Filter `files` through `accept` patterns and `maxFiles` limit.\n * Returns accepted and rejected arrays.\n */\nfunction applyFileFilters(\n files: File[],\n accept: string[],\n maxFiles: number | undefined,\n): { accepted: File[]; rejected: File[] } {\n const accepted: File[] = [];\n const rejected: File[] = [];\n\n for (const f of files) {\n (matchesAccept(f, accept) ? accepted : rejected).push(f);\n }\n\n if (maxFiles !== undefined && accepted.length > maxFiles) {\n rejected.push(...accepted.splice(maxFiles));\n }\n\n return { accepted, rejected };\n}\n\n// ─── createDropZone ───────────────────────────────────────────────────────────\n\nfunction normalizeAccept(patterns: readonly string[]): string[] {\n return patterns.map((pattern) => {\n const normalized = pattern.trim().toLowerCase();\n const extension = /^\\.[a-z0-9][a-z0-9._+-]*$/.test(normalized);\n const mime = /^[a-z0-9!#$&^_.+-]+\\/(?:\\*|[a-z0-9!#$&^_.+-]+)$/.test(normalized);\n\n if (!extension && !mime) throw new DndError(`Invalid accept pattern: \"${pattern}\"`);\n return normalized;\n });\n}\n\nfunction notify<Args extends unknown[]>(\n name: string,\n callback: ((...args: Args) => void) | undefined,\n ...args: Args\n): void {\n if (!callback) return;\n try {\n callback(...args);\n } catch {\n warn(`${name} callback failed; Dnd continued without interrupting internal state.`);\n }\n}\n\n/**\n * Attach drag-and-drop behaviour to a DOM element.\n *\n * Accepts files and provides hover state management with configurable MIME/extension filtering.\n * Calls `onDrop` only for accepted files and `onDropRejected` for filtered files.\n *\n * @example\n * ```ts\n * import { createDropZone } from '@vielzeug/dnd';\n *\n * using zone = createDropZone({\n * element: dropZoneEl,\n * accept: ['image/*', '.pdf'],\n * maxFiles: 5,\n * onDrop: (files) => { console.log('Dropped:', files); },\n * onHoverChange: (hovered) => {\n * dropZoneEl.classList.toggle('drag-over', hovered);\n * },\n * });\n * ```\n */\nexport function createDropZone(options: DropZoneOptions): DropZone {\n const accept = normalizeAccept(options.accept ?? []);\n if (options.maxFiles !== undefined && (!Number.isSafeInteger(options.maxFiles) || options.maxFiles < 0)) {\n throw new DndError('maxFiles must be a non-negative safe integer');\n }\n\n const { dropEffect = 'copy', element, maxFiles, onDrop, onDropRejected, onHoverChange, onValidatingChange } = options;\n\n let dragCounter = 0;\n // Whether the *current* drag's payload passes the accept filter.\n // Determined on the first dragenter and held for the duration of the drag.\n let dragAccepted = false;\n let validating = false;\n const validationControllers = new Set<AbortController>();\n\n const setValidating = (next: boolean): void => {\n if (validating === next) return;\n\n validating = next;\n notify('onValidatingChange', onValidatingChange, next);\n };\n\n const updateCounter = (next: number): void => {\n const wasHovered = dragCounter > 0 && dragAccepted;\n\n dragCounter = Math.max(0, next);\n\n // Reset acceptance state when the drag fully leaves so the next drag starts clean.\n if (dragCounter === 0) dragAccepted = false;\n\n const hovered = dragCounter > 0 && dragAccepted;\n\n if (hovered !== wasHovered) notify('onHoverChange', onHoverChange, hovered);\n };\n\n const resetCounter = (): void => {\n updateCounter(0);\n };\n\n const disposable = createDisposable(() => {\n for (const controller of validationControllers) controller.abort();\n\n validationControllers.clear();\n setValidating(false);\n resetCounter();\n });\n\n // Settle the final accepted/rejected split and fire callbacks.\n const settle = (acceptedFiles: File[], rejectedFiles: File[]): void => {\n if (acceptedFiles.length > 0) notify('onDrop', onDrop, [...acceptedFiles]);\n if (rejectedFiles.length > 0) notify('onDropRejected', onDropRejected, [...rejectedFiles]);\n };\n\n // Settle for paste events (which may use onPaste instead of onDrop).\n const settleForPaste = (acceptedFiles: File[], rejectedFiles: File[]): void => {\n if (acceptedFiles.length > 0) {\n if (options.onPaste) {\n notify('onPaste', options.onPaste, [...acceptedFiles]);\n } else {\n notify('onDrop', onDrop, [...acceptedFiles]);\n }\n }\n\n if (rejectedFiles.length > 0) notify('onDropRejected', onDropRejected, [...rejectedFiles]);\n };\n\n // Run accept/maxFiles filter, then async onValidate, then settle.\n const dispatchWithValidation = (rawFiles: File[], settleFn: (accepted: File[], rejected: File[]) => void): void => {\n const { accepted, rejected: rej } = applyFileFilters(rawFiles, accept, maxFiles);\n const onValidate = options.onValidate;\n const validationController = onValidate && accepted.length > 0 ? new AbortController() : null;\n\n if (validationController) {\n validationControllers.add(validationController);\n setValidating(true);\n }\n\n const finishValidation = (): void => {\n if (!validationController) return;\n\n validationControllers.delete(validationController);\n\n if (!disposable.disposed) setValidating(validationControllers.size > 0);\n };\n\n let validation: boolean | Promise<boolean>;\n\n try {\n validation =\n validationController && onValidate ? onValidate([...accepted], { signal: validationController.signal }) : true;\n } catch (error) {\n validation = Promise.reject(error);\n }\n\n void Promise.resolve(validation).then(\n (valid) => {\n finishValidation();\n\n if (disposable.disposed) return;\n\n if (valid === true) {\n settleFn(accepted, rej);\n } else {\n settleFn([], [...rej, ...accepted]);\n }\n },\n () => {\n finishValidation();\n\n if (disposable.disposed) return;\n\n settleFn([], [...rej, ...accepted]);\n },\n );\n };\n\n const handleDragEnter = (e: DragEvent): void => {\n if (resolveDisabled(options.disabled)) return;\n\n e.preventDefault();\n\n // Evaluate the filter once per drag (on first entry) — the payload is\n // constant for the lifetime of a drag operation.\n if (dragCounter === 0) {\n const items = e.dataTransfer?.items;\n\n dragAccepted = !accept.length || !items?.length || itemsMatchAccept(items, accept);\n }\n\n if (!dragAccepted && e.dataTransfer) {\n e.dataTransfer.dropEffect = 'none';\n }\n\n // Always increment so every dragenter is paired with its dragleave,\n // regardless of acceptance. This prevents counter under-runs.\n updateCounter(dragCounter + 1);\n };\n\n const handleDragOver = (e: DragEvent): void => {\n if (resolveDisabled(options.disabled)) return;\n\n e.preventDefault();\n\n if (e.dataTransfer) e.dataTransfer.dropEffect = dragAccepted ? dropEffect : 'none';\n };\n\n const handleDragLeave = (_e: DragEvent): void => {\n // Always decrement to balance the paired dragenter — disabling after enter\n // must not leave the counter permanently incremented.\n updateCounter(dragCounter - 1);\n };\n\n const handleDrop = (e: DragEvent): void => {\n // Reset counter first (idempotent at 0) so hover never sticks even when disabled.\n resetCounter();\n\n if (resolveDisabled(options.disabled)) return;\n\n e.preventDefault();\n\n const raw = e.dataTransfer?.files;\n\n if (!raw) return;\n\n dispatchWithValidation(Array.from(raw), settle);\n };\n\n const handlePaste = (e: ClipboardEvent): void => {\n if (resolveDisabled(options.disabled)) return;\n\n const clipFiles = e.clipboardData?.files;\n\n if (!clipFiles?.length) return;\n\n e.preventDefault();\n dispatchWithValidation(Array.from(clipFiles), settleForPaste);\n };\n\n element.addEventListener('dragenter', handleDragEnter, { signal: disposable.disposalSignal });\n element.addEventListener('dragover', handleDragOver, { signal: disposable.disposalSignal });\n element.addEventListener('dragleave', handleDragLeave, { signal: disposable.disposalSignal });\n element.addEventListener('drop', handleDrop, { signal: disposable.disposalSignal });\n\n if (options.paste) element.addEventListener('paste', handlePaste, { signal: disposable.disposalSignal });\n\n // These global listeners catch drags that end outside the zone.\n // The window 'drop' also fires for in-zone drops, but resetCounter() is idempotent at counter=0.\n window.addEventListener('dragend', resetCounter, { signal: disposable.disposalSignal });\n window.addEventListener('drop', resetCounter, { signal: disposable.disposalSignal });\n\n return {\n get disposalSignal() {\n return disposable.disposalSignal;\n },\n dispose: disposable.dispose,\n get disposed() {\n return disposable.disposed;\n },\n get hovered() {\n return dragCounter > 0 && dragAccepted;\n },\n [Symbol.dispose]: disposable[Symbol.dispose],\n get validating() {\n return validating;\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"drop-zone.js","names":[],"sources":["../src/drop-zone.ts"],"sourcesContent":["import { warn } from './_dev.js';\nimport { createDisposable, resolveDisabled } from './_shared.js';\nimport { DndError } from './errors.js';\nimport type { Disposable } from './types.js';\n\n// ─── Accept matching ─────────────────────────────────────────────────────────\n\n/**\n * Test whether a `File` matches an accept pattern list.\n *\n * Each pattern can be:\n * - A MIME type: `'image/png'`\n * - A MIME wildcard: `'image/*'`\n * - A file extension: `'.pdf'`\n *\n * An empty list accepts everything.\n */\nexport function matchesAccept(file: File, accept: readonly string[]): boolean {\n if (!accept.length) return true;\n\n return accept.some((pattern) => {\n const p = pattern.trim().toLowerCase();\n const type = file.type.toLowerCase();\n\n if (!p) return false;\n if (p.startsWith('.')) return file.name.toLowerCase().endsWith(p);\n if (p.endsWith('/*')) return type.startsWith(p.slice(0, -1));\n\n return type === p;\n });\n}\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface DropZoneOptions {\n /**\n * Accepted file types. Each entry may be:\n * - A MIME type: 'image/png'\n * - A MIME wildcard: 'image/*'\n * - A file extension: '.pdf'\n *\n * When empty the zone accepts everything.\n */\n accept?: readonly string[];\n /**\n * When `true`, all drag events are ignored and hover state does not change.\n *\n * Note: a disabled zone does not call `preventDefault` on drag or paste events,\n * so underlying elements (such as text editors) will still receive them.\n */\n disabled?: boolean;\n /**\n * The `dropEffect` to set on `dataTransfer` during `dragover`.\n * @default 'copy'\n */\n dropEffect?: DataTransfer['dropEffect'];\n /** The element to attach drag listeners to. */\n element: HTMLElement;\n /**\n * Maximum number of files accepted per drop. Files beyond this limit are\n * treated as rejected and forwarded to `onDropRejected`.\n *\n * When omitted there is no limit.\n */\n maxFiles?: number;\n /** Called when files are dropped or pasted (when `paste: true` and `onPaste` is omitted). Receives accepted files only. */\n onDrop?: (files: File[]) => void;\n /**\n * Called when dropped or pasted files are rejected by the `accept` filter, `maxFiles` limit, or `onValidate`.\n */\n onDropRejected?: (files: File[]) => void;\n /**\n * Called whenever hover state toggles.\n * Use this for drag-over styling.\n */\n onHoverChange?: (hovered: boolean) => void;\n /**\n * Called when files are pasted via the clipboard. Falls back to `onDrop` when omitted.\n * Only active when `paste: true`.\n */\n onPaste?: (files: File[]) => void;\n /**\n * Optional async file gating. Called after type/extension filtering, before `onDrop`.\n * Return (or resolve) `false` to move all type-accepted files to `onDropRejected`.\n *\n * Only receives type-accepted files (after `accept` and `maxFiles` filtering).\n * Files already rejected by the `accept` filter are forwarded to `onDropRejected`\n * unconditionally and are not passed to this function.\n *\n * While validation is in progress `zone.validating` is `true` and `onValidatingChange`\n * is called with `true`.\n *\n * @example\n * ```ts\n * onValidate: async (files, { signal }) => {\n * const ok = await checkServerQuota(files, { signal });\n * return ok;\n * }\n * ```\n */\n onValidate?: (files: File[], context: DropValidationContext) => boolean | Promise<boolean>;\n /**\n * Called whenever the async validation state changes.\n * Use this to drive loading spinners.\n *\n * @example\n * ```ts\n * onValidatingChange: (v) => { spinnerEl.hidden = !v; }\n * ```\n */\n onValidatingChange?: (validating: boolean) => void;\n /**\n * When `true`, a `paste` event listener is added to the drop-zone element. Pasted files run\n * through the same `accept`, `maxFiles`, and `onValidate` pipeline as dropped files.\n * @default false\n */\n paste?: boolean;\n}\n\nexport interface DropValidationContext {\n /** Aborts when the zone is disposed. Pass this to validation requests. */\n readonly signal: AbortSignal;\n}\n\nexport interface DropZone extends Disposable {\n /** Whether the pointer is currently dragging over the zone. */\n readonly hovered: boolean;\n /** `true` while an `onValidate` promise is pending. */\n readonly validating: boolean;\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\n/**\n * DataTransferItem does not expose file names, so extension patterns (for example\n * `.pdf`) cannot be validated during drag-over. We treat these as a permissive\n * pre-check and perform exact filtering in `handleDrop` when `File` objects exist.\n */\nfunction itemsMatchAccept(items: DataTransferItemList, accept: string[]): boolean {\n if (!accept.length) return true;\n\n return Array.from(items).some(\n (item) =>\n item.kind === 'file' &&\n accept.some((pattern) => {\n const p = pattern.trim();\n\n if (p.endsWith('/*')) return item.type.startsWith(p.slice(0, -1));\n\n if (p.startsWith('.')) return true; // extension cannot be checked from DataTransferItem\n\n return item.type === p;\n }),\n );\n}\n\n/**\n * Filter `files` through `accept` patterns and `maxFiles` limit.\n * Returns accepted and rejected arrays.\n */\nfunction applyFileFilters(\n files: File[],\n accept: string[],\n maxFiles: number | undefined,\n): { accepted: File[]; rejected: File[] } {\n const accepted: File[] = [];\n const rejected: File[] = [];\n\n for (const f of files) {\n (matchesAccept(f, accept) ? accepted : rejected).push(f);\n }\n\n if (maxFiles !== undefined && accepted.length > maxFiles) {\n rejected.push(...accepted.splice(maxFiles));\n }\n\n return { accepted, rejected };\n}\n\n// ─── createDropZone ───────────────────────────────────────────────────────────\n\nfunction normalizeAccept(patterns: readonly string[]): string[] {\n return patterns.map((pattern) => {\n const normalized = pattern.trim().toLowerCase();\n const extension = /^\\.[a-z0-9][a-z0-9._+-]*$/.test(normalized);\n const mime = /^[a-z0-9!#$&^_.+-]+\\/(?:\\*|[a-z0-9!#$&^_.+-]+)$/.test(normalized);\n\n if (!extension && !mime) throw new DndError(`Invalid accept pattern: \"${pattern}\"`);\n return normalized;\n });\n}\n\nfunction notify<Args extends unknown[]>(\n name: string,\n callback: ((...args: Args) => void) | undefined,\n ...args: Args\n): void {\n if (!callback) return;\n try {\n callback(...args);\n } catch {\n warn(`${name} callback failed; Dnd continued without interrupting internal state.`);\n }\n}\n\n/**\n * Attach drag-and-drop behaviour to a DOM element.\n *\n * Accepts files and provides hover state management with configurable MIME/extension filtering.\n * Calls `onDrop` only for accepted files and `onDropRejected` for filtered files.\n *\n * @example\n * ```ts\n * import { createDropZone } from '@vielzeug/dnd';\n *\n * using zone = createDropZone({\n * element: dropZoneEl,\n * accept: ['image/*', '.pdf'],\n * maxFiles: 5,\n * onDrop: (files) => { console.log('Dropped:', files); },\n * onHoverChange: (hovered) => {\n * dropZoneEl.classList.toggle('drag-over', hovered);\n * },\n * });\n * ```\n */\nexport function createDropZone(options: DropZoneOptions): DropZone {\n const accept = normalizeAccept(options.accept ?? []);\n if (options.maxFiles !== undefined && (!Number.isSafeInteger(options.maxFiles) || options.maxFiles < 0)) {\n throw new DndError('maxFiles must be a non-negative safe integer');\n }\n\n const { dropEffect = 'copy', element, maxFiles, onDrop, onDropRejected, onHoverChange, onValidatingChange } = options;\n\n let dragCounter = 0;\n // Whether the *current* drag's payload passes the accept filter.\n // Determined on the first dragenter and held for the duration of the drag.\n let dragAccepted = false;\n let validating = false;\n const validationControllers = new Set<AbortController>();\n\n const setValidating = (next: boolean): void => {\n if (validating === next) return;\n\n validating = next;\n notify('onValidatingChange', onValidatingChange, next);\n };\n\n const updateCounter = (next: number): void => {\n const wasHovered = dragCounter > 0 && dragAccepted;\n\n dragCounter = Math.max(0, next);\n\n // Reset acceptance state when the drag fully leaves so the next drag starts clean.\n if (dragCounter === 0) dragAccepted = false;\n\n const hovered = dragCounter > 0 && dragAccepted;\n\n if (hovered !== wasHovered) notify('onHoverChange', onHoverChange, hovered);\n };\n\n const resetCounter = (): void => {\n updateCounter(0);\n };\n\n const disposable = createDisposable(() => {\n for (const controller of validationControllers) controller.abort();\n\n validationControllers.clear();\n setValidating(false);\n resetCounter();\n });\n\n // Settle the final accepted/rejected split and fire callbacks.\n const settle = (acceptedFiles: File[], rejectedFiles: File[]): void => {\n if (acceptedFiles.length > 0) notify('onDrop', onDrop, [...acceptedFiles]);\n if (rejectedFiles.length > 0) notify('onDropRejected', onDropRejected, [...rejectedFiles]);\n };\n\n // Settle for paste events (which may use onPaste instead of onDrop).\n const settleForPaste = (acceptedFiles: File[], rejectedFiles: File[]): void => {\n if (acceptedFiles.length > 0) {\n if (options.onPaste) {\n notify('onPaste', options.onPaste, [...acceptedFiles]);\n } else {\n notify('onDrop', onDrop, [...acceptedFiles]);\n }\n }\n\n if (rejectedFiles.length > 0) notify('onDropRejected', onDropRejected, [...rejectedFiles]);\n };\n\n // Run accept/maxFiles filter, then async onValidate, then settle.\n const dispatchWithValidation = (rawFiles: File[], settleFn: (accepted: File[], rejected: File[]) => void): void => {\n const { accepted, rejected: rej } = applyFileFilters(rawFiles, accept, maxFiles);\n const onValidate = options.onValidate;\n const validationController = onValidate && accepted.length > 0 ? new AbortController() : null;\n\n if (validationController) {\n validationControllers.add(validationController);\n setValidating(true);\n }\n\n const finishValidation = (): void => {\n if (!validationController) return;\n\n validationControllers.delete(validationController);\n\n if (!disposable.disposed) setValidating(validationControllers.size > 0);\n };\n\n let validation: boolean | Promise<boolean>;\n\n try {\n validation =\n validationController && onValidate ? onValidate([...accepted], { signal: validationController.signal }) : true;\n } catch (error) {\n validation = Promise.reject(error);\n }\n\n void Promise.resolve(validation).then(\n (valid) => {\n finishValidation();\n\n if (disposable.disposed) return;\n\n if (valid === true) {\n settleFn(accepted, rej);\n } else {\n settleFn([], [...rej, ...accepted]);\n }\n },\n () => {\n finishValidation();\n\n if (disposable.disposed) return;\n\n settleFn([], [...rej, ...accepted]);\n },\n );\n };\n\n const handleDragEnter = (e: DragEvent): void => {\n if (resolveDisabled(options.disabled)) return;\n\n e.preventDefault();\n\n // Evaluate the filter once per drag (on first entry) — the payload is\n // constant for the lifetime of a drag operation.\n if (dragCounter === 0) {\n const items = e.dataTransfer?.items;\n\n dragAccepted = !accept.length || !items?.length || itemsMatchAccept(items, accept);\n }\n\n if (!dragAccepted && e.dataTransfer) {\n e.dataTransfer.dropEffect = 'none';\n }\n\n // Always increment so every dragenter is paired with its dragleave,\n // regardless of acceptance. This prevents counter under-runs.\n updateCounter(dragCounter + 1);\n };\n\n const handleDragOver = (e: DragEvent): void => {\n if (resolveDisabled(options.disabled)) return;\n\n e.preventDefault();\n\n if (e.dataTransfer) e.dataTransfer.dropEffect = dragAccepted ? dropEffect : 'none';\n };\n\n const handleDragLeave = (_e: DragEvent): void => {\n // Always decrement to balance the paired dragenter — disabling after enter\n // must not leave the counter permanently incremented.\n updateCounter(dragCounter - 1);\n };\n\n const handleDrop = (e: DragEvent): void => {\n // Reset counter first (idempotent at 0) so hover never sticks even when disabled.\n resetCounter();\n\n if (resolveDisabled(options.disabled)) return;\n\n e.preventDefault();\n\n const raw = e.dataTransfer?.files;\n\n if (!raw) return;\n\n dispatchWithValidation(Array.from(raw), settle);\n };\n\n const handlePaste = (e: ClipboardEvent): void => {\n if (resolveDisabled(options.disabled)) return;\n\n const clipFiles = e.clipboardData?.files;\n\n if (!clipFiles?.length) return;\n\n e.preventDefault();\n dispatchWithValidation(Array.from(clipFiles), settleForPaste);\n };\n\n element.addEventListener('dragenter', handleDragEnter, { signal: disposable.disposalSignal });\n element.addEventListener('dragover', handleDragOver, { signal: disposable.disposalSignal });\n element.addEventListener('dragleave', handleDragLeave, { signal: disposable.disposalSignal });\n element.addEventListener('drop', handleDrop, { signal: disposable.disposalSignal });\n\n if (options.paste) element.addEventListener('paste', handlePaste, { signal: disposable.disposalSignal });\n\n // These global listeners catch drags that end outside the zone.\n // The window 'drop' also fires for in-zone drops, but resetCounter() is idempotent at counter=0.\n window.addEventListener('dragend', resetCounter, { signal: disposable.disposalSignal });\n window.addEventListener('drop', resetCounter, { signal: disposable.disposalSignal });\n\n return {\n get disposalSignal() {\n return disposable.disposalSignal;\n },\n dispose: disposable.dispose,\n get disposed() {\n return disposable.disposed;\n },\n get hovered() {\n return dragCounter > 0 && dragAccepted;\n },\n [Symbol.dispose]: disposable[Symbol.dispose],\n get validating() {\n return validating;\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/drop.js
CHANGED
|
@@ -1,3 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { createDropZone as t, matchesAccept as n } from "./drop-zone.js";
|
|
3
|
-
export { e as DndError, t as createDropZone, n as matchesAccept };
|
|
1
|
+
import{DndError as e}from"./errors.js";import{createDropZone as t,matchesAccept as n}from"./drop-zone.js";export{e as DndError,t as createDropZone,n as matchesAccept};
|
package/dist/errors.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var DndError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},DndScopeError=class extends DndError{constructor(e=`Invalid scope — use createSortableScope() to create scopes.`){super(e)}};exports.DndError=DndError,exports.DndScopeError=DndScopeError;
|
|
2
2
|
//# sourceMappingURL=errors.cjs.map
|
package/dist/errors.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all dnd errors. Use `instanceof DndError` to catch any dnd-originated error. */\nexport class DndError extends Error {\n
|
|
1
|
+
{"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all dnd errors. Use `instanceof DndError` to catch any dnd-originated error. */\nexport class DndError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a sortable action is called with an invalid scope not created by `createSortableScope()`. */\nexport class DndScopeError extends DndError {\n constructor(message = 'Invalid scope — use createSortableScope() to create scopes.') {\n super(message);\n }\n}\n"],"mappings":"AACA,IAAa,SAAb,cAA8B,KAAM,CAClC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAGa,cAAb,cAAmC,QAAS,CAC1C,YAAY,EAAU,8DAA+D,CACnF,MAAM,CAAO,CACf,CACF"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/** Base class for all dnd errors. Use `instanceof DndError` to catch any dnd-originated error. */
|
|
2
2
|
export declare class DndError extends Error {
|
|
3
|
-
protected static readonly errorName: string;
|
|
4
3
|
constructor(message: string, opts?: ErrorOptions);
|
|
5
4
|
}
|
|
6
5
|
/** Thrown when a sortable action is called with an invalid scope not created by `createSortableScope()`. */
|
|
7
6
|
export declare class DndScopeError extends DndError {
|
|
8
|
-
protected static readonly errorName = "DndScopeError";
|
|
9
7
|
constructor(message?: string);
|
|
10
8
|
}
|
|
11
9
|
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,qBAAa,QAAS,SAAQ,KAAK;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,qBAAa,QAAS,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;CAKjD;AAED,4GAA4G;AAC5G,qBAAa,aAAc,SAAQ,QAAQ;gBAC7B,OAAO,SAAgE;CAGpF"}
|
package/dist/errors.js
CHANGED
|
@@ -1,16 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
var e = class extends Error {
|
|
3
|
-
static errorName = "DndError";
|
|
4
|
-
constructor(e, t) {
|
|
5
|
-
super(e, t), this.name = new.target.errorName, Object.setPrototypeOf(this, new.target.prototype);
|
|
6
|
-
}
|
|
7
|
-
}, t = class extends e {
|
|
8
|
-
static errorName = "DndScopeError";
|
|
9
|
-
constructor(e = "Invalid scope — use createSortableScope() to create scopes.") {
|
|
10
|
-
super(e);
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
//#endregion
|
|
14
|
-
export { e as DndError, t as DndScopeError };
|
|
15
|
-
|
|
1
|
+
var DndError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},DndScopeError=class extends DndError{constructor(e=`Invalid scope — use createSortableScope() to create scopes.`){super(e)}};export{DndError,DndScopeError};
|
|
16
2
|
//# sourceMappingURL=errors.js.map
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all dnd errors. Use `instanceof DndError` to catch any dnd-originated error. */\nexport class DndError extends Error {\n
|
|
1
|
+
{"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all dnd errors. Use `instanceof DndError` to catch any dnd-originated error. */\nexport class DndError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when a sortable action is called with an invalid scope not created by `createSortableScope()`. */\nexport class DndScopeError extends DndError {\n constructor(message = 'Invalid scope — use createSortableScope() to create scopes.') {\n super(message);\n }\n}\n"],"mappings":"AACA,IAAa,SAAb,cAA8B,KAAM,CAClC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAGa,cAAb,cAAmC,QAAS,CAC1C,YAAY,EAAU,8DAA+D,CACnF,MAAM,CAAO,CACf,CACF"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACtD,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { createDropZone as n, matchesAccept as r } from "./drop-zone.js";
|
|
3
|
-
import { applyReorder as i, createSortable as a, createSortableScope as o } from "./sortable.js";
|
|
4
|
-
export { e as DndError, t as DndScopeError, i as applyReorder, n as createDropZone, a as createSortable, o as createSortableScope, r as matchesAccept };
|
|
1
|
+
import{DndError as e,DndScopeError as t}from"./errors.js";import{createDropZone as n,matchesAccept as r}from"./drop-zone.js";import{applyReorder as i,createSortable as a,createSortableScope as o}from"./sortable.js";export{e as DndError,t as DndScopeError,i as applyReorder,n as createDropZone,a as createSortable,o as createSortableScope,r as matchesAccept};
|
package/dist/sortable.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require("./_dev.cjs");const e=require("./_shared.cjs"),t=require("./errors.cjs"),n=require("./_touch.cjs");var r=Symbol(`SortableScope`),i=`data-dnd-handle`,a=`data-dnd-item`,o=new WeakMap,s={container:!0,edgeThreshold:32,speed:18,viewport:!1};function c(e){let n=o.get(e);if(!n)throw new t.DndScopeError;if(e.disposed)throw new t.DndScopeError(`Cannot register a sortable with a disposed scope.`);return n}function l(e){if(e===!1)return null;if(e===!0||e===void 0)return s;if(!Number.isFinite(e.edgeThreshold??32)||(e.edgeThreshold??32)<0||!Number.isFinite(e.speed??18)||(e.speed??18)<=0)throw new t.DndError(`Auto-scroll edgeThreshold must be non-negative and speed must be positive`);return{container:e.container??!0,edgeThreshold:e.edgeThreshold??32,speed:e.speed??18,viewport:e.viewport??!1}}function u(e,t){return t.length!==e.length||t.some((t,n)=>t!==e[n])}function d(e){return e.__dndTouch===!0}function f(e){return Object.freeze([...e])}function p(e,t,...n){if(t)try{t(...n)}catch{`${e}`}}function m(e){typeof requestAnimationFrame==`function`&&(e.hideFrame=requestAnimationFrame(()=>{e.hideFrame=null,e.draggedEl.style.display=`none`}))}function h(e){e.hideFrame!==null&&(cancelAnimationFrame(e.hideFrame),e.hideFrame=null)}function g(e){h(e),e.draggedEl.style.display=e.originalDisplay,e.draggedEl.removeAttribute(`data-dragging`)}function _(e,t){e.initialOrders.has(t)||e.initialOrders.set(t,t.getOrderedIds())}function v(e){let t=e.target;return[...e.initialOrders].flatMap(([n,r])=>{let i=r.filter(t=>t!==e.draggedId);if(n===t&&e.placeholder.parentElement===n.element){let t=[...n.element.children],r=t.indexOf(e.placeholder),a=n.getOrderedItems().filter(n=>n!==e.draggedEl&&t.indexOf(n)<r).length;i.splice(a,0,e.draggedId)}return u(r,i)?[{after:i,before:r,handle:n}]:[]})}function y(e,t){let n=e.active;n&&(g(n),n.originalParent.insertBefore(n.draggedEl,n.originalNextSibling?.parentNode===n.originalParent?n.originalNextSibling:null),n.placeholder.remove(),e.active=null,n.source.notifyDragEnd(n.draggedId,t),n.source.notifyInteraction({index:n.source.getOrderedIds().indexOf(n.draggedId),itemId:n.draggedId,total:n.source.getOrderedIds().length,type:`cancel`}))}function b(e,t){let n=e.active;if(!n)return;let r=n.target,i=n.placeholder.parentElement,a=v(n);for(let{after:e,before:t,handle:n}of a)n.notifyBeforeReorder(f(t),f(e));g(n),r&&e.handles.has(r)&&i?i.insertBefore(n.draggedEl,n.placeholder):n.originalParent.insertBefore(n.draggedEl,n.originalNextSibling?.parentNode===n.originalParent?n.originalNextSibling:null),n.placeholder.remove(),e.active=null,n.source.notifyDragEnd(n.draggedId,t);let o=[];for(let[t,r]of n.initialOrders){if(!e.handles.has(t))continue;let n=t.getOrderedIds();u(r,n)&&o.push({after:n,before:r,handle:t})}if(r&&r!==n.source){let t=o.find(e=>e.handle===n.source),i=o.find(e=>e.handle===r);if(t&&i){e.commitMove({itemId:n.draggedId,source:n.source.element,sourceBeforeIds:t.before,sourceIds:t.after,target:r.element,targetBeforeIds:i.before,targetIds:i.after});let a=i.after.indexOf(n.draggedId),o=i.after.length;n.source.notifyInteraction({index:a,itemId:n.draggedId,total:o,type:`drop`}),r.notifyInteraction({index:a,itemId:n.draggedId,total:o,type:`drop`})}return}for(let{after:e,before:t,handle:r}of o)r.commitReorder({after:e,before:t,item:n.draggedId});let s=o.find(e=>e.handle===n.source),c=s?s.after:n.source.getOrderedIds(),l=c.indexOf(n.draggedId);n.source.notifyInteraction({index:l,itemId:n.draggedId,total:c.length,type:`drop`})}function x(e,t,n){if(!e.active)return;let{active:r}=e;n||!t.dataTransfer||t.dataTransfer.dropEffect===`none`||!r.target||!e.handles.has(r.target)||r.source.isDisabled()||r.target.isDisabled()?y(e,t):b(e,t)}function S(e,t,n,r){if(!r)return;let{container:i,edgeThreshold:a,speed:o,viewport:s}=r,c=t.getBoundingClientRect();if(n===`vertical`){i&&e.clientY<c.top+a?t.scrollTop-=o:i&&e.clientY>c.bottom-a&&(t.scrollTop+=o),s&&e.clientY<a?window.scrollBy({left:0,top:-o}):s&&e.clientY>window.innerHeight-a&&window.scrollBy({left:0,top:o});return}i&&e.clientX<c.left+a?t.scrollLeft-=o:i&&e.clientX>c.right-a&&(t.scrollLeft+=o),s&&e.clientX<a?window.scrollBy({left:-o,top:0}):s&&e.clientX>window.innerWidth-a&&window.scrollBy({left:o,top:0})}function C(e,t,n,r){let i=e.indexOf(t);if(i<0)return null;let a=r===`vertical`?n===`ArrowDown`:n===`ArrowRight`,o=r===`vertical`?n===`ArrowUp`:n===`ArrowLeft`,s;if(a)s=Math.min(e.length-1,i+1);else if(o)s=Math.max(0,i-1);else if(n===`Home`)s=0;else if(n===`End`)s=e.length-1;else return null;return s===i?null:s}function w(t={}){let i={active:null,commitMove(e){p(`onMove`,t.onMove,Object.freeze({...e,sourceBeforeIds:f(e.sourceBeforeIds),sourceIds:f(e.sourceIds),targetBeforeIds:f(e.targetBeforeIds),targetIds:f(e.targetIds)}))},disposables:new Set,handles:new Set,touch:null},a=e.createDisposable(()=>{i.touch?.dispose();for(let e of[...i.disposables])e();i.disposables.clear(),i.handles.clear()}),s={get disposalSignal(){return a.disposalSignal},dispose:a.dispose,get disposed(){return a.disposed},get isDragging(){return i.active!==null},[r]:!0,[Symbol.dispose]:a[Symbol.dispose]};return o.set(s,i),t.touch&&(i.touch=n.createScopeTouchController(t.touch===!0?{}:t.touch,e=>{if(i.active)return null;for(let t of i.handles){let n=t.resolveTouchTarget(e);if(n)return n}return null})),s}function T(n){let{autoScroll:r=!0,axis:o=`vertical`,element:s,getKey:u,handle:h,keyboard:g=!0,placeholderClass:v=`dnd-placeholder`,scope:y=w()}=n;if(o!==`vertical`&&o!==`horizontal`)throw new t.DndError(`axis must be "vertical" or "horizontal"`);let b=h?.trim()||null;if((h===void 0||b)&&b)try{s.querySelector(b)}catch(e){throw new t.DndError(`Invalid handle selector: "${h}"`,{cause:e})}let T=l(r),E=c(y);if([...E.handles].some(e=>e.element===s))throw new t.DndError(`A sortable is already registered for this element in the selected scope.`);let D=()=>(n.items?n.items():Array.from(s.children)).filter(e=>e.parentElement===s&&e.hasAttribute(a)),O=()=>D().map(e=>u(e)),k=new Map,A=s.getAttribute(`role`),j=e=>{let t=k.get(e);if(t)return t;let n={dataDndHandle:e.getAttribute(i),dataDndItem:e.getAttribute(a),draggable:e.getAttribute(`draggable`),role:e.getAttribute(`role`),tabIndex:e.getAttribute(`tabindex`),touchAction:e.style.touchAction};return k.set(e,n),n},M=(e,t,n)=>{n===null?e.removeAttribute(t):e.setAttribute(t,n)},N=(e=D())=>{e.forEach(e=>{let t=j(e);t.role===null&&e.setAttribute(`role`,`listitem`),t.tabIndex===null&&(e.tabIndex=0),h===void 0?(e.setAttribute(`draggable`,`true`),E.touch&&(e.style.touchAction=`none`)):b&&e.querySelectorAll(b).forEach(e=>{j(e),e.setAttribute(i,``),e.setAttribute(`draggable`,`true`),E.touch&&(e.style.touchAction=`none`)})})},P=()=>{let e=new Set,t=n.items?n.items():Array.from(s.children),r=t.filter(e=>e instanceof HTMLElement&&e.parentElement===s),i=[];r.length,t.length;for(let t of r)try{let n=u(t);if(n){if(e.has(n)){`${n}`;continue}e.add(n),i.push(t)}}catch(e){`${String(e)}`}F();for(let e of i)j(e),e.setAttribute(a,``);N(i)},F=()=>{for(let[e,t]of k)M(e,i,t.dataDndHandle),M(e,a,t.dataDndItem),M(e,`draggable`,t.draggable),M(e,`role`,t.role),M(e,`tabindex`,t.tabIndex),e.style.touchAction=t.touchAction;k.clear()},I=e=>{let t=document.createElement(`div`);return t.className=v,t.setAttribute(`aria-hidden`,`true`),o===`horizontal`?t.style.width=`${e.offsetWidth}px`:t.style.height=`${e.offsetHeight}px`,t},L={commitReorder:e=>p(`onReorder`,n.onReorder,Object.freeze({after:f(e.after),before:f(e.before),item:e.item})),element:s,getOrderedIds:O,getOrderedItems:D,isDisabled:()=>e.resolveDisabled(n.disabled),notifyBeforeReorder:(e,t)=>p(`onBeforeReorder`,n.onBeforeReorder,e,t),notifyDragEnd:(e,t)=>p(`onDragEnd`,n.onDragEnd,e,t),notifyDragStart:(e,t)=>p(`onDragStart`,n.onDragStart,e,t),notifyInteraction:e=>p(`onInteraction`,n.onInteraction,Object.freeze(e)),resolveTouchTarget:t=>{if(e.resolveDisabled(n.disabled)||!s.contains(t))return null;let r=t.closest(`[${a}]`);if(!r||!D().includes(r))return null;if(h===void 0)return r;if(!b)return null;let i=t.closest(b);return i&&r.contains(i)?i:null}},R=e=>{if(E.active||L.isDisabled())return;let t=e.target,r=t.closest(`[${a}]`);if(!r||!D().includes(r))return;if(h!==void 0){let e=b?t.closest(b):null;if(!e||!r.contains(e))return}let i=r.parentElement;if(!i)return;let o=I(r),s=r.nextSibling,c=u(r),l=new Map;l.set(L,L.getOrderedIds()),r.setAttribute(`data-dragging`,``),i.insertBefore(o,s);let f={draggedEl:r,draggedId:c,hideFrame:null,initialOrders:l,originalDisplay:r.style.display,originalNextSibling:s,originalParent:i,placeholder:o,source:L,target:L};if((!d(e)||e.__dndTouchPreview)&&m(f),E.active=f,e.dataTransfer)try{if(e.dataTransfer.effectAllowed=`move`,e.dataTransfer.setData(`text/plain`,c),n.dragImage){let t=typeof n.dragImage==`function`?n.dragImage(c,r,e):n.dragImage,[i,a]=n.dragImageOffset??[0,0];t&&e.dataTransfer.setDragImage(t,i,a)}}catch(e){`${e instanceof Error?e.message:String(e)}`}L.notifyDragStart(f.draggedId,e),L.notifyInteraction({index:L.getOrderedIds().indexOf(c),itemId:c,total:L.getOrderedIds().length,type:`pickup`})},z=e=>{let t=E.active;if(!t||t.source.isDisabled()||L.isDisabled())return;e.preventDefault(),S(e,s,o,T),_(t,L);let{draggedEl:n,placeholder:r}=t,i=e.target.closest(`[${a}]`);if(i&&!D().includes(i))return;if(!i){r.parentElement!==s&&s.appendChild(r),t.target=L;return}if(i===n||i===r)return;let c=i.getBoundingClientRect(),l=o===`vertical`?e.clientY>=c.top+c.height/2:e.clientX>=c.left+c.width/2;s.insertBefore(r,l?i.nextSibling:i),t.target=L},B=e=>{let t=E.active;t&&(t.source.isDisabled()||L.isDisabled()||(e.preventDefault(),t.target=L))},V=e=>{E.active?.source===L&&x(E,e,!1)},H=e=>{if(!g||L.isDisabled())return;let t=e.target,n=t?.closest(`[${a}]`);if(!t||!n||!D().includes(n))return;let r=t.closest(`input, textarea, select, button, a[href], [contenteditable]:not([contenteditable="false"]), [role="button"], [role="link"]`),i=b?t.closest(b):null;if(r&&(!i||!n.contains(i)))return;let c=D(),l=c.indexOf(n),d=C(c,n,e.key,o);if(d===null)return;let p=c[d];if(!p)return;let m=c.map(u),h=[...c];h.splice(l,1),h.splice(d,0,n);let _=h.map(u),v=u(n);e.preventDefault(),L.notifyBeforeReorder(f(m),f(_)),s.insertBefore(n,d>l?p.nextSibling:p),n.focus(),L.commitReorder({after:_,before:m,item:v}),L.notifyInteraction({index:d,itemId:v,previousIndex:l,total:_.length,type:`move`})};P();let U,W=e.createDisposable(()=>{E.disposables.delete(W.dispose),E.active&&(E.active.source===L||E.active.target===L)&&!E.touch?.cancel()&&x(E,new Event(`dragend`),!0),U?.(),E.handles.delete(L),M(s,`role`,A),F()});return E.handles.add(L),U=E.touch?.register(s),A===null&&s.setAttribute(`role`,`list`),s.addEventListener(`dragstart`,R,{signal:W.disposalSignal}),s.addEventListener(`dragover`,z,{signal:W.disposalSignal}),s.addEventListener(`drop`,B,{signal:W.disposalSignal}),s.addEventListener(`dragend`,V,{signal:W.disposalSignal}),s.addEventListener(`keydown`,H,{signal:W.disposalSignal}),E.disposables.add(W.dispose),{get disposalSignal(){return W.disposalSignal},dispose:W.dispose,get disposed(){return W.disposed},get isDragging(){return E.active?.source===L},[Symbol.dispose]:W[Symbol.dispose],refresh:()=>{P()}}}function E(e,n,r){let i=new Map;for(let n of e){let e=r(n);if(i.has(e))throw new t.DndError(`Duplicate item key: "${e}"`);i.set(e,n)}let a=[];for(let e of n){if(!i.has(e))continue;let t=i.get(e);a.push(t),i.delete(e)}for(let e of i.values())a.push(e);return a}exports.DndError=t.DndError,exports.DndScopeError=t.DndScopeError,exports.applyReorder=E,exports.createSortable=T,exports.createSortableScope=w;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require("./_dev.cjs");const e=require("./_shared.cjs"),t=require("./errors.cjs"),n=require("./_touch.cjs");let r=require("@vielzeug/keymap");var i=Symbol(`SortableScope`),a=`data-dnd-handle`,o=`data-dnd-item`,s=new WeakMap,c={container:!0,edgeThreshold:32,speed:18,viewport:!1};function getSortableScopeState(e){let n=s.get(e);if(!n)throw new t.DndScopeError;if(e.disposed)throw new t.DndScopeError(`Cannot register a sortable with a disposed scope.`);return n}function resolveAutoScrollOptions(e){if(e===!1)return null;if(e===!0||e===void 0)return c;if(!Number.isFinite(e.edgeThreshold??32)||(e.edgeThreshold??32)<0||!Number.isFinite(e.speed??18)||(e.speed??18)<=0)throw new t.DndError(`Auto-scroll edgeThreshold must be non-negative and speed must be positive`);return{container:e.container??!0,edgeThreshold:e.edgeThreshold??32,speed:e.speed??18,viewport:e.viewport??!1}}function hasOrderChanged(e,t){return t.length!==e.length||t.some((t,n)=>t!==e[n])}function isTouchDragEvent(e){return e.__dndTouch===!0}function immutableIds(e){return Object.freeze([...e])}function notify(e,t,...n){if(t)try{t(...n)}catch{`${e}`}}function scheduleHide(e){typeof requestAnimationFrame==`function`&&(e.hideFrame=requestAnimationFrame(()=>{e.hideFrame=null,e.draggedEl.style.display=`none`}))}function cancelHide(e){e.hideFrame!==null&&(cancelAnimationFrame(e.hideFrame),e.hideFrame=null)}function restoreSessionElement(e){cancelHide(e),e.draggedEl.style.display=e.originalDisplay,e.draggedEl.removeAttribute(`data-dragging`)}function snapshotOrder(e,t){e.initialOrders.has(t)||e.initialOrders.set(t,t.getOrderedIds())}function projectedChanges(e){let t=e.target;return[...e.initialOrders].flatMap(([n,r])=>{let i=r.filter(t=>t!==e.draggedId);if(n===t&&e.placeholder.parentElement===n.element){let t=[...n.element.children],r=t.indexOf(e.placeholder),a=n.getOrderedItems().filter(n=>n!==e.draggedEl&&t.indexOf(n)<r).length;i.splice(a,0,e.draggedId)}return hasOrderChanged(r,i)?[{after:i,before:r,handle:n}]:[]})}function cancelSession(e,t){let n=e.active;n&&(restoreSessionElement(n),n.originalParent.insertBefore(n.draggedEl,n.originalNextSibling?.parentNode===n.originalParent?n.originalNextSibling:null),n.placeholder.remove(),e.active=null,n.source.notifyDragEnd(n.draggedId,t),n.source.notifyInteraction({index:n.source.getOrderedIds().indexOf(n.draggedId),itemId:n.draggedId,total:n.source.getOrderedIds().length,type:`cancel`}))}function commitSession(e,t){let n=e.active;if(!n)return;let r=n.target,i=n.placeholder.parentElement,a=projectedChanges(n);for(let{after:e,before:t,handle:n}of a)n.notifyBeforeReorder(immutableIds(t),immutableIds(e));restoreSessionElement(n),r&&e.handles.has(r)&&i?i.insertBefore(n.draggedEl,n.placeholder):n.originalParent.insertBefore(n.draggedEl,n.originalNextSibling?.parentNode===n.originalParent?n.originalNextSibling:null),n.placeholder.remove(),e.active=null,n.source.notifyDragEnd(n.draggedId,t);let o=[];for(let[t,r]of n.initialOrders){if(!e.handles.has(t))continue;let n=t.getOrderedIds();hasOrderChanged(r,n)&&o.push({after:n,before:r,handle:t})}if(r&&r!==n.source){let t=o.find(e=>e.handle===n.source),i=o.find(e=>e.handle===r);if(t&&i){e.commitMove({itemId:n.draggedId,source:n.source.element,sourceBeforeIds:t.before,sourceIds:t.after,target:r.element,targetBeforeIds:i.before,targetIds:i.after});let a=i.after.indexOf(n.draggedId),o=i.after.length;n.source.notifyInteraction({index:a,itemId:n.draggedId,total:o,type:`drop`}),r.notifyInteraction({index:a,itemId:n.draggedId,total:o,type:`drop`})}return}for(let{after:e,before:t,handle:r}of o)r.commitReorder({after:e,before:t,item:n.draggedId});let s=o.find(e=>e.handle===n.source),c=s?s.after:n.source.getOrderedIds(),l=c.indexOf(n.draggedId);n.source.notifyInteraction({index:l,itemId:n.draggedId,total:c.length,type:`drop`})}function finishSession(e,t,n){if(!e.active)return;let{active:r}=e;n||!t.dataTransfer||t.dataTransfer.dropEffect===`none`||!r.target||!e.handles.has(r.target)||r.source.isDisabled()||r.target.isDisabled()?cancelSession(e,t):commitSession(e,t)}function maybeAutoScroll(e,t,n,r){if(!r)return;let{container:i,edgeThreshold:a,speed:o,viewport:s}=r,c=t.getBoundingClientRect();if(n===`vertical`){i&&e.clientY<c.top+a?t.scrollTop-=o:i&&e.clientY>c.bottom-a&&(t.scrollTop+=o),s&&e.clientY<a?window.scrollBy({left:0,top:-o}):s&&e.clientY>window.innerHeight-a&&window.scrollBy({left:0,top:o});return}i&&e.clientX<c.left+a?t.scrollLeft-=o:i&&e.clientX>c.right-a&&(t.scrollLeft+=o),s&&e.clientX<a?window.scrollBy({left:-o,top:0}):s&&e.clientX>window.innerWidth-a&&window.scrollBy({left:o,top:0})}function keyboardTargetIndex(e,t,n,i){let a=e.indexOf(t);if(a<0)return null;let o=i===`vertical`?`ArrowDown`:`ArrowRight`,s=i===`vertical`?`ArrowUp`:`ArrowLeft`,c=(0,r.matchKey)(n,o),l=(0,r.matchKey)(n,s),u;if(c)u=Math.min(e.length-1,a+1);else if(l)u=Math.max(0,a-1);else if((0,r.matchKey)(n,`Home`))u=0;else if((0,r.matchKey)(n,`End`))u=e.length-1;else return null;return u===a?null:u}function createSortableScope(t={}){let r={active:null,commitMove(e){notify(`onMove`,t.onMove,Object.freeze({...e,sourceBeforeIds:immutableIds(e.sourceBeforeIds),sourceIds:immutableIds(e.sourceIds),targetBeforeIds:immutableIds(e.targetBeforeIds),targetIds:immutableIds(e.targetIds)}))},disposables:new Set,handles:new Set,touch:null},a=e.createDisposable(()=>{r.touch?.dispose();for(let e of[...r.disposables])e();r.disposables.clear(),r.handles.clear()}),o={get disposalSignal(){return a.disposalSignal},dispose:a.dispose,get disposed(){return a.disposed},get isDragging(){return r.active!==null},[i]:!0,[Symbol.dispose]:a[Symbol.dispose]};return s.set(o,r),t.touch&&(r.touch=n.createScopeTouchController(t.touch===!0?{}:t.touch,e=>{if(r.active)return null;for(let t of r.handles){let n=t.resolveTouchTarget(e);if(n)return n}return null})),o}function createSortable(n){let{autoScroll:r=!0,axis:i=`vertical`,element:s,getKey:c,handle:l,keyboard:u=!0,placeholderClass:d=`dnd-placeholder`,scope:f=createSortableScope()}=n;if(i!==`vertical`&&i!==`horizontal`)throw new t.DndError(`axis must be "vertical" or "horizontal"`);let p=l?.trim()||null;if((l===void 0||p)&&p)try{s.querySelector(p)}catch(e){throw new t.DndError(`Invalid handle selector: "${l}"`,{cause:e})}let m=resolveAutoScrollOptions(r),h=getSortableScopeState(f);if([...h.handles].some(e=>e.element===s))throw new t.DndError(`A sortable is already registered for this element in the selected scope.`);let getItems=()=>(n.items?n.items():Array.from(s.children)).filter(e=>e.parentElement===s&&e.hasAttribute(o)),getOrderedIds=()=>getItems().map(e=>c(e)),g=new Map,_=s.getAttribute(`role`),rememberElement=e=>{let t=g.get(e);if(t)return t;let n={dataDndHandle:e.getAttribute(a),dataDndItem:e.getAttribute(o),draggable:e.getAttribute(`draggable`),role:e.getAttribute(`role`),tabIndex:e.getAttribute(`tabindex`),touchAction:e.style.touchAction};return g.set(e,n),n},restoreAttribute=(e,t,n)=>{n===null?e.removeAttribute(t):e.setAttribute(t,n)},syncItems=(e=getItems())=>{e.forEach(e=>{let t=rememberElement(e);t.role===null&&e.setAttribute(`role`,`listitem`),t.tabIndex===null&&(e.tabIndex=0),l===void 0?(e.setAttribute(`draggable`,`true`),h.touch&&(e.style.touchAction=`none`)):p&&e.querySelectorAll(p).forEach(e=>{rememberElement(e),e.setAttribute(a,``),e.setAttribute(`draggable`,`true`),h.touch&&(e.style.touchAction=`none`)})})},markItems=()=>{let e=new Set,t=n.items?n.items():Array.from(s.children),r=t.filter(e=>e instanceof HTMLElement&&e.parentElement===s),i=[];r.length,t.length;for(let t of r)try{let n=c(t);if(n){if(e.has(n)){`${n}`;continue}e.add(n),i.push(t)}}catch(e){`${String(e)}`}cleanupItems();for(let e of i)rememberElement(e),e.setAttribute(o,``);syncItems(i)},cleanupItems=()=>{for(let[e,t]of g)restoreAttribute(e,a,t.dataDndHandle),restoreAttribute(e,o,t.dataDndItem),restoreAttribute(e,`draggable`,t.draggable),restoreAttribute(e,`role`,t.role),restoreAttribute(e,`tabindex`,t.tabIndex),e.style.touchAction=t.touchAction;g.clear()},createPlaceholder=e=>{let t=document.createElement(`div`);return t.className=d,t.setAttribute(`aria-hidden`,`true`),i===`horizontal`?t.style.width=`${e.offsetWidth}px`:t.style.height=`${e.offsetHeight}px`,t},v={commitReorder:e=>notify(`onReorder`,n.onReorder,Object.freeze({after:immutableIds(e.after),before:immutableIds(e.before),item:e.item})),element:s,getOrderedIds,getOrderedItems:getItems,isDisabled:()=>e.resolveDisabled(n.disabled),notifyBeforeReorder:(e,t)=>notify(`onBeforeReorder`,n.onBeforeReorder,e,t),notifyDragEnd:(e,t)=>notify(`onDragEnd`,n.onDragEnd,e,t),notifyDragStart:(e,t)=>notify(`onDragStart`,n.onDragStart,e,t),notifyInteraction:e=>notify(`onInteraction`,n.onInteraction,Object.freeze(e)),resolveTouchTarget:t=>{if(e.resolveDisabled(n.disabled)||!s.contains(t))return null;let r=t.closest(`[${o}]`);if(!r||!getItems().includes(r))return null;if(l===void 0)return r;if(!p)return null;let i=t.closest(p);return i&&r.contains(i)?i:null}},handleDragStart=e=>{if(h.active||v.isDisabled())return;let t=e.target,r=t.closest(`[${o}]`);if(!r||!getItems().includes(r))return;if(l!==void 0){let e=p?t.closest(p):null;if(!e||!r.contains(e))return}let i=r.parentElement;if(!i)return;let a=createPlaceholder(r),s=r.nextSibling,u=c(r),d=new Map;d.set(v,v.getOrderedIds()),r.setAttribute(`data-dragging`,``),i.insertBefore(a,s);let f={draggedEl:r,draggedId:u,hideFrame:null,initialOrders:d,originalDisplay:r.style.display,originalNextSibling:s,originalParent:i,placeholder:a,source:v,target:v};if((!isTouchDragEvent(e)||e.__dndTouchPreview)&&scheduleHide(f),h.active=f,e.dataTransfer)try{if(e.dataTransfer.effectAllowed=`move`,e.dataTransfer.setData(`text/plain`,u),n.dragImage){let t=typeof n.dragImage==`function`?n.dragImage(u,r,e):n.dragImage,[i,a]=n.dragImageOffset??[0,0];t&&e.dataTransfer.setDragImage(t,i,a)}}catch(e){`${e instanceof Error?e.message:String(e)}`}v.notifyDragStart(f.draggedId,e),v.notifyInteraction({index:v.getOrderedIds().indexOf(u),itemId:u,total:v.getOrderedIds().length,type:`pickup`})},handleDragOver=e=>{let t=h.active;if(!t||t.source.isDisabled()||v.isDisabled())return;e.preventDefault(),maybeAutoScroll(e,s,i,m),snapshotOrder(t,v);let{draggedEl:n,placeholder:r}=t,a=e.target.closest(`[${o}]`);if(a&&!getItems().includes(a))return;if(!a){r.parentElement!==s&&s.appendChild(r),t.target=v;return}if(a===n||a===r)return;let c=a.getBoundingClientRect(),l=i===`vertical`?e.clientY>=c.top+c.height/2:e.clientX>=c.left+c.width/2;s.insertBefore(r,l?a.nextSibling:a),t.target=v},handleDrop=e=>{let t=h.active;t&&(t.source.isDisabled()||v.isDisabled()||(e.preventDefault(),t.target=v))},handleDragEnd=e=>{h.active?.source===v&&finishSession(h,e,!1)},handleKeydown=e=>{if(!u||v.isDisabled())return;let t=e.target,n=t?.closest(`[${o}]`);if(!t||!n||!getItems().includes(n))return;let r=t.closest(`input, textarea, select, button, a[href], [contenteditable]:not([contenteditable="false"]), [role="button"], [role="link"]`),a=p?t.closest(p):null;if(r&&(!a||!n.contains(a)))return;let l=getItems(),d=l.indexOf(n),f=keyboardTargetIndex(l,n,e,i);if(f===null)return;let m=l[f];if(!m)return;let h=l.map(c),g=[...l];g.splice(d,1),g.splice(f,0,n);let _=g.map(c),y=c(n);e.preventDefault(),v.notifyBeforeReorder(immutableIds(h),immutableIds(_)),s.insertBefore(n,f>d?m.nextSibling:m),n.focus(),v.commitReorder({after:_,before:h,item:y}),v.notifyInteraction({index:f,itemId:y,previousIndex:d,total:_.length,type:`move`})};markItems();let y,b=e.createDisposable(()=>{h.disposables.delete(b.dispose),h.active&&(h.active.source===v||h.active.target===v)&&!h.touch?.cancel()&&finishSession(h,new Event(`dragend`),!0),y?.(),h.handles.delete(v),restoreAttribute(s,`role`,_),cleanupItems()});return h.handles.add(v),y=h.touch?.register(s),_===null&&s.setAttribute(`role`,`list`),s.addEventListener(`dragstart`,handleDragStart,{signal:b.disposalSignal}),s.addEventListener(`dragover`,handleDragOver,{signal:b.disposalSignal}),s.addEventListener(`drop`,handleDrop,{signal:b.disposalSignal}),s.addEventListener(`dragend`,handleDragEnd,{signal:b.disposalSignal}),s.addEventListener(`keydown`,handleKeydown,{signal:b.disposalSignal}),h.disposables.add(b.dispose),{get disposalSignal(){return b.disposalSignal},dispose:b.dispose,get disposed(){return b.disposed},get isDragging(){return h.active?.source===v},[Symbol.dispose]:b[Symbol.dispose],refresh:()=>{markItems()}}}function applyReorder(e,n,r){let i=new Map;for(let n of e){let e=r(n);if(i.has(e))throw new t.DndError(`Duplicate item key: "${e}"`);i.set(e,n)}let a=[];for(let e of n){if(!i.has(e))continue;let t=i.get(e);a.push(t),i.delete(e)}for(let e of i.values())a.push(e);return a}exports.DndError=t.DndError,exports.DndScopeError=t.DndScopeError,exports.applyReorder=applyReorder,exports.createSortable=createSortable,exports.createSortableScope=createSortableScope;
|
|
2
2
|
//# sourceMappingURL=sortable.cjs.map
|