Skip to content

Commit

Permalink
automatically add content: '' to before and after variant styles (
Browse files Browse the repository at this point in the history
closes #405, related to #414)
  • Loading branch information
sastan committed Dec 12, 2022
1 parent 88bebcf commit 58c8700
Show file tree
Hide file tree
Showing 15 changed files with 157 additions and 47 deletions.
6 changes: 6 additions & 0 deletions .changeset/five-pots-give.md
@@ -0,0 +1,6 @@
---
'@twind/core': minor
'@twind/preset-tailwind': minor
---

automatically add `content: ''` to `before` and `after` variant styles (closes #405, related to #414)
6 changes: 3 additions & 3 deletions documentation/examples.md
Expand Up @@ -13,10 +13,10 @@ We have created a few [examples](https://github.com/tw-in-js/twind/tree/main/exa

## Presets

| Example | Try it live at | Description |
| ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Example | Try it live at | Description |
| ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Tailwind Forms](https://github.com/tw-in-js/twind/tree/main/examples/using-tailwind-forms) | [Stackblitz](https://stackblitz.com/fork/github/tw-in-js/twind/tree/main/examples/using-tailwind-forms)[Codesandbox](https://githubbox.com/tw-in-js/twind/tree/main/examples/using-tailwind-forms) | using [@twind/preset-autoprefix](./preset-autoprefix) and [@twind/preset-tailwind](./preset-tailwind) and [@twind/preset-tailwind-forms](./preset-tailwind-forms) |
| [Twind CDN](https://github.com/tw-in-js/twind/tree/main/examples/using-twind-cdn) | [Stackblitz](https://stackblitz.com/fork/github/tw-in-js/twind/tree/main/examples/using-twind-cdn)[Codesandbox](https://githubbox.com/tw-in-js/twind/tree/main/examples/using-twind-cdn) | using [@twind/cdn](./installation#twind-cdn) |
| [Twind CDN](https://github.com/tw-in-js/twind/tree/main/examples/using-twind-cdn) | [Stackblitz](https://stackblitz.com/fork/github/tw-in-js/twind/tree/main/examples/using-twind-cdn)[Codesandbox](https://githubbox.com/tw-in-js/twind/tree/main/examples/using-twind-cdn) | using [@twind/cdn](./installation#twind-cdn) |

## Integrations

Expand Down
6 changes: 3 additions & 3 deletions examples/README.md
Expand Up @@ -9,10 +9,10 @@ Some examples of how to use the Twind. These are great for reproductions of issu

## Packages

| Example | Try it live at | Description |
| ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Example | Try it live at | Description |
| ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Tailwind Forms](https://github.com/tw-in-js/twind/tree/main/examples/using-tailwind-forms) | [Stackblitz](https://stackblitz.com/fork/github/tw-in-js/twind/tree/main/examples/using-tailwind-forms)[Codesandbox](https://githubbox.com/tw-in-js/twind/tree/main/examples/using-tailwind-forms) | using [@twind/preset-autoprefix](https://github.com/tw-in-js/twind/tree/main/packages/preset-autoprefix) and [@twind/preset-tailwind](https://github.com/tw-in-js/twind/tree/main/packages/preset-tailwind) and [@twind/preset-tailwind-forms](https://github.com/tw-in-js/twind/tree/main/packages/preset-tailwind-forms) |
| [Twind CDN](https://github.com/tw-in-js/twind/tree/main/examples/using-twind-cdn) | [Stackblitz](https://stackblitz.com/fork/github/tw-in-js/twind/tree/main/examples/using-twind-cdn)[Codesandbox](https://githubbox.com/tw-in-js/twind/tree/main/examples/using-twind-cdn) | using [@twind/cdn](https://github.com/tw-in-js/twind/tree/main/packages/cdn) |
| [Twind CDN](https://github.com/tw-in-js/twind/tree/main/examples/using-twind-cdn) | [Stackblitz](https://stackblitz.com/fork/github/tw-in-js/twind/tree/main/examples/using-twind-cdn)[Codesandbox](https://githubbox.com/tw-in-js/twind/tree/main/examples/using-twind-cdn) | using [@twind/cdn](https://github.com/tw-in-js/twind/tree/main/packages/cdn) |

## Frameworks

Expand Down
2 changes: 1 addition & 1 deletion packages/cdn/package.json
Expand Up @@ -27,7 +27,7 @@
"name": "@twind/cdn",
"path": "dist/cdn.esnext.js",
"brotli": true,
"limit": "16kb"
"limit": "16.2kb"
}
],
"dependencies": {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/package.json
Expand Up @@ -32,14 +32,14 @@
"path": "dist/core.esnext.js",
"import": "{ setup }",
"brotli": true,
"limit": "5.55kb"
"limit": "5.6kb"
},
{
"name": "@twind/core (twind + cssom)",
"path": "dist/core.esnext.js",
"import": "{ twind, cssom }",
"brotli": true,
"limit": "4.9kb"
"limit": "5kb"
}
],
"dependencies": {
Expand Down
15 changes: 8 additions & 7 deletions packages/core/src/define-config.ts
Expand Up @@ -21,15 +21,16 @@ export function defineConfig<Theme = BaseTheme, Presets extends Preset<any>[] =
// most user config values go first to have precendence over preset config
// only `preflight` and `theme` are applied as last preset to override all presets
let config: TwindConfig<BaseTheme & ExtractThemes<Theme, Presets>> = {
preflight: userConfig.preflight !== false && [],
darkMode: undefined,
darkColor: undefined,
preflight: userConfig.preflight !== false && [],
theme: {},
variants: asArray(userConfig.variants),
rules: asArray(userConfig.rules),
ignorelist: asArray(userConfig.ignorelist),
hash: userConfig.hash,
stringify: userConfig.stringify || noprefix,
hash: undefined,
stringify: (property, value) => property + ':' + value,
finalize: [],
}

for (const preset of asArray([
Expand All @@ -41,6 +42,7 @@ export function defineConfig<Theme = BaseTheme, Presets extends Preset<any>[] =
theme: userConfig.theme as TwindConfig<BaseTheme & ExtractThemes<Theme, Presets>>['theme'],
hash: userConfig.hash,
stringify: userConfig.stringify,
finalize: userConfig.finalize,
} as TwindPresetConfig<Theme>,
])) {
const {
Expand All @@ -53,6 +55,7 @@ export function defineConfig<Theme = BaseTheme, Presets extends Preset<any>[] =
ignorelist,
hash = config.hash,
stringify = config.stringify,
finalize,
} = typeof preset == 'function' ? preset(config) : (preset as TwindPresetConfig<Theme>)

config = {
Expand All @@ -78,12 +81,10 @@ export function defineConfig<Theme = BaseTheme, Presets extends Preset<any>[] =

hash,
stringify,

finalize: [...config.finalize, ...asArray(finalize)],
} as TwindConfig<BaseTheme & ExtractThemes<Theme, Presets>>
}

return config
}

function noprefix(property: string, value: string): string {
return property + ':' + value
}
39 changes: 21 additions & 18 deletions packages/core/src/internal/context.ts
Expand Up @@ -19,7 +19,7 @@ import type {
import { DEV } from 'distilt/env'

import { makeThemeFunction } from './theme'
import { asArray, escape, hash as defaultHash, identity } from '../utils'
import { asArray, escape, hash as defaultHash, identity, noop } from '../utils'
import { fromMatch } from '../rules'
import { warn } from './warn'

Expand All @@ -37,12 +37,13 @@ type VariantFunction<Theme extends BaseTheme = BaseTheme> = (
export function createContext<Theme extends BaseTheme = BaseTheme>({
theme,
darkMode,
darkColor,
darkColor = noop,
variants,
rules,
hash,
stringify,
ignorelist,
finalize,
}: TwindConfig<Theme>): Context<Theme> {
// Used to cache resolved rule values
const variantCache = new Map<string, MaybeArray<string>>()
Expand All @@ -58,7 +59,7 @@ export function createContext<Theme extends BaseTheme = BaseTheme>({

const ignored = createRegExpExecutor(ignorelist, (value, condition) => condition.test(value))

const reportedUnknownClasses = new Set<string>()
const reportedUnknownClasses = /* #__PURE__ */ new Set<string>()

// add dark as last variant to allow user to override it
// we can modify variants as it has been passed through defineConfig which already made a copy
Expand All @@ -78,6 +79,17 @@ export function createContext<Theme extends BaseTheme = BaseTheme>({
? defaultHash
: identity

if (h !== identity) {
finalize.push((rule) => ({
...rule,
n: rule.n && h(rule.n),
d: rule.d?.replace(
/--(tw(?:-[\w-]+)?)\b/g,
(_: string, property: string) => '--' + h(property).replace('#', ''),
),
}))
}

return {
theme: makeThemeFunction(theme),

Expand All @@ -86,12 +98,11 @@ export function createContext<Theme extends BaseTheme = BaseTheme>({
h,

s(property, value) {
// Hash/Tag tailwind custom properties during serialization
return stringify(hashVars(property, h), hashVars(value, h), this)
return stringify(property, value, this)
},

d(section, key, color) {
return darkColor?.(section, key, this, color)
return darkColor(section, key, this, color)
},

v(value) {
Expand Down Expand Up @@ -131,6 +142,10 @@ export function createContext<Theme extends BaseTheme = BaseTheme>({

return ruleCache.get(key)
},

f(rule) {
return finalize.reduce((rule, p) => p(rule, this), rule)
},
}
}

Expand Down Expand Up @@ -229,15 +244,3 @@ export function toCondition(value: string | RegExp): RegExp {
? new RegExp('^' + value + (value.includes('$') || value.slice(-1) == '-' ? '' : '$'))
: value
}

function hashVars(value: string, h: Context['h']): string {
// PERF: check for --tw before running the regexp
// if (value.includes('--tw')) {
return value.replace(
/--(tw(?:-[\w-]+)?)\b/g,
(_: string, property: string) => '--' + h(property).replace('#', ''),
)
// }

// return value
}
1 change: 1 addition & 0 deletions packages/core/src/tests/twind.test.ts
Expand Up @@ -23,5 +23,6 @@ test('the config can accessed', () => {
ignorelist: [],
hash: undefined,
stringify: tw.config.stringify,
finalize: [],
})
})
6 changes: 3 additions & 3 deletions packages/core/src/twind.ts
Expand Up @@ -65,9 +65,9 @@ export function twind(userConfig: TwindConfig<any> | TwindUserConfig<any>, sheet
)

function insert(rule: TwindRule): string | undefined {
const name = rule.n && context.h(rule.n)
const finalRule = context.f(rule)

const cssText = stringify(name ? { ...rule, n: name } : rule)
const cssText = stringify(finalRule)

// If not already inserted
if (cssText && !insertedRules.has(cssText)) {
Expand All @@ -84,7 +84,7 @@ export function twind(userConfig: TwindConfig<any> | TwindUserConfig<any>, sheet
sortedPrecedences.splice(index, 0, rule)
}

return name
return finalRule.n
}

return Object.defineProperties(
Expand Down
24 changes: 21 additions & 3 deletions packages/core/src/types.ts
Expand Up @@ -108,21 +108,28 @@ export interface Context<Theme extends BaseTheme = BaseTheme> {
*
* @private
*/
v: (value: string) => MaybeArray<string>
v(value: string): MaybeArray<string>

/**
* resolves a rule
*
* @private
*/
r: (value: string, isDark?: boolean) => RuleResult
r(value: string, isDark?: boolean): RuleResult

/**
* stringifies a CSS property and value to a declaration
*
* @private
*/
s: (property: string, value: string) => string
s(property: string, value: string): string

/**
* called right before the rule is stringified and inserted into the sheet
*
* @private
*/
f(rule: TwindRule): TwindRule
}

// Get the leaf theme value and omit nested records like for colors
Expand Down Expand Up @@ -336,6 +343,11 @@ export type DarkColor<Theme extends BaseTheme> = (
color: ColorValue,
) => ColorValue | Falsey

export type Finalize<Theme extends BaseTheme = BaseTheme> = (
rule: TwindRule,
context: Context<Theme>,
) => TwindRule

export interface TwindConfig<Theme extends BaseTheme = BaseTheme> {
/** Allows to change how the `dark` variant is used (default: `"media"`) */
darkMode?: DarkModeConfig
Expand All @@ -350,6 +362,8 @@ export interface TwindConfig<Theme extends BaseTheme = BaseTheme> {
hash?: boolean | undefined | HashFunction
stringify: StringifyDeclaration<Theme>
ignorelist: (string | RegExp)[]

finalize: Finalize<Theme>[]
}

export type ArrayType<T> = T extends (infer Item)[] ? Item : T
Expand Down Expand Up @@ -389,6 +403,8 @@ export interface TwindPresetConfig<Theme = BaseTheme> {
hash?: boolean | undefined | HashFunction
stringify?: StringifyDeclaration<Theme & BaseTheme>
ignorelist?: MaybeArray<string | RegExp>

finalize?: MaybeArray<Finalize<Theme & BaseTheme>>
}

export interface TwindUserConfig<Theme = BaseTheme, Presets extends Preset<any>[] = Preset[]> {
Expand Down Expand Up @@ -427,6 +443,8 @@ export interface TwindUserConfig<Theme = BaseTheme, Presets extends Preset<any>[

stringify?: StringifyDeclaration<BaseTheme & ExtractThemes<Theme, Presets>>
ignorelist?: MaybeArray<string | RegExp>

finalize?: MaybeArray<Finalize<Theme & BaseTheme>>
}

export interface BaseTheme {
Expand Down
6 changes: 3 additions & 3 deletions packages/preset-ext/src/preset-ext.test.json
@@ -1,11 +1,11 @@
{
"background-color[#1da1f1]": ".background-color\\[\\#1da1f1\\]{background-color:#1da1f1}",
"after::block": ".after\\:\\:block::after{display:block}",
"after::block": ".after\\:\\:block::after{content:var(--tw-content);display:block}",
"before::(block inset-0)": [
"before::inset-0 before::block",
[
".before\\:\\:inset-0::before{top:0px;right:0px;bottom:0px;left:0px}",
".before\\:\\:block::before{display:block}"
".before\\:\\:inset-0::before{content:var(--tw-content);top:0px;right:0px;bottom:0px;left:0px}",
".before\\:\\:block::before{content:var(--tw-content);display:block}"
]
],
"children:underline": ".children\\:underline>*{text-decoration-line:underline}",
Expand Down
8 changes: 8 additions & 0 deletions packages/preset-tailwind/src/index.ts
Expand Up @@ -22,5 +22,13 @@ export default function presetTailwind({
theme,
variants,
rules,
finalize(rule) {
// automatically add `content: ''` to before and after so you don’t have to specify it unless you want a different value
if (rule.r.some((r) => /^&::(before|after)$/.test(r)) && !rule.d?.includes('content:')) {
return { ...rule, d: ['content:var(--tw-content)', rule.d].filter(Boolean).join(';') }
}

return rule
},
}
}

0 comments on commit 58c8700

Please sign in to comment.