zyzz 0.0.21 → 0.0.23

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 (233) 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 +217 -15
  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 +107 -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/Dynamic.d.ts.map +1 -1
  37. package/dist/compiler/internal/Dynamic.js +3 -0
  38. package/dist/compiler/internal/Dynamic.js.map +1 -1
  39. package/dist/compiler/internal/Expression.js +2 -2
  40. package/dist/compiler/internal/Expression.js.map +1 -1
  41. package/dist/compiler/internal/NativeBindings.d.ts +24 -26
  42. package/dist/compiler/internal/NativeBindings.d.ts.map +1 -1
  43. package/dist/compiler/internal/NativeBindings.js +62 -8
  44. package/dist/compiler/internal/NativeBindings.js.map +1 -1
  45. package/dist/compiler/internal/NativeMedia.d.ts +14 -0
  46. package/dist/compiler/internal/NativeMedia.d.ts.map +1 -0
  47. package/dist/compiler/internal/NativeMedia.js +287 -0
  48. package/dist/compiler/internal/NativeMedia.js.map +1 -0
  49. package/dist/compiler/internal/NativeVars.d.ts +28 -0
  50. package/dist/compiler/internal/NativeVars.d.ts.map +1 -0
  51. package/dist/compiler/internal/NativeVars.js +160 -0
  52. package/dist/compiler/internal/NativeVars.js.map +1 -0
  53. package/dist/compiler/internal/PackedStyles.d.ts +2 -0
  54. package/dist/compiler/internal/PackedStyles.d.ts.map +1 -1
  55. package/dist/compiler/internal/PackedStyles.js +2 -0
  56. package/dist/compiler/internal/PackedStyles.js.map +1 -1
  57. package/dist/compiler/internal/Themes.d.ts +24 -1
  58. package/dist/compiler/internal/Themes.d.ts.map +1 -1
  59. package/dist/compiler/internal/Themes.js +120 -3
  60. package/dist/compiler/internal/Themes.js.map +1 -1
  61. package/dist/compiler/internal/Vars.d.ts +1 -1
  62. package/dist/compiler/internal/Vars.d.ts.map +1 -1
  63. package/dist/compiler/internal/Vars.js +7 -2
  64. package/dist/compiler/internal/Vars.js.map +1 -1
  65. package/dist/default.js.zyzz.json +1 -1
  66. package/dist/internal/Completion.d.ts +1 -1
  67. package/dist/internal/Completion.d.ts.map +1 -1
  68. package/dist/internal/Targets.d.ts.map +1 -1
  69. package/dist/internal/Targets.js +2 -0
  70. package/dist/internal/Targets.js.map +1 -1
  71. package/dist/internal/Token.d.ts +0 -2
  72. package/dist/internal/Token.d.ts.map +1 -1
  73. package/dist/internal/Token.js.map +1 -1
  74. package/dist/internal/Value.d.ts +7 -0
  75. package/dist/internal/Value.d.ts.map +1 -1
  76. package/dist/internal/Value.js.map +1 -1
  77. package/dist/metro/Graph.d.ts +22 -7
  78. package/dist/metro/Graph.d.ts.map +1 -1
  79. package/dist/metro/Graph.js +188 -42
  80. package/dist/metro/Graph.js.map +1 -1
  81. package/dist/metro/Watch.d.ts +28 -4
  82. package/dist/metro/Watch.d.ts.map +1 -1
  83. package/dist/metro/Watch.js +39 -7
  84. package/dist/metro/Watch.js.map +1 -1
  85. package/dist/metro/index.d.ts +15 -4
  86. package/dist/metro/index.d.ts.map +1 -1
  87. package/dist/metro/index.js +27 -0
  88. package/dist/metro/index.js.map +1 -1
  89. package/dist/metro/transformer.d.ts +5 -1
  90. package/dist/metro/transformer.d.ts.map +1 -1
  91. package/dist/metro/transformer.js +5 -3
  92. package/dist/metro/transformer.js.map +1 -1
  93. package/dist/react-native/StyleSheet.d.ts +8 -3
  94. package/dist/react-native/StyleSheet.d.ts.map +1 -1
  95. package/dist/react-native/StyleSheet.js +25 -34
  96. package/dist/react-native/StyleSheet.js.map +1 -1
  97. package/dist/react-native/index.d.ts +1 -1
  98. package/dist/react-native/index.d.ts.map +1 -1
  99. package/dist/react-native/index.js +1 -1
  100. package/dist/react-native/index.js.map +1 -1
  101. package/dist/react-native/index.native.d.ts +5 -0
  102. package/dist/react-native/index.native.js +20 -0
  103. package/dist/react-native/index.native.js.map +7 -0
  104. package/dist/react-native/internal/Calculation.d.ts +7 -0
  105. package/dist/react-native/internal/Calculation.d.ts.map +1 -0
  106. package/dist/react-native/internal/Calculation.js +134 -0
  107. package/dist/react-native/internal/Calculation.js.map +1 -0
  108. package/dist/react-native/internal/Device.js +218 -0
  109. package/dist/react-native/internal/Device.js.map +7 -0
  110. package/dist/react-native/internal/NativeZyzz.js +7 -0
  111. package/dist/react-native/internal/NativeZyzz.js.map +7 -0
  112. package/dist/react-native/internal/Scalar.d.ts +16 -0
  113. package/dist/react-native/internal/Scalar.d.ts.map +1 -1
  114. package/dist/react-native/internal/Scalar.js +62 -4
  115. package/dist/react-native/internal/Scalar.js.map +1 -1
  116. package/dist/react-native/internal/Store.d.ts +32 -0
  117. package/dist/react-native/internal/Store.d.ts.map +1 -0
  118. package/dist/react-native/internal/Store.js +57 -0
  119. package/dist/react-native/internal/Store.js.map +1 -0
  120. package/dist/react-native/internal/Styles.d.ts +19 -0
  121. package/dist/react-native/internal/Styles.d.ts.map +1 -0
  122. package/dist/react-native/internal/Styles.js +35 -0
  123. package/dist/react-native/internal/Styles.js.map +1 -0
  124. package/dist/react-native/internal/Tokens.d.ts +21 -0
  125. package/dist/react-native/internal/Tokens.d.ts.map +1 -0
  126. package/dist/react-native/internal/Tokens.js +58 -0
  127. package/dist/react-native/internal/Tokens.js.map +1 -0
  128. package/dist/react-native/internal/Viewport.d.ts +6 -0
  129. package/dist/react-native/internal/Viewport.d.ts.map +1 -0
  130. package/dist/react-native/internal/Viewport.js +4 -0
  131. package/dist/react-native/internal/Viewport.js.map +1 -0
  132. package/dist/react-native/react.d.ts +102 -14
  133. package/dist/react-native/react.d.ts.map +1 -1
  134. package/dist/react-native/react.js +86 -18
  135. package/dist/react-native/react.js.map +1 -1
  136. package/dist/react-native/reanimated.d.ts +39 -0
  137. package/dist/react-native/reanimated.d.ts.map +1 -0
  138. package/dist/react-native/reanimated.js +76 -0
  139. package/dist/react-native/reanimated.js.map +1 -0
  140. package/dist/runtime/NativeContext.d.ts +10 -1
  141. package/dist/runtime/NativeContext.d.ts.map +1 -1
  142. package/dist/runtime/NativeContext.js +67 -14
  143. package/dist/runtime/NativeContext.js.map +1 -1
  144. package/dist/runtime/NativeDynamic.d.ts +3 -2
  145. package/dist/runtime/NativeDynamic.d.ts.map +1 -1
  146. package/dist/runtime/NativeDynamic.js +37 -7
  147. package/dist/runtime/NativeDynamic.js.map +1 -1
  148. package/dist/runtime/NativeStatic.d.ts +23 -0
  149. package/dist/runtime/NativeStatic.d.ts.map +1 -0
  150. package/dist/runtime/NativeStatic.js +106 -0
  151. package/dist/runtime/NativeStatic.js.map +1 -0
  152. package/dist/runtime/NativeVars.d.ts +53 -0
  153. package/dist/runtime/NativeVars.d.ts.map +1 -0
  154. package/dist/runtime/NativeVars.js +77 -0
  155. package/dist/runtime/NativeVars.js.map +1 -0
  156. package/dist/runtime/index.d.ts +4 -0
  157. package/dist/runtime/index.d.ts.map +1 -1
  158. package/dist/runtime/index.js +4 -0
  159. package/dist/runtime/index.js.map +1 -1
  160. package/dist/runtime/internal/NativeMedia.d.ts +25 -0
  161. package/dist/runtime/internal/NativeMedia.d.ts.map +1 -0
  162. package/dist/runtime/internal/NativeMedia.js +36 -0
  163. package/dist/runtime/internal/NativeMedia.js.map +1 -0
  164. package/dist/vite/index.d.ts.map +1 -1
  165. package/dist/vite/index.js +7 -35
  166. package/dist/vite/index.js.map +1 -1
  167. package/dist/web/Css.d.ts.map +1 -1
  168. package/dist/web/Css.js +31 -19
  169. package/dist/web/Css.js.map +1 -1
  170. package/dist/web/internal/Themes.d.ts +0 -2
  171. package/dist/web/internal/Themes.d.ts.map +1 -1
  172. package/dist/web/internal/Themes.js +30 -28
  173. package/dist/web/internal/Themes.js.map +1 -1
  174. package/dist/web/page.d.ts +2 -0
  175. package/dist/web/page.d.ts.map +1 -1
  176. package/native/NativeZyzz.cpp +215 -0
  177. package/native/NativeZyzz.h +52 -0
  178. package/native/ZyzzSpecJSI.h +65 -0
  179. package/native/android/CMakeLists.txt +8 -0
  180. package/native/android/ZyzzSpec-generated.cpp +50 -0
  181. package/native/android/ZyzzSpec.h +31 -0
  182. package/native/ios/ZyzzModuleProvider.mm +13 -0
  183. package/package.json +39 -1
  184. package/react-native.config.ts +14 -0
  185. package/src/Style.ts +11 -8
  186. package/src/babel/NativeJsx.ts +319 -33
  187. package/src/babel/index.ts +21 -3
  188. package/src/compiler/Graph.ts +126 -0
  189. package/src/compiler/Native.ts +158 -26
  190. package/src/compiler/Source.ts +32 -5
  191. package/src/compiler/internal/Configurations.ts +25 -3
  192. package/src/compiler/internal/Contract.ts +98 -50
  193. package/src/compiler/internal/Contributions.ts +7 -1
  194. package/src/compiler/internal/Descriptors.ts +12 -8
  195. package/src/compiler/internal/Dynamic.ts +4 -0
  196. package/src/compiler/internal/Expression.ts +2 -2
  197. package/src/compiler/internal/NativeBindings.ts +99 -15
  198. package/src/compiler/internal/NativeMedia.ts +342 -0
  199. package/src/compiler/internal/NativeVars.ts +231 -0
  200. package/src/compiler/internal/PackedStyles.ts +4 -0
  201. package/src/compiler/internal/Themes.ts +193 -2
  202. package/src/compiler/internal/Vars.ts +12 -1
  203. package/src/internal/Completion.ts +6 -3
  204. package/src/internal/Targets.ts +2 -0
  205. package/src/internal/Token.ts +0 -2
  206. package/src/internal/Value.ts +20 -0
  207. package/src/metro/Graph.ts +250 -50
  208. package/src/metro/Watch.ts +95 -10
  209. package/src/metro/index.ts +62 -4
  210. package/src/metro/transformer.ts +21 -11
  211. package/src/react-native/StyleSheet.ts +56 -49
  212. package/src/react-native/index.native.ts +10 -0
  213. package/src/react-native/index.ts +1 -1
  214. package/src/react-native/internal/Calculation.ts +159 -0
  215. package/src/react-native/internal/Device.ts +297 -0
  216. package/src/react-native/internal/NativeZyzz.ts +20 -0
  217. package/src/react-native/internal/Scalar.ts +86 -4
  218. package/src/react-native/internal/Store.ts +78 -0
  219. package/src/react-native/internal/Styles.ts +77 -0
  220. package/src/react-native/internal/Tokens.ts +85 -0
  221. package/src/react-native/internal/Viewport.ts +8 -0
  222. package/src/react-native/react.ts +218 -26
  223. package/src/react-native/reanimated.ts +162 -0
  224. package/src/runtime/NativeContext.ts +88 -17
  225. package/src/runtime/NativeDynamic.ts +42 -10
  226. package/src/runtime/NativeStatic.ts +145 -0
  227. package/src/runtime/NativeVars.ts +189 -0
  228. package/src/runtime/index.ts +6 -0
  229. package/src/runtime/internal/NativeMedia.ts +63 -0
  230. package/src/vite/index.ts +9 -42
  231. package/src/web/Css.ts +42 -27
  232. package/src/web/internal/Themes.ts +34 -57
  233. package/src/web/page.ts +2 -0
@@ -26,7 +26,7 @@ export function read(
26
26
  if (
27
27
  ![
28
28
  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
29
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
29
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
30
30
  ].includes(data.version as number)
31
31
  )
32
32
  throw new Error('Unsupported Zyzz contract version.')
@@ -58,26 +58,11 @@ export function read(
58
58
  for (const entry of Object.values(record(data.exports))) collect(entry)
59
59
  }
60
60
 
61
- function variableNaming(
62
- entry: Record<string, unknown>,
63
- identity: string,
64
- ): 'legacy' | 'hashed' | undefined {
65
- if (entry.variableNaming !== undefined) {
66
- if ((data.version as number) >= 30 && entry.variableNaming === 'legacy')
67
- return 'legacy'
68
- if ((data.version as number) >= 31 && entry.variableNaming === 'hashed')
69
- return 'hashed'
70
- throw new Error('Invalid packed variable naming scheme.')
71
- }
72
- if ((data.version as number) <= 30) {
73
- if (
74
- identity.startsWith('src-') ||
75
- (data.version === 30 && identity.startsWith('id-'))
61
+ function validateVariables(entry: Record<string, unknown>) {
62
+ if ((data.version as number) < 31 || entry.variableNaming !== undefined)
63
+ throw new Error(
64
+ 'Legacy packed variable names are unsupported. Rebuild the library with the current version of Zyzz.',
76
65
  )
77
- return 'hashed'
78
- return 'legacy'
79
- }
80
- return undefined
81
66
  }
82
67
 
83
68
  function decode(value: unknown): unknown {
@@ -114,19 +99,14 @@ export function read(
114
99
  if (Object.hasOwn(fields, '$variable')) {
115
100
  const reference = record(fields.$variable)
116
101
  const identity = string(reference.identity)
117
- const naming = variableNaming(reference, identity)
102
+ validateVariables(reference)
118
103
  let contract = identities.get(identity)
119
104
  if (contract && !contract.variableSet)
120
105
  throw new Error(
121
106
  'Conflicting packed variable-set modes for one identity.',
122
107
  )
123
- if (contract && contract.variableNaming !== naming)
124
- throw new Error(
125
- 'Conflicting packed variable naming schemes for one identity.',
126
- )
127
108
  if (!contract) {
128
109
  contract = Object.freeze({
129
- ...(naming ? { variableNaming: naming } : {}),
130
110
  variableSet: true,
131
111
  [Token.identity]: identity,
132
112
  })
@@ -150,7 +130,11 @@ export function read(
150
130
  for (const [name, value] of Object.entries(record(data.themes))) {
151
131
  const entry = record(value)
152
132
  const identity = string(entry.identity)
153
- const naming = variableNaming(entry, identity)
133
+ if (
134
+ Object.keys(record(entry.tokens)).length ||
135
+ entry.variableNaming !== undefined
136
+ )
137
+ validateVariables(entry)
154
138
  if (entry.variableSet === true && (data.version as number) < 28)
155
139
  throw new Error('Vars contracts require contract version 28 or later.')
156
140
  const mappings = VariableSets.mappings(entry.mappings)
@@ -209,13 +193,8 @@ export function read(
209
193
  'Conflicting packed default layers for one theme identity.',
210
194
  )
211
195
 
212
- if (contract && contract.variableNaming !== naming)
213
- throw new Error(
214
- 'Conflicting packed variable naming schemes for one identity.',
215
- )
216
196
  if (!contract) {
217
197
  contract = Object.freeze({
218
- ...(naming ? { variableNaming: naming } : {}),
219
198
  ...(entry.variableSet === true
220
199
  ? {
221
200
  variableSet: true,
@@ -267,6 +246,8 @@ export function read(
267
246
 
268
247
  function link(value: unknown): Themes.Link {
269
248
  const raw = record(value)
249
+ if (raw.nativeProvider !== undefined && (data.version as number) < 32)
250
+ throw new Error('Native providers require contract version 32 or later.')
270
251
  // Contracts before version 19 record style authoring exports as `css`.
271
252
  const entry =
272
253
  raw.kind === 'css' && (data.version as number) < 19
@@ -352,7 +333,7 @@ export function read(
352
333
  if (
353
334
  ![
354
335
  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
355
- 27, 28, 29, 30, 31,
336
+ 27, 28, 29, 30, 31, 32, 33,
356
337
  ].includes(data.version as number) ||
357
338
  ![
358
339
  'cssFunction',
@@ -421,6 +402,34 @@ export function read(
421
402
  return [key, member]
422
403
  }),
423
404
  )
405
+ const nativeContext = (() => {
406
+ if (entry.nativeContext === undefined) return undefined
407
+ if ((data.version as number) < 33)
408
+ throw new Error(
409
+ 'Native style catalogs require contract version 33 or later.',
410
+ )
411
+ if (entry.style === undefined)
412
+ throw new Error('Native style catalogs require a packed style.')
413
+ const context = record(entry.nativeContext)
414
+ const vars = Object.fromEntries(
415
+ Object.entries(record(context.vars)).map((entry) => {
416
+ const [name, value] = entry
417
+ const theme = themes[string(value)]
418
+ if (!name || !theme)
419
+ throw new Error('Unknown packed native style catalog.')
420
+ return [name, theme]
421
+ }),
422
+ )
423
+ const defaultVars = string(context.defaultVars)
424
+ if (!Object.hasOwn(vars, defaultVars))
425
+ throw new Error('Invalid packed native style default.')
426
+ const identities = new Set(
427
+ Object.values(vars).map((theme) => theme[Token.definition].contract),
428
+ )
429
+ if (identities.size !== 1)
430
+ throw new Error('Incompatible packed native style catalog.')
431
+ return { defaultVars, vars }
432
+ })()
424
433
  return {
425
434
  binding,
426
435
  call: {
@@ -434,11 +443,14 @@ export function read(
434
443
  ...(entry.style === undefined
435
444
  ? {}
436
445
  : {
437
- style: PackedStyles.read(
438
- entry.style,
439
- themes,
440
- data.version as number,
441
- ),
446
+ style: {
447
+ ...PackedStyles.read(
448
+ entry.style,
449
+ themes,
450
+ data.version as number,
451
+ ),
452
+ ...(nativeContext ? { nativeContext } : {}),
453
+ },
442
454
  }),
443
455
  ...(members ? { members } : {}),
444
456
  }
@@ -523,9 +535,11 @@ export function read(
523
535
  !!options?.themes &&
524
536
  ((data.version as number) < 4 || entry.catalogOnly === true)
525
537
  const fullConfigType = options
526
- ? entry.variableConfig === true
527
- ? `import('zyzz').Config.VariableConfig<${Configurations.type(variableOptions(options, entry.variableMappings as Vars.Mappings | false | undefined))}>`
528
- : `import('zyzz').Config.create.ReturnType<${Configurations.type(options)}>`
538
+ ? entry.nativeProvider === true
539
+ ? `import('zyzz/react-native/react').defineConfig.ReturnType<${Configurations.type(entry.variableConfig === true ? variableOptions(options, entry.variableMappings as Vars.Mappings | false | undefined) : options)}>`
540
+ : entry.variableConfig === true
541
+ ? `import('zyzz').Config.VariableConfig<${Configurations.type(variableOptions(options, entry.variableMappings as Vars.Mappings | false | undefined))}>`
542
+ : `import('zyzz').Config.create.ReturnType<${Configurations.type(options)}>`
529
543
  : ''
530
544
  // Helpers a legacy library did not compile are hidden from its consumers' types.
531
545
  const hidden = [
@@ -544,6 +558,7 @@ export function read(
544
558
  return {
545
559
  binding: string(entry.binding),
546
560
  call: {
561
+ ...(entry.nativeProvider === true ? { nativeProvider: true } : {}),
547
562
  ...(entry.variableSet === true
548
563
  ? {
549
564
  variableSet: true,
@@ -718,6 +733,28 @@ export function write(
718
733
  return {
719
734
  binding: link.binding,
720
735
  kind: link.kind,
736
+ ...(link.style?.nativeContext
737
+ ? {
738
+ nativeContext: {
739
+ defaultVars: link.style.nativeContext.defaultVars,
740
+ vars: Object.fromEntries(
741
+ Object.entries(link.style.nativeContext.vars).map((entry) => {
742
+ const [name, definition] = entry
743
+ const theme = Object.entries(themes).find(
744
+ (candidate) =>
745
+ candidate[1][Token.definition].contract ===
746
+ definition[Token.definition].contract &&
747
+ JSON.stringify(input(candidate[1])) ===
748
+ JSON.stringify(input(definition)),
749
+ )
750
+ if (!theme)
751
+ throw new Error('Missing packed native style catalog.')
752
+ return [name, theme[0]]
753
+ }),
754
+ ),
755
+ },
756
+ }
757
+ : {}),
721
758
  ...(link.style ? { style: PackedStyles.write(link.style) } : {}),
722
759
  ...(link.members
723
760
  ? {
@@ -733,6 +770,7 @@ export function write(
733
770
 
734
771
  return {
735
772
  ...(link.call.variableSet ? { variableSet: true } : {}),
773
+ ...(link.call.nativeProvider ? { nativeProvider: true } : {}),
736
774
  ...(link.call.directVariables ? { directVariables: true } : {}),
737
775
  ...(link.call.variableConfig
738
776
  ? { variableConfig: true, variableMappings: link.call.variableMappings }
@@ -800,18 +838,31 @@ export function write(
800
838
  mappings: theme[Token.definition].contract.mappings,
801
839
  }
802
840
  : {}),
803
- ...(theme[Token.definition].contract.variableNaming
804
- ? {
805
- variableNaming: theme[Token.definition].contract.variableNaming,
806
- }
807
- : {}),
808
841
  identity: theme[Token.definition].contract[Token.identity],
809
842
  tokens: encode(input(theme)),
810
843
  },
811
844
  ]),
812
845
  ),
813
- version: 31,
846
+ version: Object.values(links).some(nativeCatalog)
847
+ ? 33
848
+ : Object.values(links).some(nativeProvider)
849
+ ? 32
850
+ : 31,
814
851
  })
852
+
853
+ function nativeProvider(link: Themes.Link): boolean {
854
+ return (
855
+ link.call.nativeProvider === true ||
856
+ Object.values(link.members ?? {}).some(nativeProvider)
857
+ )
858
+ }
859
+
860
+ function nativeCatalog(link: Themes.Link): boolean {
861
+ return (
862
+ Boolean(link.style?.nativeContext) ||
863
+ Object.values(link.members ?? {}).some(nativeCatalog)
864
+ )
865
+ }
815
866
  }
816
867
 
817
868
  /** Contract writer contracts. */
@@ -894,9 +945,6 @@ function encode(value: unknown): unknown {
894
945
  if (Token.is(value))
895
946
  return {
896
947
  $variable: {
897
- ...(value.contract.variableNaming
898
- ? { variableNaming: value.contract.variableNaming }
899
- : {}),
900
948
  identity: value.contract[Token.identity],
901
949
  path: value.path,
902
950
  value: encode(value.value),
@@ -1025,7 +1025,13 @@ export function extract(
1025
1025
  ]
1026
1026
  if (
1027
1027
  !margin &&
1028
- ['bleed', 'marks', 'pageOrientation', 'size'].includes(key)
1028
+ [
1029
+ 'bleed',
1030
+ 'marks',
1031
+ 'pageMarginSafety',
1032
+ 'pageOrientation',
1033
+ 'size',
1034
+ ].includes(key)
1029
1035
  ) {
1030
1036
  if (typeof value !== 'string' && typeof value !== 'number')
1031
1037
  throw new Error('Expected a scalar page descriptor.')
@@ -8,11 +8,11 @@ export function check(options: check.Options): void {
8
8
  /[A-Z]/g,
9
9
  (letter) => `-${letter.toLowerCase()}`,
10
10
  )
11
- const result = Tree.lexer.matchAtruleDescriptor(
12
- options.rule,
13
- name,
14
- options.value,
15
- )
11
+ // The pinned parser predates this page descriptor.
12
+ const result =
13
+ options.rule === 'page' && name === 'page-margin-safety'
14
+ ? Tree.lexer.match('none | clamp | add', options.value)
15
+ : Tree.lexer.matchAtruleDescriptor(options.rule, name, options.value)
16
16
  if (result.error)
17
17
  throw new Error(`Invalid @${options.rule} ${name}: ${result.error.message}`)
18
18
  if (
@@ -102,9 +102,13 @@ export function validate(source: string): void {
102
102
  rule.block.children.forEach((declaration) => {
103
103
  if (declaration.type !== 'Declaration') return
104
104
  if (
105
- ['bleed', 'marks', 'page-orientation', 'size'].includes(
106
- declaration.property,
107
- )
105
+ [
106
+ 'bleed',
107
+ 'marks',
108
+ 'page-margin-safety',
109
+ 'page-orientation',
110
+ 'size',
111
+ ].includes(declaration.property)
108
112
  )
109
113
  check({
110
114
  rule: 'page',
@@ -154,6 +154,10 @@ export function read(
154
154
  (value) => Number.isSafeInteger(value) && value !== 0,
155
155
  )
156
156
 
157
+ // Native conversion rejects degenerate and negative ratios.
158
+ if (rule.kind === 'ratio')
159
+ return values.every((value) => Number.isFinite(value) && value > 0)
160
+
157
161
  if (rule.kind !== 'number') return false
158
162
 
159
163
  return values.every(
@@ -21,7 +21,7 @@ export function acceptsColor(
21
21
  return 'var(--zyzz-reference)'
22
22
  })
23
23
  .join('')
24
- .replace(/ !important$/, '')
24
+ .replace(/(?: !custom)?(?: !important)?$/, '')
25
25
 
26
26
  try {
27
27
  return (
@@ -61,7 +61,7 @@ export function acceptsVariables(
61
61
  (value) =>
62
62
  Tree.lexer.matchProperty(
63
63
  Literal.name(property),
64
- value.replace(/ !important$/, ''),
64
+ value.replace(/(?: !custom)?(?: !important)?$/, ''),
65
65
  ).error === null,
66
66
  )
67
67
  } catch {
@@ -1,13 +1,32 @@
1
1
  /** Lowers target-neutral callback declarations to ordered native binding data. @module */
2
- import type * as Recipe from '../../internal/Recipe.js'
3
2
  import * as Binding from '../../internal/Binding.js'
4
- import * as Token from '../../internal/Token.js'
5
- import type * as Style from '../../Style.js'
6
- import * as StyleSheet from '../../react-native/StyleSheet.js'
7
- import * as Scalar from '../../react-native/internal/Scalar.js'
8
- import type * as Runtime from '../../runtime/NativeDynamic.js'
9
3
  import type * as Native from '../Native.js'
4
+ import type * as Recipe from '../../internal/Recipe.js'
5
+ import type * as Runtime from '../../runtime/NativeDynamic.js'
6
+ import * as Scalar from '../../react-native/internal/Scalar.js'
10
7
  import type * as Source from '../Source.js'
8
+ import type * as Static from '../../runtime/NativeStatic.js'
9
+ import type * as Style from '../../Style.js'
10
+ import * as StyleSheet from '../../react-native/StyleSheet.js'
11
+ import * as Token from '../../internal/Token.js'
12
+ import * as Tokens from '../../react-native/internal/Tokens.js'
13
+
14
+ type Step = Runtime.Program['rules'][number]['steps'][number]
15
+ type PreparedStep =
16
+ | Extract<Step, { readonly style: string }>
17
+ | {
18
+ readonly property: keyof typeof Scalar.properties
19
+ readonly parts: readonly (
20
+ | string
21
+ | number
22
+ | Token.Reference
23
+ | { readonly slot: string; readonly number?: true }
24
+ )[]
25
+ }
26
+ type PreparedRule = {
27
+ readonly matches: Runtime.Program['rules'][number]['matches']
28
+ readonly steps: readonly PreparedStep[]
29
+ }
11
30
 
12
31
  /** Compiles static fragments and retains scalar assignments in authored order. */
13
32
  export function compile(
@@ -16,8 +35,36 @@ export function compile(
16
35
  options: Native.compile.Options,
17
36
  prepared = prepare(recipe, call, options),
18
37
  ): Runtime.create.Options {
38
+ const selected = options.vars?.[options.set ?? 'default']
39
+ const metadata =
40
+ selected &&
41
+ (Object.getOwnPropertyDescriptor(selected, Token.definition)?.value as
42
+ | Token.Metadata
43
+ | undefined)
19
44
  return {
20
45
  ...prepared,
46
+ program: {
47
+ slots: prepared.program.slots,
48
+ rules: prepared.program.rules.map((rule) => ({
49
+ ...rule,
50
+ steps: rule.steps.map((step) =>
51
+ 'style' in step
52
+ ? step
53
+ : {
54
+ ...step,
55
+ parts: step.parts.map((part) =>
56
+ Token.is(part)
57
+ ? Tokens.resolve(part, {
58
+ ...options,
59
+ metadata,
60
+ resolution: { schemeIndependent: true },
61
+ })
62
+ : part,
63
+ ),
64
+ },
65
+ ),
66
+ })),
67
+ },
21
68
  styles: StyleSheet.select(prepared.styles, {
22
69
  set: options.set ?? 'default',
23
70
  colorScheme: options.colorScheme,
@@ -25,6 +72,39 @@ export function compile(
25
72
  }
26
73
  }
27
74
 
75
+ /** Removes dynamic instructions and resolves absolute line heights before publication. */
76
+ export function finite(options: Runtime.create.Options): Static.create.Options {
77
+ const styles = { ...options.styles }
78
+ return {
79
+ axes: options.axes,
80
+ defaults: options.defaults,
81
+ rules: options.program.rules.map((rule) => ({
82
+ matches: rule.matches,
83
+ steps: rule.steps.map((step) => {
84
+ if ('style' in step) return step.style
85
+ if (
86
+ step.property !== 'lineHeight' ||
87
+ !step.parts.length ||
88
+ step.parts.some((part) => typeof part === 'object')
89
+ )
90
+ throw new Error(
91
+ 'Static native recipes cannot contain runtime bindings.',
92
+ )
93
+ const value = (
94
+ step.parts.length === 1 ? step.parts[0]! : step.parts.join('')
95
+ ) as string | number
96
+ if (typeof value === 'number') return value
97
+ const name = String(Object.keys(styles).length)
98
+ styles[name] = {
99
+ lineHeight: Scalar.length(value, options, false, ['lineHeight']),
100
+ }
101
+ return name
102
+ }),
103
+ })),
104
+ styles,
105
+ }
106
+ }
107
+
28
108
  /** Prepares immutable programs and all set/scheme tables before selection. */
29
109
  export function prepare(
30
110
  recipe: Recipe.Definition,
@@ -41,15 +121,10 @@ export function prepare(
41
121
  ),
42
122
  ])
43
123
  const fragments: Style.NamedStyle[] = []
44
- const rules: Runtime.Program['rules'][number][] = []
45
- let count = 1
46
- for (const choices of Object.values(recipe.axes)) count *= choices.length + 1
47
- if (count > 256)
48
- throw new Error(
49
- 'Native recipes support at most 256 selections, including null choices.',
50
- )
124
+ const rules: PreparedRule[] = []
125
+
51
126
  for (const rule of recipe.rules) {
52
- const steps: Runtime.Program['rules'][number]['steps'][number][] = []
127
+ const steps: PreparedStep[] = []
53
128
  function fragment(style: Style.NamedStyle) {
54
129
  const name = String(fragments.length)
55
130
  fragments.push({ ...style, name })
@@ -82,6 +157,7 @@ export function prepare(
82
157
  if (
83
158
  !Object.hasOwn(Scalar.properties, property) ||
84
159
  [
160
+ 'flex',
85
161
  'transform',
86
162
  'origin',
87
163
  'shadow',
@@ -94,14 +170,22 @@ export function prepare(
94
170
  )
95
171
  const values = parts.map((part) => {
96
172
  if (typeof part === 'string' || typeof part === 'number') return part
173
+ if (Token.is(part)) return part
97
174
  if (!Binding.is(part) || !available.has(part.name))
98
175
  throw new Error(
99
176
  'Native bindings require declared runtime scalar fields.',
100
177
  )
101
- return { slot: part.name }
178
+ return {
179
+ slot: part.name,
180
+ ...(part.type === 'number' ? { number: true as const } : {}),
181
+ }
102
182
  })
183
+ const calculation = values.some(
184
+ (value) => typeof value === 'string' && /(?:^|\s)calc\(/i.test(value),
185
+ )
103
186
  if (
104
187
  values.length > 1 &&
188
+ !calculation &&
105
189
  !(
106
190
  values.length === 2 &&
107
191
  typeof values[0] === 'object' &&