@unocss/core 0.20.4 → 0.22.0

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.
package/dist/index.cjs CHANGED
@@ -93,6 +93,32 @@ function mergeDeep(original, patch) {
93
93
  }
94
94
  return output;
95
95
  }
96
+ function clone(val) {
97
+ let k, out, tmp;
98
+ if (Array.isArray(val)) {
99
+ out = Array(k = val.length);
100
+ while (k--)
101
+ out[k] = (tmp = val[k]) && typeof tmp === "object" ? clone(tmp) : tmp;
102
+ return out;
103
+ }
104
+ if (Object.prototype.toString.call(val) === "[object Object]") {
105
+ out = {};
106
+ for (k in val) {
107
+ if (k === "__proto__") {
108
+ Object.defineProperty(out, k, {
109
+ value: clone(val[k]),
110
+ configurable: true,
111
+ enumerable: true,
112
+ writable: true
113
+ });
114
+ } else {
115
+ out[k] = (tmp = val[k]) && typeof tmp === "object" ? clone(tmp) : tmp;
116
+ }
117
+ }
118
+ return out;
119
+ }
120
+ return val;
121
+ }
96
122
  function isStaticRule(rule) {
97
123
  return typeof rule[0] === "string";
98
124
  }
@@ -135,6 +161,7 @@ function hex2rgba(hex = "") {
135
161
 
136
162
  const attributifyRE = /^\[(.+?)~?="(.*)"\]$/;
137
163
  const validateFilterRE = /(?!\d|-{2}|-\d)[a-zA-Z0-9\u00A0-\uFFFF-_:%-?]/;
164
+ const CONTROL_SHORTCUT_NO_MERGE = "$$shortcut-no-merge";
138
165
  function isAttributifySelector(selector) {
139
166
  return selector.match(attributifyRE);
140
167
  }
@@ -332,11 +359,11 @@ function resolveConfig(userConfig = {}, defaults = {}) {
332
359
  delete rules[i];
333
360
  }
334
361
  });
335
- const theme = [
362
+ const theme = clone([
336
363
  ...sortedPresets.map((p) => p.theme || {}),
337
364
  config.theme || {}
338
- ].reduce((a, p) => mergeDeep(a, p), {});
339
- const options = Object.assign({}, ...config.presets?.map((p) => Array.isArray(p) ? p : [p]).flat(1).map((p) => p.options ?? {}) || []);
365
+ ].reduce((a, p) => mergeDeep(a, p), {}));
366
+ mergePresets("extendTheme").forEach((extendTheme) => extendTheme(theme));
340
367
  return {
341
368
  mergeSelectors: true,
342
369
  warn: true,
@@ -357,12 +384,11 @@ function resolveConfig(userConfig = {}, defaults = {}) {
357
384
  preflights: mergePresets("preflights"),
358
385
  variants: mergePresets("variants").map(normalizeVariant),
359
386
  shortcuts: resolveShortcuts(mergePresets("shortcuts")),
360
- extractors,
361
- options
387
+ extractors
362
388
  };
363
389
  }
364
390
 
365
- const version = "0.20.4";
391
+ const version = "0.22.0";
366
392
 
367
393
  class UnoGenerator {
368
394
  constructor(userConfig = {}, defaults = {}) {
@@ -391,8 +417,7 @@ class UnoGenerator {
391
417
  return code;
392
418
  },
393
419
  code,
394
- id,
395
- options: this.config.options
420
+ id
396
421
  };
397
422
  for (const extractor of this.config.extractors) {
398
423
  const result = await extractor.extract(context);
@@ -453,8 +478,7 @@ class UnoGenerator {
453
478
  theme: this.config.theme,
454
479
  generator: this,
455
480
  variantHandlers: applied[2],
456
- constructCSS: (...args) => this.constructCustomCSS(context, ...args),
457
- options: this.config.options
481
+ constructCSS: (...args) => this.constructCustomCSS(context, ...args)
458
482
  };
459
483
  const expanded = this.expandShortcut(applied[1], context);
460
484
  if (expanded) {
@@ -476,12 +500,20 @@ class UnoGenerator {
476
500
  }
477
501
  const layerCache = {};
478
502
  const layers = this.config.sortLayers(Array.from(layerSet).sort((a, b) => (this.config.layers[a] ?? 0) - (this.config.layers[b] ?? 0) || a.localeCompare(b)));
503
+ let preflightsMap = {};
504
+ if (preflights) {
505
+ preflightsMap = Object.fromEntries(await Promise.all(layers.map(async (layer) => {
506
+ const preflights2 = await Promise.all(this.config.preflights.filter((i) => (i.layer || "default") === layer).map(async (i) => await i.getCSS()));
507
+ const css = preflights2.filter(Boolean).join(nl);
508
+ return [layer, css];
509
+ })));
510
+ }
479
511
  const getLayer = (layer) => {
480
512
  if (layerCache[layer])
481
513
  return layerCache[layer];
482
514
  let css = Array.from(sheet).sort((a, b) => (this.parentOrders.get(a[0]) ?? 0) - (this.parentOrders.get(b[0]) ?? 0) || a[0]?.localeCompare(b[0] || "") || 0).map(([parent, items]) => {
483
515
  const size = items.length;
484
- const sorted = items.filter((i) => (i[4]?.layer || "default") === layer).sort((a, b) => a[0] - b[0] || a[1]?.localeCompare(b[1] || "") || 0).map((a) => [a[1] ? applyScope(a[1], scope) : a[1], a[2]]);
516
+ const sorted = items.filter((i) => (i[4]?.layer || "default") === layer).sort((a, b) => a[0] - b[0] || a[1]?.localeCompare(b[1] || "") || 0).map((a) => [a[1] ? applyScope(a[1], scope) : a[1], a[2]]).map((a) => [a[0] == null ? a[0] : [a[0]], a[1]]);
485
517
  if (!sorted.length)
486
518
  return void 0;
487
519
  const rules = sorted.reverse().map(([selector, body], idx) => {
@@ -489,20 +521,17 @@ class UnoGenerator {
489
521
  for (let i = idx + 1; i < size; i++) {
490
522
  const current = sorted[i];
491
523
  if (current && current[0] && current[1] === body) {
492
- current[0] = `${current[0]},${nl}${selector}`;
524
+ current[0].push(...selector);
493
525
  return null;
494
526
  }
495
527
  }
496
528
  }
497
- return selector ? `${selector}{${body}}` : body;
529
+ return selector ? `${[...new Set(selector)].join(`,${nl}`)}{${body}}` : body;
498
530
  }).filter(Boolean).reverse().join(nl);
499
531
  return parent ? `${parent}{${nl}${rules}${nl}}` : rules;
500
532
  }).filter(Boolean).join(nl);
501
533
  if (preflights) {
502
- css = [
503
- ...this.config.preflights.filter((i) => (i.layer || "default") === layer).map((i) => i.getCSS()).filter(Boolean),
504
- css
505
- ].join(nl);
534
+ css = [preflightsMap[layer], css].filter(Boolean).join(nl);
506
535
  }
507
536
  return layerCache[layer] = !minify && css ? `/* layer: ${layer} */${nl}${css}` : css;
508
537
  };
@@ -527,8 +556,7 @@ class UnoGenerator {
527
556
  const context = {
528
557
  rawSelector: raw,
529
558
  theme: this.config.theme,
530
- generator: this,
531
- options: this.config.options
559
+ generator: this
532
560
  };
533
561
  while (true) {
534
562
  applied = false;
@@ -662,16 +690,18 @@ class UnoGenerator {
662
690
  continue;
663
691
  const { selector, entries, parent: parent2 } = this.applyVariants(item, [...item[4], ...parentVariants], raw);
664
692
  const mapItem = selectorMap.getFallback(selector, parent2, [[], item[0]]);
665
- mapItem[0].push(...entries);
666
- if (item[0] > mapItem[1])
667
- mapItem[1] = item[0];
693
+ mapItem[0].push(entries);
668
694
  }
669
- return selectorMap.map(([entries, index], selector, mediaQuery) => {
670
- const body = entriesToCss(entries);
671
- if (body)
672
- return [index, selector, body, mediaQuery, meta];
673
- return void 0;
674
- }).filter(Boolean);
695
+ return selectorMap.map(([e2, index], selector, mediaQuery) => {
696
+ const split = e2.filter((entries) => entries.some((entry) => entry[0] === CONTROL_SHORTCUT_NO_MERGE));
697
+ const rest = e2.filter((entries) => entries.every((entry) => entry[0] !== CONTROL_SHORTCUT_NO_MERGE));
698
+ return [...split, rest.flat(1)].map((entries) => {
699
+ const body = entriesToCss(entries);
700
+ if (body)
701
+ return [index, selector, body, mediaQuery, meta];
702
+ return void 0;
703
+ });
704
+ }).flat(1).filter(Boolean);
675
705
  }
676
706
  isBlocked(raw) {
677
707
  return !raw || this.config.blocklist.some((e2) => typeof e2 === "string" ? e2 === raw : e2.test(raw));
@@ -696,10 +726,12 @@ function toEscapedSelector(raw) {
696
726
  }
697
727
 
698
728
  exports.BetterMap = BetterMap;
729
+ exports.CONTROL_SHORTCUT_NO_MERGE = CONTROL_SHORTCUT_NO_MERGE;
699
730
  exports.TwoKeyMap = TwoKeyMap;
700
731
  exports.UnoGenerator = UnoGenerator;
701
732
  exports.attributifyRE = attributifyRE;
702
733
  exports.clearIdenticalEntries = clearIdenticalEntries;
734
+ exports.clone = clone;
703
735
  exports.createGenerator = createGenerator;
704
736
  exports.createValueHandler = createValueHandler;
705
737
  exports.e = e;
package/dist/index.d.ts CHANGED
@@ -23,6 +23,7 @@ declare function createGenerator(config?: UserConfig, defaults?: UserConfigDefau
23
23
  declare const hasScopePlaceholder: (css: string) => RegExpMatchArray | null;
24
24
 
25
25
  declare type Awaitable<T> = T | Promise<T>;
26
+ declare type Arrayable<T> = T | T[];
26
27
  declare type ArgumentType<T> = T extends ((...args: infer A) => any) ? A : never;
27
28
  declare type Shift<T> = T extends [_: any, ...args: infer A] ? A : never;
28
29
  declare type RestArgs<T> = Shift<ArgumentType<T>>;
@@ -37,7 +38,7 @@ declare type RequiredByKey<T, K extends keyof T = keyof T> = FlatObjectTuple<Req
37
38
  declare type CSSObject = Record<string, string | number | undefined>;
38
39
  declare type CSSEntries = [string, string | number | undefined][];
39
40
  declare type RGBAColorValue = [number, number, number, number] | [number, number, number];
40
- declare type ParsedColorValue = {
41
+ interface ParsedColorValue {
41
42
  /**
42
43
  * Parsed color value.
43
44
  */
@@ -62,7 +63,7 @@ declare type ParsedColorValue = {
62
63
  * Parsed rgba's alpha value.
63
64
  */
64
65
  alpha?: number | string;
65
- };
66
+ }
66
67
  declare type PresetOptions = Record<string, any>;
67
68
  interface RuleContext<Theme extends {} = {}> {
68
69
  /**
@@ -91,10 +92,6 @@ interface RuleContext<Theme extends {} = {}> {
91
92
  * Variants and selector escaping will be handled automatically.
92
93
  */
93
94
  constructCSS: (body: CSSEntries | CSSObject, overrideSelector?: string) => string;
94
- /**
95
- * User-provided options from preset.
96
- */
97
- readonly options: PresetOptions;
98
95
  }
99
96
  interface VariantContext<Theme extends {} = {}> {
100
97
  /**
@@ -109,16 +106,11 @@ interface VariantContext<Theme extends {} = {}> {
109
106
  * The theme object
110
107
  */
111
108
  theme: Theme;
112
- /**
113
- * User-provided options from preset.
114
- */
115
- readonly options: PresetOptions;
116
109
  }
117
110
  interface ExtractorContext {
118
111
  readonly original: string;
119
112
  code: string;
120
113
  id?: string;
121
- readonly options: PresetOptions;
122
114
  }
123
115
  interface Extractor {
124
116
  name: string;
@@ -150,7 +142,7 @@ declare type UserShortcuts<Theme extends {} = {}> = StaticShortcutMap | (StaticS
150
142
  declare type Shortcut<Theme extends {} = {}> = StaticShortcut | DynamicShortcut<Theme>;
151
143
  declare type FilterPattern = ReadonlyArray<string | RegExp> | string | RegExp | null;
152
144
  interface Preflight {
153
- getCSS: () => string | undefined;
145
+ getCSS: () => Promise<string | undefined> | string | undefined;
154
146
  layer?: string;
155
147
  }
156
148
  declare type BlocklistRule = string | RegExp;
@@ -177,7 +169,7 @@ interface VariantHandler {
177
169
  order?: number;
178
170
  }
179
171
  declare type VariantFunction<Theme extends {} = {}> = (matcher: string, context: Readonly<VariantContext<Theme>>) => string | VariantHandler | undefined;
180
- declare type VariantObject<Theme extends {} = {}> = {
172
+ interface VariantObject<Theme extends {} = {}> {
181
173
  /**
182
174
  * The entry function to match and rewrite the selector for futher processing.
183
175
  */
@@ -188,10 +180,11 @@ declare type VariantObject<Theme extends {} = {}> = {
188
180
  * @default false
189
181
  */
190
182
  multiPass?: boolean;
191
- };
183
+ }
192
184
  declare type Variant<Theme extends {} = {}> = VariantFunction<Theme> | VariantObject<Theme>;
193
185
  declare type Preprocessor = (matcher: string) => string | undefined;
194
186
  declare type Postprocessor = (util: UtilObject) => void;
187
+ declare type ThemeExtender<T> = (theme: T) => void;
195
188
  interface ConfigBase<Theme extends {} = {}> {
196
189
  /**
197
190
  * Rules to generate CSS utilities
@@ -240,11 +233,15 @@ interface ConfigBase<Theme extends {} = {}> {
240
233
  /**
241
234
  * Preprocess the incoming utilities, return falsy value to exclude
242
235
  */
243
- preprocess?: Preprocessor | Preprocessor[];
236
+ preprocess?: Arrayable<Preprocessor>;
244
237
  /**
245
238
  * Process the generate utils object
246
239
  */
247
- postprocess?: Postprocessor | Postprocessor[];
240
+ postprocess?: Arrayable<Postprocessor>;
241
+ /**
242
+ * Custom functions to extend the theme object
243
+ */
244
+ extendTheme?: Arrayable<ThemeExtender<Theme>>;
248
245
  }
249
246
  interface Preset<Theme extends {} = {}> extends ConfigBase<Theme> {
250
247
  name: string;
@@ -325,7 +322,6 @@ interface ResolvedConfig extends Omit<RequiredByKey<UserConfig, 'mergeSelectors'
325
322
  rulesSize: number;
326
323
  rulesDynamic: (DynamicRule | undefined)[];
327
324
  rulesStaticMap: Record<string, [number, CSSObject | CSSEntries, RuleMeta | undefined] | undefined>;
328
- options: PresetOptions;
329
325
  }
330
326
  interface GenerateResult {
331
327
  css: string;
@@ -402,6 +398,7 @@ declare function clearIdenticalEntries(entry: CSSEntries): CSSEntries;
402
398
  declare function entriesToCss(arr?: CSSEntries): string;
403
399
  declare function isObject(item: any): item is Record<string, any>;
404
400
  declare function mergeDeep<T>(original: T, patch: DeepPartial<T>): T;
401
+ declare function clone<T>(val: T): T;
405
402
  declare function isStaticRule(rule: Rule): rule is StaticRule;
406
403
  declare function isStaticShortcut(sc: Shortcut): sc is StaticShortcut;
407
404
 
@@ -413,6 +410,7 @@ declare function hex2rgba(hex?: string): RGBAColorValue | undefined;
413
410
 
414
411
  declare const attributifyRE: RegExp;
415
412
  declare const validateFilterRE: RegExp;
413
+ declare const CONTROL_SHORTCUT_NO_MERGE = "$$shortcut-no-merge";
416
414
  declare function isAttributifySelector(selector: string): RegExpMatchArray | null;
417
415
  declare function isValidSelector(selector?: string): selector is string;
418
416
  declare function normalizeVariant(variant: Variant): VariantObject;
@@ -455,4 +453,4 @@ declare const extractorSplit: Extractor;
455
453
 
456
454
  declare const extractorSvelte: Extractor;
457
455
 
458
- export { ArgumentType, Awaitable, BetterMap, BlocklistRule, CSSEntries, CSSObject, CSSValues, ConfigBase, DeepPartial, DynamicMatcher, DynamicRule, DynamicShortcut, DynamicShortcutMatcher, Extractor, ExtractorContext, FilterPattern, FlatObjectTuple, GenerateOptions, GenerateResult, GeneratorOptions, ParsedColorValue, ParsedUtil, PartialByKeys, PluginOptions, Postprocessor, Preflight, Preprocessor, Preset, PresetOptions, RGBAColorValue, RawUtil, RequiredByKey, ResolvedConfig, RestArgs, Rule, RuleContext, RuleMeta, Shift, Shortcut, StaticRule, StaticShortcut, StaticShortcutMap, StringifiedUtil, TwoKeyMap, UnoGenerator, UserConfig, UserConfigDefaults, UserOnlyOptions, UserShortcuts, UtilObject, ValueHandler, ValueHandlerCallback, Variant, VariantContext, VariantFunction, VariantHandler, VariantMatchedResult, VariantObject, attributifyRE, clearIdenticalEntries, createGenerator, createValueHandler, e, entriesToCss, escapeRegExp, escapeSelector, expandVariantGroup, extractorSplit, extractorSvelte, hasScopePlaceholder, hex2rgba, isAttributifySelector, isObject, isRawUtil, isStaticRule, isStaticShortcut, isValidSelector, mergeDeep, mergeSet, normalizeCSSEntries, normalizeCSSValues, normalizeVariant, notNull, regexClassGroup, toArray, uniq, validateFilterRE, warnOnce, withLayer };
456
+ export { ArgumentType, Arrayable, Awaitable, BetterMap, BlocklistRule, CONTROL_SHORTCUT_NO_MERGE, CSSEntries, CSSObject, CSSValues, ConfigBase, DeepPartial, DynamicMatcher, DynamicRule, DynamicShortcut, DynamicShortcutMatcher, Extractor, ExtractorContext, FilterPattern, FlatObjectTuple, GenerateOptions, GenerateResult, GeneratorOptions, ParsedColorValue, ParsedUtil, PartialByKeys, PluginOptions, Postprocessor, Preflight, Preprocessor, Preset, PresetOptions, RGBAColorValue, RawUtil, RequiredByKey, ResolvedConfig, RestArgs, Rule, RuleContext, RuleMeta, Shift, Shortcut, StaticRule, StaticShortcut, StaticShortcutMap, StringifiedUtil, ThemeExtender, TwoKeyMap, UnoGenerator, UserConfig, UserConfigDefaults, UserOnlyOptions, UserShortcuts, UtilObject, ValueHandler, ValueHandlerCallback, Variant, VariantContext, VariantFunction, VariantHandler, VariantMatchedResult, VariantObject, attributifyRE, clearIdenticalEntries, clone, createGenerator, createValueHandler, e, entriesToCss, escapeRegExp, escapeSelector, expandVariantGroup, extractorSplit, extractorSvelte, hasScopePlaceholder, hex2rgba, isAttributifySelector, isObject, isRawUtil, isStaticRule, isStaticShortcut, isValidSelector, mergeDeep, mergeSet, normalizeCSSEntries, normalizeCSSValues, normalizeVariant, notNull, regexClassGroup, toArray, uniq, validateFilterRE, warnOnce, withLayer };
package/dist/index.mjs CHANGED
@@ -89,6 +89,32 @@ function mergeDeep(original, patch) {
89
89
  }
90
90
  return output;
91
91
  }
92
+ function clone(val) {
93
+ let k, out, tmp;
94
+ if (Array.isArray(val)) {
95
+ out = Array(k = val.length);
96
+ while (k--)
97
+ out[k] = (tmp = val[k]) && typeof tmp === "object" ? clone(tmp) : tmp;
98
+ return out;
99
+ }
100
+ if (Object.prototype.toString.call(val) === "[object Object]") {
101
+ out = {};
102
+ for (k in val) {
103
+ if (k === "__proto__") {
104
+ Object.defineProperty(out, k, {
105
+ value: clone(val[k]),
106
+ configurable: true,
107
+ enumerable: true,
108
+ writable: true
109
+ });
110
+ } else {
111
+ out[k] = (tmp = val[k]) && typeof tmp === "object" ? clone(tmp) : tmp;
112
+ }
113
+ }
114
+ return out;
115
+ }
116
+ return val;
117
+ }
92
118
  function isStaticRule(rule) {
93
119
  return typeof rule[0] === "string";
94
120
  }
@@ -131,6 +157,7 @@ function hex2rgba(hex = "") {
131
157
 
132
158
  const attributifyRE = /^\[(.+?)~?="(.*)"\]$/;
133
159
  const validateFilterRE = /(?!\d|-{2}|-\d)[a-zA-Z0-9\u00A0-\uFFFF-_:%-?]/;
160
+ const CONTROL_SHORTCUT_NO_MERGE = "$$shortcut-no-merge";
134
161
  function isAttributifySelector(selector) {
135
162
  return selector.match(attributifyRE);
136
163
  }
@@ -328,11 +355,11 @@ function resolveConfig(userConfig = {}, defaults = {}) {
328
355
  delete rules[i];
329
356
  }
330
357
  });
331
- const theme = [
358
+ const theme = clone([
332
359
  ...sortedPresets.map((p) => p.theme || {}),
333
360
  config.theme || {}
334
- ].reduce((a, p) => mergeDeep(a, p), {});
335
- const options = Object.assign({}, ...config.presets?.map((p) => Array.isArray(p) ? p : [p]).flat(1).map((p) => p.options ?? {}) || []);
361
+ ].reduce((a, p) => mergeDeep(a, p), {}));
362
+ mergePresets("extendTheme").forEach((extendTheme) => extendTheme(theme));
336
363
  return {
337
364
  mergeSelectors: true,
338
365
  warn: true,
@@ -353,12 +380,11 @@ function resolveConfig(userConfig = {}, defaults = {}) {
353
380
  preflights: mergePresets("preflights"),
354
381
  variants: mergePresets("variants").map(normalizeVariant),
355
382
  shortcuts: resolveShortcuts(mergePresets("shortcuts")),
356
- extractors,
357
- options
383
+ extractors
358
384
  };
359
385
  }
360
386
 
361
- const version = "0.20.4";
387
+ const version = "0.22.0";
362
388
 
363
389
  class UnoGenerator {
364
390
  constructor(userConfig = {}, defaults = {}) {
@@ -387,8 +413,7 @@ class UnoGenerator {
387
413
  return code;
388
414
  },
389
415
  code,
390
- id,
391
- options: this.config.options
416
+ id
392
417
  };
393
418
  for (const extractor of this.config.extractors) {
394
419
  const result = await extractor.extract(context);
@@ -449,8 +474,7 @@ class UnoGenerator {
449
474
  theme: this.config.theme,
450
475
  generator: this,
451
476
  variantHandlers: applied[2],
452
- constructCSS: (...args) => this.constructCustomCSS(context, ...args),
453
- options: this.config.options
477
+ constructCSS: (...args) => this.constructCustomCSS(context, ...args)
454
478
  };
455
479
  const expanded = this.expandShortcut(applied[1], context);
456
480
  if (expanded) {
@@ -472,12 +496,20 @@ class UnoGenerator {
472
496
  }
473
497
  const layerCache = {};
474
498
  const layers = this.config.sortLayers(Array.from(layerSet).sort((a, b) => (this.config.layers[a] ?? 0) - (this.config.layers[b] ?? 0) || a.localeCompare(b)));
499
+ let preflightsMap = {};
500
+ if (preflights) {
501
+ preflightsMap = Object.fromEntries(await Promise.all(layers.map(async (layer) => {
502
+ const preflights2 = await Promise.all(this.config.preflights.filter((i) => (i.layer || "default") === layer).map(async (i) => await i.getCSS()));
503
+ const css = preflights2.filter(Boolean).join(nl);
504
+ return [layer, css];
505
+ })));
506
+ }
475
507
  const getLayer = (layer) => {
476
508
  if (layerCache[layer])
477
509
  return layerCache[layer];
478
510
  let css = Array.from(sheet).sort((a, b) => (this.parentOrders.get(a[0]) ?? 0) - (this.parentOrders.get(b[0]) ?? 0) || a[0]?.localeCompare(b[0] || "") || 0).map(([parent, items]) => {
479
511
  const size = items.length;
480
- const sorted = items.filter((i) => (i[4]?.layer || "default") === layer).sort((a, b) => a[0] - b[0] || a[1]?.localeCompare(b[1] || "") || 0).map((a) => [a[1] ? applyScope(a[1], scope) : a[1], a[2]]);
512
+ const sorted = items.filter((i) => (i[4]?.layer || "default") === layer).sort((a, b) => a[0] - b[0] || a[1]?.localeCompare(b[1] || "") || 0).map((a) => [a[1] ? applyScope(a[1], scope) : a[1], a[2]]).map((a) => [a[0] == null ? a[0] : [a[0]], a[1]]);
481
513
  if (!sorted.length)
482
514
  return void 0;
483
515
  const rules = sorted.reverse().map(([selector, body], idx) => {
@@ -485,20 +517,17 @@ class UnoGenerator {
485
517
  for (let i = idx + 1; i < size; i++) {
486
518
  const current = sorted[i];
487
519
  if (current && current[0] && current[1] === body) {
488
- current[0] = `${current[0]},${nl}${selector}`;
520
+ current[0].push(...selector);
489
521
  return null;
490
522
  }
491
523
  }
492
524
  }
493
- return selector ? `${selector}{${body}}` : body;
525
+ return selector ? `${[...new Set(selector)].join(`,${nl}`)}{${body}}` : body;
494
526
  }).filter(Boolean).reverse().join(nl);
495
527
  return parent ? `${parent}{${nl}${rules}${nl}}` : rules;
496
528
  }).filter(Boolean).join(nl);
497
529
  if (preflights) {
498
- css = [
499
- ...this.config.preflights.filter((i) => (i.layer || "default") === layer).map((i) => i.getCSS()).filter(Boolean),
500
- css
501
- ].join(nl);
530
+ css = [preflightsMap[layer], css].filter(Boolean).join(nl);
502
531
  }
503
532
  return layerCache[layer] = !minify && css ? `/* layer: ${layer} */${nl}${css}` : css;
504
533
  };
@@ -523,8 +552,7 @@ class UnoGenerator {
523
552
  const context = {
524
553
  rawSelector: raw,
525
554
  theme: this.config.theme,
526
- generator: this,
527
- options: this.config.options
555
+ generator: this
528
556
  };
529
557
  while (true) {
530
558
  applied = false;
@@ -658,16 +686,18 @@ class UnoGenerator {
658
686
  continue;
659
687
  const { selector, entries, parent: parent2 } = this.applyVariants(item, [...item[4], ...parentVariants], raw);
660
688
  const mapItem = selectorMap.getFallback(selector, parent2, [[], item[0]]);
661
- mapItem[0].push(...entries);
662
- if (item[0] > mapItem[1])
663
- mapItem[1] = item[0];
689
+ mapItem[0].push(entries);
664
690
  }
665
- return selectorMap.map(([entries, index], selector, mediaQuery) => {
666
- const body = entriesToCss(entries);
667
- if (body)
668
- return [index, selector, body, mediaQuery, meta];
669
- return void 0;
670
- }).filter(Boolean);
691
+ return selectorMap.map(([e2, index], selector, mediaQuery) => {
692
+ const split = e2.filter((entries) => entries.some((entry) => entry[0] === CONTROL_SHORTCUT_NO_MERGE));
693
+ const rest = e2.filter((entries) => entries.every((entry) => entry[0] !== CONTROL_SHORTCUT_NO_MERGE));
694
+ return [...split, rest.flat(1)].map((entries) => {
695
+ const body = entriesToCss(entries);
696
+ if (body)
697
+ return [index, selector, body, mediaQuery, meta];
698
+ return void 0;
699
+ });
700
+ }).flat(1).filter(Boolean);
671
701
  }
672
702
  isBlocked(raw) {
673
703
  return !raw || this.config.blocklist.some((e2) => typeof e2 === "string" ? e2 === raw : e2.test(raw));
@@ -691,4 +721,4 @@ function toEscapedSelector(raw) {
691
721
  return `.${e(raw)}`;
692
722
  }
693
723
 
694
- export { BetterMap, TwoKeyMap, UnoGenerator, attributifyRE, clearIdenticalEntries, createGenerator, createValueHandler, e, entriesToCss, escapeRegExp, escapeSelector, expandVariantGroup, extractorSplit, extractorSvelte, hasScopePlaceholder, hex2rgba, isAttributifySelector, isObject, isRawUtil, isStaticRule, isStaticShortcut, isValidSelector, mergeDeep, mergeSet, normalizeCSSEntries, normalizeCSSValues, normalizeVariant, notNull, regexClassGroup, toArray, uniq, validateFilterRE, warnOnce, withLayer };
724
+ export { BetterMap, CONTROL_SHORTCUT_NO_MERGE, TwoKeyMap, UnoGenerator, attributifyRE, clearIdenticalEntries, clone, createGenerator, createValueHandler, e, entriesToCss, escapeRegExp, escapeSelector, expandVariantGroup, extractorSplit, extractorSvelte, hasScopePlaceholder, hex2rgba, isAttributifySelector, isObject, isRawUtil, isStaticRule, isStaticShortcut, isValidSelector, mergeDeep, mergeSet, normalizeCSSEntries, normalizeCSSValues, normalizeVariant, notNull, regexClassGroup, toArray, uniq, validateFilterRE, warnOnce, withLayer };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unocss/core",
3
- "version": "0.20.4",
3
+ "version": "0.22.0",
4
4
  "description": "The instant on-demand Atomic CSS engine.",
5
5
  "keywords": [
6
6
  "unocss",