@rafaelaugusto/jolt 0.1.0-beta.4 → 0.1.0-beta.6
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 +134 -4
- package/dist/animate.d.ts +7 -4
- package/dist/animate.d.ts.map +1 -1
- package/dist/animate.js +58 -13
- 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/decoration.d.ts +18 -0
- package/dist/decoration.d.ts.map +1 -0
- package/dist/decoration.js +155 -0
- package/dist/decoration.js.map +1 -0
- package/dist/driver/android-color.d.ts +3 -0
- package/dist/driver/android-color.d.ts.map +1 -1
- package/dist/driver/android-color.js +20 -18
- package/dist/driver/android-color.js.map +1 -1
- package/dist/driver/android-decoration.d.ts +22 -0
- package/dist/driver/android-decoration.d.ts.map +1 -0
- package/dist/driver/android-decoration.js +139 -0
- package/dist/driver/android-decoration.js.map +1 -0
- package/dist/driver/android-playback.d.ts +13 -0
- package/dist/driver/android-playback.d.ts.map +1 -0
- package/dist/driver/android-playback.js +141 -0
- package/dist/driver/android-playback.js.map +1 -0
- package/dist/driver/android.d.ts.map +1 -1
- package/dist/driver/android.js +30 -36
- package/dist/driver/android.js.map +1 -1
- package/dist/driver/index.d.ts +9 -0
- package/dist/driver/index.d.ts.map +1 -1
- package/dist/driver/index.js.map +1 -1
- package/dist/driver/ios-color.d.ts +2 -0
- package/dist/driver/ios-color.d.ts.map +1 -1
- package/dist/driver/ios-color.js +19 -8
- package/dist/driver/ios-color.js.map +1 -1
- package/dist/driver/ios-decoration.d.ts +17 -0
- package/dist/driver/ios-decoration.d.ts.map +1 -0
- package/dist/driver/ios-decoration.js +271 -0
- package/dist/driver/ios-decoration.js.map +1 -0
- package/dist/driver/ios-playback.d.ts +10 -0
- package/dist/driver/ios-playback.d.ts.map +1 -0
- package/dist/driver/ios-playback.js +47 -0
- package/dist/driver/ios-playback.js.map +1 -0
- package/dist/driver/ios-shadow.d.ts +6 -0
- package/dist/driver/ios-shadow.d.ts.map +1 -0
- package/dist/driver/ios-shadow.js +52 -0
- package/dist/driver/ios-shadow.js.map +1 -0
- package/dist/driver/ios.d.ts.map +1 -1
- package/dist/driver/ios.js +76 -40
- package/dist/driver/ios.js.map +1 -1
- package/dist/engine.d.ts +64 -3
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +243 -19
- package/dist/engine.js.map +1 -1
- package/dist/haptics.d.ts +4 -1
- package/dist/haptics.d.ts.map +1 -1
- package/dist/haptics.js +27 -3
- package/dist/haptics.js.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -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 +2 -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 +6 -0
- package/dist/playback-group.d.ts.map +1 -0
- package/dist/playback-group.js +141 -0
- package/dist/playback-group.js.map +1 -0
- package/dist/playback.d.ts +25 -0
- package/dist/playback.d.ts.map +1 -0
- package/dist/playback.js +35 -0
- package/dist/playback.js.map +1 -0
- package/dist/press.d.ts.map +1 -1
- package/dist/press.js +3 -3
- package/dist/press.js.map +1 -1
- package/dist/properties.d.ts +2 -1
- package/dist/properties.d.ts.map +1 -1
- package/dist/properties.js +14 -1
- package/dist/properties.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 +208 -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 +72 -16
- package/dist/track.js.map +1 -1
- package/dist/transition.d.ts.map +1 -1
- package/dist/transition.js +4 -1
- package/dist/transition.js.map +1 -1
- package/dist/types.d.ts +22 -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/package.json +15 -3
- package/platforms/android/java/org/rafaelaugusto/jolt/ColorTarget.java +2 -2
- package/platforms/android/java/org/rafaelaugusto/jolt/DecorationTarget.java +154 -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/TextReveal.java +180 -0
- package/platforms/android/proguard-rules.pro +7 -0
- package/src/android-plugin.d.ts +64 -0
- package/src/animate.ts +96 -33
- package/src/config.ts +46 -0
- package/src/decoration.ts +180 -0
- package/src/driver/android-color.ts +22 -20
- package/src/driver/android-decoration.ts +182 -0
- package/src/driver/android-playback.ts +157 -0
- package/src/driver/android.ts +57 -43
- package/src/driver/index.ts +15 -0
- package/src/driver/ios-color.ts +19 -10
- package/src/driver/ios-decoration.ts +332 -0
- package/src/driver/ios-playback.ts +51 -0
- package/src/driver/ios-shadow.ts +50 -0
- package/src/driver/ios.ts +87 -46
- package/src/engine.ts +267 -22
- package/src/haptics.ts +25 -2
- package/src/index.ts +12 -1
- package/src/items.ts +140 -0
- package/src/keyboard.ts +132 -0
- package/src/label.ts +76 -0
- package/src/liquid.ts +2 -1
- package/src/loader.ts +2 -1
- package/src/particles.ts +4 -4
- package/src/path.ts +124 -0
- package/src/playback-group.ts +143 -0
- package/src/playback.ts +62 -0
- package/src/press.ts +3 -5
- package/src/properties.ts +18 -2
- 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 +204 -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 +98 -25
- package/src/transition.ts +4 -1
- package/src/types.ts +23 -1
- package/src/vue/index.ts +189 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import {
|
|
2
|
+
arrivalOf,
|
|
3
|
+
arrivalTimingOf,
|
|
4
|
+
setArrival,
|
|
5
|
+
setArrivalTiming,
|
|
6
|
+
type ViewAnimation,
|
|
7
|
+
} from './engine.js'
|
|
8
|
+
import { getDriver } from './driver/index.js'
|
|
9
|
+
import { createClock, type PlaybackClock } from './playback.js'
|
|
10
|
+
import { validateProgress, type PlaybackAnimation } from './playback.js'
|
|
11
|
+
|
|
12
|
+
/** Staggered views share a finite time range. Shorter children remain seekable
|
|
13
|
+
* until the whole group settles, unless another animation has taken ownership. */
|
|
14
|
+
export function playbackGroup(children: readonly ViewAnimation[]): PlaybackAnimation {
|
|
15
|
+
let paused = false
|
|
16
|
+
let settled = false
|
|
17
|
+
let finalProgress: number | undefined
|
|
18
|
+
let clock: PlaybackClock | undefined
|
|
19
|
+
let pendingProgress: number | undefined
|
|
20
|
+
const duration = () => Math.max(0, ...children.map((child) => child.duration))
|
|
21
|
+
const ensureClock = () => {
|
|
22
|
+
if (clock || settled || children.some((child) => !child.ready)) return
|
|
23
|
+
const driver = getDriver()
|
|
24
|
+
clock = driver.clock?.(duration()) ?? createClock(() => driver.now())
|
|
25
|
+
clock.seek(Math.max(0, ...children.map((child) => child.currentTime)))
|
|
26
|
+
if (paused) clock.pause()
|
|
27
|
+
}
|
|
28
|
+
const finishIfIdle = () => {
|
|
29
|
+
if (settled || paused || children.some((child) => !child.idle || child.paused)) return
|
|
30
|
+
settled = true
|
|
31
|
+
clock?.cancel()
|
|
32
|
+
for (const child of children) child.releaseGroup()
|
|
33
|
+
}
|
|
34
|
+
const seek = (value: number) => {
|
|
35
|
+
const total = duration()
|
|
36
|
+
validateProgress(value, total)
|
|
37
|
+
if (settled) return
|
|
38
|
+
if (children.some((child) => !child.ready)) {
|
|
39
|
+
pendingProgress = value
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
pendingProgress = undefined
|
|
43
|
+
ensureClock()
|
|
44
|
+
clock?.seek(total * value)
|
|
45
|
+
for (const child of children) child.seekTime(total * value)
|
|
46
|
+
finishIfIdle()
|
|
47
|
+
}
|
|
48
|
+
for (const child of children) {
|
|
49
|
+
child.onIdle(finishIfIdle)
|
|
50
|
+
child.onReady(() => {
|
|
51
|
+
ensureClock()
|
|
52
|
+
if (pendingProgress !== undefined && children.every((child) => child.ready))
|
|
53
|
+
seek(pendingProgress)
|
|
54
|
+
finishIfIdle()
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
const finished = Promise.all(children.map((child) => child.finished)).then(
|
|
58
|
+
(results) => {
|
|
59
|
+
finalProgress ??= results.every(Boolean)
|
|
60
|
+
? 1
|
|
61
|
+
: duration()
|
|
62
|
+
? Math.min(1, (clock?.time() ?? 0) / duration())
|
|
63
|
+
: 0
|
|
64
|
+
settled = true
|
|
65
|
+
clock?.cancel()
|
|
66
|
+
return results.every(Boolean)
|
|
67
|
+
},
|
|
68
|
+
)
|
|
69
|
+
const animation: PlaybackAnimation = {
|
|
70
|
+
finished,
|
|
71
|
+
get duration() {
|
|
72
|
+
return duration()
|
|
73
|
+
},
|
|
74
|
+
get paused() {
|
|
75
|
+
return paused
|
|
76
|
+
},
|
|
77
|
+
get progress() {
|
|
78
|
+
if (!Number.isFinite(duration()))
|
|
79
|
+
throw new RangeError('Progress requires a finite animation.')
|
|
80
|
+
if (pendingProgress !== undefined) return pendingProgress
|
|
81
|
+
return (
|
|
82
|
+
finalProgress ??
|
|
83
|
+
(settled ? 1 : duration() ? Math.min(1, (clock?.time() ?? 0) / duration()) : 0)
|
|
84
|
+
)
|
|
85
|
+
},
|
|
86
|
+
set progress(value) {
|
|
87
|
+
seek(value)
|
|
88
|
+
},
|
|
89
|
+
pause() {
|
|
90
|
+
if (!settled && !paused) {
|
|
91
|
+
paused = true
|
|
92
|
+
clock?.pause()
|
|
93
|
+
children.forEach((child) => child.pause())
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
play() {
|
|
97
|
+
if (!settled && paused) {
|
|
98
|
+
paused = false
|
|
99
|
+
clock?.play()
|
|
100
|
+
children.forEach((child) => child.play())
|
|
101
|
+
finishIfIdle()
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
stop() {
|
|
105
|
+
finalProgress = duration() ? Math.min(1, (clock?.time() ?? 0) / duration()) : 0
|
|
106
|
+
settled = true
|
|
107
|
+
clock?.cancel()
|
|
108
|
+
children.forEach((child) => child.stop())
|
|
109
|
+
},
|
|
110
|
+
then: (onfulfilled, onrejected) => finished.then(onfulfilled, onrejected),
|
|
111
|
+
}
|
|
112
|
+
setArrival(animation, Promise.all(children.map(arrivalOf)))
|
|
113
|
+
const listeners = new Set<() => void>()
|
|
114
|
+
const timings = children.map((child) => arrivalTimingOf(child)!)
|
|
115
|
+
const notify = () => {
|
|
116
|
+
for (const callback of [...listeners]) callback()
|
|
117
|
+
}
|
|
118
|
+
const unsubscribe = timings.map((timing) => timing.subscribe(notify))
|
|
119
|
+
setArrivalTiming(animation, {
|
|
120
|
+
read() {
|
|
121
|
+
const states = timings.map((timing) => timing.read())
|
|
122
|
+
return {
|
|
123
|
+
arrived: settled || states.every((state) => state.arrived),
|
|
124
|
+
paused: paused || states.some((state) => state.paused && !state.arrived),
|
|
125
|
+
remaining: states.some((state) => !state.arrived && state.remaining === undefined)
|
|
126
|
+
? undefined
|
|
127
|
+
: Math.max(0, ...states.map((state) => (state.arrived ? 0 : state.remaining!))),
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
subscribe(callback) {
|
|
131
|
+
listeners.add(callback)
|
|
132
|
+
return () => listeners.delete(callback)
|
|
133
|
+
},
|
|
134
|
+
})
|
|
135
|
+
void finished.then(() => {
|
|
136
|
+
unsubscribe.forEach((off) => off())
|
|
137
|
+
notify()
|
|
138
|
+
listeners.clear()
|
|
139
|
+
})
|
|
140
|
+
ensureClock()
|
|
141
|
+
finishIfIdle()
|
|
142
|
+
return animation
|
|
143
|
+
}
|
package/src/playback.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Animation } from './engine.js'
|
|
2
|
+
|
|
3
|
+
/** Controls returned by animate() and decay(). Effects expose the base Animation. */
|
|
4
|
+
export interface PlaybackAnimation extends Animation {
|
|
5
|
+
/** Pauses only the properties owned by this animation. */
|
|
6
|
+
pause(): void
|
|
7
|
+
/** Continues from the current position. Completed/stopped animations remain terminal. */
|
|
8
|
+
play(): void
|
|
9
|
+
readonly paused: boolean
|
|
10
|
+
/** Total milliseconds, including delays and repeats. Infinity for endless loops. */
|
|
11
|
+
readonly duration: number
|
|
12
|
+
/** Finite timeline position, from 0 to 1. Seeking preserves the playing/paused state. */
|
|
13
|
+
progress: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type PlaybackCommand = 'pause' | 'play' | 'seek'
|
|
17
|
+
|
|
18
|
+
export interface PlaybackClock {
|
|
19
|
+
time(): number
|
|
20
|
+
pause(): void
|
|
21
|
+
play(): void
|
|
22
|
+
seek(ms: number): void
|
|
23
|
+
cancel(): void
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Read only on user commands; there is no frame loop in JavaScript. */
|
|
27
|
+
export function createClock(now: () => number, initial = 0): PlaybackClock {
|
|
28
|
+
let offset = initial
|
|
29
|
+
let anchor = now()
|
|
30
|
+
let paused = false
|
|
31
|
+
const time = () => offset + (paused ? 0 : now() - anchor)
|
|
32
|
+
return {
|
|
33
|
+
time,
|
|
34
|
+
pause() {
|
|
35
|
+
offset = time()
|
|
36
|
+
paused = true
|
|
37
|
+
},
|
|
38
|
+
play() {
|
|
39
|
+
if (paused) {
|
|
40
|
+
anchor = now()
|
|
41
|
+
paused = false
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
seek(ms) {
|
|
45
|
+
offset = ms
|
|
46
|
+
anchor = now()
|
|
47
|
+
},
|
|
48
|
+
cancel() {
|
|
49
|
+
offset = time()
|
|
50
|
+
paused = true
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function validateProgress(value: number, duration: number) {
|
|
56
|
+
if (!Number.isFinite(value) || value < 0 || value > 1)
|
|
57
|
+
throw new RangeError('Animation progress must be between 0 and 1.')
|
|
58
|
+
if (!Number.isFinite(duration))
|
|
59
|
+
throw new RangeError(
|
|
60
|
+
'Progress requires a finite animation; endless loops can pause and play.',
|
|
61
|
+
)
|
|
62
|
+
}
|
package/src/press.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Color, type EventData, type TouchGestureEventData } from '@nativescript/core'
|
|
2
2
|
import { isColorProperty } from './color.js'
|
|
3
|
-
import { animate, toView } from './animate.js'
|
|
4
|
-
import {
|
|
3
|
+
import { animate, startingValues, toView } from './animate.js'
|
|
4
|
+
import { readValue } from './properties.js'
|
|
5
5
|
import type { SpringName, Transition } from './transition.js'
|
|
6
6
|
import type { AnimateOptions, Keyframes, Target } from './types.js'
|
|
7
7
|
|
|
@@ -23,9 +23,7 @@ export function press(
|
|
|
23
23
|
options?: AnimateOptions | SpringName,
|
|
24
24
|
): () => void {
|
|
25
25
|
const view = toView(target)
|
|
26
|
-
const properties =
|
|
27
|
-
key === 'scale' ? ['scaleX', 'scaleY'] : isProperty(key) ? [key] : [],
|
|
28
|
-
)
|
|
26
|
+
const properties = [...startingValues(pressed, options).keys()]
|
|
29
27
|
let rest: Keyframes | undefined
|
|
30
28
|
|
|
31
29
|
const onTouch = (event: EventData) => {
|
package/src/properties.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { Color, type View } from '@nativescript/core'
|
|
2
|
+
import {
|
|
3
|
+
isDecorationProperty,
|
|
4
|
+
readDecoration,
|
|
5
|
+
writeDecoration,
|
|
6
|
+
type DecorationProperty,
|
|
7
|
+
} from './decoration.js'
|
|
2
8
|
import { isColorProperty, readColor, type ColorProperty } from './color.js'
|
|
3
9
|
|
|
4
10
|
export type NumericProperty =
|
|
5
11
|
'opacity' | 'x' | 'y' | 'scaleX' | 'scaleY' | 'rotate' | 'rotateX' | 'rotateY'
|
|
6
|
-
export type Property = NumericProperty | ColorProperty
|
|
12
|
+
export type Property = NumericProperty | ColorProperty | DecorationProperty
|
|
7
13
|
|
|
8
14
|
const viewKeys = {
|
|
9
15
|
opacity: 'opacity',
|
|
@@ -29,6 +35,14 @@ const defaults: Record<NumericProperty, number> = {
|
|
|
29
35
|
|
|
30
36
|
/** How close to its target a spring or decay has to be to count as settled. */
|
|
31
37
|
export const precision: Record<Property, number> = {
|
|
38
|
+
borderRadius: 0.1,
|
|
39
|
+
borderWidth: 0.1,
|
|
40
|
+
shadowOpacity: 0.002,
|
|
41
|
+
shadowRadius: 0.1,
|
|
42
|
+
shadowOffsetX: 0.1,
|
|
43
|
+
shadowOffsetY: 0.1,
|
|
44
|
+
elevation: 0.1,
|
|
45
|
+
translationZ: 0.1,
|
|
32
46
|
backgroundColor: 0.002,
|
|
33
47
|
borderColor: 0.002,
|
|
34
48
|
color: 0.002,
|
|
@@ -43,11 +57,12 @@ export const precision: Record<Property, number> = {
|
|
|
43
57
|
}
|
|
44
58
|
|
|
45
59
|
export function isProperty(key: string): key is Property {
|
|
46
|
-
return key
|
|
60
|
+
return Object.hasOwn(viewKeys, key) || isColorProperty(key) || isDecorationProperty(key)
|
|
47
61
|
}
|
|
48
62
|
|
|
49
63
|
export function readValue(view: View, property: Property): number {
|
|
50
64
|
if (isColorProperty(property)) return readColor(view, property)
|
|
65
|
+
if (isDecorationProperty(property)) return readDecoration(view, property)
|
|
51
66
|
const value = view[viewKeys[property]]
|
|
52
67
|
return typeof value === 'number' && !Number.isNaN(value) ? value : defaults[property]
|
|
53
68
|
}
|
|
@@ -57,5 +72,6 @@ export function writeValue(view: View, property: Property, value: number) {
|
|
|
57
72
|
view[property] = new Color(value)
|
|
58
73
|
return
|
|
59
74
|
}
|
|
75
|
+
if (isDecorationProperty(property)) return writeDecoration(view, property, value)
|
|
60
76
|
view[viewKeys[property]] = value
|
|
61
77
|
}
|
package/src/reveal.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { toView } from './animate.js'
|
|
|
3
3
|
import { resolveEasing } from './easing.js'
|
|
4
4
|
import type { Animation } from './engine.js'
|
|
5
5
|
import type { Target } from './types.js'
|
|
6
|
+
import { reducedMotion } from './config.js'
|
|
6
7
|
|
|
7
8
|
export interface RevealOptions {
|
|
8
9
|
/** Circle origin in DIPs from the target's top-left corner. Defaults to its center. */
|
|
@@ -243,14 +244,13 @@ class CircularAnimation implements Animation {
|
|
|
243
244
|
}
|
|
244
245
|
|
|
245
246
|
private motionChanged = () => {
|
|
246
|
-
if (
|
|
247
|
+
if (reducedMotion()) this.end(true)
|
|
247
248
|
}
|
|
248
249
|
|
|
249
250
|
private update() {
|
|
250
251
|
if (!this.opening && !this.inherited && this.view.visibility !== 'visible')
|
|
251
252
|
return this.end(true, true)
|
|
252
|
-
if (this.duration === 0 ||
|
|
253
|
-
return this.end(true)
|
|
253
|
+
if (this.duration === 0 || reducedMotion()) return this.end(true)
|
|
254
254
|
if (this.waitingForLoad || !this.view.isLoaded) return
|
|
255
255
|
const native = this.view.nativeViewProtected as MaskedView | undefined
|
|
256
256
|
if (this.shape) {
|
package/src/roll-diff.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface Grapheme {
|
|
2
|
+
text: string
|
|
3
|
+
/** UTF-16 offsets, the units NSString locations and Java char indices use. */
|
|
4
|
+
start: number
|
|
5
|
+
end: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface RollChange {
|
|
9
|
+
/** The grapheme that rolls in, placed in the new text. */
|
|
10
|
+
next: Grapheme
|
|
11
|
+
/** The grapheme it replaces at the same position from the end, when there is one. */
|
|
12
|
+
previous: Grapheme | undefined
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface RollDiff {
|
|
16
|
+
/** Positions that differ, from the last one backwards. */
|
|
17
|
+
changes: RollChange[]
|
|
18
|
+
/** Old graphemes to the left of the new text's first one; they roll out alone. */
|
|
19
|
+
removed: Grapheme[]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const segmenter =
|
|
23
|
+
typeof Intl !== 'undefined' && 'Segmenter' in Intl
|
|
24
|
+
? new Intl.Segmenter(undefined, { granularity: 'grapheme' })
|
|
25
|
+
: undefined
|
|
26
|
+
|
|
27
|
+
export function graphemes(text: string): Grapheme[] {
|
|
28
|
+
if (segmenter)
|
|
29
|
+
return [...segmenter.segment(text)].map(({ segment, index }) => ({
|
|
30
|
+
text: segment,
|
|
31
|
+
start: index,
|
|
32
|
+
end: index + segment.length,
|
|
33
|
+
}))
|
|
34
|
+
const pieces: Grapheme[] = []
|
|
35
|
+
let offset = 0
|
|
36
|
+
for (const character of text) {
|
|
37
|
+
pieces.push({ text: character, start: offset, end: offset + character.length })
|
|
38
|
+
offset += character.length
|
|
39
|
+
}
|
|
40
|
+
return pieces
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Aligns both texts on their last grapheme, so the units digit stays put when the count grows. */
|
|
44
|
+
export function diffFromEnd(previous: string, next: string): RollDiff {
|
|
45
|
+
const before = graphemes(previous)
|
|
46
|
+
const after = graphemes(next)
|
|
47
|
+
const changes: RollChange[] = []
|
|
48
|
+
const removed: Grapheme[] = []
|
|
49
|
+
const count = Math.max(before.length, after.length)
|
|
50
|
+
for (let offset = 1; offset <= count; offset++) {
|
|
51
|
+
const old = before[before.length - offset]
|
|
52
|
+
const piece = after[after.length - offset]
|
|
53
|
+
if (!piece) removed.push(old!)
|
|
54
|
+
else if (!old || old.text !== piece.text) changes.push({ next: piece, previous: old })
|
|
55
|
+
}
|
|
56
|
+
return { changes, removed }
|
|
57
|
+
}
|