@sprawlify/primitives 0.0.110 → 0.0.112
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/{aria-hidden-BX4SWNE_.mjs → aria-hidden-C72KtklN.mjs} +1 -1
- package/dist/{aria-hidden-BAGrxNHt.cjs → aria-hidden-CIBHXlCy.cjs} +1 -1
- package/dist/aria-hidden.cjs +2 -2
- package/dist/aria-hidden.mjs +2 -2
- package/dist/{auto-resize-B1BDDnp1.cjs → auto-resize-BTTNXiml.cjs} +1 -1
- package/dist/{auto-resize-CN2vAzdj.mjs → auto-resize-CbNgN0OO.mjs} +1 -1
- package/dist/auto-resize.cjs +2 -2
- package/dist/auto-resize.mjs +2 -2
- package/dist/{core-BmIEKqtP.mjs → core-Ci9Yu6QI.mjs} +1 -1
- package/dist/{core-nBg9RC_y.cjs → core-DwdPztGA.cjs} +1 -1
- package/dist/core.cjs +2 -2
- package/dist/core.mjs +2 -2
- package/dist/{dismissable-DWfZGIA7.mjs → dismissable-B9k5K6f9.mjs} +2 -2
- package/dist/{dismissable-ChwcJMHk.cjs → dismissable-DxjbwsOf.cjs} +2 -2
- package/dist/dismissable.cjs +3 -3
- package/dist/dismissable.mjs +3 -3
- package/dist/{dom-query-s2ESLR2U.mjs → dom-query-BFuRs3l4.mjs} +1 -1
- package/dist/{dom-query-Bd63cRVF.cjs → dom-query-BUO7rGsg.cjs} +1 -1
- package/dist/dom-query.cjs +1 -1
- package/dist/dom-query.mjs +1 -1
- package/dist/{focus-trap-fucc6OU_.cjs → focus-trap-BewqTQFt.cjs} +1 -1
- package/dist/{focus-trap-DzBvBlTH.mjs → focus-trap-Do8IUXYh.mjs} +1 -1
- package/dist/focus-trap.cjs +2 -2
- package/dist/focus-trap.mjs +2 -2
- package/dist/{focus-visible-D5qBaAOn.mjs → focus-visible-BuLf8M9F.mjs} +10 -9
- package/dist/{focus-visible-75XTctXf.cjs → focus-visible-Co_9bW09.cjs} +15 -8
- package/dist/focus-visible.cjs +3 -2
- package/dist/focus-visible.d.cts +2 -1
- package/dist/focus-visible.d.mts +2 -1
- package/dist/focus-visible.mjs +3 -3
- package/dist/{i18n-utils-DB-lUfrr.cjs → i18n-utils-BRLqoCq8.cjs} +1 -1
- package/dist/{i18n-utils-oWZyUib_.mjs → i18n-utils-DZs1CPj8.mjs} +1 -1
- package/dist/i18n-utils.cjs +2 -2
- package/dist/i18n-utils.mjs +2 -2
- package/dist/{interact-outside-2qkUnl4N.mjs → interact-outside-Ba50N1a5.mjs} +1 -1
- package/dist/{interact-outside-Cx4J0EBf.cjs → interact-outside-Bg-QSXqp.cjs} +1 -1
- package/dist/interact-outside.cjs +2 -2
- package/dist/interact-outside.mjs +2 -2
- package/dist/machines/accordion/index.cjs +2 -2
- package/dist/machines/accordion/index.d.cts +1 -1
- package/dist/machines/accordion/index.d.mts +1 -1
- package/dist/machines/accordion/index.mjs +2 -2
- package/dist/machines/angle-slider/index.cjs +2 -2
- package/dist/machines/angle-slider/index.d.cts +1 -1
- package/dist/machines/angle-slider/index.d.mts +1 -1
- package/dist/machines/angle-slider/index.mjs +2 -2
- package/dist/machines/aspect-ratio/index.cjs +2 -2
- package/dist/machines/aspect-ratio/index.mjs +2 -2
- package/dist/machines/async-list/index.cjs +2 -2
- package/dist/machines/async-list/index.mjs +2 -2
- package/dist/machines/avatar/index.cjs +2 -2
- package/dist/machines/avatar/index.mjs +2 -2
- package/dist/machines/carousel/index.cjs +3 -3
- package/dist/machines/carousel/index.d.cts +1 -1
- package/dist/machines/carousel/index.d.mts +1 -1
- package/dist/machines/carousel/index.mjs +3 -3
- package/dist/machines/cascade-select/index.cjs +12 -7
- package/dist/machines/cascade-select/index.d.cts +2 -2
- package/dist/machines/cascade-select/index.d.mts +2 -2
- package/dist/machines/cascade-select/index.mjs +12 -7
- package/dist/machines/checkbox/index.cjs +3 -3
- package/dist/machines/checkbox/index.d.cts +1 -1
- package/dist/machines/checkbox/index.d.mts +1 -1
- package/dist/machines/checkbox/index.mjs +3 -3
- package/dist/machines/clipboard/index.cjs +2 -2
- package/dist/machines/clipboard/index.d.cts +1 -1
- package/dist/machines/clipboard/index.d.mts +1 -1
- package/dist/machines/clipboard/index.mjs +2 -2
- package/dist/machines/collapsible/index.cjs +2 -2
- package/dist/machines/collapsible/index.d.cts +1 -1
- package/dist/machines/collapsible/index.d.mts +1 -1
- package/dist/machines/collapsible/index.mjs +2 -2
- package/dist/machines/color-picker/index.cjs +5 -5
- package/dist/machines/color-picker/index.d.cts +1 -1
- package/dist/machines/color-picker/index.d.mts +1 -1
- package/dist/machines/color-picker/index.mjs +5 -5
- package/dist/machines/combobox/index.cjs +14 -8
- package/dist/machines/combobox/index.d.cts +1 -1
- package/dist/machines/combobox/index.d.mts +1 -1
- package/dist/machines/combobox/index.mjs +14 -8
- package/dist/machines/date-picker/index.cjs +5 -5
- package/dist/machines/date-picker/index.d.cts +1 -1
- package/dist/machines/date-picker/index.d.mts +1 -1
- package/dist/machines/date-picker/index.mjs +5 -5
- package/dist/machines/dialog/index.cjs +7 -7
- package/dist/machines/dialog/index.d.cts +1 -1
- package/dist/machines/dialog/index.d.mts +1 -1
- package/dist/machines/dialog/index.mjs +7 -7
- package/dist/machines/drawer/index.cjs +1574 -307
- package/dist/machines/drawer/index.d.cts +217 -35
- package/dist/machines/drawer/index.d.mts +217 -35
- package/dist/machines/drawer/index.mjs +1574 -309
- package/dist/machines/dropdown-menu/index.cjs +12 -7
- package/dist/machines/dropdown-menu/index.d.cts +1 -1
- package/dist/machines/dropdown-menu/index.d.mts +1 -1
- package/dist/machines/dropdown-menu/index.mjs +12 -7
- package/dist/machines/editable/index.cjs +3 -3
- package/dist/machines/editable/index.mjs +3 -3
- package/dist/machines/file-upload/index.cjs +3 -3
- package/dist/machines/file-upload/index.d.cts +1 -1
- package/dist/machines/file-upload/index.d.mts +1 -1
- package/dist/machines/file-upload/index.mjs +3 -3
- package/dist/machines/floating-panel/index.cjs +2 -2
- package/dist/machines/floating-panel/index.d.cts +1 -1
- package/dist/machines/floating-panel/index.d.mts +1 -1
- package/dist/machines/floating-panel/index.mjs +2 -2
- package/dist/machines/hover-card/index.cjs +5 -5
- package/dist/machines/hover-card/index.mjs +5 -5
- package/dist/machines/image-cropper/index.cjs +2 -2
- package/dist/machines/image-cropper/index.d.cts +1 -1
- package/dist/machines/image-cropper/index.d.mts +1 -1
- package/dist/machines/image-cropper/index.mjs +2 -2
- package/dist/machines/listbox/index.cjs +3 -3
- package/dist/machines/listbox/index.d.cts +1 -1
- package/dist/machines/listbox/index.d.mts +1 -1
- package/dist/machines/listbox/index.mjs +3 -3
- package/dist/machines/marquee/index.cjs +2 -2
- package/dist/machines/marquee/index.d.cts +3 -3
- package/dist/machines/marquee/index.d.mts +3 -3
- package/dist/machines/marquee/index.mjs +2 -2
- package/dist/machines/navigation-menu/index.cjs +4 -4
- package/dist/machines/navigation-menu/index.d.cts +1 -1
- package/dist/machines/navigation-menu/index.d.mts +1 -1
- package/dist/machines/navigation-menu/index.mjs +4 -4
- package/dist/machines/number-input/index.cjs +2 -2
- package/dist/machines/number-input/index.mjs +2 -2
- package/dist/machines/pagination/index.cjs +2 -2
- package/dist/machines/pagination/index.d.cts +1 -1
- package/dist/machines/pagination/index.d.mts +1 -1
- package/dist/machines/pagination/index.mjs +2 -2
- package/dist/machines/password-input/index.cjs +2 -2
- package/dist/machines/password-input/index.d.cts +1 -1
- package/dist/machines/password-input/index.d.mts +1 -1
- package/dist/machines/password-input/index.mjs +2 -2
- package/dist/machines/pin-input/index.cjs +2 -2
- package/dist/machines/pin-input/index.mjs +2 -2
- package/dist/machines/popover/index.cjs +8 -8
- package/dist/machines/popover/index.d.cts +1 -1
- package/dist/machines/popover/index.d.mts +1 -1
- package/dist/machines/popover/index.mjs +8 -8
- package/dist/machines/presence/index.cjs +2 -2
- package/dist/machines/presence/index.mjs +2 -2
- package/dist/machines/progress/index.cjs +2 -2
- package/dist/machines/progress/index.d.cts +1 -1
- package/dist/machines/progress/index.d.mts +1 -1
- package/dist/machines/progress/index.mjs +2 -2
- package/dist/machines/qr-code/index.cjs +2 -2
- package/dist/machines/qr-code/index.mjs +2 -2
- package/dist/machines/radio-group/index.cjs +3 -3
- package/dist/machines/radio-group/index.d.cts +1 -1
- package/dist/machines/radio-group/index.d.mts +1 -1
- package/dist/machines/radio-group/index.mjs +3 -3
- package/dist/machines/rating-group/index.cjs +2 -2
- package/dist/machines/rating-group/index.mjs +2 -2
- package/dist/machines/scroll-area/index.cjs +2 -2
- package/dist/machines/scroll-area/index.d.cts +1 -1
- package/dist/machines/scroll-area/index.d.mts +1 -1
- package/dist/machines/scroll-area/index.mjs +2 -2
- package/dist/machines/select/index.cjs +13 -8
- package/dist/machines/select/index.d.cts +1 -1
- package/dist/machines/select/index.d.mts +1 -1
- package/dist/machines/select/index.mjs +13 -8
- package/dist/machines/separator/index.cjs +2 -2
- package/dist/machines/separator/index.mjs +2 -2
- package/dist/machines/signature-pad/index.cjs +2 -2
- package/dist/machines/signature-pad/index.mjs +2 -2
- package/dist/machines/slider/index.cjs +2 -2
- package/dist/machines/slider/index.d.cts +1 -1
- package/dist/machines/slider/index.d.mts +1 -1
- package/dist/machines/slider/index.mjs +2 -2
- package/dist/machines/splitter/index.cjs +2 -2
- package/dist/machines/splitter/index.d.cts +1 -1
- package/dist/machines/splitter/index.d.mts +1 -1
- package/dist/machines/splitter/index.mjs +2 -2
- package/dist/machines/steps/index.cjs +2 -2
- package/dist/machines/steps/index.d.cts +1 -1
- package/dist/machines/steps/index.d.mts +1 -1
- package/dist/machines/steps/index.mjs +2 -2
- package/dist/machines/switch/index.cjs +3 -3
- package/dist/machines/switch/index.mjs +3 -3
- package/dist/machines/tabs/index.cjs +2 -2
- package/dist/machines/tabs/index.d.cts +1 -1
- package/dist/machines/tabs/index.d.mts +1 -1
- package/dist/machines/tabs/index.mjs +2 -2
- package/dist/machines/tags-input/index.cjs +4 -4
- package/dist/machines/tags-input/index.d.cts +1 -1
- package/dist/machines/tags-input/index.d.mts +1 -1
- package/dist/machines/tags-input/index.mjs +4 -4
- package/dist/machines/timer/index.cjs +2 -2
- package/dist/machines/timer/index.d.cts +1 -1
- package/dist/machines/timer/index.d.mts +1 -1
- package/dist/machines/timer/index.mjs +2 -2
- package/dist/machines/toast/index.cjs +4 -4
- package/dist/machines/toast/index.d.cts +3 -3
- package/dist/machines/toast/index.d.mts +3 -3
- package/dist/machines/toast/index.mjs +4 -4
- package/dist/machines/toggle/index.cjs +2 -2
- package/dist/machines/toggle/index.mjs +2 -2
- package/dist/machines/toggle-group/index.cjs +2 -2
- package/dist/machines/toggle-group/index.mjs +2 -2
- package/dist/machines/tooltip/index.cjs +9 -9
- package/dist/machines/tooltip/index.mjs +10 -10
- package/dist/machines/tour/index.cjs +6 -6
- package/dist/machines/tour/index.d.cts +1 -1
- package/dist/machines/tour/index.d.mts +1 -1
- package/dist/machines/tour/index.mjs +6 -6
- package/dist/machines/tree-view/index.cjs +2 -2
- package/dist/machines/tree-view/index.d.cts +1 -1
- package/dist/machines/tree-view/index.d.mts +1 -1
- package/dist/machines/tree-view/index.mjs +2 -2
- package/dist/{popper-BDy37WA0.mjs → popper-BlgbmdAn.mjs} +1 -1
- package/dist/{popper-Cx3KHzeT.cjs → popper-viCrafLC.cjs} +1 -1
- package/dist/popper.cjs +2 -2
- package/dist/popper.mjs +2 -2
- package/dist/{remove-scroll-D9FAOapi.cjs → remove-scroll-D4CMJmU2.cjs} +1 -1
- package/dist/{remove-scroll-HcSiTbd5.mjs → remove-scroll-D55GZoBb.mjs} +1 -1
- package/dist/{scroll-snap-DfSwN3As.mjs → scroll-snap-CdneVP31.mjs} +1 -1
- package/dist/{scroll-snap-Dp_2adEa.cjs → scroll-snap-vZ2q6dcN.cjs} +1 -1
- package/dist/scroll-snap.cjs +2 -2
- package/dist/scroll-snap.mjs +2 -2
- package/package.json +1 -1
|
@@ -1,47 +1,848 @@
|
|
|
1
1
|
import { t as createAnatomy } from "../../create-anatomy-Dr0evdYy.mjs";
|
|
2
|
-
import { St as isLeftClick, W as raf, ht as getEventTarget, m as resizeObserverBorderBox, pt as getEventPoint, ut as addDomEvent } from "../../dom-query-
|
|
2
|
+
import { $t as contains, D as disableTextSelection, G as getInitialFocus, Qt as getComputedStyle$1, St as isLeftClick, W as raf, fn as isHTMLElement, ht as getEventTarget, m as resizeObserverBorderBox, pn as isInputElement, pt as getEventPoint, un as isEditableElement, ut as addDomEvent } from "../../dom-query-BFuRs3l4.mjs";
|
|
3
3
|
import { t as _defineProperty } from "../../defineProperty-D5oW_HU_.mjs";
|
|
4
|
-
import { t as ariaHidden } from "../../aria-hidden-
|
|
5
|
-
import { H as toPx, u as createSplitProps } from "../../utils-VVoZ_v29.mjs";
|
|
6
|
-
import { a as createMachine } from "../../core-
|
|
7
|
-
import "../../interact-outside-
|
|
8
|
-
import { n as trackDismissableElement } from "../../dismissable-
|
|
9
|
-
import { t as trapFocus } from "../../focus-trap-
|
|
4
|
+
import { t as ariaHidden } from "../../aria-hidden-C72KtklN.mjs";
|
|
5
|
+
import { H as toPx, g as clampValue, l as compact, u as createSplitProps } from "../../utils-VVoZ_v29.mjs";
|
|
6
|
+
import { a as createMachine, i as createGuards } from "../../core-Ci9Yu6QI.mjs";
|
|
7
|
+
import "../../interact-outside-Ba50N1a5.mjs";
|
|
8
|
+
import { n as trackDismissableElement } from "../../dismissable-B9k5K6f9.mjs";
|
|
9
|
+
import { t as trapFocus } from "../../focus-trap-Do8IUXYh.mjs";
|
|
10
10
|
import { t as createProps } from "../../create-props-DFW8DUsC.mjs";
|
|
11
|
-
import { t as preventBodyScroll } from "../../remove-scroll-
|
|
11
|
+
import { t as preventBodyScroll } from "../../remove-scroll-D55GZoBb.mjs";
|
|
12
12
|
//#region src/machines/drawer/drawer.anatomy.ts
|
|
13
|
-
const anatomy = createAnatomy("drawer").parts("content", "title", "trigger", "backdrop", "grabber", "grabberIndicator", "closeTrigger");
|
|
13
|
+
const anatomy = createAnatomy("drawer").parts("positioner", "content", "title", "description", "trigger", "backdrop", "grabber", "grabberIndicator", "closeTrigger", "swipeArea");
|
|
14
14
|
const parts = anatomy.build();
|
|
15
15
|
//#endregion
|
|
16
16
|
//#region src/machines/drawer/drawer.dom.ts
|
|
17
17
|
const getContentId = (ctx) => ctx.ids?.content ?? `drawer:${ctx.id}:content`;
|
|
18
|
+
const getPositionerId = (ctx) => ctx.ids?.positioner ?? `drawer:${ctx.id}:positioner`;
|
|
18
19
|
const getTitleId = (ctx) => ctx.ids?.title ?? `drawer:${ctx.id}:title`;
|
|
20
|
+
const getDescriptionId = (ctx) => ctx.ids?.description ?? `drawer:${ctx.id}:description`;
|
|
19
21
|
const getTriggerId = (ctx) => ctx.ids?.trigger ?? `drawer:${ctx.id}:trigger`;
|
|
20
22
|
const getBackdropId = (ctx) => ctx.ids?.backdrop ?? `drawer:${ctx.id}:backdrop`;
|
|
21
23
|
const getGrabberId = (ctx) => ctx.ids?.grabber ?? `drawer:${ctx.id}:grabber`;
|
|
22
24
|
const getGrabberIndicatorId = (ctx) => ctx.ids?.grabberIndicator ?? `drawer:${ctx.id}:grabber-indicator`;
|
|
23
25
|
const getCloseTriggerId = (ctx) => ctx.ids?.closeTrigger ?? `drawer:${ctx.id}:close-trigger`;
|
|
26
|
+
const getSwipeAreaId = (ctx) => ctx.ids?.swipeArea ?? `drawer:${ctx.id}:swipe-area`;
|
|
24
27
|
const getContentEl = (ctx) => ctx.getById(getContentId(ctx));
|
|
28
|
+
const getTitleEl = (ctx) => ctx.getById(getTitleId(ctx));
|
|
29
|
+
const getDescriptionEl = (ctx) => ctx.getById(getDescriptionId(ctx));
|
|
25
30
|
const getTriggerEl = (ctx) => ctx.getById(getTriggerId(ctx));
|
|
31
|
+
const getBackdropEl = (ctx) => ctx.getById(getBackdropId(ctx));
|
|
26
32
|
const getCloseTriggerEl = (ctx) => ctx.getById(getCloseTriggerId(ctx));
|
|
33
|
+
const getSwipeAreaEl = (ctx) => ctx.getById(getSwipeAreaId(ctx));
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/machines/drawer/utils/snap-point.ts
|
|
36
|
+
function resolveSnapPointValue(snapPoint, viewportSize, rootFontSize) {
|
|
37
|
+
if (!Number.isFinite(viewportSize) || viewportSize <= 0) return null;
|
|
38
|
+
if (typeof snapPoint === "number") {
|
|
39
|
+
if (!Number.isFinite(snapPoint)) return null;
|
|
40
|
+
if (snapPoint <= 1) return clampValue(snapPoint, 0, 1) * viewportSize;
|
|
41
|
+
return snapPoint;
|
|
42
|
+
}
|
|
43
|
+
const trimmed = snapPoint.trim();
|
|
44
|
+
if (trimmed.endsWith("px")) {
|
|
45
|
+
const value = Number.parseFloat(trimmed);
|
|
46
|
+
return Number.isFinite(value) ? value : null;
|
|
47
|
+
}
|
|
48
|
+
if (trimmed.endsWith("rem")) {
|
|
49
|
+
const value = Number.parseFloat(trimmed);
|
|
50
|
+
return Number.isFinite(value) ? value * rootFontSize : null;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
function resolveSnapPoint(snapPoint, options) {
|
|
55
|
+
const { contentSize, viewportSize, rootFontSize } = options;
|
|
56
|
+
const maxSize = Math.min(contentSize, viewportSize);
|
|
57
|
+
if (!Number.isFinite(maxSize) || maxSize <= 0) return null;
|
|
58
|
+
const resolvedSize = resolveSnapPointValue(snapPoint, viewportSize, rootFontSize);
|
|
59
|
+
if (resolvedSize === null || !Number.isFinite(resolvedSize)) return null;
|
|
60
|
+
const height = clampValue(resolvedSize, 0, maxSize);
|
|
61
|
+
return {
|
|
62
|
+
value: snapPoint,
|
|
63
|
+
height,
|
|
64
|
+
offset: Math.max(0, contentSize - height)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const HEIGHT_DEDUP_EPSILON_PX = 1;
|
|
68
|
+
function dedupeSnapPoints(points) {
|
|
69
|
+
if (points.length <= 1) return points;
|
|
70
|
+
const deduped = [];
|
|
71
|
+
const seenHeights = [];
|
|
72
|
+
for (let index = points.length - 1; index >= 0; index -= 1) {
|
|
73
|
+
const point = points[index];
|
|
74
|
+
if (seenHeights.some((height) => Math.abs(height - point.height) <= HEIGHT_DEDUP_EPSILON_PX)) continue;
|
|
75
|
+
seenHeights.push(point.height);
|
|
76
|
+
deduped.push(point);
|
|
77
|
+
}
|
|
78
|
+
deduped.reverse();
|
|
79
|
+
return deduped;
|
|
80
|
+
}
|
|
81
|
+
function findClosestSnapPoint(offset, snapPoints) {
|
|
82
|
+
return snapPoints.reduce((acc, curr) => {
|
|
83
|
+
const closestDiff = Math.abs(offset - acc.offset);
|
|
84
|
+
return Math.abs(offset - curr.offset) < closestDiff ? curr : acc;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/machines/drawer/utils/session.ts
|
|
89
|
+
const VELOCITY_WINDOW_MS = 100;
|
|
90
|
+
const MAX_RELEASE_VELOCITY_AGE_MS = 80;
|
|
91
|
+
const MIN_GESTURE_DURATION_MS = 50;
|
|
92
|
+
const MIN_VELOCITY_SAMPLES = 2;
|
|
93
|
+
const SAMPLE_BUFFER_COMPACT_THRESHOLD = 8;
|
|
94
|
+
const DEFERRED_DRAG_MIN_MAIN_AXIS_PX = 6;
|
|
95
|
+
const DEFERRED_DRAG_MAIN_OVER_CROSS_RATIO = 1.35;
|
|
96
|
+
function isVerticalSwipeDirection(direction) {
|
|
97
|
+
return direction === "down" || direction === "up";
|
|
98
|
+
}
|
|
99
|
+
function isNegativeSwipeDirection(direction) {
|
|
100
|
+
return direction === "up" || direction === "left";
|
|
101
|
+
}
|
|
102
|
+
var SwipeSession = class {
|
|
103
|
+
constructor() {
|
|
104
|
+
_defineProperty(this, "startPoint", null);
|
|
105
|
+
_defineProperty(this, "velocity", null);
|
|
106
|
+
_defineProperty(this, "samples", []);
|
|
107
|
+
_defineProperty(this, "sampleStartIndex", 0);
|
|
108
|
+
_defineProperty(this, "gestureStartAxis", null);
|
|
109
|
+
_defineProperty(this, "gestureStartTime", null);
|
|
110
|
+
_defineProperty(this, "gestureSign", 1);
|
|
111
|
+
_defineProperty(this, "pendingSwipe", null);
|
|
112
|
+
}
|
|
113
|
+
setStartPoint(point) {
|
|
114
|
+
this.startPoint = point;
|
|
115
|
+
}
|
|
116
|
+
clearStartPoint() {
|
|
117
|
+
this.startPoint = null;
|
|
118
|
+
}
|
|
119
|
+
getStartPoint() {
|
|
120
|
+
return this.startPoint;
|
|
121
|
+
}
|
|
122
|
+
getGestureAxis(direction) {
|
|
123
|
+
return direction === "left" || direction === "right" ? "x" : "y";
|
|
124
|
+
}
|
|
125
|
+
getGestureSign(direction) {
|
|
126
|
+
return isNegativeSwipeDirection(direction) ? -1 : 1;
|
|
127
|
+
}
|
|
128
|
+
getAxisValue(point, axis) {
|
|
129
|
+
return point[axis];
|
|
130
|
+
}
|
|
131
|
+
getMainAxisDisplacement(point, axis, sign) {
|
|
132
|
+
if (!this.startPoint) return 0;
|
|
133
|
+
return (this.getAxisValue(this.startPoint, axis) - this.getAxisValue(point, axis)) * sign;
|
|
134
|
+
}
|
|
135
|
+
getCrossAxisDisplacement(point, axis) {
|
|
136
|
+
if (!this.startPoint) return 0;
|
|
137
|
+
const crossAxis = axis === "x" ? "y" : "x";
|
|
138
|
+
const startAxis = this.getAxisValue(this.startPoint, crossAxis);
|
|
139
|
+
return this.getAxisValue(point, crossAxis) - startAxis;
|
|
140
|
+
}
|
|
141
|
+
track(point, axis, sign) {
|
|
142
|
+
const axisValue = this.getAxisValue(point, axis);
|
|
143
|
+
const now = performance.now();
|
|
144
|
+
if (this.gestureStartAxis === null) {
|
|
145
|
+
this.gestureStartAxis = axisValue;
|
|
146
|
+
this.gestureStartTime = now;
|
|
147
|
+
this.gestureSign = sign;
|
|
148
|
+
}
|
|
149
|
+
this.samples.push({
|
|
150
|
+
axis: axisValue,
|
|
151
|
+
time: now
|
|
152
|
+
});
|
|
153
|
+
const cutoff = now - VELOCITY_WINDOW_MS;
|
|
154
|
+
while (this.sampleStartIndex < this.samples.length && this.samples[this.sampleStartIndex].time < cutoff) this.sampleStartIndex += 1;
|
|
155
|
+
if (this.sampleStartIndex >= SAMPLE_BUFFER_COMPACT_THRESHOLD) {
|
|
156
|
+
this.samples = this.samples.slice(this.sampleStartIndex);
|
|
157
|
+
this.sampleStartIndex = 0;
|
|
158
|
+
}
|
|
159
|
+
if (this.samples.length - this.sampleStartIndex < MIN_VELOCITY_SAMPLES) {
|
|
160
|
+
this.velocity = 0;
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const oldest = this.samples[this.sampleStartIndex];
|
|
164
|
+
const newest = this.samples[this.samples.length - 1];
|
|
165
|
+
const dt = newest.time - oldest.time;
|
|
166
|
+
if (dt <= 0) {
|
|
167
|
+
this.velocity = 0;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const velocity = (newest.axis - oldest.axis) * sign / dt * 1e3;
|
|
171
|
+
this.velocity = Number.isFinite(velocity) ? velocity : 0;
|
|
172
|
+
}
|
|
173
|
+
getReleaseVelocity() {
|
|
174
|
+
const now = performance.now();
|
|
175
|
+
if (this.samples.length - this.sampleStartIndex >= MIN_VELOCITY_SAMPLES) {
|
|
176
|
+
if (now - this.samples[this.samples.length - 1].time <= MAX_RELEASE_VELOCITY_AGE_MS) return this.velocity ?? 0;
|
|
177
|
+
}
|
|
178
|
+
if (this.gestureStartAxis !== null && this.gestureStartTime !== null) {
|
|
179
|
+
const lastSample = this.samples[this.samples.length - 1];
|
|
180
|
+
if (lastSample) {
|
|
181
|
+
const dt = Math.max(lastSample.time - this.gestureStartTime, MIN_GESTURE_DURATION_MS);
|
|
182
|
+
const velocity = (lastSample.axis - this.gestureStartAxis) * this.gestureSign / dt * 1e3;
|
|
183
|
+
return Number.isFinite(velocity) ? velocity : 0;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return this.velocity ?? 0;
|
|
187
|
+
}
|
|
188
|
+
clearVelocityTracking() {
|
|
189
|
+
this.samples = [];
|
|
190
|
+
this.sampleStartIndex = 0;
|
|
191
|
+
this.velocity = null;
|
|
192
|
+
this.gestureStartAxis = null;
|
|
193
|
+
this.gestureStartTime = null;
|
|
194
|
+
this.gestureSign = 1;
|
|
195
|
+
}
|
|
196
|
+
clear() {
|
|
197
|
+
this.cancelDeferredSwipe();
|
|
198
|
+
this.clearStartPoint();
|
|
199
|
+
this.clearVelocityTracking();
|
|
200
|
+
}
|
|
201
|
+
startDeferredSwipe(options) {
|
|
202
|
+
const { getWin, pointerId, startPoint, swipeDirection, onCommit, canCommit, onCancel } = options;
|
|
203
|
+
this.cancelDeferredSwipe();
|
|
204
|
+
const win = getWin();
|
|
205
|
+
const vertical = isVerticalSwipeDirection(swipeDirection);
|
|
206
|
+
const onMove = (event) => {
|
|
207
|
+
if (event.pointerId !== pointerId) return;
|
|
208
|
+
const dx = event.clientX - startPoint.x;
|
|
209
|
+
const dy = event.clientY - startPoint.y;
|
|
210
|
+
const mainDelta = vertical ? dy : dx;
|
|
211
|
+
const crossDelta = vertical ? dx : dy;
|
|
212
|
+
const absMain = Math.abs(mainDelta);
|
|
213
|
+
if (absMain >= DEFERRED_DRAG_MIN_MAIN_AXIS_PX && absMain >= Math.abs(crossDelta) * DEFERRED_DRAG_MAIN_OVER_CROSS_RATIO) {
|
|
214
|
+
if (!canCommit || canCommit()) onCommit(startPoint);
|
|
215
|
+
this.cancelDeferredSwipe();
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
const onEnd = (event) => {
|
|
219
|
+
if (event.pointerId !== pointerId) return;
|
|
220
|
+
onCancel?.();
|
|
221
|
+
this.cancelDeferredSwipe();
|
|
222
|
+
};
|
|
223
|
+
this.pendingSwipe = {
|
|
224
|
+
pointerId,
|
|
225
|
+
startPoint,
|
|
226
|
+
cleanups: [
|
|
227
|
+
addDomEvent(win, "pointermove", onMove, { capture: true }),
|
|
228
|
+
addDomEvent(win, "pointerup", onEnd, { capture: true }),
|
|
229
|
+
addDomEvent(win, "pointercancel", onEnd, { capture: true }),
|
|
230
|
+
addDomEvent(win, "lostpointercapture", onEnd, { capture: true })
|
|
231
|
+
]
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
cancelDeferredSwipe() {
|
|
235
|
+
if (!this.pendingSwipe) return;
|
|
236
|
+
this.pendingSwipe.cleanups.forEach((cleanup) => cleanup());
|
|
237
|
+
this.pendingSwipe = null;
|
|
238
|
+
}
|
|
239
|
+
bind(options) {
|
|
240
|
+
const { getDoc, getSelectionTarget, swipeDirection, onStart, onMove, onEnd, onCancel, preventDefault, cancelOnInterrupt } = options;
|
|
241
|
+
const doc = getDoc();
|
|
242
|
+
let usingTouchEvents = false;
|
|
243
|
+
let restoreSelection;
|
|
244
|
+
const axis = this.getGestureAxis(swipeDirection);
|
|
245
|
+
const sign = this.getGestureSign(swipeDirection);
|
|
246
|
+
const trackPoint = (point) => {
|
|
247
|
+
this.track(point, axis, sign);
|
|
248
|
+
};
|
|
249
|
+
const startSelectionGuard = () => {
|
|
250
|
+
restoreSelection ?? (restoreSelection = disableTextSelection({
|
|
251
|
+
doc,
|
|
252
|
+
target: getSelectionTarget?.()
|
|
253
|
+
}));
|
|
254
|
+
};
|
|
255
|
+
const stopSelectionGuard = () => {
|
|
256
|
+
restoreSelection?.();
|
|
257
|
+
restoreSelection = void 0;
|
|
258
|
+
};
|
|
259
|
+
function onPointerMove(event) {
|
|
260
|
+
if (event.pointerType === "touch" && usingTouchEvents) return;
|
|
261
|
+
const point = getEventPoint(event);
|
|
262
|
+
const target = getEventTarget(event);
|
|
263
|
+
startSelectionGuard();
|
|
264
|
+
trackPoint(point);
|
|
265
|
+
onMove({
|
|
266
|
+
point,
|
|
267
|
+
target,
|
|
268
|
+
event,
|
|
269
|
+
pointerType: event.pointerType,
|
|
270
|
+
axis,
|
|
271
|
+
swipeDirection
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
function onPointerUp(event) {
|
|
275
|
+
if (event.pointerType === "touch" && usingTouchEvents) {
|
|
276
|
+
usingTouchEvents = false;
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
stopSelectionGuard();
|
|
280
|
+
onEnd({
|
|
281
|
+
point: getEventPoint(event),
|
|
282
|
+
swipeDirection
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
function onPointerCancel(event) {
|
|
286
|
+
if (event.pointerType === "touch" && usingTouchEvents) {
|
|
287
|
+
usingTouchEvents = false;
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
stopSelectionGuard();
|
|
291
|
+
onCancel();
|
|
292
|
+
}
|
|
293
|
+
function onTouchStartEvent(event) {
|
|
294
|
+
if (!event.touches[0]) return;
|
|
295
|
+
usingTouchEvents = true;
|
|
296
|
+
const point = getEventPoint(event);
|
|
297
|
+
const target = getEventTarget(event);
|
|
298
|
+
onStart?.({
|
|
299
|
+
point,
|
|
300
|
+
target,
|
|
301
|
+
event,
|
|
302
|
+
pointerType: "touch",
|
|
303
|
+
axis,
|
|
304
|
+
swipeDirection
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
function onTouchMoveEvent(event) {
|
|
308
|
+
if (!event.touches[0]) return;
|
|
309
|
+
usingTouchEvents = true;
|
|
310
|
+
const point = getEventPoint(event);
|
|
311
|
+
const details = {
|
|
312
|
+
point,
|
|
313
|
+
target: getEventTarget(event),
|
|
314
|
+
event,
|
|
315
|
+
pointerType: "touch",
|
|
316
|
+
axis,
|
|
317
|
+
swipeDirection
|
|
318
|
+
};
|
|
319
|
+
if (preventDefault?.(details) && event.cancelable) event.preventDefault();
|
|
320
|
+
startSelectionGuard();
|
|
321
|
+
trackPoint(point);
|
|
322
|
+
onMove(details);
|
|
323
|
+
}
|
|
324
|
+
function onTouchEnd(event) {
|
|
325
|
+
if (event.touches.length !== 0) return;
|
|
326
|
+
stopSelectionGuard();
|
|
327
|
+
onEnd({
|
|
328
|
+
point: getEventPoint(event),
|
|
329
|
+
swipeDirection
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
function onTouchCancel() {
|
|
333
|
+
stopSelectionGuard();
|
|
334
|
+
onCancel();
|
|
335
|
+
}
|
|
336
|
+
function onVisibilityChange() {
|
|
337
|
+
if (doc.visibilityState !== "hidden") return;
|
|
338
|
+
if (cancelOnInterrupt?.({
|
|
339
|
+
reason: "visibility-hidden",
|
|
340
|
+
event: doc,
|
|
341
|
+
target: null,
|
|
342
|
+
pointerType: null
|
|
343
|
+
}) === false) return;
|
|
344
|
+
stopSelectionGuard();
|
|
345
|
+
onCancel();
|
|
346
|
+
}
|
|
347
|
+
function onLostPointerCapture(event) {
|
|
348
|
+
if (event.pointerType === "touch") return;
|
|
349
|
+
const target = getEventTarget(event);
|
|
350
|
+
if (cancelOnInterrupt?.({
|
|
351
|
+
reason: "lost-pointer-capture",
|
|
352
|
+
event,
|
|
353
|
+
target,
|
|
354
|
+
pointerType: event.pointerType
|
|
355
|
+
}) === false) return;
|
|
356
|
+
onCancel();
|
|
357
|
+
}
|
|
358
|
+
const cleanups = [
|
|
359
|
+
addDomEvent(doc, "pointermove", onPointerMove),
|
|
360
|
+
addDomEvent(doc, "pointerup", onPointerUp),
|
|
361
|
+
addDomEvent(doc, "pointercancel", onPointerCancel),
|
|
362
|
+
addDomEvent(doc, "touchstart", onTouchStartEvent, {
|
|
363
|
+
capture: true,
|
|
364
|
+
passive: false
|
|
365
|
+
}),
|
|
366
|
+
addDomEvent(doc, "touchmove", onTouchMoveEvent, {
|
|
367
|
+
capture: true,
|
|
368
|
+
passive: false
|
|
369
|
+
}),
|
|
370
|
+
addDomEvent(doc, "touchend", onTouchEnd, { capture: true }),
|
|
371
|
+
addDomEvent(doc, "touchcancel", onTouchCancel, { capture: true }),
|
|
372
|
+
addDomEvent(doc, "visibilitychange", onVisibilityChange),
|
|
373
|
+
addDomEvent(doc, "lostpointercapture", onLostPointerCapture, true)
|
|
374
|
+
];
|
|
375
|
+
return () => {
|
|
376
|
+
stopSelectionGuard();
|
|
377
|
+
cleanups.forEach((cleanup) => cleanup());
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
//#endregion
|
|
382
|
+
//#region src/machines/drawer/utils/drawer-session.ts
|
|
383
|
+
const RELEASE_DISPLACEMENT_TRUST_PX = 24;
|
|
384
|
+
const OPEN_SWIPE_HIDDEN_VISIBLE_RATIO = .22;
|
|
385
|
+
const OPEN_SWIPE_HIDDEN_VELOCITY_MULTIPLIER = 1.25;
|
|
386
|
+
const OPEN_SWIPE_REVEALED_VISIBLE_RATIO = .5;
|
|
387
|
+
const OPEN_SWIPE_REVEALED_OPPOSING_MAX_ABS_VELOCITY = 650;
|
|
388
|
+
const DRAG_START_THRESHOLD = .3;
|
|
389
|
+
const CROSS_AXIS_BIAS = .58;
|
|
390
|
+
const SCROLL_SLACK_GATE = .5;
|
|
391
|
+
const SCROLL_SLACK_EPSILON = 1;
|
|
392
|
+
const SEQUENTIAL_THRESHOLD = 24;
|
|
393
|
+
const SNAP_VELOCITY_THRESHOLD = 400;
|
|
394
|
+
const SNAP_VELOCITY_MULTIPLIER = .4;
|
|
395
|
+
const MAX_SNAP_VELOCITY = 4e3;
|
|
396
|
+
const SWIPE_STRENGTH_MAX_DURATION_MS = 360;
|
|
397
|
+
const SWIPE_STRENGTH_MIN_SCALAR = .1;
|
|
398
|
+
const SWIPE_STRENGTH_MAX_SCALAR = 1;
|
|
399
|
+
const SWIPE_AREA_OPEN_INTENT_MIN_PX = 5;
|
|
400
|
+
const NO_DRAG_DATA_ATTR = "data-no-drag";
|
|
401
|
+
const NO_DRAG_SELECTOR = `[${NO_DRAG_DATA_ATTR}]`;
|
|
402
|
+
var DrawerSwipeSession = class {
|
|
403
|
+
constructor(options) {
|
|
404
|
+
_defineProperty(this, "session", new SwipeSession());
|
|
405
|
+
_defineProperty(this, "dragOffset", null);
|
|
406
|
+
_defineProperty(this, "preventDragOnScroll", void 0);
|
|
407
|
+
this.preventDragOnScroll = options.preventDragOnScroll;
|
|
408
|
+
}
|
|
409
|
+
contentPointerDown(options) {
|
|
410
|
+
const { event, getDoc, getContentEl, getWin, swipeDirection, canCommit, onCommit } = options;
|
|
411
|
+
if (shouldIgnorePointerDownForDrag(event)) return;
|
|
412
|
+
if (isTextSelectionInDrawer(getDoc(), getContentEl())) return;
|
|
413
|
+
if (!canCommit()) return;
|
|
414
|
+
const point = getEventPoint(event);
|
|
415
|
+
if (!(event.pointerType === "mouse" || event.pointerType === "pen")) {
|
|
416
|
+
onCommit(point);
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
this.session.startDeferredSwipe({
|
|
420
|
+
getWin,
|
|
421
|
+
pointerId: event.pointerId,
|
|
422
|
+
startPoint: point,
|
|
423
|
+
swipeDirection,
|
|
424
|
+
onCommit,
|
|
425
|
+
canCommit
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
grabberPointerDown(options) {
|
|
429
|
+
const { event, point, canCommit, onCommit } = options;
|
|
430
|
+
if (shouldIgnorePointerDownForDrag(event)) return;
|
|
431
|
+
this.session.cancelDeferredSwipe();
|
|
432
|
+
if (!canCommit()) return;
|
|
433
|
+
onCommit(point);
|
|
434
|
+
}
|
|
435
|
+
adjustReleaseVelocityAgainstDisplacement(velocity, displacementFromSnap) {
|
|
436
|
+
const displacementSign = Math.sign(displacementFromSnap);
|
|
437
|
+
const velocitySign = Math.sign(velocity);
|
|
438
|
+
if (displacementSign !== 0 && Math.abs(displacementFromSnap) >= RELEASE_DISPLACEMENT_TRUST_PX && velocitySign !== 0 && velocitySign !== displacementSign) return 0;
|
|
439
|
+
return velocity;
|
|
440
|
+
}
|
|
441
|
+
adjustReleaseVelocityForOpenSwipe(velocity, visibleRatio, swipeVelocityThreshold) {
|
|
442
|
+
if (visibleRatio < OPEN_SWIPE_HIDDEN_VISIBLE_RATIO && velocity < 0 && Math.abs(velocity) < swipeVelocityThreshold * OPEN_SWIPE_HIDDEN_VELOCITY_MULTIPLIER) return 0;
|
|
443
|
+
if (visibleRatio > OPEN_SWIPE_REVEALED_VISIBLE_RATIO && velocity > 0 && Math.abs(velocity) < OPEN_SWIPE_REVEALED_OPPOSING_MAX_ABS_VELOCITY) return 0;
|
|
444
|
+
return velocity;
|
|
445
|
+
}
|
|
446
|
+
beginSwipe(point) {
|
|
447
|
+
this.session.setStartPoint(point);
|
|
448
|
+
}
|
|
449
|
+
clearSwipeStart() {
|
|
450
|
+
this.session.clearStartPoint();
|
|
451
|
+
}
|
|
452
|
+
getSwipeStart() {
|
|
453
|
+
return this.session.getStartPoint();
|
|
454
|
+
}
|
|
455
|
+
getDragOffset() {
|
|
456
|
+
return this.dragOffset;
|
|
457
|
+
}
|
|
458
|
+
resetDragOffset() {
|
|
459
|
+
this.dragOffset = null;
|
|
460
|
+
}
|
|
461
|
+
resetVelocity() {
|
|
462
|
+
this.session.clearVelocityTracking();
|
|
463
|
+
}
|
|
464
|
+
reset() {
|
|
465
|
+
this.dragOffset = null;
|
|
466
|
+
this.session.clear();
|
|
467
|
+
}
|
|
468
|
+
setDragOffset(point, resolvedActiveSnapPointOffset, direction) {
|
|
469
|
+
if (!this.session.getStartPoint()) {
|
|
470
|
+
this.dragOffset = null;
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
const axis = this.session.getGestureAxis(direction);
|
|
474
|
+
const sign = this.session.getGestureSign(direction);
|
|
475
|
+
let delta = this.session.getMainAxisDisplacement(point, axis, sign) - resolvedActiveSnapPointOffset;
|
|
476
|
+
if (delta > 0) delta = Math.sqrt(delta);
|
|
477
|
+
this.dragOffset = -delta;
|
|
478
|
+
}
|
|
479
|
+
setSwipeOpenOffset(point, contentSize, direction) {
|
|
480
|
+
if (!this.session.getStartPoint()) {
|
|
481
|
+
this.dragOffset = null;
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const axis = this.session.getGestureAxis(direction);
|
|
485
|
+
const sign = this.session.getGestureSign(direction);
|
|
486
|
+
const openDisplacement = this.session.getMainAxisDisplacement(point, axis, sign);
|
|
487
|
+
let dragOffset = contentSize - Math.max(0, openDisplacement);
|
|
488
|
+
if (dragOffset < 0) dragOffset = -Math.sqrt(Math.abs(dragOffset));
|
|
489
|
+
this.dragOffset = dragOffset;
|
|
490
|
+
}
|
|
491
|
+
canStartDrag(point, target, container, preventDragOnScroll, direction) {
|
|
492
|
+
if (!isHTMLElement(target)) return false;
|
|
493
|
+
if (isDragExemptElement(target)) return false;
|
|
494
|
+
if (!this.session.getStartPoint() || !container) return false;
|
|
495
|
+
if (!preventDragOnScroll) return true;
|
|
496
|
+
const axis = this.session.getGestureAxis(direction);
|
|
497
|
+
const sign = this.session.getGestureSign(direction);
|
|
498
|
+
const delta = this.session.getMainAxisDisplacement(point, axis, sign);
|
|
499
|
+
if (Math.abs(delta) < DRAG_START_THRESHOLD) return false;
|
|
500
|
+
if (Math.abs(this.session.getCrossAxisDisplacement(point, axis)) > Math.abs(delta) * CROSS_AXIS_BIAS) {
|
|
501
|
+
const crossScroll = getScrollInfo(target, container, isVerticalSwipeDirection(direction) ? "right" : "down");
|
|
502
|
+
if (crossScroll.availableForwardScroll > SCROLL_SLACK_GATE || crossScroll.availableBackwardScroll > SCROLL_SLACK_GATE) return false;
|
|
503
|
+
}
|
|
504
|
+
const { availableForwardScroll, availableBackwardScroll } = getScrollInfo(target, container, direction);
|
|
505
|
+
if (delta > 0 && availableForwardScroll > SCROLL_SLACK_GATE || delta < 0 && availableBackwardScroll > SCROLL_SLACK_GATE) return false;
|
|
506
|
+
return true;
|
|
507
|
+
}
|
|
508
|
+
resolveSnapPointOnRelease(snapPoints, snapPoint, snapToSequentialPoints, contentSize) {
|
|
509
|
+
const dragOffset = this.dragOffset;
|
|
510
|
+
if (dragOffset === null) return snapPoints[0]?.value ?? 1;
|
|
511
|
+
const releaseVelocity = this.session.getReleaseVelocity();
|
|
512
|
+
if (snapToSequentialPoints && snapPoint) {
|
|
513
|
+
const ordered = [...snapPoints].sort((a, b) => a.offset - b.offset);
|
|
514
|
+
let currentIndex = 0;
|
|
515
|
+
let closestDist = Math.abs(snapPoint.offset - ordered[0].offset);
|
|
516
|
+
for (let i = 1; i < ordered.length; i++) {
|
|
517
|
+
const dist = Math.abs(snapPoint.offset - ordered[i].offset);
|
|
518
|
+
if (dist < closestDist) {
|
|
519
|
+
closestDist = dist;
|
|
520
|
+
currentIndex = i;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
const currentPoint = ordered[currentIndex];
|
|
524
|
+
const delta = dragOffset - currentPoint.offset;
|
|
525
|
+
const dragDirection = Math.sign(delta);
|
|
526
|
+
const velocityAdjusted = this.adjustReleaseVelocityAgainstDisplacement(releaseVelocity, delta);
|
|
527
|
+
const velocityDirection = Math.sign(velocityAdjusted);
|
|
528
|
+
let targetSnapPoint = currentPoint;
|
|
529
|
+
let effectiveTargetOffset = dragOffset;
|
|
530
|
+
if (dragDirection !== 0 && velocityDirection === dragDirection && Math.abs(velocityAdjusted) >= SNAP_VELOCITY_THRESHOLD) {
|
|
531
|
+
const adjacentIndex = Math.min(Math.max(currentIndex + dragDirection, 0), ordered.length - 1);
|
|
532
|
+
if (adjacentIndex !== currentIndex) {
|
|
533
|
+
targetSnapPoint = ordered[adjacentIndex];
|
|
534
|
+
effectiveTargetOffset = targetSnapPoint.offset;
|
|
535
|
+
} else if (dragDirection > 0) return null;
|
|
536
|
+
} else if (delta > SEQUENTIAL_THRESHOLD) {
|
|
537
|
+
const nextPoint = ordered[Math.min(currentIndex + 1, ordered.length - 1)];
|
|
538
|
+
if (nextPoint) {
|
|
539
|
+
targetSnapPoint = nextPoint;
|
|
540
|
+
effectiveTargetOffset = nextPoint.offset;
|
|
541
|
+
}
|
|
542
|
+
} else if (delta < -SEQUENTIAL_THRESHOLD) {
|
|
543
|
+
const prevPoint = ordered[Math.max(currentIndex - 1, 0)];
|
|
544
|
+
if (prevPoint) {
|
|
545
|
+
targetSnapPoint = prevPoint;
|
|
546
|
+
effectiveTargetOffset = prevPoint.offset;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
if (Math.abs(effectiveTargetOffset - contentSize) < Math.abs(effectiveTargetOffset - targetSnapPoint.offset)) return null;
|
|
550
|
+
return targetSnapPoint.value;
|
|
551
|
+
}
|
|
552
|
+
const snapRestOffset = snapPoint?.offset ?? 0;
|
|
553
|
+
const velocity = this.adjustReleaseVelocityAgainstDisplacement(releaseVelocity, dragOffset - snapRestOffset);
|
|
554
|
+
let targetOffset = dragOffset;
|
|
555
|
+
if (Math.abs(velocity) >= SNAP_VELOCITY_THRESHOLD) {
|
|
556
|
+
const clamped = clampValue(velocity, -MAX_SNAP_VELOCITY, MAX_SNAP_VELOCITY);
|
|
557
|
+
targetOffset += clamped * SNAP_VELOCITY_MULTIPLIER;
|
|
558
|
+
targetOffset = Math.max(0, targetOffset);
|
|
559
|
+
}
|
|
560
|
+
return findClosestSnapPoint(targetOffset, snapPoints).value;
|
|
561
|
+
}
|
|
562
|
+
shouldOpenOnRelease(contentSize, swipeVelocityThreshold, openThreshold) {
|
|
563
|
+
const dragOffset = this.dragOffset;
|
|
564
|
+
if (dragOffset === null || contentSize === null) return false;
|
|
565
|
+
const visibleSize = contentSize - dragOffset;
|
|
566
|
+
const visibleRatio = visibleSize / contentSize;
|
|
567
|
+
const velocity = this.adjustReleaseVelocityForOpenSwipe(this.session.getReleaseVelocity(), visibleRatio, swipeVelocityThreshold);
|
|
568
|
+
return velocity < 0 && Math.abs(velocity) >= swipeVelocityThreshold || visibleSize >= contentSize * openThreshold;
|
|
569
|
+
}
|
|
570
|
+
shouldDismissOnRelease(contentSize, snapPoints, resolvedSnapOffset) {
|
|
571
|
+
const dragOffset = this.dragOffset;
|
|
572
|
+
if (dragOffset === null || contentSize === null) return false;
|
|
573
|
+
const velocity = this.adjustReleaseVelocityAgainstDisplacement(this.session.getReleaseVelocity(), dragOffset - resolvedSnapOffset);
|
|
574
|
+
if (contentSize - dragOffset <= 0) return true;
|
|
575
|
+
let targetOffset = dragOffset;
|
|
576
|
+
if (Math.abs(velocity) >= SNAP_VELOCITY_THRESHOLD) {
|
|
577
|
+
const clamped = clampValue(velocity, -MAX_SNAP_VELOCITY, MAX_SNAP_VELOCITY);
|
|
578
|
+
targetOffset += clamped * SNAP_VELOCITY_MULTIPLIER;
|
|
579
|
+
targetOffset = Math.max(0, targetOffset);
|
|
580
|
+
}
|
|
581
|
+
const closeDistance = Math.abs(targetOffset - contentSize);
|
|
582
|
+
const closest = findClosestSnapPoint(targetOffset, snapPoints);
|
|
583
|
+
return closeDistance < Math.abs(targetOffset - closest.offset);
|
|
584
|
+
}
|
|
585
|
+
getSwipeStrength(targetOffset, resolvedSnapOffset = null) {
|
|
586
|
+
const dragOffset = this.dragOffset;
|
|
587
|
+
if (dragOffset === null) return SWIPE_STRENGTH_MAX_SCALAR;
|
|
588
|
+
let velocity = this.session.getReleaseVelocity();
|
|
589
|
+
if (resolvedSnapOffset != null) velocity = this.adjustReleaseVelocityAgainstDisplacement(velocity, dragOffset - resolvedSnapOffset);
|
|
590
|
+
const distance = Math.abs(dragOffset - targetOffset);
|
|
591
|
+
const absVelocity = Math.abs(velocity);
|
|
592
|
+
if (absVelocity <= 0 || distance <= 0) return SWIPE_STRENGTH_MAX_SCALAR;
|
|
593
|
+
return SWIPE_STRENGTH_MIN_SCALAR + clampValue(distance / absVelocity * 1e3 / SWIPE_STRENGTH_MAX_DURATION_MS, 0, 1) * (SWIPE_STRENGTH_MAX_SCALAR - SWIPE_STRENGTH_MIN_SCALAR);
|
|
594
|
+
}
|
|
595
|
+
bindDragTracking(options) {
|
|
596
|
+
const { getDoc, getContentEl, getSwipeAreaEl, swipeDirection, onMove, onEnd, onCancel } = options;
|
|
597
|
+
const preventDragOnScroll = this.preventDragOnScroll;
|
|
598
|
+
const isVertical = isVerticalSwipeDirection(swipeDirection);
|
|
599
|
+
let lastAxis = 0;
|
|
600
|
+
return this.session.bind({
|
|
601
|
+
getDoc,
|
|
602
|
+
getSelectionTarget: getContentEl,
|
|
603
|
+
swipeDirection,
|
|
604
|
+
onMove,
|
|
605
|
+
onEnd,
|
|
606
|
+
onCancel,
|
|
607
|
+
cancelOnInterrupt: ({ reason, target }) => {
|
|
608
|
+
if (reason !== "lost-pointer-capture") return true;
|
|
609
|
+
return isWithinDrawerInteractionSurface(target, getContentEl(), getSwipeAreaEl());
|
|
610
|
+
},
|
|
611
|
+
onStart({ pointerType, point }) {
|
|
612
|
+
if (pointerType !== "touch") return;
|
|
613
|
+
lastAxis = isVertical ? point.y : point.x;
|
|
614
|
+
},
|
|
615
|
+
preventDefault({ event, pointerType, point, target }) {
|
|
616
|
+
if (pointerType !== "touch") return false;
|
|
617
|
+
const contentEl = getContentEl();
|
|
618
|
+
const resolvedTarget = target ?? event.target;
|
|
619
|
+
if (!preventDragOnScroll()) return false;
|
|
620
|
+
if (!contentEl || !resolvedTarget || isDragExemptElement(resolvedTarget)) return false;
|
|
621
|
+
const scrollParent = findClosestScrollableAncestorOnSwipeAxis(resolvedTarget, contentEl, swipeDirection);
|
|
622
|
+
if (scrollParent) {
|
|
623
|
+
const currentAxis = isVertical ? point.y : point.x;
|
|
624
|
+
const shouldPrevent = shouldPreventTouchScroll({
|
|
625
|
+
scrollParent,
|
|
626
|
+
swipeDirection,
|
|
627
|
+
lastMainAxis: lastAxis,
|
|
628
|
+
currentMainAxis: currentAxis
|
|
629
|
+
});
|
|
630
|
+
lastAxis = currentAxis;
|
|
631
|
+
return shouldPrevent;
|
|
632
|
+
}
|
|
633
|
+
lastAxis = isVertical ? point.y : point.x;
|
|
634
|
+
return false;
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
bindSwipeOpenTracking(options) {
|
|
639
|
+
const { getDoc, getContentEl, getSwipeAreaEl, swipeDirection, onMove, onEnd, onCancel } = options;
|
|
640
|
+
return this.session.bind({
|
|
641
|
+
getDoc,
|
|
642
|
+
getSelectionTarget: getSwipeAreaEl,
|
|
643
|
+
swipeDirection,
|
|
644
|
+
onMove({ point }) {
|
|
645
|
+
onMove({ point });
|
|
646
|
+
},
|
|
647
|
+
onEnd,
|
|
648
|
+
onCancel,
|
|
649
|
+
cancelOnInterrupt: ({ reason, target }) => {
|
|
650
|
+
if (reason !== "lost-pointer-capture") return true;
|
|
651
|
+
return isWithinDrawerInteractionSurface(target, getContentEl(), getSwipeAreaEl());
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
function isWithinDrawerInteractionSurface(target, contentEl, swipeAreaEl) {
|
|
657
|
+
if (!target) return false;
|
|
658
|
+
return contains(contentEl, target) || contains(swipeAreaEl, target);
|
|
659
|
+
}
|
|
660
|
+
const oppositeSwipeDirection = {
|
|
661
|
+
up: "down",
|
|
662
|
+
down: "up",
|
|
663
|
+
start: "end",
|
|
664
|
+
end: "start"
|
|
665
|
+
};
|
|
666
|
+
function resolveSwipeDirection(direction, dir) {
|
|
667
|
+
if (direction === "start") return dir === "rtl" ? "right" : "left";
|
|
668
|
+
if (direction === "end") return dir === "rtl" ? "left" : "right";
|
|
669
|
+
return direction;
|
|
670
|
+
}
|
|
671
|
+
function getSwipeDirectionSize(rect, direction) {
|
|
672
|
+
return isVerticalSwipeDirection(direction) ? rect.height : rect.width;
|
|
673
|
+
}
|
|
674
|
+
function resolveSwipeProgress(contentSize, dragOffset, snapPointOffset) {
|
|
675
|
+
if (!contentSize || contentSize <= 0) return 0;
|
|
676
|
+
return clampValue(1 - (dragOffset ?? snapPointOffset) / contentSize, 0, 1);
|
|
677
|
+
}
|
|
678
|
+
function hasOpeningSwipeIntent(start, current, direction) {
|
|
679
|
+
const axis = isVerticalSwipeDirection(direction) ? "y" : "x";
|
|
680
|
+
const sign = isNegativeSwipeDirection(direction) ? -1 : 1;
|
|
681
|
+
return (start[axis] - current[axis]) * sign > SWIPE_AREA_OPEN_INTENT_MIN_PX;
|
|
682
|
+
}
|
|
683
|
+
function overflowAllowsScroll(overflow) {
|
|
684
|
+
return overflow === "auto" || overflow === "scroll" || overflow === "overlay";
|
|
685
|
+
}
|
|
686
|
+
function canScrollAlongY(el) {
|
|
687
|
+
if (!overflowAllowsScroll(getComputedStyle$1(el).overflowY)) return false;
|
|
688
|
+
return el.scrollHeight > el.clientHeight + SCROLL_SLACK_EPSILON;
|
|
689
|
+
}
|
|
690
|
+
function canScrollAlongX(el) {
|
|
691
|
+
if (!overflowAllowsScroll(getComputedStyle$1(el).overflowX)) return false;
|
|
692
|
+
return el.scrollWidth > el.clientWidth + SCROLL_SLACK_EPSILON;
|
|
693
|
+
}
|
|
694
|
+
function canScrollOnSwipeAxis(el, direction) {
|
|
695
|
+
return isVerticalSwipeDirection(direction) ? canScrollAlongY(el) : canScrollAlongX(el);
|
|
696
|
+
}
|
|
697
|
+
function findClosestScrollableAncestorOnSwipeAxis(target, container, direction) {
|
|
698
|
+
if (!container) return null;
|
|
699
|
+
let el = target;
|
|
700
|
+
while (el && el !== container) {
|
|
701
|
+
if (canScrollOnSwipeAxis(el, direction)) return el;
|
|
702
|
+
el = el.parentElement;
|
|
703
|
+
}
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
706
|
+
function getScrollInfo(target, container, direction) {
|
|
707
|
+
let availableForwardScroll = 0;
|
|
708
|
+
let availableBackwardScroll = 0;
|
|
709
|
+
if (!container) return {
|
|
710
|
+
availableForwardScroll,
|
|
711
|
+
availableBackwardScroll
|
|
712
|
+
};
|
|
713
|
+
const vertical = isVerticalSwipeDirection(direction);
|
|
714
|
+
let element = target;
|
|
715
|
+
while (element) {
|
|
716
|
+
if (vertical ? canScrollAlongY(element) : canScrollAlongX(element)) {
|
|
717
|
+
const clientSize = vertical ? element.clientHeight : element.clientWidth;
|
|
718
|
+
const scrollPos = vertical ? element.scrollTop : element.scrollLeft;
|
|
719
|
+
const scrolled = (vertical ? element.scrollHeight : element.scrollWidth) - scrollPos - clientSize;
|
|
720
|
+
availableForwardScroll += scrolled;
|
|
721
|
+
availableBackwardScroll += scrollPos;
|
|
722
|
+
}
|
|
723
|
+
if (element === container || element === element.ownerDocument.documentElement) break;
|
|
724
|
+
element = element.parentElement;
|
|
725
|
+
}
|
|
726
|
+
return {
|
|
727
|
+
availableForwardScroll,
|
|
728
|
+
availableBackwardScroll
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
function shouldPreventTouchScroll(options) {
|
|
732
|
+
const { scrollParent, swipeDirection, lastMainAxis, currentMainAxis } = options;
|
|
733
|
+
const vertical = isVerticalSwipeDirection(swipeDirection);
|
|
734
|
+
const movingPositive = currentMainAxis > lastMainAxis;
|
|
735
|
+
if (vertical) {
|
|
736
|
+
const scrollPos = scrollParent.scrollTop;
|
|
737
|
+
const maxScroll = Math.max(0, scrollParent.scrollHeight - scrollParent.clientHeight);
|
|
738
|
+
if (swipeDirection === "down") return scrollPos <= SCROLL_SLACK_EPSILON && movingPositive;
|
|
739
|
+
if (swipeDirection === "up") return scrollPos >= maxScroll - SCROLL_SLACK_EPSILON && !movingPositive;
|
|
740
|
+
} else {
|
|
741
|
+
const scrollPos = scrollParent.scrollLeft;
|
|
742
|
+
const maxScroll = Math.max(0, scrollParent.scrollWidth - scrollParent.clientWidth);
|
|
743
|
+
if (swipeDirection === "right") return scrollPos <= SCROLL_SLACK_EPSILON && movingPositive;
|
|
744
|
+
if (swipeDirection === "left") return scrollPos >= maxScroll - SCROLL_SLACK_EPSILON && !movingPositive;
|
|
745
|
+
}
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
function isDragExemptElement(el) {
|
|
749
|
+
if (!isHTMLElement(el)) return false;
|
|
750
|
+
if (el.closest(NO_DRAG_SELECTOR)) return true;
|
|
751
|
+
let node = el;
|
|
752
|
+
while (node) {
|
|
753
|
+
if (isEditableElement(node)) return true;
|
|
754
|
+
node = node.parentElement;
|
|
755
|
+
}
|
|
756
|
+
const input = el.closest("input");
|
|
757
|
+
if (isInputElement(input)) {
|
|
758
|
+
const type = input.type;
|
|
759
|
+
if (type === "range" || type === "file") return true;
|
|
760
|
+
}
|
|
761
|
+
return false;
|
|
762
|
+
}
|
|
763
|
+
function isTextSelectionInDrawer(doc, contentEl) {
|
|
764
|
+
if (!contentEl) return false;
|
|
765
|
+
const selection = doc.getSelection();
|
|
766
|
+
if (!selection || selection.rangeCount === 0 || selection.isCollapsed) return false;
|
|
767
|
+
try {
|
|
768
|
+
const range = selection.getRangeAt(0);
|
|
769
|
+
if (contains(contentEl, range.commonAncestorContainer)) return true;
|
|
770
|
+
if (contains(contentEl, selection.anchorNode)) return true;
|
|
771
|
+
if (contains(contentEl, selection.focusNode)) return true;
|
|
772
|
+
if (typeof range.intersectsNode === "function" && range.intersectsNode(contentEl)) return true;
|
|
773
|
+
} catch {
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
return false;
|
|
777
|
+
}
|
|
778
|
+
function isDragExemptFromComposedPath(event) {
|
|
779
|
+
const path = typeof event.composedPath === "function" ? event.composedPath() : [];
|
|
780
|
+
for (const node of path) if (isDragExemptElement(node)) return true;
|
|
781
|
+
return isDragExemptElement(event.target);
|
|
782
|
+
}
|
|
783
|
+
function shouldIgnorePointerDownForDrag(event) {
|
|
784
|
+
if (!isLeftClick(event)) return true;
|
|
785
|
+
const target = getEventTarget(event);
|
|
786
|
+
if (target?.hasAttribute(NO_DRAG_DATA_ATTR) || target?.closest(NO_DRAG_SELECTOR)) return true;
|
|
787
|
+
return isDragExemptFromComposedPath(event);
|
|
788
|
+
}
|
|
27
789
|
//#endregion
|
|
28
790
|
//#region src/machines/drawer/drawer.connect.ts
|
|
791
|
+
const SWIPE_OPEN_HIDDEN_OFFSET = 9999;
|
|
792
|
+
function getSwipeOpenOffset(swipingOpen, dragOffset, contentSize) {
|
|
793
|
+
if (!swipingOpen || dragOffset !== null) return null;
|
|
794
|
+
return contentSize ?? SWIPE_OPEN_HIDDEN_OFFSET;
|
|
795
|
+
}
|
|
29
796
|
function connect(service, normalize) {
|
|
30
|
-
const { state, send, context, scope, prop } = service;
|
|
797
|
+
const { state, send, context, scope, prop, refs } = service;
|
|
31
798
|
const open = state.hasTag("open");
|
|
799
|
+
const closed = state.matches("closed");
|
|
800
|
+
const swipingOpen = state.matches("swiping-open");
|
|
32
801
|
const dragOffset = context.get("dragOffset");
|
|
33
802
|
const dragging = dragOffset !== null;
|
|
34
|
-
const
|
|
803
|
+
const snapPoint = context.get("snapPoint");
|
|
804
|
+
const swipeDirection = prop("swipeDirection");
|
|
805
|
+
const physicalDirection = resolveSwipeDirection(swipeDirection, prop("dir"));
|
|
806
|
+
const contentSize = context.get("contentSize");
|
|
807
|
+
const swipeStrength = context.get("swipeStrength");
|
|
35
808
|
const resolvedActiveSnapPoint = context.get("resolvedActiveSnapPoint");
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
809
|
+
const snapPointOffset = resolvedActiveSnapPoint?.offset ?? 0;
|
|
810
|
+
const currentOffset = getSwipeOpenOffset(swipingOpen, dragOffset, contentSize) ?? dragOffset ?? snapPointOffset;
|
|
811
|
+
const signedSnapPointOffset = isNegativeSwipeDirection(physicalDirection) ? -snapPointOffset : snapPointOffset;
|
|
812
|
+
const isActivelySwiping = dragging || swipingOpen;
|
|
813
|
+
const swipeMovement = dragging || swipingOpen ? currentOffset - snapPointOffset : 0;
|
|
814
|
+
const signedMovement = isNegativeSwipeDirection(physicalDirection) ? -swipeMovement : swipeMovement;
|
|
815
|
+
const swipeProgress = isActivelySwiping && contentSize && contentSize > 0 ? clampValue(Math.abs(signedMovement) / contentSize, 0, 1) : swipingOpen ? 1 : 0;
|
|
816
|
+
const signedCurrentOffset = isNegativeSwipeDirection(physicalDirection) ? -currentOffset : currentOffset;
|
|
817
|
+
const translateX = isVerticalSwipeDirection(physicalDirection) ? 0 : signedCurrentOffset;
|
|
818
|
+
const translateY = isVerticalSwipeDirection(physicalDirection) ? signedCurrentOffset : 0;
|
|
819
|
+
function onContentPointerDown(event) {
|
|
820
|
+
refs.get("swipeSession").contentPointerDown({
|
|
821
|
+
event,
|
|
822
|
+
getDoc: () => scope.getDoc(),
|
|
823
|
+
getContentEl: () => getContentEl(scope),
|
|
824
|
+
getWin: () => scope.getWin(),
|
|
825
|
+
swipeDirection: physicalDirection,
|
|
826
|
+
canCommit: () => state.hasTag("open") && !state.matches("closing"),
|
|
827
|
+
onCommit(point) {
|
|
828
|
+
send({
|
|
829
|
+
type: "POINTER_DOWN",
|
|
830
|
+
point
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
function onGrabberPointerDown(event) {
|
|
836
|
+
refs.get("swipeSession").grabberPointerDown({
|
|
837
|
+
event,
|
|
838
|
+
point: getEventPoint(event),
|
|
839
|
+
canCommit: () => state.hasTag("open") && !state.matches("closing"),
|
|
840
|
+
onCommit(point) {
|
|
841
|
+
send({
|
|
842
|
+
type: "POINTER_DOWN",
|
|
843
|
+
point
|
|
844
|
+
});
|
|
845
|
+
}
|
|
45
846
|
});
|
|
46
847
|
}
|
|
47
848
|
return {
|
|
@@ -52,47 +853,74 @@ function connect(service, normalize) {
|
|
|
52
853
|
send({ type: nextOpen ? "OPEN" : "CLOSE" });
|
|
53
854
|
},
|
|
54
855
|
snapPoints: prop("snapPoints"),
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
856
|
+
swipeDirection,
|
|
857
|
+
snapPoint,
|
|
858
|
+
setSnapPoint(snapPoint) {
|
|
859
|
+
if (context.get("snapPoint") === snapPoint) return;
|
|
58
860
|
send({
|
|
59
|
-
type: "
|
|
861
|
+
type: "SNAP_POINT.SET",
|
|
60
862
|
snapPoint
|
|
61
863
|
});
|
|
62
864
|
},
|
|
63
865
|
getOpenPercentage() {
|
|
64
|
-
if (!open) return 0;
|
|
65
|
-
|
|
66
|
-
if (!contentHeight) return 0;
|
|
67
|
-
const currentOffset = translate ?? 0;
|
|
68
|
-
return Math.max(0, Math.min(1, 1 - currentOffset / contentHeight));
|
|
866
|
+
if (!open || !contentSize) return 0;
|
|
867
|
+
return clampValue(1 - currentOffset / contentSize, 0, 1);
|
|
69
868
|
},
|
|
70
|
-
|
|
71
|
-
|
|
869
|
+
getSnapPointIndex() {
|
|
870
|
+
if (snapPoint === null) return -1;
|
|
871
|
+
return prop("snapPoints").indexOf(snapPoint);
|
|
72
872
|
},
|
|
73
|
-
|
|
74
|
-
return
|
|
873
|
+
getContentSize() {
|
|
874
|
+
return contentSize;
|
|
875
|
+
},
|
|
876
|
+
getPositionerProps() {
|
|
877
|
+
return normalize.element({
|
|
878
|
+
...parts.positioner.attrs,
|
|
879
|
+
id: getPositionerId(scope),
|
|
880
|
+
dir: prop("dir"),
|
|
881
|
+
hidden: closed,
|
|
882
|
+
"data-state": open ? "open" : "closed",
|
|
883
|
+
"data-swipe-direction": physicalDirection,
|
|
884
|
+
style: compact({ pointerEvents: prop("modal") ? void 0 : "none" })
|
|
885
|
+
});
|
|
75
886
|
},
|
|
76
887
|
getContentProps(props = { draggable: true }) {
|
|
888
|
+
const movementX = isVerticalSwipeDirection(physicalDirection) ? 0 : signedMovement;
|
|
889
|
+
const movementY = isVerticalSwipeDirection(physicalDirection) ? signedMovement : 0;
|
|
890
|
+
const rendered = context.get("rendered");
|
|
77
891
|
return normalize.element({
|
|
78
892
|
...parts.content.attrs,
|
|
79
893
|
dir: prop("dir"),
|
|
80
894
|
id: getContentId(scope),
|
|
81
895
|
tabIndex: -1,
|
|
82
|
-
role: "
|
|
896
|
+
role: prop("role"),
|
|
83
897
|
"aria-modal": prop("modal"),
|
|
84
|
-
"aria-labelledby": getTitleId(scope),
|
|
898
|
+
"aria-labelledby": rendered.title ? getTitleId(scope) : void 0,
|
|
899
|
+
"aria-describedby": rendered.description ? getDescriptionId(scope) : void 0,
|
|
85
900
|
hidden: !open,
|
|
86
901
|
"data-state": open ? "open" : "closed",
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
902
|
+
"data-expanded": resolvedActiveSnapPoint?.offset === 0 ? "" : void 0,
|
|
903
|
+
"data-swipe-direction": physicalDirection,
|
|
904
|
+
"data-swiping": dragging || swipingOpen ? "" : void 0,
|
|
905
|
+
"data-dragging": dragging ? "" : void 0,
|
|
906
|
+
style: compact({
|
|
907
|
+
pointerEvents: prop("modal") ? void 0 : "auto",
|
|
908
|
+
visibility: swipingOpen && dragOffset === null ? "hidden" : void 0,
|
|
909
|
+
transform: "translate3d(var(--drawer-translate-x, 0px), var(--drawer-translate-y, 0px), 0)",
|
|
910
|
+
transitionDuration: dragging || swipingOpen ? "0s" : void 0,
|
|
911
|
+
"--drawer-translate": toPx(translateY),
|
|
912
|
+
"--drawer-translate-x": toPx(translateX),
|
|
913
|
+
"--drawer-translate-y": toPx(translateY),
|
|
914
|
+
"--drawer-snap-point-offset-x": isVerticalSwipeDirection(physicalDirection) ? "0px" : toPx(signedSnapPointOffset),
|
|
915
|
+
"--drawer-snap-point-offset-y": isVerticalSwipeDirection(physicalDirection) ? toPx(signedSnapPointOffset) : "0px",
|
|
916
|
+
"--drawer-swipe-movement-x": toPx(movementX),
|
|
917
|
+
"--drawer-swipe-movement-y": toPx(movementY),
|
|
918
|
+
"--drawer-swipe-strength": `${swipeStrength}`,
|
|
91
919
|
willChange: "transform"
|
|
92
|
-
},
|
|
920
|
+
}),
|
|
93
921
|
onPointerDown(event) {
|
|
94
922
|
if (!props.draggable) return;
|
|
95
|
-
|
|
923
|
+
onContentPointerDown(event);
|
|
96
924
|
}
|
|
97
925
|
});
|
|
98
926
|
},
|
|
@@ -103,6 +931,13 @@ function connect(service, normalize) {
|
|
|
103
931
|
dir: prop("dir")
|
|
104
932
|
});
|
|
105
933
|
},
|
|
934
|
+
getDescriptionProps() {
|
|
935
|
+
return normalize.element({
|
|
936
|
+
...parts.description.attrs,
|
|
937
|
+
id: getDescriptionId(scope),
|
|
938
|
+
dir: prop("dir")
|
|
939
|
+
});
|
|
940
|
+
},
|
|
106
941
|
getTriggerProps() {
|
|
107
942
|
return normalize.button({
|
|
108
943
|
...parts.trigger.attrs,
|
|
@@ -117,9 +952,14 @@ function connect(service, normalize) {
|
|
|
117
952
|
return normalize.element({
|
|
118
953
|
...parts.backdrop.attrs,
|
|
119
954
|
id: getBackdropId(scope),
|
|
120
|
-
hidden: !open,
|
|
955
|
+
hidden: !open || swipingOpen && dragOffset === null,
|
|
121
956
|
"data-state": open ? "open" : "closed",
|
|
122
|
-
|
|
957
|
+
"data-swiping": dragging || swipingOpen ? "" : void 0,
|
|
958
|
+
style: {
|
|
959
|
+
willChange: "opacity",
|
|
960
|
+
"--drawer-swipe-progress": `${swipeProgress}`,
|
|
961
|
+
"--drawer-swipe-strength": `${swipeStrength}`
|
|
962
|
+
}
|
|
123
963
|
});
|
|
124
964
|
},
|
|
125
965
|
getGrabberProps() {
|
|
@@ -127,7 +967,7 @@ function connect(service, normalize) {
|
|
|
127
967
|
...parts.grabber.attrs,
|
|
128
968
|
id: getGrabberId(scope),
|
|
129
969
|
onPointerDown(event) {
|
|
130
|
-
|
|
970
|
+
onGrabberPointerDown(event);
|
|
131
971
|
},
|
|
132
972
|
style: { touchAction: "none" }
|
|
133
973
|
});
|
|
@@ -146,143 +986,121 @@ function connect(service, normalize) {
|
|
|
146
986
|
send({ type: "CLOSE" });
|
|
147
987
|
}
|
|
148
988
|
});
|
|
989
|
+
},
|
|
990
|
+
getSwipeAreaProps(props = {}) {
|
|
991
|
+
const disabled = props.disabled ?? false;
|
|
992
|
+
const physicalOpenDirection = resolveSwipeDirection(props.swipeDirection ?? oppositeSwipeDirection[swipeDirection], prop("dir"));
|
|
993
|
+
return normalize.element({
|
|
994
|
+
...parts.swipeArea.attrs,
|
|
995
|
+
id: getSwipeAreaId(scope),
|
|
996
|
+
role: "presentation",
|
|
997
|
+
"aria-hidden": true,
|
|
998
|
+
"data-state": open ? "open" : "closed",
|
|
999
|
+
"data-swiping": swipingOpen ? "" : void 0,
|
|
1000
|
+
"data-swipe-direction": physicalOpenDirection,
|
|
1001
|
+
"data-disabled": disabled ? "" : void 0,
|
|
1002
|
+
style: {
|
|
1003
|
+
touchAction: isVerticalSwipeDirection(physicalOpenDirection) ? "pan-x" : "pan-y",
|
|
1004
|
+
pointerEvents: disabled || open && !swipingOpen ? "none" : void 0
|
|
1005
|
+
},
|
|
1006
|
+
onPointerDown(event) {
|
|
1007
|
+
if (disabled) return;
|
|
1008
|
+
if (!isLeftClick(event)) return;
|
|
1009
|
+
if (event.pointerType === "touch") return;
|
|
1010
|
+
if (open && !swipingOpen) return;
|
|
1011
|
+
send({
|
|
1012
|
+
type: "SWIPE_AREA.START",
|
|
1013
|
+
point: getEventPoint(event)
|
|
1014
|
+
});
|
|
1015
|
+
if (event.cancelable) event.preventDefault();
|
|
1016
|
+
},
|
|
1017
|
+
onTouchStart(event) {
|
|
1018
|
+
if (disabled) return;
|
|
1019
|
+
if (open && !swipingOpen) return;
|
|
1020
|
+
const touch = event.touches[0];
|
|
1021
|
+
if (!touch) return;
|
|
1022
|
+
send({
|
|
1023
|
+
type: "SWIPE_AREA.START",
|
|
1024
|
+
point: {
|
|
1025
|
+
x: touch.clientX,
|
|
1026
|
+
y: touch.clientY
|
|
1027
|
+
}
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
});
|
|
149
1031
|
}
|
|
150
1032
|
};
|
|
151
1033
|
}
|
|
152
1034
|
//#endregion
|
|
153
|
-
//#region src/machines/drawer/
|
|
154
|
-
|
|
155
|
-
return snapPoints.reduce((acc, curr) => {
|
|
156
|
-
const closestDiff = Math.abs(offset - acc.offset);
|
|
157
|
-
return Math.abs(offset - curr.offset) < closestDiff ? curr : acc;
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
//#endregion
|
|
161
|
-
//#region src/machines/drawer/utils/get-scroll-info.ts
|
|
162
|
-
function isScrollContainer(element) {
|
|
163
|
-
const overflow = getComputedStyle(element).overflowY;
|
|
164
|
-
return overflow === "auto" || overflow === "scroll";
|
|
165
|
-
}
|
|
166
|
-
function getScrollInfo(target, container) {
|
|
167
|
-
let element = target;
|
|
168
|
-
let availableScroll = 0;
|
|
169
|
-
let availableScrollTop = 0;
|
|
170
|
-
while (element) {
|
|
171
|
-
const { clientHeight, scrollTop, scrollHeight } = element;
|
|
172
|
-
const scrolled = scrollHeight - scrollTop - clientHeight;
|
|
173
|
-
if ((scrollTop !== 0 || scrolled !== 0) && isScrollContainer(element)) {
|
|
174
|
-
availableScroll += scrolled;
|
|
175
|
-
availableScrollTop += scrollTop;
|
|
176
|
-
}
|
|
177
|
-
if (element === container || element === document.documentElement) break;
|
|
178
|
-
element = element.parentNode;
|
|
179
|
-
}
|
|
180
|
-
return {
|
|
181
|
-
availableScroll,
|
|
182
|
-
availableScrollTop
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
//#endregion
|
|
186
|
-
//#region src/machines/drawer/utils/drag-manager.ts
|
|
187
|
-
const DRAG_START_THRESHOLD = .3;
|
|
188
|
-
var DragManager = class {
|
|
1035
|
+
//#region src/machines/drawer/drawer.registry.ts
|
|
1036
|
+
var DrawerRegistry = class {
|
|
189
1037
|
constructor() {
|
|
190
|
-
_defineProperty(this, "
|
|
191
|
-
_defineProperty(this, "
|
|
192
|
-
_defineProperty(this, "
|
|
193
|
-
_defineProperty(this, "
|
|
194
|
-
_defineProperty(this, "velocity", null);
|
|
1038
|
+
_defineProperty(this, "elements", /* @__PURE__ */ new Map());
|
|
1039
|
+
_defineProperty(this, "swipingIds", /* @__PURE__ */ new Set());
|
|
1040
|
+
_defineProperty(this, "swipeProgress", /* @__PURE__ */ new Map());
|
|
1041
|
+
_defineProperty(this, "listeners", /* @__PURE__ */ new Set());
|
|
195
1042
|
}
|
|
196
|
-
|
|
197
|
-
this.
|
|
198
|
-
}
|
|
199
|
-
clearPointerStart() {
|
|
200
|
-
this.pointerStart = null;
|
|
201
|
-
}
|
|
202
|
-
getPointerStart() {
|
|
203
|
-
return this.pointerStart;
|
|
204
|
-
}
|
|
205
|
-
setDragOffset(point, resolvedActiveSnapPointOffset) {
|
|
206
|
-
if (!this.pointerStart) return;
|
|
207
|
-
const currentTimestamp = (/* @__PURE__ */ new Date()).getTime();
|
|
208
|
-
if (this.lastPoint) {
|
|
209
|
-
const dy = point.y - this.lastPoint.y;
|
|
210
|
-
if (this.lastTimestamp) {
|
|
211
|
-
const dt = currentTimestamp - this.lastTimestamp;
|
|
212
|
-
if (dt > 0) {
|
|
213
|
-
const calculatedVelocity = dy / dt * 1e3;
|
|
214
|
-
this.velocity = Number.isFinite(calculatedVelocity) ? calculatedVelocity : 0;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
this.lastPoint = point;
|
|
219
|
-
this.lastTimestamp = currentTimestamp;
|
|
220
|
-
let delta = this.pointerStart.y - point.y - resolvedActiveSnapPointOffset;
|
|
221
|
-
if (delta > 0) delta = 0;
|
|
222
|
-
this.dragOffset = -delta;
|
|
1043
|
+
notify() {
|
|
1044
|
+
this.listeners.forEach((fn) => fn());
|
|
223
1045
|
}
|
|
224
|
-
|
|
225
|
-
|
|
1046
|
+
register(id, el) {
|
|
1047
|
+
this.elements.set(id, el);
|
|
1048
|
+
this.notify();
|
|
226
1049
|
}
|
|
227
|
-
|
|
228
|
-
this.
|
|
1050
|
+
unregister(id) {
|
|
1051
|
+
this.swipingIds.delete(id);
|
|
1052
|
+
this.swipeProgress.delete(id);
|
|
1053
|
+
if (!this.elements.delete(id)) return;
|
|
1054
|
+
this.notify();
|
|
229
1055
|
}
|
|
230
|
-
|
|
231
|
-
|
|
1056
|
+
setSwiping(id, swiping) {
|
|
1057
|
+
if (!(swiping ? !this.swipingIds.has(id) : this.swipingIds.has(id)) && swiping) return;
|
|
1058
|
+
if (swiping) this.swipingIds.add(id);
|
|
1059
|
+
else {
|
|
1060
|
+
this.swipingIds.delete(id);
|
|
1061
|
+
this.swipeProgress.delete(id);
|
|
1062
|
+
}
|
|
1063
|
+
this.notify();
|
|
232
1064
|
}
|
|
233
|
-
|
|
234
|
-
this.
|
|
235
|
-
this.
|
|
236
|
-
this.velocity = null;
|
|
1065
|
+
setSwipeProgress(id, progress) {
|
|
1066
|
+
this.swipeProgress.set(id, progress);
|
|
1067
|
+
this.notify();
|
|
237
1068
|
}
|
|
238
|
-
|
|
239
|
-
this.
|
|
240
|
-
|
|
241
|
-
|
|
1069
|
+
getSwipeProgressAfter(id) {
|
|
1070
|
+
const keys = [...this.elements.keys()];
|
|
1071
|
+
const myIndex = keys.indexOf(id);
|
|
1072
|
+
if (myIndex === -1) return 0;
|
|
1073
|
+
for (let i = keys.length - 1; i > myIndex; i -= 1) if (this.swipingIds.has(keys[i])) return this.swipeProgress.get(keys[i]) ?? 0;
|
|
1074
|
+
return 0;
|
|
242
1075
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const { availableScroll, availableScrollTop } = getScrollInfo(target, container);
|
|
249
|
-
if (delta > 0 && Math.abs(availableScroll) > 1 || delta < 0 && Math.abs(availableScrollTop) > 0) return false;
|
|
250
|
-
}
|
|
251
|
-
return true;
|
|
1076
|
+
hasSwipingAfter(id) {
|
|
1077
|
+
const keys = [...this.elements.keys()];
|
|
1078
|
+
const myIndex = keys.indexOf(id);
|
|
1079
|
+
if (myIndex === -1) return false;
|
|
1080
|
+
return keys.slice(myIndex + 1).some((key) => this.swipingIds.has(key));
|
|
252
1081
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
return findClosestSnapPoint(this.dragOffset, snapPoints).value;
|
|
1082
|
+
getEntries() {
|
|
1083
|
+
return this.elements;
|
|
256
1084
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const closeThresholdInPixels = contentHeight * (1 - closeThreshold);
|
|
263
|
-
const isBelowSmallestSnapPoint = visibleHeight < contentHeight - smallestSnapPoint.offset;
|
|
264
|
-
return isFastSwipe || visibleHeight < closeThresholdInPixels && isBelowSmallestSnapPoint || visibleHeight === 0;
|
|
1085
|
+
subscribe(fn) {
|
|
1086
|
+
this.listeners.add(fn);
|
|
1087
|
+
return () => {
|
|
1088
|
+
this.listeners.delete(fn);
|
|
1089
|
+
};
|
|
265
1090
|
}
|
|
266
1091
|
};
|
|
267
|
-
|
|
268
|
-
//#region src/machines/drawer/utils/resolve-snap-point.ts
|
|
269
|
-
function resolveSnapPoint(snapPoint, containerHeight) {
|
|
270
|
-
if (typeof snapPoint === "number") return {
|
|
271
|
-
value: snapPoint,
|
|
272
|
-
offset: containerHeight - snapPoint * containerHeight
|
|
273
|
-
};
|
|
274
|
-
if (typeof snapPoint === "string") return {
|
|
275
|
-
value: snapPoint,
|
|
276
|
-
offset: containerHeight - parseFloat(snapPoint)
|
|
277
|
-
};
|
|
278
|
-
throw new Error(`Invalid snap point: ${snapPoint}`);
|
|
279
|
-
}
|
|
1092
|
+
const drawerRegistry = new DrawerRegistry();
|
|
280
1093
|
//#endregion
|
|
281
1094
|
//#region src/machines/drawer/drawer.machine.ts
|
|
1095
|
+
const { and } = createGuards();
|
|
1096
|
+
const getActiveSnapOffset = (context) => context.get("resolvedActiveSnapPoint")?.offset ?? 0;
|
|
1097
|
+
const hasRemSnapPoints = (snapPoints) => snapPoints.some((snapPoint) => typeof snapPoint === "string" && snapPoint.trim().endsWith("rem"));
|
|
1098
|
+
const DEFAULT_SNAP_POINTS = [1];
|
|
282
1099
|
const machine = createMachine({
|
|
283
1100
|
props({ props, scope }) {
|
|
284
1101
|
const initialFocusEl = props.role === "alertdialog" ? () => getCloseTriggerEl(scope) : void 0;
|
|
285
1102
|
const modal = typeof props.modal === "boolean" ? props.modal : true;
|
|
1103
|
+
const snapPoints = props.snapPoints ?? DEFAULT_SNAP_POINTS;
|
|
286
1104
|
return {
|
|
287
1105
|
modal,
|
|
288
1106
|
trapFocus: modal,
|
|
@@ -290,11 +1108,14 @@ const machine = createMachine({
|
|
|
290
1108
|
closeOnInteractOutside: true,
|
|
291
1109
|
closeOnEscape: true,
|
|
292
1110
|
restoreFocus: true,
|
|
1111
|
+
role: "dialog",
|
|
293
1112
|
initialFocusEl,
|
|
294
|
-
snapPoints
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
1113
|
+
snapPoints,
|
|
1114
|
+
defaultSnapPoint: props.defaultSnapPoint ?? snapPoints[0] ?? null,
|
|
1115
|
+
swipeDirection: "down",
|
|
1116
|
+
snapToSequentialPoints: false,
|
|
1117
|
+
swipeVelocityThreshold: 500,
|
|
1118
|
+
closeThreshold: .5,
|
|
298
1119
|
preventDragOnScroll: true,
|
|
299
1120
|
...props
|
|
300
1121
|
};
|
|
@@ -302,88 +1123,198 @@ const machine = createMachine({
|
|
|
302
1123
|
context({ bindable, prop }) {
|
|
303
1124
|
return {
|
|
304
1125
|
dragOffset: bindable(() => ({ defaultValue: null })),
|
|
305
|
-
|
|
306
|
-
defaultValue: prop("
|
|
307
|
-
value: prop("
|
|
308
|
-
onChange(
|
|
309
|
-
return prop("
|
|
1126
|
+
snapPoint: bindable(() => ({
|
|
1127
|
+
defaultValue: prop("defaultSnapPoint"),
|
|
1128
|
+
value: prop("snapPoint"),
|
|
1129
|
+
onChange(snapPoint) {
|
|
1130
|
+
return prop("onSnapPointChange")?.({ snapPoint });
|
|
310
1131
|
}
|
|
311
1132
|
})),
|
|
312
1133
|
resolvedActiveSnapPoint: bindable(() => ({ defaultValue: null })),
|
|
313
|
-
|
|
1134
|
+
contentSize: bindable(() => ({ defaultValue: null })),
|
|
1135
|
+
viewportSize: bindable(() => ({ defaultValue: 0 })),
|
|
1136
|
+
rootFontSize: bindable(() => ({ defaultValue: 16 })),
|
|
1137
|
+
swipeStrength: bindable(() => ({ defaultValue: 1 })),
|
|
1138
|
+
rendered: bindable(() => ({ defaultValue: {
|
|
1139
|
+
title: true,
|
|
1140
|
+
description: true
|
|
1141
|
+
} }))
|
|
314
1142
|
};
|
|
315
1143
|
},
|
|
316
|
-
refs() {
|
|
317
|
-
return {
|
|
1144
|
+
refs({ prop }) {
|
|
1145
|
+
return { swipeSession: new DrawerSwipeSession({ preventDragOnScroll: () => prop("preventDragOnScroll") }) };
|
|
318
1146
|
},
|
|
319
|
-
computed: {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
const
|
|
330
|
-
|
|
1147
|
+
computed: {
|
|
1148
|
+
drawerId({ prop, scope }) {
|
|
1149
|
+
return String(prop("id") ?? scope.id);
|
|
1150
|
+
},
|
|
1151
|
+
physicalSwipeDirection({ prop }) {
|
|
1152
|
+
return resolveSwipeDirection(prop("swipeDirection"), prop("dir"));
|
|
1153
|
+
},
|
|
1154
|
+
resolvedSnapPoints({ context, prop }) {
|
|
1155
|
+
const contentSize = context.get("contentSize");
|
|
1156
|
+
const viewportSize = context.get("viewportSize");
|
|
1157
|
+
const rootFontSize = context.get("rootFontSize");
|
|
1158
|
+
if (contentSize === null) return [];
|
|
1159
|
+
return dedupeSnapPoints(prop("snapPoints").map((snapPoint) => resolveSnapPoint(snapPoint, {
|
|
1160
|
+
contentSize,
|
|
1161
|
+
viewportSize,
|
|
1162
|
+
rootFontSize
|
|
1163
|
+
})).filter((point) => point !== null));
|
|
1164
|
+
}
|
|
1165
|
+
},
|
|
1166
|
+
watch({ track, context, prop, action, computed }) {
|
|
1167
|
+
track([
|
|
1168
|
+
() => context.get("snapPoint"),
|
|
1169
|
+
() => context.get("contentSize"),
|
|
1170
|
+
() => context.get("viewportSize"),
|
|
1171
|
+
() => context.get("rootFontSize"),
|
|
1172
|
+
() => prop("snapPoints").join("|")
|
|
1173
|
+
], () => {
|
|
1174
|
+
const snapPoint = context.get("snapPoint");
|
|
1175
|
+
const contentSize = context.get("contentSize");
|
|
1176
|
+
const viewportSize = context.get("viewportSize");
|
|
1177
|
+
const rootFontSize = context.get("rootFontSize");
|
|
1178
|
+
if (snapPoint === null || contentSize === null) {
|
|
1179
|
+
context.set("resolvedActiveSnapPoint", null);
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
const resolvedPoints = computed("resolvedSnapPoints");
|
|
1183
|
+
const matchedPoint = resolvedPoints.find((point) => Object.is(point.value, snapPoint));
|
|
1184
|
+
if (matchedPoint) {
|
|
1185
|
+
context.set("resolvedActiveSnapPoint", matchedPoint);
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
const resolvedActiveSnapPoint = resolveSnapPoint(snapPoint, {
|
|
1189
|
+
contentSize,
|
|
1190
|
+
viewportSize,
|
|
1191
|
+
rootFontSize
|
|
1192
|
+
});
|
|
1193
|
+
if (resolvedActiveSnapPoint) {
|
|
1194
|
+
context.set("resolvedActiveSnapPoint", resolvedActiveSnapPoint);
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
const fallbackPoint = resolvedPoints[0];
|
|
1198
|
+
if (!fallbackPoint) {
|
|
1199
|
+
context.set("resolvedActiveSnapPoint", null);
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
context.set("snapPoint", fallbackPoint.value);
|
|
1203
|
+
context.set("resolvedActiveSnapPoint", fallbackPoint);
|
|
331
1204
|
});
|
|
332
1205
|
track([() => prop("open")], () => {
|
|
333
1206
|
action(["toggleVisibility"]);
|
|
334
1207
|
});
|
|
1208
|
+
track([
|
|
1209
|
+
() => context.get("dragOffset"),
|
|
1210
|
+
() => context.get("contentSize"),
|
|
1211
|
+
() => getActiveSnapOffset(context)
|
|
1212
|
+
], () => {
|
|
1213
|
+
action(["syncDrawerStack"]);
|
|
1214
|
+
});
|
|
335
1215
|
},
|
|
336
1216
|
initialState({ prop }) {
|
|
337
1217
|
return prop("open") || prop("defaultOpen") ? "open" : "closed";
|
|
338
1218
|
},
|
|
339
|
-
on: { "
|
|
1219
|
+
on: { "SNAP_POINT.SET": { actions: ["setSnapPoint"] } },
|
|
340
1220
|
states: {
|
|
341
1221
|
open: {
|
|
342
1222
|
tags: ["open"],
|
|
1223
|
+
entry: [
|
|
1224
|
+
"checkRenderedElements",
|
|
1225
|
+
"setInitialFocus",
|
|
1226
|
+
"deferClearDragOffset"
|
|
1227
|
+
],
|
|
343
1228
|
effects: [
|
|
344
1229
|
"trackDismissableElement",
|
|
345
1230
|
"preventScroll",
|
|
346
1231
|
"trapFocus",
|
|
347
1232
|
"hideContentBelow",
|
|
348
1233
|
"trackPointerMove",
|
|
349
|
-
"
|
|
1234
|
+
"trackSizeMeasurements",
|
|
1235
|
+
"trackNestedDrawerMetrics",
|
|
1236
|
+
"trackDrawerStack"
|
|
350
1237
|
],
|
|
351
1238
|
on: {
|
|
352
|
-
"CONTROLLED.CLOSE": {
|
|
1239
|
+
"CONTROLLED.CLOSE": {
|
|
1240
|
+
target: "closing",
|
|
1241
|
+
actions: ["clearSwipeOpenAnimation", "resetSwipeStrength"]
|
|
1242
|
+
},
|
|
353
1243
|
POINTER_DOWN: { actions: ["setPointerStart"] },
|
|
354
1244
|
POINTER_MOVE: [{
|
|
355
1245
|
guard: "isDragging",
|
|
356
1246
|
actions: ["setDragOffset"]
|
|
357
1247
|
}, {
|
|
358
1248
|
guard: "shouldStartDragging",
|
|
359
|
-
actions: ["setDragOffset"]
|
|
1249
|
+
actions: ["setRegistrySwiping", "setDragOffset"]
|
|
360
1250
|
}],
|
|
361
1251
|
POINTER_UP: [
|
|
1252
|
+
{
|
|
1253
|
+
guard: and("shouldCloseOnSwipe", "isOpenControlled"),
|
|
1254
|
+
actions: [
|
|
1255
|
+
"clearSwipeOpenAnimation",
|
|
1256
|
+
"clearRegistrySwiping",
|
|
1257
|
+
"clearPointerStart",
|
|
1258
|
+
"clearDragOffset",
|
|
1259
|
+
"invokeOnClose"
|
|
1260
|
+
]
|
|
1261
|
+
},
|
|
362
1262
|
{
|
|
363
1263
|
guard: "shouldCloseOnSwipe",
|
|
364
|
-
target: "closing"
|
|
1264
|
+
target: "closing",
|
|
1265
|
+
actions: [
|
|
1266
|
+
"clearSwipeOpenAnimation",
|
|
1267
|
+
"clearRegistrySwiping",
|
|
1268
|
+
"setDismissSwipeStrength"
|
|
1269
|
+
]
|
|
365
1270
|
},
|
|
366
1271
|
{
|
|
367
1272
|
guard: "isDragging",
|
|
368
1273
|
actions: [
|
|
1274
|
+
"clearRegistrySwiping",
|
|
1275
|
+
"suppressBackdropAnimation",
|
|
1276
|
+
"setSnapSwipeStrength",
|
|
369
1277
|
"setClosestSnapPoint",
|
|
370
1278
|
"clearPointerStart",
|
|
371
|
-
"clearDragOffset"
|
|
1279
|
+
"clearDragOffset",
|
|
1280
|
+
"clearVelocityTracking"
|
|
372
1281
|
]
|
|
373
1282
|
},
|
|
374
|
-
{ actions: [
|
|
1283
|
+
{ actions: [
|
|
1284
|
+
"clearRegistrySwiping",
|
|
1285
|
+
"clearPointerStart",
|
|
1286
|
+
"clearDragOffset",
|
|
1287
|
+
"clearVelocityTracking"
|
|
1288
|
+
] }
|
|
375
1289
|
],
|
|
1290
|
+
POINTER_CANCEL: [{
|
|
1291
|
+
guard: "isDragging",
|
|
1292
|
+
actions: [
|
|
1293
|
+
"clearRegistrySwiping",
|
|
1294
|
+
"clearPointerStart",
|
|
1295
|
+
"clearDragOffset",
|
|
1296
|
+
"clearVelocityTracking"
|
|
1297
|
+
]
|
|
1298
|
+
}, { actions: [
|
|
1299
|
+
"clearRegistrySwiping",
|
|
1300
|
+
"clearPointerStart",
|
|
1301
|
+
"clearVelocityTracking"
|
|
1302
|
+
] }],
|
|
376
1303
|
CLOSE: [{
|
|
377
1304
|
guard: "isOpenControlled",
|
|
378
|
-
actions: ["invokeOnClose"]
|
|
1305
|
+
actions: ["clearSwipeOpenAnimation", "invokeOnClose"]
|
|
379
1306
|
}, {
|
|
380
1307
|
target: "closing",
|
|
381
|
-
actions: [
|
|
1308
|
+
actions: [
|
|
1309
|
+
"clearSwipeOpenAnimation",
|
|
1310
|
+
"resetSwipeStrength",
|
|
1311
|
+
"invokeOnClose"
|
|
1312
|
+
]
|
|
382
1313
|
}]
|
|
383
1314
|
}
|
|
384
1315
|
},
|
|
385
1316
|
closing: {
|
|
386
|
-
effects: ["trackExitAnimation"],
|
|
1317
|
+
effects: ["trackExitAnimation", "trackDrawerStack"],
|
|
387
1318
|
on: { ANIMATION_END: {
|
|
388
1319
|
target: "closed",
|
|
389
1320
|
actions: [
|
|
@@ -392,11 +1323,73 @@ const machine = createMachine({
|
|
|
392
1323
|
"clearDragOffset",
|
|
393
1324
|
"clearActiveSnapPoint",
|
|
394
1325
|
"clearResolvedActiveSnapPoint",
|
|
395
|
-
"
|
|
1326
|
+
"clearSizeMeasurements",
|
|
396
1327
|
"clearVelocityTracking"
|
|
397
1328
|
]
|
|
398
1329
|
} }
|
|
399
1330
|
},
|
|
1331
|
+
"swipe-area-dragging": {
|
|
1332
|
+
tags: ["closed"],
|
|
1333
|
+
effects: ["trackSwipeOpenPointerMove"],
|
|
1334
|
+
on: {
|
|
1335
|
+
POINTER_MOVE: {
|
|
1336
|
+
guard: "hasSwipeIntent",
|
|
1337
|
+
target: "swiping-open"
|
|
1338
|
+
},
|
|
1339
|
+
POINTER_UP: {
|
|
1340
|
+
target: "closed",
|
|
1341
|
+
actions: ["clearPointerStart", "clearVelocityTracking"]
|
|
1342
|
+
},
|
|
1343
|
+
POINTER_CANCEL: {
|
|
1344
|
+
target: "closed",
|
|
1345
|
+
actions: ["clearPointerStart", "clearVelocityTracking"]
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
},
|
|
1349
|
+
"swiping-open": {
|
|
1350
|
+
tags: ["open"],
|
|
1351
|
+
effects: ["trackSwipeOpenPointerMove", "trackSizeMeasurements"],
|
|
1352
|
+
on: {
|
|
1353
|
+
POINTER_MOVE: { actions: ["setSwipeOpenDragOffset"] },
|
|
1354
|
+
POINTER_UP: [
|
|
1355
|
+
{
|
|
1356
|
+
guard: and("shouldOpenOnSwipe", "isOpenControlled"),
|
|
1357
|
+
actions: ["clearPointerStart", "invokeOnOpen"]
|
|
1358
|
+
},
|
|
1359
|
+
{
|
|
1360
|
+
guard: "shouldOpenOnSwipe",
|
|
1361
|
+
target: "open",
|
|
1362
|
+
actions: ["clearPointerStart", "invokeOnOpen"]
|
|
1363
|
+
},
|
|
1364
|
+
{
|
|
1365
|
+
target: "closed",
|
|
1366
|
+
actions: [
|
|
1367
|
+
"clearPointerStart",
|
|
1368
|
+
"clearDragOffset",
|
|
1369
|
+
"clearSizeMeasurements"
|
|
1370
|
+
]
|
|
1371
|
+
}
|
|
1372
|
+
],
|
|
1373
|
+
POINTER_CANCEL: {
|
|
1374
|
+
target: "closed",
|
|
1375
|
+
actions: [
|
|
1376
|
+
"clearPointerStart",
|
|
1377
|
+
"clearDragOffset",
|
|
1378
|
+
"clearSizeMeasurements",
|
|
1379
|
+
"clearVelocityTracking"
|
|
1380
|
+
]
|
|
1381
|
+
},
|
|
1382
|
+
"CONTROLLED.OPEN": { target: "open" },
|
|
1383
|
+
CLOSE: {
|
|
1384
|
+
target: "closed",
|
|
1385
|
+
actions: [
|
|
1386
|
+
"clearPointerStart",
|
|
1387
|
+
"clearDragOffset",
|
|
1388
|
+
"clearSizeMeasurements"
|
|
1389
|
+
]
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
},
|
|
400
1393
|
closed: {
|
|
401
1394
|
tags: ["closed"],
|
|
402
1395
|
on: {
|
|
@@ -407,7 +1400,11 @@ const machine = createMachine({
|
|
|
407
1400
|
}, {
|
|
408
1401
|
target: "open",
|
|
409
1402
|
actions: ["invokeOnOpen"]
|
|
410
|
-
}]
|
|
1403
|
+
}],
|
|
1404
|
+
"SWIPE_AREA.START": {
|
|
1405
|
+
target: "swipe-area-dragging",
|
|
1406
|
+
actions: ["setPointerStart"]
|
|
1407
|
+
}
|
|
411
1408
|
}
|
|
412
1409
|
}
|
|
413
1410
|
},
|
|
@@ -417,71 +1414,204 @@ const machine = createMachine({
|
|
|
417
1414
|
isDragging({ context }) {
|
|
418
1415
|
return context.get("dragOffset") !== null;
|
|
419
1416
|
},
|
|
420
|
-
shouldStartDragging({ prop, refs, event, scope }) {
|
|
421
|
-
return refs.get("
|
|
1417
|
+
shouldStartDragging({ computed, prop, refs, event, scope }) {
|
|
1418
|
+
return refs.get("swipeSession").canStartDrag(event.point, event.target, getContentEl(scope), prop("preventDragOnScroll"), computed("physicalSwipeDirection"));
|
|
422
1419
|
},
|
|
423
1420
|
shouldCloseOnSwipe({ prop, context, computed, refs }) {
|
|
424
|
-
|
|
1421
|
+
if (prop("snapToSequentialPoints")) return false;
|
|
1422
|
+
return refs.get("swipeSession").shouldDismissOnRelease(context.get("contentSize"), computed("resolvedSnapPoints"), getActiveSnapOffset(context));
|
|
1423
|
+
},
|
|
1424
|
+
hasSwipeIntent({ refs, computed, event }) {
|
|
1425
|
+
const start = refs.get("swipeSession").getSwipeStart();
|
|
1426
|
+
if (!start || !event.point) return false;
|
|
1427
|
+
return hasOpeningSwipeIntent(start, event.point, computed("physicalSwipeDirection"));
|
|
1428
|
+
},
|
|
1429
|
+
shouldOpenOnSwipe({ context, refs, prop }) {
|
|
1430
|
+
return refs.get("swipeSession").shouldOpenOnRelease(context.get("contentSize"), prop("swipeVelocityThreshold"), prop("closeThreshold"));
|
|
425
1431
|
}
|
|
426
1432
|
},
|
|
427
1433
|
actions: {
|
|
1434
|
+
setInitialFocus({ prop, scope }) {
|
|
1435
|
+
if (prop("trapFocus")) return;
|
|
1436
|
+
raf(() => {
|
|
1437
|
+
getInitialFocus({
|
|
1438
|
+
root: getContentEl(scope),
|
|
1439
|
+
getInitialEl: prop("initialFocusEl")
|
|
1440
|
+
})?.focus({ preventScroll: true });
|
|
1441
|
+
});
|
|
1442
|
+
},
|
|
1443
|
+
checkRenderedElements({ context, scope }) {
|
|
1444
|
+
raf(() => {
|
|
1445
|
+
context.set("rendered", {
|
|
1446
|
+
title: !!getTitleEl(scope),
|
|
1447
|
+
description: !!getDescriptionEl(scope)
|
|
1448
|
+
});
|
|
1449
|
+
});
|
|
1450
|
+
},
|
|
1451
|
+
deferClearDragOffset({ context, refs, scope }) {
|
|
1452
|
+
if (context.get("dragOffset") === null) return;
|
|
1453
|
+
const contentEl = getContentEl(scope);
|
|
1454
|
+
const backdropEl = getBackdropEl(scope);
|
|
1455
|
+
if (contentEl) contentEl.style.setProperty("animation", "none", "important");
|
|
1456
|
+
if (backdropEl) backdropEl.style.setProperty("animation", "none", "important");
|
|
1457
|
+
raf(() => {
|
|
1458
|
+
refs.get("swipeSession").resetDragOffset();
|
|
1459
|
+
context.set("dragOffset", null);
|
|
1460
|
+
});
|
|
1461
|
+
},
|
|
1462
|
+
suppressBackdropAnimation({ scope }) {
|
|
1463
|
+
const backdropEl = getBackdropEl(scope);
|
|
1464
|
+
if (!backdropEl) return;
|
|
1465
|
+
backdropEl.style.setProperty("animation", "none", "important");
|
|
1466
|
+
},
|
|
1467
|
+
clearSwipeOpenAnimation({ scope }) {
|
|
1468
|
+
const contentEl = getContentEl(scope);
|
|
1469
|
+
const backdropEl = getBackdropEl(scope);
|
|
1470
|
+
if (contentEl) contentEl.style.removeProperty("animation");
|
|
1471
|
+
if (backdropEl) backdropEl.style.removeProperty("animation");
|
|
1472
|
+
},
|
|
428
1473
|
invokeOnOpen({ prop }) {
|
|
429
1474
|
prop("onOpenChange")?.({ open: true });
|
|
430
1475
|
},
|
|
431
1476
|
invokeOnClose({ prop }) {
|
|
432
1477
|
prop("onOpenChange")?.({ open: false });
|
|
433
1478
|
},
|
|
434
|
-
|
|
435
|
-
context.set("
|
|
1479
|
+
setSnapPoint({ context, event }) {
|
|
1480
|
+
context.set("snapPoint", event.snapPoint);
|
|
436
1481
|
},
|
|
437
1482
|
setPointerStart({ event, refs }) {
|
|
438
|
-
refs.get("
|
|
1483
|
+
refs.get("swipeSession").beginSwipe(event.point);
|
|
439
1484
|
},
|
|
440
|
-
setDragOffset({ context, event, refs }) {
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
1485
|
+
setDragOffset({ context, event, refs, computed }) {
|
|
1486
|
+
const swipeSession = refs.get("swipeSession");
|
|
1487
|
+
const physicalSwipeDirection = event.swipeDirection ?? computed("physicalSwipeDirection");
|
|
1488
|
+
swipeSession.setDragOffset(event.point, getActiveSnapOffset(context), physicalSwipeDirection);
|
|
1489
|
+
context.set("dragOffset", swipeSession.getDragOffset());
|
|
444
1490
|
},
|
|
445
|
-
|
|
1491
|
+
setSwipeOpenDragOffset({ context, event, refs, computed }) {
|
|
1492
|
+
const swipeSession = refs.get("swipeSession");
|
|
1493
|
+
const contentSize = context.get("contentSize");
|
|
1494
|
+
if (!contentSize) return;
|
|
1495
|
+
swipeSession.setSwipeOpenOffset(event.point, contentSize, computed("physicalSwipeDirection"));
|
|
1496
|
+
context.set("dragOffset", swipeSession.getDragOffset());
|
|
1497
|
+
},
|
|
1498
|
+
setClosestSnapPoint({ computed, context, refs, prop, send }) {
|
|
446
1499
|
const snapPoints = computed("resolvedSnapPoints");
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
const
|
|
1500
|
+
const contentSize = context.get("contentSize");
|
|
1501
|
+
const viewportSize = context.get("viewportSize");
|
|
1502
|
+
const rootFontSize = context.get("rootFontSize");
|
|
1503
|
+
if (!snapPoints.length || contentSize === null) return;
|
|
1504
|
+
const closestSnapPoint = refs.get("swipeSession").resolveSnapPointOnRelease(snapPoints, context.get("resolvedActiveSnapPoint"), prop("snapToSequentialPoints"), contentSize);
|
|
1505
|
+
if (closestSnapPoint === null) {
|
|
1506
|
+
send({ type: "CLOSE" });
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
context.set("snapPoint", closestSnapPoint);
|
|
1510
|
+
const resolved = resolveSnapPoint(closestSnapPoint, {
|
|
1511
|
+
contentSize,
|
|
1512
|
+
viewportSize,
|
|
1513
|
+
rootFontSize
|
|
1514
|
+
});
|
|
452
1515
|
context.set("resolvedActiveSnapPoint", resolved);
|
|
453
1516
|
},
|
|
454
1517
|
clearDragOffset({ context, refs }) {
|
|
455
|
-
refs.get("
|
|
1518
|
+
refs.get("swipeSession").resetDragOffset();
|
|
456
1519
|
context.set("dragOffset", null);
|
|
457
1520
|
},
|
|
458
|
-
clearActiveSnapPoint({ context
|
|
459
|
-
context.set("
|
|
1521
|
+
clearActiveSnapPoint({ context }) {
|
|
1522
|
+
context.set("snapPoint", context.initial("snapPoint"));
|
|
1523
|
+
},
|
|
1524
|
+
clearSizeMeasurements({ context }) {
|
|
1525
|
+
context.set("contentSize", null);
|
|
1526
|
+
context.set("viewportSize", 0);
|
|
1527
|
+
context.set("rootFontSize", 16);
|
|
460
1528
|
},
|
|
461
1529
|
clearResolvedActiveSnapPoint({ context }) {
|
|
462
1530
|
context.set("resolvedActiveSnapPoint", null);
|
|
463
1531
|
},
|
|
464
1532
|
clearPointerStart({ refs }) {
|
|
465
|
-
refs.get("
|
|
466
|
-
},
|
|
467
|
-
clearContentHeight({ context }) {
|
|
468
|
-
context.set("contentHeight", null);
|
|
1533
|
+
refs.get("swipeSession").clearSwipeStart();
|
|
469
1534
|
},
|
|
470
1535
|
clearVelocityTracking({ refs }) {
|
|
471
|
-
refs.get("
|
|
1536
|
+
refs.get("swipeSession").resetVelocity();
|
|
1537
|
+
},
|
|
1538
|
+
setSnapSwipeStrength({ context, refs, computed, prop }) {
|
|
1539
|
+
const swipeSession = refs.get("swipeSession");
|
|
1540
|
+
const snapPoints = computed("resolvedSnapPoints");
|
|
1541
|
+
const contentSize = context.get("contentSize");
|
|
1542
|
+
const closestSnapPoint = swipeSession.resolveSnapPointOnRelease(snapPoints, context.get("resolvedActiveSnapPoint"), prop("snapToSequentialPoints"), contentSize ?? 0);
|
|
1543
|
+
if (closestSnapPoint === null) return;
|
|
1544
|
+
const viewportSize = context.get("viewportSize");
|
|
1545
|
+
const rootFontSize = context.get("rootFontSize");
|
|
1546
|
+
const resolved = resolveSnapPoint(closestSnapPoint, {
|
|
1547
|
+
contentSize: contentSize ?? 0,
|
|
1548
|
+
viewportSize,
|
|
1549
|
+
rootFontSize
|
|
1550
|
+
});
|
|
1551
|
+
const restOffset = getActiveSnapOffset(context);
|
|
1552
|
+
context.set("swipeStrength", swipeSession.getSwipeStrength(resolved?.offset ?? 0, restOffset));
|
|
1553
|
+
},
|
|
1554
|
+
setDismissSwipeStrength({ context, refs }) {
|
|
1555
|
+
const swipeSession = refs.get("swipeSession");
|
|
1556
|
+
const contentSize = context.get("contentSize");
|
|
1557
|
+
const restOffset = getActiveSnapOffset(context);
|
|
1558
|
+
context.set("swipeStrength", swipeSession.getSwipeStrength(contentSize ?? 0, restOffset));
|
|
1559
|
+
},
|
|
1560
|
+
resetSwipeStrength({ context }) {
|
|
1561
|
+
context.set("swipeStrength", 1);
|
|
1562
|
+
},
|
|
1563
|
+
setRegistrySwiping({ computed }) {
|
|
1564
|
+
drawerRegistry.setSwiping(computed("drawerId"), true);
|
|
1565
|
+
},
|
|
1566
|
+
clearRegistrySwiping({ computed }) {
|
|
1567
|
+
drawerRegistry.setSwiping(computed("drawerId"), false);
|
|
472
1568
|
},
|
|
473
1569
|
toggleVisibility({ event, send, prop }) {
|
|
474
1570
|
send({
|
|
475
1571
|
type: prop("open") ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE",
|
|
476
1572
|
previousEvent: event
|
|
477
1573
|
});
|
|
1574
|
+
},
|
|
1575
|
+
syncDrawerStack({ context, prop, computed }) {
|
|
1576
|
+
const contentSize = context.get("contentSize");
|
|
1577
|
+
if (contentSize === null) return;
|
|
1578
|
+
const dragOffset = context.get("dragOffset");
|
|
1579
|
+
const progress = resolveSwipeProgress(contentSize, dragOffset, getActiveSnapOffset(context));
|
|
1580
|
+
const id = computed("drawerId");
|
|
1581
|
+
if (dragOffset !== null) drawerRegistry.setSwipeProgress(id, progress);
|
|
1582
|
+
const stack = prop("stack");
|
|
1583
|
+
if (!stack) return;
|
|
1584
|
+
stack.setHeight(id, contentSize);
|
|
1585
|
+
stack.setSwipe(id, dragOffset !== null, progress);
|
|
478
1586
|
}
|
|
479
1587
|
},
|
|
480
1588
|
effects: {
|
|
1589
|
+
trackDrawerStack({ context, prop, computed }) {
|
|
1590
|
+
const stack = prop("stack");
|
|
1591
|
+
if (!stack) return;
|
|
1592
|
+
const id = computed("drawerId");
|
|
1593
|
+
stack.register(id);
|
|
1594
|
+
stack.setOpen(id, true);
|
|
1595
|
+
const sync = () => {
|
|
1596
|
+
const contentSize = context.get("contentSize");
|
|
1597
|
+
const dragOffset = context.get("dragOffset");
|
|
1598
|
+
const snapPointOffset = getActiveSnapOffset(context);
|
|
1599
|
+
stack.setHeight(id, contentSize ?? 0);
|
|
1600
|
+
stack.setSwipe(id, dragOffset !== null, resolveSwipeProgress(contentSize, dragOffset, snapPointOffset));
|
|
1601
|
+
};
|
|
1602
|
+
sync();
|
|
1603
|
+
return () => {
|
|
1604
|
+
stack.setSwipe(id, false, 0);
|
|
1605
|
+
stack.setOpen(id, false);
|
|
1606
|
+
stack.unregister(id);
|
|
1607
|
+
};
|
|
1608
|
+
},
|
|
481
1609
|
trackDismissableElement({ scope, prop, send }) {
|
|
482
1610
|
const getContentEl$1 = () => getContentEl(scope);
|
|
483
1611
|
return trackDismissableElement(getContentEl$1, {
|
|
1612
|
+
type: "drawer",
|
|
484
1613
|
defer: true,
|
|
1614
|
+
pointerBlocking: prop("modal"),
|
|
485
1615
|
exclude: [getTriggerEl(scope)],
|
|
486
1616
|
onInteractOutside(event) {
|
|
487
1617
|
prop("onInteractOutside")?.(event);
|
|
@@ -513,7 +1643,7 @@ const machine = createMachine({
|
|
|
513
1643
|
preventScroll: true,
|
|
514
1644
|
returnFocusOnDeactivate: !!prop("restoreFocus"),
|
|
515
1645
|
initialFocus: prop("initialFocusEl"),
|
|
516
|
-
setReturnFocus: (el) => prop("finalFocusEl")?.()
|
|
1646
|
+
setReturnFocus: (el) => prop("finalFocusEl")?.() ?? getTriggerEl(scope) ?? el,
|
|
517
1647
|
getShadowRoot: true
|
|
518
1648
|
});
|
|
519
1649
|
},
|
|
@@ -522,105 +1652,115 @@ const machine = createMachine({
|
|
|
522
1652
|
const getElements = () => [getContentEl(scope)];
|
|
523
1653
|
return ariaHidden(getElements, { defer: true });
|
|
524
1654
|
},
|
|
525
|
-
trackPointerMove({ scope, send,
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
function onPointerUp(event) {
|
|
535
|
-
if (event.pointerType === "touch") return;
|
|
536
|
-
send({
|
|
537
|
-
type: "POINTER_UP",
|
|
538
|
-
point: getEventPoint(event)
|
|
539
|
-
});
|
|
540
|
-
}
|
|
541
|
-
function onTouchStart(event) {
|
|
542
|
-
if (!event.touches[0]) return;
|
|
543
|
-
lastY = event.touches[0].clientY;
|
|
544
|
-
}
|
|
545
|
-
function onTouchMove(event) {
|
|
546
|
-
if (!event.touches[0]) return;
|
|
547
|
-
const point = getEventPoint(event);
|
|
548
|
-
const target = event.target;
|
|
549
|
-
if (!prop("preventDragOnScroll")) {
|
|
1655
|
+
trackPointerMove({ scope, send, refs, computed }) {
|
|
1656
|
+
return refs.get("swipeSession").bindDragTracking({
|
|
1657
|
+
getDoc: () => scope.getDoc(),
|
|
1658
|
+
getContentEl: () => getContentEl(scope),
|
|
1659
|
+
getSwipeAreaEl: () => getSwipeAreaEl(scope),
|
|
1660
|
+
swipeDirection: computed("physicalSwipeDirection"),
|
|
1661
|
+
onMove(details) {
|
|
550
1662
|
send({
|
|
551
1663
|
type: "POINTER_MOVE",
|
|
552
|
-
|
|
553
|
-
target
|
|
1664
|
+
...details
|
|
554
1665
|
});
|
|
555
|
-
|
|
1666
|
+
},
|
|
1667
|
+
onEnd(details) {
|
|
1668
|
+
send({
|
|
1669
|
+
type: "POINTER_UP",
|
|
1670
|
+
...details
|
|
1671
|
+
});
|
|
1672
|
+
},
|
|
1673
|
+
onCancel() {
|
|
1674
|
+
send({ type: "POINTER_CANCEL" });
|
|
556
1675
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
1676
|
+
});
|
|
1677
|
+
},
|
|
1678
|
+
trackSizeMeasurements({ context, scope, computed, prop }) {
|
|
1679
|
+
const contentEl = getContentEl(scope);
|
|
1680
|
+
if (!contentEl) return;
|
|
1681
|
+
const html = scope.getDoc().documentElement;
|
|
1682
|
+
const shouldMeasureRootFontSize = hasRemSnapPoints(prop("snapPoints"));
|
|
1683
|
+
const updateSize = () => {
|
|
1684
|
+
const direction = computed("physicalSwipeDirection");
|
|
1685
|
+
const rect = contentEl.getBoundingClientRect();
|
|
1686
|
+
const viewportSize = isVerticalSwipeDirection(direction) ? html.clientHeight : html.clientWidth;
|
|
1687
|
+
context.set("contentSize", getSwipeDirectionSize(rect, direction));
|
|
1688
|
+
context.set("viewportSize", viewportSize);
|
|
1689
|
+
if (shouldMeasureRootFontSize) {
|
|
1690
|
+
const rootFontSize = Number.parseFloat(getComputedStyle(html).fontSize);
|
|
1691
|
+
if (Number.isFinite(rootFontSize)) context.set("rootFontSize", rootFontSize);
|
|
566
1692
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
target
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
function onTouchEnd(event) {
|
|
574
|
-
if (event.touches.length !== 0) return;
|
|
575
|
-
send({
|
|
576
|
-
type: "POINTER_UP",
|
|
577
|
-
point: getEventPoint(event)
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
const doc = scope.getDoc();
|
|
581
|
-
const cleanups = [
|
|
582
|
-
addDomEvent(doc, "pointermove", onPointerMove),
|
|
583
|
-
addDomEvent(doc, "pointerup", onPointerUp),
|
|
584
|
-
addDomEvent(doc, "touchstart", onTouchStart, { passive: false }),
|
|
585
|
-
addDomEvent(doc, "touchmove", onTouchMove, { passive: false }),
|
|
586
|
-
addDomEvent(doc, "touchend", onTouchEnd)
|
|
587
|
-
];
|
|
1693
|
+
};
|
|
1694
|
+
updateSize();
|
|
1695
|
+
const cleanups = [resizeObserverBorderBox.observe(contentEl, updateSize), addDomEvent(scope.getWin(), "resize", updateSize)];
|
|
588
1696
|
return () => {
|
|
589
|
-
cleanups.forEach((cleanup) => cleanup());
|
|
1697
|
+
cleanups.forEach((cleanup) => cleanup?.());
|
|
590
1698
|
};
|
|
591
1699
|
},
|
|
592
|
-
|
|
1700
|
+
trackNestedDrawerMetrics({ scope, computed }) {
|
|
593
1701
|
const contentEl = getContentEl(scope);
|
|
594
1702
|
if (!contentEl) return;
|
|
595
|
-
const
|
|
596
|
-
|
|
597
|
-
|
|
1703
|
+
const id = computed("drawerId");
|
|
1704
|
+
drawerRegistry.register(id, contentEl);
|
|
1705
|
+
const sync = () => {
|
|
1706
|
+
const entries = [...drawerRegistry.getEntries().entries()];
|
|
1707
|
+
const myIndex = entries.findIndex(([entryId]) => entryId === id);
|
|
1708
|
+
if (myIndex === -1) return;
|
|
1709
|
+
const nestedCount = entries.length - 1 - myIndex;
|
|
1710
|
+
const frontmostHeight = (entries[entries.length - 1]?.[1])?.getBoundingClientRect().height ?? 0;
|
|
1711
|
+
const myHeight = contentEl.getBoundingClientRect().height;
|
|
1712
|
+
contentEl.style.setProperty("--nested-drawers", `${nestedCount}`);
|
|
1713
|
+
contentEl.style.setProperty("--drawer-height", `${myHeight}px`);
|
|
1714
|
+
contentEl.style.setProperty("--drawer-frontmost-height", `${frontmostHeight}px`);
|
|
1715
|
+
if (nestedCount > 0 && frontmostHeight > 0) contentEl.setAttribute("data-nested-drawer-open", "");
|
|
1716
|
+
else if (nestedCount === 0) contentEl.removeAttribute("data-nested-drawer-open");
|
|
1717
|
+
if (drawerRegistry.hasSwipingAfter(id)) contentEl.setAttribute("data-nested-drawer-swiping", "");
|
|
1718
|
+
else contentEl.removeAttribute("data-nested-drawer-swiping");
|
|
1719
|
+
};
|
|
1720
|
+
sync();
|
|
1721
|
+
const cleanups = [
|
|
1722
|
+
drawerRegistry.subscribe(sync),
|
|
1723
|
+
resizeObserverBorderBox.observe(contentEl, () => drawerRegistry.notify()),
|
|
1724
|
+
addDomEvent(scope.getWin(), "resize", () => drawerRegistry.notify())
|
|
1725
|
+
];
|
|
1726
|
+
return () => {
|
|
1727
|
+
cleanups.forEach((cleanup) => cleanup?.());
|
|
1728
|
+
contentEl.removeAttribute("data-nested-drawer-open");
|
|
1729
|
+
contentEl.removeAttribute("data-nested-drawer-swiping");
|
|
1730
|
+
contentEl.style.setProperty("--nested-drawers", "0");
|
|
1731
|
+
contentEl.style.removeProperty("--drawer-frontmost-height");
|
|
1732
|
+
drawerRegistry.unregister(id);
|
|
598
1733
|
};
|
|
599
|
-
updateHeight();
|
|
600
|
-
return resizeObserverBorderBox.observe(contentEl, updateHeight);
|
|
601
1734
|
},
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
send({
|
|
610
|
-
|
|
1735
|
+
trackSwipeOpenPointerMove({ scope, send, refs, computed }) {
|
|
1736
|
+
return refs.get("swipeSession").bindSwipeOpenTracking({
|
|
1737
|
+
getDoc: () => scope.getDoc(),
|
|
1738
|
+
getContentEl: () => getContentEl(scope),
|
|
1739
|
+
getSwipeAreaEl: () => getSwipeAreaEl(scope),
|
|
1740
|
+
swipeDirection: computed("physicalSwipeDirection"),
|
|
1741
|
+
onMove(details) {
|
|
1742
|
+
send({
|
|
1743
|
+
type: "POINTER_MOVE",
|
|
1744
|
+
...details
|
|
1745
|
+
});
|
|
1746
|
+
},
|
|
1747
|
+
onEnd(details) {
|
|
1748
|
+
send({
|
|
1749
|
+
type: "POINTER_UP",
|
|
1750
|
+
...details
|
|
1751
|
+
});
|
|
1752
|
+
},
|
|
1753
|
+
onCancel() {
|
|
1754
|
+
send({ type: "POINTER_CANCEL" });
|
|
611
1755
|
}
|
|
612
|
-
const onEnd = (event) => {
|
|
613
|
-
if (getEventTarget(event) === contentEl) send({ type: "ANIMATION_END" });
|
|
614
|
-
};
|
|
615
|
-
contentEl.addEventListener("animationend", onEnd);
|
|
616
|
-
cleanup = () => {
|
|
617
|
-
contentEl.removeEventListener("animationend", onEnd);
|
|
618
|
-
};
|
|
619
1756
|
});
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
1757
|
+
},
|
|
1758
|
+
trackExitAnimation({ send, scope }) {
|
|
1759
|
+
const contentEl = getContentEl(scope);
|
|
1760
|
+
if (!contentEl) return;
|
|
1761
|
+
return addDomEvent(contentEl, "exitcomplete", () => {
|
|
1762
|
+
send({ type: "ANIMATION_END" });
|
|
1763
|
+
});
|
|
624
1764
|
}
|
|
625
1765
|
}
|
|
626
1766
|
}
|
|
@@ -638,6 +1778,8 @@ const props = createProps()([
|
|
|
638
1778
|
"defaultOpen",
|
|
639
1779
|
"getRootNode",
|
|
640
1780
|
"snapPoints",
|
|
1781
|
+
"swipeDirection",
|
|
1782
|
+
"snapToSequentialPoints",
|
|
641
1783
|
"swipeVelocityThreshold",
|
|
642
1784
|
"closeThreshold",
|
|
643
1785
|
"preventDragOnScroll",
|
|
@@ -653,10 +1795,133 @@ const props = createProps()([
|
|
|
653
1795
|
"restoreFocus",
|
|
654
1796
|
"role",
|
|
655
1797
|
"trapFocus",
|
|
656
|
-
"
|
|
657
|
-
"
|
|
658
|
-
"
|
|
1798
|
+
"defaultSnapPoint",
|
|
1799
|
+
"snapPoint",
|
|
1800
|
+
"onSnapPointChange",
|
|
1801
|
+
"stack"
|
|
659
1802
|
]);
|
|
660
1803
|
const splitProps = createSplitProps(props);
|
|
661
1804
|
//#endregion
|
|
662
|
-
|
|
1805
|
+
//#region src/machines/drawer/drawer.stack.ts
|
|
1806
|
+
function resolveSnapshot(entries) {
|
|
1807
|
+
let openCount = 0;
|
|
1808
|
+
let frontmostHeight = 0;
|
|
1809
|
+
let swipeProgress = 0;
|
|
1810
|
+
let frontmostOrder = -1;
|
|
1811
|
+
entries.forEach((entry) => {
|
|
1812
|
+
if (!entry.open) return;
|
|
1813
|
+
openCount += 1;
|
|
1814
|
+
if (entry.order < frontmostOrder) return;
|
|
1815
|
+
frontmostOrder = entry.order;
|
|
1816
|
+
frontmostHeight = entry.height > 0 ? entry.height : 0;
|
|
1817
|
+
swipeProgress = entry.swiping ? clampValue(entry.swipeProgress, 0, 1) : 0;
|
|
1818
|
+
});
|
|
1819
|
+
return {
|
|
1820
|
+
active: openCount > 0,
|
|
1821
|
+
openCount,
|
|
1822
|
+
swipeProgress,
|
|
1823
|
+
frontmostHeight
|
|
1824
|
+
};
|
|
1825
|
+
}
|
|
1826
|
+
function createStack() {
|
|
1827
|
+
const entries = /* @__PURE__ */ new Map();
|
|
1828
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1829
|
+
let order = 0;
|
|
1830
|
+
let pendingNotify = false;
|
|
1831
|
+
let snapshot = Object.freeze({
|
|
1832
|
+
active: false,
|
|
1833
|
+
openCount: 0,
|
|
1834
|
+
swipeProgress: 0,
|
|
1835
|
+
frontmostHeight: 0
|
|
1836
|
+
});
|
|
1837
|
+
const scheduleNotify = () => {
|
|
1838
|
+
if (pendingNotify) return;
|
|
1839
|
+
pendingNotify = true;
|
|
1840
|
+
queueMicrotask(() => {
|
|
1841
|
+
pendingNotify = false;
|
|
1842
|
+
listeners.forEach((listener) => listener());
|
|
1843
|
+
});
|
|
1844
|
+
};
|
|
1845
|
+
const notify = () => {
|
|
1846
|
+
const nextSnapshot = resolveSnapshot(entries);
|
|
1847
|
+
if (snapshot.active === nextSnapshot.active && snapshot.openCount === nextSnapshot.openCount && snapshot.swipeProgress === nextSnapshot.swipeProgress && snapshot.frontmostHeight === nextSnapshot.frontmostHeight) return;
|
|
1848
|
+
snapshot = Object.freeze(nextSnapshot);
|
|
1849
|
+
scheduleNotify();
|
|
1850
|
+
};
|
|
1851
|
+
const ensureEntry = (id) => {
|
|
1852
|
+
let entry = entries.get(id);
|
|
1853
|
+
if (!entry) {
|
|
1854
|
+
entry = {
|
|
1855
|
+
order: ++order,
|
|
1856
|
+
open: false,
|
|
1857
|
+
height: 0,
|
|
1858
|
+
swiping: false,
|
|
1859
|
+
swipeProgress: 0
|
|
1860
|
+
};
|
|
1861
|
+
entries.set(id, entry);
|
|
1862
|
+
}
|
|
1863
|
+
return entry;
|
|
1864
|
+
};
|
|
1865
|
+
return {
|
|
1866
|
+
getSnapshot() {
|
|
1867
|
+
return snapshot;
|
|
1868
|
+
},
|
|
1869
|
+
subscribe(listener) {
|
|
1870
|
+
listeners.add(listener);
|
|
1871
|
+
return () => {
|
|
1872
|
+
listeners.delete(listener);
|
|
1873
|
+
};
|
|
1874
|
+
},
|
|
1875
|
+
register(id) {
|
|
1876
|
+
ensureEntry(id);
|
|
1877
|
+
notify();
|
|
1878
|
+
},
|
|
1879
|
+
unregister(id) {
|
|
1880
|
+
if (!entries.delete(id)) return;
|
|
1881
|
+
notify();
|
|
1882
|
+
},
|
|
1883
|
+
setOpen(id, open) {
|
|
1884
|
+
const entry = ensureEntry(id);
|
|
1885
|
+
if (entry.open === open) return;
|
|
1886
|
+
entry.open = open;
|
|
1887
|
+
if (!open) {
|
|
1888
|
+
entry.swiping = false;
|
|
1889
|
+
entry.swipeProgress = 0;
|
|
1890
|
+
}
|
|
1891
|
+
notify();
|
|
1892
|
+
},
|
|
1893
|
+
setHeight(id, height) {
|
|
1894
|
+
const entry = ensureEntry(id);
|
|
1895
|
+
const nextHeight = Number.isFinite(height) && height > 0 ? height : 0;
|
|
1896
|
+
if (entry.height === nextHeight) return;
|
|
1897
|
+
entry.height = nextHeight;
|
|
1898
|
+
notify();
|
|
1899
|
+
},
|
|
1900
|
+
setSwipe(id, swiping, progress) {
|
|
1901
|
+
const entry = ensureEntry(id);
|
|
1902
|
+
const nextProgress = swiping ? clampValue(Number.isFinite(progress) ? progress : 0, 0, 1) : 0;
|
|
1903
|
+
if (entry.swiping === swiping && entry.swipeProgress === nextProgress) return;
|
|
1904
|
+
entry.swiping = swiping;
|
|
1905
|
+
entry.swipeProgress = nextProgress;
|
|
1906
|
+
notify();
|
|
1907
|
+
}
|
|
1908
|
+
};
|
|
1909
|
+
}
|
|
1910
|
+
function connectStack(snapshot, normalize) {
|
|
1911
|
+
const getIndentProps = () => {
|
|
1912
|
+
return normalize.element({
|
|
1913
|
+
"data-active": snapshot.active ? "" : void 0,
|
|
1914
|
+
"data-inactive": snapshot.active ? void 0 : "",
|
|
1915
|
+
style: {
|
|
1916
|
+
"--drawer-swipe-progress": `${clampValue(snapshot.swipeProgress, 0, 1)}`,
|
|
1917
|
+
"--drawer-frontmost-height": snapshot.frontmostHeight > 0 ? `${snapshot.frontmostHeight}px` : void 0
|
|
1918
|
+
}
|
|
1919
|
+
});
|
|
1920
|
+
};
|
|
1921
|
+
return {
|
|
1922
|
+
getIndentProps,
|
|
1923
|
+
getIndentBackgroundProps: getIndentProps
|
|
1924
|
+
};
|
|
1925
|
+
}
|
|
1926
|
+
//#endregion
|
|
1927
|
+
export { anatomy, connect, connectStack, createStack, machine, props, splitProps };
|