@rafaelaugusto/jolt 0.1.0-beta.5 → 0.1.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -5
- package/dist/animate.d.ts +4 -2
- package/dist/animate.d.ts.map +1 -1
- package/dist/animate.js +48 -11
- package/dist/animate.js.map +1 -1
- package/dist/config.d.ts +22 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +34 -0
- package/dist/config.js.map +1 -0
- package/dist/driver/android.d.ts.map +1 -1
- package/dist/driver/android.js +7 -0
- package/dist/driver/android.js.map +1 -1
- package/dist/driver/index.d.ts +2 -0
- package/dist/driver/index.d.ts.map +1 -1
- package/dist/driver/index.js.map +1 -1
- package/dist/driver/ios-color.js +1 -1
- package/dist/driver/ios-color.js.map +1 -1
- package/dist/driver/ios-decoration.js +1 -1
- package/dist/driver/ios-decoration.js.map +1 -1
- package/dist/driver/ios-playback.d.ts +1 -1
- package/dist/driver/ios-playback.d.ts.map +1 -1
- package/dist/driver/ios-playback.js +14 -0
- package/dist/driver/ios-playback.js.map +1 -1
- package/dist/driver/ios.d.ts.map +1 -1
- package/dist/driver/ios.js +1 -0
- package/dist/driver/ios.js.map +1 -1
- package/dist/engine.d.ts +16 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +33 -1
- package/dist/engine.js.map +1 -1
- package/dist/image-effect-native.d.ts +26 -0
- package/dist/image-effect-native.d.ts.map +1 -0
- package/dist/image-effect-native.js +73 -0
- package/dist/image-effect-native.js.map +1 -0
- package/dist/image-effect.d.ts +50 -0
- package/dist/image-effect.d.ts.map +1 -0
- package/dist/image-effect.js +290 -0
- package/dist/image-effect.js.map +1 -0
- package/dist/image-owner.d.ts +3 -0
- package/dist/image-owner.d.ts.map +1 -0
- package/dist/image-owner.js +11 -0
- package/dist/image-owner.js.map +1 -0
- package/dist/index.d.ts +15 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/items.d.ts +20 -0
- package/dist/items.d.ts.map +1 -0
- package/dist/items.js +109 -0
- package/dist/items.js.map +1 -0
- package/dist/keyboard.d.ts +17 -0
- package/dist/keyboard.d.ts.map +1 -0
- package/dist/keyboard.js +116 -0
- package/dist/keyboard.js.map +1 -0
- package/dist/label.d.ts +7 -0
- package/dist/label.d.ts.map +1 -0
- package/dist/label.js +60 -0
- package/dist/label.js.map +1 -0
- package/dist/liquid.d.ts.map +1 -1
- package/dist/liquid.js +6 -1
- package/dist/liquid.js.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +2 -1
- package/dist/loader.js.map +1 -1
- package/dist/particles.d.ts.map +1 -1
- package/dist/particles.js +4 -3
- package/dist/particles.js.map +1 -1
- package/dist/path.d.ts +12 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +90 -0
- package/dist/path.js.map +1 -0
- package/dist/playback-group.d.ts.map +1 -1
- package/dist/playback-group.js +29 -1
- package/dist/playback-group.js.map +1 -1
- package/dist/press.d.ts.map +1 -1
- package/dist/press.js +3 -3
- package/dist/press.js.map +1 -1
- package/dist/reveal.d.ts.map +1 -1
- package/dist/reveal.js +3 -2
- package/dist/reveal.js.map +1 -1
- package/dist/roll-diff.d.ts +22 -0
- package/dist/roll-diff.d.ts.map +1 -0
- package/dist/roll-diff.js +36 -0
- package/dist/roll-diff.js.map +1 -0
- package/dist/roll.d.ts +29 -0
- package/dist/roll.d.ts.map +1 -0
- package/dist/roll.js +442 -0
- package/dist/roll.js.map +1 -0
- package/dist/scroll-linked.d.ts +10 -0
- package/dist/scroll-linked.d.ts.map +1 -0
- package/dist/scroll-linked.js +58 -0
- package/dist/scroll-linked.js.map +1 -0
- package/dist/sequence.d.ts +10 -5
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +202 -14
- package/dist/sequence.js.map +1 -1
- package/dist/shimmer.d.ts.map +1 -1
- package/dist/shimmer.js +2 -1
- package/dist/shimmer.js.map +1 -1
- package/dist/svg-path.d.ts +14 -0
- package/dist/svg-path.d.ts.map +1 -0
- package/dist/svg-path.js +281 -0
- package/dist/svg-path.js.map +1 -0
- package/dist/symbol-effect.d.ts.map +1 -1
- package/dist/symbol-effect.js +4 -3
- package/dist/symbol-effect.js.map +1 -1
- package/dist/text-layout.d.ts +8 -0
- package/dist/text-layout.d.ts.map +1 -1
- package/dist/text-layout.js +8 -2
- package/dist/text-layout.js.map +1 -1
- package/dist/text.d.ts +1 -1
- package/dist/text.d.ts.map +1 -1
- package/dist/text.js +60 -64
- package/dist/text.js.map +1 -1
- package/dist/track.d.ts +2 -0
- package/dist/track.d.ts.map +1 -1
- package/dist/track.js +62 -15
- package/dist/track.js.map +1 -1
- package/dist/types.d.ts +7 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/vue/index.d.ts +89 -0
- package/dist/vue/index.d.ts.map +1 -0
- package/dist/vue/index.js +134 -0
- package/dist/vue/index.js.map +1 -0
- package/dist/zoom-native.d.ts +30 -0
- package/dist/zoom-native.d.ts.map +1 -0
- package/dist/zoom-native.js +56 -0
- package/dist/zoom-native.js.map +1 -0
- package/dist/zoomable.d.ts +48 -0
- package/dist/zoomable.d.ts.map +1 -0
- package/dist/zoomable.js +249 -0
- package/dist/zoomable.js.map +1 -0
- package/package.json +16 -3
- package/platforms/android/java/org/rafaelaugusto/jolt/ImageEffect.java +288 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/KeyboardFollower.java +91 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/NumberRoll.java +190 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/PhotoZoom.java +250 -0
- package/platforms/android/java/org/rafaelaugusto/jolt/TextReveal.java +180 -0
- package/platforms/android/proguard-rules.pro +10 -0
- package/platforms/ios/build.xcconfig +1 -0
- package/platforms/ios/src/JoltImageEffect.h +25 -0
- package/platforms/ios/src/JoltImageEffect.mm +242 -0
- package/platforms/ios/src/JoltPhotoZoom.h +23 -0
- package/platforms/ios/src/JoltPhotoZoom.m +229 -0
- package/platforms/ios/src/module.modulemap +5 -0
- package/src/android-plugin.d.ts +142 -0
- package/src/animate.ts +80 -30
- package/src/config.ts +46 -0
- package/src/driver/android.ts +14 -0
- package/src/driver/index.ts +2 -0
- package/src/driver/ios-color.ts +1 -1
- package/src/driver/ios-decoration.ts +1 -1
- package/src/driver/ios-playback.ts +15 -1
- package/src/driver/ios.ts +2 -0
- package/src/engine.ts +47 -2
- package/src/image-effect-native.ts +129 -0
- package/src/image-effect.ts +336 -0
- package/src/image-owner.ts +12 -0
- package/src/index.ts +20 -1
- package/src/ios-plugin.d.ts +59 -0
- package/src/items.ts +140 -0
- package/src/keyboard.ts +132 -0
- package/src/label.ts +76 -0
- package/src/liquid.ts +6 -1
- package/src/loader.ts +2 -1
- package/src/particles.ts +4 -4
- package/src/path.ts +124 -0
- package/src/playback-group.ts +34 -1
- package/src/press.ts +3 -5
- package/src/reveal.ts +3 -3
- package/src/roll-diff.ts +57 -0
- package/src/roll.ts +515 -0
- package/src/scroll-linked.ts +73 -0
- package/src/sequence.ts +199 -14
- package/src/shimmer.ts +2 -1
- package/src/svg-path.ts +355 -0
- package/src/symbol-effect.ts +4 -3
- package/src/text-layout.ts +14 -2
- package/src/text.ts +62 -81
- package/src/track.ts +89 -24
- package/src/types.ts +8 -1
- package/src/vue/index.ts +189 -0
- package/src/zoom-native.ts +124 -0
- package/src/zoomable.ts +330 -0
package/src/zoomable.ts
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { Application, Image, isIOS, type View } from '@nativescript/core'
|
|
2
|
+
import { stop, toView } from './animate.js'
|
|
3
|
+
import { reducedMotion } from './config.js'
|
|
4
|
+
import { ownImage } from './image-owner.js'
|
|
5
|
+
import { createZoomDriver, type ZoomDriver, type ZoomSnapshot } from './zoom-native.js'
|
|
6
|
+
import type { Target } from './types.js'
|
|
7
|
+
|
|
8
|
+
export type ZoomState = Readonly<ZoomSnapshot>
|
|
9
|
+
export interface PhotoDismissal {
|
|
10
|
+
readonly state: ZoomState
|
|
11
|
+
/** Release velocity in viewport-local DIPs per second. */
|
|
12
|
+
readonly velocity: number
|
|
13
|
+
/** Return to the viewer. False means this intent is obsolete. */
|
|
14
|
+
cancel(): boolean
|
|
15
|
+
/** Release the controller. Navigate only when this returns true. */
|
|
16
|
+
complete(): boolean
|
|
17
|
+
}
|
|
18
|
+
export interface ZoomableOptions {
|
|
19
|
+
/** Direct parent of the Image. Its bounds are the clipping/pointer viewport. */
|
|
20
|
+
viewport?: Target
|
|
21
|
+
/** Relative zoom range. Defaults to [1, 5]; minimum must be >= 1. */
|
|
22
|
+
scale?: readonly [number, number]
|
|
23
|
+
/** Double-tap zoom, clamped into the configured range. Defaults to 2.5. */
|
|
24
|
+
doubleTap?: number
|
|
25
|
+
dismiss?: 'vertical' | false
|
|
26
|
+
/** These views follow dismissal natively; no JS progress callback is needed. */
|
|
27
|
+
backdrop?: Target
|
|
28
|
+
chrome?: Target
|
|
29
|
+
/** One terminal intent per drag/programmatic close. App/router owns navigation. */
|
|
30
|
+
onDismiss?: (dismissal: PhotoDismissal) => void
|
|
31
|
+
/** Called at rest, never on each pointer/frame update. */
|
|
32
|
+
onSettled?: (state: ZoomState) => void
|
|
33
|
+
/** Setup failed after loading; resources are disposed before this callback. */
|
|
34
|
+
onError?: (error: Error) => void
|
|
35
|
+
}
|
|
36
|
+
export interface Zoomable {
|
|
37
|
+
readonly ready: boolean
|
|
38
|
+
readonly error: Error | undefined
|
|
39
|
+
readonly state: ZoomState
|
|
40
|
+
/** Native adapter entry point for native navigation integrations. */
|
|
41
|
+
readonly nativeController: object | undefined
|
|
42
|
+
zoomTo(scale: number, focus?: { x: number; y: number }, animated?: boolean): void
|
|
43
|
+
reset(animated?: boolean): void
|
|
44
|
+
requestDismiss(): void
|
|
45
|
+
cancelDismiss(): void
|
|
46
|
+
dispose(): void
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Makes an Image interactive without per-frame JS. Owns its transforms until disposed. */
|
|
50
|
+
export function zoomable(target: Target, options: ZoomableOptions = {}): Zoomable {
|
|
51
|
+
const image = toView(target)
|
|
52
|
+
if (!(image instanceof Image))
|
|
53
|
+
throw new TypeError('zoomable() expects a NativeScript Image.')
|
|
54
|
+
if (!options || typeof options !== 'object')
|
|
55
|
+
throw new TypeError('Zoom options must be an object.')
|
|
56
|
+
const viewport = options.viewport
|
|
57
|
+
? toView(options.viewport)
|
|
58
|
+
: (image.parent as View | undefined)
|
|
59
|
+
if (!viewport)
|
|
60
|
+
throw new TypeError('A zoom viewport is required before the image has a parent.')
|
|
61
|
+
const scale = options.scale ?? [1, 5]
|
|
62
|
+
if (
|
|
63
|
+
!Array.isArray(scale) ||
|
|
64
|
+
scale.length !== 2 ||
|
|
65
|
+
!scale.every(Number.isFinite) ||
|
|
66
|
+
scale[0]! < 1 ||
|
|
67
|
+
scale[1]! < scale[0]!
|
|
68
|
+
)
|
|
69
|
+
throw new RangeError(
|
|
70
|
+
'Zoom scale must be [minimum, maximum], with 1 <= minimum <= maximum.',
|
|
71
|
+
)
|
|
72
|
+
const doubleTap = options.doubleTap ?? 2.5
|
|
73
|
+
if (!Number.isFinite(doubleTap) || doubleTap < 1)
|
|
74
|
+
throw new RangeError('Double-tap zoom must be a finite number >= 1.')
|
|
75
|
+
if (
|
|
76
|
+
options.dismiss !== undefined &&
|
|
77
|
+
options.dismiss !== false &&
|
|
78
|
+
options.dismiss !== 'vertical'
|
|
79
|
+
)
|
|
80
|
+
throw new TypeError("Dismiss must be 'vertical' or false.")
|
|
81
|
+
for (const callback of [options.onDismiss, options.onSettled, options.onError])
|
|
82
|
+
if (callback !== undefined && typeof callback !== 'function')
|
|
83
|
+
throw new TypeError('Zoom callbacks must be functions.')
|
|
84
|
+
const backdrop = options.backdrop ? toView(options.backdrop) : undefined
|
|
85
|
+
const chrome = options.chrome ? toView(options.chrome) : undefined
|
|
86
|
+
if (
|
|
87
|
+
backdrop === image ||
|
|
88
|
+
chrome === image ||
|
|
89
|
+
backdrop === viewport ||
|
|
90
|
+
chrome === viewport
|
|
91
|
+
)
|
|
92
|
+
throw new TypeError(
|
|
93
|
+
'Dismissal backdrop/chrome must be separate from the image and viewport.',
|
|
94
|
+
)
|
|
95
|
+
if (image.parent && image.parent !== viewport)
|
|
96
|
+
throw new TypeError('The zoom viewport must be the image’s direct parent.')
|
|
97
|
+
if (
|
|
98
|
+
image.rotate ||
|
|
99
|
+
image.rotateX ||
|
|
100
|
+
image.rotateY ||
|
|
101
|
+
image.scaleX <= 0 ||
|
|
102
|
+
image.scaleY <= 0
|
|
103
|
+
)
|
|
104
|
+
throw new TypeError(
|
|
105
|
+
'Zoom supports positive axis-aligned image transforms; rotate an ancestor instead.',
|
|
106
|
+
)
|
|
107
|
+
return new Photo(image, viewport, { ...options, doubleTap, scale, backdrop, chrome })
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
class Photo implements Zoomable {
|
|
111
|
+
private failure: Error | undefined
|
|
112
|
+
private suspended = false
|
|
113
|
+
private driver: ZoomDriver | undefined
|
|
114
|
+
private stopped = false
|
|
115
|
+
private queued = false
|
|
116
|
+
private releaseOwnership: () => void = () => {}
|
|
117
|
+
private generation = 0
|
|
118
|
+
private reduceObserver:
|
|
119
|
+
ReturnType<typeof Application.ios.addNotificationObserver> | undefined
|
|
120
|
+
private latest: ZoomSnapshot
|
|
121
|
+
constructor(
|
|
122
|
+
private readonly image: Image,
|
|
123
|
+
private readonly viewport: View,
|
|
124
|
+
private readonly options: Omit<ZoomableOptions, 'backdrop' | 'chrome'> & {
|
|
125
|
+
scale: readonly [number, number]
|
|
126
|
+
doubleTap: number
|
|
127
|
+
backdrop?: View
|
|
128
|
+
chrome?: View
|
|
129
|
+
},
|
|
130
|
+
) {
|
|
131
|
+
this.latest = { x: 0, y: 0, scale: options.scale[0], progress: 0, pending: false }
|
|
132
|
+
this.releaseOwnership = ownImage(image, this.dispose)
|
|
133
|
+
stop(image, ['x', 'y', 'scaleX', 'scaleY'])
|
|
134
|
+
for (const view of [image, viewport]) {
|
|
135
|
+
view.on('loaded', this.schedule)
|
|
136
|
+
view.on('layoutChanged', this.schedule)
|
|
137
|
+
view.on('unloaded', this.dispose)
|
|
138
|
+
}
|
|
139
|
+
image.on('imageSourceChange', this.sourceChanged)
|
|
140
|
+
image.on('stretchChange', this.sourceChanged)
|
|
141
|
+
Application.on(Application.suspendEvent, this.suspend)
|
|
142
|
+
Application.on(Application.resumeEvent, this.resume)
|
|
143
|
+
if (isIOS)
|
|
144
|
+
this.reduceObserver = Application.ios.addNotificationObserver(
|
|
145
|
+
UIAccessibilityReduceMotionStatusDidChangeNotification,
|
|
146
|
+
this.preferences,
|
|
147
|
+
)
|
|
148
|
+
this.schedule()
|
|
149
|
+
}
|
|
150
|
+
get ready() {
|
|
151
|
+
return !!this.driver
|
|
152
|
+
}
|
|
153
|
+
get error() {
|
|
154
|
+
return this.failure
|
|
155
|
+
}
|
|
156
|
+
get state(): ZoomState {
|
|
157
|
+
return { ...(this.driver?.state ?? this.latest) }
|
|
158
|
+
}
|
|
159
|
+
get nativeController() {
|
|
160
|
+
return this.driver?.native
|
|
161
|
+
}
|
|
162
|
+
zoomTo(value: number, focus?: { x: number; y: number }, animated = true) {
|
|
163
|
+
if (
|
|
164
|
+
!Number.isFinite(value) ||
|
|
165
|
+
value < this.options.scale[0] ||
|
|
166
|
+
value > this.options.scale[1]
|
|
167
|
+
)
|
|
168
|
+
throw new RangeError('Zoom must be within the configured scale range.')
|
|
169
|
+
if (focus && (!Number.isFinite(focus.x) || !Number.isFinite(focus.y)))
|
|
170
|
+
throw new RangeError('Zoom focus must be finite.')
|
|
171
|
+
if (this.stopped) return
|
|
172
|
+
const size = this.viewport.getActualSize()
|
|
173
|
+
this.driver?.zoom(
|
|
174
|
+
value,
|
|
175
|
+
focus?.x ?? size.width / 2,
|
|
176
|
+
focus?.y ?? size.height / 2,
|
|
177
|
+
animated,
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
reset(animated = true) {
|
|
181
|
+
this.generation++
|
|
182
|
+
this.driver?.reset(animated)
|
|
183
|
+
}
|
|
184
|
+
requestDismiss() {
|
|
185
|
+
this.driver?.requestDismiss()
|
|
186
|
+
}
|
|
187
|
+
cancelDismiss() {
|
|
188
|
+
this.reset(true)
|
|
189
|
+
}
|
|
190
|
+
dispose = () => {
|
|
191
|
+
if (this.stopped) return
|
|
192
|
+
this.stopped = true
|
|
193
|
+
this.generation++
|
|
194
|
+
this.latest = {
|
|
195
|
+
x: 0,
|
|
196
|
+
y: 0,
|
|
197
|
+
scale: this.options.scale[0],
|
|
198
|
+
progress: 0,
|
|
199
|
+
pending: false,
|
|
200
|
+
}
|
|
201
|
+
this.driver?.stop()
|
|
202
|
+
this.driver = undefined
|
|
203
|
+
this.releaseOwnership()
|
|
204
|
+
for (const view of [this.image, this.viewport]) {
|
|
205
|
+
view.off('loaded', this.schedule)
|
|
206
|
+
view.off('layoutChanged', this.schedule)
|
|
207
|
+
view.off('unloaded', this.dispose)
|
|
208
|
+
}
|
|
209
|
+
this.image.off('imageSourceChange', this.sourceChanged)
|
|
210
|
+
this.image.off('stretchChange', this.sourceChanged)
|
|
211
|
+
Application.off(Application.suspendEvent, this.suspend)
|
|
212
|
+
Application.off(Application.resumeEvent, this.resume)
|
|
213
|
+
if (this.reduceObserver)
|
|
214
|
+
Application.ios.removeNotificationObserver(
|
|
215
|
+
this.reduceObserver,
|
|
216
|
+
UIAccessibilityReduceMotionStatusDidChangeNotification,
|
|
217
|
+
)
|
|
218
|
+
this.reduceObserver = undefined
|
|
219
|
+
}
|
|
220
|
+
private dismissed = (
|
|
221
|
+
x: number,
|
|
222
|
+
y: number,
|
|
223
|
+
scale: number,
|
|
224
|
+
velocity: number,
|
|
225
|
+
progress: number,
|
|
226
|
+
) => {
|
|
227
|
+
if (this.stopped) return
|
|
228
|
+
const generation = ++this.generation
|
|
229
|
+
const valid = () => !this.stopped && generation === this.generation
|
|
230
|
+
const dismissal: PhotoDismissal = {
|
|
231
|
+
state: { x, y, scale, progress, pending: true },
|
|
232
|
+
velocity,
|
|
233
|
+
cancel: () => {
|
|
234
|
+
if (!valid()) return false
|
|
235
|
+
this.cancelDismiss()
|
|
236
|
+
return true
|
|
237
|
+
},
|
|
238
|
+
complete: () => {
|
|
239
|
+
if (!valid()) return false
|
|
240
|
+
this.dispose()
|
|
241
|
+
return true
|
|
242
|
+
},
|
|
243
|
+
}
|
|
244
|
+
if (this.options.onDismiss) this.options.onDismiss(dismissal)
|
|
245
|
+
else dismissal.cancel()
|
|
246
|
+
}
|
|
247
|
+
private settled = (x: number, y: number, scale: number) => {
|
|
248
|
+
if (this.stopped) return
|
|
249
|
+
this.generation++
|
|
250
|
+
this.latest = { x, y, scale, progress: 0, pending: false }
|
|
251
|
+
this.options.onSettled?.({ ...this.latest })
|
|
252
|
+
}
|
|
253
|
+
private sourceChanged = () => {
|
|
254
|
+
this.generation++
|
|
255
|
+
this.driver?.stop()
|
|
256
|
+
this.driver = undefined
|
|
257
|
+
this.schedule()
|
|
258
|
+
}
|
|
259
|
+
private suspend = () => {
|
|
260
|
+
this.suspended = true
|
|
261
|
+
this.generation++
|
|
262
|
+
this.driver?.setActive(false)
|
|
263
|
+
}
|
|
264
|
+
private resume = () => {
|
|
265
|
+
this.suspended = false
|
|
266
|
+
this.preferences()
|
|
267
|
+
this.driver?.setActive(true)
|
|
268
|
+
this.schedule()
|
|
269
|
+
}
|
|
270
|
+
private preferences = () => this.driver?.setReduced(reducedMotion())
|
|
271
|
+
private schedule = () => {
|
|
272
|
+
if (this.stopped || this.queued) return
|
|
273
|
+
this.queued = true
|
|
274
|
+
void Promise.resolve()
|
|
275
|
+
.then(() => {
|
|
276
|
+
this.queued = false
|
|
277
|
+
if (
|
|
278
|
+
this.stopped ||
|
|
279
|
+
this.suspended ||
|
|
280
|
+
!this.image.isLoaded ||
|
|
281
|
+
!this.viewport.isLoaded
|
|
282
|
+
)
|
|
283
|
+
return
|
|
284
|
+
if (this.driver) {
|
|
285
|
+
this.driver.layout()
|
|
286
|
+
return
|
|
287
|
+
}
|
|
288
|
+
if (this.image.parent !== this.viewport)
|
|
289
|
+
throw new TypeError('Zoom viewport must remain the direct image parent.')
|
|
290
|
+
const size = this.viewport.getActualSize()
|
|
291
|
+
const imageSize = this.image.getActualSize(),
|
|
292
|
+
source = this.image.imageSource
|
|
293
|
+
if (
|
|
294
|
+
size.width <= 0 ||
|
|
295
|
+
size.height <= 0 ||
|
|
296
|
+
imageSize.width <= 0 ||
|
|
297
|
+
imageSize.height <= 0 ||
|
|
298
|
+
!source ||
|
|
299
|
+
!Number.isFinite(source.width) ||
|
|
300
|
+
!Number.isFinite(source.height) ||
|
|
301
|
+
source.width <= 0 ||
|
|
302
|
+
source.height <= 0
|
|
303
|
+
)
|
|
304
|
+
return
|
|
305
|
+
if (isIOS && typeof JoltPhotoZoom === 'undefined')
|
|
306
|
+
throw new Error('Rebuild the native app to install Jolt photo gestures.')
|
|
307
|
+
this.driver = createZoomDriver(
|
|
308
|
+
this.image,
|
|
309
|
+
this.viewport,
|
|
310
|
+
{
|
|
311
|
+
minimum: this.options.scale[0],
|
|
312
|
+
maximum: this.options.scale[1],
|
|
313
|
+
doubleTap: this.options.doubleTap,
|
|
314
|
+
dismiss: this.options.dismiss === 'vertical',
|
|
315
|
+
reduced: reducedMotion(),
|
|
316
|
+
backdrop: this.options.backdrop,
|
|
317
|
+
chrome: this.options.chrome,
|
|
318
|
+
},
|
|
319
|
+
this.dismissed,
|
|
320
|
+
this.settled,
|
|
321
|
+
)
|
|
322
|
+
})
|
|
323
|
+
.catch((error: unknown) => {
|
|
324
|
+
if (this.stopped) return
|
|
325
|
+
this.failure = error instanceof Error ? error : new Error(String(error))
|
|
326
|
+
this.dispose()
|
|
327
|
+
this.options.onError?.(this.failure)
|
|
328
|
+
})
|
|
329
|
+
}
|
|
330
|
+
}
|