@prose-reader/enhancer-gestures 1.303.0 → 1.305.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/dist/index.js +385 -532
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +403 -543
- package/dist/index.umd.cjs.map +1 -1
- package/package.json +3 -3
package/dist/index.umd.cjs
CHANGED
|
@@ -1,544 +1,404 @@
|
|
|
1
1
|
(function(global, factory) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
};
|
|
406
|
-
}
|
|
407
|
-
getDefaultSettings() {
|
|
408
|
-
return {
|
|
409
|
-
panNavigation: "pan",
|
|
410
|
-
pinchCancelPan: true,
|
|
411
|
-
fontScalePinchEnabled: true,
|
|
412
|
-
fontScalePinchThrottleTime: 500,
|
|
413
|
-
fontScaleMaxScale: 5,
|
|
414
|
-
fontScaleMinScale: 0.2,
|
|
415
|
-
zoomMaxScale: Infinity,
|
|
416
|
-
ignore: []
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
const styles = '[data-prose-reader-container="${id}"] * {\n /* Make sure that touche actions are correctly dispatched no matter where the user interact */\n touch-action: inherit;\n}\n';
|
|
421
|
-
const gesturesEnhancer = (next) => (options) => {
|
|
422
|
-
const { gestures = {}, ...rest } = options;
|
|
423
|
-
const reader = next(rest);
|
|
424
|
-
const removeStylesheet = reader.utils.injectScopedCSS(
|
|
425
|
-
document,
|
|
426
|
-
name,
|
|
427
|
-
styles
|
|
428
|
-
);
|
|
429
|
-
const settingsManager = new GesturesSettingsManager(gestures, reader);
|
|
430
|
-
const hookManager = new core.HookManager();
|
|
431
|
-
const pinchRecognizer = new gesturx.PinchRecognizer({
|
|
432
|
-
options: {
|
|
433
|
-
/**
|
|
434
|
-
* @important
|
|
435
|
-
* Ideally we want pinch to triggers before pan so we can
|
|
436
|
-
* capture zoom before starting panning.
|
|
437
|
-
*/
|
|
438
|
-
posThreshold: 10
|
|
439
|
-
}
|
|
440
|
-
});
|
|
441
|
-
const failWithSelection = {
|
|
442
|
-
start$: reader.selection.selectionStart$,
|
|
443
|
-
end$: reader.selection.selectionEnd$
|
|
444
|
-
};
|
|
445
|
-
const panRecognizer = new gesturx.PanRecognizer({
|
|
446
|
-
failWith: [pinchRecognizer, failWithSelection],
|
|
447
|
-
options: {
|
|
448
|
-
// we want to have some margin to trigger zoom
|
|
449
|
-
posThreshold: 20
|
|
450
|
-
}
|
|
451
|
-
});
|
|
452
|
-
const tapRecognizer = new gesturx.TapRecognizer({
|
|
453
|
-
failWith: [panRecognizer]
|
|
454
|
-
});
|
|
455
|
-
const swipeRecognizer = new gesturx.SwipeRecognizer({
|
|
456
|
-
failWith: [failWithSelection]
|
|
457
|
-
});
|
|
458
|
-
const recognizable = new gesturx.Recognizable({
|
|
459
|
-
recognizers: [
|
|
460
|
-
tapRecognizer,
|
|
461
|
-
panRecognizer,
|
|
462
|
-
swipeRecognizer,
|
|
463
|
-
pinchRecognizer
|
|
464
|
-
],
|
|
465
|
-
disableTextSelection: false
|
|
466
|
-
});
|
|
467
|
-
const tapGestures$ = registerTaps({
|
|
468
|
-
hookManager,
|
|
469
|
-
reader,
|
|
470
|
-
recognizable,
|
|
471
|
-
settingsManager,
|
|
472
|
-
recognizer: tapRecognizer
|
|
473
|
-
});
|
|
474
|
-
const panGestures$ = registerPan({
|
|
475
|
-
reader,
|
|
476
|
-
recognizer: panRecognizer,
|
|
477
|
-
settingsManager
|
|
478
|
-
});
|
|
479
|
-
const swipeGestures$ = registerSwipe({
|
|
480
|
-
reader,
|
|
481
|
-
recognizable,
|
|
482
|
-
settingsManager
|
|
483
|
-
});
|
|
484
|
-
const pinchGestures$ = registerPinch({
|
|
485
|
-
reader,
|
|
486
|
-
recognizable,
|
|
487
|
-
settingsManager
|
|
488
|
-
});
|
|
489
|
-
const containerUpdate$ = reader.context.watch(`rootElement`).pipe(
|
|
490
|
-
rxjs.tap((container) => {
|
|
491
|
-
recognizable.update({
|
|
492
|
-
container
|
|
493
|
-
});
|
|
494
|
-
})
|
|
495
|
-
);
|
|
496
|
-
const watchSettings$ = rxjs.combineLatest([
|
|
497
|
-
settingsManager.values$,
|
|
498
|
-
panRecognizer.config$
|
|
499
|
-
]).pipe(
|
|
500
|
-
rxjs.tap(([{ pinchCancelPan }, panRecognizerConfig]) => {
|
|
501
|
-
const pinchAlreadyInFailWith = panRecognizerConfig.failWith?.includes(pinchRecognizer);
|
|
502
|
-
if (pinchCancelPan && !pinchAlreadyInFailWith) {
|
|
503
|
-
panRecognizer.update({
|
|
504
|
-
failWith: [
|
|
505
|
-
...panRecognizerConfig.failWith ?? [],
|
|
506
|
-
pinchRecognizer
|
|
507
|
-
]
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
if (!pinchCancelPan && pinchAlreadyInFailWith) {
|
|
511
|
-
panRecognizer.update({
|
|
512
|
-
failWith: panRecognizerConfig.failWith?.filter(
|
|
513
|
-
(recognizer) => recognizer !== pinchRecognizer
|
|
514
|
-
)
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
})
|
|
518
|
-
);
|
|
519
|
-
const gestures$ = rxjs.merge(
|
|
520
|
-
pinchGestures$,
|
|
521
|
-
tapGestures$,
|
|
522
|
-
swipeGestures$,
|
|
523
|
-
panGestures$
|
|
524
|
-
).pipe(rxjs.share());
|
|
525
|
-
rxjs.merge(containerUpdate$, watchSettings$, gestures$).pipe(rxjs.takeUntil(reader.$.destroy$)).subscribe();
|
|
526
|
-
return {
|
|
527
|
-
...reader,
|
|
528
|
-
destroy: () => {
|
|
529
|
-
removeStylesheet();
|
|
530
|
-
reader.destroy();
|
|
531
|
-
settingsManager.destroy();
|
|
532
|
-
},
|
|
533
|
-
gestures: {
|
|
534
|
-
settings: settingsManager,
|
|
535
|
-
gestures$,
|
|
536
|
-
hooks: hookManager
|
|
537
|
-
}
|
|
538
|
-
};
|
|
539
|
-
};
|
|
540
|
-
exports2.gesturesEnhancer = gesturesEnhancer;
|
|
541
|
-
exports2.isPositionInArea = isPositionInArea;
|
|
542
|
-
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
|
|
543
|
-
}));
|
|
544
|
-
//# sourceMappingURL=index.umd.cjs.map
|
|
2
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@prose-reader/core"), require("gesturx"), require("rxjs")) : typeof define === "function" && define.amd ? define([
|
|
3
|
+
"exports",
|
|
4
|
+
"@prose-reader/core",
|
|
5
|
+
"gesturx",
|
|
6
|
+
"rxjs"
|
|
7
|
+
], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["prose-reader-enhancer-gestures"] = {}, global._prose_reader_core, global.gesturx, global.rxjs));
|
|
8
|
+
})(this, function(exports, _prose_reader_core, gesturx, rxjs) {
|
|
9
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
10
|
+
//#region package.json
|
|
11
|
+
var name = "@prose-reader/enhancer-gestures";
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/gestures/pan.ts
|
|
14
|
+
var registerPan = ({ reader, recognizer, settingsManager }) => {
|
|
15
|
+
return settingsManager.values$.pipe((0, rxjs.switchMap)(({ panNavigation }) => {
|
|
16
|
+
const panStart$ = recognizer.events$.pipe((0, rxjs.filter)((event) => event.type === `panStart`));
|
|
17
|
+
const panMove$ = recognizer.events$.pipe((0, rxjs.filter)((event) => event.type === `panMove`));
|
|
18
|
+
const panEnd$ = recognizer.events$.pipe((0, rxjs.filter)((event) => event.type === `panEnd`));
|
|
19
|
+
return panStart$.pipe((0, rxjs.switchMap)((panStartEvent) => {
|
|
20
|
+
/**
|
|
21
|
+
* We use the last cumulative delta to derive the new event atomic delta.
|
|
22
|
+
* This is because panning the zoom does not necessarily means the zoom position
|
|
23
|
+
* will always changes. If the user keep dragging while the zoom is blocked, we want
|
|
24
|
+
* it to move the other direction when he start dragging the other way.
|
|
25
|
+
* We cannot use the `reader.zoom.state.currentPosition` as previous position
|
|
26
|
+
* and the event.deltaX to compute the new zoom position.
|
|
27
|
+
*/
|
|
28
|
+
let lastDelta = {
|
|
29
|
+
x: 0,
|
|
30
|
+
y: 0
|
|
31
|
+
};
|
|
32
|
+
const moveAndEnd$ = (0, rxjs.merge)(panMove$, panEnd$).pipe((0, rxjs.tap)((event) => {
|
|
33
|
+
const isZooming = reader.zoom.state.isZooming;
|
|
34
|
+
const isZoomingIn = reader.zoom.state.currentScale > 1;
|
|
35
|
+
/**
|
|
36
|
+
* When user is zooming in, we don't navigate anymore.
|
|
37
|
+
* We still allow the pan gesture to move the zoomed controlled
|
|
38
|
+
* viewport even when pan navigation itself is disabled.
|
|
39
|
+
*/
|
|
40
|
+
if (isZooming && isZoomingIn) {
|
|
41
|
+
const deltaX = event.deltaX - lastDelta.x;
|
|
42
|
+
const deltaY = event.deltaY - lastDelta.y;
|
|
43
|
+
lastDelta = {
|
|
44
|
+
x: event.deltaX,
|
|
45
|
+
y: event.deltaY
|
|
46
|
+
};
|
|
47
|
+
reader.zoom.move({
|
|
48
|
+
x: reader.zoom.state.currentPosition.x + deltaX,
|
|
49
|
+
y: reader.zoom.state.currentPosition.y + deltaY
|
|
50
|
+
}, { constrain: "within-viewport" });
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (panNavigation !== "pan") return;
|
|
54
|
+
if (event.type === `panMove`) {
|
|
55
|
+
if (!reader.navigation.panNavigator.value.isStarted) {
|
|
56
|
+
reader.navigation.panNavigator.start({
|
|
57
|
+
x: event.deltaX,
|
|
58
|
+
y: event.deltaY
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
reader.navigation.panNavigator.panMoveTo({
|
|
63
|
+
x: event.deltaX,
|
|
64
|
+
y: event.deltaY
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (event.type === `panEnd` && reader.navigation.panNavigator.value.isStarted) reader.navigation.panNavigator.stop({
|
|
69
|
+
x: event.deltaX,
|
|
70
|
+
y: event.deltaY
|
|
71
|
+
});
|
|
72
|
+
}));
|
|
73
|
+
return (0, rxjs.merge)((0, rxjs.of)(panStartEvent), moveAndEnd$).pipe((0, rxjs.map)((event) => ({
|
|
74
|
+
type: "pan",
|
|
75
|
+
gestureEvent: event
|
|
76
|
+
})));
|
|
77
|
+
}));
|
|
78
|
+
}));
|
|
79
|
+
};
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/gestures/pinch.ts
|
|
82
|
+
var isHtmlImageElement = (target) => (0, _prose_reader_core.isHtmlElement)(target) && !!target.ownerDocument.defaultView && target instanceof target.ownerDocument.defaultView.HTMLImageElement;
|
|
83
|
+
var registerPinch = ({ reader, recognizable, settingsManager }) => {
|
|
84
|
+
const pinchStart$ = recognizable.events$.pipe((0, rxjs.map)(({ event }) => event), (0, rxjs.filter)((event) => event.type === "pinchStart"));
|
|
85
|
+
const pinchMove$ = recognizable.events$.pipe((0, rxjs.map)(({ event }) => event), (0, rxjs.filter)((event) => event.type === "pinchMove"));
|
|
86
|
+
const pinchEnd$ = recognizable.events$.pipe((0, rxjs.map)(({ event }) => event), (0, rxjs.filter)((event) => event.type === "pinchEnd"));
|
|
87
|
+
const shouldStartZoom = (target) => isHtmlImageElement(target) && !reader.zoom.state.isZooming;
|
|
88
|
+
return settingsManager.values$.pipe((0, rxjs.switchMap)(({ fontScalePinchEnabled, fontScalePinchThrottleTime }) => {
|
|
89
|
+
return (0, rxjs.merge)(pinchStart$.pipe((0, rxjs.switchMap)(() => {
|
|
90
|
+
const startScale = reader.zoom.state.currentScale;
|
|
91
|
+
return pinchMove$.pipe((0, rxjs.withLatestFrom)(reader.viewportState$), (0, rxjs.map)(([event, viewportState]) => {
|
|
92
|
+
const newScale = startScale * event.scale;
|
|
93
|
+
/**
|
|
94
|
+
* @important
|
|
95
|
+
* We don't want to trigger zoom gestures if there is a pan navigation
|
|
96
|
+
* in progress. This can happens if the user start panning and then adds
|
|
97
|
+
* another finger triggering a pinch.
|
|
98
|
+
*/
|
|
99
|
+
if (viewportState === "busy") return event;
|
|
100
|
+
if (!reader.zoom.state.isZooming && event.scale > 1) {
|
|
101
|
+
reader.zoom.enter({
|
|
102
|
+
animate: false,
|
|
103
|
+
scale: newScale
|
|
104
|
+
});
|
|
105
|
+
return event;
|
|
106
|
+
}
|
|
107
|
+
if (reader.zoom.state.isZooming) {
|
|
108
|
+
if (newScale < 1) reader.zoom.exit();
|
|
109
|
+
else reader.zoom.scaleAt(Math.min(newScale, settingsManager.values.zoomMaxScale), { constrain: "within-viewport" });
|
|
110
|
+
return event;
|
|
111
|
+
}
|
|
112
|
+
return event;
|
|
113
|
+
}));
|
|
114
|
+
})), !fontScalePinchEnabled ? rxjs.EMPTY : pinchStart$.pipe((0, rxjs.withLatestFrom)(reader.viewportState$), (0, rxjs.switchMap)(([pinchStartEvent, viewportState]) => {
|
|
115
|
+
if (viewportState === "busy" || shouldStartZoom(pinchStartEvent.event.target) || reader.zoom.state.isZooming) return rxjs.EMPTY;
|
|
116
|
+
const lastFontScaleOnPinchStart = reader.settings.values.fontScale;
|
|
117
|
+
return pinchMove$.pipe((0, rxjs.throttleTime)(fontScalePinchThrottleTime, rxjs.animationFrameScheduler, { trailing: true }), (0, rxjs.tap)((event) => {
|
|
118
|
+
const newScale = Number.parseFloat((lastFontScaleOnPinchStart + (event.scale - 1)).toFixed(2));
|
|
119
|
+
const newMinMaxedFontScale = Math.max(Math.min(newScale, settingsManager.values.fontScaleMaxScale), settingsManager.values.fontScaleMinScale);
|
|
120
|
+
reader.settings.update({ fontScale: newMinMaxedFontScale });
|
|
121
|
+
}), (0, rxjs.takeUntil)(pinchEnd$));
|
|
122
|
+
}))).pipe((0, rxjs.map)((event) => ({
|
|
123
|
+
type: "pinch",
|
|
124
|
+
gestureEvent: event
|
|
125
|
+
})));
|
|
126
|
+
}));
|
|
127
|
+
};
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region src/gestures/swipe.ts
|
|
130
|
+
var isSwipeEvent = (event) => event.type === "swipe";
|
|
131
|
+
var registerSwipe = ({ reader, recognizable, settingsManager }) => {
|
|
132
|
+
return settingsManager.values$.pipe((0, rxjs.switchMap)(({ panNavigation }) => panNavigation !== "swipe" ? rxjs.EMPTY : recognizable.events$.pipe((0, rxjs.map)(({ event }) => event), (0, rxjs.filter)(isSwipeEvent), (0, rxjs.tap)((event) => {
|
|
133
|
+
const { computedPageTurnDirection } = reader.settings.values;
|
|
134
|
+
if (computedPageTurnDirection === "vertical") {
|
|
135
|
+
if (event.velocityY < -.5) reader?.navigation.turnRight();
|
|
136
|
+
if (event.velocityY > .5) reader?.navigation.turnLeft();
|
|
137
|
+
} else {
|
|
138
|
+
if (event.velocityX < -.5) reader?.navigation.turnRight();
|
|
139
|
+
if (event.velocityX > .5) reader?.navigation.turnLeft();
|
|
140
|
+
}
|
|
141
|
+
}), (0, rxjs.map)((event) => ({
|
|
142
|
+
type: "swipe",
|
|
143
|
+
gestureEvent: event
|
|
144
|
+
})))));
|
|
145
|
+
};
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region src/utils.ts
|
|
148
|
+
var isNotLink = (event) => {
|
|
149
|
+
const target = event.event.target;
|
|
150
|
+
if ((0, _prose_reader_core.isHtmlElement)(target) && target.tagName === "a") return false;
|
|
151
|
+
return true;
|
|
152
|
+
};
|
|
153
|
+
var getPositionRelativeToContainer = (event, containerElementRect) => {
|
|
154
|
+
const { x, y } = event;
|
|
155
|
+
const { left, top } = containerElementRect;
|
|
156
|
+
return {
|
|
157
|
+
x: x - left,
|
|
158
|
+
y: y - top
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
var istMatchingSelectors = (selectors, event) => {
|
|
162
|
+
const target = event.event.target;
|
|
163
|
+
if (!(0, _prose_reader_core.isHtmlElement)(target)) return false;
|
|
164
|
+
return !!selectors.find((selector) => {
|
|
165
|
+
if (target.matches(selector)) return true;
|
|
166
|
+
if (target.closest(selector)) return true;
|
|
167
|
+
return false;
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region src/gestures/taps/utils.ts
|
|
172
|
+
var isPositionInArea = (position, area, containerSize) => {
|
|
173
|
+
const { x, y } = position;
|
|
174
|
+
const { width, height } = containerSize;
|
|
175
|
+
switch (area.type) {
|
|
176
|
+
case "margins": {
|
|
177
|
+
const { top, bottom, left, right } = area;
|
|
178
|
+
const inTop = top !== void 0 ? y < height * top : true;
|
|
179
|
+
const inBottom = bottom !== void 0 ? y > height * (1 - bottom) : true;
|
|
180
|
+
const inLeft = left !== void 0 ? x < width * left : true;
|
|
181
|
+
const inRight = right !== void 0 ? x > width * (1 - right) : true;
|
|
182
|
+
return top !== void 0 && inTop || bottom !== void 0 && inBottom || left !== void 0 && inLeft || right !== void 0 && inRight;
|
|
183
|
+
}
|
|
184
|
+
case "rectangle": {
|
|
185
|
+
const { x: rectX, y: rectY, width: rectWidth, height: rectHeight, unit = "%" } = area;
|
|
186
|
+
const actualX = unit === "%" ? width * (rectX / 100) : rectX;
|
|
187
|
+
const actualY = unit === "%" ? height * (rectY / 100) : rectY;
|
|
188
|
+
const actualWidth = unit === "%" ? width * (rectWidth / 100) : rectWidth;
|
|
189
|
+
const actualHeight = unit === "%" ? height * (rectHeight / 100) : rectHeight;
|
|
190
|
+
return x >= actualX && x <= actualX + actualWidth && y >= actualY && y <= actualY + actualHeight;
|
|
191
|
+
}
|
|
192
|
+
case "corner": {
|
|
193
|
+
const { corner, size, unit = "%" } = area;
|
|
194
|
+
const actualSize = unit === "%" ? Math.min(width, height) * (size / 100) : size;
|
|
195
|
+
switch (corner) {
|
|
196
|
+
case "top-left": return x < actualSize && y < actualSize;
|
|
197
|
+
case "top-right": return x > width - actualSize && y < actualSize;
|
|
198
|
+
case "bottom-left": return x < actualSize && y > height - actualSize;
|
|
199
|
+
case "bottom-right": return x > width - actualSize && y > height - actualSize;
|
|
200
|
+
default: return false;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
case "center": {
|
|
204
|
+
const { width: centerWidth, height: centerHeight, unit = "%" } = area;
|
|
205
|
+
const actualWidth = unit === "%" ? width * (centerWidth / 100) : centerWidth;
|
|
206
|
+
const actualHeight = unit === "%" ? height * (centerHeight / 100) : centerHeight;
|
|
207
|
+
const centerX = width / 2;
|
|
208
|
+
const centerY = height / 2;
|
|
209
|
+
return x >= centerX - actualWidth / 2 && x <= centerX + actualWidth / 2 && y >= centerY - actualHeight / 2 && y <= centerY + actualHeight / 2;
|
|
210
|
+
}
|
|
211
|
+
default: return false;
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
var calculatePageTurnLinearMargin = (screenWidth) => {
|
|
215
|
+
const minMargin = .15;
|
|
216
|
+
const maxMargin = .2;
|
|
217
|
+
const minWidth = 320;
|
|
218
|
+
const maxWidth = 1200;
|
|
219
|
+
if (screenWidth <= minWidth) return maxMargin;
|
|
220
|
+
if (screenWidth >= maxWidth) return minMargin;
|
|
221
|
+
return maxMargin - (screenWidth - minWidth) / (maxWidth - minWidth) * (maxMargin - minMargin);
|
|
222
|
+
};
|
|
223
|
+
//#endregion
|
|
224
|
+
//#region src/gestures/taps/registerTaps.ts
|
|
225
|
+
var registerTaps = ({ reader, recognizable, hookManager, settingsManager, recognizer }) => {
|
|
226
|
+
return recognizable.events$.pipe((0, rxjs.filter)((event) => event.recognizer === recognizer), (0, rxjs.withLatestFrom)(reader.context.watch(`rootElement`), reader.spine.element$), (0, rxjs.switchMap)(([{ event }, containerElement, spineElement]) => {
|
|
227
|
+
if (!containerElement || !spineElement) return rxjs.EMPTY;
|
|
228
|
+
const normalizedEvent = event.event;
|
|
229
|
+
const { computedPageTurnDirection, computedPageTurnMode } = reader.settings.values;
|
|
230
|
+
if (event.type === "tap" && isNotLink(event) && !istMatchingSelectors(settingsManager.values.ignore, event)) {
|
|
231
|
+
if (`x` in normalizedEvent) {
|
|
232
|
+
const containerElementRect = containerElement.getBoundingClientRect();
|
|
233
|
+
const width = containerElementRect.width;
|
|
234
|
+
const pageTurnMargin = calculatePageTurnLinearMargin(width);
|
|
235
|
+
const positionInContainer = getPositionRelativeToContainer(normalizedEvent, containerElementRect);
|
|
236
|
+
const positionInSpineNonTransformed = reader.coordinates.getSpinePositionFromClientPosition(normalizedEvent);
|
|
237
|
+
const spineItemPageInfo = positionInSpineNonTransformed ? reader.spine.locator.getSpineItemPagePositionFromSpinePosition(positionInSpineNonTransformed) : void 0;
|
|
238
|
+
return (0, rxjs.combineLatest)([...hookManager.execute("beforeTapGesture", { event$: (0, rxjs.of)({
|
|
239
|
+
event,
|
|
240
|
+
page: spineItemPageInfo
|
|
241
|
+
}) }), (0, rxjs.of)(true)]).pipe((0, rxjs.first)(), (0, rxjs.filter)((results) => !results.some((result) => result === false)), (0, rxjs.map)(() => {
|
|
242
|
+
const isZoomedIn = reader.zoom.state.isZooming && reader.zoom.state.currentScale > 1;
|
|
243
|
+
if (computedPageTurnMode === "scrollable" || isZoomedIn) return {
|
|
244
|
+
type: "tap",
|
|
245
|
+
gestureEvent: event,
|
|
246
|
+
handled: false
|
|
247
|
+
};
|
|
248
|
+
if (computedPageTurnDirection === "horizontal" && isPositionInArea(positionInContainer, {
|
|
249
|
+
type: "margins",
|
|
250
|
+
left: pageTurnMargin
|
|
251
|
+
}, containerElementRect)) reader.navigation.turnLeftOrTop();
|
|
252
|
+
else if (computedPageTurnDirection === "vertical" && isPositionInArea(positionInContainer, {
|
|
253
|
+
type: "margins",
|
|
254
|
+
top: pageTurnMargin
|
|
255
|
+
}, containerElementRect)) reader.navigation.turnLeftOrTop();
|
|
256
|
+
else if (computedPageTurnDirection === "vertical" && isPositionInArea(positionInContainer, {
|
|
257
|
+
type: "margins",
|
|
258
|
+
bottom: pageTurnMargin
|
|
259
|
+
}, containerElementRect)) reader.navigation.turnRightOrBottom();
|
|
260
|
+
else if (computedPageTurnDirection === "horizontal" && isPositionInArea(positionInContainer, {
|
|
261
|
+
type: "margins",
|
|
262
|
+
right: pageTurnMargin
|
|
263
|
+
}, containerElementRect)) reader.navigation.turnRightOrBottom();
|
|
264
|
+
else return {
|
|
265
|
+
type: "tap",
|
|
266
|
+
gestureEvent: event,
|
|
267
|
+
handled: false
|
|
268
|
+
};
|
|
269
|
+
return {
|
|
270
|
+
type: "tap",
|
|
271
|
+
gestureEvent: event,
|
|
272
|
+
handled: true
|
|
273
|
+
};
|
|
274
|
+
}));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return rxjs.EMPTY;
|
|
278
|
+
}));
|
|
279
|
+
};
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region src/SettingsManager.ts
|
|
282
|
+
var GesturesSettingsManager = class extends _prose_reader_core.SettingsManager {
|
|
283
|
+
reader;
|
|
284
|
+
constructor(initialSettings, reader) {
|
|
285
|
+
super(initialSettings);
|
|
286
|
+
this.reader = reader;
|
|
287
|
+
/**
|
|
288
|
+
* Since we have settings that may be locked due to some reader settings
|
|
289
|
+
* we need to update as soon as they update as well.
|
|
290
|
+
*/
|
|
291
|
+
reader.settings.values$.pipe((0, rxjs.tap)(() => {
|
|
292
|
+
this.update({});
|
|
293
|
+
}), (0, rxjs.takeUntil)(this.destroy$)).subscribe();
|
|
294
|
+
}
|
|
295
|
+
getOutputSettings(inputSettings) {
|
|
296
|
+
return {
|
|
297
|
+
...inputSettings,
|
|
298
|
+
panNavigation: this.reader.settings.values.computedPageTurnMode === `scrollable` ? false : inputSettings.panNavigation
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
getDefaultSettings() {
|
|
302
|
+
return {
|
|
303
|
+
panNavigation: "pan",
|
|
304
|
+
pinchCancelPan: true,
|
|
305
|
+
fontScalePinchEnabled: true,
|
|
306
|
+
fontScalePinchThrottleTime: 500,
|
|
307
|
+
fontScaleMaxScale: 5,
|
|
308
|
+
fontScaleMinScale: .2,
|
|
309
|
+
zoomMaxScale: Infinity,
|
|
310
|
+
ignore: []
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region src/style.css?inline
|
|
316
|
+
var style_default = "[data-prose-reader-container=\"${id}\"] * {\n /* Make sure that touche actions are correctly dispatched no matter where the user interact */\n touch-action: inherit;\n}\n";
|
|
317
|
+
//#endregion
|
|
318
|
+
//#region src/index.ts
|
|
319
|
+
var gesturesEnhancer = (next) => (options) => {
|
|
320
|
+
const { gestures = {}, ...rest } = options;
|
|
321
|
+
const reader = next(rest);
|
|
322
|
+
const removeStylesheet = reader.utils.injectScopedCSS(document, name, style_default);
|
|
323
|
+
const settingsManager = new GesturesSettingsManager(gestures, reader);
|
|
324
|
+
const hookManager = new _prose_reader_core.HookManager();
|
|
325
|
+
const pinchRecognizer = new gesturx.PinchRecognizer({ options: {
|
|
326
|
+
/**
|
|
327
|
+
* @important
|
|
328
|
+
* Ideally we want pinch to triggers before pan so we can
|
|
329
|
+
* capture zoom before starting panning.
|
|
330
|
+
*/
|
|
331
|
+
posThreshold: 10 } });
|
|
332
|
+
const failWithSelection = {
|
|
333
|
+
start$: reader.selection.selectionStart$,
|
|
334
|
+
end$: reader.selection.selectionEnd$
|
|
335
|
+
};
|
|
336
|
+
const panRecognizer = new gesturx.PanRecognizer({
|
|
337
|
+
failWith: [pinchRecognizer, failWithSelection],
|
|
338
|
+
options: { posThreshold: 20 }
|
|
339
|
+
});
|
|
340
|
+
const tapRecognizer = new gesturx.TapRecognizer({ failWith: [panRecognizer] });
|
|
341
|
+
const recognizable = new gesturx.Recognizable({
|
|
342
|
+
recognizers: [
|
|
343
|
+
tapRecognizer,
|
|
344
|
+
panRecognizer,
|
|
345
|
+
new gesturx.SwipeRecognizer({ failWith: [failWithSelection] }),
|
|
346
|
+
pinchRecognizer
|
|
347
|
+
],
|
|
348
|
+
disableTextSelection: false
|
|
349
|
+
});
|
|
350
|
+
const tapGestures$ = registerTaps({
|
|
351
|
+
hookManager,
|
|
352
|
+
reader,
|
|
353
|
+
recognizable,
|
|
354
|
+
settingsManager,
|
|
355
|
+
recognizer: tapRecognizer
|
|
356
|
+
});
|
|
357
|
+
const panGestures$ = registerPan({
|
|
358
|
+
hookManager,
|
|
359
|
+
reader,
|
|
360
|
+
recognizer: panRecognizer,
|
|
361
|
+
settingsManager
|
|
362
|
+
});
|
|
363
|
+
const swipeGestures$ = registerSwipe({
|
|
364
|
+
hookManager,
|
|
365
|
+
reader,
|
|
366
|
+
recognizable,
|
|
367
|
+
settingsManager
|
|
368
|
+
});
|
|
369
|
+
const pinchGestures$ = registerPinch({
|
|
370
|
+
hookManager,
|
|
371
|
+
reader,
|
|
372
|
+
recognizable,
|
|
373
|
+
settingsManager
|
|
374
|
+
});
|
|
375
|
+
const containerUpdate$ = reader.context.watch(`rootElement`).pipe((0, rxjs.tap)((container) => {
|
|
376
|
+
recognizable.update({ container });
|
|
377
|
+
}));
|
|
378
|
+
const watchSettings$ = (0, rxjs.combineLatest)([settingsManager.values$, panRecognizer.config$]).pipe((0, rxjs.tap)(([{ pinchCancelPan }, panRecognizerConfig]) => {
|
|
379
|
+
const pinchAlreadyInFailWith = panRecognizerConfig.failWith?.includes(pinchRecognizer);
|
|
380
|
+
if (pinchCancelPan && !pinchAlreadyInFailWith) panRecognizer.update({ failWith: [...panRecognizerConfig.failWith ?? [], pinchRecognizer] });
|
|
381
|
+
if (!pinchCancelPan && pinchAlreadyInFailWith) panRecognizer.update({ failWith: panRecognizerConfig.failWith?.filter((recognizer) => recognizer !== pinchRecognizer) });
|
|
382
|
+
}));
|
|
383
|
+
const gestures$ = (0, rxjs.merge)(pinchGestures$, tapGestures$, swipeGestures$, panGestures$).pipe((0, rxjs.share)());
|
|
384
|
+
(0, rxjs.merge)(containerUpdate$, watchSettings$, gestures$).pipe((0, rxjs.takeUntil)(reader.$.destroy$)).subscribe();
|
|
385
|
+
return {
|
|
386
|
+
...reader,
|
|
387
|
+
destroy: () => {
|
|
388
|
+
removeStylesheet();
|
|
389
|
+
reader.destroy();
|
|
390
|
+
settingsManager.destroy();
|
|
391
|
+
},
|
|
392
|
+
gestures: {
|
|
393
|
+
settings: settingsManager,
|
|
394
|
+
gestures$,
|
|
395
|
+
hooks: hookManager
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
};
|
|
399
|
+
//#endregion
|
|
400
|
+
exports.gesturesEnhancer = gesturesEnhancer;
|
|
401
|
+
exports.isPositionInArea = isPositionInArea;
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
//# sourceMappingURL=index.umd.cjs.map
|