-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR adds a codemod that migrates the `@media screen(…)` to the properly expanded `@media (…)` syntax. ```css @media screen(md) { .foo { color: red; } } ``` Will be converted to: ```css @media (width >= 48rem) { .foo { color: red; } } ``` If you happen to have custom screens (even complex ones), the screen will be converted to a custom media query. ```css @media screen(foo) { .foo { color: red; } } ``` With a custom `tailwind.config.js` file with a config like this: ```js module.exports = { // … theme: { screens: { foo: { min: '100px', max: '123px' }, }, } } ``` Then the codemod will convert it to: ```css @media (123px >= width >= 100px) { .foo { color: red; } } ```
- Loading branch information
1 parent
958bfc9
commit 3ae22f1
Showing
4 changed files
with
224 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
177 changes: 177 additions & 0 deletions
177
packages/@tailwindcss-upgrade/src/codemods/migrate-media-screen.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
import { __unstable__loadDesignSystem } from '@tailwindcss/node' | ||
import dedent from 'dedent' | ||
import postcss from 'postcss' | ||
import { expect, it } from 'vitest' | ||
import type { UserConfig } from '../../../tailwindcss/src/compat/config/types' | ||
import { formatNodes } from './format-nodes' | ||
import { migrateMediaScreen } from './migrate-media-screen' | ||
|
||
const css = dedent | ||
|
||
async function migrate(input: string, userConfig: UserConfig = {}) { | ||
return postcss() | ||
.use( | ||
migrateMediaScreen({ | ||
designSystem: await __unstable__loadDesignSystem(`@import 'tailwindcss';`, { | ||
base: __dirname, | ||
}), | ||
userConfig, | ||
}), | ||
) | ||
.use(formatNodes()) | ||
.process(input, { from: expect.getState().testPath }) | ||
.then((result) => result.css) | ||
} | ||
|
||
it('should migrate a built-in breakpoint', async () => { | ||
expect( | ||
await migrate(css` | ||
@media screen(md) { | ||
.foo { | ||
color: red; | ||
} | ||
} | ||
`), | ||
).toMatchInlineSnapshot(` | ||
"@media (width >= theme(--breakpoint-md)) { | ||
.foo { | ||
color: red; | ||
} | ||
}" | ||
`) | ||
}) | ||
|
||
it('should migrate a custom min-width screen (string)', async () => { | ||
expect( | ||
await migrate( | ||
css` | ||
@media screen(foo) { | ||
.foo { | ||
color: red; | ||
} | ||
} | ||
`, | ||
{ | ||
theme: { | ||
screens: { | ||
foo: '123px', | ||
}, | ||
}, | ||
}, | ||
), | ||
).toMatchInlineSnapshot(` | ||
"@media (width >= theme(--breakpoint-foo)) { | ||
.foo { | ||
color: red; | ||
} | ||
}" | ||
`) | ||
}) | ||
|
||
it('should migrate a custom min-width screen (object)', async () => { | ||
expect( | ||
await migrate( | ||
css` | ||
@media screen(foo) { | ||
.foo { | ||
color: red; | ||
} | ||
} | ||
`, | ||
{ | ||
theme: { | ||
screens: { | ||
foo: { min: '123px' }, | ||
}, | ||
}, | ||
}, | ||
), | ||
).toMatchInlineSnapshot(` | ||
"@media (width >= theme(--breakpoint-foo)) { | ||
.foo { | ||
color: red; | ||
} | ||
}" | ||
`) | ||
}) | ||
|
||
it('should migrate a custom max-width screen', async () => { | ||
expect( | ||
await migrate( | ||
css` | ||
@media screen(foo) { | ||
.foo { | ||
color: red; | ||
} | ||
} | ||
`, | ||
{ | ||
theme: { | ||
screens: { | ||
foo: { max: '123px' }, | ||
}, | ||
}, | ||
}, | ||
), | ||
).toMatchInlineSnapshot(` | ||
"@media (123px >= width) { | ||
.foo { | ||
color: red; | ||
} | ||
}" | ||
`) | ||
}) | ||
|
||
it('should migrate a custom min and max-width screen', async () => { | ||
expect( | ||
await migrate( | ||
css` | ||
@media screen(foo) { | ||
.foo { | ||
color: red; | ||
} | ||
} | ||
`, | ||
{ | ||
theme: { | ||
screens: { | ||
foo: { min: '100px', max: '123px' }, | ||
}, | ||
}, | ||
}, | ||
), | ||
).toMatchInlineSnapshot(` | ||
"@media (123px >= width >= 100px) { | ||
.foo { | ||
color: red; | ||
} | ||
}" | ||
`) | ||
}) | ||
|
||
it('should migrate a raw media query', async () => { | ||
expect( | ||
await migrate( | ||
css` | ||
@media screen(foo) { | ||
.foo { | ||
color: red; | ||
} | ||
} | ||
`, | ||
{ | ||
theme: { | ||
screens: { | ||
foo: { raw: 'only screen and (min-width: 123px)' }, | ||
}, | ||
}, | ||
}, | ||
), | ||
).toMatchInlineSnapshot(` | ||
"@media only screen and (min-width: 123px) { | ||
.foo { | ||
color: red; | ||
} | ||
}" | ||
`) | ||
}) |
44 changes: 44 additions & 0 deletions
44
packages/@tailwindcss-upgrade/src/codemods/migrate-media-screen.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { type Plugin, type Root } from 'postcss' | ||
import type { Config } from 'tailwindcss' | ||
import { resolveConfig } from '../../../tailwindcss/src/compat/config/resolve-config' | ||
import { buildMediaQuery } from '../../../tailwindcss/src/compat/screens-config' | ||
import type { DesignSystem } from '../../../tailwindcss/src/design-system' | ||
import { DefaultMap } from '../../../tailwindcss/src/utils/default-map' | ||
|
||
export function migrateMediaScreen({ | ||
designSystem, | ||
userConfig, | ||
}: { | ||
designSystem?: DesignSystem | ||
userConfig?: Config | ||
} = {}): Plugin { | ||
function migrate(root: Root) { | ||
if (!designSystem || !userConfig) return | ||
|
||
let resolvedUserConfig = resolveConfig(designSystem, [{ base: '', config: userConfig }]) | ||
let screens = resolvedUserConfig?.theme?.screens || {} | ||
|
||
let mediaQueries = new DefaultMap<string, string | null>((name) => { | ||
let value = designSystem?.resolveThemeValue(`--breakpoint-${name}`) ?? screens?.[name] | ||
if (typeof value === 'string') return `(width >= theme(--breakpoint-${name}))` | ||
return value ? buildMediaQuery(value) : null | ||
}) | ||
|
||
root.walkAtRules((rule) => { | ||
if (rule.name !== 'media') return | ||
|
||
let screen = rule.params.match(/screen\(([^)]+)\)/) | ||
if (!screen) return | ||
|
||
let value = mediaQueries.get(screen[1]) | ||
if (!value) return | ||
|
||
rule.params = value | ||
}) | ||
} | ||
|
||
return { | ||
postcssPlugin: '@tailwindcss/upgrade/migrate-media-screen', | ||
OnceExit: migrate, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters