Allow configuring dark mode from configs
This commit is contained in:
parent
cc353d310b
commit
67efbfe628
4 changed files with 96 additions and 0 deletions
|
|
@ -26,6 +26,7 @@ interface ResolutionContext {
|
|||
}
|
||||
|
||||
let minimal: ResolvedConfig = {
|
||||
darkMode: null,
|
||||
theme: {},
|
||||
plugins: [],
|
||||
content: {
|
||||
|
|
@ -52,10 +53,18 @@ export function resolveConfig(design: DesignSystem, files: ConfigFile[]): Resolv
|
|||
resolveInternal(ctx, file)
|
||||
}
|
||||
|
||||
// Merge dark mode
|
||||
for (let config of ctx.configs) {
|
||||
if ('darkMode' in config && config.darkMode !== undefined) {
|
||||
ctx.result.darkMode = config.darkMode ?? null
|
||||
}
|
||||
}
|
||||
|
||||
// Merge themes
|
||||
mergeTheme(ctx)
|
||||
|
||||
return {
|
||||
...ctx.result,
|
||||
content: ctx.content,
|
||||
theme: ctx.theme as ResolvedConfig['theme'],
|
||||
plugins: ctx.plugins,
|
||||
|
|
|
|||
|
|
@ -39,3 +39,35 @@ export interface ResolvedContentConfig {
|
|||
export interface ResolvedConfig {
|
||||
content: ResolvedContentConfig
|
||||
}
|
||||
|
||||
// Dark Mode support
|
||||
type DarkModeStrategy =
|
||||
// No dark mode support
|
||||
| false
|
||||
|
||||
// Use the `media` query strategy.
|
||||
| 'media'
|
||||
|
||||
// Use the `class` strategy, which requires a `.dark` class on the `html`.
|
||||
| 'class'
|
||||
|
||||
// Use the `class` strategy with a custom class instead of `.dark`.
|
||||
| ['class', string]
|
||||
|
||||
// Use the `selector` strategy — same as `class` but uses `:where()` for more predicable behavior
|
||||
| 'selector'
|
||||
|
||||
// Use the `selector` strategy with a custom selector instead of `.dark`.
|
||||
| ['selector', string]
|
||||
|
||||
// Use the `variant` strategy, which allows you to completely customize the selector
|
||||
// It takes a string or an array of strings, which are passed directly to `addVariant()`
|
||||
| ['variant', string | string[]]
|
||||
|
||||
export interface UserConfig {
|
||||
darkMode?: DarkModeStrategy
|
||||
}
|
||||
|
||||
export interface ResolvedConfig {
|
||||
darkMode: DarkModeStrategy | null
|
||||
}
|
||||
|
|
|
|||
53
packages/tailwindcss/src/compat/dark-mode.ts
Normal file
53
packages/tailwindcss/src/compat/dark-mode.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import type { PluginAPI } from "../plugin-api"
|
||||
import type { ResolvedConfig } from "./config/types"
|
||||
|
||||
export function darkModePlugin({ addVariant, config }: PluginAPI) {
|
||||
let darkMode = config('darkMode', null) as ResolvedConfig['darkMode']
|
||||
let [mode, selector = '.dark'] = Array.isArray(darkMode) ? darkMode : [darkMode]
|
||||
|
||||
if (mode === 'variant') {
|
||||
let formats
|
||||
|
||||
if (Array.isArray(selector)) {
|
||||
formats = selector
|
||||
} else if (typeof selector === 'function') {
|
||||
formats = selector
|
||||
} else if (typeof selector === 'string') {
|
||||
formats = [selector]
|
||||
}
|
||||
|
||||
if (Array.isArray(formats)) {
|
||||
for (let format of formats) {
|
||||
if (format === '.dark') {
|
||||
mode = false
|
||||
console.warn('darkmode-variant-without-selector', [
|
||||
'When using `variant` for `darkMode`, you must provide a selector.',
|
||||
'Example: `darkMode: ["variant", ".your-selector &"]`',
|
||||
])
|
||||
} else if (!format.includes('&')) {
|
||||
mode = false
|
||||
console.warn('darkmode-variant-without-ampersand', [
|
||||
'When using `variant` for `darkMode`, your selector must contain `&`.',
|
||||
'Example `darkMode: ["variant", ".your-selector &"]`',
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selector = formats as any
|
||||
}
|
||||
|
||||
if (mode === null) {
|
||||
// Do nothing
|
||||
} else if (mode === 'selector') {
|
||||
// New preferred behavior
|
||||
addVariant('dark', `&:where(${selector}, ${selector} *)`)
|
||||
} else if (mode === 'media') {
|
||||
addVariant('dark', '@media (prefers-color-scheme: dark)')
|
||||
} else if (mode === 'variant') {
|
||||
addVariant('dark', selector)
|
||||
} else if (mode === 'class') {
|
||||
// Old behavior
|
||||
addVariant('dark', `&:is(${selector} *)`)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import type { Candidate, NamedUtilityValue } from './candidate'
|
|||
import { createCompatConfig } from './compat/config/create-compat-config'
|
||||
import { resolveConfig, type ConfigFile } from './compat/config/resolve-config'
|
||||
import type { ResolvedConfig, UserConfig } from './compat/config/types'
|
||||
import { darkModePlugin } from './compat/dark-mode'
|
||||
import type { DesignSystem } from './design-system'
|
||||
import { createThemeFn } from './theme-fn'
|
||||
import { withAlpha, withNegative } from './utilities'
|
||||
|
|
@ -354,6 +355,7 @@ export function registerPlugins(
|
|||
{ config: createCompatConfig(designSystem.theme) },
|
||||
...configs,
|
||||
{ config: { plugins } },
|
||||
{ config: { plugins: [darkModePlugin] } },
|
||||
])
|
||||
|
||||
let pluginApi = buildPluginApi(designSystem, ast, resolvedConfig)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue