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
package/dist/morph.js
CHANGED
|
@@ -25,70 +25,55 @@ import {
|
|
|
25
25
|
wayBackOf,
|
|
26
26
|
wayOut,
|
|
27
27
|
within
|
|
28
|
-
} from "./chunks/chunk-
|
|
28
|
+
} from "./chunks/chunk-LM3XLSCW.js";
|
|
29
29
|
import {
|
|
30
30
|
defineMove
|
|
31
|
-
} from "./chunks/chunk-
|
|
31
|
+
} from "./chunks/chunk-6FXXBNAF.js";
|
|
32
|
+
import "./chunks/chunk-JHM7F4CH.js";
|
|
32
33
|
import {
|
|
33
34
|
isFocusGivenBack,
|
|
34
35
|
reducesMotion
|
|
35
|
-
} from "./chunks/chunk-
|
|
36
|
+
} from "./chunks/chunk-AEOAXMU3.js";
|
|
36
37
|
import {
|
|
37
38
|
isDeclined
|
|
38
|
-
} from "./chunks/chunk-
|
|
39
|
+
} from "./chunks/chunk-YAL4MNCU.js";
|
|
39
40
|
|
|
40
41
|
// src/morph/frame.ts
|
|
41
42
|
var FRAME_STYLE = "position:fixed;top:0;border:0;margin:0;padding:0;max-width:none;max-height:none;pointer-events:none";
|
|
42
43
|
function loadInFrame(address, style, name = "") {
|
|
43
44
|
return new Promise((resolve) => {
|
|
44
|
-
|
|
45
|
-
frame.name = name;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
frame.inert = true;
|
|
49
|
-
frame.style.cssText = `${FRAME_STYLE};width:${document.documentElement.clientWidth}px;height:${innerHeight}px;${style}`;
|
|
50
|
-
const fail = () => {
|
|
51
|
-
frame.remove();
|
|
52
|
-
resolve(null);
|
|
45
|
+
let frame = document.createElement("iframe");
|
|
46
|
+
frame.name = name, frame.setAttribute("aria-hidden", "true"), frame.tabIndex = -1, frame.inert = !0, frame.style.cssText = `${FRAME_STYLE};width:${document.documentElement.clientWidth}px;height:${innerHeight}px;${style}`;
|
|
47
|
+
let fail = () => {
|
|
48
|
+
frame.remove(), resolve(null);
|
|
53
49
|
};
|
|
54
|
-
frame.addEventListener("error", fail)
|
|
55
|
-
frame.addEventListener("load", async () => {
|
|
50
|
+
frame.addEventListener("error", fail), frame.addEventListener("load", async () => {
|
|
56
51
|
try {
|
|
57
|
-
await frame.contentDocument?.fonts.ready;
|
|
58
|
-
if (!frame.contentDocument?.body) throw new Error("no page");
|
|
52
|
+
if (await frame.contentDocument?.fonts.ready, !frame.contentDocument?.body) throw new Error("no page");
|
|
59
53
|
resolve(frame);
|
|
60
54
|
} catch {
|
|
61
55
|
fail();
|
|
62
56
|
}
|
|
63
|
-
});
|
|
64
|
-
frame.src = address;
|
|
65
|
-
document.documentElement.append(frame);
|
|
57
|
+
}), frame.src = address, document.documentElement.append(frame);
|
|
66
58
|
});
|
|
67
59
|
}
|
|
68
60
|
var INTENTS = ["pointerover", "focusin", "touchstart"];
|
|
69
61
|
function onApproach(tell) {
|
|
70
|
-
let last = null
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
from: new URL(location.href),
|
|
80
|
-
to: new URL(link.href),
|
|
81
|
-
canHandOver: true
|
|
82
|
-
});
|
|
83
|
-
}
|
|
62
|
+
let last = null, heard = (event) => {
|
|
63
|
+
let link = event.target instanceof Element ? event.target.closest("a[href]") : null;
|
|
64
|
+
link !== last && (last = link, link && !isFocusGivenBack(link) && !reducesMotion() && tell({
|
|
65
|
+
link,
|
|
66
|
+
via: "link",
|
|
67
|
+
from: new URL(location.href),
|
|
68
|
+
to: new URL(link.href),
|
|
69
|
+
canHandOver: !0
|
|
70
|
+
}));
|
|
84
71
|
};
|
|
85
|
-
for (
|
|
86
|
-
addEventListener(intent, heard, { passive:
|
|
87
|
-
}
|
|
72
|
+
for (let intent of INTENTS)
|
|
73
|
+
addEventListener(intent, heard, { passive: !0, capture: !0 });
|
|
88
74
|
return () => {
|
|
89
|
-
for (
|
|
90
|
-
removeEventListener(intent, heard, { capture:
|
|
91
|
-
}
|
|
75
|
+
for (let intent of INTENTS)
|
|
76
|
+
removeEventListener(intent, heard, { capture: !0 });
|
|
92
77
|
};
|
|
93
78
|
}
|
|
94
79
|
|
|
@@ -96,30 +81,27 @@ function onApproach(tell) {
|
|
|
96
81
|
var BEHIND_WAIT_MS = 800;
|
|
97
82
|
function behind(options = {}) {
|
|
98
83
|
return (stage) => {
|
|
99
|
-
|
|
84
|
+
let way = wayBackOf(stage);
|
|
100
85
|
stage.appear = options.appear;
|
|
101
|
-
let loading = null
|
|
102
|
-
|
|
103
|
-
loading?.frame.then((frame) => frame?.remove());
|
|
104
|
-
loading = null;
|
|
86
|
+
let loading = null, dropFrame = () => {
|
|
87
|
+
loading?.frame.then((frame) => frame?.remove()), loading = null;
|
|
105
88
|
};
|
|
106
89
|
function showBehind(address, from) {
|
|
107
90
|
if (loading?.address !== address) {
|
|
108
91
|
dropFrame();
|
|
109
|
-
|
|
92
|
+
let frame = loadInFrame(
|
|
110
93
|
address,
|
|
111
94
|
// Just under the layer, above everything of the page's.
|
|
112
95
|
"left:0;opacity:0;z-index:2147483646",
|
|
113
96
|
`${MORPH_KEY}:${JSON.stringify({ x: from.x, y: from.y, m: way.name, d: from.d, p: from.p, ...putBackFields(from, stage.name) })}`
|
|
114
97
|
).then((loaded) => {
|
|
115
|
-
|
|
98
|
+
let view = loaded?.contentWindow;
|
|
116
99
|
if (!loaded || !view) return null;
|
|
117
100
|
view.scrollTo(from.x, from.y);
|
|
118
|
-
|
|
101
|
+
let there = loaded.contentDocument?.querySelector(
|
|
119
102
|
from.p
|
|
120
103
|
);
|
|
121
|
-
|
|
122
|
-
return new Promise(
|
|
104
|
+
return there && (there.style.visibility = "hidden"), new Promise(
|
|
123
105
|
(resolve) => view.requestAnimationFrame(
|
|
124
106
|
() => view.requestAnimationFrame(() => resolve(loaded))
|
|
125
107
|
)
|
|
@@ -130,20 +112,16 @@ function behind(options = {}) {
|
|
|
130
112
|
return loading.frame;
|
|
131
113
|
}
|
|
132
114
|
way.aims = (from, end, about) => {
|
|
133
|
-
|
|
115
|
+
let ends = {
|
|
134
116
|
from: { ...from.e },
|
|
135
117
|
to: end
|
|
136
118
|
};
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
};
|
|
140
|
-
way.frameBehind = (visit, from) => within(showBehind(visit.to.href, from), options.wait ?? BEHIND_WAIT_MS);
|
|
141
|
-
way.dropFrame = dropFrame;
|
|
142
|
-
stage.onRemove.push(
|
|
119
|
+
return isDeclined(stage.morph.ends?.(ends, about)) ? !1 : { stop: ends.from, end: ends.to ?? end };
|
|
120
|
+
}, way.frameBehind = (visit, from) => within(showBehind(visit.to.href, from), options.wait ?? BEHIND_WAIT_MS), way.dropFrame = dropFrame, stage.onRemove.push(
|
|
143
121
|
dropFrame,
|
|
144
122
|
onApproach((visit) => {
|
|
145
|
-
|
|
146
|
-
|
|
123
|
+
let from = way.origin();
|
|
124
|
+
from && way.leadsBack?.(visit) && showBehind(visit.to.href, from);
|
|
147
125
|
})
|
|
148
126
|
);
|
|
149
127
|
};
|
|
@@ -153,23 +131,13 @@ function behind(options = {}) {
|
|
|
153
131
|
function copy() {
|
|
154
132
|
return {
|
|
155
133
|
build(element) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const own = element;
|
|
159
|
-
const drawn = own.offsetWidth && own.offsetHeight ? null : element.getBoundingClientRect();
|
|
160
|
-
const width = own.offsetWidth || (drawn?.width ?? 0);
|
|
161
|
-
const height = own.offsetHeight || (drawn?.height ?? 0);
|
|
162
|
-
content.style.cssText += `;width:${width}px;height:${height}px;${CONTENT_STYLE}`;
|
|
163
|
-
content.dataset.turnContent = "";
|
|
164
|
-
layer.style.cssText = `${LAYER_STYLE};width:${width}px;height:${height}px`;
|
|
165
|
-
layer.append(content);
|
|
166
|
-
return layer;
|
|
134
|
+
let layer = document.createElement("div"), content = cloned(element), own = element, drawn = own.offsetWidth && own.offsetHeight ? null : element.getBoundingClientRect(), width = own.offsetWidth || (drawn?.width ?? 0), height = own.offsetHeight || (drawn?.height ?? 0);
|
|
135
|
+
return content.style.cssText += `;width:${width}px;height:${height}px;${CONTENT_STYLE}`, content.dataset.turnContent = "", layer.style.cssText = `${LAYER_STYLE};width:${width}px;height:${height}px`, layer.append(content), layer;
|
|
167
136
|
},
|
|
168
137
|
pose(layer) {
|
|
169
|
-
|
|
138
|
+
let [width, height] = sizeOf(layer);
|
|
170
139
|
return ({ box, rotate = 0, radius }) => {
|
|
171
|
-
|
|
172
|
-
const y = box.height / height;
|
|
140
|
+
let x = box.width / width, y = box.height / height;
|
|
173
141
|
return {
|
|
174
142
|
move: {
|
|
175
143
|
translate: centredOn(box, width, height),
|
|
@@ -189,79 +157,58 @@ function copy() {
|
|
|
189
157
|
// src/morph/link-back.ts
|
|
190
158
|
function linkBack(options = {}) {
|
|
191
159
|
return (stage) => {
|
|
192
|
-
|
|
193
|
-
way.byLink = options;
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
return options.match ? options.match(visit) : visit.to.pathname === way.origin()?.f;
|
|
199
|
-
};
|
|
200
|
-
const started = way.origin();
|
|
201
|
-
for (const link of document.querySelectorAll(
|
|
160
|
+
let way = wayBackOf(stage);
|
|
161
|
+
way.byLink = options, Object.assign(way.keep, options.keep);
|
|
162
|
+
let isMarked = (link) => link.getAttribute("data-turn-back") === stage.name;
|
|
163
|
+
way.leadsBack = (visit) => isMarked(visit.link) ? !0 : options.match ? options.match(visit) : visit.to.pathname === way.origin()?.f;
|
|
164
|
+
let started = way.origin();
|
|
165
|
+
for (let link of document.querySelectorAll(
|
|
202
166
|
"a[data-turn-back]"
|
|
203
|
-
))
|
|
204
|
-
if (
|
|
205
|
-
link.dataset.turn = way.name;
|
|
206
|
-
if (started && started.f !== link.pathname) {
|
|
167
|
+
))
|
|
168
|
+
if (isMarked(link) && (link.dataset.turn = way.name, started && started.f !== link.pathname)) {
|
|
207
169
|
link.href = started.f;
|
|
208
|
-
|
|
209
|
-
|
|
170
|
+
let label = link.dataset.turnBackLabel;
|
|
171
|
+
label && link.setAttribute("aria-label", label);
|
|
210
172
|
}
|
|
211
|
-
}
|
|
212
173
|
stage.onRemove.push(
|
|
213
174
|
defineMove(way.name, {
|
|
214
175
|
match: way.leadsBack,
|
|
215
176
|
async leave(turn) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const element = onPage(stage.morph.to);
|
|
219
|
-
if (!element || !turn.canHandOver || stage.live) {
|
|
177
|
+
let origin = way.origin(), from = origin?.f === turn.to.pathname ? origin : null, element = onPage(stage.morph.to);
|
|
178
|
+
if (!element || !turn.canHandOver || stage.live)
|
|
220
179
|
return turn.decline();
|
|
221
|
-
|
|
222
|
-
const about = stage.about(null, true);
|
|
223
|
-
let end = stage.read(element);
|
|
224
|
-
let stop = null;
|
|
180
|
+
let about = stage.about(null, !0), end = stage.read(element), stop = null;
|
|
225
181
|
if (from && way.aims) {
|
|
226
|
-
|
|
227
|
-
if (aimed ===
|
|
182
|
+
let aimed = way.aims(from, end, about);
|
|
183
|
+
if (aimed === !1) return turn.decline();
|
|
228
184
|
({ stop, end } = aimed);
|
|
229
185
|
}
|
|
230
|
-
if (shareOnScreen(end.box) < (options.inView ?? IN_VIEW))
|
|
186
|
+
if (shareOnScreen(end.box) < (options.inView ?? IN_VIEW))
|
|
231
187
|
return turn.decline();
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
frame
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
await leaving;
|
|
247
|
-
const scrollsBack = from && (stop || options.scroll !== false && !turn.to.hash);
|
|
248
|
-
stage.hand({
|
|
188
|
+
let frame = from && stop ? await way.frameBehind?.(turn, from) ?? null : null, layer = await stage.put(element, end, stop), leaving = turn.leaving();
|
|
189
|
+
stop && await stage.travel(
|
|
190
|
+
end,
|
|
191
|
+
stop,
|
|
192
|
+
about,
|
|
193
|
+
stage.timing(options),
|
|
194
|
+
!0,
|
|
195
|
+
frame
|
|
196
|
+
), await leaving;
|
|
197
|
+
let scrollsBack = from && (stop || options.scroll !== !1 && !turn.to.hash);
|
|
198
|
+
return stage.hand({
|
|
249
199
|
n: way.name,
|
|
250
200
|
m: way.name,
|
|
251
201
|
h: markup(layer),
|
|
252
202
|
e: stop ?? end,
|
|
253
203
|
...stop ? { f: end } : {},
|
|
254
|
-
t:
|
|
255
|
-
b:
|
|
204
|
+
t: !!stop,
|
|
205
|
+
b: !!frame,
|
|
256
206
|
...backFields(from, stage.name),
|
|
257
207
|
...from && scrollsBack ? { x: from.x, y: from.y } : {}
|
|
258
|
-
});
|
|
259
|
-
return { data: from?.d ?? null };
|
|
208
|
+
}), { data: from?.d ?? null };
|
|
260
209
|
},
|
|
261
210
|
stay(turn, stay) {
|
|
262
|
-
stage.drop();
|
|
263
|
-
way.dropFrame?.();
|
|
264
|
-
stage.morph.stay?.(turn, stay);
|
|
211
|
+
stage.drop(), way.dropFrame?.(), stage.morph.stay?.(turn, stay);
|
|
265
212
|
}
|
|
266
213
|
})
|
|
267
214
|
);
|
|
@@ -271,84 +218,56 @@ function linkBack(options = {}) {
|
|
|
271
218
|
// src/morph/peek.ts
|
|
272
219
|
var PEEK_WAIT_MS = 1500;
|
|
273
220
|
function peek(options = {}) {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
return answer;
|
|
295
|
-
};
|
|
296
|
-
const finder = (to, selector, measure) => within(measureThere(to, selector, measure), options.wait ?? PEEK_WAIT_MS);
|
|
297
|
-
if (options.warm ?? true) {
|
|
298
|
-
finder.start = (stage) => {
|
|
299
|
-
stage.onRemove.push(
|
|
300
|
-
onApproach((visit) => {
|
|
301
|
-
const { match, from } = stage.morph;
|
|
302
|
-
if (match ? match(visit) : from?.(visit.link)) {
|
|
303
|
-
measureThere(visit.to, stage.morph.to, stage.read);
|
|
304
|
-
}
|
|
305
|
-
})
|
|
306
|
-
);
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
return finder;
|
|
221
|
+
let asked = /* @__PURE__ */ new Map(), measureThere = (to, selector, measure) => {
|
|
222
|
+
let key = `${to.href} ${selector} ${innerWidth}x${innerHeight}`, answer = asked.get(key);
|
|
223
|
+
return answer || (answer = loadInFrame(to.href, "left:-200vw;visibility:hidden").then(
|
|
224
|
+
(frame) => {
|
|
225
|
+
let page = frame?.contentDocument, element = page?.querySelector(selector);
|
|
226
|
+
for (let animation of page?.getAnimations() ?? [])
|
|
227
|
+
isEnding(animation) && animation.finish();
|
|
228
|
+
let end = element ? measure(element) : null;
|
|
229
|
+
return frame?.remove(), end || asked.delete(key), end;
|
|
230
|
+
}
|
|
231
|
+
), asked.set(key, answer)), answer;
|
|
232
|
+
}, finder = (to, selector, measure) => within(measureThere(to, selector, measure), options.wait ?? PEEK_WAIT_MS);
|
|
233
|
+
return (options.warm ?? !0) && (finder.start = (stage) => {
|
|
234
|
+
stage.onRemove.push(
|
|
235
|
+
onApproach((visit) => {
|
|
236
|
+
let { match, from } = stage.morph;
|
|
237
|
+
(match ? match(visit) : from?.(visit.link)) && measureThere(visit.to, stage.morph.to, stage.read);
|
|
238
|
+
})
|
|
239
|
+
);
|
|
240
|
+
}), finder;
|
|
310
241
|
}
|
|
311
242
|
|
|
312
243
|
// src/morph/shadow.ts
|
|
313
244
|
function asDropShadow(shadow2) {
|
|
314
245
|
if (/^[-\d.]/.test(shadow2)) return shadow2;
|
|
315
|
-
|
|
246
|
+
let [, color, x, y, blur] = /^(.*?\)|\S+) (\S+) (\S+) (\S+)/.exec(shadow2) ?? [];
|
|
316
247
|
return color && blur ? `${x} ${y} ${blur} ${color}` : void 0;
|
|
317
248
|
}
|
|
318
249
|
var dropShadow = (shadow2) => `drop-shadow(${shadow2})`;
|
|
319
250
|
function shadow() {
|
|
320
251
|
return (stage) => {
|
|
321
|
-
|
|
252
|
+
let { read } = stage;
|
|
322
253
|
stage.read = (element) => {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
};
|
|
328
|
-
stage.onPlay.push((layer, first, last, timing, finished) => {
|
|
329
|
-
const start = first.shadow && asDropShadow(first.shadow);
|
|
330
|
-
const stop = last.shadow && asDropShadow(last.shadow);
|
|
331
|
-
const one = start ?? stop;
|
|
254
|
+
let end = read(element), own = asDropShadow(getComputedStyle(element).boxShadow);
|
|
255
|
+
return own && (end.shadow = own), end;
|
|
256
|
+
}, stage.onPlay.push((layer, first, last, timing, finished) => {
|
|
257
|
+
let start = first.shadow && asDropShadow(first.shadow), stop = last.shadow && asDropShadow(last.shadow), one = start ?? stop;
|
|
332
258
|
if (!one) return;
|
|
333
|
-
|
|
334
|
-
caster.setAttribute("aria-hidden", "true");
|
|
335
|
-
|
|
336
|
-
caster.style.cssText = `position:fixed;left:0;top:0;z-index:2147483646;pointer-events:none;filter:${dropShadow(one)}`;
|
|
337
|
-
const shape = document.createElement("div");
|
|
259
|
+
let caster = document.createElement("div");
|
|
260
|
+
caster.setAttribute("aria-hidden", "true"), caster.dataset.turnShadow = "", caster.style.cssText = `position:fixed;left:0;top:0;z-index:2147483646;pointer-events:none;filter:${dropShadow(one)}`;
|
|
261
|
+
let shape = document.createElement("div");
|
|
338
262
|
shape.style.cssText = `background:#000;width:${layer.style.width};height:${layer.style.height}`;
|
|
339
|
-
for (
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
shape.animate(effect.getKeyframes(), timing);
|
|
343
|
-
}
|
|
263
|
+
for (let animation of layer.getAnimations()) {
|
|
264
|
+
let { effect } = animation;
|
|
265
|
+
effect instanceof KeyframeEffect && shape.animate(effect.getKeyframes(), timing);
|
|
344
266
|
}
|
|
345
267
|
caster.animate(
|
|
346
268
|
start && stop ? { filter: [dropShadow(start), dropShadow(stop)] } : { opacity: start ? [1, 0] : [0, 1] },
|
|
347
269
|
timing
|
|
348
|
-
);
|
|
349
|
-
caster.append(shape);
|
|
350
|
-
layer.before(caster);
|
|
351
|
-
finished.then(() => caster.remove());
|
|
270
|
+
), caster.append(shape), layer.before(caster), finished.then(() => caster.remove());
|
|
352
271
|
});
|
|
353
272
|
};
|
|
354
273
|
}
|
|
@@ -360,8 +279,7 @@ var TYPE = [
|
|
|
360
279
|
"fontStretch",
|
|
361
280
|
"letterSpacing",
|
|
362
281
|
"fontVariationSettings"
|
|
363
|
-
]
|
|
364
|
-
var FACE = [
|
|
282
|
+
], FACE = [
|
|
365
283
|
"fontFamily",
|
|
366
284
|
"fontStyle",
|
|
367
285
|
"textTransform",
|
|
@@ -369,19 +287,17 @@ var FACE = [
|
|
|
369
287
|
"fontFeatureSettings"
|
|
370
288
|
];
|
|
371
289
|
function glyphs(element) {
|
|
372
|
-
|
|
290
|
+
let range = element.ownerDocument.createRange();
|
|
373
291
|
range.selectNodeContents(element);
|
|
374
|
-
|
|
292
|
+
let { left, top, width, height } = range.getBoundingClientRect();
|
|
375
293
|
return { left, top, width, height };
|
|
376
294
|
}
|
|
377
295
|
function splitDifference(one, other) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
while (head < least && one[head] === other[head]) head++;
|
|
296
|
+
let least = Math.min(one.length, other.length), head = 0;
|
|
297
|
+
for (; head < least && one[head] === other[head]; ) head++;
|
|
381
298
|
let tail = 0;
|
|
382
|
-
|
|
299
|
+
for (; tail < least - head && one[one.length - 1 - tail] === other[other.length - 1 - tail]; )
|
|
383
300
|
tail++;
|
|
384
|
-
}
|
|
385
301
|
return [
|
|
386
302
|
one.slice(0, head),
|
|
387
303
|
one.slice(head, one.length - tail),
|
|
@@ -390,48 +306,33 @@ function splitDifference(one, other) {
|
|
|
390
306
|
];
|
|
391
307
|
}
|
|
392
308
|
function text(options = {}) {
|
|
393
|
-
|
|
394
|
-
const part = (layer, name) => layer.querySelector(`[data-turn-part="${name}"]`);
|
|
309
|
+
let pseudoOf = (isTo) => typeof options.box == "object" ? options.box[isTo ? "to" : "from"] : options.box, part = (layer, name) => layer.querySelector(`[data-turn-part="${name}"]`);
|
|
395
310
|
return {
|
|
396
311
|
read(element, end, isTo) {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
if (
|
|
402
|
-
|
|
403
|
-
}
|
|
404
|
-
let box = glyphs(element);
|
|
405
|
-
const words = (element.textContent ?? "").replace(/\s+/g, " ").trim();
|
|
406
|
-
end.background = style.backgroundColor;
|
|
407
|
-
if (element.getClientRects().length === 0) {
|
|
408
|
-
const copy2 = document.createElement("span");
|
|
312
|
+
let style = getComputedStyle(element), type = {};
|
|
313
|
+
for (let property of TYPE) type[property] = style[property];
|
|
314
|
+
type.letterSpacing === "normal" && (type.letterSpacing = "0px"), type.fontVariationSettings === "normal" && (type.fontVariationSettings = `"opsz" ${Number.parseFloat(style.fontSize)}`);
|
|
315
|
+
let box = glyphs(element), words = (element.textContent ?? "").replace(/\s+/g, " ").trim();
|
|
316
|
+
if (end.background = style.backgroundColor, element.getClientRects().length === 0) {
|
|
317
|
+
let copy2 = document.createElement("span");
|
|
409
318
|
copy2.style.cssText = "position:fixed;left:0;top:0;white-space:nowrap;line-height:1;font-optical-sizing:none;visibility:hidden";
|
|
410
|
-
for (
|
|
411
|
-
Object.assign(copy2.style, type);
|
|
412
|
-
copy2.textContent = words;
|
|
413
|
-
document.documentElement.append(copy2);
|
|
414
|
-
box = glyphs(copy2);
|
|
415
|
-
copy2.remove();
|
|
416
|
-
end.box = { ...box };
|
|
319
|
+
for (let property of FACE) copy2.style[property] = style[property];
|
|
320
|
+
Object.assign(copy2.style, type), copy2.textContent = words, document.documentElement.append(copy2), box = glyphs(copy2), copy2.remove(), end.box = { ...box };
|
|
417
321
|
} else if (pseudoOf(isTo)) {
|
|
418
|
-
|
|
419
|
-
const [left, top, width, height] = [
|
|
322
|
+
let drawn = getComputedStyle(element, pseudoOf(isTo)), [left, top, width, height] = [
|
|
420
323
|
drawn.left,
|
|
421
324
|
drawn.top,
|
|
422
325
|
drawn.width,
|
|
423
326
|
drawn.height
|
|
424
327
|
].map(Number.parseFloat);
|
|
425
328
|
if (drawn.content !== "none" && [left, top, width, height].every(Number.isFinite)) {
|
|
426
|
-
|
|
329
|
+
let own = element.getBoundingClientRect();
|
|
427
330
|
end.box = {
|
|
428
331
|
left: own.left + element.clientLeft + (left ?? 0),
|
|
429
332
|
top: own.top + element.clientTop + (top ?? 0),
|
|
430
333
|
width: width ?? 0,
|
|
431
334
|
height: height ?? 0
|
|
432
|
-
};
|
|
433
|
-
end.radius = ownCorners(drawn, width ?? 0);
|
|
434
|
-
end.background = drawn.backgroundColor;
|
|
335
|
+
}, end.radius = ownCorners(drawn, width ?? 0), end.background = drawn.backgroundColor;
|
|
435
336
|
}
|
|
436
337
|
}
|
|
437
338
|
end.text = {
|
|
@@ -442,49 +343,25 @@ function text(options = {}) {
|
|
|
442
343
|
};
|
|
443
344
|
},
|
|
444
345
|
build(element, from) {
|
|
445
|
-
|
|
446
|
-
const content = document.createElement("span");
|
|
447
|
-
const fill = document.createElement("span");
|
|
448
|
-
const style = getComputedStyle(element);
|
|
449
|
-
const type = from.text?.type ?? {};
|
|
346
|
+
let layer = document.createElement("div"), content = document.createElement("span"), fill = document.createElement("span"), style = getComputedStyle(element), type = from.text?.type ?? {};
|
|
450
347
|
layer.style.cssText = `${LAYER_STYLE};width:0;height:0;white-space:nowrap;line-height:1;font-optical-sizing:none`;
|
|
451
|
-
for (
|
|
452
|
-
Object.assign(layer.style, type);
|
|
453
|
-
content.style.cssText = "position:absolute;left:0;top:0";
|
|
454
|
-
content.textContent = from.text?.words ?? "";
|
|
455
|
-
content.dataset.turnContent = "";
|
|
456
|
-
content.dataset.turnWords = "";
|
|
457
|
-
fill.style.cssText = "position:absolute;z-index:-1";
|
|
458
|
-
fill.dataset.turnBox = "";
|
|
459
|
-
layer.append(content, fill);
|
|
460
|
-
return layer;
|
|
348
|
+
for (let property of FACE) layer.style[property] = style[property];
|
|
349
|
+
return Object.assign(layer.style, type), content.style.cssText = "position:absolute;left:0;top:0", content.textContent = from.text?.words ?? "", content.dataset.turnContent = "", content.dataset.turnWords = "", fill.style.cssText = "position:absolute;z-index:-1", fill.dataset.turnBox = "", layer.append(content, fill), layer;
|
|
461
350
|
},
|
|
462
351
|
pose(layer) {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
const line = document.createElement("span");
|
|
467
|
-
probe.removeAttribute("popover");
|
|
468
|
-
delete probe.dataset.turnLayer;
|
|
469
|
-
Object.assign(probe.style, words.type, {
|
|
352
|
+
let fill = layer.lastElementChild, insetOf = (words) => {
|
|
353
|
+
let probe = layer.cloneNode(!1), line = document.createElement("span");
|
|
354
|
+
probe.removeAttribute("popover"), delete probe.dataset.turnLayer, Object.assign(probe.style, words.type, {
|
|
470
355
|
translate: "none",
|
|
471
356
|
rotate: "none",
|
|
472
357
|
visibility: "hidden"
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
probe.append(line);
|
|
477
|
-
document.documentElement.append(probe);
|
|
478
|
-
const corner = probe.getBoundingClientRect();
|
|
479
|
-
const drawn = glyphs(line);
|
|
480
|
-
probe.remove();
|
|
481
|
-
return [drawn.left - corner.left, drawn.top - corner.top];
|
|
358
|
+
}), line.style.cssText = "position:absolute;left:0;top:0", line.textContent = words.words, probe.append(line), document.documentElement.append(probe);
|
|
359
|
+
let corner = probe.getBoundingClientRect(), drawn = glyphs(line);
|
|
360
|
+
return probe.remove(), [drawn.left - corner.left, drawn.top - corner.top];
|
|
482
361
|
};
|
|
483
362
|
return ({ text: words, rotate = 0, box, radius, background }) => {
|
|
484
363
|
if (!words) throw new Error("pageturn/morph: an end has no text");
|
|
485
|
-
|
|
486
|
-
const left = words.box.left - x;
|
|
487
|
-
const top = words.box.top - y;
|
|
364
|
+
let [x, y] = insetOf(words), left = words.box.left - x, top = words.box.top - y;
|
|
488
365
|
return {
|
|
489
366
|
// By a translation, not `left` and `top`: Safari does not show those travel.
|
|
490
367
|
move: { translate: `${left}px ${top}px`, rotate: `${rotate}deg` },
|
|
@@ -514,33 +391,22 @@ function text(options = {}) {
|
|
|
514
391
|
};
|
|
515
392
|
},
|
|
516
393
|
play(layer, start, stop, timing, back2) {
|
|
517
|
-
|
|
518
|
-
const [from, to] = [start.text?.words ?? "", stop.text?.words ?? ""];
|
|
394
|
+
let content = layer.firstElementChild, [from, to] = [start.text?.words ?? "", stop.text?.words ?? ""];
|
|
519
395
|
if (from === to || !to || content.firstElementChild) return;
|
|
520
|
-
|
|
521
|
-
const swap = (typeof options.swap === "function" ? options.swap({ back: back2 }) : options.swap) ?? {};
|
|
522
|
-
const span = (name, words, style) => `<span data-turn-part="${name}" style="${style}">${words.replace(/[&<]/g, (sign) => sign === "&" ? "&" : "<")}</span>`;
|
|
396
|
+
let [head, leaving, arriving, rest] = splitDifference(from, to), swap = (typeof options.swap == "function" ? options.swap({ back: back2 }) : options.swap) ?? {}, span = (name, words, style) => `<span data-turn-part="${name}" style="${style}">${words.replace(/[&<]/g, (sign) => sign === "&" ? "&" : "<")}</span>`;
|
|
523
397
|
content.innerHTML = span("head", head, "") + `<span style="position:relative;display:inline-block">${span("arriving", arriving, "display:inline-block")}${span("leaving", leaving, "position:absolute;left:0;top:0")}</span><span data-turn-part="fit" style="display:inline-block">${span("rest", rest, "display:inline-block;white-space:pre")}</span>`;
|
|
524
|
-
|
|
398
|
+
let [fit, restPart, leavingPart, arrivingPart] = [
|
|
525
399
|
"fit",
|
|
526
400
|
"rest",
|
|
527
401
|
"leaving",
|
|
528
402
|
"arriving"
|
|
529
|
-
].map((name) => part(layer, name));
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
const shareToClose = () => 100 * (widthOf(arrivingPart) - widthOf(leavingPart)) / (widthOf(restPart) || 1);
|
|
534
|
-
const atStart = shareToClose();
|
|
535
|
-
const atStop = atTheirEnd(layer.getAnimations(), shareToClose);
|
|
536
|
-
const swapTiming = over(timing, swap);
|
|
537
|
-
fit?.animate({ translate: [`${-atStart}% 0`, `${-atStop}% 0`] }, timing);
|
|
538
|
-
restPart?.animate({ translate: ["0% 0", `${atStop}% 0`] }, swapTiming);
|
|
539
|
-
leavingPart?.animate(
|
|
403
|
+
].map((name) => part(layer, name)), slot = arrivingPart?.parentElement;
|
|
404
|
+
swap.clip && (slot.style.clipPath = swap.clip);
|
|
405
|
+
let widthOf = (element) => element?.getBoundingClientRect().width ?? 0, shareToClose = () => 100 * (widthOf(arrivingPart) - widthOf(leavingPart)) / (widthOf(restPart) || 1), atStart = shareToClose(), atStop = atTheirEnd(layer.getAnimations(), shareToClose), swapTiming = over(timing, swap);
|
|
406
|
+
fit?.animate({ translate: [`${-atStart}% 0`, `${-atStop}% 0`] }, timing), restPart?.animate({ translate: ["0% 0", `${atStop}% 0`] }, swapTiming), leavingPart?.animate(
|
|
540
407
|
swap.leave ?? [{ opacity: 1 }, { opacity: 0 }],
|
|
541
408
|
swapTiming
|
|
542
|
-
)
|
|
543
|
-
arrivingPart?.animate(
|
|
409
|
+
), arrivingPart?.animate(
|
|
544
410
|
swap.arrive ?? [{ opacity: 0 }, { opacity: 1 }],
|
|
545
411
|
swapTiming
|
|
546
412
|
);
|
|
@@ -550,24 +416,16 @@ function text(options = {}) {
|
|
|
550
416
|
|
|
551
417
|
// src/morph/turned.ts
|
|
552
418
|
function ownTransform(style) {
|
|
553
|
-
|
|
419
|
+
let [x = 1, y = x] = style.scale.split(" ").map(Number.parseFloat);
|
|
554
420
|
return new DOMMatrix().rotate(Number.parseFloat(style.rotate) || 0).scale(x || 1, y || 1).multiply(new DOMMatrix(style.transform));
|
|
555
421
|
}
|
|
556
422
|
function turned() {
|
|
557
423
|
return (stage) => {
|
|
558
424
|
stage.endOf = (element) => {
|
|
559
|
-
|
|
560
|
-
let
|
|
561
|
-
for (let node = element; node; node = node.parentElement) {
|
|
425
|
+
let end = endOf(element), matrix = new DOMMatrix();
|
|
426
|
+
for (let node = element; node; node = node.parentElement)
|
|
562
427
|
matrix = ownTransform(getComputedStyle(node)).multiply(matrix);
|
|
563
|
-
}
|
|
564
|
-
const rotate = Math.atan2(matrix.b, matrix.a) * 180 / Math.PI;
|
|
565
|
-
const scaleX = Math.hypot(matrix.a, matrix.b);
|
|
566
|
-
const own = element;
|
|
567
|
-
const isTurned = Math.abs(rotate) > 0.01 && own.offsetWidth > 0;
|
|
568
|
-
const { box } = end;
|
|
569
|
-
const width = isTurned ? own.offsetWidth * scaleX : box.width;
|
|
570
|
-
const height = isTurned ? own.offsetHeight * Math.hypot(matrix.c, matrix.d) : box.height;
|
|
428
|
+
let rotate = Math.atan2(matrix.b, matrix.a) * 180 / Math.PI, scaleX = Math.hypot(matrix.a, matrix.b), own = element, isTurned = Math.abs(rotate) > 0.01 && own.offsetWidth > 0, { box } = end, width = isTurned ? own.offsetWidth * scaleX : box.width, height = isTurned ? own.offsetHeight * Math.hypot(matrix.c, matrix.d) : box.height;
|
|
571
429
|
return {
|
|
572
430
|
...end,
|
|
573
431
|
box: {
|
package/dist/native.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import "./chunks/chunk-
|
|
2
|
-
import "./chunks/chunk-
|
|
1
|
+
import "./chunks/chunk-C3T7BGNG.js";
|
|
2
|
+
import "./chunks/chunk-AEOAXMU3.js";
|
|
3
|
+
import "./chunks/chunk-YAL4MNCU.js";
|