@tamagui/static 1.100.6 → 1.101.1

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 (63) hide show
  1. package/dist/cjs/extractor/createExtractor.js +21 -12
  2. package/dist/cjs/extractor/createExtractor.js.map +1 -1
  3. package/dist/cjs/extractor/createExtractor.native.js +18 -12
  4. package/dist/cjs/extractor/createExtractor.native.js.map +2 -2
  5. package/dist/cjs/extractor/extractMediaStyle.js +2 -2
  6. package/dist/cjs/extractor/extractMediaStyle.js.map +1 -1
  7. package/dist/cjs/extractor/extractMediaStyle.native.js +2 -2
  8. package/dist/cjs/extractor/extractMediaStyle.native.js.map +2 -2
  9. package/dist/cjs/extractor/extractToClassNames.js +17 -15
  10. package/dist/cjs/extractor/extractToClassNames.js.map +1 -1
  11. package/dist/cjs/extractor/extractToClassNames.native.js +12 -14
  12. package/dist/cjs/extractor/extractToClassNames.native.js.map +2 -2
  13. package/dist/cjs/extractor/extractToNative.js +319 -0
  14. package/dist/cjs/extractor/extractToNative.js.map +6 -0
  15. package/dist/cjs/extractor/extractToNative.native.js +353 -0
  16. package/dist/cjs/extractor/extractToNative.native.js.map +6 -0
  17. package/dist/cjs/index.js +1 -0
  18. package/dist/cjs/index.js.map +1 -1
  19. package/dist/cjs/index.native.js +2 -0
  20. package/dist/cjs/index.native.js.map +1 -1
  21. package/dist/esm/extractor/createExtractor.js +24 -11
  22. package/dist/esm/extractor/createExtractor.js.map +1 -1
  23. package/dist/esm/extractor/createExtractor.mjs +16 -12
  24. package/dist/esm/extractor/createExtractor.native.js +18 -11
  25. package/dist/esm/extractor/createExtractor.native.js.map +2 -2
  26. package/dist/esm/extractor/extractMediaStyle.js +2 -2
  27. package/dist/esm/extractor/extractMediaStyle.js.map +1 -1
  28. package/dist/esm/extractor/extractMediaStyle.mjs +2 -2
  29. package/dist/esm/extractor/extractMediaStyle.native.js +2 -2
  30. package/dist/esm/extractor/extractMediaStyle.native.js.map +2 -2
  31. package/dist/esm/extractor/extractToClassNames.js +16 -15
  32. package/dist/esm/extractor/extractToClassNames.js.map +1 -1
  33. package/dist/esm/extractor/extractToClassNames.mjs +14 -16
  34. package/dist/esm/extractor/extractToClassNames.native.js +11 -14
  35. package/dist/esm/extractor/extractToClassNames.native.js.map +2 -2
  36. package/dist/esm/extractor/extractToNative.js +309 -0
  37. package/dist/esm/extractor/extractToNative.js.map +6 -0
  38. package/dist/esm/extractor/extractToNative.mjs +232 -0
  39. package/dist/esm/extractor/extractToNative.native.js +329 -0
  40. package/dist/esm/extractor/extractToNative.native.js.map +6 -0
  41. package/dist/esm/index.js +1 -0
  42. package/dist/esm/index.js.map +1 -1
  43. package/dist/esm/index.mjs +1 -0
  44. package/dist/esm/index.native.js +1 -0
  45. package/dist/esm/index.native.js.map +1 -1
  46. package/package.json +16 -15
  47. package/src/extractor/createExtractor.ts +23 -22
  48. package/src/extractor/extractMediaStyle.ts +2 -2
  49. package/src/extractor/extractToClassNames.ts +30 -16
  50. package/src/extractor/extractToNative.ts +504 -0
  51. package/src/index.ts +1 -0
  52. package/types/extractor/babelParse.d.ts +0 -1
  53. package/types/extractor/babelParse.d.ts.map +1 -1
  54. package/types/extractor/createEvaluator.d.ts.map +1 -1
  55. package/types/extractor/createExtractor.d.ts.map +1 -1
  56. package/types/extractor/extractToClassNames.d.ts +0 -1
  57. package/types/extractor/extractToClassNames.d.ts.map +1 -1
  58. package/types/extractor/extractToNative.d.ts +13 -0
  59. package/types/extractor/extractToNative.d.ts.map +1 -0
  60. package/types/extractor/getStaticBindingsForScope.d.ts.map +1 -1
  61. package/types/extractor/loadTamagui.d.ts.map +1 -1
  62. package/types/index.d.ts +1 -0
  63. package/types/index.d.ts.map +1 -1
