@tamagui/cli 2.7.7 → 3.0.0-beta.643.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.
- package/dist/add.cjs +77 -87
- package/dist/build.cjs +415 -277
- package/dist/cli.cjs +343 -340
- package/dist/generate-prompt.cjs +344 -357
- package/dist/generate.cjs +46 -54
- package/dist/index.cjs +2 -1
- package/dist/migrate.cjs +370 -0
- package/dist/setup-prompt.cjs +158 -0
- package/dist/to-tailwind-default-config.cjs +778 -0
- package/dist/to-tailwind.cjs +214 -0
- package/dist/update-template.cjs +44 -52
- package/dist/update.cjs +15 -18
- package/dist/upgrade.cjs +407 -398
- package/dist/utils.cjs +85 -101
- package/metro.cjs +1 -0
- package/metro.d.ts +1 -0
- package/metro.mjs +1 -0
- package/package.json +41 -12
- package/src/build.ts +574 -363
- package/src/cli.ts +96 -12
- package/src/generate-prompt.ts +16 -24
- package/src/migrate.ts +354 -0
- package/src/setup-prompt.ts +139 -0
- package/src/to-tailwind-default-config.ts +755 -0
- package/src/to-tailwind.ts +313 -0
- package/src/utils.ts +11 -9
- package/types/add.d.ts +1 -1
- package/types/add.d.ts.map +1 -1
- package/types/build.d.ts +1 -1
- package/types/build.d.ts.map +1 -1
- package/types/migrate.d.ts +7 -0
- package/types/migrate.d.ts.map +1 -0
- package/types/setup-prompt.d.ts +3 -0
- package/types/setup-prompt.d.ts.map +1 -0
- package/types/to-tailwind-default-config.d.ts +53 -0
- package/types/to-tailwind-default-config.d.ts.map +1 -0
- package/types/to-tailwind.d.ts +16 -0
- package/types/to-tailwind.d.ts.map +1 -0
- package/types/utils.d.ts.map +1 -1
- package/vite.cjs +1 -0
- package/vite.d.ts +1 -0
- package/vite.mjs +1 -0
package/src/cli.ts
CHANGED
|
@@ -3,30 +3,45 @@ import chalk from 'chalk'
|
|
|
3
3
|
|
|
4
4
|
import { disposeAll, getOptions } from './utils'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
;['exit', 'SIGINT'].forEach((_) => {
|
|
8
|
-
process.on(_, () => {
|
|
9
|
-
disposeAll()
|
|
10
|
-
process.exit()
|
|
11
|
-
})
|
|
12
|
-
})
|
|
6
|
+
process.on('exit', disposeAll)
|
|
13
7
|
|
|
14
8
|
const COMMAND_MAP = {
|
|
15
9
|
check: {
|
|
16
|
-
description: `Checks
|
|
10
|
+
description: `Checks flat style values, inconsistent versions, duplicate installs, lockfile issues, and missing config.`,
|
|
17
11
|
shorthands: [],
|
|
18
12
|
flags: {
|
|
19
13
|
'--help': Boolean,
|
|
20
14
|
'--debug': Boolean,
|
|
21
15
|
'--verbose': Boolean,
|
|
16
|
+
'--styles-only': Boolean,
|
|
17
|
+
'--deps-only': Boolean,
|
|
22
18
|
},
|
|
23
19
|
async run() {
|
|
24
20
|
const { _, ...flags } = arg(this.flags)
|
|
25
21
|
const options = await getOptions({
|
|
26
22
|
debug: flags['--debug'] ? (flags['--verbose'] ? 'verbose' : true) : false,
|
|
27
23
|
})
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
if (!flags['--styles-only']) {
|
|
25
|
+
const { checkDeps } = require('@tamagui/static/checkDeps')
|
|
26
|
+
await checkDeps(options.paths.root)
|
|
27
|
+
}
|
|
28
|
+
if (flags['--deps-only']) return
|
|
29
|
+
const { checkStyleFiles, formatCheckResults, MissingConfigArtifactError } =
|
|
30
|
+
require('@tamagui/language-service/check') as typeof import('@tamagui/language-service/check')
|
|
31
|
+
try {
|
|
32
|
+
const result = checkStyleFiles({
|
|
33
|
+
root: options.paths.root,
|
|
34
|
+
configPath: options.paths.conf,
|
|
35
|
+
})
|
|
36
|
+
console.info(formatCheckResults(result))
|
|
37
|
+
if (result.diagnosticCount > 0) process.exitCode = 1
|
|
38
|
+
} catch (error) {
|
|
39
|
+
if (error instanceof MissingConfigArtifactError) {
|
|
40
|
+
console.warn(chalk.yellow(`skipping flat value check: ${error.message}`))
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
throw error
|
|
44
|
+
}
|
|
30
45
|
},
|
|
31
46
|
},
|
|
32
47
|
|
|
@@ -227,6 +242,68 @@ const COMMAND_MAP = {
|
|
|
227
242
|
},
|
|
228
243
|
},
|
|
229
244
|
|
|
245
|
+
setup: {
|
|
246
|
+
shorthands: [],
|
|
247
|
+
description: `Print an AI-agent prompt for adding Tamagui to a project for the first time`,
|
|
248
|
+
usage: `$ tamagui setup`,
|
|
249
|
+
flags: {
|
|
250
|
+
'--help': Boolean,
|
|
251
|
+
},
|
|
252
|
+
async run() {
|
|
253
|
+
const { printSetupPrompt } = require('./setup-prompt')
|
|
254
|
+
printSetupPrompt()
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
|
|
258
|
+
migrate: {
|
|
259
|
+
shorthands: [],
|
|
260
|
+
description: `Print an AI-agent prompt for migrating a Tamagui app to v3`,
|
|
261
|
+
usage: `$ tamagui migrate --from v2
|
|
262
|
+
$ tamagui migrate --from v1`,
|
|
263
|
+
flags: {
|
|
264
|
+
'--help': Boolean,
|
|
265
|
+
'--from': String,
|
|
266
|
+
},
|
|
267
|
+
async run() {
|
|
268
|
+
const { _, ...flags } = arg(this.flags)
|
|
269
|
+
const [_cmd, fromArg] = _
|
|
270
|
+
const { printMigrationPrompt } = require('./migrate')
|
|
271
|
+
|
|
272
|
+
printMigrationPrompt({
|
|
273
|
+
from: flags['--from'] || fromArg,
|
|
274
|
+
})
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
'to-tailwind': {
|
|
279
|
+
shorthands: [],
|
|
280
|
+
description: `Convert Tamagui JSX props in files or globs to Tailwind className syntax`,
|
|
281
|
+
flags: {
|
|
282
|
+
'--help': Boolean,
|
|
283
|
+
'--write': Boolean,
|
|
284
|
+
// path to the app's tamagui config so token/media/shorthand resolution uses the app's
|
|
285
|
+
// ACTUAL scales, not the bundled default fallback.
|
|
286
|
+
'--config': String,
|
|
287
|
+
// acknowledge use of the bundled default scales (required for --write without --config).
|
|
288
|
+
'--use-default-config': Boolean,
|
|
289
|
+
// opt in to DOM renaming (View→div). default: preserve Tamagui components (RN-safe).
|
|
290
|
+
'--rename-dom': Boolean,
|
|
291
|
+
},
|
|
292
|
+
async run() {
|
|
293
|
+
const { _, ...flags } = arg(this.flags)
|
|
294
|
+
const { toTailwind } = require('./to-tailwind')
|
|
295
|
+
const [_cmd, ...patterns] = _
|
|
296
|
+
|
|
297
|
+
await toTailwind({
|
|
298
|
+
patterns,
|
|
299
|
+
write: flags['--write'],
|
|
300
|
+
configPath: flags['--config'],
|
|
301
|
+
useDefaultConfig: flags['--use-default-config'],
|
|
302
|
+
renameDom: flags['--rename-dom'],
|
|
303
|
+
})
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
|
|
230
307
|
'update-template': {
|
|
231
308
|
shorthands: ['ut'],
|
|
232
309
|
description: `Used to update your git repo with the source template. (e.g. Takeout)`,
|
|
@@ -332,8 +409,13 @@ main()
|
|
|
332
409
|
async function main() {
|
|
333
410
|
if (flags['--help']) {
|
|
334
411
|
console.info(`\n$ tamagui ${command}: ${definition.description}\n`)
|
|
412
|
+
if ('usage' in definition && definition.usage) {
|
|
413
|
+
console.info(`Usage:\n${definition.usage}\n`)
|
|
414
|
+
}
|
|
335
415
|
console.info(
|
|
336
|
-
`Flags
|
|
416
|
+
`Flags:\n${Object.entries(definition.flags)
|
|
417
|
+
.map(([k, v]) => ` ${k} (${v.name})`)
|
|
418
|
+
.join('\n')}`
|
|
337
419
|
)
|
|
338
420
|
process.exit(0)
|
|
339
421
|
}
|
|
@@ -354,7 +436,9 @@ async function main() {
|
|
|
354
436
|
await definition.run()
|
|
355
437
|
} catch (err: any) {
|
|
356
438
|
console.error(`Error running command: ${err.message}`)
|
|
439
|
+
process.exit(1) // a thrown command error must be a NON-ZERO exit (safety: --write aborts)
|
|
357
440
|
}
|
|
358
441
|
|
|
359
|
-
|
|
442
|
+
// `check` sets exitCode when it finds problems; a literal 0 would erase it
|
|
443
|
+
process.exit(process.exitCode ?? 0)
|
|
360
444
|
}
|
package/src/generate-prompt.ts
CHANGED
|
@@ -83,8 +83,8 @@ function generateMarkdown(config: any): string {
|
|
|
83
83
|
if (settings.onlyAllowShorthands) {
|
|
84
84
|
sections.push('**You MUST use shorthand properties in this project.**\n\n')
|
|
85
85
|
sections.push('Full property names are not allowed. For example:\n')
|
|
86
|
-
sections.push('- ✅ `<View w="
|
|
87
|
-
sections.push('- ❌ `<View width="
|
|
86
|
+
sections.push('- ✅ `<View w="10" />` (correct)\n')
|
|
87
|
+
sections.push('- ❌ `<View width="10" />` (will error)\n\n')
|
|
88
88
|
sections.push(
|
|
89
89
|
'See the Shorthand Properties section below for all available shorthands.\n\n'
|
|
90
90
|
)
|
|
@@ -93,11 +93,9 @@ function generateMarkdown(config: any): string {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
if (settings.
|
|
97
|
-
sections.push(
|
|
98
|
-
|
|
99
|
-
)
|
|
100
|
-
if (settings.themeClassNameOnRoot) {
|
|
96
|
+
if (settings.addThemeClassName !== undefined) {
|
|
97
|
+
sections.push(`### Theme Class Name: \`${settings.addThemeClassName}\`\n\n`)
|
|
98
|
+
if (settings.addThemeClassName === 'html') {
|
|
101
99
|
sections.push('Theme classes are applied to the root HTML element.\n\n')
|
|
102
100
|
}
|
|
103
101
|
}
|
|
@@ -347,22 +345,20 @@ function generateMarkdown(config: any): string {
|
|
|
347
345
|
sections.push('```\n\n')
|
|
348
346
|
|
|
349
347
|
sections.push('**Accessing theme values:**\n\n')
|
|
350
|
-
sections.push('Components
|
|
348
|
+
sections.push('Components access theme values by their bare names:\n\n')
|
|
351
349
|
sections.push('```tsx\n')
|
|
352
350
|
sections.push(
|
|
353
|
-
`<View ${getPropName('backgroundColor')}="
|
|
351
|
+
`<View ${getPropName('backgroundColor')}="background" ${getPropName('color')}="color" />\n`
|
|
354
352
|
)
|
|
355
353
|
sections.push('```\n\n')
|
|
356
354
|
|
|
357
355
|
sections.push('**Special props:**\n\n')
|
|
358
|
-
sections.push('- `inverse`:
|
|
356
|
+
sections.push('- `theme="inverse"`: Uses the opposite light or dark sub-theme\n')
|
|
359
357
|
sections.push('- `reset`: Reverts to grandparent theme\n\n')
|
|
360
358
|
|
|
361
359
|
// Tokens
|
|
362
360
|
sections.push('## Tokens\n\n')
|
|
363
|
-
sections.push(
|
|
364
|
-
'Tokens are design system values that can be referenced using the `$` prefix.\n\n'
|
|
365
|
-
)
|
|
361
|
+
sections.push('Tokens are design system values referenced by their bare names.\n\n')
|
|
366
362
|
|
|
367
363
|
const tokens = config.tamaguiConfig?.tokens || {}
|
|
368
364
|
|
|
@@ -459,22 +455,20 @@ function generateMarkdown(config: any): string {
|
|
|
459
455
|
|
|
460
456
|
// Token usage examples
|
|
461
457
|
sections.push('### Token Usage\n\n')
|
|
462
|
-
sections.push('Tokens can be used in component props
|
|
458
|
+
sections.push('Tokens can be used in component props by their bare names:\n\n')
|
|
463
459
|
sections.push('```tsx\n')
|
|
464
460
|
sections.push('// Space tokens - for margin, padding, gap\n')
|
|
465
461
|
sections.push(
|
|
466
|
-
`<View ${getPropName('padding')}="
|
|
462
|
+
`<View ${getPropName('padding')}="4" ${getPropName('gap')}="2" ${getPropName('margin')}="3" />\n\n`
|
|
467
463
|
)
|
|
468
464
|
sections.push('// Size tokens - for width, height, dimensions\n')
|
|
469
|
-
sections.push(
|
|
470
|
-
`<View ${getPropName('width')}="$10" ${getPropName('height')}="$6" />\n\n`
|
|
471
|
-
)
|
|
465
|
+
sections.push(`<View ${getPropName('width')}="10" ${getPropName('height')}="6" />\n\n`)
|
|
472
466
|
sections.push('// Color tokens - for colors and backgrounds\n')
|
|
473
467
|
sections.push(
|
|
474
|
-
`<View ${getPropName('backgroundColor')}="
|
|
468
|
+
`<View ${getPropName('backgroundColor')}="blue5" ${getPropName('color')}="gray12" />\n\n`
|
|
475
469
|
)
|
|
476
470
|
sections.push('// Radius tokens - for border-radius\n')
|
|
477
|
-
sections.push(`<View ${getPropName('borderRadius')}="
|
|
471
|
+
sections.push(`<View ${getPropName('borderRadius')}="4" />\n`)
|
|
478
472
|
sections.push('```\n\n')
|
|
479
473
|
|
|
480
474
|
// Media queries
|
|
@@ -495,14 +489,12 @@ function generateMarkdown(config: any): string {
|
|
|
495
489
|
'Media queries can be used as style props or with the `useMedia` hook:\n\n'
|
|
496
490
|
)
|
|
497
491
|
sections.push('```tsx\n')
|
|
498
|
-
sections.push('// As
|
|
492
|
+
sections.push('// As a clause in the same style value\n')
|
|
499
493
|
|
|
500
494
|
// Get first media query name as example
|
|
501
495
|
const firstMediaName = mediaEntries[0]?.[0]
|
|
502
496
|
if (firstMediaName) {
|
|
503
|
-
sections.push(
|
|
504
|
-
`<View ${getPropName('width')}="100%" $${firstMediaName}={{ ${getPropName('width')}: "50%" }} />\n\n`
|
|
505
|
-
)
|
|
497
|
+
sections.push(`<View ${getPropName('width')}="100% ${firstMediaName}:50%" />\n\n`)
|
|
506
498
|
}
|
|
507
499
|
|
|
508
500
|
sections.push('// Using the useMedia hook\n')
|
package/src/migrate.ts
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
type MigrationFrom = 'v1' | 'v2'
|
|
2
|
+
|
|
3
|
+
export function printMigrationPrompt({ from }: { from?: string }) {
|
|
4
|
+
process.stdout.write(getMigrationPrompt({ from }))
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function getMigrationPrompt({ from }: { from?: string } = {}) {
|
|
8
|
+
const source = normalizeFrom(from)
|
|
9
|
+
|
|
10
|
+
if (source === 'v1') {
|
|
11
|
+
return `${promptHeader('v1', 'v3')}
|
|
12
|
+
|
|
13
|
+
${v1ToV2Prompt}
|
|
14
|
+
|
|
15
|
+
After the v1 to v2 pass is complete, apply the v2 to v3 pass below.
|
|
16
|
+
|
|
17
|
+
${v2ToV3Prompt}
|
|
18
|
+
`
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return `${promptHeader('v2', 'v3')}
|
|
22
|
+
|
|
23
|
+
${v2ToV3Prompt}
|
|
24
|
+
`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function normalizeFrom(from: string | undefined): MigrationFrom {
|
|
28
|
+
const value = (from || 'v2').toLowerCase().replace(/^from-?/, '')
|
|
29
|
+
|
|
30
|
+
if (value === '1' || value === 'v1') return 'v1'
|
|
31
|
+
if (value === '2' || value === 'v2') return 'v2'
|
|
32
|
+
|
|
33
|
+
throw new Error('Usage: tamagui migrate --from v2 | --from v1')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function promptHeader(from: string, to: string) {
|
|
37
|
+
return `You are migrating a Tamagui app from ${from} to ${to}.
|
|
38
|
+
|
|
39
|
+
Work like a careful coding agent:
|
|
40
|
+
|
|
41
|
+
- Read the app's Tamagui config, package manager, bundler, and component usage before editing.
|
|
42
|
+
- Keep changes scoped to the migration.
|
|
43
|
+
- Run the codemods listed below, then review the diff by hand.
|
|
44
|
+
- Do not publish packages, rotate secrets, or change production infrastructure.
|
|
45
|
+
- Validate with typecheck/build and at least one real app run or browser/native smoke test.
|
|
46
|
+
- Report any behavior that cannot be migrated mechanically.`
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const v2ToV3Prompt = `## v2 -> v3 migration prompt
|
|
50
|
+
|
|
51
|
+
### 1. Update dependencies
|
|
52
|
+
|
|
53
|
+
- Bump every \`tamagui\` and \`@tamagui/*\` package together to v3.
|
|
54
|
+
- Keep \`@tamagui/core\`, \`@tamagui/web\`, and \`tamagui\` deduped in the lockfile.
|
|
55
|
+
- Run:
|
|
56
|
+
|
|
57
|
+
\`\`\`bash
|
|
58
|
+
npx tamagui check
|
|
59
|
+
\`\`\`
|
|
60
|
+
|
|
61
|
+
### 2. Migrate tokens and conditional styles
|
|
62
|
+
|
|
63
|
+
V3 accepts bare token/theme names and flat clauses only. Run the transactional
|
|
64
|
+
flat-values codemod from your project root, dry run first:
|
|
65
|
+
|
|
66
|
+
\`\`\`bash
|
|
67
|
+
npx @tamagui/codemod-flat-values --report flat-values-report.md ./src
|
|
68
|
+
npx @tamagui/codemod-flat-values --write \\
|
|
69
|
+
--report flat-values-report.md \\
|
|
70
|
+
--json flat-values-report.json \\
|
|
71
|
+
./src
|
|
72
|
+
\`\`\`
|
|
73
|
+
|
|
74
|
+
For example, this V2 input:
|
|
75
|
+
|
|
76
|
+
\`\`\`tsx
|
|
77
|
+
<View bg="$background" hoverStyle={{ bg: '$backgroundHover' }} $sm={{ p: '$6' }} p="$4" />
|
|
78
|
+
\`\`\`
|
|
79
|
+
|
|
80
|
+
becomes:
|
|
81
|
+
|
|
82
|
+
\`\`\`tsx
|
|
83
|
+
<View bg="background hover:background-hover" p="4 sm:6" />
|
|
84
|
+
\`\`\`
|
|
85
|
+
|
|
86
|
+
Resolve every report row and rerun until the app has no V2 authoring. Do not
|
|
87
|
+
add a compatibility setting or restore condition-object parsing.
|
|
88
|
+
|
|
89
|
+
### 3. Migrate config and themes
|
|
90
|
+
|
|
91
|
+
- New applications should use \`defaultConfig\` from \`@tamagui/config/v6\`.
|
|
92
|
+
- Existing V5 applications can keep \`@tamagui/config/v5\` or \`/v5-subtle\` while migrating incrementally. These are frozen static compatibility packs, so they preserve the V5 token and theme values but will not receive new theme-builder features.
|
|
93
|
+
- Import animations from \`@tamagui/config/animations-css\`, \`animations-rn\`, \`animations-reanimated\`, or \`animations-motion\`.
|
|
94
|
+
- Remove \`@tamagui/theme-builder\` and any V5 builder imports. Static \`@tamagui/themes/v5\`, \`/v5-subtle\`, and \`/v5-tokens\` imports remain supported.
|
|
95
|
+
- Use \`createThemes\`, \`levels\`, scales, and the other recipe helpers from \`@tamagui/themes/builder\`.
|
|
96
|
+
- Remove \`componentThemes\`, \`templates\`, \`masks\`, \`childrenThemes\`, and \`grandChildrenThemes\`. Express hierarchy in the recipe tree, semantic values in scales, and exact one-theme overrides in \`values\`.
|
|
97
|
+
- Component names no longer select uppercase theme segments automatically. Replace component themes with explicit normal theme or \`level2\` boundaries in component skins.
|
|
98
|
+
|
|
99
|
+
Rename the adaptive 12-step ramp approximately:
|
|
100
|
+
|
|
101
|
+
- \`color1\` -> \`color1\`
|
|
102
|
+
- \`color2\` -> \`color2\`
|
|
103
|
+
- \`color3\` -> \`color3\`
|
|
104
|
+
- \`color4\` -> \`color4\`
|
|
105
|
+
- \`color5\` -> \`color5\`
|
|
106
|
+
- \`color6\` and \`color7\` -> \`color6\`
|
|
107
|
+
- \`color8\` -> \`color7\`
|
|
108
|
+
- \`color9\` -> \`color8\`
|
|
109
|
+
- \`color10\` -> \`color9\`
|
|
110
|
+
- \`color11\` -> \`color10\`
|
|
111
|
+
- \`color12\` -> \`color11\`
|
|
112
|
+
|
|
113
|
+
The endpoints are exact; inspect contrast in the compressed middle. Replace
|
|
114
|
+
\`surface1\` with \`level2\`, \`surface2\` with \`level3\`, and \`surface3\`
|
|
115
|
+
or \`surface4\` with \`level4\`. Levels are relative and preserve a surrounding
|
|
116
|
+
color theme when nested.
|
|
117
|
+
|
|
118
|
+
Search the config and application together:
|
|
119
|
+
|
|
120
|
+
\`\`\`bash
|
|
121
|
+
rg "@tamagui/theme-builder|v5-builder|createV5Theme|componentThemes|grandChildrenThemes|surface[1-4]|color12"
|
|
122
|
+
\`\`\`
|
|
123
|
+
|
|
124
|
+
### 4. Run the Sheet codemod
|
|
125
|
+
|
|
126
|
+
Run the codemod, then inspect every changed Sheet:
|
|
127
|
+
|
|
128
|
+
\`\`\`bash
|
|
129
|
+
node ./node_modules/tamagui/scripts/codemods/sheet-frame-to-container.js "src/**/*.{ts,tsx}"
|
|
130
|
+
\`\`\`
|
|
131
|
+
|
|
132
|
+
If working inside a Tamagui checkout, this path is also valid:
|
|
133
|
+
|
|
134
|
+
\`\`\`bash
|
|
135
|
+
node ./scripts/codemods/sheet-frame-to-container.js "src/**/*.{ts,tsx}"
|
|
136
|
+
\`\`\`
|
|
137
|
+
|
|
138
|
+
Migration rules:
|
|
139
|
+
|
|
140
|
+
- Replace \`Sheet.Frame\` with \`Sheet.Container\` plus \`Sheet.Background\`.
|
|
141
|
+
- Keep layout props such as \`padding\`, \`gap\`, \`height\`, \`maxHeight\`, and flex props on \`Sheet.Container\`.
|
|
142
|
+
- Move visual surface props such as \`bg\`, \`borderRadius\`, \`elevation\`, and \`shadow*\` to \`Sheet.Background\`.
|
|
143
|
+
- Keep \`Sheet.Overlay\` as a direct child of \`Sheet\`.
|
|
144
|
+
- Add explicit clipping if old \`Sheet.Frame\` overflow clipping mattered.
|
|
145
|
+
- \`disableHideBottomOverflow\` belongs on \`Sheet.Background\`.
|
|
146
|
+
|
|
147
|
+
Before:
|
|
148
|
+
|
|
149
|
+
\`\`\`tsx
|
|
150
|
+
<Sheet>
|
|
151
|
+
<Sheet.Overlay />
|
|
152
|
+
<Sheet.Frame padding="$4" bg="$background" borderTopRadius="$6">
|
|
153
|
+
<Sheet.ScrollView>{children}</Sheet.ScrollView>
|
|
154
|
+
</Sheet.Frame>
|
|
155
|
+
</Sheet>
|
|
156
|
+
\`\`\`
|
|
157
|
+
|
|
158
|
+
After:
|
|
159
|
+
|
|
160
|
+
\`\`\`tsx
|
|
161
|
+
<Sheet>
|
|
162
|
+
<Sheet.Overlay />
|
|
163
|
+
<Sheet.Container padding="4">
|
|
164
|
+
<Sheet.Background bg="background" borderTopRadius="6" />
|
|
165
|
+
<Sheet.ScrollView>{children}</Sheet.ScrollView>
|
|
166
|
+
</Sheet.Container>
|
|
167
|
+
</Sheet>
|
|
168
|
+
\`\`\`
|
|
169
|
+
|
|
170
|
+
### 5. Remove deprecated v2 APIs
|
|
171
|
+
|
|
172
|
+
Search:
|
|
173
|
+
|
|
174
|
+
\`\`\`bash
|
|
175
|
+
rg "focusable|fullscreen|themeInverse|<Theme inverse|Sheet\\.Frame|styleable\\(|inlineWhenUnflattened|\\$true|getTokenRelative|stepTokenUpOrDown|forceRemoveScrollEnabled|sizeAdjust"
|
|
176
|
+
\`\`\`
|
|
177
|
+
|
|
178
|
+
Replace:
|
|
179
|
+
|
|
180
|
+
- \`focusable\` -> \`tabIndex\`.
|
|
181
|
+
- \`fullscreen\` -> explicit \`position\` and \`inset\` props.
|
|
182
|
+
- \`themeInverse\` -> \`theme="inverse"\`.
|
|
183
|
+
- \`<Theme inverse>\` -> \`<Theme name="inverse">\`.
|
|
184
|
+
- \`Sheet.Frame\` -> \`Sheet.Container\` plus \`Sheet.Background\`.
|
|
185
|
+
- \`Component.styleable(fn)\` -> \`createStyledHOC(Component, fn)\` (same behavior, standalone function).
|
|
186
|
+
- forwardRef wrapper statics -> direct refs and normal composition.
|
|
187
|
+
- \`inlineWhenUnflattened\` -> remove it.
|
|
188
|
+
- deprecated UI kit aliases -> current component names.
|
|
189
|
+
- old platform style keys -> flat \`web:\`, \`native:\`, \`ios:\`, and \`android:\` clauses.
|
|
190
|
+
- \`forceRemoveScrollEnabled\` -> \`disableRemoveScroll\` with inverted intent.
|
|
191
|
+
- \`createCheckbox\` \`sizeAdjust\` -> explicit sizing math or component styles.
|
|
192
|
+
|
|
193
|
+
### 6. Replace true tokens
|
|
194
|
+
|
|
195
|
+
- Default v3 configs no longer export the legacy \`$true\` token key.
|
|
196
|
+
- Component default size resolves to bare \`4\`.
|
|
197
|
+
- Replace authored \`$true\` tokens with real bare keys such as \`4\`.
|
|
198
|
+
- Do not change unrelated boolean props or boolean variant values.
|
|
199
|
+
|
|
200
|
+
### 7. Replace token stepping
|
|
201
|
+
|
|
202
|
+
Removed from \`@tamagui/get-token\`:
|
|
203
|
+
|
|
204
|
+
- \`stepTokenUpOrDown\`
|
|
205
|
+
- \`getTokenRelative\`
|
|
206
|
+
- the second options argument to \`getSize\`, \`getSpace\`, and \`getRadius\`
|
|
207
|
+
- \`shift\`, \`bounds\`, and \`excludeHalfSteps\`
|
|
208
|
+
|
|
209
|
+
Before:
|
|
210
|
+
|
|
211
|
+
\`\`\`tsx
|
|
212
|
+
const padding = getSize(size, { shift: -2 })
|
|
213
|
+
\`\`\`
|
|
214
|
+
|
|
215
|
+
After:
|
|
216
|
+
|
|
217
|
+
\`\`\`tsx
|
|
218
|
+
const padding = getVariableValue(getSize(size)) * 0.6
|
|
219
|
+
\`\`\`
|
|
220
|
+
|
|
221
|
+
Use explicit token keys when you need a named smaller or larger token. Use numeric multiplication when proportional sizing is intended.
|
|
222
|
+
|
|
223
|
+
### 8. Audit font size values
|
|
224
|
+
|
|
225
|
+
- \`fontSize={17}\` is a raw numeric platform value and keeps platform-default line-height behavior.
|
|
226
|
+
- \`fontSize="17px"\` is an exact pixel value.
|
|
227
|
+
- Configured font \`size\` and \`lineHeight\` tokens should use px strings when exact web pixels are intended.
|
|
228
|
+
- Convert custom config font tokens to px strings if exact pixels were intended.
|
|
229
|
+
|
|
230
|
+
### 9. Update FocusScope
|
|
231
|
+
|
|
232
|
+
- Function-as-children is removed. Pass JSX children directly.
|
|
233
|
+
- FocusScope renders a \`display: contents\` wrapper.
|
|
234
|
+
- Use \`noFocus\` for zero-focus mode when focus should be rejected entirely.
|
|
235
|
+
|
|
236
|
+
Before:
|
|
237
|
+
|
|
238
|
+
\`\`\`tsx
|
|
239
|
+
<FocusScope loop>
|
|
240
|
+
{({ ref, onKeyDown, tabIndex }) => (
|
|
241
|
+
<View ref={ref} onKeyDown={onKeyDown} tabIndex={tabIndex} />
|
|
242
|
+
)}
|
|
243
|
+
</FocusScope>
|
|
244
|
+
\`\`\`
|
|
245
|
+
|
|
246
|
+
After:
|
|
247
|
+
|
|
248
|
+
\`\`\`tsx
|
|
249
|
+
<FocusScope loop>
|
|
250
|
+
<View />
|
|
251
|
+
</FocusScope>
|
|
252
|
+
\`\`\`
|
|
253
|
+
|
|
254
|
+
### 10. Update Dialog, Popover, Select, and Adapt flows
|
|
255
|
+
|
|
256
|
+
- Dialog, Popover, and Select use one Adapt handoff model.
|
|
257
|
+
- Adapted Sheet content stays mounted through the sheet slide-out.
|
|
258
|
+
- Parts own their presence animation lifecycles.
|
|
259
|
+
- The \`onDidAnimate\` prop is replaced by the typed \`onTransition\` lifecycle: \`onTransition={(e) => e.phase === 'end' && e.cause === 'enter' && done()}\`.
|
|
260
|
+
- \`Popover.Content forceMount\` now matches Dialog semantics.
|
|
261
|
+
- \`Dialog.Content\` no longer accepts the old no-op \`size\` variant.
|
|
262
|
+
- Non-modal Dialog content no longer enables RemoveScroll while open.
|
|
263
|
+
- Remove internal imports such as \`useShowPopoverSheet\`, \`PopoverAdaptHiddenContext\`, or \`useSelectBreakpointActive\` if the app used them.
|
|
264
|
+
|
|
265
|
+
### 11. Update Select
|
|
266
|
+
|
|
267
|
+
- Keep \`name\` when Select participates in a form. Remove the unsupported \`autoComplete\` prop.
|
|
268
|
+
- Use \`Select.Separator\` for visual grouping.
|
|
269
|
+
- \`Select.Content\` accepts \`onEscapeKeyDown\` and \`onInteractOutside\`.
|
|
270
|
+
- \`Select.Trigger\` and web \`Select.Viewport\` expose \`data-state="open" | "closed"\`.
|
|
271
|
+
|
|
272
|
+
### 12. Update themed icons
|
|
273
|
+
|
|
274
|
+
- \`<Icon size="4" />\` now resolves through the current font's \`font.size['4']\` scale.
|
|
275
|
+
- Raw numeric icon sizes are unchanged.
|
|
276
|
+
- Themed icons no longer accept Tamagui media or pseudo props directly.
|
|
277
|
+
- Wrap icons in a styled \`View\` for media and state clauses.
|
|
278
|
+
|
|
279
|
+
### 13. Check ScrollView web usage
|
|
280
|
+
|
|
281
|
+
\`@tamagui/scroll-view\` now has its own web implementation. It supports \`scrollTo\`, \`scrollToEnd\`, \`getScrollableNode\`, RN-shaped \`onScroll\`, \`contentContainerStyle\`, \`horizontal\`, and indicator props.
|
|
282
|
+
|
|
283
|
+
Replace unsupported old web/lite usage such as momentum events, \`snapTo*\`, and \`keyboardDismissMode\`.
|
|
284
|
+
|
|
285
|
+
### 14. Optional Tailwind frontend
|
|
286
|
+
|
|
287
|
+
Tailwind authoring is selected by the component package, with no global config:
|
|
288
|
+
|
|
289
|
+
\`\`\`tsx
|
|
290
|
+
import { View, Text, styled } from '@tamagui/tailwind'
|
|
291
|
+
\`\`\`
|
|
292
|
+
|
|
293
|
+
Keep importing regular Tamagui components from \`tamagui\` or
|
|
294
|
+
\`@tamagui/core\`. Do not mix utility classes and Tamagui style props on the
|
|
295
|
+
same component; choose the import whose styling language that component uses.
|
|
296
|
+
|
|
297
|
+
### 15. Verification
|
|
298
|
+
|
|
299
|
+
- Run \`npx tamagui check\`.
|
|
300
|
+
- Run typecheck and build.
|
|
301
|
+
- Start the app and manually test screens using Sheet, Dialog, Popover, Select, FocusScope, icons, and ScrollView.
|
|
302
|
+
- Test Adapt breakpoints where popovers/selects/dialogs become sheets.
|
|
303
|
+
- Verify keyboard focus, Escape, outside click, scroll locking, and close animations.
|
|
304
|
+
- Inspect icon alignment next to text at each app size token.
|
|
305
|
+
- If the Tailwind frontend is used, compare web and native output for the classes used.`
|
|
306
|
+
|
|
307
|
+
const v1ToV2Prompt = `## v1 -> v2 migration pass
|
|
308
|
+
|
|
309
|
+
Bring the app to the v2 baseline before applying v3 changes.
|
|
310
|
+
|
|
311
|
+
### Requirements
|
|
312
|
+
|
|
313
|
+
- React 19+
|
|
314
|
+
- React Native 0.81+ with New Architecture support
|
|
315
|
+
- TypeScript 5+
|
|
316
|
+
|
|
317
|
+
### Config
|
|
318
|
+
|
|
319
|
+
- Move to \`@tamagui/config/v6\`.
|
|
320
|
+
- Import animations separately from \`@tamagui/config/animations-css\`, \`animations-rn\`, \`animations-reanimated\`, or \`animations-motion\`.
|
|
321
|
+
- Move root \`createTamagui\` settings into \`settings\`.
|
|
322
|
+
- Account for the defaults \`flexBasis: 0\` and \`position: static\`. Use \`styleCompat: 'legacy'\` or explicit props if needed.
|
|
323
|
+
- Rename media queries: \`$2xl\` -> \`$xxl\`, \`$2xs\` -> \`$xxs\`, and max queries to kebab-case such as \`$max-md\`.
|
|
324
|
+
- Update colors and themes to the v3 recipe helpers in \`@tamagui/themes/builder\`.
|
|
325
|
+
|
|
326
|
+
### v1 prop and API changes
|
|
327
|
+
|
|
328
|
+
- \`animation\` -> \`transition\`.
|
|
329
|
+
- \`AnimationProp\` -> \`TransitionProp\`.
|
|
330
|
+
- \`tag\` -> \`render\`.
|
|
331
|
+
- \`Stack\` -> \`View\`.
|
|
332
|
+
- \`StackProps\` -> \`ViewProps\`.
|
|
333
|
+
- \`space\` and \`spaceDirection\` -> \`gap\`.
|
|
334
|
+
- \`themeInverse\` and \`<Theme inverse>\` -> \`theme="inverse"\` and \`<Theme name="inverse">\`.
|
|
335
|
+
- \`onHoverIn\` / \`onHoverOut\` -> \`onPointerEnter\` / \`onPointerLeave\` or mouse events.
|
|
336
|
+
- \`ellipse\` -> \`numberOfLines={1}\`.
|
|
337
|
+
- React Native accessibility props -> ARIA/web equivalents where applicable.
|
|
338
|
+
- React Native shadow props -> \`boxShadow\`.
|
|
339
|
+
|
|
340
|
+
### v1 component changes
|
|
341
|
+
|
|
342
|
+
- Input and Image prefer web-standard props such as \`type\`, \`inputMode\`, \`src\`, \`alt\`, and \`objectFit\`.
|
|
343
|
+
- Button and ListItem no longer take direct text style props. Style text through child components.
|
|
344
|
+
- Tabs uses \`Tabs.Tab\` instead of \`Tabs.Trigger\`; \`activationMode\` defaults to \`manual\`.
|
|
345
|
+
- Group requires \`Group.Item\`; remove old separator/space/scrollable auto-cloning props.
|
|
346
|
+
- Replace old \`Popover.Sheet\` subcomponents with standalone \`Sheet\` inside \`Adapt\`.
|
|
347
|
+
- Add native setup imports where needed: \`@tamagui/native/setup-teleport\`, \`setup-gesture-handler\`, \`setup-expo-ui-menu\` or \`setup-zeego\`, \`setup-burnt\`, and linear-gradient setup.
|
|
348
|
+
|
|
349
|
+
### v1 -> v2 verification
|
|
350
|
+
|
|
351
|
+
- Run the app before starting v3 changes.
|
|
352
|
+
- Verify layout affected by flex/position defaults.
|
|
353
|
+
- Verify forms, tabs, groups, portals, native sheets, and Input/Image behavior.
|
|
354
|
+
- Commit the v1 -> v2 migration separately if possible.`
|