@bquery/bquery 1.6.0 → 1.7.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/README.md +716 -586
- package/dist/a11y/announce.d.ts +43 -0
- package/dist/a11y/announce.d.ts.map +1 -0
- package/dist/a11y/audit.d.ts +42 -0
- package/dist/a11y/audit.d.ts.map +1 -0
- package/dist/a11y/index.d.ts +53 -0
- package/dist/a11y/index.d.ts.map +1 -0
- package/dist/a11y/media-preferences.d.ts +77 -0
- package/dist/a11y/media-preferences.d.ts.map +1 -0
- package/dist/a11y/roving-tab-index.d.ts +38 -0
- package/dist/a11y/roving-tab-index.d.ts.map +1 -0
- package/dist/a11y/skip-link.d.ts +37 -0
- package/dist/a11y/skip-link.d.ts.map +1 -0
- package/dist/a11y/trap-focus.d.ts +49 -0
- package/dist/a11y/trap-focus.d.ts.map +1 -0
- package/dist/a11y/types.d.ts +152 -0
- package/dist/a11y/types.d.ts.map +1 -0
- package/dist/a11y-C5QOVvRn.js +421 -0
- package/dist/a11y-C5QOVvRn.js.map +1 -0
- package/dist/a11y.es.mjs +14 -0
- package/dist/component/component.d.ts.map +1 -1
- package/dist/component/html.d.ts.map +1 -1
- package/dist/component/index.d.ts +2 -1
- package/dist/component/index.d.ts.map +1 -1
- package/dist/component/library.d.ts.map +1 -1
- package/dist/component/scope.d.ts +138 -0
- package/dist/component/scope.d.ts.map +1 -0
- package/dist/component/types.d.ts +53 -1
- package/dist/component/types.d.ts.map +1 -1
- package/dist/component-CuuTijA6.js +684 -0
- package/dist/component-CuuTijA6.js.map +1 -0
- package/dist/component.es.mjs +9 -6
- package/dist/{config-DRmZZno3.js → config-BW35FKuA.js} +4 -4
- package/dist/{config-DRmZZno3.js.map → config-BW35FKuA.js.map} +1 -1
- package/dist/constraints-3lV9yyBw.js +100 -0
- package/dist/constraints-3lV9yyBw.js.map +1 -0
- package/dist/core/collection.d.ts +48 -0
- package/dist/core/collection.d.ts.map +1 -1
- package/dist/core/element.d.ts +92 -0
- package/dist/core/element.d.ts.map +1 -1
- package/dist/core/env.d.ts +18 -0
- package/dist/core/env.d.ts.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/shared.d.ts +8 -0
- package/dist/core/shared.d.ts.map +1 -1
- package/dist/core/utils/index.d.ts +52 -41
- package/dist/core/utils/index.d.ts.map +1 -1
- package/dist/core-Cjl7GUu8.js +717 -0
- package/dist/core-Cjl7GUu8.js.map +1 -0
- package/dist/core-DnlyjbF2.js +112 -0
- package/dist/core-DnlyjbF2.js.map +1 -0
- package/dist/core.es.mjs +45 -44
- package/dist/custom-directives-7wAShnnd.js +9 -0
- package/dist/custom-directives-7wAShnnd.js.map +1 -0
- package/dist/devtools/devtools.d.ts +212 -0
- package/dist/devtools/devtools.d.ts.map +1 -0
- package/dist/devtools/index.d.ts +20 -0
- package/dist/devtools/index.d.ts.map +1 -0
- package/dist/devtools/types.d.ts +69 -0
- package/dist/devtools/types.d.ts.map +1 -0
- package/dist/devtools-D2fQLhDN.js +122 -0
- package/dist/devtools-D2fQLhDN.js.map +1 -0
- package/dist/devtools.es.mjs +19 -0
- package/dist/dnd/draggable.d.ts +51 -0
- package/dist/dnd/draggable.d.ts.map +1 -0
- package/dist/dnd/droppable.d.ts +38 -0
- package/dist/dnd/droppable.d.ts.map +1 -0
- package/dist/dnd/index.d.ts +47 -0
- package/dist/dnd/index.d.ts.map +1 -0
- package/dist/dnd/sortable.d.ts +43 -0
- package/dist/dnd/sortable.d.ts.map +1 -0
- package/dist/dnd/types.d.ts +250 -0
- package/dist/dnd/types.d.ts.map +1 -0
- package/dist/dnd-B8EgyzaI.js +244 -0
- package/dist/dnd-B8EgyzaI.js.map +1 -0
- package/dist/dnd.es.mjs +6 -0
- package/dist/env-NeVmr4Gf.js +19 -0
- package/dist/env-NeVmr4Gf.js.map +1 -0
- package/dist/forms/create-form.d.ts +49 -0
- package/dist/forms/create-form.d.ts.map +1 -0
- package/dist/forms/index.d.ts +39 -0
- package/dist/forms/index.d.ts.map +1 -0
- package/dist/forms/types.d.ts +139 -0
- package/dist/forms/types.d.ts.map +1 -0
- package/dist/forms/validators.d.ts +179 -0
- package/dist/forms/validators.d.ts.map +1 -0
- package/dist/forms-C3yovgH9.js +141 -0
- package/dist/forms-C3yovgH9.js.map +1 -0
- package/dist/forms.es.mjs +14 -0
- package/dist/full.d.ts +35 -7
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +182 -91
- package/dist/full.iife.js +47 -31
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +47 -31
- package/dist/full.umd.js.map +1 -1
- package/dist/i18n/formatting.d.ts +40 -0
- package/dist/i18n/formatting.d.ts.map +1 -0
- package/dist/i18n/i18n.d.ts +48 -0
- package/dist/i18n/i18n.d.ts.map +1 -0
- package/dist/i18n/index.d.ts +57 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/translate.d.ts +83 -0
- package/dist/i18n/translate.d.ts.map +1 -0
- package/dist/i18n/types.d.ts +156 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n-BnnhTFOS.js +89 -0
- package/dist/i18n-BnnhTFOS.js.map +1 -0
- package/dist/i18n.es.mjs +6 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.mjs +227 -136
- package/dist/media/battery.d.ts +35 -0
- package/dist/media/battery.d.ts.map +1 -0
- package/dist/media/breakpoints.d.ts +51 -0
- package/dist/media/breakpoints.d.ts.map +1 -0
- package/dist/media/clipboard.d.ts +30 -0
- package/dist/media/clipboard.d.ts.map +1 -0
- package/dist/media/device-sensors.d.ts +54 -0
- package/dist/media/device-sensors.d.ts.map +1 -0
- package/dist/media/geolocation.d.ts +38 -0
- package/dist/media/geolocation.d.ts.map +1 -0
- package/dist/media/index.d.ts +42 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media/media-query.d.ts +36 -0
- package/dist/media/media-query.d.ts.map +1 -0
- package/dist/media/network.d.ts +35 -0
- package/dist/media/network.d.ts.map +1 -0
- package/dist/media/types.d.ts +173 -0
- package/dist/media/types.d.ts.map +1 -0
- package/dist/media/viewport.d.ts +32 -0
- package/dist/media/viewport.d.ts.map +1 -0
- package/dist/media-Di2Ta22s.js +340 -0
- package/dist/media-Di2Ta22s.js.map +1 -0
- package/dist/media.es.mjs +12 -0
- package/dist/motion/index.d.ts +7 -3
- package/dist/motion/index.d.ts.map +1 -1
- package/dist/motion/morph.d.ts +27 -0
- package/dist/motion/morph.d.ts.map +1 -0
- package/dist/motion/parallax.d.ts +30 -0
- package/dist/motion/parallax.d.ts.map +1 -0
- package/dist/motion/reduced-motion.d.ts +36 -3
- package/dist/motion/reduced-motion.d.ts.map +1 -1
- package/dist/motion/types.d.ts +58 -0
- package/dist/motion/types.d.ts.map +1 -1
- package/dist/motion/typewriter.d.ts +31 -0
- package/dist/motion/typewriter.d.ts.map +1 -0
- package/dist/motion-qPj_TYGv.js +530 -0
- package/dist/motion-qPj_TYGv.js.map +1 -0
- package/dist/motion.es.mjs +27 -23
- package/dist/{view-C70lA3vf.js → mount-SM07RUa6.js} +166 -160
- package/dist/mount-SM07RUa6.js.map +1 -0
- package/dist/{object-qGpWr6-J.js → object-BCk-1c8T.js} +5 -4
- package/dist/{object-qGpWr6-J.js.map → object-BCk-1c8T.js.map} +1 -1
- package/dist/{platform-Dr9b6fsq.js → platform-CPbCprb6.js} +21 -22
- package/dist/{platform-Dr9b6fsq.js.map → platform-CPbCprb6.js.map} +1 -1
- package/dist/platform.es.mjs +2 -2
- package/dist/plugin/index.d.ts +22 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/registry.d.ts +108 -0
- package/dist/plugin/registry.d.ts.map +1 -0
- package/dist/plugin/types.d.ts +110 -0
- package/dist/plugin/types.d.ts.map +1 -0
- package/dist/plugin-cPoOHFLY.js +64 -0
- package/dist/plugin-cPoOHFLY.js.map +1 -0
- package/dist/plugin.es.mjs +9 -0
- package/dist/reactive/computed.d.ts +7 -0
- package/dist/reactive/computed.d.ts.map +1 -1
- package/dist/reactive-Cfv0RK6x.js +233 -0
- package/dist/reactive-Cfv0RK6x.js.map +1 -0
- package/dist/reactive.es.mjs +19 -20
- package/dist/registry-CWf368tT.js +26 -0
- package/dist/registry-CWf368tT.js.map +1 -0
- package/dist/router/bq-link.d.ts +112 -0
- package/dist/router/bq-link.d.ts.map +1 -0
- package/dist/router/constraints.d.ts +9 -0
- package/dist/router/constraints.d.ts.map +1 -0
- package/dist/router/index.d.ts +14 -6
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/match.d.ts +0 -1
- package/dist/router/match.d.ts.map +1 -1
- package/dist/router/path-pattern.d.ts +14 -0
- package/dist/router/path-pattern.d.ts.map +1 -0
- package/dist/router/query.d.ts.map +1 -1
- package/dist/router/router.d.ts +3 -1
- package/dist/router/router.d.ts.map +1 -1
- package/dist/router/types.d.ts +48 -4
- package/dist/router/types.d.ts.map +1 -1
- package/dist/router/use-route.d.ts +50 -0
- package/dist/router/use-route.d.ts.map +1 -0
- package/dist/router/utils.d.ts +3 -0
- package/dist/router/utils.d.ts.map +1 -1
- package/dist/router-BrthaP_z.js +473 -0
- package/dist/router-BrthaP_z.js.map +1 -0
- package/dist/router.es.mjs +13 -10
- package/dist/{sanitize-Bs2dkMby.js → sanitize-B1V4JswB.js} +2 -1
- package/dist/{sanitize-Bs2dkMby.js.map → sanitize-B1V4JswB.js.map} +1 -1
- package/dist/security/index.d.ts +2 -2
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security.es.mjs +1 -1
- package/dist/ssr/hydrate.d.ts +65 -0
- package/dist/ssr/hydrate.d.ts.map +1 -0
- package/dist/ssr/index.d.ts +59 -0
- package/dist/ssr/index.d.ts.map +1 -0
- package/dist/ssr/render.d.ts +62 -0
- package/dist/ssr/render.d.ts.map +1 -0
- package/dist/ssr/serialize.d.ts +118 -0
- package/dist/ssr/serialize.d.ts.map +1 -0
- package/dist/ssr/types.d.ts +70 -0
- package/dist/ssr/types.d.ts.map +1 -0
- package/dist/ssr-B2qd_WBB.js +248 -0
- package/dist/ssr-B2qd_WBB.js.map +1 -0
- package/dist/ssr.es.mjs +9 -0
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/index.d.ts +1 -1
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/persisted.d.ts +38 -4
- package/dist/store/persisted.d.ts.map +1 -1
- package/dist/store/types.d.ts +138 -1
- package/dist/store/types.d.ts.map +1 -1
- package/dist/store/utils.d.ts +2 -2
- package/dist/store/utils.d.ts.map +1 -1
- package/dist/store-DWpyH6p5.js +338 -0
- package/dist/store-DWpyH6p5.js.map +1 -0
- package/dist/store.es.mjs +11 -10
- package/dist/storybook/index.d.ts.map +1 -1
- package/dist/storybook.es.mjs +1 -1
- package/dist/storybook.es.mjs.map +1 -1
- package/dist/testing/index.d.ts +23 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/testing.d.ts +156 -0
- package/dist/testing/testing.d.ts.map +1 -0
- package/dist/testing/types.d.ts +134 -0
- package/dist/testing/types.d.ts.map +1 -0
- package/dist/testing-CsqjNUyy.js +224 -0
- package/dist/testing-CsqjNUyy.js.map +1 -0
- package/dist/testing.es.mjs +9 -0
- package/dist/type-guards-Do9DWgNp.js +44 -0
- package/dist/type-guards-Do9DWgNp.js.map +1 -0
- package/dist/untrack-DJVQQ2WM.js +33 -0
- package/dist/untrack-DJVQQ2WM.js.map +1 -0
- package/dist/view/custom-directives.d.ts +20 -0
- package/dist/view/custom-directives.d.ts.map +1 -0
- package/dist/view/evaluate.d.ts.map +1 -1
- package/dist/view/process.d.ts.map +1 -1
- package/dist/view.es.mjs +9 -9
- package/package.json +177 -141
- package/src/a11y/announce.ts +131 -0
- package/src/a11y/audit.ts +314 -0
- package/src/a11y/index.ts +68 -0
- package/src/a11y/media-preferences.ts +255 -0
- package/src/a11y/roving-tab-index.ts +164 -0
- package/src/a11y/skip-link.ts +255 -0
- package/src/a11y/trap-focus.ts +184 -0
- package/src/a11y/types.ts +183 -0
- package/src/component/component.ts +104 -29
- package/src/component/html.ts +5 -5
- package/src/component/index.ts +2 -0
- package/src/component/library.ts +26 -2
- package/src/component/scope.ts +212 -0
- package/src/component/types.ts +94 -40
- package/src/core/collection.ts +707 -628
- package/src/core/element.ts +981 -774
- package/src/core/env.ts +60 -0
- package/src/core/index.ts +49 -48
- package/src/core/shared.ts +62 -13
- package/src/core/utils/index.ts +148 -83
- package/src/devtools/devtools.ts +410 -0
- package/src/devtools/index.ts +48 -0
- package/src/devtools/types.ts +104 -0
- package/src/dnd/draggable.ts +296 -0
- package/src/dnd/droppable.ts +228 -0
- package/src/dnd/index.ts +62 -0
- package/src/dnd/sortable.ts +307 -0
- package/src/dnd/types.ts +293 -0
- package/src/forms/create-form.ts +278 -0
- package/src/forms/index.ts +65 -0
- package/src/forms/types.ts +154 -0
- package/src/forms/validators.ts +265 -0
- package/src/full.ts +253 -2
- package/src/i18n/formatting.ts +67 -0
- package/src/i18n/i18n.ts +200 -0
- package/src/i18n/index.ts +67 -0
- package/src/i18n/translate.ts +182 -0
- package/src/i18n/types.ts +171 -0
- package/src/index.ts +108 -36
- package/src/media/battery.ts +116 -0
- package/src/media/breakpoints.ts +131 -0
- package/src/media/clipboard.ts +80 -0
- package/src/media/device-sensors.ts +158 -0
- package/src/media/geolocation.ts +119 -0
- package/src/media/index.ts +76 -0
- package/src/media/media-query.ts +92 -0
- package/src/media/network.ts +115 -0
- package/src/media/types.ts +177 -0
- package/src/media/viewport.ts +84 -0
- package/src/motion/index.ts +57 -48
- package/src/motion/morph.ts +151 -0
- package/src/motion/parallax.ts +120 -0
- package/src/motion/reduced-motion.ts +66 -17
- package/src/motion/types.ts +271 -208
- package/src/motion/typewriter.ts +164 -0
- package/src/plugin/index.ts +37 -0
- package/src/plugin/registry.ts +269 -0
- package/src/plugin/types.ts +137 -0
- package/src/reactive/computed.ts +130 -92
- package/src/router/bq-link.ts +279 -0
- package/src/router/constraints.ts +201 -0
- package/src/router/index.ts +49 -41
- package/src/router/match.ts +312 -106
- package/src/router/path-pattern.ts +52 -0
- package/src/router/query.ts +38 -35
- package/src/router/router.ts +402 -211
- package/src/router/types.ts +139 -93
- package/src/router/use-route.ts +68 -0
- package/src/router/utils.ts +157 -116
- package/src/security/index.ts +2 -7
- package/src/security/sanitize.ts +70 -70
- package/src/security/trusted-html.ts +71 -71
- package/src/ssr/hydrate.ts +82 -0
- package/src/ssr/index.ts +70 -0
- package/src/ssr/render.ts +508 -0
- package/src/ssr/serialize.ts +296 -0
- package/src/ssr/types.ts +81 -0
- package/src/store/create-store.ts +467 -329
- package/src/store/define-store.ts +49 -49
- package/src/store/index.ts +27 -22
- package/src/store/mapping.ts +74 -74
- package/src/store/persisted.ts +206 -19
- package/src/store/types.ts +157 -2
- package/src/store/utils.ts +135 -141
- package/src/store/watch.ts +53 -53
- package/src/storybook/index.ts +2 -1
- package/src/testing/index.ts +42 -0
- package/src/testing/testing.ts +593 -0
- package/src/testing/types.ts +170 -0
- package/src/view/custom-directives.ts +30 -0
- package/src/view/evaluate.ts +292 -290
- package/src/view/process.ts +108 -92
- package/dist/component-BEQgt5hl.js +0 -600
- package/dist/component-BEQgt5hl.js.map +0 -1
- package/dist/core-BGQJVw0-.js +0 -35
- package/dist/core-BGQJVw0-.js.map +0 -1
- package/dist/core-CCEabVHl.js +0 -648
- package/dist/core-CCEabVHl.js.map +0 -1
- package/dist/effect-AFRW_Plg.js +0 -84
- package/dist/effect-AFRW_Plg.js.map +0 -1
- package/dist/motion-D9TcHxOF.js +0 -415
- package/dist/motion-D9TcHxOF.js.map +0 -1
- package/dist/reactive-DSkct0dO.js +0 -254
- package/dist/reactive-DSkct0dO.js.map +0 -1
- package/dist/router-CbDhl8rS.js +0 -188
- package/dist/router-CbDhl8rS.js.map +0 -1
- package/dist/store-BwDvI45q.js +0 -263
- package/dist/store-BwDvI45q.js.map +0 -1
- package/dist/untrack-B0rVscTc.js +0 -7
- package/dist/untrack-B0rVscTc.js.map +0 -1
- package/dist/view-C70lA3vf.js.map +0 -1
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sortable list with animated reordering via pointer events.
|
|
3
|
+
*
|
|
4
|
+
* Makes children of a container sortable by dragging. Items are
|
|
5
|
+
* rearranged in the DOM with optional CSS animation.
|
|
6
|
+
*
|
|
7
|
+
* @module bquery/dnd
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { SortEventData, SortableHandle, SortableOptions } from './types';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gets the sortable items within a container.
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
const getItems = (container: HTMLElement, selector: string): HTMLElement[] => {
|
|
17
|
+
return Array.from(container.querySelectorAll(selector)) as HTMLElement[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Finds the closest sortable item to a given Y (or X) position.
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
const getClosestItem = (
|
|
25
|
+
items: HTMLElement[],
|
|
26
|
+
clientPos: number,
|
|
27
|
+
axis: 'x' | 'y',
|
|
28
|
+
dragged: HTMLElement
|
|
29
|
+
): { element: HTMLElement; index: number } | null => {
|
|
30
|
+
let closest: { element: HTMLElement; index: number; distance: number } | null = null;
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < items.length; i++) {
|
|
33
|
+
const item = items[i];
|
|
34
|
+
if (item === dragged) continue;
|
|
35
|
+
|
|
36
|
+
const rect = item.getBoundingClientRect();
|
|
37
|
+
const mid = axis === 'y' ? rect.top + rect.height / 2 : rect.left + rect.width / 2;
|
|
38
|
+
const distance = clientPos - mid;
|
|
39
|
+
|
|
40
|
+
if (
|
|
41
|
+
closest === null ||
|
|
42
|
+
(distance < 0 && distance > closest.distance) ||
|
|
43
|
+
(closest.distance >= 0 && distance < 0 && Math.abs(distance) < Math.abs(closest.distance))
|
|
44
|
+
) {
|
|
45
|
+
// Find the item we're just before
|
|
46
|
+
if (distance < 0) {
|
|
47
|
+
closest = { element: item, index: i, distance };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return closest ? { element: closest.element, index: closest.index } : null;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Makes the children of a container sortable by dragging.
|
|
57
|
+
*
|
|
58
|
+
* Features:
|
|
59
|
+
* - Pointer event based (touch + mouse)
|
|
60
|
+
* - Animated reordering with configurable duration
|
|
61
|
+
* - Axis constraint (vertical or horizontal)
|
|
62
|
+
* - Optional drag handle
|
|
63
|
+
* - Placeholder element during sort
|
|
64
|
+
* - Callbacks: `onSortStart`, `onSortMove`, `onSortEnd`
|
|
65
|
+
*
|
|
66
|
+
* @param container - The container element whose children will be sortable
|
|
67
|
+
* @param options - Configuration options
|
|
68
|
+
* @returns A handle with `destroy()`, `disable()`, and `enable()` methods
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* import { sortable } from '@bquery/bquery/dnd';
|
|
73
|
+
*
|
|
74
|
+
* const handle = sortable(document.querySelector('#list'), {
|
|
75
|
+
* items: 'li',
|
|
76
|
+
* axis: 'y',
|
|
77
|
+
* animationDuration: 200,
|
|
78
|
+
* onSortEnd: ({ oldIndex, newIndex }) => {
|
|
79
|
+
* console.log(`Moved from ${oldIndex} to ${newIndex}`);
|
|
80
|
+
* },
|
|
81
|
+
* });
|
|
82
|
+
*
|
|
83
|
+
* // Later:
|
|
84
|
+
* handle.destroy();
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export const sortable = (container: HTMLElement, options: SortableOptions = {}): SortableHandle => {
|
|
88
|
+
const {
|
|
89
|
+
items: itemSelector = ':scope > *',
|
|
90
|
+
axis = 'y',
|
|
91
|
+
handle,
|
|
92
|
+
placeholderClass = 'bq-sort-placeholder',
|
|
93
|
+
sortingClass = 'bq-sorting',
|
|
94
|
+
animationDuration = 200,
|
|
95
|
+
onSortStart,
|
|
96
|
+
onSortMove,
|
|
97
|
+
onSortEnd,
|
|
98
|
+
} = options;
|
|
99
|
+
|
|
100
|
+
let enabled = !options.disabled;
|
|
101
|
+
let isDragging = false;
|
|
102
|
+
let dragItem: HTMLElement | null = null;
|
|
103
|
+
let placeholder: HTMLElement | null = null;
|
|
104
|
+
let startIndex = -1;
|
|
105
|
+
let startPointerY = 0;
|
|
106
|
+
let startPointerX = 0;
|
|
107
|
+
let itemStartTop = 0;
|
|
108
|
+
let itemStartLeft = 0;
|
|
109
|
+
|
|
110
|
+
const createEventData = (item: HTMLElement, oldIdx: number, newIdx: number): SortEventData => ({
|
|
111
|
+
container,
|
|
112
|
+
item,
|
|
113
|
+
oldIndex: oldIdx,
|
|
114
|
+
newIndex: newIdx,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const onPointerDown = (e: PointerEvent): void => {
|
|
118
|
+
if (!enabled) return;
|
|
119
|
+
|
|
120
|
+
const target = e.target as HTMLElement;
|
|
121
|
+
|
|
122
|
+
// Find the item being dragged
|
|
123
|
+
const items = getItems(container, itemSelector);
|
|
124
|
+
let item: HTMLElement | null = null;
|
|
125
|
+
|
|
126
|
+
for (const it of items) {
|
|
127
|
+
if (it.contains(target)) {
|
|
128
|
+
item = it;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!item) return;
|
|
134
|
+
|
|
135
|
+
// Check handle constraint
|
|
136
|
+
if (handle && !target.closest(handle)) return;
|
|
137
|
+
|
|
138
|
+
e.preventDefault();
|
|
139
|
+
|
|
140
|
+
isDragging = true;
|
|
141
|
+
dragItem = item;
|
|
142
|
+
startIndex = items.indexOf(item);
|
|
143
|
+
startPointerY = e.clientY;
|
|
144
|
+
startPointerX = e.clientX;
|
|
145
|
+
|
|
146
|
+
const rect = item.getBoundingClientRect();
|
|
147
|
+
itemStartTop = rect.top;
|
|
148
|
+
itemStartLeft = rect.left;
|
|
149
|
+
|
|
150
|
+
// Create placeholder
|
|
151
|
+
placeholder = document.createElement('div');
|
|
152
|
+
placeholder.classList.add(placeholderClass);
|
|
153
|
+
placeholder.style.width = `${rect.width}px`;
|
|
154
|
+
placeholder.style.height = `${rect.height}px`;
|
|
155
|
+
placeholder.style.boxSizing = 'border-box';
|
|
156
|
+
|
|
157
|
+
// Style the dragged item
|
|
158
|
+
item.classList.add(sortingClass);
|
|
159
|
+
item.style.position = 'fixed';
|
|
160
|
+
item.style.width = `${rect.width}px`;
|
|
161
|
+
item.style.height = `${rect.height}px`;
|
|
162
|
+
item.style.left = `${rect.left}px`;
|
|
163
|
+
item.style.top = `${rect.top}px`;
|
|
164
|
+
item.style.zIndex = '999999';
|
|
165
|
+
item.style.pointerEvents = 'none';
|
|
166
|
+
item.style.margin = '0';
|
|
167
|
+
|
|
168
|
+
// Insert placeholder where the item was
|
|
169
|
+
item.parentNode?.insertBefore(placeholder, item);
|
|
170
|
+
|
|
171
|
+
container.setPointerCapture(e.pointerId);
|
|
172
|
+
|
|
173
|
+
onSortStart?.(createEventData(item, startIndex, startIndex));
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const onPointerMove = (e: PointerEvent): void => {
|
|
177
|
+
if (!isDragging || !dragItem || !placeholder) return;
|
|
178
|
+
|
|
179
|
+
e.preventDefault();
|
|
180
|
+
|
|
181
|
+
const deltaX = e.clientX - startPointerX;
|
|
182
|
+
const deltaY = e.clientY - startPointerY;
|
|
183
|
+
|
|
184
|
+
// Move the dragged item
|
|
185
|
+
if (axis === 'y') {
|
|
186
|
+
dragItem.style.top = `${itemStartTop + deltaY}px`;
|
|
187
|
+
} else {
|
|
188
|
+
dragItem.style.left = `${itemStartLeft + deltaX}px`;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Find the closest item to determine insertion point
|
|
192
|
+
const items = getItems(container, itemSelector);
|
|
193
|
+
const clientPos = axis === 'y' ? e.clientY : e.clientX;
|
|
194
|
+
const closest = getClosestItem(items, clientPos, axis, dragItem);
|
|
195
|
+
|
|
196
|
+
if (closest) {
|
|
197
|
+
// Move placeholder before the closest element
|
|
198
|
+
container.insertBefore(placeholder, closest.element);
|
|
199
|
+
} else {
|
|
200
|
+
// Append to end
|
|
201
|
+
container.appendChild(placeholder);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const currentIndex = Array.from(container.children).indexOf(placeholder);
|
|
205
|
+
onSortMove?.(createEventData(dragItem, startIndex, currentIndex));
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const onPointerUp = (e: PointerEvent): void => {
|
|
209
|
+
if (!isDragging || !dragItem || !placeholder) return;
|
|
210
|
+
|
|
211
|
+
isDragging = false;
|
|
212
|
+
const draggedItem = dragItem;
|
|
213
|
+
|
|
214
|
+
// Get final index
|
|
215
|
+
const newIndex = Array.from(container.children).indexOf(placeholder);
|
|
216
|
+
|
|
217
|
+
// Animate the item back to the placeholder position
|
|
218
|
+
const placeholderRect = placeholder.getBoundingClientRect();
|
|
219
|
+
const itemRect = draggedItem.getBoundingClientRect();
|
|
220
|
+
|
|
221
|
+
if (animationDuration > 0) {
|
|
222
|
+
const deltaX = placeholderRect.left - itemRect.left;
|
|
223
|
+
const deltaY = placeholderRect.top - itemRect.top;
|
|
224
|
+
|
|
225
|
+
draggedItem.style.transition = `transform ${animationDuration}ms ease`;
|
|
226
|
+
draggedItem.style.transform = `translate(${deltaX}px, ${deltaY}px)`;
|
|
227
|
+
|
|
228
|
+
let finalized = false;
|
|
229
|
+
let timeoutId: number | null = null;
|
|
230
|
+
const finalize = (): void => {
|
|
231
|
+
if (finalized) return;
|
|
232
|
+
finalized = true;
|
|
233
|
+
if (timeoutId !== null) {
|
|
234
|
+
window.clearTimeout(timeoutId);
|
|
235
|
+
timeoutId = null;
|
|
236
|
+
}
|
|
237
|
+
resetDragItem();
|
|
238
|
+
onSortEnd?.(createEventData(draggedItem, startIndex, newIndex));
|
|
239
|
+
};
|
|
240
|
+
timeoutId = window.setTimeout(() => {
|
|
241
|
+
finalize();
|
|
242
|
+
}, animationDuration + 50);
|
|
243
|
+
|
|
244
|
+
draggedItem.addEventListener('transitionend', finalize, { once: true });
|
|
245
|
+
} else {
|
|
246
|
+
resetDragItem();
|
|
247
|
+
onSortEnd?.(createEventData(draggedItem, startIndex, newIndex));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
container.releasePointerCapture(e.pointerId);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const resetDragItem = (): void => {
|
|
254
|
+
if (!dragItem || !placeholder) return;
|
|
255
|
+
|
|
256
|
+
// Insert the real item where the placeholder is
|
|
257
|
+
placeholder.parentNode?.insertBefore(dragItem, placeholder);
|
|
258
|
+
placeholder.remove();
|
|
259
|
+
placeholder = null;
|
|
260
|
+
|
|
261
|
+
// Reset styles
|
|
262
|
+
dragItem.classList.remove(sortingClass);
|
|
263
|
+
dragItem.style.position = '';
|
|
264
|
+
dragItem.style.width = '';
|
|
265
|
+
dragItem.style.height = '';
|
|
266
|
+
dragItem.style.left = '';
|
|
267
|
+
dragItem.style.top = '';
|
|
268
|
+
dragItem.style.zIndex = '';
|
|
269
|
+
dragItem.style.pointerEvents = '';
|
|
270
|
+
dragItem.style.margin = '';
|
|
271
|
+
dragItem.style.transition = '';
|
|
272
|
+
dragItem.style.transform = '';
|
|
273
|
+
|
|
274
|
+
dragItem = null;
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
container.addEventListener('pointerdown', onPointerDown);
|
|
278
|
+
container.addEventListener('pointermove', onPointerMove);
|
|
279
|
+
container.addEventListener('pointerup', onPointerUp);
|
|
280
|
+
container.addEventListener('pointercancel', onPointerUp);
|
|
281
|
+
|
|
282
|
+
// Prevent default touch behavior on container
|
|
283
|
+
container.style.touchAction = 'none';
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
destroy: () => {
|
|
287
|
+
container.removeEventListener('pointerdown', onPointerDown);
|
|
288
|
+
container.removeEventListener('pointermove', onPointerMove);
|
|
289
|
+
container.removeEventListener('pointerup', onPointerUp);
|
|
290
|
+
container.removeEventListener('pointercancel', onPointerUp);
|
|
291
|
+
container.style.touchAction = '';
|
|
292
|
+
|
|
293
|
+
if (isDragging) {
|
|
294
|
+
resetDragItem();
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
disable: () => {
|
|
298
|
+
enabled = false;
|
|
299
|
+
},
|
|
300
|
+
enable: () => {
|
|
301
|
+
enabled = true;
|
|
302
|
+
},
|
|
303
|
+
get enabled() {
|
|
304
|
+
return enabled;
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
};
|
package/src/dnd/types.ts
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the bQuery Drag & Drop module.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/dnd
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// ─── Shared Types ────────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Axis constraint for draggable elements.
|
|
11
|
+
* - `'x'` — horizontal only
|
|
12
|
+
* - `'y'` — vertical only
|
|
13
|
+
* - `'both'` — free movement (default)
|
|
14
|
+
*/
|
|
15
|
+
export type DragAxis = 'x' | 'y' | 'both';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Position coordinates in pixels.
|
|
19
|
+
*/
|
|
20
|
+
export interface DragPosition {
|
|
21
|
+
/** Horizontal position in pixels. */
|
|
22
|
+
x: number;
|
|
23
|
+
/** Vertical position in pixels. */
|
|
24
|
+
y: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A bounding rectangle used to constrain drag movement.
|
|
29
|
+
*/
|
|
30
|
+
export interface BoundsRect {
|
|
31
|
+
/** Minimum X coordinate (left edge). */
|
|
32
|
+
left: number;
|
|
33
|
+
/** Minimum Y coordinate (top edge). */
|
|
34
|
+
top: number;
|
|
35
|
+
/** Maximum X coordinate (right edge). */
|
|
36
|
+
right: number;
|
|
37
|
+
/** Maximum Y coordinate (bottom edge). */
|
|
38
|
+
bottom: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Bounds constraint for draggable elements.
|
|
43
|
+
* - `'parent'` — constrain to parent element's bounds
|
|
44
|
+
* - A CSS selector string — constrain to the matched element's bounds
|
|
45
|
+
* - A `BoundsRect` — constrain to explicit coordinates
|
|
46
|
+
*/
|
|
47
|
+
export type DragBounds = 'parent' | string | BoundsRect;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Data passed to all drag event callbacks.
|
|
51
|
+
*/
|
|
52
|
+
export interface DragEventData {
|
|
53
|
+
/** The dragged element. */
|
|
54
|
+
element: HTMLElement;
|
|
55
|
+
/** Current position relative to the initial position (0,0 at start). */
|
|
56
|
+
position: DragPosition;
|
|
57
|
+
/** Movement delta since the last event. */
|
|
58
|
+
delta: DragPosition;
|
|
59
|
+
/** The original pointer event. */
|
|
60
|
+
event: PointerEvent;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ─── Draggable ───────────────────────────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Configuration options for `draggable()`.
|
|
67
|
+
*/
|
|
68
|
+
export interface DraggableOptions {
|
|
69
|
+
/**
|
|
70
|
+
* Axis constraint for movement.
|
|
71
|
+
* @default 'both'
|
|
72
|
+
*/
|
|
73
|
+
axis?: DragAxis;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Bounds constraint. Restricts the element's movement to within the
|
|
77
|
+
* specified area.
|
|
78
|
+
*/
|
|
79
|
+
bounds?: DragBounds;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* CSS selector for a drag handle. If provided, only pointer events
|
|
83
|
+
* on matching child elements will initiate a drag.
|
|
84
|
+
*/
|
|
85
|
+
handle?: string;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Whether to show a ghost/clone preview during drag instead of
|
|
89
|
+
* moving the original element. The ghost follows the pointer while
|
|
90
|
+
* the original stays in place.
|
|
91
|
+
* @default false
|
|
92
|
+
*/
|
|
93
|
+
ghost?: boolean;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* CSS class applied to the ghost element.
|
|
97
|
+
* @default 'bq-drag-ghost'
|
|
98
|
+
*/
|
|
99
|
+
ghostClass?: string;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* CSS class applied to the element while it is being dragged.
|
|
103
|
+
* @default 'bq-dragging'
|
|
104
|
+
*/
|
|
105
|
+
draggingClass?: string;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Whether the element is initially disabled for dragging.
|
|
109
|
+
* @default false
|
|
110
|
+
*/
|
|
111
|
+
disabled?: boolean;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Called when a drag operation starts.
|
|
115
|
+
*/
|
|
116
|
+
onDragStart?: (data: DragEventData) => void;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Called continuously during drag movement.
|
|
120
|
+
*/
|
|
121
|
+
onDrag?: (data: DragEventData) => void;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Called when a drag operation ends.
|
|
125
|
+
*/
|
|
126
|
+
onDragEnd?: (data: DragEventData) => void;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Handle returned by `draggable()` for controlling the drag behavior.
|
|
131
|
+
*/
|
|
132
|
+
export interface DraggableHandle {
|
|
133
|
+
/** Remove all event listeners and clean up. */
|
|
134
|
+
destroy: () => void;
|
|
135
|
+
/** Disable dragging. */
|
|
136
|
+
disable: () => void;
|
|
137
|
+
/** Re-enable dragging. */
|
|
138
|
+
enable: () => void;
|
|
139
|
+
/** Whether dragging is currently enabled. */
|
|
140
|
+
readonly enabled: boolean;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ─── Droppable ───────────────────────────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Data passed to droppable event callbacks.
|
|
147
|
+
*/
|
|
148
|
+
export interface DropEventData {
|
|
149
|
+
/** The drop zone element. */
|
|
150
|
+
zone: HTMLElement;
|
|
151
|
+
/** The dragged element entering/leaving/dropping onto the zone. */
|
|
152
|
+
dragged: HTMLElement;
|
|
153
|
+
/** The original pointer event. */
|
|
154
|
+
event: PointerEvent;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Configuration options for `droppable()`.
|
|
159
|
+
*/
|
|
160
|
+
export interface DroppableOptions {
|
|
161
|
+
/**
|
|
162
|
+
* CSS class applied to the zone while a draggable element is over it.
|
|
163
|
+
* @default 'bq-drop-over'
|
|
164
|
+
*/
|
|
165
|
+
overClass?: string;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* CSS selector or predicate to filter which dragged elements are
|
|
169
|
+
* accepted. If a string, only elements matching the selector can
|
|
170
|
+
* be dropped. If a function, return `true` to accept.
|
|
171
|
+
*/
|
|
172
|
+
accept?: string | ((el: HTMLElement) => boolean);
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Called when a dragged element enters the drop zone.
|
|
176
|
+
*/
|
|
177
|
+
onDragEnter?: (data: DropEventData) => void;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Called while a dragged element is over the drop zone.
|
|
181
|
+
*/
|
|
182
|
+
onDragOver?: (data: DropEventData) => void;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Called when a dragged element leaves the drop zone.
|
|
186
|
+
*/
|
|
187
|
+
onDragLeave?: (data: DropEventData) => void;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Called when a dragged element is dropped onto the zone.
|
|
191
|
+
*/
|
|
192
|
+
onDrop?: (data: DropEventData) => void;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Handle returned by `droppable()` for controlling the drop zone.
|
|
197
|
+
*/
|
|
198
|
+
export interface DroppableHandle {
|
|
199
|
+
/** Remove all event listeners and clean up. */
|
|
200
|
+
destroy: () => void;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ─── Sortable ────────────────────────────────────────────────────────────────
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Data passed to sortable event callbacks.
|
|
207
|
+
*/
|
|
208
|
+
export interface SortEventData {
|
|
209
|
+
/** The container element. */
|
|
210
|
+
container: HTMLElement;
|
|
211
|
+
/** The item being moved. */
|
|
212
|
+
item: HTMLElement;
|
|
213
|
+
/** The old index before the move. */
|
|
214
|
+
oldIndex: number;
|
|
215
|
+
/** The new index after the move. */
|
|
216
|
+
newIndex: number;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Configuration options for `sortable()`.
|
|
221
|
+
*/
|
|
222
|
+
export interface SortableOptions {
|
|
223
|
+
/**
|
|
224
|
+
* CSS selector for the sortable items within the container.
|
|
225
|
+
* @default '> *'
|
|
226
|
+
*/
|
|
227
|
+
items?: string;
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Axis constraint for sorting.
|
|
231
|
+
* @default 'y'
|
|
232
|
+
*/
|
|
233
|
+
axis?: 'x' | 'y';
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* CSS selector for a drag handle within each item. If provided,
|
|
237
|
+
* only pointer events on handle elements initiate sorting.
|
|
238
|
+
*/
|
|
239
|
+
handle?: string;
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* CSS class applied to the placeholder element during sorting.
|
|
243
|
+
* @default 'bq-sort-placeholder'
|
|
244
|
+
*/
|
|
245
|
+
placeholderClass?: string;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* CSS class applied to the item being sorted.
|
|
249
|
+
* @default 'bq-sorting'
|
|
250
|
+
*/
|
|
251
|
+
sortingClass?: string;
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Duration of the reorder animation in milliseconds.
|
|
255
|
+
* @default 200
|
|
256
|
+
*/
|
|
257
|
+
animationDuration?: number;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Whether sorting is initially disabled.
|
|
261
|
+
* @default false
|
|
262
|
+
*/
|
|
263
|
+
disabled?: boolean;
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Called when sorting starts.
|
|
267
|
+
*/
|
|
268
|
+
onSortStart?: (data: SortEventData) => void;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Called when an item is moved to a new position.
|
|
272
|
+
*/
|
|
273
|
+
onSortMove?: (data: SortEventData) => void;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Called when sorting ends and the item is placed.
|
|
277
|
+
*/
|
|
278
|
+
onSortEnd?: (data: SortEventData) => void;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Handle returned by `sortable()` for controlling the sortable list.
|
|
283
|
+
*/
|
|
284
|
+
export interface SortableHandle {
|
|
285
|
+
/** Remove all event listeners and clean up. */
|
|
286
|
+
destroy: () => void;
|
|
287
|
+
/** Disable sorting. */
|
|
288
|
+
disable: () => void;
|
|
289
|
+
/** Re-enable sorting. */
|
|
290
|
+
enable: () => void;
|
|
291
|
+
/** Whether sorting is currently enabled. */
|
|
292
|
+
readonly enabled: boolean;
|
|
293
|
+
}
|