@@ -190,18 +190,24 @@ export async function extractToClassNames({
190
190
 
191
191
  for (const style of styles) {
192
192
  // leave them as attributes
193
- const prop = style.pseudo
194
- ? `${style.property}-${style.pseudo}`
195
- : style.property
193
+ const prop = style[helpers.StyleObjectPseudo]
194
+ ? `${style[helpers.StyleObjectProperty]}-${
195
+ style[helpers.StyleObjectPseudo]
196
+ }`
197
+ : style[helpers.StyleObjectProperty]
196
198
  finalAttrs.push(
197
- t.jsxAttribute(t.jsxIdentifier(prop), t.stringLiteral(style.identifier))
199
+ t.jsxAttribute(
200
+ t.jsxIdentifier(prop),
201
+ t.stringLiteral(style[helpers.StyleObjectIdentifier])
202
+ )
198
203
  )
199
204
  }
200
205
  } else {
201
206
  const styles = addStyles(attr.value)
202
207
  const newFontFamily = getFontFamilyClassNameFromProps(attr.value) || ''
203
208
  const newClassNames = helpers.concatClassName(
204
- styles.map((x) => x.identifier).join(' ') + newFontFamily
209
+ styles.map((x) => x[helpers.StyleObjectIdentifier]).join(' ') +
210
+ newFontFamily
205
211
  )
206
212
  const existing = finalClassNames.find(
207
213
  (x) => x.type == 'StringLiteral'
@@ -266,11 +272,18 @@ export async function extractToClassNames({
266
272
  console.info(
267
273
  'ternary (mediaStyles)',
268
274
  mediaExtraction.ternaryWithoutMedia?.inlineMediaQuery ?? '',
269
- mediaExtraction.mediaStyles.map((x) => x.identifier).join('.')
275
+ mediaExtraction.mediaStyles
276
+ .map((x) => x[helpers.StyleObjectIdentifier])
277
+ .join('.')
270
278
  )
271
279
  }
272
280
  }
273
281
  if (!mediaExtraction) {
282
+ if (shouldPrintDebug) {
283
+ if (mediaExtraction) {
284
+ console.info('add ternary')
285
+ }
286
+ }
274
287
  addTernaryStyle(
275
288
  attr.value,
276
289
  addStyles(attr.value.consequent),
@@ -291,7 +304,9 @@ export async function extractToClassNames({
291
304
  } else {
292
305
  finalClassNames = [
293
306
  ...finalClassNames,
294
- ...mediaExtraction.mediaStyles.map((x) => t.stringLiteral(x.identifier)),
307
+ ...mediaExtraction.mediaStyles.map((x) =>
308
+ t.stringLiteral(x[helpers.StyleObjectIdentifier])
309
+ ),
295
310
  ]
296
311
  }
297
312
  break
@@ -299,9 +314,9 @@ export async function extractToClassNames({
299
314
  }
300
315
  }
301
316
 
302
- function addTernaryStyle(ternary: Ternary, a: any, b: any) {
303
- const cCN = a.map((x) => x.identifier).join(' ')
304
- const aCN = b.map((x) => x.identifier).join(' ')
317
+ function addTernaryStyle(ternary: Ternary, a: StyleObject[], b: StyleObject[]) {
318
+ const cCN = a.map((x) => x[helpers.StyleObjectIdentifier]).join(' ')
319
+ const aCN = b.map((x) => x[helpers.StyleObjectIdentifier]).join(' ')
305
320
 
306
321
  if (a.length && b.length) {
307
322
  finalClassNames.push(
@@ -322,11 +337,8 @@ export async function extractToClassNames({
322
337
  }
323
338
  }
324
339
 
325
- if (shouldPrintDebug) {
326
- console.info(
327
- ' finalClassNames\n',
328
- logLines(finalClassNames.map((x) => x['value']).join(' '))
329
- )
340
+ if (shouldPrintDebug === 'verbose') {
341
+ console.info(' finalClassNames AST\n', JSON.stringify(finalClassNames, null, 2))
330
342
  }
331
343
 
332
344
  node.attributes = finalAttrs
@@ -389,7 +401,9 @@ export async function extractToClassNames({
389
401
  originalNodeName
390
402
  )
391
403
 
392
- for (const { identifier, rules } of finalStyles) {
404
+ for (const styleObject of finalStyles) {
405
+ const identifier = styleObject[helpers.StyleObjectIdentifier]
406
+ const rules = styleObject[helpers.StyleObjectRules]
393
407
  const className = `.${identifier}`
394
408
  if (cssMap.has(className)) {
395
409
  if (comment) {
@@ -0,0 +1,504 @@
1
+ import { basename } from 'node:path'
2
+
3
+ import { type BabelFileResult, transformFromAstSync } from '@babel/core'
4
+ import generator from '@babel/generator'
5
+ import { declare } from '@babel/helper-plugin-utils'
6
+ import { parse } from '@babel/parser'
7
+ import template from '@babel/template'
8
+ import * as t from '@babel/types'
9
+ import type { TamaguiOptions } from '@tamagui/static'
10
+ import {
11
+ createExtractor,
12
+ createLogger,
13
+ getPragmaOptions,
14
+ isSimpleSpread,
15
+ literalToAst,
16
+ loadTamaguiBuildConfigSync,
17
+ } from '@tamagui/static'
18
+
19
+ const importNativeView = template(`
20
+ const __ReactNativeView = require('react-native').View;
21
+ const __ReactNativeText = require('react-native').Text;
22
+ `)
23
+
24
+ const importStyleSheet = template(`
25
+ const __ReactNativeStyleSheet = require('react-native').StyleSheet;
26
+ `)
27
+
28
+ const importWithStyle = template(`
29
+ const __withStableStyle = require('@tamagui/core')._withStableStyle;
30
+ `)
31
+
32
+ const extractor = createExtractor({ platform: 'native' })
33
+
34
+ let tamaguiBuildOptionsLoaded: TamaguiOptions | null
35
+
36
+ export function extractToNative(
37
+ sourceFileName: string,
38
+ sourceCode: string,
39
+ options: TamaguiOptions
40
+ ): BabelFileResult {
41
+ const ast = parse(sourceCode, {
42
+ sourceType: 'module',
43
+ plugins: ['jsx', 'typescript'],
44
+ })
45
+
46
+ const babelPlugin = getBabelPlugin()
47
+
48
+ const out = transformFromAstSync(ast, sourceCode, {
49
+ plugins: [[babelPlugin, options]],
50
+ configFile: false,
51
+ sourceFileName,
52
+ filename: sourceFileName,
53
+ })
54
+
55
+ if (!out) {
56
+ throw new Error(`No output returned`)
57
+ }
58
+
59
+ return out
60
+ }
61
+
62
+ export function getBabelPlugin() {
63
+ return declare((api, options: TamaguiOptions) => {
64
+ api.assertVersion(7)
65
+ return getBabelParseDefinition(options)
66
+ })
67
+ }
68
+
69
+ export function getBabelParseDefinition(options: TamaguiOptions) {
70
+ return {
71
+ name: 'tamagui',
72
+
73
+ visitor: {
74
+ Program: {
75
+ enter(this: any, root) {
76
+ let sourcePath = this.file.opts.filename
77
+ if (sourcePath?.includes('node_modules')) {
78
+ return
79
+ }
80
+ // by default only pick up .jsx / .tsx
81
+ if (!sourcePath?.endsWith('.jsx') && !sourcePath?.endsWith('.tsx')) {
82
+ return
83
+ }
84
+
85
+ // this filename comes back incorrect in react-native, it adds /ios/ for some reason
86
+ // adding a fix here, but it's a bit tentative...
87
+ if (process.env.SOURCE_ROOT?.endsWith('ios')) {
88
+ sourcePath = sourcePath.replace('/ios', '')
89
+ }
90
+
91
+ let hasImportedView = false
92
+ let hasImportedViewWrapper = false
93
+ const sheetStyles = {}
94
+ const sheetIdentifier = root.scope.generateUidIdentifier('sheet')
95
+
96
+ // babel doesnt append the `//` so we need to
97
+ const firstCommentContents = // join because you can join together multiple pragmas
98
+ root.node.body[0]?.leadingComments
99
+ ?.map((comment) => comment?.value || ' ')
100
+ .join(' ') ?? ''
101
+ const firstComment = firstCommentContents ? `//${firstCommentContents}` : ''
102
+
103
+ const { shouldPrintDebug, shouldDisable } = getPragmaOptions({
104
+ source: firstComment,
105
+ path: sourcePath,
106
+ })
107
+
108
+ if (shouldDisable) {
109
+ return
110
+ }
111
+
112
+ if (!options.config && !options.components) {
113
+ // if no config/components given try and load from the tamagui.build.ts file
114
+ tamaguiBuildOptionsLoaded ||= loadTamaguiBuildConfigSync({})
115
+ }
116
+
117
+ const finalOptions = {
118
+ // @ts-ignore just in case they leave it out
119
+ platform: 'native',
120
+ ...tamaguiBuildOptionsLoaded,
121
+ ...options,
122
+ } satisfies TamaguiOptions
123
+
124
+ const printLog = createLogger(sourcePath, finalOptions)
125
+
126
+ function addSheetStyle(style: any, node: t.JSXOpeningElement) {
127
+ const styleIndex = `${Object.keys(sheetStyles).length}`
128
+ let key = `${styleIndex}`
129
+ if (process.env.NODE_ENV === 'development') {
130
+ const lineNumbers = node.loc
131
+ ? node.loc.start.line +
132
+ (node.loc.start.line !== node.loc.end.line
133
+ ? `-${node.loc.end.line}`
134
+ : '')
135
+ : ''
136
+ key += `:${basename(sourcePath)}:${lineNumbers}`
137
+ }
138
+ sheetStyles[key] = style
139
+ return readStyleExpr(key)
140
+ }
141
+
142
+ function readStyleExpr(key: string) {
143
+ return template(`SHEET['KEY']`)({
144
+ SHEET: sheetIdentifier.name,
145
+ KEY: key,
146
+ })['expression'] as t.MemberExpression
147
+ }
148
+
149
+ let res
150
+
151
+ try {
152
+ res = extractor.parseSync(root, {
153
+ importsWhitelist: ['constants.js', 'colors.js'],
154
+ extractStyledDefinitions: options.forceExtractStyleDefinitions,
155
+ excludeProps: new Set([
156
+ 'className',
157
+ 'userSelect',
158
+ 'whiteSpace',
159
+ 'textOverflow',
160
+ 'cursor',
161
+ 'contain',
162
+ ]),
163
+ shouldPrintDebug,
164
+ ...finalOptions,
165
+ // disable this extraction for now at least, need to figure out merging theme vs non-theme
166
+ // because theme need to stay in render(), whereas non-theme can be extracted
167
+ // for now just turn it off entirely at a small perf loss
168
+ disableExtractInlineMedia: true,
169
+ // disable extracting variables as no native concept of them (only theme values)
170
+ disableExtractVariables: options.experimentalFlattenThemesOnNative
171
+ ? false
172
+ : 'theme',
173
+ sourcePath,
174
+
175
+ // disabling flattening for now
176
+ // it's flattening a plain <Paragraph>hello</Paragraph> which breaks things because themes
177
+ // thinking it's not really worth the effort to do much compilation on native
178
+ // for now just disable flatten as it can only run in narrow places on native
179
+ // disableFlattening: 'styled',
180
+
181
+ getFlattenedNode({ isTextView }) {
182
+ if (!hasImportedView) {
183
+ hasImportedView = true
184
+ root.unshiftContainer('body', importNativeView())
185
+ }
186
+ return isTextView ? '__ReactNativeText' : '__ReactNativeView'
187
+ },
188
+
189
+ onExtractTag(props) {
190
+ const { isFlattened } = props
191
+
192
+ if (!isFlattened) {
193
+ // we aren't optimizing at all if not flattened anymore
194
+ return
195
+ }
196
+
197
+ assertValidTag(props.node)
198
+ const stylesExpr = t.arrayExpression([])
199
+ const hocStylesExpr = t.arrayExpression([])
200
+ const expressions: t.Expression[] = []
201
+ const finalAttrs: (t.JSXAttribute | t.JSXSpreadAttribute)[] = []
202
+ const themeKeysUsed = new Set<string>()
203
+
204
+ function getStyleExpression(style: Object | null) {
205
+ if (!style) return
206
+
207
+ // split theme properties and leave them as props since RN has no concept of theme
208
+ const { plain, themed } = splitThemeStyles(style)
209
+
210
+ // TODO: themed is not a good name, because it's not just theme it also includes tokens
211
+ let themeExpr: t.ObjectExpression | null = null
212
+ if (themed && options.experimentalFlattenThemesOnNative) {
213
+ for (const key in themed) {
214
+ themeKeysUsed.add(themed[key].split('$')[1])
215
+ }
216
+
217
+ // make a sub-array
218
+ themeExpr = getThemedStyleExpression(themed)
219
+ }
220
+ const ident = addSheetStyle(plain, props.node)
221
+ if (themeExpr) {
222
+ addStyleExpression(ident)
223
+ addStyleExpression(ident, true)
224
+ return themeExpr
225
+ }
226
+ // since we only do flattened disabling this path
227
+ return ident
228
+ }
229
+
230
+ function addStyleExpression(expr: any, HOC = false) {
231
+ if (Array.isArray(expr)) {
232
+ ;(HOC ? hocStylesExpr : stylesExpr).elements.push(...expr)
233
+ } else {
234
+ ;(HOC ? hocStylesExpr : stylesExpr).elements.push(expr)
235
+ }
236
+ }
237
+
238
+ function getThemedStyleExpression(styles: Object) {
239
+ const themedStylesAst = literalToAst(styles) as t.ObjectExpression
240
+ themedStylesAst.properties.forEach((_) => {
241
+ const prop = _ as t.ObjectProperty
242
+ if (prop.value.type === 'StringLiteral') {
243
+ prop.value = t.memberExpression(
244
+ t.identifier('theme'),
245
+ t.identifier(prop.value.value.slice(1) + '.get()')
246
+ )
247
+ }
248
+ })
249
+ return themedStylesAst
250
+ }
251
+
252
+ let hasDynamicStyle = false
253
+
254
+ for (const attr of props.attrs) {
255
+ switch (attr.type) {
256
+ case 'style': {
257
+ let styleExpr = getStyleExpression(attr.value)
258
+ addStyleExpression(styleExpr)
259
+ if (options.experimentalFlattenThemesOnNative) {
260
+ addStyleExpression(styleExpr, true)
261
+ }
262
+ break
263
+ }
264
+
265
+ case 'ternary': {
266
+ const { consequent, alternate } = attr.value
267
+ const consExpr = getStyleExpression(consequent)
268
+ const altExpr = getStyleExpression(alternate)
269
+
270
+ if (options.experimentalFlattenThemesOnNative) {
271
+ expressions.push(attr.value.test)
272
+ addStyleExpression(
273
+ t.conditionalExpression(
274
+ t.identifier(`_expressions[${expressions.length - 1}]`),
275
+ consExpr || t.nullLiteral(),
276
+ altExpr || t.nullLiteral()
277
+ ),
278
+ true
279
+ )
280
+ }
281
+
282
+ const styleExpr = t.conditionalExpression(
283
+ attr.value.test,
284
+ consExpr || t.nullLiteral(),
285
+ altExpr || t.nullLiteral()
286
+ )
287
+ addStyleExpression(
288
+ styleExpr
289
+ // TODO: what is this for ?
290
+ // isFlattened ? simpleHash(JSON.stringify({ consequent, alternate })) : undefined
291
+ )
292
+ break
293
+ }
294
+
295
+ case 'dynamic-style': {
296
+ hasDynamicStyle = true
297
+ expressions.push(attr.value as t.Expression)
298
+ if (options.experimentalFlattenDynamicValues) {
299
+ addStyleExpression(
300
+ t.objectExpression([
301
+ t.objectProperty(
302
+ t.identifier(attr.name as string),
303
+ t.identifier(`_expressions[${expressions.length - 1}]`)
304
+ ),
305
+ ]),
306
+ true
307
+ )
308
+ } else {
309
+ addStyleExpression(
310
+ t.objectExpression([
311
+ t.objectProperty(
312
+ t.identifier(attr.name as string),
313
+ attr.value as t.Expression
314
+ ),
315
+ ])
316
+ )
317
+ }
318
+ break
319
+ }
320
+
321
+ case 'attr': {
322
+ if (t.isJSXSpreadAttribute(attr.value)) {
323
+ if (isSimpleSpread(attr.value)) {
324
+ stylesExpr.elements.push(
325
+ t.memberExpression(attr.value.argument, t.identifier('style'))
326
+ )
327
+ if (options.experimentalFlattenThemesOnNative) {
328
+ hocStylesExpr.elements.push(
329
+ t.memberExpression(
330
+ attr.value.argument,
331
+ t.identifier('style')
332
+ )
333
+ )
334
+ }
335
+ }
336
+ }
337
+ finalAttrs.push(attr.value)
338
+ break
339
+ }
340
+ }
341
+ }
342
+
343
+ props.node.attributes = finalAttrs
344
+
345
+ if (props.isFlattened) {
346
+ if (
347
+ options.experimentalFlattenThemesOnNative &&
348
+ (themeKeysUsed.size ||
349
+ hocStylesExpr.elements.length > 1 ||
350
+ hasDynamicStyle)
351
+ ) {
352
+ if (!hasImportedViewWrapper) {
353
+ root.unshiftContainer('body', importWithStyle())
354
+ hasImportedViewWrapper = true
355
+ }
356
+
357
+ const name = props.node.name['name']
358
+ const WrapperIdentifier = root.scope.generateUidIdentifier(
359
+ name + 'Wrapper'
360
+ )
361
+
362
+ root.pushContainer(
363
+ 'body',
364
+ t.variableDeclaration('const', [
365
+ t.variableDeclarator(
366
+ WrapperIdentifier,
367
+ t.callExpression(t.identifier('__withStableStyle'), [
368
+ t.identifier(name),
369
+ t.arrowFunctionExpression(
370
+ [t.identifier('theme'), t.identifier('_expressions')],
371
+ t.blockStatement([
372
+ t.returnStatement(
373
+ t.callExpression(
374
+ t.memberExpression(
375
+ t.identifier('React'),
376
+ t.identifier('useMemo')
377
+ ),
378
+ [
379
+ t.arrowFunctionExpression(
380
+ [],
381
+ t.blockStatement([
382
+ t.returnStatement(
383
+ t.arrayExpression([...hocStylesExpr.elements])
384
+ ),
385
+ ])
386
+ ),
387
+ t.arrayExpression([
388
+ t.spreadElement(t.identifier('_expressions')),
389
+ ]),
390
+ ]
391
+ )
392
+ ),
393
+ ])
394
+ ),
395
+ ])
396
+ ),
397
+ ])
398
+ )
399
+
400
+ // @ts-ignore
401
+ props.node.name = WrapperIdentifier
402
+ if (props.jsxPath.node.closingElement) {
403
+ // @ts-ignore
404
+ props.jsxPath.node.closingElement.name = WrapperIdentifier
405
+ }
406
+
407
+ if (expressions.length) {
408
+ props.node.attributes.push(
409
+ t.jsxAttribute(
410
+ t.jsxIdentifier('expressions'),
411
+ t.jsxExpressionContainer(t.arrayExpression(expressions))
412
+ )
413
+ )
414
+ }
415
+ } else {
416
+ props.node.attributes.push(
417
+ t.jsxAttribute(
418
+ t.jsxIdentifier('style'),
419
+ t.jsxExpressionContainer(
420
+ stylesExpr.elements.length === 1
421
+ ? (stylesExpr.elements[0] as any)
422
+ : stylesExpr
423
+ )
424
+ )
425
+ )
426
+ }
427
+ }
428
+ },
429
+ })
430
+ } catch (err) {
431
+ if (err instanceof Error) {
432
+ // metro doesn't show stack so we can
433
+ let message = `${shouldPrintDebug === 'verbose' ? err : err.message}`
434
+ if (message.includes('Unexpected return value from visitor method')) {
435
+ message = 'Unexpected return value from visitor method'
436
+ }
437
+ console.warn('Error in Tamagui parse, skipping', message, err.stack)
438
+ return
439
+ }
440
+ }
441
+
442
+ if (!Object.keys(sheetStyles).length) {
443
+ if (shouldPrintDebug) {
444
+ console.info('END no styles')
445
+ }
446
+ if (res) printLog(res)
447
+ return
448
+ }
449
+
450
+ const sheetObject = literalToAst(sheetStyles)
451
+ const sheetOuter = template(
452
+ 'const SHEET = __ReactNativeStyleSheet.create(null)'
453
+ )({
454
+ SHEET: sheetIdentifier.name,
455
+ }) as any
456
+
457
+ // replace the null with our object
458
+ sheetOuter.declarations[0].init.arguments[0] = sheetObject
459
+ root.unshiftContainer('body', sheetOuter)
460
+ // add import
461
+ root.unshiftContainer('body', importStyleSheet())
462
+
463
+ if (shouldPrintDebug) {
464
+ console.info('\n -------- output code ------- \n')
465
+ console.info(
466
+ generator(root.parent)
467
+ .code.split('\n')
468
+ .filter((x) => !x.startsWith('//'))
469
+ .join('\n')
470
+ )
471
+ }
472
+
473
+ if (res) printLog(res)
474
+ },
475
+ },
476
+ },
477
+ }
478
+ }
479
+
480
+ function assertValidTag(node: t.JSXOpeningElement) {
481
+ if (node.attributes.find((x) => x.type === 'JSXAttribute' && x.name.name === 'style')) {
482
+ // we can just deopt here instead and log warning
483
+ // need to make onExtractTag have a special catch error or similar
484
+ if (process.env.DEBUG?.startsWith('tamagui')) {
485
+ console.warn('⚠️ Cannot pass style attribute to extracted style')
486
+ }
487
+ }
488
+ }
489
+
490
+ function splitThemeStyles(style: Object) {
491
+ const themed: Object = {}
492
+ const plain: Object = {}
493
+ let noTheme = true
494
+ for (const key in style) {
495
+ const val = style[key]
496
+ if (val && val[0] === '$') {
497
+ themed[key] = val
498
+ noTheme = false
499
+ } else {
500
+ plain[key] = val
501
+ }
502
+ }
503
+ return { themed: noTheme ? null : themed, plain }
504
+ }
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@ export { createExtractor } from './extractor/createExtractor'
6
6
  export { literalToAst } from './extractor/literalToAst'
7
7
  export * from './constants'
8
8
  export * from './extractor/extractToClassNames'
9
+ export * from './extractor/extractToNative'
9
10
  export * from './extractor/extractHelpers'
10
11
  export * from './extractor/loadTamagui'
11
12
  export * from './extractor/watchTamaguiConfig'
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import * as babelParser from '@babel/parser';
3
2
  import type * as t from '@babel/types';
4
3
  export declare const parserOptions: babelParser.ParserOptions;
@@ -1 +1 @@
1
- {"version":3,"file":"babelParse.d.ts","sourceRoot":"","sources":["../../src/extractor/babelParse.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,WAAW,MAAM,eAAe,CAAA;AAC5C,OAAO,KAAK,KAAK,CAAC,MAAM,cAAc,CAAA;AAiBtC,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,aAGtC,CAAA;AAIF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,CAW3E"}
1
+ {"version":3,"file":"babelParse.d.ts","sourceRoot":"","sources":["../../src/extractor/babelParse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,eAAe,CAAA;AAC5C,OAAO,KAAK,KAAK,CAAC,MAAM,cAAc,CAAA;AAiBtC,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,aAGtC,CAAA;AAIF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,CAW3E"}
@@ -1 +1 @@
1
- {"version":3,"file":"createEvaluator.d.ts","sourceRoot":"","sources":["../../src/extractor/createEvaluator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,KAAK,CAAC,MAAM,cAAc,CAAA;AAIjC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAA;AAG1D,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,eAAe,EACf,UAAU,EACV,YAAY,EACZ,gBAAgB,GACjB,EAAE;IACD,KAAK,EAAE,0BAA0B,CAAA;IACjC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACpC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;IACrC,gBAAgB,EAAE,OAAO,GAAG,SAAS,CAAA;CACtC,OAoBY,MAAM,SAGlB;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,GAAG,OACtD,MAAM,SAOlB"}
1
+ {"version":3,"file":"createEvaluator.d.ts","sourceRoot":"","sources":["../../src/extractor/createEvaluator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,KAAK,CAAC,MAAM,cAAc,CAAA;AAIjC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAA;AAG1D,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,eAAe,EACf,UAAU,EACV,YAAY,EACZ,gBAAgB,GACjB,EAAE;IACD,KAAK,EAAE,0BAA0B,CAAA;IACjC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACpC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;IACrC,gBAAgB,EAAE,OAAO,GAAG,SAAS,CAAA;CACtC,OAoBY,CAAC,CAAC,IAAI,SAGlB;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,GAAG,OACtD,CAAC,CAAC,IAAI,SAOlB"}
@@ -1 +1 @@
1
- {"version":3,"file":"createExtractor.d.ts","sourceRoot":"","sources":["../../src/extractor/createExtractor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,iBAAiB,CAAA;AAEhE,OAAO,KAAK,CAAC,MAAM,cAAc,CAAA;AAcjC,OAAO,KAAK,EAGV,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EAGf,MAAM,UAAU,CAAA;AACjB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAcxD,OAAO,EAAE,iBAAiB,EAA6B,MAAM,6BAA6B,CAAA;AAuB1F,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAA;AAE1D,KAAK,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA;AAQ9C,wBAAgB,eAAe,CAC7B,EAAE,MAAgB,EAAE,QAAgB,EAAE,GAAE,gBAAsC;;;;;yBAwDnD,cAAc;6BAPhB,cAAc;;mBAwBtB,UAAU,SAAS,mBAAmB;;;;;;;eAIpC,UAAU,SAAS,mBAAmB;;;;;;;EAytE1D"}
1
+ {"version":3,"file":"createExtractor.d.ts","sourceRoot":"","sources":["../../src/extractor/createExtractor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,iBAAiB,CAAA;AAEhE,OAAO,KAAK,CAAC,MAAM,cAAc,CAAA;AAgBjC,OAAO,KAAK,EAGV,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EAGf,MAAM,UAAU,CAAA;AACjB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAcxD,OAAO,EAAE,iBAAiB,EAA6B,MAAM,6BAA6B,CAAA;AAuB1F,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAA;AAE1D,KAAK,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA;AAQ9C,wBAAgB,eAAe,CAC7B,EAAE,MAAgB,EAAE,QAAgB,EAAE,GAAE,gBAAsC;;;;;yBAwDnD,cAAc;6BAPhB,cAAc;;mBAwBtB,UAAU,SAAS,mBAAmB;;;;;;;eAIpC,UAAU,SAAS,mBAAmB;;;;;;;EAwtE1D"}
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import * as t from '@babel/types';
3
2
  import type { TamaguiOptions } from '../types';
4
3
  import type { Extractor } from './createExtractor';
@@ -1 +1 @@
1
- {"version":3,"file":"extractToClassNames.d.ts","sourceRoot":"","sources":["../../src/extractor/extractToClassNames.ts"],"names":[],"mappings":";AAIA,OAAO,KAAK,CAAC,MAAM,cAAc,CAAA;AAKjC,OAAO,KAAK,EAAgC,cAAc,EAAW,MAAM,UAAU,CAAA;AAGrF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAiBlD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,CAAC,CAAC,IAAI,CAAA;IACX,GAAG,EAAE,GAAG,CAAA;CACT,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,SAAS,CAAA;IACpB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,cAAc,CAAA;IACvB,gBAAgB,EAAE,OAAO,GAAG,SAAS,CAAA;CACtC,CAAA;AAED,wBAAsB,mBAAmB,CAAC,EACxC,SAAS,EACT,MAAM,EACN,UAAe,EACf,OAAO,EACP,gBAAgB,GACjB,EAAE,wBAAwB,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAmZ9D"}
1
+ {"version":3,"file":"extractToClassNames.d.ts","sourceRoot":"","sources":["../../src/extractor/extractToClassNames.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,CAAC,MAAM,cAAc,CAAA;AAKjC,OAAO,KAAK,EAAgC,cAAc,EAAW,MAAM,UAAU,CAAA;AAGrF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAiBlD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,CAAC,CAAC,IAAI,CAAA;IACX,GAAG,EAAE,GAAG,CAAA;CACT,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,SAAS,CAAA;IACpB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,cAAc,CAAA;IACvB,gBAAgB,EAAE,OAAO,GAAG,SAAS,CAAA;CACtC,CAAA;AAED,wBAAsB,mBAAmB,CAAC,EACxC,SAAS,EACT,MAAM,EACN,UAAe,EACf,OAAO,EACP,gBAAgB,GACjB,EAAE,wBAAwB,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAia9D"}
@@ -0,0 +1,13 @@
1
+ import { type BabelFileResult } from '@babel/core';
2
+ import type { TamaguiOptions } from '@tamagui/static';
3
+ export declare function extractToNative(sourceFileName: string, sourceCode: string, options: TamaguiOptions): BabelFileResult;
4
+ export declare function getBabelPlugin(): any;
5
+ export declare function getBabelParseDefinition(options: TamaguiOptions): {
6
+ name: string;
7
+ visitor: {
8
+ Program: {
9
+ enter(this: any, root: any): void;
10
+ };
11
+ };
12
+ };
13
+ //# sourceMappingURL=extractToNative.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractToNative.d.ts","sourceRoot":"","sources":["../../src/extractor/extractToNative.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,eAAe,EAAwB,MAAM,aAAa,CAAA;AAMxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AA2BrD,wBAAgB,eAAe,CAC7B,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,eAAe,CAoBjB;AAED,wBAAgB,cAAc,QAK7B;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,cAAc;;;;wBAM3C,GAAG;;;EAmZtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"getStaticBindingsForScope.d.ts","sourceRoot":"","sources":["../../src/extractor/getStaticBindingsForScope.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAW,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AACxD,OAAO,KAAK,CAAC,MAAM,cAAc,CAAA;AAuCjC,wBAAgB,iBAAiB,SAQhC;AAyCD,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EACtC,SAAS,sBAAe,EACxB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAC3C,gBAAgB,EAAE,OAAO,GAAG,SAAS,GACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAsI9B"}
1
+ {"version":3,"file":"getStaticBindingsForScope.d.ts","sourceRoot":"","sources":["../../src/extractor/getStaticBindingsForScope.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAW,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AACxD,OAAO,KAAK,CAAC,MAAM,cAAc,CAAA;AAuCjC,wBAAgB,iBAAiB,SAQhC;AAyCD,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EACtC,SAAS,EAAE,MAAM,EAAE,YAAK,EACxB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAC3C,gBAAgB,EAAE,OAAO,GAAG,SAAS,GACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAsI9B"}