@octane-xplat/motion 0.7.2 → 0.9.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/UPSTREAM.md +47 -14
- package/dist/native/octane-client-build.json +1 -1
- package/dist/web/octane-client-build.json +1 -1
- package/package.json +20 -16
- package/src/components.mobile.test.tsrx +19 -6
- package/src/components.web.test.tsrx +3 -2
- package/src/engine.test.ts +13 -0
- package/src/engine.ts +5 -5
- package/src/presence-input.ts +11 -4
- package/src/presence-input.web.ts +13 -4
- package/src/presence-state.ts +27 -7
- package/src/types.ts +6 -2
- package/src/value.ts +3 -3
- package/types/engine.d.ts +2 -2
- package/types/index.d.ts +12 -5
- package/types/types.d.ts +6 -2
- package/types/value.d.ts +3 -3
package/UPSTREAM.md
CHANGED
|
@@ -6,16 +6,16 @@ inspected from Octane main on 2026-09-29. Its UPSTREAM.md pins Motion 12.42.2
|
|
|
6
6
|
`motion-dom@12.42.2` and bundles its pure numeric generators and interpolation.
|
|
7
7
|
The adapter is original code; it does not copy upstream's DOM host factory.
|
|
8
8
|
|
|
9
|
-
| Contract | Upstream reference under packages/motion | Xplat implementation / evidence
|
|
10
|
-
| ------------------------------------------------ | ----------------------------------------------------------------- |
|
|
11
|
-
| Initial and changing targets, equal destinations | src/index.ts; tests/conformance/rerender.test.ts, effects.test.ts | Compiled wrappers over UI; components.web.test.tsrx
|
|
12
|
-
| Numeric spring/tween samples | Motion's motion-dom animation/generators | Reused generators; engine.test.ts compares irregular-time samples
|
|
13
|
-
| Stable value, subscriptions, style replacement | src/useMotionValue.ts; tests/conformance/motionValue.test.ts | Numeric adapter with native clock; components.web.test.tsrx
|
|
14
|
-
| Spring set versus jump; follow source | src/useSpring.ts; tests/conformance/useSpring.test.ts | Owned spring interception and cleanup; hook tests
|
|
15
|
-
| Derived numeric values | src/useTransform.ts; tests/conformance/useTransform.test.ts | Upstream interpolation, direct subscriptions; hook tests
|
|
16
|
-
| Config and reduced motion | src/context.ts; tests/conformance/reducedMotionConfig.test.ts | Context inheritance; transforms settle immediately
|
|
17
|
-
| Exit lifecycle | src/index.ts; tests/conformance/exit.test.ts | Deliberate live-subtree retention on both leaves; presence.web.test.tsrx and native presence test
|
|
18
|
-
| Retained hosts on native | Not a DOM binding concern | components.mobile.test.tsrx uses the universal object driver
|
|
9
|
+
| Contract | Upstream reference under packages/motion | Xplat implementation / evidence |
|
|
10
|
+
| ------------------------------------------------ | ----------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| Initial and changing targets, equal destinations | src/index.ts; tests/conformance/rerender.test.ts, effects.test.ts | Compiled wrappers over UI; components.web.test.tsrx |
|
|
12
|
+
| Numeric spring/tween samples | Motion's motion-dom animation/generators | Reused generators; engine.test.ts compares irregular-time samples |
|
|
13
|
+
| Stable value, subscriptions, style replacement | src/useMotionValue.ts; tests/conformance/motionValue.test.ts | Numeric adapter with native clock; components.web.test.tsrx |
|
|
14
|
+
| Spring set versus jump; follow source | src/useSpring.ts; tests/conformance/useSpring.test.ts | Owned spring interception and cleanup; hook tests |
|
|
15
|
+
| Derived numeric values | src/useTransform.ts; tests/conformance/useTransform.test.ts | Upstream interpolation, direct subscriptions; hook tests |
|
|
16
|
+
| Config and reduced motion | src/context.ts; tests/conformance/reducedMotionConfig.test.ts | Context inheritance; spring transforms settle immediately on live preference changes while opacity can keep animating (`components.web.test.tsrx`, `engine.test.ts`) |
|
|
17
|
+
| Exit lifecycle | src/index.ts; tests/conformance/exit.test.ts | Deliberate live-subtree retention on both leaves; presence.web.test.tsrx and native presence test |
|
|
18
|
+
| Retained hosts on native | Not a DOM binding concern | components.mobile.test.tsrx uses the universal object driver |
|
|
19
19
|
|
|
20
20
|
Source links: [Octane motion](https://github.com/octanejs/octane/tree/main/packages/motion),
|
|
21
21
|
[upstream ledger](https://github.com/octanejs/octane/blob/main/packages/motion/UPSTREAM.md),
|
|
@@ -55,7 +55,40 @@ An ancestor unmount always disposes immediately. Nested boundaries are independe
|
|
|
55
55
|
|
|
56
56
|
Unit and DOM tests establish bounded behavior, not full Framer Motion parity.
|
|
57
57
|
Universal object-driver tests establish retention and lifecycle without an OS.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
Partial device observations are recorded in the
|
|
59
|
+
[motion v1 validation matrix](../../docs/animation-notes.md). An isolated iOS
|
|
60
|
+
26.5 MotionProbe run verified pan completion/cancellation, Presence
|
|
61
|
+
focus/reversal/removal, and live Reduce Motion, including immediate transform
|
|
62
|
+
settlement. The API 35 Android emulator verified tween/spring completion,
|
|
63
|
+
cancellation, disposal, pan phase delivery, focus release on Presence exit, and
|
|
64
|
+
live reduced-motion observation. Changing `animator_duration_scale` to `0`
|
|
65
|
+
while mounted changed the probe state to reduced, and a subsequent idle snapshot
|
|
66
|
+
showed the `-100` tween destination; deleting the setting restored the default
|
|
67
|
+
and the state returned to normal. The idle snapshot does not establish
|
|
68
|
+
frame-accurate settlement time. Its injected pan release reported zero velocity,
|
|
69
|
+
and the accessibility runner did not reach idle during reversal, so those
|
|
70
|
+
checks remain open.
|
|
71
|
+
|
|
72
|
+
A physical iPhone 13 Pro Max running iOS 27.0.1 launched the temporary direct
|
|
73
|
+
MotionProbe under an Xcode UI-test host. The test verified tween-to-spring
|
|
74
|
+
retargeting, explicit `MotionValue.stop()` cancellation, native pan begin/move/end
|
|
75
|
+
with nonzero release velocity and settling, and Presence child retention through
|
|
76
|
+
a focus-triggered exit/reversal. Presence dismissed the keyboard; after
|
|
77
|
+
re-entry the retained field accepted focus and typed input, and a later exit
|
|
78
|
+
dismissed the keyboard and reported one removal. The failed check expected the
|
|
79
|
+
keyboard to remain open immediately after the focus-triggered reversal; that
|
|
80
|
+
expectation conflicts with Presence releasing focus on exit. The physical
|
|
81
|
+
Reduce Motion change remains inconclusive: the test did not record the system
|
|
82
|
+
switch value before and after its Settings tap. A corrected rerun was blocked
|
|
83
|
+
when the phone re-locked.
|
|
84
|
+
|
|
85
|
+
Physical Android CPH2551 evidence covers app launch and target retarget only;
|
|
86
|
+
ADB sees the handset, but its keyguard is currently locked. The regular mobile app now builds and
|
|
87
|
+
mounts on the iOS 26.5 simulator using NativeScript's `NSObject.extend()` API
|
|
88
|
+
for the auth-session presentation delegate. The Android build also passes with
|
|
89
|
+
the iOS delegate behind the `NSObject` runtime guard. Motion-specific simulator,
|
|
90
|
+
emulator, and iPhone checks still use a temporary direct MotionProbe entry to
|
|
91
|
+
isolate the driver. Physical input suppression during exit, Android gesture
|
|
92
|
+
cancellation/natural velocity, background/resume, and frame pacing remain
|
|
93
|
+
uncharacterized. Native preference observation polls at 500 ms while subscribed
|
|
94
|
+
and refreshes on resume; Android reads `animator_duration_scale`.
|
package/package.json
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octane-xplat/motion",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Declarative motion and retained presence for Octane on web, iOS and Android",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"xplat",
|
|
8
|
-
"cross-platform",
|
|
6
|
+
"android",
|
|
9
7
|
"animation",
|
|
8
|
+
"cross-platform",
|
|
9
|
+
"ios",
|
|
10
10
|
"motion",
|
|
11
|
-
"transitions",
|
|
12
|
-
"spring",
|
|
13
|
-
"presence",
|
|
14
11
|
"nativescript",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
12
|
+
"octane",
|
|
13
|
+
"presence",
|
|
14
|
+
"spring",
|
|
15
|
+
"transitions",
|
|
16
|
+
"web",
|
|
17
|
+
"xplat"
|
|
18
18
|
],
|
|
19
|
-
"license": "MIT",
|
|
20
19
|
"homepage": "https://github.com/octane-xplat/octane-xplat/tree/main/packages/motion",
|
|
20
|
+
"license": "MIT",
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
|
23
|
-
"url": "
|
|
23
|
+
"url": "https://github.com/octane-xplat/octane-xplat",
|
|
24
24
|
"directory": "packages/motion"
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
@@ -43,15 +43,16 @@
|
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@octane-xplat/ui": "0.
|
|
46
|
+
"@octane-xplat/ui": "0.9.0",
|
|
47
47
|
"motion-dom": "12.42.2"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@nativescript-community/octane": "0.2.
|
|
50
|
+
"@nativescript-community/octane": "0.2.4",
|
|
51
51
|
"@nativescript/core": "9.1.2",
|
|
52
52
|
"@octanejs/vite-plugin": "0.1.61",
|
|
53
53
|
"jsdom": "30.1.1",
|
|
54
54
|
"octane": "0.6.3",
|
|
55
|
+
"tsrx-typegen": "0.2.1",
|
|
55
56
|
"typescript": "5.9.3",
|
|
56
57
|
"vite": "8.3.0",
|
|
57
58
|
"vitest": "5.0.1"
|
|
@@ -70,7 +71,10 @@
|
|
|
70
71
|
}
|
|
71
72
|
},
|
|
72
73
|
"scripts": {
|
|
73
|
-
"build": "vite build && vite build --mode native &&
|
|
74
|
-
"test": "vitest run"
|
|
74
|
+
"build": "vite build && vite build --mode native && pnpm typegen",
|
|
75
|
+
"test": "vitest run",
|
|
76
|
+
"typegen": "tsc -p tsconfig.types.json",
|
|
77
|
+
"test:packed": "node tests/packed-consumer.mjs",
|
|
78
|
+
"pack:check": "tsrx-typegen --pack-check"
|
|
75
79
|
}
|
|
76
80
|
}
|
|
@@ -1,30 +1,43 @@
|
|
|
1
1
|
/** @jsxImportSource @nativescript-community/octane */
|
|
2
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
3
|
import { createObjectContainer, createObjectDriver, createUniversalRoot, flushUniversalSync } from 'octane/universal/native'
|
|
4
4
|
import { motion, MotionConfig } from './index'
|
|
5
5
|
|
|
6
6
|
function NativeBox(props: any) @{
|
|
7
7
|
<MotionConfig reducedMotion="always">
|
|
8
|
-
<motion.View
|
|
8
|
+
<motion.View
|
|
9
|
+
id="native"
|
|
10
|
+
initial={{ x: 10 }}
|
|
11
|
+
animate={{ x: props.x }}
|
|
12
|
+
transition={{ duration: 20 }}
|
|
13
|
+
onAnimationComplete={props.done}
|
|
14
|
+
/>
|
|
9
15
|
</MotionConfig>
|
|
10
16
|
}
|
|
11
17
|
|
|
12
18
|
describe('native compiled hosts', () => {
|
|
13
|
-
it('updates retained hosts
|
|
19
|
+
it('updates retained hosts and reports one completion for each changed destination', async () => {
|
|
14
20
|
const container = createObjectContainer('nativescript')
|
|
15
21
|
const root = createUniversalRoot(container, createObjectDriver('nativescript'))
|
|
16
|
-
|
|
22
|
+
const done = vi.fn()
|
|
23
|
+
root.render(NativeBox, { x: 50, done })
|
|
17
24
|
const node: any = container.children[0]
|
|
18
25
|
expect(node.translateX).toBe(50)
|
|
19
|
-
|
|
26
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
27
|
+
expect(done).toHaveBeenCalledTimes(1)
|
|
28
|
+
flushUniversalSync(() => root.render(NativeBox, { x: 50, done }))
|
|
29
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
30
|
+
expect(done).toHaveBeenCalledTimes(1)
|
|
31
|
+
flushUniversalSync(() => root.render(NativeBox, { x: 80, done }))
|
|
32
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
20
33
|
expect(container.children[0]).toBe(node)
|
|
21
34
|
expect(node.translateX).toBe(80)
|
|
35
|
+
expect(done).toHaveBeenCalledTimes(2)
|
|
22
36
|
root.unmount()
|
|
23
37
|
expect(container.children.length).toBe(0)
|
|
24
38
|
})
|
|
25
39
|
})
|
|
26
40
|
|
|
27
|
-
import { vi } from 'vitest'
|
|
28
41
|
import { useEffect } from 'octane'
|
|
29
42
|
import { Presence } from './index'
|
|
30
43
|
let nativeCleanups = 0
|
|
@@ -16,7 +16,7 @@ function Values(props: any) @{
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
function Reduced() @{
|
|
19
|
-
<MotionConfig reducedMotion="always"><motion.Pressable id="reduced" initial={{ x: 0 }} animate={{ x: 100 }} transition={{
|
|
19
|
+
<MotionConfig reducedMotion="always"><motion.Pressable id="reduced" initial={{ x: 0 }} animate={{ x: 100 }} transition={{ type: 'spring' }} /></MotionConfig>
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function mount(component: any) {
|
|
@@ -40,6 +40,7 @@ describe('motion hosts', () => {
|
|
|
40
40
|
await act(async () => {})
|
|
41
41
|
expect(mounted.container.querySelector('#box')).toBe(node)
|
|
42
42
|
expect(node.style.transform).toContain('translateX(80px)')
|
|
43
|
+
expect(done).toHaveBeenCalledTimes(2)
|
|
43
44
|
mounted.close()
|
|
44
45
|
})
|
|
45
46
|
|
|
@@ -120,7 +121,7 @@ it('retargets from a render-time signal read', () => {
|
|
|
120
121
|
})
|
|
121
122
|
|
|
122
123
|
function UserReduced() @{
|
|
123
|
-
<MotionConfig reducedMotion="user"><motion.View id="user-reduced" animate={{ x: 100 }} transition={{
|
|
124
|
+
<MotionConfig reducedMotion="user"><motion.View id="user-reduced" animate={{ x: 100 }} transition={{ type: 'spring' }} /></MotionConfig>
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
it('observes live system reduced-motion changes', () => {
|
package/src/engine.test.ts
CHANGED
|
@@ -123,4 +123,17 @@ describe('portable playback', () => {
|
|
|
123
123
|
expect(await result).toBe('replaced')
|
|
124
124
|
expect(time.count()).toBe(0)
|
|
125
125
|
})
|
|
126
|
+
|
|
127
|
+
it('reduces positional springs immediately while preserving opacity motion', async () => {
|
|
128
|
+
const time = fakeClock()
|
|
129
|
+
const controller = new Controller(time.clock)
|
|
130
|
+
const result = controller.animate({ x: 100, opacity: 0 }, { type: 'spring' }, true)
|
|
131
|
+
|
|
132
|
+
expect(controller.snapshot()).toMatchObject({ x: 100, opacity: 1 })
|
|
133
|
+
expect(time.count()).toBe(1)
|
|
134
|
+
time.advance(10000)
|
|
135
|
+
expect(await result).toBe('finished')
|
|
136
|
+
expect(controller.snapshot()).toEqual({ x: 100, opacity: 0 })
|
|
137
|
+
controller.destroy()
|
|
138
|
+
})
|
|
126
139
|
})
|
package/src/engine.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { keyframes, spring } from 'motion-dom'
|
|
2
|
-
import type { Clock } from './clock-types'
|
|
3
|
-
import type { Transition } from './types'
|
|
2
|
+
import type { Clock } from './clock-types.js'
|
|
3
|
+
import type { Transition } from './types.js'
|
|
4
4
|
|
|
5
5
|
/** Terminal status; cancellation never masquerades as completion. */
|
|
6
6
|
export type AnimationResult = 'finished' | 'cancelled' | 'replaced'
|
|
@@ -12,10 +12,10 @@ export interface AnimationControls {
|
|
|
12
12
|
|
|
13
13
|
export function validateTransition(t: Transition): void {
|
|
14
14
|
if (t.type === 'spring' && (t.duration !== undefined || t.ease !== undefined)) {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
throw new Error('motion: physical springs do not accept duration or ease')
|
|
16
|
+
}
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
const allowed = [
|
|
19
19
|
'type',
|
|
20
20
|
'duration',
|
|
21
21
|
'delay',
|
package/src/presence-input.ts
CHANGED
|
@@ -15,12 +15,19 @@ export function blockInput(node: any): () => void {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
node.isUserInteractionEnabled = false
|
|
18
|
-
if (node.ios) {
|
|
18
|
+
if (node.ios) {
|
|
19
|
+
node.ios.accessibilityElementsHidden = true
|
|
20
|
+
}
|
|
21
|
+
|
|
19
22
|
node.android?.setImportantForAccessibility?.(4) // IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
|
|
20
23
|
return () => {
|
|
21
24
|
node.isUserInteractionEnabled = enabled
|
|
22
|
-
if (node.ios) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
if (node.ios) {
|
|
26
|
+
node.ios.accessibilityElementsHidden = iosHidden
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (androidImportance !== undefined) {
|
|
30
|
+
node.android?.setImportantForAccessibility?.(androidImportance)
|
|
31
|
+
}
|
|
25
32
|
}
|
|
26
33
|
}
|
|
@@ -3,14 +3,23 @@ export function blockInput(node: HTMLElement): () => void {
|
|
|
3
3
|
const hidden = node.getAttribute('aria-hidden')
|
|
4
4
|
const pointerEvents = node.style.pointerEvents
|
|
5
5
|
const focused = node.ownerDocument.activeElement as HTMLElement | null
|
|
6
|
-
if (focused && node.contains(focused)) {
|
|
6
|
+
if (focused && node.contains(focused)) {
|
|
7
|
+
focused.blur()
|
|
8
|
+
}
|
|
9
|
+
|
|
7
10
|
node.setAttribute('inert', '')
|
|
8
11
|
node.setAttribute('aria-hidden', 'true')
|
|
9
12
|
node.style.pointerEvents = 'none'
|
|
10
13
|
return () => {
|
|
11
|
-
if (!inert) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
if (!inert) {
|
|
15
|
+
node.removeAttribute('inert')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (hidden === null) {
|
|
19
|
+
node.removeAttribute('aria-hidden')
|
|
20
|
+
} else {
|
|
21
|
+
node.setAttribute('aria-hidden', hidden)
|
|
22
|
+
}
|
|
14
23
|
|
|
15
24
|
node.style.pointerEvents = pointerEvents
|
|
16
25
|
}
|
package/src/presence-state.ts
CHANGED
|
@@ -20,7 +20,10 @@ export class PresenceState {
|
|
|
20
20
|
) {}
|
|
21
21
|
register(member: PresenceMember): () => void {
|
|
22
22
|
this.members.add(member)
|
|
23
|
-
if (!this.present) {
|
|
23
|
+
if (!this.present) {
|
|
24
|
+
this.restart(member)
|
|
25
|
+
}
|
|
26
|
+
|
|
24
27
|
return () => {
|
|
25
28
|
this.members.delete(member)
|
|
26
29
|
this.pending.delete(member)
|
|
@@ -28,26 +31,43 @@ export class PresenceState {
|
|
|
28
31
|
}
|
|
29
32
|
}
|
|
30
33
|
setPresent(present: boolean) {
|
|
31
|
-
if (this.disposed || present === this.present) {
|
|
34
|
+
if (this.disposed || present === this.present) {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
32
38
|
this.present = present
|
|
33
39
|
++this.generation
|
|
34
40
|
this.removed = false
|
|
35
41
|
this.pending.clear()
|
|
36
42
|
if (present) {
|
|
37
|
-
for (const member of this.members) {
|
|
43
|
+
for (const member of this.members) {
|
|
44
|
+
member.enter()
|
|
45
|
+
}
|
|
38
46
|
} else {
|
|
39
|
-
for (const member of this.members) {
|
|
47
|
+
for (const member of this.members) {
|
|
48
|
+
this.restart(member)
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
this.check()
|
|
41
52
|
}
|
|
42
53
|
}
|
|
43
54
|
restart(member: PresenceMember) {
|
|
44
|
-
if (this.disposed || this.present || !this.members.has(member)) {
|
|
55
|
+
if (this.disposed || this.present || !this.members.has(member)) {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
45
59
|
const token = ++this.sequence
|
|
46
60
|
this.pending.set(member, token)
|
|
47
61
|
void member.exit().then((result) => {
|
|
48
|
-
if (this.disposed || this.present || this.pending.get(member) !== token) {
|
|
62
|
+
if (this.disposed || this.present || this.pending.get(member) !== token) {
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
49
66
|
// Replacement is owned by the next restart. Cancellation cannot remove a live subtree.
|
|
50
|
-
if (result !== 'finished') {
|
|
67
|
+
if (result !== 'finished') {
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
51
71
|
this.pending.delete(member)
|
|
52
72
|
this.check()
|
|
53
73
|
})
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { MotionValue } from './value'
|
|
1
|
+
import type { View, Row, Pressable } from '@octane-xplat/ui'
|
|
2
|
+
import type { MotionValue } from './value.js'
|
|
3
|
+
|
|
4
|
+
type ViewProps = Parameters<typeof View>[0]
|
|
5
|
+
type RowProps = Parameters<typeof Row>[0]
|
|
6
|
+
type PressableProps = Parameters<typeof Pressable>[0]
|
|
3
7
|
|
|
4
8
|
/** Supported channels. Translation is CSS pixels/DIP; rotation is degrees. */
|
|
5
9
|
export type MotionKey = 'opacity' | 'x' | 'y' | 'scale' | 'scaleX' | 'scaleY' | 'rotate'
|
package/src/value.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Clock } from './clock-types'
|
|
2
|
-
import type { Transition } from './types'
|
|
3
|
-
import { runAnimation, validateTransition, type AnimationControls } from './engine'
|
|
1
|
+
import type { Clock } from './clock-types.js'
|
|
2
|
+
import type { Transition } from './types.js'
|
|
3
|
+
import { runAnimation, validateTransition, type AnimationControls } from './engine.js'
|
|
4
4
|
|
|
5
5
|
/** Events supported by numeric motion values. */
|
|
6
6
|
export interface MotionValueEvents {
|
package/types/engine.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Clock } from './clock-types';
|
|
2
|
-
import type { Transition } from './types';
|
|
1
|
+
import type { Clock } from './clock-types.js';
|
|
2
|
+
import type { Transition } from './types.js';
|
|
3
3
|
/** Terminal status; cancellation never masquerades as completion. */
|
|
4
4
|
export type AnimationResult = 'finished' | 'cancelled' | 'replaced';
|
|
5
5
|
/** A cancellable animation whose finished promise always settles. */
|
package/types/index.d.ts
CHANGED
|
@@ -5,14 +5,16 @@ import type {
|
|
|
5
5
|
MotionPressableProps,
|
|
6
6
|
MotionConfigProps,
|
|
7
7
|
Transition,
|
|
8
|
-
} from './types'
|
|
9
|
-
|
|
8
|
+
} from './types.js'
|
|
9
|
+
|
|
10
|
+
import type { MotionValue, MotionValueEvents } from './value.js'
|
|
10
11
|
/** Bounded motion hosts for shared xplat UI primitives. */
|
|
11
12
|
export declare const motion: {
|
|
12
13
|
View: UniversalComponent<MotionViewProps>
|
|
13
14
|
Row: UniversalComponent<MotionRowProps>
|
|
14
15
|
Pressable: UniversalComponent<MotionPressableProps>
|
|
15
16
|
}
|
|
17
|
+
|
|
16
18
|
/** Inherit transition and reduced-motion defaults within this root. */
|
|
17
19
|
export declare const MotionConfig: UniversalComponent<MotionConfigProps>
|
|
18
20
|
/** Observe the live system reduced-motion preference. */
|
|
@@ -25,6 +27,7 @@ export declare function useMotionValueEvent<K extends keyof MotionValueEvents>(
|
|
|
25
27
|
event: K,
|
|
26
28
|
callback: MotionValueEvents[K],
|
|
27
29
|
): void
|
|
30
|
+
|
|
28
31
|
/** Derive a numeric value by mapping ranges or transforming source samples. */
|
|
29
32
|
export declare function useTransform(
|
|
30
33
|
source: MotionValue,
|
|
@@ -32,22 +35,26 @@ export declare function useTransform(
|
|
|
32
35
|
output: number[],
|
|
33
36
|
options?: { clamp?: boolean },
|
|
34
37
|
): MotionValue
|
|
38
|
+
|
|
35
39
|
export declare function useTransform(
|
|
36
40
|
source: MotionValue,
|
|
37
41
|
transform: (value: number) => number,
|
|
38
42
|
): MotionValue
|
|
43
|
+
|
|
39
44
|
export declare function useTransform(
|
|
40
45
|
source: MotionValue[],
|
|
41
46
|
transform: (values: number[]) => number,
|
|
42
47
|
): MotionValue
|
|
48
|
+
|
|
43
49
|
/** Spring toward set targets or a source MotionValue; jump snaps. */
|
|
44
50
|
export declare function useSpring(
|
|
45
51
|
source: number | MotionValue,
|
|
46
52
|
options?: Omit<Transition, 'type' | 'duration' | 'ease' | 'delay'>,
|
|
47
53
|
): MotionValue
|
|
54
|
+
|
|
48
55
|
export type { MotionValue, MotionValueEvents }
|
|
49
|
-
export type { AnimationControls, AnimationResult } from './engine'
|
|
50
|
-
export type * from './types'
|
|
56
|
+
export type { AnimationControls, AnimationResult } from './engine.js'
|
|
57
|
+
export type * from './types.js'
|
|
51
58
|
|
|
52
59
|
/** Retain live children through exit; removing the boundary disposes immediately. */
|
|
53
|
-
export declare const Presence: UniversalComponent<import('./types').PresenceProps>
|
|
60
|
+
export declare const Presence: UniversalComponent<import('./types.js').PresenceProps>
|
package/types/types.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { MotionValue } from './value';
|
|
1
|
+
import type { View, Row, Pressable } from '@octane-xplat/ui';
|
|
2
|
+
import type { MotionValue } from './value.js';
|
|
3
|
+
type ViewProps = Parameters<typeof View>[0];
|
|
4
|
+
type RowProps = Parameters<typeof Row>[0];
|
|
5
|
+
type PressableProps = Parameters<typeof Pressable>[0];
|
|
3
6
|
/** Supported channels. Translation is CSS pixels/DIP; rotation is degrees. */
|
|
4
7
|
export type MotionKey = 'opacity' | 'x' | 'y' | 'scale' | 'scaleX' | 'scaleY' | 'rotate';
|
|
5
8
|
/** Absolute numeric destinations; omitted channels retain their current values. */
|
|
@@ -49,3 +52,4 @@ export interface PresenceProps extends ViewProps {
|
|
|
49
52
|
/** Called once after all registered exits finish, never after reversal/disposal. */
|
|
50
53
|
onExitComplete?: () => void;
|
|
51
54
|
}
|
|
55
|
+
export {};
|
package/types/value.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Clock } from './clock-types';
|
|
2
|
-
import type { Transition } from './types';
|
|
3
|
-
import { type AnimationControls } from './engine';
|
|
1
|
+
import type { Clock } from './clock-types.js';
|
|
2
|
+
import type { Transition } from './types.js';
|
|
3
|
+
import { type AnimationControls } from './engine.js';
|
|
4
4
|
/** Events supported by numeric motion values. */
|
|
5
5
|
export interface MotionValueEvents {
|
|
6
6
|
change: (value: number) => void;
|