@unrulysystems/native-motion 0.1.0-alpha.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/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +55 -0
- package/android/build.gradle +24 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/com/unrulysystems/nativemotion/GestureExclusionModule.kt +55 -0
- package/android/src/main/java/com/unrulysystems/nativemotion/NativeMotionPackage.kt +27 -0
- package/package.json +57 -0
- package/react-native.config.js +14 -0
- package/src/native/driver/instantWindow.ts +31 -0
- package/src/native/driver/strictModeReplay.ts +20 -0
- package/src/native/driver/uiLayoutEngine.ts +845 -0
- package/src/native/driver/uiLayoutGraph.ts +338 -0
- package/src/native/driver/uiValueChannel.ts +4640 -0
- package/src/native/driver/workletDriver.ts +3860 -0
- package/src/native/motion/AnimatePresence.tsx +1605 -0
- package/src/native/motion/LayoutGroup.tsx +163 -0
- package/src/native/motion/MotionConfig.tsx +400 -0
- package/src/native/motion/MotionRoot.tsx +250 -0
- package/src/native/motion/MotionView.tsx +6761 -0
- package/src/native/motion/addScaleCorrector.ts +97 -0
- package/src/native/motion/colorEndpointUiFeed.ts +32 -0
- package/src/native/motion/colorProjection.ts +39 -0
- package/src/native/motion/composeTransform.ts +271 -0
- package/src/native/motion/constraintMeasure.ts +157 -0
- package/src/native/motion/deferredPendingSnapshots.ts +25 -0
- package/src/native/motion/discreteProjection.ts +36 -0
- package/src/native/motion/dragAncestorPanContext.ts +28 -0
- package/src/native/motion/dragControls.ts +152 -0
- package/src/native/motion/dragGestureWiring.ts +1168 -0
- package/src/native/motion/dragHandoffBinding.ts +179 -0
- package/src/native/motion/dragHubStream.ts +756 -0
- package/src/native/motion/dragPropagationLock.ts +57 -0
- package/src/native/motion/driverValueChannel.ts +3288 -0
- package/src/native/motion/externalDragDriver.ts +214 -0
- package/src/native/motion/frameData.ts +31 -0
- package/src/native/motion/gestureBinding.ts +107 -0
- package/src/native/motion/gestureStateGate.ts +563 -0
- package/src/native/motion/gestureStateResolver.ts +286 -0
- package/src/native/motion/identityValueChannelControllerAdapter.ts +2043 -0
- package/src/native/motion/identityValueChannelControllerReconciliation.ts +176 -0
- package/src/native/motion/identityValueChannelLaneMarker.ts +14 -0
- package/src/native/motion/imperativeAnimate.ts +816 -0
- package/src/native/motion/keyframeTiming.ts +7 -0
- package/src/native/motion/layoutIdBinding.ts +261 -0
- package/src/native/motion/layoutIdFlightConfig.ts +51 -0
- package/src/native/motion/layoutProjection.ts +89 -0
- package/src/native/motion/layoutScroll.ts +204 -0
- package/src/native/motion/layoutTransition.ts +1302 -0
- package/src/native/motion/lengthLayoutContext.tsx +100 -0
- package/src/native/motion/lengthLayoutHost.ts +44 -0
- package/src/native/motion/mappedKeys.ts +184 -0
- package/src/native/motion/motionViewController.ts +3180 -0
- package/src/native/motion/nativeHostMarker.ts +22 -0
- package/src/native/motion/panSessionWiring.ts +127 -0
- package/src/native/motion/pathTransition.ts +101 -0
- package/src/native/motion/popLayout.ts +176 -0
- package/src/native/motion/presenceBinding.ts +382 -0
- package/src/native/motion/scaleCorrectorRegistry.ts +123 -0
- package/src/native/motion/scrollValues.ts +260 -0
- package/src/native/motion/serializablePayload.ts +151 -0
- package/src/native/motion/severity.ts +16 -0
- package/src/native/motion/shippedSurface.ts +843 -0
- package/src/native/motion/staticLengthGate.ts +86 -0
- package/src/native/motion/styleBaseGate.ts +72 -0
- package/src/native/motion/styleValueBinding.ts +657 -0
- package/src/native/motion/systemGestureExclusion.ts +61 -0
- package/src/native/motion/tapGestureWiring.ts +215 -0
- package/src/native/motion/transformOrder.ts +38 -0
- package/src/native/motion/transformStringBinding.ts +200 -0
- package/src/native/motion/transformTemplateGate.ts +45 -0
- package/src/native/motion/transitionGate.ts +435 -0
- package/src/native/motion/useAnimate.ts +52 -0
- package/src/native/motion/useCycle.ts +44 -0
- package/src/native/motion/useInstantTransition.ts +68 -0
- package/src/native/motion/useReducedMotion.ts +58 -0
- package/src/native/motion/useScroll.ts +162 -0
- package/src/native/motion/useViewportScroll.ts +29 -0
- package/src/native/motion/valueChannel.ts +7121 -0
- package/src/native/motion/valueHooks.ts +901 -0
- package/src/native/motion/variantChildRegistry.ts +67 -0
- package/src/native/motion/variantContext.tsx +172 -0
- package/src/native/motion/variantProps.ts +598 -0
- package/src/native.ts +159 -0
- package/src/verification/harnessMetrics.ts +78 -0
- package/src/verification/probe/LayoutIdentityWorkletProbe.tsx +251 -0
- package/src/verification/probe/WorkletParityProbe.tsx +162 -0
- package/src/verification/probe/layoutIdentityProbeEngine.ts +429 -0
- package/src/verification/screens/ArcPathChecksScreen.tsx +273 -0
- package/src/verification/screens/BooleanAnimateChecksScreen.tsx +358 -0
- package/src/verification/screens/ChoreographyGalleryScreen.tsx +1010 -0
- package/src/verification/screens/ColorBindingChecksScreen.tsx +568 -0
- package/src/verification/screens/CompletionChecksScreen.tsx +294 -0
- package/src/verification/screens/ConformanceScreen.tsx +573 -0
- package/src/verification/screens/ContentionProbeScreen.tsx +224 -0
- package/src/verification/screens/DriverSmokeScreen.tsx +99 -0
- package/src/verification/screens/DurationOnlyTweenChecksScreen.tsx +294 -0
- package/src/verification/screens/DynamicDragConfigChecksScreen.tsx +237 -0
- package/src/verification/screens/FrameDataChecksScreen.tsx +252 -0
- package/src/verification/screens/GestureChecksScreen.tsx +685 -0
- package/src/verification/screens/InstantTransitionChecksScreen.tsx +839 -0
- package/src/verification/screens/LayoutAnimationStartChecksScreen.tsx +648 -0
- package/src/verification/screens/LayoutChecksScreen.tsx +822 -0
- package/src/verification/screens/LayoutCommitSpikeScreen.tsx +142 -0
- package/src/verification/screens/MotionViewChecksScreen.tsx +930 -0
- package/src/verification/screens/PresenceChecksScreen.tsx +614 -0
- package/src/verification/screens/ReducedMotionChecksScreen.tsx +614 -0
- package/src/verification/screens/RestThresholdChecksScreen.tsx +634 -0
- package/src/verification/screens/ScaleCorrectorChecksScreen.tsx +425 -0
- package/src/verification/screens/SharedLayoutContinuityChecksScreen.tsx +338 -0
- package/src/verification/screens/SharedLayoutCrossfadeChecksScreen.tsx +425 -0
- package/src/verification/screens/TransitionDefaultSelectionChecksScreen.tsx +514 -0
- package/src/verification/screens/ViewportScrollAliasChecksScreen.tsx +303 -0
- package/src/verification/screens/conformanceBanner.ts +21 -0
- package/src/verification/screens/proofConsoleTap.ts +18 -0
- package/src/verification.ts +47 -0
- package/src/web.ts +98 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# @unrulysystems/native-motion
|
|
2
|
+
|
|
3
|
+
## 0.1.0-alpha.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Initial alpha prerelease: the M3-era public surface (layout, presence, drag, gestures, variants,
|
|
8
|
+
orchestration, value types) with the cross-engine conformance suite published alongside the
|
|
9
|
+
runtime packages.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
- @unrulysystems/native-motion-core@0.1.0-alpha.0
|
|
15
|
+
- @unrulysystems/native-motion-web@0.1.0-alpha.0
|
|
16
|
+
- @unrulysystems/native-motion-conformance@0.1.0-alpha.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Unruly Systems LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# @unrulysystems/native-motion
|
|
2
|
+
|
|
3
|
+
The single public import (REQ-UNIVERSAL-001): one specifier resolving to two engine entries —
|
|
4
|
+
AND, since the dogfood extraction (`specs/DOGFOOD-MIGRATION-BUILD-PACKET.md`), the home of the
|
|
5
|
+
native runtime itself.
|
|
6
|
+
|
|
7
|
+
- `src/web.ts` — `'use client'`, an EXPLICIT re-export of the universal surface from the web
|
|
8
|
+
engine (`@unrulysystems/native-motion-web`); web-internal helpers stay out of the namespace.
|
|
9
|
+
- `src/native.ts` — the native runtime entry: the universal surface (`View`, `ViewProps`, `Text`,
|
|
10
|
+
`TextProps`, `Image`, `ImageProps`, `AnimatePresence` (+ pin-catalog `onRest` alias of
|
|
11
|
+
`onExitComplete`), `usePresence`, `useIsPresent`, `MotionRoot`, `MotionRootProps`,
|
|
12
|
+
`MotionLengthLayoutProvider` (parent/viewport geometry for measure-resolved `%`/`calc`),
|
|
13
|
+
`LayoutScrollOffsetProvider` + `recordLayoutScrollOffsetFromEvent` /
|
|
14
|
+
`createLayoutScrollOffsetRef` (REQ-LAYOUT-022(c) live container-scroll feed), `DragInfo` + the
|
|
15
|
+
canonical core types) over the engine in `src/native/{driver,motion}` (the worklet driver, the
|
|
16
|
+
bindings, the UI-thread layout-identity engine). `View`, `Text`, and `Image` share the FLAG 5a
|
|
17
|
+
drag family (`drag` (`'x' | 'y' | true` — both-axes ships at R15 D1, REQ-API-041),
|
|
18
|
+
`dragConstraints`, `dragElastic`, `dragSnapPoints`, `dragPropagation` (Motion's nested-drag
|
|
19
|
+
lock, R15 D1),
|
|
20
|
+
`onDragStart`/`onDrag`/`onDragEnd`), the FLAG 5b layout family (`layout`, `layoutId`,
|
|
21
|
+
`layoutScroll`), and distinct property/layout lifecycle callbacks (`onAnimationComplete`,
|
|
22
|
+
`onLayoutAnimationStart`, `onLayoutAnimationComplete`); `Text` accepts ordinary React Native
|
|
23
|
+
text children while `Image`
|
|
24
|
+
is childless and requires a valid `source`. Text's universal `as="p" | "span"` selector is
|
|
25
|
+
validated on native (nested Text accepts only `span`, preventing a divergent invalid text tree)
|
|
26
|
+
even though RN has no DOM display-mode split; the web entry uses it to preserve a catalog
|
|
27
|
+
paragraph/inline choice. `MotionRoot` owns the gesture recognizer root (a gesture-carrying host
|
|
28
|
+
outside it fails loud). Capabilities the native surface has not pulled yet are absent —
|
|
29
|
+
premature use is a build error, never a stub. The host element set is CLOSED at these three RN
|
|
30
|
+
leaf primitives (ratified 2026-07-22, BRIEF Decisions): container classes adjudicate to `View`,
|
|
31
|
+
controls animate through a `View` wrapper, and `motion.create` stays internal-only.
|
|
32
|
+
- `src/verification.ts` — the engine's intrinsic verification harness (probes, deterministic
|
|
33
|
+
check screens, the choreography gallery). SHELL-ONLY by law: the proof-harness app shell
|
|
34
|
+
mounts it; it is never part of a consumer example (REQ-EXHARNESS-010).
|
|
35
|
+
|
|
36
|
+
## Dual skew-checked resolution (the ratified architecture)
|
|
37
|
+
|
|
38
|
+
The manifest ships BOTH resolution mechanisms — the `exports` `react-native` condition (newer
|
|
39
|
+
Metro) AND the top-level `react-native` field (older Metro floor) — and two guards keep them
|
|
40
|
+
from ever disagreeing:
|
|
41
|
+
|
|
42
|
+
1. `scripts/check-resolution-skew.mjs` (wired into `nub run check`): asserts the condition and
|
|
43
|
+
the field point at the same file, that `browser`/`import`/`default` agree and differ from
|
|
44
|
+
the native entry, and that both entries exist on disk.
|
|
45
|
+
2. `src/resolution.test.ts`: resolves the export map with `resolve.exports` — react-native →
|
|
46
|
+
native, browser/import/default → web, no engine-mixing fall-through.
|
|
47
|
+
|
|
48
|
+
Type identity across entries is a COMPILE-TIME gate: `src/type-identity.keys.ts` fails
|
|
49
|
+
`nub run typecheck` if a native value export is absent on web while allowing intentional pinned
|
|
50
|
+
Motion additions to the web namespace. `src/type-identity.assert.ts` fails if the universal View-,
|
|
51
|
+
Text-, and Image-prop subsets (`initial`/`animate`/`exit`/`transition`/`onAnimationComplete`/
|
|
52
|
+
`onLayoutAnimationStart`/`onLayoutAnimationComplete`/`layout`/`layoutId`) or the pinned
|
|
53
|
+
AnimatePresence props stop being
|
|
54
|
+
structurally identical, or if the presence-hook signatures drift from the pinned `motion/react`
|
|
55
|
+
shapes (portable across test runners because it is not a test at all).
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
apply plugin: 'com.android.library'
|
|
2
|
+
apply plugin: 'org.jetbrains.kotlin.android'
|
|
3
|
+
|
|
4
|
+
android {
|
|
5
|
+
namespace 'com.unrulysystems.nativemotion'
|
|
6
|
+
compileSdk 36
|
|
7
|
+
|
|
8
|
+
defaultConfig {
|
|
9
|
+
minSdk 24
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
compileOptions {
|
|
13
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
14
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
kotlinOptions {
|
|
18
|
+
jvmTarget = '17'
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
dependencies {
|
|
23
|
+
implementation 'com.facebook.react:react-android'
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
package com.unrulysystems.nativemotion
|
|
2
|
+
|
|
3
|
+
import android.graphics.Rect
|
|
4
|
+
import android.os.Build
|
|
5
|
+
import android.view.View
|
|
6
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
7
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
8
|
+
import com.facebook.react.bridge.ReactMethod
|
|
9
|
+
import com.facebook.react.fabric.FabricUIManager
|
|
10
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
11
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
12
|
+
import com.facebook.react.uimanager.common.UIManagerType
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* REQ-GESTURE-032 — Android drag surfaces tell the system *this drag is mine*.
|
|
16
|
+
*
|
|
17
|
+
* `View.setSystemGestureExclusionRects` is the host API; Motion does not have an equivalent
|
|
18
|
+
* because web has no edge-back strip. Mapping: no-op on web and on API < 29. Not a public
|
|
19
|
+
* prop — a drag host registers its own bounds automatically.
|
|
20
|
+
*/
|
|
21
|
+
@ReactModule(name = GestureExclusionModule.NAME)
|
|
22
|
+
class GestureExclusionModule(
|
|
23
|
+
private val reactContext: ReactApplicationContext,
|
|
24
|
+
) : ReactContextBaseJavaModule(reactContext) {
|
|
25
|
+
override fun getName(): String = NAME
|
|
26
|
+
|
|
27
|
+
@ReactMethod
|
|
28
|
+
fun excludeView(viewTag: Double) {
|
|
29
|
+
applyOnView(viewTag.toInt()) { view ->
|
|
30
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return@applyOnView
|
|
31
|
+
view.systemGestureExclusionRects = listOf(Rect(0, 0, view.width, view.height))
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@ReactMethod
|
|
36
|
+
fun clearView(viewTag: Double) {
|
|
37
|
+
applyOnView(viewTag.toInt()) { view ->
|
|
38
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return@applyOnView
|
|
39
|
+
view.systemGestureExclusionRects = emptyList()
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private fun applyOnView(tag: Int, block: (View) -> Unit) {
|
|
44
|
+
reactContext.runOnUiQueueThread {
|
|
45
|
+
val uiManager =
|
|
46
|
+
UIManagerHelper.getUIManager(reactContext, UIManagerType.FABRIC) as? FabricUIManager
|
|
47
|
+
val view = uiManager?.resolveView(tag) ?: return@runOnUiQueueThread
|
|
48
|
+
block(view)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
companion object {
|
|
53
|
+
const val NAME = "NativeMotionGestureExclusion"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
package com.unrulysystems.nativemotion
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.BaseReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.module.model.ReactModuleInfo
|
|
7
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
8
|
+
|
|
9
|
+
class NativeMotionPackage : BaseReactPackage() {
|
|
10
|
+
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? =
|
|
11
|
+
if (name == GestureExclusionModule.NAME) GestureExclusionModule(reactContext) else null
|
|
12
|
+
|
|
13
|
+
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider =
|
|
14
|
+
ReactModuleInfoProvider {
|
|
15
|
+
mapOf(
|
|
16
|
+
GestureExclusionModule.NAME to
|
|
17
|
+
ReactModuleInfo(
|
|
18
|
+
GestureExclusionModule.NAME,
|
|
19
|
+
GestureExclusionModule::class.java.name,
|
|
20
|
+
false,
|
|
21
|
+
false,
|
|
22
|
+
false,
|
|
23
|
+
false,
|
|
24
|
+
),
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@unrulysystems/native-motion",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"files": [
|
|
6
|
+
"src",
|
|
7
|
+
"CHANGELOG.md",
|
|
8
|
+
"android/build.gradle",
|
|
9
|
+
"android/src",
|
|
10
|
+
"react-native.config.js",
|
|
11
|
+
"!src/**/*.test.*",
|
|
12
|
+
"!src/**/*.assert.ts",
|
|
13
|
+
"!src/type-identity.keys.ts",
|
|
14
|
+
"!src/**/*Fixtures.ts",
|
|
15
|
+
"!src/native/motion/reactNativeRequireStub.ts"
|
|
16
|
+
],
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "./src/web.ts",
|
|
19
|
+
"react-native": "./src/native.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"react-native": "./src/native.ts",
|
|
23
|
+
"browser": "./src/web.ts",
|
|
24
|
+
"import": "./src/web.ts",
|
|
25
|
+
"default": "./src/web.ts"
|
|
26
|
+
},
|
|
27
|
+
"./driver-mapped-keys": "./src/native/motion/mappedKeys.ts",
|
|
28
|
+
"./native-public-surface": "./src/native/motion/shippedSurface.ts",
|
|
29
|
+
"./verification": "./src/verification.ts"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"test": "vitest run"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@unrulysystems/native-motion-conformance": "0.1.0-alpha.0",
|
|
36
|
+
"@unrulysystems/native-motion-core": "0.1.0-alpha.0",
|
|
37
|
+
"@unrulysystems/native-motion-web": "0.1.0-alpha.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@babel/core": "^7.29.7",
|
|
41
|
+
"@types/babel__core": "^7.20.5",
|
|
42
|
+
"@types/node": "^24.0.0",
|
|
43
|
+
"@types/react-dom": "^19",
|
|
44
|
+
"motion": "12.42.2",
|
|
45
|
+
"motion-dom": "12.42.2",
|
|
46
|
+
"react-dom": "19.2.3",
|
|
47
|
+
"resolve.exports": "^2.0.3",
|
|
48
|
+
"vitest": "^4.1.9"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"react": "*",
|
|
52
|
+
"react-native": "*",
|
|
53
|
+
"react-native-gesture-handler": ">=2.28.0",
|
|
54
|
+
"react-native-reanimated": ">=4.1.0",
|
|
55
|
+
"react-native-worklets": ">=0.5.0"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// The mobile app also lists this package in apps/mobile/react-native.config.js — Expo's
|
|
2
|
+
// RN autolinker does not discover workspace packages from this file alone.
|
|
3
|
+
module.exports = {
|
|
4
|
+
dependency: {
|
|
5
|
+
platforms: {
|
|
6
|
+
android: {
|
|
7
|
+
sourceDir: './android',
|
|
8
|
+
packageImportPath: 'import com.unrulysystems.nativemotion.NativeMotionPackage;',
|
|
9
|
+
packageInstance: 'new NativeMotionPackage()',
|
|
10
|
+
},
|
|
11
|
+
ios: null,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// U7b — the GLOBAL instant-window authority: the `MotionGlobalConfig.instantAnimations`
|
|
2
|
+
// analogue (pin: motion-dom@12.42.2 animation/interfaces/motion-value.ts:100-109). While the
|
|
3
|
+
// window is open, EVERY property-lane animation start on the PRODUCT (worklet) driver — any
|
|
4
|
+
// component — takes the
|
|
5
|
+
// U7a instant commit (skip the generator, final keyframe on the driver's next update tick,
|
|
6
|
+
// completion fires) with `delay` ZEROED. The pin's asymmetry (F2): the authored `type: false`
|
|
7
|
+
// honors a nonzero delay; the global window does not. Reduced motion is orthogonal — never
|
|
8
|
+
// composed here. The reference driver (core's host-agnostic parity oracle) never consults the
|
|
9
|
+
// window by design; the imperative playback lane does not consult it either (U7b review minor
|
|
10
|
+
// — a demand for that class should REFUSE loud there like U7a's `type: false` arm, never
|
|
11
|
+
// silently run full-duration).
|
|
12
|
+
//
|
|
13
|
+
// Plain JS-side module state: the consult happens at JS-side transition resolution
|
|
14
|
+
// (workletDriver's toPlainTransition), before anything crosses to the UI runtime, so the flag
|
|
15
|
+
// never marshals. `useInstantTransition` opens the window and relocks it two post-render frames
|
|
16
|
+
// later under a token guard; `disableInstantTransitions` is the pin's sibling escape hatch for a
|
|
17
|
+
// stuck window.
|
|
18
|
+
|
|
19
|
+
let instantWindowOpen = false
|
|
20
|
+
|
|
21
|
+
export function openInstantWindow(): void {
|
|
22
|
+
instantWindowOpen = true
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function closeInstantWindow(): void {
|
|
26
|
+
instantWindowOpen = false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function isInstantWindowOpen(): boolean {
|
|
30
|
+
return instantWindowOpen
|
|
31
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// REQ-DRIVER-022 StrictMode-replay phase (BRIEF Decisions 2026-07-10, registry-port round 7
|
|
2
|
+
// major 5). React StrictMode's dev-only setup→cleanup→setup effect replay runs the hook's
|
|
3
|
+
// dispose() cleanup and then replays setup against the SAME render-created binding — now
|
|
4
|
+
// disposed. Resurrection (recreate the driver and rebind shared values on replay) is a deferred
|
|
5
|
+
// capability with its own future rung; until it lands the replayed setup fails loud instead of
|
|
6
|
+
// leaving a mounted component holding a permanently disposed binding. RN-free on purpose: the
|
|
7
|
+
// mobile vitest suite pins this contract while the binding itself stays device/e2e territory.
|
|
8
|
+
//
|
|
9
|
+
// Severity law note: StrictMode double-invocation exists only in development builds, so this
|
|
10
|
+
// throw is dev-only by construction — production never reaches the replay phase.
|
|
11
|
+
|
|
12
|
+
export function assertSetupNotReplayedOnDisposed(disposed: boolean): void {
|
|
13
|
+
if (!disposed) return
|
|
14
|
+
throw new Error(
|
|
15
|
+
'useWorkletDriver: this binding was disposed by a StrictMode setup→cleanup→setup effect ' +
|
|
16
|
+
'replay. StrictMode remount replay is a deferred capability — resurrection (recreate the ' +
|
|
17
|
+
'driver and rebind shared values on replay) is its own future rung (BRIEF Decisions ' +
|
|
18
|
+
'2026-07-10; REQ-DRIVER-022). Unwrap this tree from <StrictMode> until that rung lands.',
|
|
19
|
+
)
|
|
20
|
+
}
|