pageturn 0.1.0 → 0.2.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/CHANGELOG.md +41 -0
- package/README.md +179 -4
- package/dist/astro.js +0 -2
- package/dist/chunks/chunk-3ABPYO7H.js +43 -0
- package/dist/chunks/chunk-6FXXBNAF.js +197 -0
- package/dist/chunks/chunk-AEOAXMU3.js +33 -0
- package/dist/chunks/chunk-BOM5VXA5.js +167 -0
- package/dist/chunks/chunk-C3T7BGNG.js +30 -0
- package/dist/chunks/chunk-FYSSNYA4.js +17 -0
- package/dist/chunks/chunk-JHM7F4CH.js +172 -0
- package/dist/chunks/chunk-LM3XLSCW.js +799 -0
- package/dist/chunks/{chunk-QJ7GGFM4.js → chunk-YAL4MNCU.js} +4 -6
- package/dist/core.js +4 -3
- package/dist/dev/chunks/chunk-3JAWIMHB.js +184 -0
- package/dist/dev/chunks/chunk-3SU4CIKL.js +799 -0
- package/dist/dev/chunks/chunk-AEOAXMU3.js +33 -0
- package/dist/dev/chunks/chunk-C3T7BGNG.js +30 -0
- package/dist/dev/chunks/chunk-FYSSNYA4.js +17 -0
- package/dist/dev/chunks/chunk-I4SBUABE.js +175 -0
- package/dist/dev/chunks/chunk-U3XN54YY.js +219 -0
- package/dist/dev/chunks/chunk-Y6TD2T53.js +43 -0
- package/dist/dev/chunks/chunk-YAL4MNCU.js +22 -0
- package/dist/dev/core.js +19 -0
- package/dist/dev/index.js +21 -0
- package/dist/dev/morph-markup.js +34 -0
- package/dist/dev/morph.js +457 -0
- package/dist/dev/native.js +3 -0
- package/dist/dev/next.js +79 -0
- package/dist/dev/nuxt-plugin.js +24 -0
- package/dist/dev/prefetch.js +2 -0
- package/dist/dev/react-router.js +46 -0
- package/dist/dev/router.js +9 -0
- package/dist/dev/sveltekit.js +32 -0
- package/dist/dev/testing.js +48 -0
- package/dist/dev/turbo.js +49 -0
- package/dist/dev/vue.js +11 -0
- package/dist/head-core.js +1 -1
- package/dist/head-string.js +6 -6
- package/dist/head.js +1 -1
- package/dist/index.js +6 -5
- package/dist/morph-head.js +1 -1
- package/dist/morph-markup.js +11 -9
- package/dist/morph.js +145 -287
- package/dist/native.js +3 -2
- package/dist/next.js +79 -0
- package/dist/nuxt-plugin.js +24 -0
- package/dist/nuxt.js +34 -0
- package/dist/pageturn-morph.js +1 -1
- package/dist/pageturn.js +1 -1
- package/dist/prefetch.js +2 -2
- package/dist/react-router.js +46 -0
- package/dist/router.js +5 -183
- package/dist/sveltekit-server.js +22 -0
- package/dist/sveltekit.js +32 -0
- package/dist/testing.js +12 -22
- package/dist/turbo.js +49 -0
- package/dist/types/astro/integration.d.ts +0 -4
- package/dist/types/common/dev.d.ts +6 -0
- package/dist/types/common/page.d.ts +5 -0
- package/dist/types/common/registry.d.ts +3 -1
- package/dist/types/next/next.d.ts +27 -0
- package/dist/types/nuxt/module.d.ts +32 -0
- package/dist/types/react-router/react-router.d.ts +12 -0
- package/dist/types/router/router.d.ts +4 -2
- package/dist/types/sveltekit/server.d.ts +21 -0
- package/dist/types/sveltekit/sveltekit.d.ts +32 -0
- package/dist/types/turbo/turbo.d.ts +1 -0
- package/dist/types/vue/vue.d.ts +36 -0
- package/dist/vue.js +11 -0
- package/package.json +102 -23
- package/dist/chunks/chunk-237GNQNZ.js +0 -37
- package/dist/chunks/chunk-7LMNJ25V.js +0 -244
- package/dist/chunks/chunk-QC36TQP3.js +0 -24
- package/dist/chunks/chunk-WTHN3UIQ.js +0 -1000
- package/dist/chunks/chunk-YBAP3PHO.js +0 -247
|
@@ -1,1000 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
arrival,
|
|
3
|
-
defineMove
|
|
4
|
-
} from "./chunk-7LMNJ25V.js";
|
|
5
|
-
import {
|
|
6
|
-
afterDomContentLoaded,
|
|
7
|
-
giveFocusTo,
|
|
8
|
-
navigationEntry,
|
|
9
|
-
notShownAnew,
|
|
10
|
-
readSession,
|
|
11
|
-
reducesMotion,
|
|
12
|
-
removeSession,
|
|
13
|
-
writeSession
|
|
14
|
-
} from "./chunk-YBAP3PHO.js";
|
|
15
|
-
import {
|
|
16
|
-
isDeclined,
|
|
17
|
-
registry
|
|
18
|
-
} from "./chunk-QJ7GGFM4.js";
|
|
19
|
-
|
|
20
|
-
// src/morph/end.ts
|
|
21
|
-
var wait = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
22
|
-
var within = (promise, milliseconds) => Promise.race([promise, wait(milliseconds).then(() => null)]);
|
|
23
|
-
var isEnding = (animation) => Number.isFinite(animation.effect?.getComputedTiming().endTime);
|
|
24
|
-
var CORNERS = ["TopLeft", "TopRight", "BottomRight", "BottomLeft"];
|
|
25
|
-
var cornersOf = (radius) => typeof radius === "number" ? [radius, radius, radius, radius] : radius;
|
|
26
|
-
var radiusOf = (corners) => corners.every((corner) => corner === corners[0]) ? corners[0] : corners;
|
|
27
|
-
function ownCorners(style, width, scale = 1) {
|
|
28
|
-
return radiusOf(
|
|
29
|
-
CORNERS.map((corner) => {
|
|
30
|
-
const value = style[`border${corner}Radius`];
|
|
31
|
-
const radius = Number.parseFloat(value) || 0;
|
|
32
|
-
return value.includes("%") ? radius / 100 * width : radius * scale;
|
|
33
|
-
})
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
var cornersCss = (radius, scale = 1) => cornersOf(radius).map((corner) => `${corner / scale}px`).join(" ");
|
|
37
|
-
function seenCorners(element, box) {
|
|
38
|
-
const corners = [
|
|
39
|
-
...cornersOf(ownCorners(getComputedStyle(element), box.width))
|
|
40
|
-
];
|
|
41
|
-
const near = (one, other) => Math.abs(one - other) < 1;
|
|
42
|
-
for (let clip = element.parentElement; clip && clip !== document.body; clip = clip.parentElement) {
|
|
43
|
-
const style = getComputedStyle(clip);
|
|
44
|
-
if (style.overflow === "visible" && !/paint|strict|content/.test(style.contain)) {
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
const edge = clip.getBoundingClientRect();
|
|
48
|
-
const left = edge.left + clip.clientLeft;
|
|
49
|
-
const top = edge.top + clip.clientTop;
|
|
50
|
-
const right = near(box.right, left + clip.clientWidth);
|
|
51
|
-
const bottom = near(box.bottom, top + clip.clientHeight);
|
|
52
|
-
const atLeft = near(box.left, left);
|
|
53
|
-
const atTop = near(box.top, top);
|
|
54
|
-
const radii = cornersOf(ownCorners(style, edge.width));
|
|
55
|
-
const border = Math.max(clip.clientLeft, clip.clientTop);
|
|
56
|
-
[
|
|
57
|
-
atLeft && atTop,
|
|
58
|
-
right && atTop,
|
|
59
|
-
right && bottom,
|
|
60
|
-
atLeft && bottom
|
|
61
|
-
].forEach((meets, index) => {
|
|
62
|
-
if (meets) {
|
|
63
|
-
corners[index] = Math.max(
|
|
64
|
-
corners[index] ?? 0,
|
|
65
|
-
(radii[index] ?? 0) - border
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
return radiusOf(corners);
|
|
71
|
-
}
|
|
72
|
-
function endOf(element) {
|
|
73
|
-
const rect = element.getBoundingClientRect();
|
|
74
|
-
const { left, top, width, height } = rect;
|
|
75
|
-
const end = {
|
|
76
|
-
box: { left, top, width, height },
|
|
77
|
-
radius: seenCorners(element, rect)
|
|
78
|
-
};
|
|
79
|
-
const picture2 = element.matches("img") ? element : element.querySelector("img");
|
|
80
|
-
if (picture2?.sizes) end.sizes = picture2.sizes;
|
|
81
|
-
return end;
|
|
82
|
-
}
|
|
83
|
-
var shifted = (end, x, y) => ({
|
|
84
|
-
...end,
|
|
85
|
-
box: { ...end.box, left: end.box.left + x, top: end.box.top + y }
|
|
86
|
-
});
|
|
87
|
-
var looksSame = (one, other) => {
|
|
88
|
-
const drawn = (end) => [
|
|
89
|
-
end.box.left,
|
|
90
|
-
end.box.top,
|
|
91
|
-
end.box.width,
|
|
92
|
-
end.box.height,
|
|
93
|
-
...cornersOf(end.radius),
|
|
94
|
-
end.rotate ?? 0,
|
|
95
|
-
end.text?.box.left ?? 0,
|
|
96
|
-
end.text?.box.top ?? 0,
|
|
97
|
-
Number.parseFloat(end.text?.type.fontSize ?? "0")
|
|
98
|
-
];
|
|
99
|
-
const others = drawn(other);
|
|
100
|
-
return drawn(one).every(
|
|
101
|
-
(value, index) => Math.abs(value - (others[index] ?? 0)) < 0.5
|
|
102
|
-
) && one.text?.color === other.text?.color && one.background === other.background;
|
|
103
|
-
};
|
|
104
|
-
function atTheirEnd(animations, read) {
|
|
105
|
-
const held = animations.filter(isEnding);
|
|
106
|
-
const times = held.map((animation) => animation.currentTime);
|
|
107
|
-
for (const animation of held) {
|
|
108
|
-
animation.currentTime = animation.effect?.getComputedTiming().endTime;
|
|
109
|
-
}
|
|
110
|
-
try {
|
|
111
|
-
return read();
|
|
112
|
-
} finally {
|
|
113
|
-
held.forEach((animation, index) => {
|
|
114
|
-
animation.currentTime = times[index] ?? null;
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// src/morph/layer.ts
|
|
120
|
-
var LAYER_STYLE = "position:fixed;inset:auto;left:0;top:0;margin:0;border:0;padding:0;overflow:visible;background:none;color:inherit;pointer-events:none;z-index:2147483647;transform-origin:50% 50%;max-width:none;max-height:none";
|
|
121
|
-
var CONTENT_STYLE = "margin:0;max-width:none;max-height:none;box-sizing:border-box;visibility:visible;translate:none;rotate:none;scale:none;transform:none";
|
|
122
|
-
function cloned(element) {
|
|
123
|
-
const copy = element.cloneNode(true);
|
|
124
|
-
for (const named of [copy, ...copy.querySelectorAll("[id]")]) {
|
|
125
|
-
named.removeAttribute("id");
|
|
126
|
-
}
|
|
127
|
-
return copy;
|
|
128
|
-
}
|
|
129
|
-
var sizeOf = (layer) => [
|
|
130
|
-
Number.parseFloat(layer.style.width),
|
|
131
|
-
Number.parseFloat(layer.style.height)
|
|
132
|
-
];
|
|
133
|
-
var centredOn = (box, width, height) => `${box.left + (box.width - width) / 2}px ${box.top + (box.height - height) / 2}px`;
|
|
134
|
-
var moveAt = (pose, end) => ({
|
|
135
|
-
...pose.move,
|
|
136
|
-
opacity: end.opacity ?? 1
|
|
137
|
-
});
|
|
138
|
-
function standAt(layer, kind, end) {
|
|
139
|
-
const pose = kind.pose(layer)(end);
|
|
140
|
-
Object.assign(layer.style, moveAt(pose, end));
|
|
141
|
-
Object.assign(pose.on.style, pose.look);
|
|
142
|
-
if (pose.inner) Object.assign(pose.inner.on.style, pose.inner.look);
|
|
143
|
-
}
|
|
144
|
-
function markup(layer) {
|
|
145
|
-
const copy = layer.cloneNode(true);
|
|
146
|
-
for (const shot of copy.querySelectorAll("[data-turn-shot]")) shot.remove();
|
|
147
|
-
const drawn = layer.querySelectorAll("img");
|
|
148
|
-
copy.querySelectorAll("img").forEach((picture2, index) => {
|
|
149
|
-
const live = drawn[index];
|
|
150
|
-
const file = live?.complete && live.naturalWidth ? live.currentSrc : picture2.dataset.turnFile;
|
|
151
|
-
if (!file) return;
|
|
152
|
-
picture2.src = file;
|
|
153
|
-
picture2.removeAttribute("srcset");
|
|
154
|
-
picture2.removeAttribute("sizes");
|
|
155
|
-
for (const source of picture2.parentElement?.querySelectorAll("source") ?? []) {
|
|
156
|
-
source.remove();
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
for (const styled of [
|
|
160
|
-
copy,
|
|
161
|
-
...copy.querySelectorAll("[style]")
|
|
162
|
-
]) {
|
|
163
|
-
styled.dataset.turnStyle = styled.style.cssText;
|
|
164
|
-
styled.removeAttribute("style");
|
|
165
|
-
}
|
|
166
|
-
return copy.outerHTML;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// src/morph/picture.ts
|
|
170
|
-
var PICTURE_WAIT_MS = 250;
|
|
171
|
-
var MEDIA = "img,video,canvas";
|
|
172
|
-
async function whenDrawn(element) {
|
|
173
|
-
const picture2 = element.matches("img") ? element : element.querySelector("img");
|
|
174
|
-
if (picture2 instanceof HTMLImageElement) {
|
|
175
|
-
await within(picture2.decode(), PICTURE_WAIT_MS).catch(() => {
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
function snapshot(shown, width, height, position) {
|
|
180
|
-
const { naturalWidth, naturalHeight } = shown;
|
|
181
|
-
if (!shown.complete || !naturalWidth || !naturalHeight) return null;
|
|
182
|
-
const canvas = document.createElement("canvas");
|
|
183
|
-
const cover = Math.max(width / naturalWidth, height / naturalHeight);
|
|
184
|
-
const across = width / cover;
|
|
185
|
-
const down = height / cover;
|
|
186
|
-
const [x = 0.5, y = 0.5] = position.split(" ").map(
|
|
187
|
-
(share) => share.endsWith("%") ? Number.parseFloat(share) / 100 : 0.5
|
|
188
|
-
);
|
|
189
|
-
canvas.width = Math.round(across);
|
|
190
|
-
canvas.height = Math.round(down);
|
|
191
|
-
try {
|
|
192
|
-
canvas.getContext("2d")?.drawImage(
|
|
193
|
-
shown,
|
|
194
|
-
(naturalWidth - across) * x,
|
|
195
|
-
(naturalHeight - down) * y,
|
|
196
|
-
across,
|
|
197
|
-
down,
|
|
198
|
-
0,
|
|
199
|
-
0,
|
|
200
|
-
canvas.width,
|
|
201
|
-
canvas.height
|
|
202
|
-
);
|
|
203
|
-
} catch {
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
canvas.dataset.turnShot = "";
|
|
207
|
-
canvas.style.cssText = "position:absolute;left:0;top:0;width:100%;height:100%;z-index:-1";
|
|
208
|
-
return canvas;
|
|
209
|
-
}
|
|
210
|
-
function pictureOf(element) {
|
|
211
|
-
const inside = element.querySelectorAll(MEDIA);
|
|
212
|
-
return element.matches(MEDIA) ? element : inside.length === 1 ? inside[0] : null;
|
|
213
|
-
}
|
|
214
|
-
var picture = {
|
|
215
|
-
read(element, end) {
|
|
216
|
-
const inner = pictureOf(element);
|
|
217
|
-
if (!inner || inner === element) return;
|
|
218
|
-
const style = getComputedStyle(inner);
|
|
219
|
-
const own = new DOMMatrix(style.transform);
|
|
220
|
-
const zoom = Math.hypot(own.a, own.b) * (Number.parseFloat(style.scale) || 1);
|
|
221
|
-
if (Math.abs(zoom - 1) > 1e-3) end.zoom = zoom;
|
|
222
|
-
},
|
|
223
|
-
build(element, from, to) {
|
|
224
|
-
const layer = document.createElement("div");
|
|
225
|
-
const media = pictureOf(element);
|
|
226
|
-
const content = cloned(
|
|
227
|
-
media ? media.closest("picture") ?? media : element
|
|
228
|
-
);
|
|
229
|
-
const drawn = content.matches(MEDIA) ? content : (media && content.querySelector(MEDIA)) ?? content;
|
|
230
|
-
if (drawn !== content) content.style.cssText = "display:contents";
|
|
231
|
-
content.dataset.turnContent = "";
|
|
232
|
-
drawn.style.cssText += `;display:block;width:100%;height:100%;${CONTENT_STYLE}`;
|
|
233
|
-
if (media) {
|
|
234
|
-
drawn.style.objectFit = "cover";
|
|
235
|
-
drawn.style.objectPosition = getComputedStyle(media).objectPosition;
|
|
236
|
-
}
|
|
237
|
-
const { width, height } = (to ?? from).box;
|
|
238
|
-
layer.style.cssText = `${LAYER_STYLE};width:${width}px;height:${height}px`;
|
|
239
|
-
layer.append(content);
|
|
240
|
-
if (drawn instanceof HTMLImageElement && media instanceof HTMLImageElement) {
|
|
241
|
-
drawn.loading = "eager";
|
|
242
|
-
drawn.decoding = "sync";
|
|
243
|
-
drawn.dataset.turnFile = media.currentSrc;
|
|
244
|
-
if (to) {
|
|
245
|
-
const sizes = to.sizes ?? `${Math.ceil(width)}px`;
|
|
246
|
-
for (const sized of layer.querySelectorAll("img[srcset],source[srcset]")) {
|
|
247
|
-
sized.sizes = sizes;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
const shot = snapshot(media, width, height, drawn.style.objectPosition);
|
|
251
|
-
if (shot) {
|
|
252
|
-
layer.append(shot);
|
|
253
|
-
const drew = () => {
|
|
254
|
-
drawn.decode().then(
|
|
255
|
-
() => shot.remove(),
|
|
256
|
-
() => {
|
|
257
|
-
}
|
|
258
|
-
);
|
|
259
|
-
};
|
|
260
|
-
if (drawn.complete && drawn.naturalWidth) drew();
|
|
261
|
-
else drawn.addEventListener("load", drew, { once: true });
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
return layer;
|
|
265
|
-
},
|
|
266
|
-
pose(layer) {
|
|
267
|
-
const [width, height] = sizeOf(layer);
|
|
268
|
-
const held = layer.querySelector(MEDIA) ?? layer.firstElementChild;
|
|
269
|
-
return ({ box, rotate = 0, radius, zoom = 1 }) => {
|
|
270
|
-
const cover = Math.max(box.width / width, box.height / height);
|
|
271
|
-
return {
|
|
272
|
-
move: {
|
|
273
|
-
translate: centredOn(box, width, height),
|
|
274
|
-
rotate: `${rotate}deg`,
|
|
275
|
-
scale: `${cover}`
|
|
276
|
-
},
|
|
277
|
-
look: {
|
|
278
|
-
clipPath: `inset(${(height - box.height / cover) / 2}px ${(width - box.width / cover) / 2}px round ${cornersCss(radius, cover)})`
|
|
279
|
-
},
|
|
280
|
-
on: layer,
|
|
281
|
-
inner: { look: { scale: `${zoom}` }, on: held }
|
|
282
|
-
};
|
|
283
|
-
};
|
|
284
|
-
},
|
|
285
|
-
fit(layer, to) {
|
|
286
|
-
layer.style.width = `${to.box.width}px`;
|
|
287
|
-
layer.style.height = `${to.box.height}px`;
|
|
288
|
-
}
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
// src/morph/place.ts
|
|
292
|
-
var MORPH_KEY = "pageturn:morph";
|
|
293
|
-
var outsideLayer = (selector) => `:is(${selector}):not([data-turn-layer] *)`;
|
|
294
|
-
var onPage = (selector) => document.querySelector(outsideLayer(selector));
|
|
295
|
-
function whenParsed(run) {
|
|
296
|
-
if (document.readyState === "loading") {
|
|
297
|
-
document.addEventListener("readystatechange", run, { once: true });
|
|
298
|
-
} else {
|
|
299
|
-
run();
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
function putBack(selector, name, reopens = false, kept = [], link) {
|
|
303
|
-
const root = document.documentElement;
|
|
304
|
-
root.dataset.turnRestoring = "";
|
|
305
|
-
notShownAnew();
|
|
306
|
-
const around = [];
|
|
307
|
-
whenParsed(() => {
|
|
308
|
-
let origin = null;
|
|
309
|
-
try {
|
|
310
|
-
origin = selector ? onPage(selector) : null;
|
|
311
|
-
} catch {
|
|
312
|
-
}
|
|
313
|
-
origin?.setAttribute("data-turn-origin", name);
|
|
314
|
-
for (const [where, attribute, value] of kept) {
|
|
315
|
-
try {
|
|
316
|
-
const element = document.querySelector(where);
|
|
317
|
-
if (value === null) element?.removeAttribute(attribute);
|
|
318
|
-
else element?.setAttribute(attribute, value);
|
|
319
|
-
} catch {
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
for (let within2 = origin?.parentElement?.closest("[popover]"); reopens && within2; within2 = within2.parentElement?.closest("[popover]")) {
|
|
323
|
-
around.unshift(within2);
|
|
324
|
-
}
|
|
325
|
-
for (const popover of around) {
|
|
326
|
-
try {
|
|
327
|
-
popover.showPopover();
|
|
328
|
-
} catch {
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
afterDomContentLoaded(
|
|
333
|
-
() => requestAnimationFrame(
|
|
334
|
-
() => requestAnimationFrame(() => {
|
|
335
|
-
if (link) giveFocusBack(link, around);
|
|
336
|
-
delete root.dataset.turnRestoring;
|
|
337
|
-
})
|
|
338
|
-
)
|
|
339
|
-
);
|
|
340
|
-
}
|
|
341
|
-
var linkAt = (address, rank) => [...document.querySelectorAll("a[href]")].filter(
|
|
342
|
-
(anchor) => anchor.href === address
|
|
343
|
-
)[rank];
|
|
344
|
-
function giveFocusBack([address, rank, isShown], around) {
|
|
345
|
-
const focused = document.activeElement;
|
|
346
|
-
const target = linkAt(address, rank);
|
|
347
|
-
if (target && (!focused || focused === document.body || around.some((popover) => popover.contains(focused)))) {
|
|
348
|
-
giveFocusTo(target, {
|
|
349
|
-
preventScroll: true,
|
|
350
|
-
focusVisible: isShown
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
function showLayer(layer) {
|
|
355
|
-
layer.setAttribute("aria-hidden", "true");
|
|
356
|
-
layer.setAttribute("popover", "manual");
|
|
357
|
-
layer.dataset.turnLayer = "";
|
|
358
|
-
document.documentElement.append(layer);
|
|
359
|
-
try {
|
|
360
|
-
layer.showPopover();
|
|
361
|
-
} catch {
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
function placeHandedLayer() {
|
|
365
|
-
if (window.top !== window) {
|
|
366
|
-
try {
|
|
367
|
-
const fromName = JSON.parse(
|
|
368
|
-
window.name.split(`${MORPH_KEY}:`)[1] ?? ""
|
|
369
|
-
);
|
|
370
|
-
whenParsed(() => scrollTo(fromName.x, fromName.y));
|
|
371
|
-
putBack(fromName.p, fromName.o, fromName.v, fromName.w);
|
|
372
|
-
if (window.pageturn) {
|
|
373
|
-
window.pageturn.behind = { move: fromName.m, data: fromName.d };
|
|
374
|
-
}
|
|
375
|
-
} catch {
|
|
376
|
-
}
|
|
377
|
-
return null;
|
|
378
|
-
}
|
|
379
|
-
const flight = readSession(MORPH_KEY);
|
|
380
|
-
removeSession(MORPH_KEY);
|
|
381
|
-
if (!flight || flight.n !== window.pageturn?.arrival?.move) return null;
|
|
382
|
-
const holder = document.createElement("div");
|
|
383
|
-
holder.innerHTML = flight.h;
|
|
384
|
-
const layer = holder.firstElementChild;
|
|
385
|
-
if (!(layer instanceof HTMLElement)) return null;
|
|
386
|
-
let sheet = null;
|
|
387
|
-
if (flight.s) {
|
|
388
|
-
try {
|
|
389
|
-
const rule = new CSSStyleSheet();
|
|
390
|
-
rule.insertRule(`${outsideLayer(flight.s)}{visibility:hidden!important}`);
|
|
391
|
-
document.adoptedStyleSheets = [...document.adoptedStyleSheets, rule];
|
|
392
|
-
sheet = rule;
|
|
393
|
-
} catch {
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
for (const styled of [
|
|
397
|
-
layer,
|
|
398
|
-
...layer.querySelectorAll("[data-turn-style]")
|
|
399
|
-
]) {
|
|
400
|
-
styled.style.cssText = styled.dataset.turnStyle ?? "";
|
|
401
|
-
}
|
|
402
|
-
showLayer(layer);
|
|
403
|
-
const placed = { flight, layer, sheet, taken: false };
|
|
404
|
-
if (flight.b) document.documentElement.dataset.turnBehind = "";
|
|
405
|
-
const { x = 0, y } = flight;
|
|
406
|
-
if (y !== void 0) whenParsed(() => scrollTo(x, y));
|
|
407
|
-
if (flight.o) putBack(flight.s, flight.o, flight.v, flight.w, flight.l);
|
|
408
|
-
afterDomContentLoaded(
|
|
409
|
-
() => setTimeout(() => placed.taken || clearLayer(placed))
|
|
410
|
-
);
|
|
411
|
-
return placed;
|
|
412
|
-
}
|
|
413
|
-
function clearLayer(placed) {
|
|
414
|
-
placed.taken = true;
|
|
415
|
-
document.querySelector("[data-turn-origin]")?.removeAttribute("data-turn-origin");
|
|
416
|
-
placed.layer.remove();
|
|
417
|
-
document.adoptedStyleSheets = document.adoptedStyleSheets.filter(
|
|
418
|
-
(sheet) => sheet !== placed.sheet
|
|
419
|
-
);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// src/morph/timing.ts
|
|
423
|
-
var over = (timing, leg = {}) => ({
|
|
424
|
-
...timing,
|
|
425
|
-
duration: leg.duration ?? timing.duration,
|
|
426
|
-
delay: leg.delay ?? timing.delay,
|
|
427
|
-
easing: leg.easing ?? timing.easing
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
// src/morph/define.ts
|
|
431
|
-
var DURATION_MS = 500;
|
|
432
|
-
var EASING = "cubic-bezier(0.2, 0, 0, 1)";
|
|
433
|
-
var CORRECTION_MS = 300;
|
|
434
|
-
function handedOver() {
|
|
435
|
-
if (window.pageturnMorph === void 0)
|
|
436
|
-
window.pageturnMorph = placeHandedLayer();
|
|
437
|
-
return window.pageturnMorph;
|
|
438
|
-
}
|
|
439
|
-
var isHandingOver = false;
|
|
440
|
-
var isLeaving = () => isHandingOver;
|
|
441
|
-
function hide(element) {
|
|
442
|
-
const hidden = element;
|
|
443
|
-
hidden.style.visibility = "hidden";
|
|
444
|
-
return hidden;
|
|
445
|
-
}
|
|
446
|
-
var defined = /* @__PURE__ */ new Set();
|
|
447
|
-
var isDefined = (name) => defined.has(name);
|
|
448
|
-
function defineMorph(name, morph) {
|
|
449
|
-
if (window.top !== window || reducesMotion()) {
|
|
450
|
-
return () => {
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
defined.add(name);
|
|
454
|
-
const kind = morph.as ?? picture;
|
|
455
|
-
const finders = [morph.find ?? []].flat();
|
|
456
|
-
const atRest = (element) => (
|
|
457
|
-
// An element of another document (a page peek() loaded) has none of this one's.
|
|
458
|
-
element.ownerDocument !== document ? stage.read(element) : atTheirEnd(
|
|
459
|
-
document.getAnimations().filter((animation) => {
|
|
460
|
-
const { effect } = animation;
|
|
461
|
-
return effect instanceof KeyframeEffect && effect.target?.contains(element);
|
|
462
|
-
}),
|
|
463
|
-
() => stage.read(element)
|
|
464
|
-
)
|
|
465
|
-
);
|
|
466
|
-
const stage = {
|
|
467
|
-
name,
|
|
468
|
-
morph,
|
|
469
|
-
live: null,
|
|
470
|
-
endOf,
|
|
471
|
-
onLeave: [],
|
|
472
|
-
onStay: [],
|
|
473
|
-
onPlay: [],
|
|
474
|
-
onRemove: [],
|
|
475
|
-
siteAnimations: [],
|
|
476
|
-
atRest,
|
|
477
|
-
read(element) {
|
|
478
|
-
const end = stage.endOf(element);
|
|
479
|
-
kind.read?.(element, end, element.matches(morph.to));
|
|
480
|
-
return end;
|
|
481
|
-
},
|
|
482
|
-
timing: (leg) => over(
|
|
483
|
-
over(
|
|
484
|
-
{ duration: DURATION_MS, delay: 0, easing: EASING, fill: "both" },
|
|
485
|
-
morph
|
|
486
|
-
),
|
|
487
|
-
leg
|
|
488
|
-
),
|
|
489
|
-
about: (link, back2) => ({
|
|
490
|
-
back: back2,
|
|
491
|
-
link,
|
|
492
|
-
decline: () => registry.f,
|
|
493
|
-
measure(element, at) {
|
|
494
|
-
const end = stage.read(element);
|
|
495
|
-
if (!at) return end;
|
|
496
|
-
const place = stage.read(at);
|
|
497
|
-
const own = end.text?.box ?? end.box;
|
|
498
|
-
const other = place.text?.box ?? place.box;
|
|
499
|
-
const across = other.left - own.left;
|
|
500
|
-
const down = other.top - own.top;
|
|
501
|
-
const there = shifted(end, across, down);
|
|
502
|
-
if (there.text) {
|
|
503
|
-
there.text = {
|
|
504
|
-
...there.text,
|
|
505
|
-
box: {
|
|
506
|
-
...there.text.box,
|
|
507
|
-
left: there.text.box.left + across,
|
|
508
|
-
top: there.text.box.top + down
|
|
509
|
-
}
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
return there;
|
|
513
|
-
},
|
|
514
|
-
scroll: { x: scrollX, y: scrollY }
|
|
515
|
-
}),
|
|
516
|
-
layer(element, at, to) {
|
|
517
|
-
const layer = kind.build(element, at, to);
|
|
518
|
-
standAt(layer, kind, at);
|
|
519
|
-
return layer;
|
|
520
|
-
},
|
|
521
|
-
async put(element, at, to) {
|
|
522
|
-
const layer = stage.layer(element, at, to);
|
|
523
|
-
stage.live = { layer, hidden: hide(element) };
|
|
524
|
-
showLayer(layer);
|
|
525
|
-
return layer;
|
|
526
|
-
},
|
|
527
|
-
async travel(start, stop, about, timing, plays = true, behind = null) {
|
|
528
|
-
const layer = stage.live?.layer;
|
|
529
|
-
if (!layer) return;
|
|
530
|
-
const pose = kind.pose(layer);
|
|
531
|
-
const first = pose(start);
|
|
532
|
-
const last = pose(stop);
|
|
533
|
-
layer.animate([moveAt(first, start), moveAt(last, stop)], timing);
|
|
534
|
-
first.on.animate([first.look, last.look], timing);
|
|
535
|
-
if (first.inner && last.inner && JSON.stringify(first.inner.look) !== JSON.stringify(last.inner.look)) {
|
|
536
|
-
first.inner.on.animate([first.inner.look, last.inner.look], timing);
|
|
537
|
-
}
|
|
538
|
-
let end = () => {
|
|
539
|
-
};
|
|
540
|
-
const finished = new Promise((resolve) => {
|
|
541
|
-
end = resolve;
|
|
542
|
-
});
|
|
543
|
-
try {
|
|
544
|
-
kind.play?.(layer, start, stop, timing, about.back);
|
|
545
|
-
for (const play of stage.onPlay) {
|
|
546
|
-
play(layer, start, stop, timing, finished);
|
|
547
|
-
}
|
|
548
|
-
if (plays) {
|
|
549
|
-
morph.during?.({
|
|
550
|
-
...about,
|
|
551
|
-
layer,
|
|
552
|
-
content: layer.firstElementChild,
|
|
553
|
-
box: layer.querySelector("[data-turn-box]"),
|
|
554
|
-
words: layer.querySelector("[data-turn-words]"),
|
|
555
|
-
animate(element, keyframes, options) {
|
|
556
|
-
const animation = element.animate(keyframes, {
|
|
557
|
-
...timing,
|
|
558
|
-
...options
|
|
559
|
-
});
|
|
560
|
-
stage.siteAnimations.push(animation);
|
|
561
|
-
return animation;
|
|
562
|
-
},
|
|
563
|
-
start,
|
|
564
|
-
stop,
|
|
565
|
-
timing,
|
|
566
|
-
behind,
|
|
567
|
-
finished,
|
|
568
|
-
atEnd: (read) => atTheirEnd(layer.getAnimations({ subtree: true }), read)
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
} catch (error) {
|
|
572
|
-
reportError(error);
|
|
573
|
-
}
|
|
574
|
-
if (behind && behind.getAnimations().length === 0) {
|
|
575
|
-
behind.animate({ opacity: [0, 1] }, over(timing, stage.appear));
|
|
576
|
-
}
|
|
577
|
-
const playing = () => [
|
|
578
|
-
...layer.getAnimations({ subtree: true }),
|
|
579
|
-
...behind?.getAnimations() ?? []
|
|
580
|
-
].filter(isEnding);
|
|
581
|
-
await Promise.all(
|
|
582
|
-
[...playing(), ...stage.siteAnimations.filter(isEnding)].map(
|
|
583
|
-
(animation) => animation.finished
|
|
584
|
-
)
|
|
585
|
-
).catch(() => {
|
|
586
|
-
});
|
|
587
|
-
for (const animation of playing()) {
|
|
588
|
-
try {
|
|
589
|
-
animation.commitStyles();
|
|
590
|
-
} catch {
|
|
591
|
-
}
|
|
592
|
-
animation.cancel();
|
|
593
|
-
}
|
|
594
|
-
end();
|
|
595
|
-
},
|
|
596
|
-
hand(flight) {
|
|
597
|
-
isHandingOver = true;
|
|
598
|
-
writeSession(MORPH_KEY, flight);
|
|
599
|
-
},
|
|
600
|
-
async land(placed2, target, told, scroll = { x: scrollX, y: scrollY }, leg) {
|
|
601
|
-
const about = { ...told, scroll };
|
|
602
|
-
placed2.taken = true;
|
|
603
|
-
const { flight, layer } = placed2;
|
|
604
|
-
try {
|
|
605
|
-
if (document.readyState === "loading") {
|
|
606
|
-
await new Promise((parsed) => whenParsed(parsed));
|
|
607
|
-
}
|
|
608
|
-
const element = target();
|
|
609
|
-
if (!element) return;
|
|
610
|
-
stage.live = { layer, hidden: hide(element) };
|
|
611
|
-
const there = shifted(
|
|
612
|
-
atRest(element),
|
|
613
|
-
scrollX - scroll.x,
|
|
614
|
-
scrollY - scroll.y
|
|
615
|
-
);
|
|
616
|
-
if (flight.t) {
|
|
617
|
-
const ends = about.back ? { from: there, to: flight.f ?? null } : { from: flight.f ?? there, to: there };
|
|
618
|
-
if (flight.f) morph.ends?.(ends, about);
|
|
619
|
-
const stop = (about.back ? ends.from : ends.to) ?? there;
|
|
620
|
-
if (!looksSame(flight.e, stop)) {
|
|
621
|
-
await stage.travel(
|
|
622
|
-
flight.e,
|
|
623
|
-
stop,
|
|
624
|
-
about,
|
|
625
|
-
{ ...stage.timing(leg), delay: 0, duration: CORRECTION_MS },
|
|
626
|
-
false
|
|
627
|
-
);
|
|
628
|
-
}
|
|
629
|
-
} else {
|
|
630
|
-
const ends = about.back ? { from: there, to: flight.e } : { from: flight.e, to: there };
|
|
631
|
-
if (!isDeclined(morph.ends?.(ends, about))) {
|
|
632
|
-
const start = (about.back ? ends.to : ends.from) ?? flight.e;
|
|
633
|
-
const stop = (about.back ? ends.from : ends.to) ?? there;
|
|
634
|
-
kind.fit?.(layer, stop);
|
|
635
|
-
await stage.travel(start, stop, about, stage.timing(leg));
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
await whenDrawn(element);
|
|
639
|
-
} catch (error) {
|
|
640
|
-
reportError(error);
|
|
641
|
-
} finally {
|
|
642
|
-
stage.drop();
|
|
643
|
-
clearLayer(placed2);
|
|
644
|
-
}
|
|
645
|
-
},
|
|
646
|
-
drop() {
|
|
647
|
-
for (const animation of stage.siteAnimations.splice(0))
|
|
648
|
-
animation.cancel();
|
|
649
|
-
stage.live?.layer.remove();
|
|
650
|
-
stage.live?.hidden.style.removeProperty("visibility");
|
|
651
|
-
stage.live = null;
|
|
652
|
-
}
|
|
653
|
-
};
|
|
654
|
-
const remove = defineMove(name, {
|
|
655
|
-
match: (visit) => morph.match ? morph.match(visit) : Boolean(morph.from?.(visit.link)),
|
|
656
|
-
async leave(turn) {
|
|
657
|
-
const element = morph.from?.(turn.link);
|
|
658
|
-
if (!element || !turn.canHandOver || stage.live) return turn.decline();
|
|
659
|
-
const about = stage.about(turn.link, false);
|
|
660
|
-
const ends = {
|
|
661
|
-
from: stage.read(element),
|
|
662
|
-
to: null
|
|
663
|
-
};
|
|
664
|
-
for (const finder of finders) {
|
|
665
|
-
try {
|
|
666
|
-
ends.to ??= await finder(turn.to, morph.to, atRest);
|
|
667
|
-
} catch (error) {
|
|
668
|
-
reportError(error);
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
if (isDeclined(morph.ends?.(ends, about))) return turn.decline();
|
|
672
|
-
const { from, to } = ends;
|
|
673
|
-
if (from.box.width === 0 || from.box.height === 0) return turn.decline();
|
|
674
|
-
const layer = await stage.put(element, from, to);
|
|
675
|
-
const leaving = turn.leaving();
|
|
676
|
-
if (to) await stage.travel(from, to, about, stage.timing());
|
|
677
|
-
await leaving;
|
|
678
|
-
stage.hand({
|
|
679
|
-
n: morph.arriveAs ?? name,
|
|
680
|
-
m: name,
|
|
681
|
-
h: markup(layer),
|
|
682
|
-
e: to ?? from,
|
|
683
|
-
...to ? { f: from } : {},
|
|
684
|
-
t: Boolean(to),
|
|
685
|
-
s: morph.to
|
|
686
|
-
});
|
|
687
|
-
let handover = {
|
|
688
|
-
arriveAs: morph.arriveAs ?? name,
|
|
689
|
-
data: morph.data?.(turn) ?? null
|
|
690
|
-
};
|
|
691
|
-
for (const add of stage.onLeave) {
|
|
692
|
-
handover = {
|
|
693
|
-
...handover,
|
|
694
|
-
...add(turn, element, from, handover.data)
|
|
695
|
-
};
|
|
696
|
-
}
|
|
697
|
-
return handover;
|
|
698
|
-
},
|
|
699
|
-
stay(turn, stay) {
|
|
700
|
-
isHandingOver = false;
|
|
701
|
-
stage.drop();
|
|
702
|
-
for (const tell of stage.onStay) tell(stay);
|
|
703
|
-
morph.stay?.(turn, stay);
|
|
704
|
-
}
|
|
705
|
-
});
|
|
706
|
-
for (const begin of [
|
|
707
|
-
...finders.map((finder) => finder.start),
|
|
708
|
-
...morph.use ?? []
|
|
709
|
-
]) {
|
|
710
|
-
begin?.(stage);
|
|
711
|
-
}
|
|
712
|
-
const placed = handedOver();
|
|
713
|
-
if (placed && !placed.taken && placed.flight.m === name) {
|
|
714
|
-
stage.land(placed, () => onPage(morph.to), stage.about(null, false));
|
|
715
|
-
}
|
|
716
|
-
return () => {
|
|
717
|
-
remove();
|
|
718
|
-
defined.delete(name);
|
|
719
|
-
for (const stop of stage.onRemove) stop();
|
|
720
|
-
};
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
// src/morph/way.ts
|
|
724
|
-
var originKey = (name) => `${MORPH_KEY}:from:${name}`;
|
|
725
|
-
function originOf(name) {
|
|
726
|
-
const from = readSession(originKey(name));
|
|
727
|
-
const entry = navigationEntry();
|
|
728
|
-
if (from && window.top === window && new URL(from.u).pathname === location.pathname && entry?.type === "navigate" && window.pageturn?.arrival?.move !== from.a) {
|
|
729
|
-
forgetWayOut(name);
|
|
730
|
-
return null;
|
|
731
|
-
}
|
|
732
|
-
return from;
|
|
733
|
-
}
|
|
734
|
-
function forgetWayOut(name) {
|
|
735
|
-
if (window.top !== window) return;
|
|
736
|
-
removeSession(originKey(name));
|
|
737
|
-
}
|
|
738
|
-
var IN_VIEW = 0.25;
|
|
739
|
-
function shareOnScreen({ left, top, width, height }) {
|
|
740
|
-
const across = Math.min(left + width, innerWidth) - Math.max(left, 0);
|
|
741
|
-
const down = Math.min(top + height, innerHeight) - Math.max(top, 0);
|
|
742
|
-
return Math.max(across, 0) * Math.max(down, 0) / (width * height || 1);
|
|
743
|
-
}
|
|
744
|
-
function pathOf(element) {
|
|
745
|
-
let path = "";
|
|
746
|
-
for (let node = element; node !== document.body && node.parentElement; node = node.parentElement) {
|
|
747
|
-
const rank = [...node.parentElement.children].indexOf(node) + 1;
|
|
748
|
-
path = `>${node.localName}:nth-child(${rank})${path}`;
|
|
749
|
-
}
|
|
750
|
-
return `body${path}`;
|
|
751
|
-
}
|
|
752
|
-
function elementNamedByAddress() {
|
|
753
|
-
try {
|
|
754
|
-
return document.getElementById(decodeURIComponent(location.hash.slice(1)));
|
|
755
|
-
} catch {
|
|
756
|
-
return null;
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
function scrollOfAddress() {
|
|
760
|
-
elementNamedByAddress()?.scrollIntoView({ behavior: "instant" });
|
|
761
|
-
return { x: scrollX, y: scrollY };
|
|
762
|
-
}
|
|
763
|
-
function isInAnOpenPopover(element) {
|
|
764
|
-
try {
|
|
765
|
-
return element.parentElement?.closest(":popover-open") != null;
|
|
766
|
-
} catch {
|
|
767
|
-
return false;
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
var links = () => [
|
|
771
|
-
...document.querySelectorAll("a[href]")
|
|
772
|
-
];
|
|
773
|
-
var waysBack = /* @__PURE__ */ new WeakMap();
|
|
774
|
-
function readKept(keep) {
|
|
775
|
-
const read = [];
|
|
776
|
-
for (const [selector, names] of Object.entries(keep)) {
|
|
777
|
-
let element = null;
|
|
778
|
-
try {
|
|
779
|
-
element = document.querySelector(selector);
|
|
780
|
-
} catch {
|
|
781
|
-
}
|
|
782
|
-
if (!element) continue;
|
|
783
|
-
for (const attribute of [names].flat()) {
|
|
784
|
-
read.push([selector, attribute, element.getAttribute(attribute)]);
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
return read;
|
|
788
|
-
}
|
|
789
|
-
function rankOf(link) {
|
|
790
|
-
const { href } = link;
|
|
791
|
-
let rank = 0;
|
|
792
|
-
for (const other of links()) {
|
|
793
|
-
if (other === link) return rank;
|
|
794
|
-
if (other.href === href) rank += 1;
|
|
795
|
-
}
|
|
796
|
-
return -1;
|
|
797
|
-
}
|
|
798
|
-
var backFields = (from, name) => ({
|
|
799
|
-
s: from?.p ?? "",
|
|
800
|
-
...from ? {
|
|
801
|
-
...putBackFields(from, name),
|
|
802
|
-
l: [from.u, from.k, !!from.i]
|
|
803
|
-
} : {}
|
|
804
|
-
});
|
|
805
|
-
var putBackFields = (from, name) => ({
|
|
806
|
-
o: name,
|
|
807
|
-
v: from.v,
|
|
808
|
-
...from.w?.length ? { w: from.w } : {}
|
|
809
|
-
});
|
|
810
|
-
function wayBackOf(stage) {
|
|
811
|
-
const known = waysBack.get(stage);
|
|
812
|
-
if (known) return known;
|
|
813
|
-
const key = originKey(stage.name);
|
|
814
|
-
const way = {
|
|
815
|
-
name: `${stage.name}-back`,
|
|
816
|
-
origin: () => originOf(stage.name),
|
|
817
|
-
keep: {}
|
|
818
|
-
};
|
|
819
|
-
waysBack.set(stage, way);
|
|
820
|
-
stage.onLeave.push((turn, element, from, data) => {
|
|
821
|
-
writeSession(key, {
|
|
822
|
-
d: data,
|
|
823
|
-
a: stage.morph.arriveAs ?? stage.name,
|
|
824
|
-
f: location.pathname,
|
|
825
|
-
u: turn.link.href,
|
|
826
|
-
k: rankOf(turn.link),
|
|
827
|
-
p: pathOf(element),
|
|
828
|
-
v: isInAnOpenPopover(element),
|
|
829
|
-
w: readKept(way.keep),
|
|
830
|
-
// A click from the keyboard leaves the link with its ring; a mouse's, without.
|
|
831
|
-
i: turn.link.matches(":focus-visible"),
|
|
832
|
-
x: scrollX,
|
|
833
|
-
y: scrollY,
|
|
834
|
-
e: from
|
|
835
|
-
});
|
|
836
|
-
});
|
|
837
|
-
function startedHere() {
|
|
838
|
-
const from = way.origin();
|
|
839
|
-
return from?.f === location.pathname ? from : null;
|
|
840
|
-
}
|
|
841
|
-
function landBack(placed, isShown) {
|
|
842
|
-
const reached = arrival();
|
|
843
|
-
const options = reached?.via === "history" ? way.byHistory : way.byLink;
|
|
844
|
-
if (!reached || !options) return;
|
|
845
|
-
const from = startedHere();
|
|
846
|
-
const leading = links().filter((link2) => link2.pathname === reached.from);
|
|
847
|
-
const clicked = from ? linkAt(from.u, from.k) : void 0;
|
|
848
|
-
const link = clicked && leading.includes(clicked) ? clicked : leading.find((link2) => stage.morph.from?.(link2));
|
|
849
|
-
if (!link) return;
|
|
850
|
-
if (link !== clicked) {
|
|
851
|
-
document.adoptedStyleSheets = document.adoptedStyleSheets.filter(
|
|
852
|
-
(sheet) => sheet !== placed.sheet
|
|
853
|
-
);
|
|
854
|
-
}
|
|
855
|
-
const isByLink = reached.via === "link";
|
|
856
|
-
const { x = 0, y } = placed.flight;
|
|
857
|
-
if (y !== void 0) scrollTo(x, y);
|
|
858
|
-
stage.land(
|
|
859
|
-
placed,
|
|
860
|
-
() => stage.morph.from?.(link) ?? null,
|
|
861
|
-
stage.about(link, true),
|
|
862
|
-
y !== void 0 ? { x, y } : from && !isByLink && !isShown ? (
|
|
863
|
-
// On a Back the browser brings the scroll back itself, sometimes after this.
|
|
864
|
-
{ x: from.x, y: from.y }
|
|
865
|
-
) : isByLink ? scrollOfAddress() : { x: scrollX, y: scrollY },
|
|
866
|
-
options
|
|
867
|
-
);
|
|
868
|
-
}
|
|
869
|
-
queueMicrotask(() => {
|
|
870
|
-
const placed = handedOver();
|
|
871
|
-
if (placed && !placed.taken && placed.flight.m === way.name) {
|
|
872
|
-
landBack(placed, false);
|
|
873
|
-
}
|
|
874
|
-
});
|
|
875
|
-
stage.onStay.push((stay) => {
|
|
876
|
-
if (stay.reason !== "returned" || !arrival()) return;
|
|
877
|
-
const placed = placeHandedLayer();
|
|
878
|
-
if (placed?.flight.m === way.name) {
|
|
879
|
-
landBack(placed, true);
|
|
880
|
-
if (!placed.taken) clearLayer(placed);
|
|
881
|
-
}
|
|
882
|
-
});
|
|
883
|
-
return way;
|
|
884
|
-
}
|
|
885
|
-
function wayOut(name) {
|
|
886
|
-
const from = originOf(name);
|
|
887
|
-
return from && {
|
|
888
|
-
page: from.f,
|
|
889
|
-
scroll: { x: from.x, y: from.y },
|
|
890
|
-
data: from.d
|
|
891
|
-
};
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
// src/morph/back.ts
|
|
895
|
-
function back(options = {}) {
|
|
896
|
-
return (stage) => {
|
|
897
|
-
const way = wayBackOf(stage);
|
|
898
|
-
way.byHistory = options;
|
|
899
|
-
Object.assign(way.keep, options.keep);
|
|
900
|
-
stage.onLeave.push((_turn, _element, _from, data) => ({
|
|
901
|
-
returnAs: way.name,
|
|
902
|
-
remember: data
|
|
903
|
-
}));
|
|
904
|
-
const said = () => {
|
|
905
|
-
if (isLeaving()) return;
|
|
906
|
-
const from = way.origin();
|
|
907
|
-
const element = onPage(stage.morph.to);
|
|
908
|
-
const end = element && stage.read(element);
|
|
909
|
-
const store = window.pageturn?.i;
|
|
910
|
-
const report = { from: location.pathname, at: Date.now(), data: null };
|
|
911
|
-
if (!element || !end || shareOnScreen(end.box) < (options.inView ?? IN_VIEW)) {
|
|
912
|
-
if (from && new URL(from.u).pathname === location.pathname) {
|
|
913
|
-
store?.p({ ...report, none: true });
|
|
914
|
-
}
|
|
915
|
-
return;
|
|
916
|
-
}
|
|
917
|
-
if (store && !store.o()) store.p(report);
|
|
918
|
-
const layer = stage.layer(element, end, null);
|
|
919
|
-
writeSession(MORPH_KEY, {
|
|
920
|
-
n: way.name,
|
|
921
|
-
m: way.name,
|
|
922
|
-
h: markup(layer),
|
|
923
|
-
e: end,
|
|
924
|
-
t: false,
|
|
925
|
-
...backFields(from, stage.name)
|
|
926
|
-
});
|
|
927
|
-
};
|
|
928
|
-
addEventListener("pagehide", said);
|
|
929
|
-
stage.onRemove.push(() => removeEventListener("pagehide", said));
|
|
930
|
-
};
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
// src/morph/finders.ts
|
|
934
|
-
var SEEN_KEY = `${MORPH_KEY}:seen:`;
|
|
935
|
-
function here() {
|
|
936
|
-
return (_to, selector, measure) => {
|
|
937
|
-
const element = onPage(selector);
|
|
938
|
-
return element && shifted(measure(element), scrollX, scrollY);
|
|
939
|
-
};
|
|
940
|
-
}
|
|
941
|
-
var seenKey = (selector) => `${SEEN_KEY}${selector}:${innerWidth}x${innerHeight}`;
|
|
942
|
-
var SEEN_PAGES = 20;
|
|
943
|
-
function seen() {
|
|
944
|
-
const finder = (to, selector) => {
|
|
945
|
-
const pages = readSession(seenKey(selector)) ?? {};
|
|
946
|
-
const others = Object.keys(pages).filter(
|
|
947
|
-
(path) => path !== location.pathname
|
|
948
|
-
);
|
|
949
|
-
return pages[to.pathname] ?? pages[others[others.length - 1] ?? ""] ?? null;
|
|
950
|
-
};
|
|
951
|
-
finder.start = ({ morph, atRest }) => {
|
|
952
|
-
const say = () => {
|
|
953
|
-
const element = onPage(morph.to);
|
|
954
|
-
if (!element) return;
|
|
955
|
-
const end = atRest(element);
|
|
956
|
-
if (end.box.width > 0) {
|
|
957
|
-
const key = seenKey(morph.to);
|
|
958
|
-
const { [location.pathname]: _, ...pages } = readSession(key) ?? {};
|
|
959
|
-
const kept = Object.entries(pages).slice(1 - SEEN_PAGES);
|
|
960
|
-
writeSession(key, {
|
|
961
|
-
...Object.fromEntries(kept),
|
|
962
|
-
[location.pathname]: shifted(end, scrollX, scrollY)
|
|
963
|
-
});
|
|
964
|
-
}
|
|
965
|
-
};
|
|
966
|
-
if (document.readyState === "complete") say();
|
|
967
|
-
else addEventListener("load", say, { once: true });
|
|
968
|
-
};
|
|
969
|
-
return finder;
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
export {
|
|
973
|
-
within,
|
|
974
|
-
isEnding,
|
|
975
|
-
ownCorners,
|
|
976
|
-
cornersCss,
|
|
977
|
-
endOf,
|
|
978
|
-
atTheirEnd,
|
|
979
|
-
LAYER_STYLE,
|
|
980
|
-
CONTENT_STYLE,
|
|
981
|
-
cloned,
|
|
982
|
-
sizeOf,
|
|
983
|
-
centredOn,
|
|
984
|
-
markup,
|
|
985
|
-
MORPH_KEY,
|
|
986
|
-
onPage,
|
|
987
|
-
over,
|
|
988
|
-
isDefined,
|
|
989
|
-
defineMorph,
|
|
990
|
-
forgetWayOut,
|
|
991
|
-
IN_VIEW,
|
|
992
|
-
shareOnScreen,
|
|
993
|
-
backFields,
|
|
994
|
-
putBackFields,
|
|
995
|
-
wayBackOf,
|
|
996
|
-
wayOut,
|
|
997
|
-
back,
|
|
998
|
-
here,
|
|
999
|
-
seen
|
|
1000
|
-
};
|