zyzz 0.0.21 → 0.0.22

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 (220) hide show
  1. package/Zyzz.podspec +16 -0
  2. package/dist/Style.d.ts +3 -1
  3. package/dist/Style.d.ts.map +1 -1
  4. package/dist/Style.js.map +1 -1
  5. package/dist/babel/NativeJsx.d.ts.map +1 -1
  6. package/dist/babel/NativeJsx.js +204 -12
  7. package/dist/babel/NativeJsx.js.map +1 -1
  8. package/dist/babel/index.d.ts +6 -2
  9. package/dist/babel/index.d.ts.map +1 -1
  10. package/dist/babel/index.js +10 -1
  11. package/dist/babel/index.js.map +1 -1
  12. package/dist/compiler/Graph.d.ts.map +1 -1
  13. package/dist/compiler/Graph.js +64 -0
  14. package/dist/compiler/Graph.js.map +1 -1
  15. package/dist/compiler/Native.d.ts +6 -3
  16. package/dist/compiler/Native.d.ts.map +1 -1
  17. package/dist/compiler/Native.js +142 -24
  18. package/dist/compiler/Native.js.map +1 -1
  19. package/dist/compiler/Source.d.ts +2 -0
  20. package/dist/compiler/Source.d.ts.map +1 -1
  21. package/dist/compiler/Source.js +17 -5
  22. package/dist/compiler/Source.js.map +1 -1
  23. package/dist/compiler/internal/Configurations.d.ts +2 -0
  24. package/dist/compiler/internal/Configurations.d.ts.map +1 -1
  25. package/dist/compiler/internal/Configurations.js +21 -3
  26. package/dist/compiler/internal/Configurations.js.map +1 -1
  27. package/dist/compiler/internal/Contract.d.ts.map +1 -1
  28. package/dist/compiler/internal/Contract.js +75 -38
  29. package/dist/compiler/internal/Contract.js.map +1 -1
  30. package/dist/compiler/internal/Contributions.d.ts.map +1 -1
  31. package/dist/compiler/internal/Contributions.js +7 -1
  32. package/dist/compiler/internal/Contributions.js.map +1 -1
  33. package/dist/compiler/internal/Descriptors.d.ts.map +1 -1
  34. package/dist/compiler/internal/Descriptors.js +11 -2
  35. package/dist/compiler/internal/Descriptors.js.map +1 -1
  36. package/dist/compiler/internal/NativeBindings.d.ts +24 -26
  37. package/dist/compiler/internal/NativeBindings.d.ts.map +1 -1
  38. package/dist/compiler/internal/NativeBindings.js +61 -8
  39. package/dist/compiler/internal/NativeBindings.js.map +1 -1
  40. package/dist/compiler/internal/NativeMedia.d.ts +14 -0
  41. package/dist/compiler/internal/NativeMedia.d.ts.map +1 -0
  42. package/dist/compiler/internal/NativeMedia.js +287 -0
  43. package/dist/compiler/internal/NativeMedia.js.map +1 -0
  44. package/dist/compiler/internal/NativeVars.d.ts +28 -0
  45. package/dist/compiler/internal/NativeVars.d.ts.map +1 -0
  46. package/dist/compiler/internal/NativeVars.js +157 -0
  47. package/dist/compiler/internal/NativeVars.js.map +1 -0
  48. package/dist/compiler/internal/PackedStyles.d.ts +2 -0
  49. package/dist/compiler/internal/PackedStyles.d.ts.map +1 -1
  50. package/dist/compiler/internal/PackedStyles.js +2 -0
  51. package/dist/compiler/internal/PackedStyles.js.map +1 -1
  52. package/dist/compiler/internal/Themes.d.ts +22 -1
  53. package/dist/compiler/internal/Themes.d.ts.map +1 -1
  54. package/dist/compiler/internal/Themes.js +118 -3
  55. package/dist/compiler/internal/Themes.js.map +1 -1
  56. package/dist/compiler/internal/Vars.d.ts +1 -1
  57. package/dist/compiler/internal/Vars.d.ts.map +1 -1
  58. package/dist/compiler/internal/Vars.js +7 -2
  59. package/dist/compiler/internal/Vars.js.map +1 -1
  60. package/dist/default.js.zyzz.json +1 -1
  61. package/dist/internal/Completion.d.ts +1 -1
  62. package/dist/internal/Completion.d.ts.map +1 -1
  63. package/dist/internal/Targets.d.ts.map +1 -1
  64. package/dist/internal/Targets.js +2 -0
  65. package/dist/internal/Targets.js.map +1 -1
  66. package/dist/internal/Token.d.ts +0 -2
  67. package/dist/internal/Token.d.ts.map +1 -1
  68. package/dist/internal/Token.js.map +1 -1
  69. package/dist/internal/Value.d.ts +7 -0
  70. package/dist/internal/Value.d.ts.map +1 -1
  71. package/dist/internal/Value.js.map +1 -1
  72. package/dist/metro/Graph.d.ts +22 -7
  73. package/dist/metro/Graph.d.ts.map +1 -1
  74. package/dist/metro/Graph.js +179 -42
  75. package/dist/metro/Graph.js.map +1 -1
  76. package/dist/metro/Watch.d.ts +28 -4
  77. package/dist/metro/Watch.d.ts.map +1 -1
  78. package/dist/metro/Watch.js +39 -7
  79. package/dist/metro/Watch.js.map +1 -1
  80. package/dist/metro/index.d.ts +15 -4
  81. package/dist/metro/index.d.ts.map +1 -1
  82. package/dist/metro/index.js +27 -0
  83. package/dist/metro/index.js.map +1 -1
  84. package/dist/metro/transformer.d.ts +5 -1
  85. package/dist/metro/transformer.d.ts.map +1 -1
  86. package/dist/metro/transformer.js +5 -3
  87. package/dist/metro/transformer.js.map +1 -1
  88. package/dist/react-native/StyleSheet.d.ts +3 -2
  89. package/dist/react-native/StyleSheet.d.ts.map +1 -1
  90. package/dist/react-native/StyleSheet.js +17 -34
  91. package/dist/react-native/StyleSheet.js.map +1 -1
  92. package/dist/react-native/index.d.ts +1 -1
  93. package/dist/react-native/index.d.ts.map +1 -1
  94. package/dist/react-native/index.js +1 -1
  95. package/dist/react-native/index.js.map +1 -1
  96. package/dist/react-native/index.native.d.ts +5 -0
  97. package/dist/react-native/index.native.js +20 -0
  98. package/dist/react-native/index.native.js.map +7 -0
  99. package/dist/react-native/internal/Calculation.d.ts +7 -0
  100. package/dist/react-native/internal/Calculation.d.ts.map +1 -0
  101. package/dist/react-native/internal/Calculation.js +134 -0
  102. package/dist/react-native/internal/Calculation.js.map +1 -0
  103. package/dist/react-native/internal/Device.js +191 -0
  104. package/dist/react-native/internal/Device.js.map +7 -0
  105. package/dist/react-native/internal/NativeZyzz.js +7 -0
  106. package/dist/react-native/internal/NativeZyzz.js.map +7 -0
  107. package/dist/react-native/internal/Scalar.d.ts.map +1 -1
  108. package/dist/react-native/internal/Scalar.js +9 -2
  109. package/dist/react-native/internal/Scalar.js.map +1 -1
  110. package/dist/react-native/internal/Store.d.ts +32 -0
  111. package/dist/react-native/internal/Store.d.ts.map +1 -0
  112. package/dist/react-native/internal/Store.js +57 -0
  113. package/dist/react-native/internal/Store.js.map +1 -0
  114. package/dist/react-native/internal/Tokens.d.ts +21 -0
  115. package/dist/react-native/internal/Tokens.d.ts.map +1 -0
  116. package/dist/react-native/internal/Tokens.js +58 -0
  117. package/dist/react-native/internal/Tokens.js.map +1 -0
  118. package/dist/react-native/internal/Viewport.d.ts +6 -0
  119. package/dist/react-native/internal/Viewport.d.ts.map +1 -0
  120. package/dist/react-native/internal/Viewport.js +4 -0
  121. package/dist/react-native/internal/Viewport.js.map +1 -0
  122. package/dist/react-native/react.d.ts +74 -11
  123. package/dist/react-native/react.d.ts.map +1 -1
  124. package/dist/react-native/react.js +111 -12
  125. package/dist/react-native/react.js.map +1 -1
  126. package/dist/react-native/reanimated.d.ts +39 -0
  127. package/dist/react-native/reanimated.d.ts.map +1 -0
  128. package/dist/react-native/reanimated.js +76 -0
  129. package/dist/react-native/reanimated.js.map +1 -0
  130. package/dist/runtime/NativeContext.d.ts +10 -1
  131. package/dist/runtime/NativeContext.d.ts.map +1 -1
  132. package/dist/runtime/NativeContext.js +67 -14
  133. package/dist/runtime/NativeContext.js.map +1 -1
  134. package/dist/runtime/NativeDynamic.d.ts +3 -2
  135. package/dist/runtime/NativeDynamic.d.ts.map +1 -1
  136. package/dist/runtime/NativeDynamic.js +32 -7
  137. package/dist/runtime/NativeDynamic.js.map +1 -1
  138. package/dist/runtime/NativeStatic.d.ts +23 -0
  139. package/dist/runtime/NativeStatic.d.ts.map +1 -0
  140. package/dist/runtime/NativeStatic.js +106 -0
  141. package/dist/runtime/NativeStatic.js.map +1 -0
  142. package/dist/runtime/NativeVars.d.ts +53 -0
  143. package/dist/runtime/NativeVars.d.ts.map +1 -0
  144. package/dist/runtime/NativeVars.js +77 -0
  145. package/dist/runtime/NativeVars.js.map +1 -0
  146. package/dist/runtime/index.d.ts +4 -0
  147. package/dist/runtime/index.d.ts.map +1 -1
  148. package/dist/runtime/index.js +4 -0
  149. package/dist/runtime/index.js.map +1 -1
  150. package/dist/runtime/internal/NativeMedia.d.ts +25 -0
  151. package/dist/runtime/internal/NativeMedia.d.ts.map +1 -0
  152. package/dist/runtime/internal/NativeMedia.js +36 -0
  153. package/dist/runtime/internal/NativeMedia.js.map +1 -0
  154. package/dist/vite/index.d.ts.map +1 -1
  155. package/dist/vite/index.js +7 -35
  156. package/dist/vite/index.js.map +1 -1
  157. package/dist/web/Css.d.ts.map +1 -1
  158. package/dist/web/Css.js +31 -19
  159. package/dist/web/Css.js.map +1 -1
  160. package/dist/web/internal/Themes.d.ts +0 -2
  161. package/dist/web/internal/Themes.d.ts.map +1 -1
  162. package/dist/web/internal/Themes.js +30 -28
  163. package/dist/web/internal/Themes.js.map +1 -1
  164. package/dist/web/page.d.ts +2 -0
  165. package/dist/web/page.d.ts.map +1 -1
  166. package/native/NativeZyzz.cpp +215 -0
  167. package/native/NativeZyzz.h +52 -0
  168. package/native/ZyzzSpecJSI.h +65 -0
  169. package/native/android/CMakeLists.txt +8 -0
  170. package/native/android/ZyzzSpec-generated.cpp +50 -0
  171. package/native/android/ZyzzSpec.h +31 -0
  172. package/native/ios/ZyzzModuleProvider.mm +13 -0
  173. package/package.json +39 -1
  174. package/react-native.config.ts +14 -0
  175. package/src/Style.ts +11 -8
  176. package/src/babel/NativeJsx.ts +305 -28
  177. package/src/babel/index.ts +21 -3
  178. package/src/compiler/Graph.ts +75 -0
  179. package/src/compiler/Native.ts +158 -26
  180. package/src/compiler/Source.ts +32 -5
  181. package/src/compiler/internal/Configurations.ts +25 -3
  182. package/src/compiler/internal/Contract.ts +98 -50
  183. package/src/compiler/internal/Contributions.ts +7 -1
  184. package/src/compiler/internal/Descriptors.ts +12 -8
  185. package/src/compiler/internal/NativeBindings.ts +98 -15
  186. package/src/compiler/internal/NativeMedia.ts +342 -0
  187. package/src/compiler/internal/NativeVars.ts +228 -0
  188. package/src/compiler/internal/PackedStyles.ts +4 -0
  189. package/src/compiler/internal/Themes.ts +187 -2
  190. package/src/compiler/internal/Vars.ts +12 -1
  191. package/src/internal/Completion.ts +6 -3
  192. package/src/internal/Targets.ts +2 -0
  193. package/src/internal/Token.ts +0 -2
  194. package/src/internal/Value.ts +20 -0
  195. package/src/metro/Graph.ts +235 -50
  196. package/src/metro/Watch.ts +95 -10
  197. package/src/metro/index.ts +62 -4
  198. package/src/metro/transformer.ts +21 -11
  199. package/src/react-native/StyleSheet.ts +28 -44
  200. package/src/react-native/index.native.ts +10 -0
  201. package/src/react-native/index.ts +1 -1
  202. package/src/react-native/internal/Calculation.ts +159 -0
  203. package/src/react-native/internal/Device.ts +231 -0
  204. package/src/react-native/internal/NativeZyzz.ts +20 -0
  205. package/src/react-native/internal/Scalar.ts +13 -2
  206. package/src/react-native/internal/Store.ts +78 -0
  207. package/src/react-native/internal/Tokens.ts +85 -0
  208. package/src/react-native/internal/Viewport.ts +8 -0
  209. package/src/react-native/react.ts +211 -19
  210. package/src/react-native/reanimated.ts +162 -0
  211. package/src/runtime/NativeContext.ts +88 -17
  212. package/src/runtime/NativeDynamic.ts +35 -10
  213. package/src/runtime/NativeStatic.ts +145 -0
  214. package/src/runtime/NativeVars.ts +189 -0
  215. package/src/runtime/index.ts +6 -0
  216. package/src/runtime/internal/NativeMedia.ts +63 -0
  217. package/src/vite/index.ts +9 -42
  218. package/src/web/Css.ts +42 -27
  219. package/src/web/internal/Themes.ts +34 -57
  220. package/src/web/page.ts +2 -0
