@stacknav/core 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -59
- package/dist/animate.d.ts +18 -0
- package/dist/animate.d.ts.map +1 -1
- package/dist/animate.js +44 -2
- package/dist/animate.js.map +1 -1
- package/dist/css-vars.d.ts +3 -3
- package/dist/css-vars.d.ts.map +1 -1
- package/dist/css-vars.js +47 -4
- package/dist/css-vars.js.map +1 -1
- package/dist/history-adapter.d.ts +0 -1
- package/dist/history-adapter.d.ts.map +1 -1
- package/dist/history-adapter.js +1 -5
- package/dist/history-adapter.js.map +1 -1
- package/dist/index.d.ts +27 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -15
- package/dist/index.js.map +1 -1
- package/dist/native-transition.d.ts +93 -0
- package/dist/native-transition.d.ts.map +1 -0
- package/dist/{ios-transition.js → native-transition.js} +42 -25
- package/dist/native-transition.js.map +1 -0
- package/dist/navigation-stack.d.ts +3 -0
- package/dist/navigation-stack.d.ts.map +1 -1
- package/dist/navigation-stack.js +42 -3
- package/dist/navigation-stack.js.map +1 -1
- package/dist/platform.d.ts +6 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +22 -0
- package/dist/platform.js.map +1 -0
- package/dist/stacknav.css +4 -13
- package/dist/styles.d.ts +5 -9
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +6 -12
- package/dist/styles.js.map +1 -1
- package/dist/swipe-back.d.ts +4 -0
- package/dist/swipe-back.d.ts.map +1 -0
- package/dist/swipe-back.js +31 -0
- package/dist/swipe-back.js.map +1 -0
- package/package.json +3 -2
- package/src/animate.ts +47 -4
- package/src/css-vars.ts +43 -4
- package/src/history-adapter.ts +1 -5
- package/src/index.ts +49 -24
- package/src/{ios-transition.ts → native-transition.ts} +67 -35
- package/src/navigation-stack.ts +30 -3
- package/src/platform.ts +23 -0
- package/src/styles.ts +6 -12
- package/src/swipe-back.ts +35 -0
- package/dist/edge-pan-gesture.d.ts +0 -36
- package/dist/edge-pan-gesture.d.ts.map +0 -1
- package/dist/edge-pan-gesture.js +0 -155
- package/dist/edge-pan-gesture.js.map +0 -1
- package/dist/ios-transition.d.ts +0 -61
- package/dist/ios-transition.d.ts.map +0 -1
- package/dist/ios-transition.js.map +0 -1
- package/src/edge-pan-gesture.ts +0 -190
package/dist/ios-transition.d.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { type Easing } from './animate.ts';
|
|
2
|
-
import type { Transition } from './navigation-stack.ts';
|
|
3
|
-
export interface IOSTransitionOptions {
|
|
4
|
-
/** ms, programmatic push/pop */
|
|
5
|
-
duration: number;
|
|
6
|
-
/**
|
|
7
|
-
* the curve a programmatic push/pop runs on. CSS runs it, so it has to be
|
|
8
|
-
* one CSS can spell: everything `cubicBezier()` and `parseEasing()` build
|
|
9
|
-
* carries a `css` property. A bare `(t) => number` of your own has none, so
|
|
10
|
-
* the pages would run `linear` while `progress` reported your curve; give it
|
|
11
|
-
* a `css` property, or write the whole transition yourself.
|
|
12
|
-
*/
|
|
13
|
-
ease: Easing;
|
|
14
|
-
/** fraction of the width the lower page travels */
|
|
15
|
-
parallax: number;
|
|
16
|
-
dimColor: string;
|
|
17
|
-
/** lower-page overlay opacity at p = 1 (≈0.35 suits dark UIs) */
|
|
18
|
-
dimMax: number;
|
|
19
|
-
/** box-shadow on the incoming page */
|
|
20
|
-
shadow: string;
|
|
21
|
-
/** ms bounds for finishing an interactive pop */
|
|
22
|
-
settleMin: number;
|
|
23
|
-
settleMax: number;
|
|
24
|
-
/** the curve the remaining distance of an interactive pop runs on; see `ease` */
|
|
25
|
-
settleEase: Easing;
|
|
26
|
-
/** px/s assumed when the pointer was slower than this */
|
|
27
|
-
settleVelocityFloor: number;
|
|
28
|
-
/** multiplies every duration, for slow motion and tests */
|
|
29
|
-
timeScale: number;
|
|
30
|
-
}
|
|
31
|
-
/** The CSS custom property behind each option. */
|
|
32
|
-
export declare const IOS_TRANSITION_CSS_VARS: Readonly<Record<keyof IOSTransitionOptions, string>>;
|
|
33
|
-
export interface IOSTransition extends Transition {
|
|
34
|
-
/** The JS options: the defaults with the caller's merged in. Mutable at runtime. */
|
|
35
|
-
readonly options: IOSTransitionOptions;
|
|
36
|
-
/** The values currently in force: `options` with the CSS variables applied over them. */
|
|
37
|
-
readonly resolved: Readonly<IOSTransitionOptions>;
|
|
38
|
-
/**
|
|
39
|
-
* Re-reads the CSS variables, from `el` or from the container of the last
|
|
40
|
-
* transition. Called at the start of every transition. Call it directly
|
|
41
|
-
* after changing `options` or the variables mid-animation.
|
|
42
|
-
*/
|
|
43
|
-
refresh(el?: Element | null): void;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* The iOS navigation transition: the upper page slides in from the trailing
|
|
47
|
-
* edge with a shadow on its leading edge, while the lower page parallaxes
|
|
48
|
-
* toward the leading edge and dims. Every value is a function of one number, p.
|
|
49
|
-
*
|
|
50
|
-
* Every option is also a CSS custom property on the container (see
|
|
51
|
-
* `IOS_TRANSITION_CSS_VARS`), read when a transition starts. A variable that
|
|
52
|
-
* is set wins over the JS option, so a stylesheet can slow the animation down
|
|
53
|
-
* or restyle it per theme without the app rebuilding the transition.
|
|
54
|
-
*
|
|
55
|
-
* p is only ever written at the ends of a phase. The stack puts that phase's
|
|
56
|
-
* duration and curve in `--sn-t` / `--sn-e` and CSS interpolates between the
|
|
57
|
-
* two writes, so the animation costs a handful of style writes rather than one
|
|
58
|
-
* per page per frame, and runs on the compositor rather than the main thread.
|
|
59
|
-
*/
|
|
60
|
-
export declare function createIOSTransition(options?: Partial<IOSTransitionOptions>): IOSTransition;
|
|
61
|
-
//# sourceMappingURL=ios-transition.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ios-transition.d.ts","sourceRoot":"","sources":["../src/ios-transition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE1E,OAAO,KAAK,EAA2B,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEjF,MAAM,WAAW,oBAAoB;IACnC,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,kDAAkD;AAClD,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,oBAAoB,EAAE,MAAM,CAAC,CAYvF,CAAC;AAEH,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,oFAAoF;IACpF,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;IACvC,yFAAyF;IACzF,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IAClD;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC;CACpC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,OAAO,CAAC,oBAAoB,CAAM,GAAG,aAAa,CAuG9F"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ios-transition.js","sourceRoot":"","sources":["../src/ios-transition.ts"],"names":[],"mappings":"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"}
|
package/src/edge-pan-gesture.ts
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import type { InteractivePopHandle, NavigationStack } from './navigation-stack.ts';
|
|
2
|
-
|
|
3
|
-
export interface EdgePanGestureOptions {
|
|
4
|
-
/** px strip on the leading edge that starts the gesture */
|
|
5
|
-
edgeWidth: number;
|
|
6
|
-
/** recognize the drag from anywhere on the page */
|
|
7
|
-
anywhere: boolean;
|
|
8
|
-
/** px of horizontal movement before the drag begins */
|
|
9
|
-
startSlop: number;
|
|
10
|
-
/** px of vertical movement that hands the touch back to scrolling */
|
|
11
|
-
verticalCancelSlop: number;
|
|
12
|
-
/** fraction of the width dragged that completes without velocity */
|
|
13
|
-
completeThreshold: number;
|
|
14
|
-
/** px/s toward the trailing edge that completes the pop regardless of distance */
|
|
15
|
-
completeVelocity: number;
|
|
16
|
-
/** px/s back toward the leading edge that cancels the pop regardless of distance */
|
|
17
|
-
cancelVelocity: number;
|
|
18
|
-
velocitySamples: number;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface EdgePanGesture {
|
|
22
|
-
readonly options: EdgePanGestureOptions;
|
|
23
|
-
/** Re-reads options changed at runtime, such as `edgeWidth` and `anywhere`. */
|
|
24
|
-
refresh(): void;
|
|
25
|
-
attach(stack: NavigationStack): EdgePanGesture;
|
|
26
|
-
detach(): void;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface Drag {
|
|
30
|
-
id: number;
|
|
31
|
-
target: EventTarget & { setPointerCapture?(id: number): void };
|
|
32
|
-
x0: number;
|
|
33
|
-
y0: number;
|
|
34
|
-
/** +1 when back is a drag to the right, -1 when the container reads right-to-left */
|
|
35
|
-
dir: number;
|
|
36
|
-
handle: InteractivePopHandle | null;
|
|
37
|
-
p: number;
|
|
38
|
-
samples: Array<[number, number]>;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Recognizes a horizontal drag from the leading edge and drives the stack's
|
|
43
|
-
* interactive pop from it. Built on pointer events, so it handles both mouse
|
|
44
|
-
* and touch. Vertical movement early in the gesture hands the touch back to
|
|
45
|
-
* native scrolling.
|
|
46
|
-
*
|
|
47
|
-
* "Leading" is whichever edge the container reads from, so in a right-to-left
|
|
48
|
-
* container the strip sits on the right and back is a drag to the left.
|
|
49
|
-
*/
|
|
50
|
-
export function createEdgePanGesture(options: Partial<EdgePanGestureOptions> = {}): EdgePanGesture {
|
|
51
|
-
const o: EdgePanGestureOptions = {
|
|
52
|
-
edgeWidth: 28,
|
|
53
|
-
anywhere: false,
|
|
54
|
-
startSlop: 6,
|
|
55
|
-
verticalCancelSlop: 10,
|
|
56
|
-
completeThreshold: 0.5,
|
|
57
|
-
completeVelocity: 500,
|
|
58
|
-
cancelVelocity: -500,
|
|
59
|
-
velocitySamples: 6,
|
|
60
|
-
...options,
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
let stack: NavigationStack;
|
|
64
|
-
let strip: HTMLElement | null = null;
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Which way forward is, read the same way the pages read it: `--sn-dir` when
|
|
68
|
-
* the stylesheet sets it, the container's reading direction otherwise. Taking
|
|
69
|
-
* it from one place is what keeps the drag and the transition from disagreeing
|
|
70
|
-
* about which edge is the back edge.
|
|
71
|
-
*/
|
|
72
|
-
const direction = (): number => {
|
|
73
|
-
const style = typeof getComputedStyle === 'function' ? getComputedStyle(stack.container) : null;
|
|
74
|
-
const declared = Number(style?.getPropertyValue('--sn-dir'));
|
|
75
|
-
if (declared < 0) return -1;
|
|
76
|
-
if (declared > 0) return 1;
|
|
77
|
-
return style?.direction === 'rtl' ? -1 : 1;
|
|
78
|
-
};
|
|
79
|
-
let drag: Drag | null = null;
|
|
80
|
-
let suppressClick = false;
|
|
81
|
-
let offs: Array<() => void> = [];
|
|
82
|
-
|
|
83
|
-
const onDown = (ev: PointerEvent) => {
|
|
84
|
-
if (drag || !stack.canPop()) return;
|
|
85
|
-
if (ev.pointerType === 'mouse' && ev.button !== 0) return;
|
|
86
|
-
if (!o.anywhere && ev.target !== strip) return;
|
|
87
|
-
drag = { id: ev.pointerId, target: ev.currentTarget as Drag['target'], x0: ev.clientX, y0: ev.clientY, dir: direction(), handle: null, p: 1, samples: [[ev.clientX, performance.now()]] };
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const onMove = (ev: PointerEvent) => {
|
|
91
|
-
if (!drag || ev.pointerId !== drag.id) return;
|
|
92
|
-
// Signed so that "forward along the drag" is always positive, whichever
|
|
93
|
-
// edge the container calls leading.
|
|
94
|
-
const dx = (ev.clientX - drag.x0) * drag.dir;
|
|
95
|
-
const dy = ev.clientY - drag.y0;
|
|
96
|
-
if (!drag.handle) {
|
|
97
|
-
if (Math.abs(dy) > o.verticalCancelSlop && Math.abs(dy) > Math.abs(dx)) {
|
|
98
|
-
drag = null;
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
if (dx < o.startSlop) return;
|
|
102
|
-
const handle = stack.beginInteractivePop();
|
|
103
|
-
if (!handle) {
|
|
104
|
-
drag = null;
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
drag.handle = handle;
|
|
108
|
-
try {
|
|
109
|
-
drag.target.setPointerCapture?.(ev.pointerId);
|
|
110
|
-
} catch {
|
|
111
|
-
/* capture is best-effort */
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
drag.samples.push([ev.clientX, performance.now()]);
|
|
115
|
-
if (drag.samples.length > o.velocitySamples) drag.samples.shift();
|
|
116
|
-
drag.p = 1 - Math.min(1, Math.max(0, (dx - o.startSlop) / stack.width()));
|
|
117
|
-
drag.handle.update(drag.p);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const onUp = (ev: PointerEvent) => {
|
|
121
|
-
if (!drag || ev.pointerId !== drag.id) return;
|
|
122
|
-
const d = drag;
|
|
123
|
-
drag = null;
|
|
124
|
-
if (!d.handle) return;
|
|
125
|
-
const s = d.samples;
|
|
126
|
-
const [x1, t1] = s[0];
|
|
127
|
-
const [x2, t2] = s[s.length - 1];
|
|
128
|
-
const velocity = (t2 > t1 ? ((x2 - x1) / (t2 - t1)) * 1000 : 0) * d.dir;
|
|
129
|
-
const cancelled = ev.type === 'pointercancel';
|
|
130
|
-
const complete = !cancelled && (velocity > o.completeVelocity || (d.p < 1 - o.completeThreshold && velocity > o.cancelVelocity));
|
|
131
|
-
// The click that follows a drag release must not activate whatever is under the pointer.
|
|
132
|
-
suppressClick = true;
|
|
133
|
-
setTimeout(() => {
|
|
134
|
-
suppressClick = false;
|
|
135
|
-
}, 0);
|
|
136
|
-
void d.handle.finish({ complete, velocity });
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const onClick = (ev: Event) => {
|
|
140
|
-
if (suppressClick) {
|
|
141
|
-
ev.stopPropagation();
|
|
142
|
-
ev.preventDefault();
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const EVENTS: Record<string, (ev: PointerEvent) => void> = { pointerdown: onDown, pointermove: onMove, pointerup: onUp, pointercancel: onUp };
|
|
147
|
-
const listen = (el: HTMLElement) => Object.entries(EVENTS).forEach(([k, f]) => el.addEventListener(k, f as EventListener));
|
|
148
|
-
const unlisten = (el: HTMLElement) => Object.entries(EVENTS).forEach(([k, f]) => el.removeEventListener(k, f as EventListener));
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Whether the strip is shown at all is a CSS question — the stylesheet hides
|
|
152
|
-
* it when there is nothing to go back to, or when the whole page is the
|
|
153
|
-
* target — so this only has to say what is true.
|
|
154
|
-
*/
|
|
155
|
-
const refresh = () => {
|
|
156
|
-
if (!strip) return;
|
|
157
|
-
strip.style.width = o.edgeWidth + 'px';
|
|
158
|
-
stack.container.classList.toggle('sn-anywhere', o.anywhere);
|
|
159
|
-
stack.container.classList.toggle('sn-can-pop', stack.entries.length > 1);
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
const gesture: EdgePanGesture = {
|
|
163
|
-
options: o,
|
|
164
|
-
refresh,
|
|
165
|
-
attach(s) {
|
|
166
|
-
stack = s;
|
|
167
|
-
strip = document.createElement('div');
|
|
168
|
-
strip.className = 'sn-edge';
|
|
169
|
-
strip.setAttribute('aria-hidden', 'true');
|
|
170
|
-
stack.container.append(strip);
|
|
171
|
-
// Pointer events from the strip bubble here; one listener per event
|
|
172
|
-
// avoids applying each move and recording its velocity sample twice.
|
|
173
|
-
listen(stack.container);
|
|
174
|
-
stack.container.addEventListener('click', onClick, true);
|
|
175
|
-
offs = (['push', 'pop', 'replace', 'reset'] as const).map((e) => stack.on(e, refresh));
|
|
176
|
-
refresh();
|
|
177
|
-
return gesture;
|
|
178
|
-
},
|
|
179
|
-
detach() {
|
|
180
|
-
if (!strip) return;
|
|
181
|
-
offs.forEach((f) => f());
|
|
182
|
-
unlisten(stack.container);
|
|
183
|
-
stack.container.removeEventListener('click', onClick, true);
|
|
184
|
-
stack.container.classList.remove('sn-anywhere', 'sn-can-pop');
|
|
185
|
-
strip.remove();
|
|
186
|
-
strip = null;
|
|
187
|
-
},
|
|
188
|
-
};
|
|
189
|
-
return gesture;
|
|
190
|
-
}
|