Skip to content

Commit

Permalink
Add support for setting screens in JS config (#14415)
Browse files Browse the repository at this point in the history
This PR adds support for the _simple_ case of the `screens` option
inside JS config paths. This allows JS configs to extend the responsive
theme by adding custom breakpoints. Here's an example from our v3 docs:

```js
{
  theme: {
    screens: {
      'sm': '640px',
      // => @media (min-width: 640px) { ... }

      'md': '768px',
      // => @media (min-width: 768px) { ... }

      'lg': '1024px',
      // => @media (min-width: 1024px) { ... }

      'xl': '1280px',
      // => @media (min-width: 1280px) { ... }

      '2xl': '1536px',
      // => @media (min-width: 1536px) { ... }
    }
  }
}
```

For simple breakpoints, this will extend the core breakpoints and will
work with the `min-*` and `max-*` utilities. However, we also support
complex ways of setting up custom screens like this:

```js
{
  theme: {
    extend: {
      screens: {
        sm: { max: '639px' },
        md: [
          { min: '668px', max: '767px' },
          { min: '868px' },
        ],
        lg: { min: '868px' },
        xl: { min: '1024px', max: '1279px' },
        tall: { raw: '(min-height: 800px)' },
      },
    },
  },
}
```

For these complex setups, we _only_ generate the shorthand variant (e.g.
`tall`) but those won't integrate within `min-*` and `max-*`. In v3,
adding any of these complex configurations would omit any `min-*` and
`max-*` variants.
  • Loading branch information
philipp-spiess committed Sep 18, 2024
1 parent 6ca8cc6 commit 2ddb715
Show file tree
Hide file tree
Showing 9 changed files with 806 additions and 27 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add support for `aria`, `supports`, and `data` variants defined in JS config files ([#14407](https://github.com/tailwindlabs/tailwindcss/pull/14407))
- Add `@tailwindcss/upgrade` tooling ([#14434](https://github.com/tailwindlabs/tailwindcss/pull/14434))

### Added

- Support `screens` in JS config files ([#14415](https://github.com/tailwindlabs/tailwindcss/pull/14415))

### Fixed

- Support `borderRadius.*` as an alias for `--radius-*` when using dot notation inside the `theme()` function ([#14436](https://github.com/tailwindlabs/tailwindcss/pull/14436))
Expand Down
7 changes: 5 additions & 2 deletions packages/tailwindcss/src/compat/apply-compat-hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { resolveConfig } from './config/resolve-config'
import type { UserConfig } from './config/types'
import { darkModePlugin } from './dark-mode'
import { buildPluginApi, type CssPluginOptions, type Plugin } from './plugin-api'
import { registerScreensConfig } from './screens-config'
import { registerThemeVariantOverrides } from './theme-variants'

export async function applyCompatibilityHooks({
Expand Down Expand Up @@ -174,6 +175,7 @@ export async function applyCompatibilityHooks({
...userConfig,
{ config: { plugins: [darkModePlugin] } },
])
let resolvedUserConfig = resolveConfig(designSystem, userConfig)

let pluginApi = buildPluginApi(designSystem, ast, resolvedConfig)

Expand All @@ -184,9 +186,10 @@ export async function applyCompatibilityHooks({
// Merge the user-configured theme keys into the design system. The compat
// config would otherwise expand into namespaces like `background-color` which
// core utilities already read from.
applyConfigToTheme(designSystem, userConfig)
applyConfigToTheme(designSystem, resolvedUserConfig)

registerThemeVariantOverrides(resolvedConfig, designSystem)
registerThemeVariantOverrides(resolvedUserConfig, designSystem)
registerScreensConfig(resolvedUserConfig, designSystem)

// Replace `resolveThemeValue` with a version that is backwards compatible
// with dot-notation but also aware of any JS theme configurations registered
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import { expect, test } from 'vitest'
import { buildDesignSystem } from '../design-system'
import { Theme } from '../theme'
import { applyConfigToTheme } from './apply-config-to-theme'
import { resolveConfig } from './config/resolve-config'

test('Config values can be merged into the theme', () => {
let theme = new Theme()
let design = buildDesignSystem(theme)

applyConfigToTheme(design, [
let resolvedUserConfig = resolveConfig(design, [
{
config: {
theme: {
Expand Down Expand Up @@ -36,6 +37,7 @@ test('Config values can be merged into the theme', () => {
},
},
])
applyConfigToTheme(design, resolvedUserConfig)

expect(theme.resolve('primary', ['--color'])).toEqual('#c0ffee')
expect(theme.resolve('red-500', ['--color'])).toEqual('red')
Expand Down
13 changes: 6 additions & 7 deletions packages/tailwindcss/src/compat/apply-config-to-theme.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { DesignSystem } from '../design-system'
import { ThemeOptions } from '../theme'
import { resolveConfig, type ConfigFile } from './config/resolve-config'
import type { ResolvedConfig } from './config/types'

function resolveThemeValue(value: unknown, subValue: string | null = null): string | null {
Expand All @@ -20,10 +19,11 @@ function resolveThemeValue(value: unknown, subValue: string | null = null): stri
return null
}

export function applyConfigToTheme(designSystem: DesignSystem, configs: ConfigFile[]) {
let theme = resolveConfig(designSystem, configs).theme

export function applyConfigToTheme(designSystem: DesignSystem, { theme }: ResolvedConfig) {
for (let [path, value] of themeableValues(theme)) {
if (typeof value !== 'string' && typeof value !== 'number') {
continue
}
let name = keyPathToCssProperty(path)
designSystem.theme.add(
`--${name}`,
Expand Down Expand Up @@ -111,9 +111,8 @@ function themeableValues(config: ResolvedConfig['theme']): [string[], unknown][]
}

function keyPathToCssProperty(path: string[]) {
if (path[0] === 'colors') {
path[0] = 'color'
}
if (path[0] === 'colors') path[0] = 'color'
if (path[0] === 'screens') path[0] = 'breakpoint'

return (
path
Expand Down
62 changes: 62 additions & 0 deletions packages/tailwindcss/src/compat/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1078,3 +1078,65 @@ test('creates variants for `data`, `supports`, and `aria` theme options at the s
"
`)
})

test('merges css breakpoints with js config screens', async () => {
let input = css`
@theme default {
--breakpoint-sm: 40rem;
--breakpoint-md: 48rem;
--breakpoint-lg: 64rem;
--breakpoint-xl: 80rem;
--breakpoint-2xl: 96rem;
}
@theme {
--breakpoint-md: 50rem;
}
@config "./config.js";
@tailwind utilities;
`

let compiler = await compile(input, {
loadConfig: async () => ({
theme: {
extend: {
screens: {
sm: '44rem',
},
},
},
}),
})

expect(compiler.build(['sm:flex', 'md:flex', 'lg:flex', 'min-sm:max-md:underline']))
.toMatchInlineSnapshot(`
":root {
--breakpoint-md: 50rem;
--breakpoint-lg: 64rem;
--breakpoint-xl: 80rem;
--breakpoint-2xl: 96rem;
}
.sm\\:flex {
@media (width >= 44rem) {
display: flex;
}
}
.min-sm\\:max-md\\:underline {
@media (width >= 44rem) {
@media (width < 50rem) {
text-decoration-line: underline;
}
}
}
.md\\:flex {
@media (width >= 50rem) {
display: flex;
}
}
.lg\\:flex {
@media (width >= 64rem) {
display: flex;
}
}
"
`)
})
10 changes: 5 additions & 5 deletions packages/tailwindcss/src/compat/default-theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -884,11 +884,11 @@ export default {
...barePercentages,
},
screens: {
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
'2xl': '1536px',
sm: '40rem',
md: '48rem',
lg: '64rem',
xl: '80rem',
'2xl': '96rem',
},
scrollMargin: ({ theme }) => theme('spacing'),
scrollPadding: ({ theme }) => theme('spacing'),
Expand Down
Loading

0 comments on commit 2ddb715

Please sign in to comment.