tailwindcss 3.2.7 → 3.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/CHANGELOG.md +55 -8
  2. package/lib/cli/build/index.js +7 -3
  3. package/lib/cli/build/plugin.js +28 -19
  4. package/lib/cli/build/watching.js +4 -2
  5. package/lib/cli/index.js +12 -21
  6. package/lib/cli/init/index.js +21 -6
  7. package/lib/corePluginList.js +4 -0
  8. package/lib/corePlugins.js +282 -26
  9. package/lib/css/preflight.css +2 -0
  10. package/lib/featureFlags.js +8 -1
  11. package/lib/lib/expandApplyAtRules.js +12 -1
  12. package/lib/lib/generateRules.js +14 -10
  13. package/lib/lib/getModuleDependencies.js +79 -33
  14. package/lib/lib/load-config.js +40 -0
  15. package/lib/lib/setupContextUtils.js +10 -2
  16. package/lib/lib/setupTrackingContext.js +4 -4
  17. package/lib/lib/sharedState.js +6 -1
  18. package/lib/oxide/cli/build/index.js +7 -3
  19. package/lib/oxide/cli/build/plugin.js +27 -18
  20. package/lib/oxide/cli/build/watching.js +1 -1
  21. package/lib/oxide/cli/index.js +10 -16
  22. package/lib/oxide/cli/init/index.js +19 -4
  23. package/lib/public/colors.js +44 -22
  24. package/lib/public/default-config.js +2 -2
  25. package/lib/public/default-theme.js +2 -2
  26. package/lib/public/load-config.js +10 -0
  27. package/lib/util/applyImportantSelector.js +37 -0
  28. package/lib/util/dataTypes.js +3 -0
  29. package/lib/util/formatVariantSelector.js +34 -32
  30. package/lib/util/getAllConfigs.js +2 -2
  31. package/lib/util/normalizeConfig.js +2 -3
  32. package/lib/util/pluginUtils.js +9 -2
  33. package/lib/util/resolveConfigPath.js +19 -7
  34. package/lib/util/splitAtTopLevelOnly.js +7 -1
  35. package/lib/util/validateConfig.js +11 -0
  36. package/loadConfig.d.ts +4 -0
  37. package/loadConfig.js +2 -0
  38. package/package.json +5 -4
  39. package/src/cli/build/index.js +7 -7
  40. package/src/cli/build/plugin.js +28 -23
  41. package/src/cli/build/watching.js +4 -2
  42. package/src/cli/index.js +8 -26
  43. package/src/cli/init/index.js +37 -8
  44. package/src/corePluginList.js +1 -1
  45. package/src/corePlugins.js +184 -27
  46. package/src/css/preflight.css +2 -0
  47. package/src/featureFlags.js +7 -0
  48. package/src/lib/expandApplyAtRules.js +14 -1
  49. package/src/lib/generateRules.js +15 -5
  50. package/src/lib/getModuleDependencies.js +70 -30
  51. package/src/lib/load-config.ts +31 -0
  52. package/src/lib/setupContextUtils.js +9 -2
  53. package/src/lib/setupTrackingContext.js +4 -4
  54. package/src/lib/sharedState.js +15 -6
  55. package/src/oxide/cli/build/index.ts +7 -7
  56. package/src/oxide/cli/build/plugin.ts +28 -22
  57. package/src/oxide/cli/build/watching.ts +1 -1
  58. package/src/oxide/cli/index.ts +7 -15
  59. package/src/oxide/cli/init/index.ts +34 -7
  60. package/src/public/colors.js +22 -0
  61. package/src/public/default-config.js +1 -1
  62. package/src/public/default-theme.js +2 -2
  63. package/src/public/load-config.js +2 -0
  64. package/src/util/applyImportantSelector.js +30 -0
  65. package/src/util/dataTypes.js +4 -0
  66. package/src/util/formatVariantSelector.js +36 -10
  67. package/src/util/getAllConfigs.js +2 -2
  68. package/src/util/normalizeConfig.js +2 -1
  69. package/src/util/pluginUtils.js +10 -2
  70. package/src/util/resolveConfigPath.js +12 -1
  71. package/src/util/splitAtTopLevelOnly.js +8 -1
  72. package/src/util/validateConfig.js +13 -0
  73. package/stubs/.gitignore +1 -0
  74. package/stubs/.prettierrc.json +6 -0
  75. package/stubs/{defaultConfig.stub.js → config.full.js} +36 -1
  76. package/stubs/{simpleConfig.stub.js → config.simple.js} +0 -1
  77. package/stubs/postcss.config.js +6 -0
  78. package/stubs/tailwind.config.cjs +2 -0
  79. package/stubs/tailwind.config.js +2 -0
  80. package/stubs/tailwind.config.ts +3 -0
  81. package/types/config.d.ts +8 -7
  82. package/types/generated/colors.d.ts +22 -0
  83. package/types/generated/corePluginList.d.ts +1 -1
  84. package/types/generated/default-theme.d.ts +31 -2
  85. package/lib/constants.js +0 -44
  86. package/src/constants.js +0 -17
  87. /package/stubs/{defaultPostCssConfig.stub.js → postcss.config.cjs} +0 -0
@@ -0,0 +1,31 @@
1
+ import jitiFactory from 'jiti'
2
+ import { transform } from 'sucrase'
3
+
4
+ import { Config } from '../../types/config'
5
+
6
+ let jiti: ReturnType<typeof jitiFactory> | null = null
7
+ function lazyJiti() {
8
+ return (
9
+ jiti ??
10
+ (jiti = jitiFactory(__filename, {
11
+ interopDefault: true,
12
+ transform: (opts) => {
13
+ return transform(opts.source, {
14
+ transforms: ['typescript', 'imports'],
15
+ })
16
+ },
17
+ }))
18
+ )
19
+ }
20
+
21
+ export function loadConfig(path: string): Config {
22
+ let config = (function () {
23
+ try {
24
+ return path ? require(path) : {}
25
+ } catch {
26
+ return lazyJiti()(path)
27
+ }
28
+ })()
29
+
30
+ return config.default ?? config
31
+ }
@@ -931,12 +931,19 @@ function registerPlugins(plugins, context) {
931
931
  prefix(context, 'peer'),
932
932
  ]
933
933
  context.getClassOrder = function getClassOrder(classes) {
934
+ // Sort classes so they're ordered in a deterministic manner
935
+ let sorted = [...classes].sort((a, z) => {
936
+ if (a === z) return 0
937
+ if (a < z) return -1
938
+ return 1
939
+ })
940
+
934
941
  // Non-util classes won't be generated, so we default them to null
935
- let sortedClassNames = new Map(classes.map((className) => [className, null]))
942
+ let sortedClassNames = new Map(sorted.map((className) => [className, null]))
936
943
 
937
944
  // Sort all classes in order
938
945
  // Non-tailwind classes won't be generated and will be left as `null`
939
- let rules = generateRules(new Set(classes), context)
946
+ let rules = generateRules(new Set(sorted), context)
940
947
  rules = context.offsets.sort(rules)
941
948
 
942
949
  let idx = BigInt(parasiteUtilities.length)
@@ -4,13 +4,14 @@ import fs from 'fs'
4
4
  import LRU from 'quick-lru'
5
5
 
6
6
  import hash from '../util/hashConfig'
7
- import getModuleDependencies from '../lib/getModuleDependencies'
8
7
  import resolveConfig from '../public/resolve-config'
9
8
  import resolveConfigPath from '../util/resolveConfigPath'
10
9
  import { getContext, getFileModifiedMap } from './setupContextUtils'
11
10
  import parseDependency from '../util/parseDependency'
12
11
  import { validateConfig } from '../util/validateConfig.js'
13
12
  import { parseCandidateFiles, resolvedChangedContent } from './content.js'
13
+ import { loadConfig } from '../lib/load-config'
14
+ import getModuleDependencies from './getModuleDependencies'
14
15
 
15
16
  let configPathCache = new LRU({ maxSize: 100 })
16
17
 
@@ -34,7 +35,7 @@ function getTailwindConfig(configOrPath) {
34
35
  let [prevConfig, prevConfigHash, prevDeps, prevModified] =
35
36
  configPathCache.get(userConfigPath) || []
36
37
 
37
- let newDeps = getModuleDependencies(userConfigPath).map((dep) => dep.file)
38
+ let newDeps = getModuleDependencies(userConfigPath)
38
39
 
39
40
  let modified = false
40
41
  let newModified = new Map()
@@ -55,8 +56,7 @@ function getTailwindConfig(configOrPath) {
55
56
  for (let file of newDeps) {
56
57
  delete require.cache[file]
57
58
  }
58
- let newConfig = resolveConfig(require(userConfigPath))
59
- newConfig = validateConfig(newConfig)
59
+ let newConfig = validateConfig(resolveConfig(loadConfig(userConfigPath)))
60
60
  let newHash = hash(newConfig)
61
61
  configPathCache.set(userConfigPath, [newConfig, newHash, newDeps, newModified])
62
62
  return [newConfig, userConfigPath, newHash, newDeps]
@@ -1,12 +1,21 @@
1
1
  import pkg from '../../package.json'
2
2
  let OXIDE_DEFAULT_ENABLED = pkg.tailwindcss.engine === 'oxide'
3
3
 
4
- export const env = {
5
- NODE_ENV: process.env.NODE_ENV,
6
- DEBUG: resolveDebug(process.env.DEBUG),
7
- ENGINE: pkg.tailwindcss.engine,
8
- OXIDE: resolveBoolean(process.env.OXIDE, OXIDE_DEFAULT_ENABLED),
9
- }
4
+ export const env =
5
+ typeof process !== 'undefined'
6
+ ? {
7
+ NODE_ENV: process.env.NODE_ENV,
8
+ DEBUG: resolveDebug(process.env.DEBUG),
9
+ ENGINE: pkg.tailwindcss.engine,
10
+ OXIDE: resolveBoolean(process.env.OXIDE, OXIDE_DEFAULT_ENABLED),
11
+ }
12
+ : {
13
+ NODE_ENV: 'production',
14
+ DEBUG: false,
15
+ ENGINE: pkg.tailwindcss.engine,
16
+ OXIDE: OXIDE_DEFAULT_ENABLED,
17
+ }
18
+
10
19
  export const contextMap = new Map()
11
20
  export const configContextMap = new Map()
12
21
  export const contextSourcesMap = new Map()
@@ -1,8 +1,9 @@
1
1
  import fs from 'fs'
2
2
  import path from 'path'
3
+ import { resolveDefaultConfigPath } from '../../../util/resolveConfigPath'
3
4
  import { createProcessor } from './plugin'
4
5
 
5
- export async function build(args, configs) {
6
+ export async function build(args) {
6
7
  let input = args['--input']
7
8
  let shouldWatch = args['--watch']
8
9
 
@@ -23,11 +24,7 @@ export async function build(args, configs) {
23
24
  }
24
25
 
25
26
  // TODO: Reference the @config path here if exists
26
- let configPath = args['--config']
27
- ? args['--config']
28
- : ((defaultPath) => (fs.existsSync(defaultPath) ? defaultPath : null))(
29
- path.resolve(`./${configs.tailwind}`)
30
- )
27
+ let configPath = args['--config'] ? args['--config'] : resolveDefaultConfigPath()
31
28
 
32
29
  let processor = await createProcessor(args, configPath)
33
30
 
@@ -42,6 +39,9 @@ export async function build(args, configs) {
42
39
 
43
40
  await processor.watch()
44
41
  } else {
45
- await processor.build()
42
+ await processor.build().catch((e) => {
43
+ console.error(e)
44
+ process.exit(1)
45
+ })
46
46
  }
47
47
  }
@@ -10,12 +10,14 @@ import { loadPostcss, loadPostcssImport, lightningcss } from './deps'
10
10
  import { formatNodes, drainStdin, outputFile } from './utils'
11
11
  import { env } from '../../../lib/sharedState'
12
12
  import resolveConfig from '../../../../resolveConfig'
13
- import getModuleDependencies from '../../../lib/getModuleDependencies'
14
13
  import { parseCandidateFiles } from '../../../lib/content'
15
14
  import { createWatcher } from './watching'
16
15
  import fastGlob from 'fast-glob'
17
16
  import { findAtConfigPath } from '../../../lib/findAtConfigPath'
18
17
  import log from '../../../util/log'
18
+ import { loadConfig } from '../../../lib/load-config'
19
+ import getModuleDependencies from '../../../lib/getModuleDependencies'
20
+ import type { Config } from '../../../../types'
19
21
 
20
22
  /**
21
23
  *
@@ -115,7 +117,9 @@ let state = {
115
117
  /** @type {{content: string, extension: string}[]} */
116
118
  changedContent: [],
117
119
 
118
- configDependencies: new Set(),
120
+ /** @type {{config: Config, dependencies: Set<string>, dispose: Function } | null} */
121
+ configBag: null,
122
+
119
123
  contextDependencies: new Set(),
120
124
 
121
125
  /** @type {import('../../lib/content.js').ContentPath[]} */
@@ -140,37 +144,35 @@ let state = {
140
144
 
141
145
  loadConfig(configPath, content) {
142
146
  if (this.watcher && configPath) {
143
- this.refreshConfigDependencies(configPath)
147
+ this.refreshConfigDependencies()
144
148
  }
145
149
 
146
- let config = configPath ? require(configPath) : {}
150
+ let config = loadConfig(configPath)
151
+ let dependencies = getModuleDependencies(configPath)
152
+ this.configBag = {
153
+ config,
154
+ dependencies,
155
+ dispose() {
156
+ for (let file of dependencies) {
157
+ delete require.cache[require.resolve(file)]
158
+ }
159
+ },
160
+ }
147
161
 
148
162
  // @ts-ignore
149
- config = resolveConfig(config, { content: { files: [] } })
163
+ this.configBag.config = resolveConfig(this.configBag.config, { content: { files: [] } })
150
164
 
151
165
  // Override content files if `--content` has been passed explicitly
152
166
  if (content?.length > 0) {
153
- config.content.files = content
167
+ this.configBag.config.content.files = content
154
168
  }
155
169
 
156
- return config
170
+ return this.configBag.config
157
171
  },
158
172
 
159
173
  refreshConfigDependencies(configPath) {
160
174
  env.DEBUG && console.time('Module dependencies')
161
-
162
- for (let file of this.configDependencies) {
163
- delete require.cache[require.resolve(file)]
164
- }
165
-
166
- if (configPath) {
167
- let deps = getModuleDependencies(configPath).map(({ file }) => file)
168
-
169
- for (let dependency of deps) {
170
- this.configDependencies.add(dependency)
171
- }
172
- }
173
-
175
+ this.configBag?.dispose()
174
176
  env.DEBUG && console.timeEnd('Module dependencies')
175
177
  },
176
178
 
@@ -380,7 +382,11 @@ export async function createProcessor(args, cliConfigPath) {
380
382
  // The watcher will start watching the imported CSS files and will be
381
383
  // resilient to future errors.
382
384
 
383
- console.error(err)
385
+ if (state.watcher) {
386
+ console.error(err)
387
+ } else {
388
+ return Promise.reject(err)
389
+ }
384
390
  }
385
391
  )
386
392
  }
@@ -413,7 +419,7 @@ export async function createProcessor(args, cliConfigPath) {
413
419
  async rebuild(changes) {
414
420
  let needsNewContext = changes.some((change) => {
415
421
  return (
416
- state.configDependencies.has(change.file) ||
422
+ state.configBag?.dependencies.has(change.file) ||
417
423
  state.contextDependencies.has(change.file)
418
424
  )
419
425
  })
@@ -218,7 +218,7 @@ export function createWatcher(args, { state, rebuild }) {
218
218
 
219
219
  refreshWatchedFiles() {
220
220
  watcher.add(Array.from(state.contextDependencies))
221
- watcher.add(Array.from(state.configDependencies))
221
+ watcher.add(Array.from(state.configBag.dependencies))
222
222
  watcher.add(state.contentPatterns.all)
223
223
  },
224
224
  }
@@ -8,19 +8,6 @@ import { build } from './build'
8
8
  import { help } from './help'
9
9
  import { init } from './init'
10
10
 
11
- function isESM() {
12
- const pkgPath = path.resolve('./package.json')
13
-
14
- try {
15
- let pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
16
- return pkg.type && pkg.type === 'module'
17
- } catch (err) {
18
- return false
19
- }
20
- }
21
-
22
- let configs = isESM() ? { tailwind: 'tailwind.config.cjs' } : { tailwind: 'tailwind.config.js' }
23
-
24
11
  // ---
25
12
 
26
13
  function oneOf(...options) {
@@ -43,7 +30,12 @@ let commands = {
43
30
  init: {
44
31
  run: init,
45
32
  args: {
46
- '--full': { type: Boolean, description: `Initialize a full \`${configs.tailwind}\` file` },
33
+ '--esm': { type: Boolean, description: `Initialize configuration file as ESM` },
34
+ '--ts': { type: Boolean, description: `Initialize configuration file as TypeScript` },
35
+ '--full': {
36
+ type: Boolean,
37
+ description: `Include the default values for all options in the generated configuration file`,
38
+ },
47
39
  '-f': '--full',
48
40
  },
49
41
  },
@@ -209,4 +201,4 @@ if (args['--help']) {
209
201
  process.exit(0)
210
202
  }
211
203
 
212
- run(args, configs)
204
+ run(args)
@@ -1,22 +1,49 @@
1
1
  import fs from 'fs'
2
2
  import path from 'path'
3
3
 
4
- export function init(args, configs) {
5
- let messages = []
4
+ function isESM() {
5
+ const pkgPath = path.resolve('./package.json')
6
+
7
+ try {
8
+ let pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
9
+ return pkg.type && pkg.type === 'module'
10
+ } catch (err) {
11
+ return false
12
+ }
13
+ }
14
+
15
+ export function init(args) {
16
+ let messages: string[] = []
17
+
18
+ let isProjectESM = args['--ts'] || args['--esm'] || isESM()
19
+ let syntax = args['--ts'] ? 'ts' : isProjectESM ? 'js' : 'cjs'
20
+ let extension = args['--ts'] ? 'ts' : 'js'
21
+
22
+ let tailwindConfigLocation = path.resolve(args['_'][1] ?? `./tailwind.config.${extension}`)
6
23
 
7
- let tailwindConfigLocation = path.resolve(args['_'][1] ?? `./${configs.tailwind}`)
8
24
  if (fs.existsSync(tailwindConfigLocation)) {
9
25
  messages.push(`${path.basename(tailwindConfigLocation)} already exists.`)
10
26
  } else {
11
- let stubFile = fs.readFileSync(
27
+ let stubContentsFile = fs.readFileSync(
12
28
  args['--full']
13
- ? path.resolve(__dirname, '../../../../stubs/defaultConfig.stub.js')
14
- : path.resolve(__dirname, '../../../../stubs/simpleConfig.stub.js'),
29
+ ? path.resolve(__dirname, '../../../../stubs/config.full.js')
30
+ : path.resolve(__dirname, '../../../../stubs/config.simple.js'),
31
+ 'utf8'
32
+ )
33
+
34
+ let stubFile = fs.readFileSync(
35
+ path.resolve(__dirname, `../../../../stubs/tailwind.config.${syntax}`),
15
36
  'utf8'
16
37
  )
17
38
 
18
39
  // Change colors import
19
- stubFile = stubFile.replace('../colors', 'tailwindcss/colors')
40
+ stubContentsFile = stubContentsFile.replace('../colors', 'tailwindcss/colors')
41
+
42
+ // Replace contents of {ts,js,cjs} file with the stub {simple,full}.
43
+ stubFile =
44
+ stubFile
45
+ .replace('__CONFIG__', stubContentsFile.replace('module.exports =', '').trim())
46
+ .trim() + '\n\n'
20
47
 
21
48
  fs.writeFileSync(tailwindConfigLocation, stubFile, 'utf8')
22
49
 
@@ -24,6 +24,7 @@ export default {
24
24
  700: '#334155',
25
25
  800: '#1e293b',
26
26
  900: '#0f172a',
27
+ 950: '#020617',
27
28
  },
28
29
  gray: {
29
30
  50: '#f9fafb',
@@ -36,6 +37,7 @@ export default {
36
37
  700: '#374151',
37
38
  800: '#1f2937',
38
39
  900: '#111827',
40
+ 950: '#030712',
39
41
  },
40
42
  zinc: {
41
43
  50: '#fafafa',
@@ -48,6 +50,7 @@ export default {
48
50
  700: '#3f3f46',
49
51
  800: '#27272a',
50
52
  900: '#18181b',
53
+ 950: '#09090b',
51
54
  },
52
55
  neutral: {
53
56
  50: '#fafafa',
@@ -60,6 +63,7 @@ export default {
60
63
  700: '#404040',
61
64
  800: '#262626',
62
65
  900: '#171717',
66
+ 950: '#0a0a0a',
63
67
  },
64
68
  stone: {
65
69
  50: '#fafaf9',
@@ -72,6 +76,7 @@ export default {
72
76
  700: '#44403c',
73
77
  800: '#292524',
74
78
  900: '#1c1917',
79
+ 950: '#0c0a09',
75
80
  },
76
81
  red: {
77
82
  50: '#fef2f2',
@@ -84,6 +89,7 @@ export default {
84
89
  700: '#b91c1c',
85
90
  800: '#991b1b',
86
91
  900: '#7f1d1d',
92
+ 950: '#450a0a',
87
93
  },
88
94
  orange: {
89
95
  50: '#fff7ed',
@@ -96,6 +102,7 @@ export default {
96
102
  700: '#c2410c',
97
103
  800: '#9a3412',
98
104
  900: '#7c2d12',
105
+ 950: '#431407',
99
106
  },
100
107
  amber: {
101
108
  50: '#fffbeb',
@@ -108,6 +115,7 @@ export default {
108
115
  700: '#b45309',
109
116
  800: '#92400e',
110
117
  900: '#78350f',
118
+ 950: '#451a03',
111
119
  },
112
120
  yellow: {
113
121
  50: '#fefce8',
@@ -120,6 +128,7 @@ export default {
120
128
  700: '#a16207',
121
129
  800: '#854d0e',
122
130
  900: '#713f12',
131
+ 950: '#422006',
123
132
  },
124
133
  lime: {
125
134
  50: '#f7fee7',
@@ -132,6 +141,7 @@ export default {
132
141
  700: '#4d7c0f',
133
142
  800: '#3f6212',
134
143
  900: '#365314',
144
+ 950: '#1a2e05',
135
145
  },
136
146
  green: {
137
147
  50: '#f0fdf4',
@@ -144,6 +154,7 @@ export default {
144
154
  700: '#15803d',
145
155
  800: '#166534',
146
156
  900: '#14532d',
157
+ 950: '#052e16',
147
158
  },
148
159
  emerald: {
149
160
  50: '#ecfdf5',
@@ -156,6 +167,7 @@ export default {
156
167
  700: '#047857',
157
168
  800: '#065f46',
158
169
  900: '#064e3b',
170
+ 950: '#022c22',
159
171
  },
160
172
  teal: {
161
173
  50: '#f0fdfa',
@@ -168,6 +180,7 @@ export default {
168
180
  700: '#0f766e',
169
181
  800: '#115e59',
170
182
  900: '#134e4a',
183
+ 950: '#042f2e',
171
184
  },
172
185
  cyan: {
173
186
  50: '#ecfeff',
@@ -180,6 +193,7 @@ export default {
180
193
  700: '#0e7490',
181
194
  800: '#155e75',
182
195
  900: '#164e63',
196
+ 950: '#083344',
183
197
  },
184
198
  sky: {
185
199
  50: '#f0f9ff',
@@ -192,6 +206,7 @@ export default {
192
206
  700: '#0369a1',
193
207
  800: '#075985',
194
208
  900: '#0c4a6e',
209
+ 950: '#082f49',
195
210
  },
196
211
  blue: {
197
212
  50: '#eff6ff',
@@ -204,6 +219,7 @@ export default {
204
219
  700: '#1d4ed8',
205
220
  800: '#1e40af',
206
221
  900: '#1e3a8a',
222
+ 950: '#172554',
207
223
  },
208
224
  indigo: {
209
225
  50: '#eef2ff',
@@ -216,6 +232,7 @@ export default {
216
232
  700: '#4338ca',
217
233
  800: '#3730a3',
218
234
  900: '#312e81',
235
+ 950: '#1e1b4b',
219
236
  },
220
237
  violet: {
221
238
  50: '#f5f3ff',
@@ -228,6 +245,7 @@ export default {
228
245
  700: '#6d28d9',
229
246
  800: '#5b21b6',
230
247
  900: '#4c1d95',
248
+ 950: '#2e1065',
231
249
  },
232
250
  purple: {
233
251
  50: '#faf5ff',
@@ -240,6 +258,7 @@ export default {
240
258
  700: '#7e22ce',
241
259
  800: '#6b21a8',
242
260
  900: '#581c87',
261
+ 950: '#3b0764',
243
262
  },
244
263
  fuchsia: {
245
264
  50: '#fdf4ff',
@@ -252,6 +271,7 @@ export default {
252
271
  700: '#a21caf',
253
272
  800: '#86198f',
254
273
  900: '#701a75',
274
+ 950: '#4a044e',
255
275
  },
256
276
  pink: {
257
277
  50: '#fdf2f8',
@@ -264,6 +284,7 @@ export default {
264
284
  700: '#be185d',
265
285
  800: '#9d174d',
266
286
  900: '#831843',
287
+ 950: '#500724',
267
288
  },
268
289
  rose: {
269
290
  50: '#fff1f2',
@@ -276,6 +297,7 @@ export default {
276
297
  700: '#be123c',
277
298
  800: '#9f1239',
278
299
  900: '#881337',
300
+ 950: '#4c0519',
279
301
  },
280
302
  get lightBlue() {
281
303
  warn({ version: 'v2.2', from: 'lightBlue', to: 'sky' })
@@ -1,4 +1,4 @@
1
1
  import { cloneDeep } from '../util/cloneDeep'
2
- import defaultConfig from '../../stubs/defaultConfig.stub'
2
+ import defaultConfig from '../../stubs/config.full'
3
3
 
4
4
  export default cloneDeep(defaultConfig)
@@ -1,4 +1,4 @@
1
1
  import { cloneDeep } from '../util/cloneDeep'
2
- import defaultConfig from '../../stubs/defaultConfig.stub'
2
+ import defaultFullConfig from '../../stubs/config.full'
3
3
 
4
- export default cloneDeep(defaultConfig.theme)
4
+ export default cloneDeep(defaultFullConfig.theme)
@@ -0,0 +1,2 @@
1
+ import { loadConfig } from '../lib/load-config'
2
+ export default loadConfig
@@ -0,0 +1,30 @@
1
+ import parser from 'postcss-selector-parser'
2
+ import { collectPseudoElements, sortSelector } from './formatVariantSelector.js'
3
+
4
+ export function applyImportantSelector(selector, important) {
5
+ let sel = parser().astSync(selector)
6
+
7
+ sel.each((sel) => {
8
+ // Wrap with :is if it's not already wrapped
9
+ let isWrapped =
10
+ sel.nodes[0].type === 'pseudo' &&
11
+ sel.nodes[0].value === ':is' &&
12
+ sel.nodes.every((node) => node.type !== 'combinator')
13
+
14
+ if (!isWrapped) {
15
+ sel.nodes = [
16
+ parser.pseudo({
17
+ value: ':is',
18
+ nodes: [sel.clone()],
19
+ }),
20
+ ]
21
+ }
22
+
23
+ let [pseudoElements] = collectPseudoElements(sel)
24
+ if (pseudoElements.length > 0) {
25
+ sel.nodes.push(...pseudoElements.sort(sortSelector))
26
+ }
27
+ })
28
+
29
+ return `${important} ${sel.toString()}`
30
+ }
@@ -16,6 +16,10 @@ const placeholderRe = new RegExp(placeholder, 'g')
16
16
  // This is not a data type, but rather a function that can normalize the
17
17
  // correct values.
18
18
  export function normalize(value, isRoot = true) {
19
+ if (value.startsWith('--')) {
20
+ return `var(${value})`
21
+ }
22
+
19
23
  // Keep raw strings if it starts with `url(`
20
24
  if (value.includes('url(')) {
21
25
  return value
@@ -246,9 +246,9 @@ export function finalizeSelector(current, formats, { context, candidate, base })
246
246
 
247
247
  // Move pseudo elements to the end of the selector (if necessary)
248
248
  selector.each((sel) => {
249
- let pseudoElements = collectPseudoElements(sel)
249
+ let [pseudoElements] = collectPseudoElements(sel)
250
250
  if (pseudoElements.length > 0) {
251
- sel.nodes.push(pseudoElements.sort(sortSelector))
251
+ sel.nodes.push(...pseudoElements.sort(sortSelector))
252
252
  }
253
253
  })
254
254
 
@@ -351,23 +351,45 @@ let pseudoElementExceptions = [
351
351
  * `::before:hover` doesn't work, which means that we can make it work for you by flipping the order.
352
352
  *
353
353
  * @param {Selector} selector
354
+ * @param {boolean} force
354
355
  **/
355
- function collectPseudoElements(selector) {
356
+ export function collectPseudoElements(selector, force = false) {
356
357
  /** @type {Node[]} */
357
358
  let nodes = []
359
+ let seenPseudoElement = null
358
360
 
359
- for (let node of selector.nodes) {
360
- if (isPseudoElement(node)) {
361
+ for (let node of [...selector.nodes]) {
362
+ if (isPseudoElement(node, force)) {
361
363
  nodes.push(node)
362
364
  selector.removeChild(node)
365
+ seenPseudoElement = node.value
366
+ } else if (seenPseudoElement !== null) {
367
+ if (pseudoElementExceptions.includes(seenPseudoElement) && isPseudoClass(node, force)) {
368
+ nodes.push(node)
369
+ selector.removeChild(node)
370
+ } else {
371
+ seenPseudoElement = null
372
+ }
363
373
  }
364
374
 
365
375
  if (node?.nodes) {
366
- nodes.push(...collectPseudoElements(node))
376
+ let hasPseudoElementRestrictions =
377
+ node.type === 'pseudo' && (node.value === ':is' || node.value === ':has')
378
+
379
+ let [collected, seenPseudoElementInSelector] = collectPseudoElements(
380
+ node,
381
+ force || hasPseudoElementRestrictions
382
+ )
383
+
384
+ if (seenPseudoElementInSelector) {
385
+ seenPseudoElement = seenPseudoElementInSelector
386
+ }
387
+
388
+ nodes.push(...collected)
367
389
  }
368
390
  }
369
391
 
370
- return nodes
392
+ return [nodes, seenPseudoElement]
371
393
  }
372
394
 
373
395
  // This will make sure to move pseudo's to the correct spot (the end for
@@ -380,7 +402,7 @@ function collectPseudoElements(selector) {
380
402
  //
381
403
  // `::before:hover` doesn't work, which means that we can make it work
382
404
  // for you by flipping the order.
383
- function sortSelector(a, z) {
405
+ export function sortSelector(a, z) {
384
406
  // Both nodes are non-pseudo's so we can safely ignore them and keep
385
407
  // them in the same order.
386
408
  if (a.type !== 'pseudo' && z.type !== 'pseudo') {
@@ -404,9 +426,13 @@ function sortSelector(a, z) {
404
426
  return isPseudoElement(a) - isPseudoElement(z)
405
427
  }
406
428
 
407
- function isPseudoElement(node) {
429
+ function isPseudoElement(node, force = false) {
408
430
  if (node.type !== 'pseudo') return false
409
- if (pseudoElementExceptions.includes(node.value)) return false
431
+ if (pseudoElementExceptions.includes(node.value) && !force) return false
410
432
 
411
433
  return node.value.startsWith('::') || pseudoElementsBC.includes(node.value)
412
434
  }
435
+
436
+ function isPseudoClass(node, force) {
437
+ return node.type === 'pseudo' && !isPseudoElement(node, force)
438
+ }