@@ -32,6 +32,8 @@ export type Alias = Call & {
32
32
 
33
33
  /** Theme factory span and generated scope key. */
34
34
  export type Call = {
35
+ /** Whether native defineConfig retains a typed React Provider. */
36
+ readonly nativeProvider?: boolean | undefined
35
37
  readonly variableSet?: boolean | undefined
36
38
  readonly directVariables?: boolean | undefined
37
39
  readonly variableConfig?: boolean | undefined
@@ -102,6 +104,22 @@ export type Link = {
102
104
  readonly members?: Readonly<Record<string, Link>> | undefined
103
105
  }
104
106
 
107
+ /** A readonly variable argument consumed by a native React hook. */
108
+ export type VarsRead = {
109
+ /** Owning configuration fallback. */
110
+ readonly defaultVars: string
111
+ /** Exclusive source offset. */
112
+ readonly end: number
113
+ /** Stable configuration identity for graph-owned native profiles. */
114
+ readonly owner: string
115
+ /** Inclusive source offset. */
116
+ readonly start: number
117
+ /** A standalone definition that does not select a named catalog entry. */
118
+ readonly unnamed: boolean
119
+ /** Complete compatible variable alternatives. */
120
+ readonly vars: Readonly<Record<string, Theme.Definition>>
121
+ }
122
+
105
123
  /** Shared graph data; no filesystem or runtime evaluation is involved. */
106
124
  export type Context = {
107
125
  /** Canonical identifier names collected during graph validation. */
@@ -137,6 +155,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
137
155
  { end: number; output: 'html' | undefined }
138
156
  >()
139
157
  const selections = new Set<string>()
158
+ const selectionUses = new Set<string>()
140
159
  const calls: Call[] = []
141
160
  const scripts = new Set<string>()
142
161
  const definitions = new Map<number, Call>()
@@ -145,10 +164,12 @@ export function collect(program: Ast.Program, options: collect.Options) {
145
164
  const variableImports = new Set<number>()
146
165
  const configImports = new Set<number>()
147
166
  const factoryImports = new Map<number, 'create' | 'define' | 'extend'>()
167
+ const nativeFactories = new Set<string>()
148
168
  const configs = new Map<string, Link>()
149
169
  const configBindings = new Map<number, Link>()
150
170
  const factoryReferences = new Set<number>()
151
171
  const references: Reference[] = []
172
+ const varsReads: VarsRead[] = []
152
173
 
153
174
  const styles = new Map<
154
175
  number,
@@ -166,12 +187,28 @@ export function collect(program: Ast.Program, options: collect.Options) {
166
187
  for (const node of program.body) {
167
188
  if (
168
189
  node.type !== 'ImportDeclaration' ||
169
- node.source.value !== 'zyzz' ||
190
+ !['zyzz', 'zyzz/react-native', 'zyzz/react-native/react'].includes(
191
+ node.source.value,
192
+ ) ||
170
193
  node.importKind === 'type'
171
194
  )
172
195
  continue
173
196
 
174
- for (const specifier of node.specifiers)
197
+ for (const specifier of node.specifiers) {
198
+ if (node.source.value !== 'zyzz') {
199
+ if (
200
+ specifier.type === 'ImportSpecifier' &&
201
+ specifier.importKind !== 'type' &&
202
+ (specifier.imported.type === 'Identifier'
203
+ ? specifier.imported.name
204
+ : specifier.imported.value) === 'defineConfig'
205
+ ) {
206
+ factoryImports.set(specifier.start, 'create')
207
+ nativeFactories.add(specifier.local.name)
208
+ }
209
+ continue
210
+ }
211
+
175
212
  if (
176
213
  specifier.type === 'ImportSpecifier' &&
177
214
  specifier.importKind !== 'type' &&
@@ -208,6 +245,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
208
245
  factoryImports.set(specifier.start, 'define')
209
246
  else factoryImports.set(specifier.start, 'extend')
210
247
  }
248
+ }
211
249
  }
212
250
 
213
251
  if (
@@ -686,11 +724,20 @@ export function collect(program: Ast.Program, options: collect.Options) {
686
724
  }
687
725
 
688
726
  if (config) {
727
+ const nativeProvider =
728
+ member.type === 'Identifier' && nativeFactories.has(member.name)
729
+ if (nativeProvider && !options.native)
730
+ fail(
731
+ 'Native defineConfig requires a native compilation target.',
732
+ expression,
733
+ )
734
+
689
735
  try {
690
736
  const link = Configurations.collect({
691
737
  data,
692
738
  expression,
693
739
  name,
740
+ nativeProvider,
694
741
  resolve: (node) => {
695
742
  const link = resolve(node)
696
743
 
@@ -717,6 +764,8 @@ export function collect(program: Ast.Program, options: collect.Options) {
717
764
  themes[link.call.name] = link.definition
718
765
 
719
766
  for (const { key, id } of bindings) {
767
+ if (key === 'Provider' && link.call.nativeProvider) continue
768
+
720
769
  if (
721
770
  (key === 'style' || key === 'variants') &&
722
771
  !link.call.selection &&
@@ -1046,6 +1095,15 @@ export function collect(program: Ast.Program, options: collect.Options) {
1046
1095
  })
1047
1096
 
1048
1097
  for (const { key, id } of bindings) {
1098
+ if (
1099
+ key === 'Provider' &&
1100
+ link.call.nativeProvider &&
1101
+ !link.call.initialization &&
1102
+ !link.call.root &&
1103
+ !link.call.selection
1104
+ )
1105
+ continue
1106
+
1049
1107
  if (
1050
1108
  (key === 'style' || key === 'variants') &&
1051
1109
  !link.call.selection &&
@@ -1351,6 +1409,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
1351
1409
  parent: Ast.Node,
1352
1410
  ancestors: readonly Ast.Node[],
1353
1411
  binding: Walker.ScopeTrackerNode | null,
1412
+ lookup: (name: string) => Walker.ScopeTrackerNode | null,
1354
1413
  ): boolean {
1355
1414
  const grandparent = ancestors.at(-3)
1356
1415
 
@@ -1438,6 +1497,13 @@ export function collect(program: Ast.Program, options: collect.Options) {
1438
1497
  )
1439
1498
  fail('Configuration references must follow their definition.', node)
1440
1499
 
1500
+ if (
1501
+ config.call.variableConfig &&
1502
+ config.call.selection &&
1503
+ readVars(node, parent, config, lookup)
1504
+ )
1505
+ return true
1506
+
1441
1507
  // Root controls are an ordinary runtime object; any read or call is valid.
1442
1508
  if (config.call.root) {
1443
1509
  appearances.add(config.call.name)
@@ -1459,6 +1525,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
1459
1525
 
1460
1526
  if (config.call.selection) {
1461
1527
  selections.add(config.call.name)
1528
+ selectionUses.add(config.call.name)
1462
1529
  scopeApplications.set(parent.start, {
1463
1530
  end: parent.end,
1464
1531
  output: config.call.options?.output === 'html' ? 'html' : undefined,
@@ -1504,6 +1571,24 @@ export function collect(program: Ast.Program, options: collect.Options) {
1504
1571
  path.push(key)
1505
1572
  target = member
1506
1573
 
1574
+ if (
1575
+ path.length === 1 &&
1576
+ path[0] === 'Provider' &&
1577
+ config.call.nativeProvider &&
1578
+ !config.call.initialization &&
1579
+ !config.call.root &&
1580
+ !config.call.selection
1581
+ )
1582
+ return true
1583
+
1584
+ if (
1585
+ config.call.variableConfig &&
1586
+ path.length === 1 &&
1587
+ path[0] === 'vars' &&
1588
+ readVars(target, ancestors[index - 1]!, config, lookup)
1589
+ )
1590
+ return true
1591
+
1507
1592
  if (
1508
1593
  aliasReferences.has(target.start) ||
1509
1594
  factoryReferences.has(target.start)
@@ -1562,6 +1647,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
1562
1647
 
1563
1648
  if (path[0] === 'themes' || path[0] === 'vars') {
1564
1649
  selections.add(config.call.name)
1650
+ selectionUses.add(config.call.name)
1565
1651
  const application = ancestors[index - 1]!
1566
1652
  scopeApplications.set(application.start, {
1567
1653
  end: application.end,
@@ -1623,6 +1709,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
1623
1709
  // A compiled selector is an ordinary runtime function, so passing or storing it is safe.
1624
1710
  if (config.call.selection && !config.call.catalogOnly && !path.length) {
1625
1711
  selections.add(config.call.name)
1712
+ selectionUses.add(config.call.name)
1626
1713
 
1627
1714
  return true
1628
1715
  }
@@ -1640,9 +1727,101 @@ export function collect(program: Ast.Program, options: collect.Options) {
1640
1727
  if (!theme) return false
1641
1728
  if (node.start === binding!.node.start) return true
1642
1729
 
1730
+ if (
1731
+ theme.variableSet &&
1732
+ readVars(
1733
+ node,
1734
+ parent,
1735
+ {
1736
+ call: theme,
1737
+ definition: themes[theme.name]!,
1738
+ },
1739
+ lookup,
1740
+ )
1741
+ )
1742
+ return true
1743
+
1643
1744
  return themeReference(node, parent, ancestors, theme)
1644
1745
  }
1645
1746
 
1747
+ function readVars(
1748
+ node: Ast.Node,
1749
+ parent: Ast.Node,
1750
+ link: Pick<Link, 'call' | 'definition' | 'members'>,
1751
+ lookup: (name: string) => Walker.ScopeTrackerNode | null,
1752
+ ): boolean {
1753
+ if (
1754
+ !options.native ||
1755
+ parent.type !== 'CallExpression' ||
1756
+ parent.optional ||
1757
+ parent.arguments[0] !== node
1758
+ )
1759
+ return false
1760
+
1761
+ const callee = parent.callee
1762
+ const name =
1763
+ callee.type === 'Identifier'
1764
+ ? callee.name
1765
+ : callee.type === 'MemberExpression' &&
1766
+ !callee.computed &&
1767
+ !callee.optional &&
1768
+ callee.object.type === 'Identifier' &&
1769
+ callee.property.type === 'Identifier' &&
1770
+ ['useAnimatedVars', 'useVars'].includes(callee.property.name)
1771
+ ? callee.object.name
1772
+ : undefined
1773
+ const binding = name === undefined ? undefined : lookup(name)
1774
+ if (
1775
+ binding?.type !== 'Import' ||
1776
+ ![
1777
+ 'zyzz/react-native',
1778
+ 'zyzz/react-native/reanimated',
1779
+ 'zyzz/react-native/react',
1780
+ ].includes(binding.importNode.source.value) ||
1781
+ binding.importNode.importKind === 'type'
1782
+ )
1783
+ return false
1784
+
1785
+ const specifier = binding.node
1786
+ if (
1787
+ callee.type === 'Identifier'
1788
+ ? specifier.type !== 'ImportSpecifier' ||
1789
+ specifier.importKind === 'type' ||
1790
+ !['useAnimatedVars', 'useVars'].includes(
1791
+ specifier.imported.type === 'Identifier'
1792
+ ? specifier.imported.name
1793
+ : specifier.imported.value,
1794
+ )
1795
+ : specifier.type !== 'ImportNamespaceSpecifier'
1796
+ )
1797
+ return false
1798
+
1799
+ const named = link.call.options?.themes !== undefined
1800
+ const vars = (() => {
1801
+ if (!named) return { default: link.definition }
1802
+ return Object.fromEntries(
1803
+ Object.entries(link.members ?? {}).flatMap((entry) => {
1804
+ const [key, member] = entry
1805
+ const path = JSON.parse(key) as string[]
1806
+ if (path.length === 1 && link.call.selection)
1807
+ return [[path[0]!, member.definition]]
1808
+ if (path.length === 2 && path[0] === 'themes')
1809
+ return [[path[1]!, member.definition]]
1810
+ return []
1811
+ }),
1812
+ )
1813
+ })()
1814
+ varsReads.push({
1815
+ defaultVars: named ? String(link.call.options!.defaultTheme) : 'default',
1816
+ end: node.end,
1817
+ owner: link.call.name,
1818
+ start: node.start,
1819
+ unnamed: !named,
1820
+ vars,
1821
+ })
1822
+ return true
1823
+ }
1824
+
1646
1825
  function themeReference(
1647
1826
  node: Ast.Node,
1648
1827
  parent: Ast.Node,
@@ -2023,6 +2202,8 @@ export function collect(program: Ast.Program, options: collect.Options) {
2023
2202
  const entries = Object.entries(config.members ?? {}).flatMap(
2024
2203
  ([key, value]) => {
2025
2204
  const path = JSON.parse(key) as string[]
2205
+ if (config.call.selection && path.length === 1)
2206
+ return [[path[0]!, value.definition] as const]
2026
2207
  return (path[0] === 'themes' || path[0] === 'vars') &&
2027
2208
  path.length === 2
2028
2209
  ? [[path[1]!, value.definition] as const]
@@ -2045,10 +2226,12 @@ export function collect(program: Ast.Program, options: collect.Options) {
2045
2226
  scopeApplications,
2046
2227
  scripts,
2047
2228
  selections,
2229
+ selectionUses,
2048
2230
  staticTokens,
2049
2231
  styles,
2050
2232
  themes: Object.freeze(themes),
2051
2233
  tokens,
2234
+ varsReads,
2052
2235
  }
2053
2236
  }
2054
2237
 
@@ -2056,6 +2239,8 @@ export function collect(program: Ast.Program, options: collect.Options) {
2056
2239
  export declare namespace collect {
2057
2240
  /** Stable module namespace, independent of token values and call offsets. */
2058
2241
  type Options = {
2242
+ /** Captures readonly variable arguments for native React hooks. */
2243
+ readonly native?: boolean | undefined
2059
2244
  /** Encoded package/module identity from the source adapter. */
2060
2245
  readonly staticBindings?: ReadonlySet<number> | undefined
2061
2246
  readonly contributionCalls?: ReadonlySet<number> | undefined
@@ -477,6 +477,7 @@ export function collect(
477
477
  function reference(
478
478
  node: Extract<Ast.Node, { type: 'Identifier' | 'JSXIdentifier' }>,
479
479
  parent: Ast.Node,
480
+ ancestors: readonly Ast.Node[],
480
481
  binding: Walker.ScopeTrackerNode | null,
481
482
  ) {
482
483
  if (binding?.type === 'Import' && imports.has(binding.node.start))
@@ -488,7 +489,17 @@ export function collect(
488
489
  : node,
489
490
  ) ?? resolve(node)
490
491
  if (!link) return false
491
- if (link.call.start >= 0 && node.start < link.call.end)
492
+ // Reads inside functions wait for a call, so only module-scope reads must follow the declaration.
493
+ if (
494
+ link.call.start >= 0 &&
495
+ node.start < link.call.end &&
496
+ !ancestors.some(
497
+ (ancestor) =>
498
+ ancestor.type === 'ArrowFunctionExpression' ||
499
+ ancestor.type === 'FunctionDeclaration' ||
500
+ ancestor.type === 'FunctionExpression',
501
+ )
502
+ )
492
503
  throw new InvalidError('Vars must be declared before use.', node)
493
504
  return true
494
505
  }
@@ -11,9 +11,12 @@ export type Properties<
11
11
  styles = Record<string, unknown>,
12
12
  > = {
13
13
  readonly [property in keyof Literal.Properties & keyof styles]?:
14
- | (string extends Literal.Properties[property]
15
- ? never
16
- : Literal.Properties[property])
14
+ // Configured tokens replace literal CSS values, so only token names are suggested.
15
+ | ([Token.Names<tokens, property>] extends [never]
16
+ ? string extends Literal.Properties[property]
17
+ ? never
18
+ : Literal.Properties[property]
19
+ : never)
17
20
  | Token.Names<tokens, property>
18
21
  | (string & {})
19
22
  | number
@@ -147,6 +147,8 @@ export function copy(
147
147
  export function web<name extends string>(
148
148
  style: Style.NamedStyle<name>,
149
149
  ): Style.NamedStyle<name> {
150
+ if (!style.rules && !style.targets) return style
151
+
150
152
  const rules = style.rules?.map((rule) => ({
151
153
  ...rule,
152
154
  style: web(rule.style),
@@ -391,8 +391,6 @@ export const complete = Symbol('zyzz.contract.complete')
391
391
  export type Contract = {
392
392
  /** Whether values belong to independent variables rather than fixed theme categories. */
393
393
  readonly variableSet?: boolean | undefined
394
- /** Custom-property spelling retained by older packed producers. */
395
- readonly variableNaming?: 'legacy' | 'hashed' | undefined
396
394
  /** Configuration-local category-to-property mappings. */
397
395
  readonly mappings?: VariableSets.Mappings | false | undefined
398
396
  /** Web emission mode retained by configuration-bound theme handles. */
@@ -190,6 +190,26 @@ type CheckedArray<values, property extends PropertyKey, tokens> = {
190
190
  >[property]
191
191
  }
192
192
 
193
+ /** Lists the values a token-constrained property accepts, so mismatch diagnostics name them. */
194
+ export type Mismatch<tokens, property extends keyof Literal.Properties> =
195
+ // Resolving through a conditional prints the expected values instead of this alias's arguments.
196
+ tokens extends unknown
197
+ ? Expected<
198
+ | Extract<Token.Names<tokens, property>, string>
199
+ | NumericNames<Token.Names<tokens, property>>
200
+ | `${string} !custom`
201
+ >
202
+ : never
203
+
204
+ // An object brand never reduces with a string literal, so the diagnostic keeps the expected values.
205
+ type Expected<values> = { readonly [expected]: values }
206
+
207
+ declare const expected: unique symbol
208
+
209
+ type NumericNames<names> = names extends `${infer value extends number}`
210
+ ? value
211
+ : never
212
+
193
213
  /** Requires tokens for properties with configured values. */
194
214
  export type Tokens<
195
215
  value,