zyzz 0.0.22 → 0.0.24

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 (96) hide show
  1. package/README.md +6 -6
  2. package/dist/babel/NativeJsx.d.ts.map +1 -1
  3. package/dist/babel/NativeJsx.js +14 -4
  4. package/dist/babel/NativeJsx.js.map +1 -1
  5. package/dist/compiler/Graph.js +78 -35
  6. package/dist/compiler/Graph.js.map +1 -1
  7. package/dist/compiler/internal/Dynamic.d.ts.map +1 -1
  8. package/dist/compiler/internal/Dynamic.js +3 -0
  9. package/dist/compiler/internal/Dynamic.js.map +1 -1
  10. package/dist/compiler/internal/Expression.js +2 -2
  11. package/dist/compiler/internal/Expression.js.map +1 -1
  12. package/dist/compiler/internal/NativeBindings.d.ts.map +1 -1
  13. package/dist/compiler/internal/NativeBindings.js +1 -0
  14. package/dist/compiler/internal/NativeBindings.js.map +1 -1
  15. package/dist/compiler/internal/NativeVars.d.ts.map +1 -1
  16. package/dist/compiler/internal/NativeVars.js +3 -0
  17. package/dist/compiler/internal/NativeVars.js.map +1 -1
  18. package/dist/compiler/internal/Themes.d.ts +2 -0
  19. package/dist/compiler/internal/Themes.d.ts.map +1 -1
  20. package/dist/compiler/internal/Themes.js +24 -22
  21. package/dist/compiler/internal/Themes.js.map +1 -1
  22. package/dist/internal/Configuration.d.ts.map +1 -1
  23. package/dist/internal/Configuration.js +2 -1
  24. package/dist/internal/Configuration.js.map +1 -1
  25. package/dist/metro/Graph.d.ts.map +1 -1
  26. package/dist/metro/Graph.js +11 -2
  27. package/dist/metro/Graph.js.map +1 -1
  28. package/dist/node/Host.d.ts.map +1 -1
  29. package/dist/node/Host.js +40 -12
  30. package/dist/node/Host.js.map +1 -1
  31. package/dist/react-native/StyleSheet.d.ts +7 -3
  32. package/dist/react-native/StyleSheet.d.ts.map +1 -1
  33. package/dist/react-native/StyleSheet.js +8 -0
  34. package/dist/react-native/StyleSheet.js.map +1 -1
  35. package/dist/react-native/internal/Device.js +118 -38
  36. package/dist/react-native/internal/Device.js.map +3 -3
  37. package/dist/react-native/internal/NativeZyzz.js.map +2 -2
  38. package/dist/react-native/internal/Scalar.d.ts +16 -0
  39. package/dist/react-native/internal/Scalar.d.ts.map +1 -1
  40. package/dist/react-native/internal/Scalar.js +53 -2
  41. package/dist/react-native/internal/Scalar.js.map +1 -1
  42. package/dist/react-native/internal/Store.d.ts +4 -0
  43. package/dist/react-native/internal/Store.d.ts.map +1 -1
  44. package/dist/react-native/internal/Store.js.map +1 -1
  45. package/dist/react-native/internal/Styles.d.ts +19 -0
  46. package/dist/react-native/internal/Styles.d.ts.map +1 -0
  47. package/dist/react-native/internal/Styles.js +35 -0
  48. package/dist/react-native/internal/Styles.js.map +1 -0
  49. package/dist/react-native/internal/Viewport.d.ts +6 -0
  50. package/dist/react-native/internal/Viewport.d.ts.map +1 -1
  51. package/dist/react-native/internal/Viewport.js +2 -0
  52. package/dist/react-native/internal/Viewport.js.map +1 -1
  53. package/dist/react-native/react.d.ts +44 -16
  54. package/dist/react-native/react.d.ts.map +1 -1
  55. package/dist/react-native/react.js +68 -47
  56. package/dist/react-native/react.js.map +1 -1
  57. package/dist/runtime/NativeContext.d.ts +6 -0
  58. package/dist/runtime/NativeContext.d.ts.map +1 -1
  59. package/dist/runtime/NativeContext.js +62 -9
  60. package/dist/runtime/NativeContext.js.map +1 -1
  61. package/dist/runtime/NativeDynamic.d.ts.map +1 -1
  62. package/dist/runtime/NativeDynamic.js +5 -0
  63. package/dist/runtime/NativeDynamic.js.map +1 -1
  64. package/dist/unplugin/index.d.ts.map +1 -1
  65. package/dist/unplugin/index.js +4 -1
  66. package/dist/unplugin/index.js.map +1 -1
  67. package/dist/variants.d.ts +3 -2
  68. package/dist/variants.d.ts.map +1 -1
  69. package/dist/variants.js.map +1 -1
  70. package/native/NativeZyzz.cpp +52 -65
  71. package/native/NativeZyzz.h +0 -4
  72. package/native/ZyzzSpecJSI.h +0 -10
  73. package/native/android/ZyzzSpec-generated.cpp +0 -6
  74. package/package.json +1 -1
  75. package/src/babel/NativeJsx.ts +17 -8
  76. package/src/compiler/Graph.ts +89 -38
  77. package/src/compiler/internal/Dynamic.ts +4 -0
  78. package/src/compiler/internal/Expression.ts +2 -2
  79. package/src/compiler/internal/NativeBindings.ts +1 -0
  80. package/src/compiler/internal/NativeVars.ts +3 -0
  81. package/src/compiler/internal/Themes.ts +29 -23
  82. package/src/internal/Configuration.ts +2 -1
  83. package/src/metro/Graph.ts +17 -2
  84. package/src/node/Host.ts +64 -17
  85. package/src/react-native/StyleSheet.ts +32 -9
  86. package/src/react-native/internal/Device.ts +196 -49
  87. package/src/react-native/internal/NativeZyzz.ts +4 -6
  88. package/src/react-native/internal/Scalar.ts +73 -2
  89. package/src/react-native/internal/Store.ts +4 -0
  90. package/src/react-native/internal/Styles.ts +77 -0
  91. package/src/react-native/internal/Viewport.ts +7 -0
  92. package/src/react-native/react.ts +142 -72
  93. package/src/runtime/NativeContext.ts +83 -9
  94. package/src/runtime/NativeDynamic.ts +7 -0
  95. package/src/unplugin/index.ts +4 -1
  96. package/src/variants.ts +3 -2
