@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 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, opacity may animate |
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
- Physical iOS/Android interruption, cancellation, gesture velocity/arbitration,
59
- background/resume, and frame pacing are pending. Native system preference
60
- observation polls at 500 ms while subscribed and refreshes on resume; Android
61
- uses animator_duration_scale. Real-device accessibility behavior remains pending.
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`.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 1,
3
- "buildId": "94107006-b597-4968-a144-f6d341177465",
3
+ "buildId": "f3ab3f25-9a1e-4436-9723-a402e32f5c04",
4
4
  "mode": "production",
5
5
  "capabilities": {
6
6
  "independentHydration": false
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 1,
3
- "buildId": "e19c4c64-edd7-4cd8-a1e3-a06e64a02fec",
3
+ "buildId": "fcb6bc74-25e4-4f8e-af58-42140062b9cd",
4
4
  "mode": "production",
5
5
  "capabilities": {
6
6
  "independentHydration": false
package/package.json CHANGED
@@ -1,26 +1,26 @@
1
1
  {
2
2
  "name": "@octane-xplat/motion",
3
- "version": "0.7.2",
3
+ "version": "0.9.0",
4
4
  "description": "Declarative motion and retained presence for Octane on web, iOS and Android",
5
5
  "keywords": [
6
- "octane",
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
- "ios",
16
- "android",
17
- "web"
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": "git+https://github.com/octane-xplat/octane-xplat.git",
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.7.2",
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.1",
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 && tsc -p tsconfig.types.json",
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 id="native" initial={{ x: 10 }} animate={{ x: props.x }} transition={{ duration: 20 }} />
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 through universal context and props', () => {
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
- root.render(NativeBox, { x: 50 })
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
- flushUniversalSync(() => root.render(NativeBox, { x: 80 }))
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={{ duration: 10 }} /></MotionConfig>
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={{ duration: 10 }} /></MotionConfig>
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', () => {
@@ -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
- throw new Error('motion: physical springs do not accept duration or ease')
16
- }
15
+ throw new Error('motion: physical springs do not accept duration or ease')
16
+ }
17
17
 
18
- const allowed = [
18
+ const allowed = [
19
19
  'type',
20
20
  'duration',
21
21
  'delay',
@@ -15,12 +15,19 @@ export function blockInput(node: any): () => void {
15
15
  }
16
16
 
17
17
  node.isUserInteractionEnabled = false
18
- if (node.ios) {node.ios.accessibilityElementsHidden = true}
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) {node.ios.accessibilityElementsHidden = iosHidden}
23
- if (androidImportance !== undefined)
24
- {node.android?.setImportantForAccessibility?.(androidImportance)}
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)) {focused.blur()}
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) {node.removeAttribute('inert')}
12
- if (hidden === null) {node.removeAttribute('aria-hidden')}
13
- else {node.setAttribute('aria-hidden', hidden)}
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
  }
@@ -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) {this.restart(member)}
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) {return}
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) {member.enter()}
43
+ for (const member of this.members) {
44
+ member.enter()
45
+ }
38
46
  } else {
39
- for (const member of this.members) {this.restart(member)}
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)) {return}
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) {return}
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') {return}
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 { ViewProps, RowProps, PressableProps } from '@octane-xplat/ui'
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
- import type { MotionValue, MotionValueEvents } from './value'
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 { ViewProps, RowProps, PressableProps } from '@octane-xplat/ui';
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;