Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dark and light mode variants #142

Merged
merged 1 commit into from
Sep 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions __fixtures__/!variants.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,12 @@ tw`focus-within:flex`
tw`motion-safe:flex`
tw`motion-reduce:flex`

// Dark/Light themes
tw`dark:bg-black`
tw`light:bg-black`
tw`dark:sm:bg-black`
tw`light:sm:bg-black`
tw`dark:group-hover:sm:bg-black`
tw`light:group-hocus:sm:bg-black`

const multiVariants = tw`xl:placeholder-red-500! first:md:block sm:disabled:flex`
53 changes: 53 additions & 0 deletions __snapshots__/plugin.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1892,6 +1892,14 @@ tw\`focus-within:flex\`
tw\`motion-safe:flex\`
tw\`motion-reduce:flex\`

// Dark/Light themes
tw\`dark:bg-black\`
tw\`light:bg-black\`
tw\`dark:sm:bg-black\`
tw\`light:sm:bg-black\`
tw\`dark:group-hover:sm:bg-black\`
tw\`light:group-hocus:sm:bg-black\`

const multiVariants = tw\`xl:placeholder-red-500! first:md:block sm:disabled:flex\`

↓ ↓ ↓ ↓ ↓ ↓
Expand Down Expand Up @@ -2137,6 +2145,51 @@ const multiVariants = tw\`xl:placeholder-red-500! first:md:block sm:disabled:fle
'@media (prefers-reduced-motion: reduce)': {
display: 'flex',
},
}) // Dark/Light themes

;({
'.dark &': {
'--bg-opacity': '1',
backgroundColor: 'rgba(0, 0, 0, var(--bg-opacity))',
},
})
;({
'.light &': {
'--bg-opacity': '1',
backgroundColor: 'rgba(0, 0, 0, var(--bg-opacity))',
},
})
;({
'.dark &': {
'@media (min-width: 640px)': {
'--bg-opacity': '1',
backgroundColor: 'rgba(0, 0, 0, var(--bg-opacity))',
},
},
})
;({
'.light &': {
'@media (min-width: 640px)': {
'--bg-opacity': '1',
backgroundColor: 'rgba(0, 0, 0, var(--bg-opacity))',
},
},
})
;({
'.dark .group:hover &, .dark.group:hover &': {
'@media (min-width: 640px)': {
'--bg-opacity': '1',
backgroundColor: 'rgba(0, 0, 0, var(--bg-opacity))',
},
},
})
;({
'.light .group:hover &, .light .group:focus &, .light.group:hover &, .light.group:focus &': {
'@media (min-width: 640px)': {
'--bg-opacity': '1',
backgroundColor: 'rgba(0, 0, 0, var(--bg-opacity))',
},
},
})
const multiVariants = {
':first-child': {
Expand Down
12 changes: 9 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"dset": "^2.0.1",
"lodash.merge": "^4.6.2",
"string-similarity": "^4.0.1",
"tailwindcss": "^1.7.5",
"tailwindcss": "^1.8.8",
"timsort": "^0.3.0"
},
"peerDependencies": {
Expand Down
86 changes: 80 additions & 6 deletions src/config/variantConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,90 @@ export default {
'odd-of-type': ':nth-of-type(odd)',

// Group states
// Add className="group" to an ancestor and add these on the children
// You'll need to add className="group" to an ancestor to make these work
// https://github.com/ben-rogerson/twin.macro/blob/master/docs/group.md
'group-hover': '.group:hover &', // Tailwind
'group-focus': '.group:focus &', // Tailwind
'group-hocus': '.group:hover &, .group:focus &',
'group-active': '.group:active &',
'group-visited': '.group:visited &',
'group-hover': variantData =>
generateGroupSelector('.group:hover &', variantData), // Tailwind
'group-focus': variantData =>
generateGroupSelector('.group:focus &', variantData), // Tailwind
'group-hocus': variantData =>
generateGroupSelector('.group:hover &, .group:focus &', variantData),
'group-active': variantData =>
generateGroupSelector('.group:active &', variantData),
'group-visited': variantData =>
generateGroupSelector('.group:visited &', variantData),

// Motion control
// https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion
'motion-safe': '@media (prefers-reduced-motion: no-preference)',
'motion-reduce': '@media (prefers-reduced-motion: reduce)',

// Dark theme
dark: ({ hasGroupVariant, config, errorCustom }) => {
const styles =
{
// Media strategy: The default when you prepend with dark, tw`dark:block`
media: '@media (prefers-color-scheme: dark)',
// Class strategy: In your tailwind.config.js, add `{ dark: 'class' }
// then add a `className="dark"` on a parent element.
class: !hasGroupVariant && '.dark &',
}[config('dark') || 'media'] || null

