@unrulysystems/native-motion-core 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.
Files changed (326) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +21 -0
  3. package/README.md +48 -0
  4. package/dist/clock.cjs +71 -0
  5. package/dist/clock.d.cts +23 -0
  6. package/dist/clock.d.ts +23 -0
  7. package/dist/clock.js +66 -0
  8. package/dist/collect-reads.cjs +68 -0
  9. package/dist/collect-reads.d.cts +23 -0
  10. package/dist/collect-reads.d.ts +23 -0
  11. package/dist/collect-reads.js +62 -0
  12. package/dist/component/boundedArray.cjs +74 -0
  13. package/dist/component/boundedArray.d.cts +25 -0
  14. package/dist/component/boundedArray.d.ts +25 -0
  15. package/dist/component/boundedArray.js +68 -0
  16. package/dist/component/index.cjs +57 -0
  17. package/dist/component/index.d.cts +12 -0
  18. package/dist/component/index.d.ts +12 -0
  19. package/dist/component/index.js +22 -0
  20. package/dist/component/orchestration.cjs +129 -0
  21. package/dist/component/orchestration.d.cts +66 -0
  22. package/dist/component/orchestration.d.ts +66 -0
  23. package/dist/component/orchestration.js +124 -0
  24. package/dist/component/resolve.cjs +104 -0
  25. package/dist/component/resolve.d.cts +11 -0
  26. package/dist/component/resolve.d.ts +11 -0
  27. package/dist/component/resolve.js +97 -0
  28. package/dist/component/transition.cjs +352 -0
  29. package/dist/component/transition.d.cts +33 -0
  30. package/dist/component/transition.d.ts +33 -0
  31. package/dist/component/transition.js +339 -0
  32. package/dist/component/types.cjs +114 -0
  33. package/dist/component/types.d.cts +60 -0
  34. package/dist/component/types.d.ts +60 -0
  35. package/dist/component/types.js +111 -0
  36. package/dist/component/validate.cjs +1015 -0
  37. package/dist/component/validate.d.cts +37 -0
  38. package/dist/component/validate.d.ts +37 -0
  39. package/dist/component/validate.js +1002 -0
  40. package/dist/component/variants.cjs +333 -0
  41. package/dist/component/variants.d.cts +106 -0
  42. package/dist/component/variants.d.ts +106 -0
  43. package/dist/component/variants.js +321 -0
  44. package/dist/config/constants.cjs +41 -0
  45. package/dist/config/constants.d.cts +29 -0
  46. package/dist/config/constants.d.ts +29 -0
  47. package/dist/config/constants.js +38 -0
  48. package/dist/delay.cjs +72 -0
  49. package/dist/delay.d.cts +26 -0
  50. package/dist/delay.d.ts +26 -0
  51. package/dist/delay.js +70 -0
  52. package/dist/derived.cjs +143 -0
  53. package/dist/derived.d.cts +41 -0
  54. package/dist/derived.d.ts +41 -0
  55. package/dist/derived.js +139 -0
  56. package/dist/driver/index.cjs +22 -0
  57. package/dist/driver/index.d.cts +7 -0
  58. package/dist/driver/index.d.ts +7 -0
  59. package/dist/driver/index.js +14 -0
  60. package/dist/driver/keyframeTiming.cjs +130 -0
  61. package/dist/driver/keyframeTiming.d.cts +18 -0
  62. package/dist/driver/keyframeTiming.d.ts +18 -0
  63. package/dist/driver/keyframeTiming.js +124 -0
  64. package/dist/driver/keyframeTimingConfig.cjs +24 -0
  65. package/dist/driver/keyframeTimingConfig.d.cts +5 -0
  66. package/dist/driver/keyframeTimingConfig.d.ts +5 -0
  67. package/dist/driver/keyframeTimingConfig.js +22 -0
  68. package/dist/driver/prepare.cjs +459 -0
  69. package/dist/driver/prepare.d.cts +4 -0
  70. package/dist/driver/prepare.d.ts +4 -0
  71. package/dist/driver/prepare.js +454 -0
  72. package/dist/driver/reference.cjs +762 -0
  73. package/dist/driver/reference.d.cts +53 -0
  74. package/dist/driver/reference.d.ts +53 -0
  75. package/dist/driver/reference.js +757 -0
  76. package/dist/driver/step.cjs +55 -0
  77. package/dist/driver/step.d.cts +9 -0
  78. package/dist/driver/step.d.ts +9 -0
  79. package/dist/driver/step.js +52 -0
  80. package/dist/driver/tiers.cjs +40 -0
  81. package/dist/driver/tiers.d.cts +2 -0
  82. package/dist/driver/tiers.d.ts +2 -0
  83. package/dist/driver/tiers.js +37 -0
  84. package/dist/driver/types.cjs +9 -0
  85. package/dist/driver/types.d.cts +68 -0
  86. package/dist/driver/types.d.ts +68 -0
  87. package/dist/driver/types.js +8 -0
  88. package/dist/external-animation-ledger.cjs +1250 -0
  89. package/dist/external-animation-ledger.d.cts +416 -0
  90. package/dist/external-animation-ledger.d.ts +416 -0
  91. package/dist/external-animation-ledger.js +1243 -0
  92. package/dist/gesture/directionLock.cjs +25 -0
  93. package/dist/gesture/directionLock.d.cts +8 -0
  94. package/dist/gesture/directionLock.d.ts +8 -0
  95. package/dist/gesture/directionLock.js +21 -0
  96. package/dist/gesture/dragConfig.cjs +634 -0
  97. package/dist/gesture/dragConfig.d.cts +298 -0
  98. package/dist/gesture/dragConfig.d.ts +298 -0
  99. package/dist/gesture/dragConfig.js +624 -0
  100. package/dist/gesture/elastic.cjs +44 -0
  101. package/dist/gesture/elastic.d.cts +4 -0
  102. package/dist/gesture/elastic.d.ts +4 -0
  103. package/dist/gesture/elastic.js +39 -0
  104. package/dist/gesture/handoffSession.cjs +161 -0
  105. package/dist/gesture/handoffSession.d.cts +35 -0
  106. package/dist/gesture/handoffSession.d.ts +35 -0
  107. package/dist/gesture/handoffSession.js +158 -0
  108. package/dist/gesture/index.cjs +37 -0
  109. package/dist/gesture/index.d.cts +12 -0
  110. package/dist/gesture/index.d.ts +12 -0
  111. package/dist/gesture/index.js +11 -0
  112. package/dist/gesture/projection.cjs +95 -0
  113. package/dist/gesture/projection.d.cts +7 -0
  114. package/dist/gesture/projection.d.ts +7 -0
  115. package/dist/gesture/projection.js +87 -0
  116. package/dist/gesture/session.cjs +162 -0
  117. package/dist/gesture/session.d.cts +29 -0
  118. package/dist/gesture/session.d.ts +29 -0
  119. package/dist/gesture/session.js +158 -0
  120. package/dist/gesture/types.cjs +5 -0
  121. package/dist/gesture/types.d.cts +13 -0
  122. package/dist/gesture/types.d.ts +13 -0
  123. package/dist/gesture/types.js +4 -0
  124. package/dist/gesture/viewportConstraints.cjs +38 -0
  125. package/dist/gesture/viewportConstraints.d.cts +6 -0
  126. package/dist/gesture/viewportConstraints.d.ts +6 -0
  127. package/dist/gesture/viewportConstraints.js +34 -0
  128. package/dist/graph.cjs +226 -0
  129. package/dist/graph.d.cts +2 -0
  130. package/dist/graph.d.ts +2 -0
  131. package/dist/graph.js +223 -0
  132. package/dist/index.cjs +140 -0
  133. package/dist/index.d.cts +33 -0
  134. package/dist/index.d.ts +33 -0
  135. package/dist/index.js +70 -0
  136. package/dist/inertia.cjs +214 -0
  137. package/dist/inertia.d.cts +53 -0
  138. package/dist/inertia.d.ts +53 -0
  139. package/dist/inertia.js +212 -0
  140. package/dist/instant.cjs +66 -0
  141. package/dist/instant.d.cts +16 -0
  142. package/dist/instant.d.ts +16 -0
  143. package/dist/instant.js +63 -0
  144. package/dist/internal-driver.cjs +81 -0
  145. package/dist/internal-driver.d.cts +19 -0
  146. package/dist/internal-driver.d.ts +19 -0
  147. package/dist/internal-driver.js +35 -0
  148. package/dist/keyframes.cjs +191 -0
  149. package/dist/keyframes.d.cts +13 -0
  150. package/dist/keyframes.d.ts +13 -0
  151. package/dist/keyframes.js +188 -0
  152. package/dist/layout/commitDetector.cjs +67 -0
  153. package/dist/layout/commitDetector.d.cts +21 -0
  154. package/dist/layout/commitDetector.d.ts +21 -0
  155. package/dist/layout/commitDetector.js +64 -0
  156. package/dist/layout/compose.cjs +67 -0
  157. package/dist/layout/compose.d.cts +30 -0
  158. package/dist/layout/compose.d.ts +30 -0
  159. package/dist/layout/compose.js +65 -0
  160. package/dist/layout/constants.cjs +13 -0
  161. package/dist/layout/constants.d.cts +6 -0
  162. package/dist/layout/constants.d.ts +6 -0
  163. package/dist/layout/constants.js +10 -0
  164. package/dist/layout/identity.cjs +700 -0
  165. package/dist/layout/identity.d.cts +67 -0
  166. package/dist/layout/identity.d.ts +67 -0
  167. package/dist/layout/identity.js +698 -0
  168. package/dist/layout/index.cjs +36 -0
  169. package/dist/layout/index.d.cts +18 -0
  170. package/dist/layout/index.d.ts +18 -0
  171. package/dist/layout/index.js +13 -0
  172. package/dist/layout/measure.cjs +81 -0
  173. package/dist/layout/measure.d.cts +43 -0
  174. package/dist/layout/measure.d.ts +43 -0
  175. package/dist/layout/measure.js +78 -0
  176. package/dist/layout/projection.cjs +99 -0
  177. package/dist/layout/projection.d.cts +23 -0
  178. package/dist/layout/projection.d.ts +23 -0
  179. package/dist/layout/projection.js +97 -0
  180. package/dist/layout/scroll.cjs +27 -0
  181. package/dist/layout/scroll.d.cts +13 -0
  182. package/dist/layout/scroll.d.ts +13 -0
  183. package/dist/layout/scroll.js +24 -0
  184. package/dist/layout/session.cjs +207 -0
  185. package/dist/layout/session.d.cts +73 -0
  186. package/dist/layout/session.d.ts +73 -0
  187. package/dist/layout/session.js +205 -0
  188. package/dist/layout/tree.cjs +826 -0
  189. package/dist/layout/tree.d.cts +70 -0
  190. package/dist/layout/tree.d.ts +70 -0
  191. package/dist/layout/tree.js +823 -0
  192. package/dist/layout/types.cjs +36 -0
  193. package/dist/layout/types.d.cts +31 -0
  194. package/dist/layout/types.d.ts +31 -0
  195. package/dist/layout/types.js +35 -0
  196. package/dist/motion-arc.cjs +184 -0
  197. package/dist/motion-arc.d.cts +78 -0
  198. package/dist/motion-arc.d.ts +78 -0
  199. package/dist/motion-arc.js +183 -0
  200. package/dist/motion-mix.cjs +205 -0
  201. package/dist/motion-mix.d.cts +3 -0
  202. package/dist/motion-mix.d.ts +3 -0
  203. package/dist/motion-mix.js +202 -0
  204. package/dist/motion-value-driver-port.cjs +636 -0
  205. package/dist/motion-value-driver-port.d.cts +406 -0
  206. package/dist/motion-value-driver-port.d.ts +406 -0
  207. package/dist/motion-value-driver-port.js +627 -0
  208. package/dist/motion-value.cjs +189 -0
  209. package/dist/motion-value.d.cts +51 -0
  210. package/dist/motion-value.d.ts +51 -0
  211. package/dist/motion-value.js +185 -0
  212. package/dist/presence/controller.cjs +657 -0
  213. package/dist/presence/controller.d.cts +6 -0
  214. package/dist/presence/controller.d.ts +6 -0
  215. package/dist/presence/controller.js +652 -0
  216. package/dist/presence/index.cjs +19 -0
  217. package/dist/presence/index.d.cts +4 -0
  218. package/dist/presence/index.d.ts +4 -0
  219. package/dist/presence/index.js +12 -0
  220. package/dist/presence/machine.cjs +50 -0
  221. package/dist/presence/machine.d.cts +10 -0
  222. package/dist/presence/machine.d.ts +10 -0
  223. package/dist/presence/machine.js +46 -0
  224. package/dist/presence/types.cjs +6 -0
  225. package/dist/presence/types.d.cts +32 -0
  226. package/dist/presence/types.d.ts +32 -0
  227. package/dist/presence/types.js +5 -0
  228. package/dist/repeat.cjs +311 -0
  229. package/dist/repeat.d.cts +174 -0
  230. package/dist/repeat.d.ts +174 -0
  231. package/dist/repeat.js +300 -0
  232. package/dist/spring.cjs +128 -0
  233. package/dist/spring.d.cts +18 -0
  234. package/dist/spring.d.ts +18 -0
  235. package/dist/spring.js +125 -0
  236. package/dist/subscriptions.cjs +74 -0
  237. package/dist/subscriptions.d.cts +19 -0
  238. package/dist/subscriptions.d.ts +19 -0
  239. package/dist/subscriptions.js +69 -0
  240. package/dist/subset/index.cjs +23 -0
  241. package/dist/subset/index.d.cts +6 -0
  242. package/dist/subset/index.d.ts +6 -0
  243. package/dist/subset/index.js +13 -0
  244. package/dist/subset/normalize.cjs +90 -0
  245. package/dist/subset/normalize.d.cts +10 -0
  246. package/dist/subset/normalize.d.ts +10 -0
  247. package/dist/subset/normalize.js +85 -0
  248. package/dist/subset/registry.cjs +259 -0
  249. package/dist/subset/registry.d.cts +25 -0
  250. package/dist/subset/registry.d.ts +25 -0
  251. package/dist/subset/registry.js +256 -0
  252. package/dist/subset/resolve.cjs +98 -0
  253. package/dist/subset/resolve.d.cts +24 -0
  254. package/dist/subset/resolve.d.ts +24 -0
  255. package/dist/subset/resolve.js +90 -0
  256. package/dist/timing.cjs +206 -0
  257. package/dist/timing.d.cts +17 -0
  258. package/dist/timing.d.ts +17 -0
  259. package/dist/timing.js +201 -0
  260. package/dist/transformTemplate.cjs +219 -0
  261. package/dist/transformTemplate.d.cts +29 -0
  262. package/dist/transformTemplate.d.ts +29 -0
  263. package/dist/transformTemplate.js +215 -0
  264. package/dist/transition.cjs +231 -0
  265. package/dist/transition.d.cts +89 -0
  266. package/dist/transition.d.ts +89 -0
  267. package/dist/transition.js +223 -0
  268. package/dist/types.cjs +4 -0
  269. package/dist/types.d.cts +175 -0
  270. package/dist/types.d.ts +175 -0
  271. package/dist/types.js +3 -0
  272. package/dist/value-types/color.cjs +220 -0
  273. package/dist/value-types/color.d.cts +19 -0
  274. package/dist/value-types/color.d.ts +19 -0
  275. package/dist/value-types/color.js +218 -0
  276. package/dist/value-types/complex.cjs +160 -0
  277. package/dist/value-types/complex.d.cts +19 -0
  278. package/dist/value-types/complex.d.ts +19 -0
  279. package/dist/value-types/complex.js +155 -0
  280. package/dist/value-types/constants.cjs +15 -0
  281. package/dist/value-types/constants.d.cts +6 -0
  282. package/dist/value-types/constants.d.ts +6 -0
  283. package/dist/value-types/constants.js +12 -0
  284. package/dist/value-types/discrete.cjs +62 -0
  285. package/dist/value-types/discrete.d.cts +4 -0
  286. package/dist/value-types/discrete.d.ts +4 -0
  287. package/dist/value-types/discrete.js +56 -0
  288. package/dist/value-types/index.cjs +59 -0
  289. package/dist/value-types/index.d.cts +14 -0
  290. package/dist/value-types/index.d.ts +14 -0
  291. package/dist/value-types/index.js +24 -0
  292. package/dist/value-types/measure-resolve.cjs +325 -0
  293. package/dist/value-types/measure-resolve.d.cts +91 -0
  294. package/dist/value-types/measure-resolve.d.ts +91 -0
  295. package/dist/value-types/measure-resolve.js +313 -0
  296. package/dist/value-types/mix.cjs +90 -0
  297. package/dist/value-types/mix.d.cts +27 -0
  298. package/dist/value-types/mix.d.ts +27 -0
  299. package/dist/value-types/mix.js +85 -0
  300. package/dist/value-types/named-colors.cjs +61 -0
  301. package/dist/value-types/named-colors.d.cts +2 -0
  302. package/dist/value-types/named-colors.d.ts +2 -0
  303. package/dist/value-types/named-colors.js +58 -0
  304. package/dist/value-types/numeric.cjs +86 -0
  305. package/dist/value-types/numeric.d.cts +16 -0
  306. package/dist/value-types/numeric.d.ts +16 -0
  307. package/dist/value-types/numeric.js +79 -0
  308. package/dist/worklet-layout/config/constants.js +39 -0
  309. package/dist/worklet-layout/layout/constants.js +11 -0
  310. package/dist/worklet-layout/layout/identity.js +699 -0
  311. package/dist/worklet-layout/layout/projection.js +98 -0
  312. package/dist/worklet-layout/layout/session.js +206 -0
  313. package/dist/worklet-layout/layout/tree.js +824 -0
  314. package/dist/worklet-layout/layout/types.js +36 -0
  315. package/dist/worklet-layout/spring.js +125 -0
  316. package/dist/worklet-layout/timing.js +201 -0
  317. package/dist/worklet-layout/transition.js +223 -0
  318. package/dist/worklet-layout.cjs +47 -0
  319. package/dist/worklet-layout.d.cts +15 -0
  320. package/dist/worklet-layout.d.ts +15 -0
  321. package/dist/worklet-layout.js +28 -0
  322. package/dist/wrap.cjs +7 -0
  323. package/dist/wrap.d.cts +1 -0
  324. package/dist/wrap.d.ts +1 -0
  325. package/dist/wrap.js +4 -0
  326. package/package.json +45 -0
@@ -0,0 +1,85 @@
1
+ // SPEC-UNIVERSAL-SUBSET §3 — the per-value-type normalizer + epsilon floors (REQ-SUBSET-016). Reduces an
2
+ // engine-native encoding (RN unitless dp number, web `px`/`deg`/`rad` string, any color syntax) to ONE
3
+ // comparable value per value type so the cross-engine comparator compares like for like. It DELEGATES to
4
+ // VALUE-TYPES for every parse and for the epsilon floors — there is exactly one parser and one set of
5
+ // floors in the codebase (REQ-SUBSET-016 "adopted verbatim"); this file re-declares neither.
6
+ import { EPS_ANGLE, EPS_COLOR_CHANNEL, EPS_LENGTH, EPS_UNITLESS } from "../value-types/index.js";
7
+ import { parseColorVerdict } from "../value-types/color.js";
8
+ import { parseNumericVerdict } from "../value-types/numeric.js";
9
+ const DEG_PER_RAD = 180 / Math.PI;
10
+ // The units each numeric value type may carry and still reduce to ONE comparable value. `''` is the
11
+ // engine-native unitless encoding (RN dp for length, a bare scalar for unitless, degrees for angle).
12
+ // length is px + dp ONLY — vw/vh/% are viewport-/parent-relative and NOT px-comparable without a layout
13
+ // context (they are excluded from the guaranteed subset, REQ-SUBSET-011/§8); an angle unit on a length
14
+ // (or vice versa) is a category error. Anything outside the set fails loud rather than being silently
15
+ // reduced to a bare number that would make incompatible encodings compare equal (REQ-SUBSET-016).
16
+ const COMPATIBLE_UNITS = {
17
+ length: new Set(['', 'px']),
18
+ unitless: new Set(['']),
19
+ angle: new Set(['', 'deg', 'rad']),
20
+ };
21
+ const refuseNormalize = (message) => ({
22
+ value: null,
23
+ refusal: new Error(message),
24
+ });
25
+ function scalarVerdict(kind, engineValue) {
26
+ if (typeof engineValue === 'number')
27
+ return { value: engineValue, refusal: null };
28
+ const parsed = parseNumericVerdict(engineValue);
29
+ if (parsed.refusal !== null)
30
+ return refuseNormalize(parsed.refusal);
31
+ const { value, unit } = parsed.parsed;
32
+ if (!COMPATIBLE_UNITS[kind].has(unit)) {
33
+ const allowed = [...COMPATIBLE_UNITS[kind]].map((u) => u || '<unitless>').join(', ');
34
+ return refuseNormalize(`Incompatible unit '${unit}' for a ${kind} value ${JSON.stringify(engineValue)}: it cannot be ` +
35
+ `normalized as ${kind} (compatible units: ${allowed}).`);
36
+ }
37
+ return { value: kind === 'angle' && unit === 'rad' ? value * DEG_PER_RAD : value, refusal: null };
38
+ }
39
+ export function normalizeCapabilityVerdict(entry, engineValue) {
40
+ switch (entry.valueType) {
41
+ case 'length':
42
+ case 'unitless':
43
+ case 'angle':
44
+ return scalarVerdict(entry.valueType, engineValue);
45
+ case 'rgba': {
46
+ const parsed = parseColorVerdict(String(engineValue));
47
+ return parsed.refusal !== null
48
+ ? refuseNormalize(parsed.refusal)
49
+ : { value: parsed.parsed, refusal: null };
50
+ }
51
+ case 'complex':
52
+ case 'gesture':
53
+ case 'discrete':
54
+ // Web-only compositor effects (complex), gestures, and discrete keywords (T23 B — compared
55
+ // by exact keyword equality, never a normalized scalar) have no cross-engine numeric value to
56
+ // compare — asking for one is a caller error, not a silent zero. Fail loud (REQ-SUBSET-014 ethos).
57
+ return refuseNormalize(`Capability '${entry.keys[0]}' (valueType '${entry.valueType}') has no cross-engine ` +
58
+ `normalized value — it is not a comparable animated scalar/color.`);
59
+ }
60
+ return refuseNormalize(`unreachable valueType`);
61
+ }
62
+ export function normalizeCapability(entry, engineValue) {
63
+ const verdict = normalizeCapabilityVerdict(entry, engineValue);
64
+ if (verdict.refusal !== null)
65
+ throw verdict.refusal;
66
+ return verdict.value;
67
+ }
68
+ // The comparison epsilon FLOOR for a value type, imported verbatim from VALUE-TYPES (REQ-SUBSET-016).
69
+ // complex/gesture have no comparison tolerance — requesting one is a loud failure, not a default.
70
+ export function epsilonFor(valueType) {
71
+ switch (valueType) {
72
+ case 'length':
73
+ return EPS_LENGTH;
74
+ case 'unitless':
75
+ return EPS_UNITLESS;
76
+ case 'angle':
77
+ return EPS_ANGLE;
78
+ case 'rgba':
79
+ return EPS_COLOR_CHANNEL;
80
+ case 'complex':
81
+ case 'gesture':
82
+ case 'discrete':
83
+ throw new Error(`valueType '${valueType}' has no comparison epsilon — it is not a cross-engine numeric value.`);
84
+ }
85
+ }
@@ -0,0 +1,259 @@
1
+ "use strict";
2
+ // SPEC-UNIVERSAL-SUBSET §3 — the single frozen, machine-readable universal-subset registry
3
+ // (REQ-SUBSET-010). It is the SOLE source of subset membership: app code, the native runtime, the web
4
+ // shim, and the conformance runner all read this one object; no engine carries a private list. Lives in
5
+ // `core` with ZERO host dependencies (structural isolation gate) — the host-aware Motion-seam canary
6
+ // (REQ-SUBSET-015) and authoring gate (REQ-SUBSET-018) read this registry from `packages/conformance`.
7
+ //
8
+ // Each entry declares every REQ-SUBSET-010 field. Schema completions beyond the spec's illustrative
9
+ // enums, flagged as vetoable (see .rl decision log): the `webEffect` CLASS carries web-only compositor
10
+ // effects (filter/clipPath/boxShadow/gradients) that fit none of transform|opacity|color|layoutProp|
11
+ // gesture; the `gesture` VALUE-TYPE and `complex` VALUE-TYPE fill §5.1's "enum-valid valueType on every
12
+ // entry" for gesture and web-effect entries respectively. Membership + marking follow REQ-SUBSET-011
13
+ // (properties), -012 (gestures), -013 (platform-specific), -015 (web path), -017 (native mapping).
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.UNIVERSAL_SUBSET = void 0;
16
+ // --- entry builders (keep the tables below declarative) --------------------------------------------
17
+ // A universal transform maps to one RN transform-array token and takes the accelerated web path
18
+ // (Motion folds every transform into the composite `transform` string it accelerates via WAAPI).
19
+ function transform(key, token, valueType) {
20
+ return {
21
+ keys: [key],
22
+ class: 'transform',
23
+ universality: 'universal',
24
+ shipping: 'shipped', // the animate pipeline drives every transform today
25
+ referenceDisposition: 'portable-shipped',
26
+ valueType,
27
+ webEnginePath: 'accelerated',
28
+ nativeMapping: token,
29
+ };
30
+ }
31
+ // A universal non-transform property maps to the identically-named RN style field. Opacity is the lone
32
+ // accelerated non-transform; colors + layout props take Motion's JS path (REQ-SUBSET-015).
33
+ function styleProp(key, cls, valueType, webEnginePath) {
34
+ return {
35
+ keys: [key],
36
+ class: cls,
37
+ universality: 'universal',
38
+ shipping: 'shipped', // opacity/colors/layout props all animate today
39
+ referenceDisposition: 'portable-shipped',
40
+ valueType,
41
+ webEnginePath,
42
+ nativeMapping: key,
43
+ };
44
+ }
45
+ // A web-only compositor effect: no faithful native mapping (RN has no per-layer filter/clip/shadow
46
+ // parity), so `unsupported` — but it still records its Motion web path so the canary stays exact and a
47
+ // native use fails loud (REQ-SUBSET-013/-014).
48
+ function webEffect(key, webEnginePath) {
49
+ return {
50
+ keys: [key],
51
+ class: 'webEffect',
52
+ universality: 'web-only',
53
+ shipping: 'deferred',
54
+ referenceDisposition: 'intrinsic-web',
55
+ valueType: 'complex',
56
+ webEnginePath,
57
+ nativeMapping: 'unsupported',
58
+ };
59
+ }
60
+ const RAW_ENTRIES = [
61
+ // Transforms (REQ-SUBSET-011) — accelerated; each folds into the composite `transform`.
62
+ transform('x', 'translateX', 'length'),
63
+ transform('y', 'translateY', 'length'),
64
+ transform('scale', 'scale', 'unitless'),
65
+ transform('scaleX', 'scaleX', 'unitless'),
66
+ transform('scaleY', 'scaleY', 'unitless'),
67
+ transform('rotate', 'rotate', 'angle'),
68
+ transform('rotateX', 'rotateX', 'angle'),
69
+ transform('rotateY', 'rotateY', 'angle'),
70
+ transform('skewX', 'skewX', 'angle'),
71
+ transform('skewY', 'skewY', 'angle'),
72
+ transform('perspective', 'perspective', 'length'),
73
+ // Opacity (REQ-SUBSET-011) — the one accelerated non-transform.
74
+ styleProp('opacity', 'opacity', 'unitless', 'accelerated'),
75
+ // Colors (REQ-SUBSET-011) — JS path (Motion's `background-color` acceleration is disabled at pin).
76
+ styleProp('backgroundColor', 'color', 'rgba', 'js'),
77
+ styleProp('color', 'color', 'rgba', 'js'),
78
+ styleProp('borderColor', 'color', 'rgba', 'js'),
79
+ // Layout props to explicit numeric targets (REQ-SUBSET-011) — JS path, length value type.
80
+ styleProp('width', 'layoutProp', 'length', 'js'),
81
+ styleProp('height', 'layoutProp', 'length', 'js'),
82
+ styleProp('top', 'layoutProp', 'length', 'js'),
83
+ styleProp('right', 'layoutProp', 'length', 'js'),
84
+ styleProp('bottom', 'layoutProp', 'length', 'js'),
85
+ styleProp('left', 'layoutProp', 'length', 'js'),
86
+ styleProp('borderRadius', 'layoutProp', 'length', 'js'),
87
+ styleProp('borderTopLeftRadius', 'layoutProp', 'length', 'js'),
88
+ styleProp('borderTopRightRadius', 'layoutProp', 'length', 'js'),
89
+ styleProp('borderBottomLeftRadius', 'layoutProp', 'length', 'js'),
90
+ styleProp('borderBottomRightRadius', 'layoutProp', 'length', 'js'),
91
+ styleProp('borderWidth', 'layoutProp', 'length', 'js'),
92
+ styleProp('borderTopWidth', 'layoutProp', 'length', 'js'),
93
+ styleProp('borderRightWidth', 'layoutProp', 'length', 'js'),
94
+ styleProp('borderBottomWidth', 'layoutProp', 'length', 'js'),
95
+ styleProp('borderLeftWidth', 'layoutProp', 'length', 'js'),
96
+ styleProp('margin', 'layoutProp', 'length', 'js'),
97
+ styleProp('marginTop', 'layoutProp', 'length', 'js'),
98
+ styleProp('marginRight', 'layoutProp', 'length', 'js'),
99
+ styleProp('marginBottom', 'layoutProp', 'length', 'js'),
100
+ styleProp('marginLeft', 'layoutProp', 'length', 'js'),
101
+ styleProp('padding', 'layoutProp', 'length', 'js'),
102
+ styleProp('paddingTop', 'layoutProp', 'length', 'js'),
103
+ styleProp('paddingRight', 'layoutProp', 'length', 'js'),
104
+ styleProp('paddingBottom', 'layoutProp', 'length', 'js'),
105
+ styleProp('paddingLeft', 'layoutProp', 'length', 'js'),
106
+ // Discrete keywords (REQ-SUBSET-011 amendment; mix law REQ-VALUETYPE-015) — JS path; a pair
107
+ // takes the pin's mixVisibility step when an endpoint is invisible ({none, hidden}) and its
108
+ // counterpart has zero values, and otherwise publishes the TARGET as a constant. `display`
109
+ // maps to the identically-named RN style field (RN vocabulary flex↔none; web block is a port
110
+ // adaptation). `visibility` has NO RN style field: it commits as the ratified composed override
111
+ // (charter Decision 15 — hidden = effective opacity 0 overriding animated opacity +
112
+ // pointerEvents 'none'), recorded as a marker token since no faithful single field exists.
113
+ styleProp('display', 'discrete', 'discrete', 'js'),
114
+ {
115
+ keys: ['visibility'],
116
+ class: 'discrete',
117
+ universality: 'universal',
118
+ shipping: 'shipped',
119
+ referenceDisposition: 'portable-shipped',
120
+ valueType: 'discrete',
121
+ webEnginePath: 'js',
122
+ nativeMapping: 'composed:opacity+pointerEvents',
123
+ },
124
+ // Universal gestures (REQ-SUBSET-012) — the RECOGNIZERS are the universal gesture intersection;
125
+ // recognition detail owned by the gesture sub-SPEC, membership owned here. JS-thread event
126
+ // capabilities, not accelerated values. `universality` = host membership; `shipping` = subset
127
+ // availability today (the two axes, review r4 bd59a7c). The gesture-STATE TARGET props
128
+ // (`whileTap`/`whileDrag`) are SEPARATE deferred entries below — the BRIEF puts them "outside the
129
+ // subset" (BRIEF.md:139), which the machine-readable `shipping: 'deferred'` now records; they are
130
+ // NOT lumped with the shipped recognizer.
131
+ //
132
+ // Pan/drag RECOGNIZER — SHIPPED on the public surface as of FLAG 5a (`drag`, `onDrag*`).
133
+ // R15 D1 (REQ-API-041) widened it: both-axes `drag={true}` and `dragPropagation` (Motion's
134
+ // global nested-drag lock) ship on both entries; the axis-scope record lives in
135
+ // SPEC-UNIVERSAL-SUBSET § gestures.
136
+ // R15 D3 (REQ-API-043): `dragControls` / `dragListener` ship with the pan recognizer
137
+ // (imperative hub + element-originated start gate).
138
+ {
139
+ keys: [
140
+ 'drag',
141
+ 'dragPropagation',
142
+ 'dragControls',
143
+ 'dragListener',
144
+ 'onMeasureDragConstraints',
145
+ 'onDrag',
146
+ 'onDragStart',
147
+ 'onDragEnd',
148
+ ],
149
+ class: 'gesture',
150
+ universality: 'universal',
151
+ shipping: 'shipped',
152
+ referenceDisposition: 'portable-shipped',
153
+ valueType: 'gesture',
154
+ webEnginePath: 'js',
155
+ nativeMapping: 'gesture:pan',
156
+ },
157
+ // Press/tap RECOGNIZER callbacks — SHIPPED as of R5 (REQ-API-030,
158
+ // specs/R5-TAP-BUILD-PACKET.md): the pinned MotionNodeTapHandlers trio on both entries.
159
+ {
160
+ keys: ['onTap', 'onTapStart', 'onTapCancel'],
161
+ class: 'gesture',
162
+ universality: 'universal',
163
+ shipping: 'shipped',
164
+ referenceDisposition: 'portable-shipped',
165
+ valueType: 'gesture',
166
+ webEnginePath: 'js',
167
+ nativeMapping: 'gesture:tap',
168
+ },
169
+ // Gesture-STATE TARGET props (`whileTap`/`whileDrag`) — SHIPPED at R6 (REQ-API-031), OBJECT
170
+ // form: the priority-overlay law over the shipped recognizers. The LABEL (variant) form
171
+ // remains R7's at the runtime gates on both engines; `shipping` records the object surface.
172
+ // Separate entries because they map to different recognizers.
173
+ {
174
+ keys: ['whileTap'],
175
+ class: 'gesture',
176
+ universality: 'universal',
177
+ shipping: 'shipped',
178
+ referenceDisposition: 'portable-shipped',
179
+ valueType: 'gesture',
180
+ webEnginePath: 'js',
181
+ nativeMapping: 'gesture:tap',
182
+ },
183
+ {
184
+ keys: ['whileDrag'],
185
+ class: 'gesture',
186
+ universality: 'universal',
187
+ shipping: 'shipped',
188
+ referenceDisposition: 'portable-shipped',
189
+ valueType: 'gesture',
190
+ webEnginePath: 'js',
191
+ nativeMapping: 'gesture:pan',
192
+ },
193
+ // Web-only compositor effects (REQ-SUBSET-013). filter/clipPath ARE accelerated in Motion (canary),
194
+ // boxShadow + CSS gradients are not. All unsupported natively, deferred (outside the universal Target).
195
+ webEffect('filter', 'accelerated'),
196
+ webEffect('clipPath', 'accelerated'),
197
+ webEffect('boxShadow', 'js'),
198
+ webEffect('backgroundImage', 'js'),
199
+ // Pointer-gated interactions (REQ-SUBSET-013) — hover/focus are pointer/keyboard concepts absent on
200
+ // touch-only hosts; unsupported natively, fail loud there (REQ-SUBSET-014). Deferred (no rung).
201
+ {
202
+ keys: ['whileHover', 'onHoverStart', 'onHoverEnd'],
203
+ class: 'gesture',
204
+ universality: 'pointer-gated',
205
+ shipping: 'deferred',
206
+ referenceDisposition: 'intrinsic-web',
207
+ valueType: 'gesture',
208
+ webEnginePath: 'js',
209
+ nativeMapping: 'unsupported',
210
+ },
211
+ {
212
+ keys: ['whileFocus'],
213
+ class: 'gesture',
214
+ universality: 'pointer-gated',
215
+ shipping: 'deferred',
216
+ referenceDisposition: 'intrinsic-web',
217
+ valueType: 'gesture',
218
+ webEnginePath: 'js',
219
+ nativeMapping: 'unsupported',
220
+ },
221
+ ];
222
+ // Deep-freeze: each entry + its keys array + the entries array are frozen so no consumer can mutate the
223
+ // shared source of truth (REQ-SUBSET-010 invariant, §5.1). The lookup Map is module-private and derived,
224
+ // so it is not part of the frozen public surface.
225
+ const entries = Object.freeze(RAW_ENTRIES.map((e) => Object.freeze({ ...e, keys: Object.freeze([...e.keys]) })));
226
+ const byKey = new Map();
227
+ for (const e of entries)
228
+ for (const k of e.keys)
229
+ byKey.set(k, e);
230
+ exports.UNIVERSAL_SUBSET = Object.freeze({
231
+ entries,
232
+ // Membership lookup by any single prop key (a gesture's cluster keys all resolve to its entry).
233
+ get(key) {
234
+ return byKey.get(key);
235
+ },
236
+ has(key) {
237
+ return byKey.has(key);
238
+ },
239
+ byUniversality(universality) {
240
+ return entries.filter((e) => e.universality === universality);
241
+ },
242
+ // The accelerated set at Motion's token granularity (REQ-SUBSET-015): every transform-class entry
243
+ // collapses to the single `transform` token; opacity + the web-only accelerated effects appear as
244
+ // themselves. This is compared for EXACT equality against motion-dom's live `acceleratedValues` by the
245
+ // Milestone-4 conformance canary — a superset/subset match would silently mis-route the oracle.
246
+ acceleratedKeys() {
247
+ const out = new Set();
248
+ for (const e of entries) {
249
+ if (e.webEnginePath !== 'accelerated')
250
+ continue;
251
+ if (e.class === 'transform')
252
+ out.add('transform');
253
+ else
254
+ for (const k of e.keys)
255
+ out.add(k);
256
+ }
257
+ return out;
258
+ },
259
+ });
@@ -0,0 +1,25 @@
1
+ export type CapabilityClass = 'transform' | 'opacity' | 'color' | 'layoutProp' | 'discrete' | 'gesture' | 'webEffect';
2
+ export type Universality = 'universal' | 'web-only' | 'pointer-gated' | 'native-extension';
3
+ export type ShippingStatus = 'shipped' | 'deferred';
4
+ export type ReferenceDisposition = 'portable-shipped' | 'portable-deferred' | 'intrinsic-web' | 'extension' | 'waived-divergence';
5
+ export type WebEnginePath = 'accelerated' | 'js';
6
+ export type ValueType = 'length' | 'unitless' | 'angle' | 'rgba' | 'complex' | 'discrete' | 'gesture';
7
+ export interface CapabilityEntry {
8
+ readonly keys: readonly string[];
9
+ readonly class: CapabilityClass;
10
+ readonly universality: Universality;
11
+ readonly shipping: ShippingStatus;
12
+ readonly referenceDisposition: ReferenceDisposition;
13
+ readonly valueType: ValueType;
14
+ readonly webEnginePath: WebEnginePath;
15
+ readonly nativeMapping: string;
16
+ readonly debtId?: string;
17
+ readonly waiverId?: string;
18
+ }
19
+ export declare const UNIVERSAL_SUBSET: Readonly<{
20
+ entries: readonly CapabilityEntry[];
21
+ get(key: string): CapabilityEntry | undefined;
22
+ has(key: string): boolean;
23
+ byUniversality(universality: Universality): readonly CapabilityEntry[];
24
+ acceleratedKeys(): ReadonlySet<string>;
25
+ }>;
@@ -0,0 +1,25 @@
1
+ export type CapabilityClass = 'transform' | 'opacity' | 'color' | 'layoutProp' | 'discrete' | 'gesture' | 'webEffect';
2
+ export type Universality = 'universal' | 'web-only' | 'pointer-gated' | 'native-extension';
3
+ export type ShippingStatus = 'shipped' | 'deferred';
4
+ export type ReferenceDisposition = 'portable-shipped' | 'portable-deferred' | 'intrinsic-web' | 'extension' | 'waived-divergence';
5
+ export type WebEnginePath = 'accelerated' | 'js';
6
+ export type ValueType = 'length' | 'unitless' | 'angle' | 'rgba' | 'complex' | 'discrete' | 'gesture';
7
+ export interface CapabilityEntry {
8
+ readonly keys: readonly string[];
9
+ readonly class: CapabilityClass;
10
+ readonly universality: Universality;
11
+ readonly shipping: ShippingStatus;
12
+ readonly referenceDisposition: ReferenceDisposition;
13
+ readonly valueType: ValueType;
14
+ readonly webEnginePath: WebEnginePath;
15
+ readonly nativeMapping: string;
16
+ readonly debtId?: string;
17
+ readonly waiverId?: string;
18
+ }
19
+ export declare const UNIVERSAL_SUBSET: Readonly<{
20
+ entries: readonly CapabilityEntry[];
21
+ get(key: string): CapabilityEntry | undefined;
22
+ has(key: string): boolean;
23
+ byUniversality(universality: Universality): readonly CapabilityEntry[];
24
+ acceleratedKeys(): ReadonlySet<string>;
25
+ }>;
@@ -0,0 +1,256 @@
1
+ // SPEC-UNIVERSAL-SUBSET §3 — the single frozen, machine-readable universal-subset registry
2
+ // (REQ-SUBSET-010). It is the SOLE source of subset membership: app code, the native runtime, the web
3
+ // shim, and the conformance runner all read this one object; no engine carries a private list. Lives in
4
+ // `core` with ZERO host dependencies (structural isolation gate) — the host-aware Motion-seam canary
5
+ // (REQ-SUBSET-015) and authoring gate (REQ-SUBSET-018) read this registry from `packages/conformance`.
6
+ //
7
+ // Each entry declares every REQ-SUBSET-010 field. Schema completions beyond the spec's illustrative
8
+ // enums, flagged as vetoable (see .rl decision log): the `webEffect` CLASS carries web-only compositor
9
+ // effects (filter/clipPath/boxShadow/gradients) that fit none of transform|opacity|color|layoutProp|
10
+ // gesture; the `gesture` VALUE-TYPE and `complex` VALUE-TYPE fill §5.1's "enum-valid valueType on every
11
+ // entry" for gesture and web-effect entries respectively. Membership + marking follow REQ-SUBSET-011
12
+ // (properties), -012 (gestures), -013 (platform-specific), -015 (web path), -017 (native mapping).
13
+ // --- entry builders (keep the tables below declarative) --------------------------------------------
14
+ // A universal transform maps to one RN transform-array token and takes the accelerated web path
15
+ // (Motion folds every transform into the composite `transform` string it accelerates via WAAPI).
16
+ function transform(key, token, valueType) {
17
+ return {
18
+ keys: [key],
19
+ class: 'transform',
20
+ universality: 'universal',
21
+ shipping: 'shipped', // the animate pipeline drives every transform today
22
+ referenceDisposition: 'portable-shipped',
23
+ valueType,
24
+ webEnginePath: 'accelerated',
25
+ nativeMapping: token,
26
+ };
27
+ }
28
+ // A universal non-transform property maps to the identically-named RN style field. Opacity is the lone
29
+ // accelerated non-transform; colors + layout props take Motion's JS path (REQ-SUBSET-015).
30
+ function styleProp(key, cls, valueType, webEnginePath) {
31
+ return {
32
+ keys: [key],
33
+ class: cls,
34
+ universality: 'universal',
35
+ shipping: 'shipped', // opacity/colors/layout props all animate today
36
+ referenceDisposition: 'portable-shipped',
37
+ valueType,
38
+ webEnginePath,
39
+ nativeMapping: key,
40
+ };
41
+ }
42
+ // A web-only compositor effect: no faithful native mapping (RN has no per-layer filter/clip/shadow
43
+ // parity), so `unsupported` — but it still records its Motion web path so the canary stays exact and a
44
+ // native use fails loud (REQ-SUBSET-013/-014).
45
+ function webEffect(key, webEnginePath) {
46
+ return {
47
+ keys: [key],
48
+ class: 'webEffect',
49
+ universality: 'web-only',
50
+ shipping: 'deferred',
51
+ referenceDisposition: 'intrinsic-web',
52
+ valueType: 'complex',
53
+ webEnginePath,
54
+ nativeMapping: 'unsupported',
55
+ };
56
+ }
57
+ const RAW_ENTRIES = [
58
+ // Transforms (REQ-SUBSET-011) — accelerated; each folds into the composite `transform`.
59
+ transform('x', 'translateX', 'length'),
60
+ transform('y', 'translateY', 'length'),
61
+ transform('scale', 'scale', 'unitless'),
62
+ transform('scaleX', 'scaleX', 'unitless'),
63
+ transform('scaleY', 'scaleY', 'unitless'),
64
+ transform('rotate', 'rotate', 'angle'),
65
+ transform('rotateX', 'rotateX', 'angle'),
66
+ transform('rotateY', 'rotateY', 'angle'),
67
+ transform('skewX', 'skewX', 'angle'),
68
+ transform('skewY', 'skewY', 'angle'),
69
+ transform('perspective', 'perspective', 'length'),
70
+ // Opacity (REQ-SUBSET-011) — the one accelerated non-transform.
71
+ styleProp('opacity', 'opacity', 'unitless', 'accelerated'),
72
+ // Colors (REQ-SUBSET-011) — JS path (Motion's `background-color` acceleration is disabled at pin).
73
+ styleProp('backgroundColor', 'color', 'rgba', 'js'),
74
+ styleProp('color', 'color', 'rgba', 'js'),
75
+ styleProp('borderColor', 'color', 'rgba', 'js'),
76
+ // Layout props to explicit numeric targets (REQ-SUBSET-011) — JS path, length value type.
77
+ styleProp('width', 'layoutProp', 'length', 'js'),
78
+ styleProp('height', 'layoutProp', 'length', 'js'),
79
+ styleProp('top', 'layoutProp', 'length', 'js'),
80
+ styleProp('right', 'layoutProp', 'length', 'js'),
81
+ styleProp('bottom', 'layoutProp', 'length', 'js'),
82
+ styleProp('left', 'layoutProp', 'length', 'js'),
83
+ styleProp('borderRadius', 'layoutProp', 'length', 'js'),
84
+ styleProp('borderTopLeftRadius', 'layoutProp', 'length', 'js'),
85
+ styleProp('borderTopRightRadius', 'layoutProp', 'length', 'js'),
86
+ styleProp('borderBottomLeftRadius', 'layoutProp', 'length', 'js'),
87
+ styleProp('borderBottomRightRadius', 'layoutProp', 'length', 'js'),
88
+ styleProp('borderWidth', 'layoutProp', 'length', 'js'),
89
+ styleProp('borderTopWidth', 'layoutProp', 'length', 'js'),
90
+ styleProp('borderRightWidth', 'layoutProp', 'length', 'js'),
91
+ styleProp('borderBottomWidth', 'layoutProp', 'length', 'js'),
92
+ styleProp('borderLeftWidth', 'layoutProp', 'length', 'js'),
93
+ styleProp('margin', 'layoutProp', 'length', 'js'),
94
+ styleProp('marginTop', 'layoutProp', 'length', 'js'),
95
+ styleProp('marginRight', 'layoutProp', 'length', 'js'),
96
+ styleProp('marginBottom', 'layoutProp', 'length', 'js'),
97
+ styleProp('marginLeft', 'layoutProp', 'length', 'js'),
98
+ styleProp('padding', 'layoutProp', 'length', 'js'),
99
+ styleProp('paddingTop', 'layoutProp', 'length', 'js'),
100
+ styleProp('paddingRight', 'layoutProp', 'length', 'js'),
101
+ styleProp('paddingBottom', 'layoutProp', 'length', 'js'),
102
+ styleProp('paddingLeft', 'layoutProp', 'length', 'js'),
103
+ // Discrete keywords (REQ-SUBSET-011 amendment; mix law REQ-VALUETYPE-015) — JS path; a pair
104
+ // takes the pin's mixVisibility step when an endpoint is invisible ({none, hidden}) and its
105
+ // counterpart has zero values, and otherwise publishes the TARGET as a constant. `display`
106
+ // maps to the identically-named RN style field (RN vocabulary flex↔none; web block is a port
107
+ // adaptation). `visibility` has NO RN style field: it commits as the ratified composed override
108
+ // (charter Decision 15 — hidden = effective opacity 0 overriding animated opacity +
109
+ // pointerEvents 'none'), recorded as a marker token since no faithful single field exists.
110
+ styleProp('display', 'discrete', 'discrete', 'js'),
111
+ {
112
+ keys: ['visibility'],
113
+ class: 'discrete',
114
+ universality: 'universal',
115
+ shipping: 'shipped',
116
+ referenceDisposition: 'portable-shipped',
117
+ valueType: 'discrete',
118
+ webEnginePath: 'js',
119
+ nativeMapping: 'composed:opacity+pointerEvents',
120
+ },
121
+ // Universal gestures (REQ-SUBSET-012) — the RECOGNIZERS are the universal gesture intersection;
122
+ // recognition detail owned by the gesture sub-SPEC, membership owned here. JS-thread event
123
+ // capabilities, not accelerated values. `universality` = host membership; `shipping` = subset
124
+ // availability today (the two axes, review r4 bd59a7c). The gesture-STATE TARGET props
125
+ // (`whileTap`/`whileDrag`) are SEPARATE deferred entries below — the BRIEF puts them "outside the
126
+ // subset" (BRIEF.md:139), which the machine-readable `shipping: 'deferred'` now records; they are
127
+ // NOT lumped with the shipped recognizer.
128
+ //
129
+ // Pan/drag RECOGNIZER — SHIPPED on the public surface as of FLAG 5a (`drag`, `onDrag*`).
130
+ // R15 D1 (REQ-API-041) widened it: both-axes `drag={true}` and `dragPropagation` (Motion's
131
+ // global nested-drag lock) ship on both entries; the axis-scope record lives in
132
+ // SPEC-UNIVERSAL-SUBSET § gestures.
133
+ // R15 D3 (REQ-API-043): `dragControls` / `dragListener` ship with the pan recognizer
134
+ // (imperative hub + element-originated start gate).
135
+ {
136
+ keys: [
137
+ 'drag',
138
+ 'dragPropagation',
139
+ 'dragControls',
140
+ 'dragListener',
141
+ 'onMeasureDragConstraints',
142
+ 'onDrag',
143
+ 'onDragStart',
144
+ 'onDragEnd',
145
+ ],
146
+ class: 'gesture',
147
+ universality: 'universal',
148
+ shipping: 'shipped',
149
+ referenceDisposition: 'portable-shipped',
150
+ valueType: 'gesture',
151
+ webEnginePath: 'js',
152
+ nativeMapping: 'gesture:pan',
153
+ },
154
+ // Press/tap RECOGNIZER callbacks — SHIPPED as of R5 (REQ-API-030,
155
+ // specs/R5-TAP-BUILD-PACKET.md): the pinned MotionNodeTapHandlers trio on both entries.
156
+ {
157
+ keys: ['onTap', 'onTapStart', 'onTapCancel'],
158
+ class: 'gesture',
159
+ universality: 'universal',
160
+ shipping: 'shipped',
161
+ referenceDisposition: 'portable-shipped',
162
+ valueType: 'gesture',
163
+ webEnginePath: 'js',
164
+ nativeMapping: 'gesture:tap',
165
+ },
166
+ // Gesture-STATE TARGET props (`whileTap`/`whileDrag`) — SHIPPED at R6 (REQ-API-031), OBJECT
167
+ // form: the priority-overlay law over the shipped recognizers. The LABEL (variant) form
168
+ // remains R7's at the runtime gates on both engines; `shipping` records the object surface.
169
+ // Separate entries because they map to different recognizers.
170
+ {
171
+ keys: ['whileTap'],
172
+ class: 'gesture',
173
+ universality: 'universal',
174
+ shipping: 'shipped',
175
+ referenceDisposition: 'portable-shipped',
176
+ valueType: 'gesture',
177
+ webEnginePath: 'js',
178
+ nativeMapping: 'gesture:tap',
179
+ },
180
+ {
181
+ keys: ['whileDrag'],
182
+ class: 'gesture',
183
+ universality: 'universal',
184
+ shipping: 'shipped',
185
+ referenceDisposition: 'portable-shipped',
186
+ valueType: 'gesture',
187
+ webEnginePath: 'js',
188
+ nativeMapping: 'gesture:pan',
189
+ },
190
+ // Web-only compositor effects (REQ-SUBSET-013). filter/clipPath ARE accelerated in Motion (canary),
191
+ // boxShadow + CSS gradients are not. All unsupported natively, deferred (outside the universal Target).
192
+ webEffect('filter', 'accelerated'),
193
+ webEffect('clipPath', 'accelerated'),
194
+ webEffect('boxShadow', 'js'),
195
+ webEffect('backgroundImage', 'js'),
196
+ // Pointer-gated interactions (REQ-SUBSET-013) — hover/focus are pointer/keyboard concepts absent on
197
+ // touch-only hosts; unsupported natively, fail loud there (REQ-SUBSET-014). Deferred (no rung).
198
+ {
199
+ keys: ['whileHover', 'onHoverStart', 'onHoverEnd'],
200
+ class: 'gesture',
201
+ universality: 'pointer-gated',
202
+ shipping: 'deferred',
203
+ referenceDisposition: 'intrinsic-web',
204
+ valueType: 'gesture',
205
+ webEnginePath: 'js',
206
+ nativeMapping: 'unsupported',
207
+ },
208
+ {
209
+ keys: ['whileFocus'],
210
+ class: 'gesture',
211
+ universality: 'pointer-gated',
212
+ shipping: 'deferred',
213
+ referenceDisposition: 'intrinsic-web',
214
+ valueType: 'gesture',
215
+ webEnginePath: 'js',
216
+ nativeMapping: 'unsupported',
217
+ },
218
+ ];
219
+ // Deep-freeze: each entry + its keys array + the entries array are frozen so no consumer can mutate the
220
+ // shared source of truth (REQ-SUBSET-010 invariant, §5.1). The lookup Map is module-private and derived,
221
+ // so it is not part of the frozen public surface.
222
+ const entries = Object.freeze(RAW_ENTRIES.map((e) => Object.freeze({ ...e, keys: Object.freeze([...e.keys]) })));
223
+ const byKey = new Map();
224
+ for (const e of entries)
225
+ for (const k of e.keys)
226
+ byKey.set(k, e);
227
+ export const UNIVERSAL_SUBSET = Object.freeze({
228
+ entries,
229
+ // Membership lookup by any single prop key (a gesture's cluster keys all resolve to its entry).
230
+ get(key) {
231
+ return byKey.get(key);
232
+ },
233
+ has(key) {
234
+ return byKey.has(key);
235
+ },
236
+ byUniversality(universality) {
237
+ return entries.filter((e) => e.universality === universality);
238
+ },
239
+ // The accelerated set at Motion's token granularity (REQ-SUBSET-015): every transform-class entry
240
+ // collapses to the single `transform` token; opacity + the web-only accelerated effects appear as
241
+ // themselves. This is compared for EXACT equality against motion-dom's live `acceleratedValues` by the
242
+ // Milestone-4 conformance canary — a superset/subset match would silently mis-route the oracle.
243
+ acceleratedKeys() {
244
+ const out = new Set();
245
+ for (const e of entries) {
246
+ if (e.webEnginePath !== 'accelerated')
247
+ continue;
248
+ if (e.class === 'transform')
249
+ out.add('transform');
250
+ else
251
+ for (const k of e.keys)
252
+ out.add(k);
253
+ }
254
+ return out;
255
+ },
256
+ });