@@ -157,6 +157,7 @@ export function prepare(
157
157
  if (
158
158
  !Object.hasOwn(Scalar.properties, property) ||
159
159
  [
160
+ 'flex',
160
161
  'transform',
161
162
  'origin',
162
163
  'shadow',
@@ -155,6 +155,7 @@ export function compile(options: compile.Options): Runtime.create.Options {
155
155
  if (
156
156
  typeof kind === 'string' &&
157
157
  [
158
+ 'flex',
158
159
  'fontVariant',
159
160
  'origin',
160
161
  'shadow',
@@ -171,6 +172,8 @@ export function compile(options: compile.Options): Runtime.create.Options {
171
172
  )
172
173
  if (kind === 'box' || kind === 'boxSigned')
173
174
  return Scalar.length(value, options, kind === 'boxSigned', [path])
175
+ if (kind === 'boxOffset')
176
+ return Scalar.convert('offset', value, options, [path])
174
177
  return Scalar.convert(kind, value, options, [path])
175
178
  }
176
179
 
@@ -120,6 +120,34 @@ export type VarsRead = {
120
120
  readonly vars: Readonly<Record<string, Theme.Definition>>
121
121
  }
122
122
 
123
+ /** Resolves the variable alternatives a linked configuration or variable set exposes to native hooks. */
124
+ export function varsRead(
125
+ link: Pick<Link, 'call' | 'definition' | 'members'>,
126
+ ): Omit<VarsRead, 'end' | 'start'> {
127
+ const named = link.call.options?.themes !== undefined
128
+ const vars = (() => {
129
+ if (!named) return { default: link.definition }
130
+ return Object.fromEntries(
131
+ Object.entries(link.members ?? {}).flatMap((entry) => {
132
+ const [key, member] = entry
133
+ const path = JSON.parse(key) as string[]
134
+ if (path.length === 1 && link.call.selection)
135
+ return [[path[0]!, member.definition]]
136
+ if (path.length === 2 && path[0] === 'themes')
137
+ return [[path[1]!, member.definition]]
138
+ return []
139
+ }),
140
+ )
141
+ })()
142
+
143
+ return {
144
+ defaultVars: named ? String(link.call.options!.defaultTheme) : 'default',
145
+ owner: link.call.name,
146
+ unnamed: !named,
147
+ vars,
148
+ }
149
+ }
150
+
123
151
  /** Shared graph data; no filesystem or runtime evaluation is involved. */
124
152
  export type Context = {
125
153
  /** Canonical identifier names collected during graph validation. */
@@ -1796,29 +1824,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
1796
1824
  )
1797
1825
  return false
1798
1826
 
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
- })
1827
+ varsReads.push({ ...varsRead(link), end: node.end, start: node.start })
1822
1828
  return true
1823
1829
  }
1824
1830
 
@@ -63,7 +63,8 @@ export function create(
63
63
  ? (value as Vars.Definition)
64
64
  : Vars.define(value as Vars.Values)
65
65
  const theme = VariableSets.theme(definition, variableMappings)
66
- if (variableMappings === false) return theme
66
+ // Tokens are ambiguous only through an explicit mapping, so skip the property scan without one.
67
+ if (!variableMappings) return theme
67
68
  const metadata = theme[Token.definition]
68
69
  const names = new Map<string, string>()
69
70
  for (const path of Object.keys(metadata.values)) {
@@ -148,7 +148,10 @@ export function read(
148
148
  seen.add(filename)
149
149
  const source = snapshot.readSync(filename)
150
150
  const file = manifest(filename)
151
- if (file && !/['"]zyzz(?:\/default)?['"]/.test(source)) {
151
+ if (
152
+ file &&
153
+ !/['"]zyzz(?:\/default|\/react-native(?:\/react)?)?['"]/.test(source)
154
+ ) {
152
155
  const data = JSON.parse(snapshot.readSync(file)) as Record<
153
156
  string,
154
157
  unknown
@@ -174,7 +177,19 @@ export function read(
174
177
  for (const node of snapshot.parse({ moduleId: identity(filename), source })
175
178
  .program.body) {
176
179
  const name = specifier(node)
177
- if (name === 'zyzz' || name === 'zyzz/default') {
180
+ // Consumers import vars profiles from defineConfig modules, so those modules must compile.
181
+ const native =
182
+ (name === 'zyzz/react-native' || name === 'zyzz/react-native/react') &&
183
+ node.type === 'ImportDeclaration' &&
184
+ node.specifiers.some(
185
+ (entry) =>
186
+ entry.type === 'ImportSpecifier' &&
187
+ entry.importKind !== 'type' &&
188
+ (entry.imported.type === 'Identifier'
189
+ ? entry.imported.name
190
+ : entry.imported.value) === 'defineConfig',
191
+ )
192
+ if (name === 'zyzz' || name === 'zyzz/default' || native) {
178
193
  authored.add(filename)
179
194
  return true
180
195
  }
package/src/node/Host.ts CHANGED
@@ -13,6 +13,7 @@ import * as Graph from '../compiler/Graph.js'
13
13
  import * as AtRules from '../compiler/internal/AtRules.js'
14
14
  import * as Catalogs from '../compiler/internal/Catalogs.js'
15
15
  import * as Relative from '../compiler/internal/Relative.js'
16
+ import * as Scheme from '../internal/Scheme.js'
16
17
  import * as Snapshot from './internal/Snapshot.js'
17
18
  import * as Syntax from '../compiler/internal/Syntax.js'
18
19
  import * as Source from '../compiler/Source.js'
@@ -620,7 +621,10 @@ export async function create(options: create.Options): Promise<Runtime> {
620
621
  artifacts.set('zyzz.shared.css.map', shared.map)
621
622
  }
622
623
 
623
- const moduleStylesheets = new Map<string, Stylesheet>()
624
+ const moduleStylesheets = new Map<
625
+ string,
626
+ { name: string; stylesheet: Stylesheet }
627
+ >()
624
628
 
625
629
  for (const name of Object.keys(sources)) {
626
630
  const output = graph.modules[`${options.packageId}/${name}`]!
@@ -661,23 +665,40 @@ export async function create(options: create.Options): Promise<Runtime> {
661
665
 
662
666
  artifacts.set(`${name}.css`, stylesheet.code)
663
667
  artifacts.set(`${name}.css.map`, stylesheet.map)
664
- // Module URLs resolve beside the module file; the complete stylesheet at
665
- // the output root carries a copy with those URLs rebased.
666
- moduleStylesheets.set(
667
- `${options.packageId}/${name}`,
668
- rebase(stylesheet, name, css === false ? false : css.minify),
669
- )
668
+ moduleStylesheets.set(`${options.packageId}/${name}`, {
669
+ name,
670
+ stylesheet,
671
+ })
670
672
  }
671
673
 
672
674
  // The complete stylesheet follows the module graph so a consumer's rules
673
675
  // cascade over the rules of the modules it imports.
674
676
  if (shared || moduleStylesheets.size) {
675
- const complete = concatenate([
676
- ...(shared ? [shared] : []),
677
- ...order(graph.dependencies, [...moduleStylesheets.keys()]).map(
678
- (id) => moduleStylesheets.get(id)!,
679
- ),
680
- ])
677
+ const parts = shared ? [shared] : []
678
+ let schemes = false
679
+
680
+ // Each module stylesheet declares the scheme classes to load alone. The
681
+ // complete stylesheet keeps the first declaration.
682
+ for (const id of order(graph.dependencies, [
683
+ ...moduleStylesheets.keys(),
684
+ ])) {
685
+ const { name, stylesheet } = moduleStylesheets.get(id)!
686
+ const declares = Object.values(Scheme.classes).some((className) =>
687
+ stylesheet.code.includes(`.${className}`),
688
+ )
689
+
690
+ parts.push(
691
+ rebase(
692
+ stylesheet,
693
+ name,
694
+ css === false ? false : css.minify,
695
+ schemes && declares,
696
+ ),
697
+ )
698
+ schemes ||= declares
699
+ }
700
+
701
+ const complete = concatenate(parts)
681
702
 
682
703
  artifacts.set('zyzz.css', complete.code)
683
704
  artifacts.set('zyzz.css.map', complete.map)
@@ -1025,7 +1046,7 @@ function concatenate(parts: readonly { code: string; map: string }[]) {
1025
1046
  let offset = 0
1026
1047
 
1027
1048
  for (const part of parts) {
1028
- if (!part.code) continue
1049
+ if (!part.code.trim()) continue
1029
1050
 
1030
1051
  const code = part.code.endsWith('\n') ? part.code : `${part.code}\n`
1031
1052
  const traced = Mapping.fromMap(part.map)
@@ -1169,15 +1190,22 @@ async function read(
1169
1190
  }
1170
1191
  }
1171
1192
 
1172
- /** Rewrites a nested module stylesheet's relative URLs against the output root. */
1193
+ /**
1194
+ * Copies a module stylesheet into the complete stylesheet at the output root,
1195
+ * rebasing nested relative URLs and optionally dropping the scheme rules.
1196
+ */
1173
1197
  function rebase(
1174
1198
  stylesheet: { code: string; map: string },
1175
1199
  name: string,
1176
1200
  minify: boolean,
1201
+ schemes: boolean,
1177
1202
  ) {
1178
1203
  const directory = Path.posix.dirname(name)
1179
1204
 
1180
- if (directory === '.' || !stylesheet.code.includes('url(')) return stylesheet
1205
+ if (!schemes && (directory === '.' || !stylesheet.code.includes('url(')))
1206
+ return stylesheet
1207
+
1208
+ const classes = Object.values(Scheme.classes)
1181
1209
 
1182
1210
  const result = AtRules.transform({
1183
1211
  code: Buffer.from(stylesheet.code),
@@ -1186,8 +1214,27 @@ function rebase(
1186
1214
  minify,
1187
1215
  sourceMap: true,
1188
1216
  visitor: {
1217
+ Rule: {
1218
+ style(rule) {
1219
+ const [selector, ...others] = rule.value.selectors
1220
+ const [component, ...rest] = selector ?? []
1221
+
1222
+ if (
1223
+ schemes &&
1224
+ !others.length &&
1225
+ !rest.length &&
1226
+ component?.type === 'class' &&
1227
+ classes.includes(component.name)
1228
+ )
1229
+ return []
1230
+ },
1231
+ },
1189
1232
  Url(url) {
1190
- if (/^(?:\/|[?#]|[a-z][a-z\d+.-]*:)/i.test(url.url)) return url
1233
+ if (
1234
+ directory === '.' ||
1235
+ /^(?:\/|[?#]|[a-z][a-z\d+.-]*:)/i.test(url.url)
1236
+ )
1237
+ return url
1191
1238
 
1192
1239
  return { ...url, url: Path.posix.join(directory, url.url) }
1193
1240
  },
@@ -278,6 +278,14 @@ export function compile<
278
278
  output[`${property}Right`] = right!
279
279
  output[`${property}Bottom`] = bottom!
280
280
  output[`${property}Left`] = left!
281
+ } else if (property === 'flex') {
282
+ Object.assign(output, Scalar.flex(value, options, path))
283
+ } else if (property === 'inset') {
284
+ const values =
285
+ typeof value === 'string' ? Calculation.parts(value) : [value]
286
+ const [top, right = top, bottom = top, left = right] =
287
+ values.map((value) => convert('offset', value, options, path))
288
+ Object.assign(output, { top, right, bottom, left })
281
289
  } else if (
282
290
  property === 'borderColor' ||
283
291
  property === 'borderWidth'
@@ -613,15 +621,26 @@ type Length =
613
621
  | `${number}px`
614
622
  | `${number}rem`
615
623
  | `${'c' | 'C'}${'a' | 'A'}${'l' | 'L'}${'c' | 'C'}(${string})`
616
- type Box =
617
- | Length
618
- | `${Length} ${Length}`
619
- | `${Length} ${Length} ${Length}`
620
- | Box4
624
+ type Box<item extends string | number = Length> =
625
+ | item
626
+ | `${item} ${item}`
627
+ | `${item} ${item} ${item}`
628
+ | Box4<item>
621
629
  // Distribute the first item to keep case-insensitive calculations below the template expansion limit.
622
- type Box4<first extends string | number = Length> = first extends unknown
623
- ? `${first} ${Length} ${Length} ${Length}`
624
- : never
630
+ type Box4<
631
+ item extends string | number,
632
+ first extends string | number = item,
633
+ > = first extends unknown ? `${first} ${item} ${item} ${item}` : never
634
+ type FlexBasis = Length | `${number}%` | 'auto'
635
+ type Flex =
636
+ | number
637
+ | 'initial'
638
+ | 'none'
639
+ | FlexBasis
640
+ | `${number} ${number | FlexBasis}`
641
+ | `${FlexBasis} ${number}`
642
+ | `${number} ${number} ${FlexBasis}`
643
+ | `${FlexBasis} ${number} ${number}`
625
644
  type Weight =
626
645
  | 'bold'
627
646
  | 'normal'
@@ -666,7 +685,11 @@ type Atom<kind> = kind extends readonly string[]
666
685
  ? Length | number
667
686
  : kind extends 'box' | 'boxSigned'
668
687
  ? Box
669
- : Length
688
+ : kind extends 'boxOffset'
689
+ ? Box<Length | `${number}%`>
690
+ : kind extends 'flex'
691
+ ? Flex
692
+ : Length
670
693
 
671
694
  type Reference<property extends keyof typeof properties> = {
672
695
  [group in Token.Group]: property extends Token.Properties<group>