if (!styles && !hasGroupVariant) {
errorCustom(
"The `dark` config option must be either `{ dark: 'media' }` (default) or `{ dark: 'class' }`"
)
}

return styles
},

// Light theme
light: ({ hasGroupVariant, config, errorCustom }) => {
const styles =
{
// Media strategy: The default when you prepend with light, tw`light:block`
media: '@media (prefers-color-scheme: light)',
// Class strategy: In your tailwind.config.js, add `{ light: 'class' }
// then add a `className="light"` on a parent element.
class: !hasGroupVariant && '.light &',
}[config('light') || config('dark') || 'media'] || null

if (!styles && !hasGroupVariant) {
if (config('light')) {
errorCustom(
"The `light` config option must be either `{ light: 'media' }` (default) or `{ light: 'class' }`"
)
}

errorCustom(
"The `dark` config option must be either `{ dark: 'media' }` (default) or `{ dark: 'class' }`"
)
}

return styles
},
}

const generateGroupSelector = (
className,
{ hasDarkVariant, hasLightVariant, config }
) => {
const themeVariant =
(hasDarkVariant && config('dark') === 'class' && ['dark ', 'dark']) ||
(hasLightVariant &&
(config('light') === 'class' || config('dark') === 'class') && [
'light ',
'light',
])
return themeVariant
? themeVariant
.map(v =>
className
.split(', ')
.map(cn => `.${v}${cn}`)
.join(', ')
)
.join(', ')
: className
}
33 changes: 30 additions & 3 deletions src/variants.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { MacroError } from 'babel-plugin-macros'
import dlv from 'dlv'
import cleanSet from 'clean-set'
import { stringifyScreen } from './screens'
import { logNoVariant } from './logging'
import { logNoVariant, logGeneralError } from './logging'
import { variantConfig } from './config'

/**
* Validate variants against the variants config key
*/
const validateVariants = ({ variants, state }) => {
const validateVariants = ({ variants, state, ...rest }) => {
if (!variants) return []

const screens = dlv(state.config, ['theme', 'screens'])
Expand All @@ -22,7 +22,18 @@ const validateVariants = ({ variants, state }) => {
}

if (variantConfig[variant]) {
const foundVariant = variantConfig[variant]
let foundVariant = variantConfig[variant]

if (typeof foundVariant === 'function') {
const context = {
...rest,
config: item => state.config[item] || null,
errorCustom: message => {
throw new MacroError(logGeneralError(message))
},
}
foundVariant = foundVariant(context)
}

if (state.sassyPseudo) {
return foundVariant.replace(/(?<= ):|^:/g, '&:')
Expand Down Expand Up @@ -55,10 +66,26 @@ const splitVariants = ({ classNameRaw, state }) => {
}
}

// dark: and light: variants
const hasDarkVariant = variantsList.some(v => v === 'dark')
const hasLightVariant = variantsList.some(v => v === 'light')
if (hasDarkVariant && hasLightVariant) {
throw new MacroError(
logGeneralError(
'The light: and dark: variants can’t be used on the same element'
)
)
}

const hasGroupVariant = variantsList.some(v => v.startsWith('group-'))

// Match the filtered variants
const variants = validateVariants({
variants: variantsList,
state,
hasDarkVariant,
hasLightVariant,
hasGroupVariant,
})

const hasVariants = variants.length > 0
Expand Down
1 change: 1 addition & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const animations = {
}

module.exports = {
dark: 'class',
theme: {
...animations,
container: {
Expand Down