@unocss/core 0.21.1 → 0.22.2

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
@@ -161,6 +161,7 @@ function hex2rgba(hex = "") {
161
161
 
162
162
  const attributifyRE = /^\[(.+?)~?="(.*)"\]$/;
163
163
  const validateFilterRE = /(?!\d|-{2}|-\d)[a-zA-Z0-9\u00A0-\uFFFF-_:%-?]/;
164
+ const CONTROL_SHORTCUT_NO_MERGE = "$$shortcut-no-merge";
164
165
  function isAttributifySelector(selector) {
165
166
  return selector.match(attributifyRE);
166
167
  }
@@ -387,7 +388,7 @@ function resolveConfig(userConfig = {}, defaults = {}) {
387
388
  };
388
389
  }
389
390
 
390
- const version = "0.21.1";
391
+ const version = "0.22.2";
391
392
 
392
393
  class UnoGenerator {
393
394
  constructor(userConfig = {}, defaults = {}) {
@@ -499,33 +500,38 @@ class UnoGenerator {
499
500
  }
500
501
  const layerCache = {};
501
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
+ }
502
511
  const getLayer = (layer) => {
503
512
  if (layerCache[layer])
504
513
  return layerCache[layer];
505
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]) => {
506
515
  const size = items.length;
507
- 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], !!a[4]?.noMerge]).map((a) => [a[0] == null ? a[0] : [a[0]], a[1], a[2]]);
508
517
  if (!sorted.length)
509
518
  return void 0;
510
- const rules = sorted.reverse().map(([selector, body], idx) => {
519
+ const rules = sorted.reverse().map(([selector, body, noMerge], idx) => {
511
520
  if (selector && this.config.mergeSelectors) {
512
521
  for (let i = idx + 1; i < size; i++) {
513
522
  const current = sorted[i];
514
- if (current && current[0] && current[1] === body) {
515
- current[0] = `${current[0]},${nl}${selector}`;
523
+ if (!noMerge && current && current[0] && current[1] === body) {
524
+ current[0].push(...selector);
516
525
  return null;
517
526
  }
518
527
  }
519
528
  }
520
- return selector ? `${selector}{${body}}` : body;
529
+ return selector ? `${[...new Set(selector)].join(`,${nl}`)}{${body}}` : body;
521
530
  }).filter(Boolean).reverse().join(nl);
522
531
  return parent ? `${parent}{${nl}${rules}${nl}}` : rules;
523
532
  }).filter(Boolean).join(nl);
524
533
  if (preflights) {
525
- css = [
526
- ...this.config.preflights.filter((i) => (i.layer || "default") === layer).map((i) => i.getCSS()).filter(Boolean),
527
- css
528
- ].join(nl);
534
+ css = [preflightsMap[layer], css].filter(Boolean).join(nl);
529
535
  }
530
536
  return layerCache[layer] = !minify && css ? `/* layer: ${layer} */${nl}${css}` : css;
531
537
  };
@@ -684,16 +690,18 @@ class UnoGenerator {
684
690
  continue;
685
691
  const { selector, entries, parent: parent2 } = this.applyVariants(item, [...item[4], ...parentVariants], raw);
686
692
  const mapItem = selectorMap.getFallback(selector, parent2, [[], item[0]]);
687
- mapItem[0].push(...entries);
688
- if (item[0] > mapItem[1])
689
- mapItem[1] = item[0];
693
+ mapItem[0].push(entries);
690
694
  }
691
- return selectorMap.map(([entries, index], selector, mediaQuery) => {
692
- const body = entriesToCss(entries);
693
- if (body)
694
- return [index, selector, body, mediaQuery, meta];
695
- return void 0;
696
- }).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);
697
705
  }
698
706
  isBlocked(raw) {
699
707
  return !raw || this.config.blocklist.some((e2) => typeof e2 === "string" ? e2 === raw : e2.test(raw));
@@ -710,14 +718,15 @@ function applyScope(css, scope) {
710
718
  else
711
719
  return scope ? `${scope} ${css}` : css;
712
720
  }
721
+ const attributifyRe = /^\[(.+?)(~?=)"(.*)"\]$/;
713
722
  function toEscapedSelector(raw) {
714
- if (raw.startsWith("["))
715
- return raw.replace(/^\[(.+?)(~?=)"(.*)"\]$/, (_, n, s, i) => `[${e(n)}${s}"${e(i)}"]`);
716
- else
717
- return `.${e(raw)}`;
723
+ if (raw.startsWith("[") && attributifyRe.test(raw))
724
+ return raw.replace(attributifyRe, (_, n, s, i) => `[${e(n)}${s}"${e(i)}"]`);
725
+ return `.${e(raw)}`;
718
726
  }
719
727
 
720
728
  exports.BetterMap = BetterMap;
729
+ exports.CONTROL_SHORTCUT_NO_MERGE = CONTROL_SHORTCUT_NO_MERGE;
721
730
  exports.TwoKeyMap = TwoKeyMap;
722
731
  exports.UnoGenerator = UnoGenerator;
723
732
  exports.attributifyRE = attributifyRE;
package/dist/index.d.ts CHANGED
@@ -38,7 +38,7 @@ declare type RequiredByKey<T, K extends keyof T = keyof T> = FlatObjectTuple<Req
38
38
  declare type CSSObject = Record<string, string | number | undefined>;
39
39
  declare type CSSEntries = [string, string | number | undefined][];
40
40
  declare type RGBAColorValue = [number, number, number, number] | [number, number, number];
41
- declare type ParsedColorValue = {
41
+ interface ParsedColorValue {
42
42
  /**
43
43
  * Parsed color value.
44
44
  */
@@ -63,7 +63,7 @@ declare type ParsedColorValue = {
63
63
  * Parsed rgba's alpha value.
64
64
  */
65
65
  alpha?: number | string;
66
- };
66
+ }
67
67
  declare type PresetOptions = Record<string, any>;
68
68
  interface RuleContext<Theme extends {} = {}> {
69
69
  /**
@@ -123,6 +123,11 @@ interface RuleMeta {
123
123
  * @default 'default'
124
124
  */
125
125
  layer?: string;
126
+ /**
127
+ * Option to not merge this selector even if the body are the same.
128
+ * @default false
129
+ */
130
+ noMerge?: boolean;
126
131
  /**
127
132
  * Internal rules will only be matched for shortcuts but not the user code.
128
133
  * @default false
@@ -142,7 +147,7 @@ declare type UserShortcuts<Theme extends {} = {}> = StaticShortcutMap | (StaticS
142
147
  declare type Shortcut<Theme extends {} = {}> = StaticShortcut | DynamicShortcut<Theme>;
143
148
  declare type FilterPattern = ReadonlyArray<string | RegExp> | string | RegExp | null;
144
149
  interface Preflight {
145
- getCSS: () => string | undefined;
150
+ getCSS: () => Promise<string | undefined> | string | undefined;
146
151
  layer?: string;
147
152
  }
148
153
  declare type BlocklistRule = string | RegExp;
@@ -169,7 +174,7 @@ interface VariantHandler {
169
174
  order?: number;
170
175
  }
171
176
  declare type VariantFunction<Theme extends {} = {}> = (matcher: string, context: Readonly<VariantContext<Theme>>) => string | VariantHandler | undefined;
172
- declare type VariantObject<Theme extends {} = {}> = {
177
+ interface VariantObject<Theme extends {} = {}> {
173
178
  /**
174
179
  * The entry function to match and rewrite the selector for futher processing.
175
180
  */
@@ -180,7 +185,7 @@ declare type VariantObject<Theme extends {} = {}> = {
180
185
  * @default false
181
186
  */
182
187
  multiPass?: boolean;
183
- };
188
+ }
184
189
  declare type Variant<Theme extends {} = {}> = VariantFunction<Theme> | VariantObject<Theme>;
185
190
  declare type Preprocessor = (matcher: string) => string | undefined;
186
191
  declare type Postprocessor = (util: UtilObject) => void;
@@ -410,6 +415,7 @@ declare function hex2rgba(hex?: string): RGBAColorValue | undefined;
410
415
 
411
416
  declare const attributifyRE: RegExp;
412
417
  declare const validateFilterRE: RegExp;
418
+ declare const CONTROL_SHORTCUT_NO_MERGE = "$$shortcut-no-merge";
413
419
  declare function isAttributifySelector(selector: string): RegExpMatchArray | null;
414
420
  declare function isValidSelector(selector?: string): selector is string;
415
421
  declare function normalizeVariant(variant: Variant): VariantObject;
@@ -452,4 +458,4 @@ declare const extractorSplit: Extractor;
452
458
 
453
459
  declare const extractorSvelte: Extractor;
454
460
 
455
- export { ArgumentType, Arrayable, 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, 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 };
461
+ 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
@@ -157,6 +157,7 @@ function hex2rgba(hex = "") {
157
157
 
158
158
  const attributifyRE = /^\[(.+?)~?="(.*)"\]$/;
159
159
  const validateFilterRE = /(?!\d|-{2}|-\d)[a-zA-Z0-9\u00A0-\uFFFF-_:%-?]/;
160
+ const CONTROL_SHORTCUT_NO_MERGE = "$$shortcut-no-merge";
160
161
  function isAttributifySelector(selector) {
161
162
  return selector.match(attributifyRE);
162
163
  }
@@ -383,7 +384,7 @@ function resolveConfig(userConfig = {}, defaults = {}) {
383
384
  };
384
385
  }
385
386
 
386
- const version = "0.21.1";
387
+ const version = "0.22.2";
387
388
 
388
389
  class UnoGenerator {
389
390
  constructor(userConfig = {}, defaults = {}) {
@@ -495,33 +496,38 @@ class UnoGenerator {
495
496
  }
496
497
  const layerCache = {};
497
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
+ }
498
507
  const getLayer = (layer) => {
499
508
  if (layerCache[layer])
500
509
  return layerCache[layer];
501
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]) => {
502
511
  const size = items.length;
503
- 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], !!a[4]?.noMerge]).map((a) => [a[0] == null ? a[0] : [a[0]], a[1], a[2]]);
504
513
  if (!sorted.length)
505
514
  return void 0;
506
- const rules = sorted.reverse().map(([selector, body], idx) => {
515
+ const rules = sorted.reverse().map(([selector, body, noMerge], idx) => {
507
516
  if (selector && this.config.mergeSelectors) {
508
517
  for (let i = idx + 1; i < size; i++) {
509
518
  const current = sorted[i];
510
- if (current && current[0] && current[1] === body) {
511
- current[0] = `${current[0]},${nl}${selector}`;
519
+ if (!noMerge && current && current[0] && current[1] === body) {
520
+ current[0].push(...selector);
512
521
  return null;
513
522
  }
514
523
  }
515
524
  }
516
- return selector ? `${selector}{${body}}` : body;
525
+ return selector ? `${[...new Set(selector)].join(`,${nl}`)}{${body}}` : body;
517
526
  }).filter(Boolean).reverse().join(nl);
518
527
  return parent ? `${parent}{${nl}${rules}${nl}}` : rules;
519
528
  }).filter(Boolean).join(nl);
520
529
  if (preflights) {
521
- css = [
522
- ...this.config.preflights.filter((i) => (i.layer || "default") === layer).map((i) => i.getCSS()).filter(Boolean),
523
- css
524
- ].join(nl);
530
+ css = [preflightsMap[layer], css].filter(Boolean).join(nl);
525
531
  }
526
532
  return layerCache[layer] = !minify && css ? `/* layer: ${layer} */${nl}${css}` : css;
527
533
  };
@@ -680,16 +686,18 @@ class UnoGenerator {
680
686
  continue;
681
687
  const { selector, entries, parent: parent2 } = this.applyVariants(item, [...item[4], ...parentVariants], raw);
682
688
  const mapItem = selectorMap.getFallback(selector, parent2, [[], item[0]]);
683
- mapItem[0].push(...entries);
684
- if (item[0] > mapItem[1])
685
- mapItem[1] = item[0];
689
+ mapItem[0].push(entries);
686
690
  }
687
- return selectorMap.map(([entries, index], selector, mediaQuery) => {
688
- const body = entriesToCss(entries);
689
- if (body)
690
- return [index, selector, body, mediaQuery, meta];
691
- return void 0;
692
- }).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);
693
701
  }
694
702
  isBlocked(raw) {
695
703
  return !raw || this.config.blocklist.some((e2) => typeof e2 === "string" ? e2 === raw : e2.test(raw));
@@ -706,11 +714,11 @@ function applyScope(css, scope) {
706
714
  else
707
715
  return scope ? `${scope} ${css}` : css;
708
716
  }
717
+ const attributifyRe = /^\[(.+?)(~?=)"(.*)"\]$/;
709
718
  function toEscapedSelector(raw) {
710
- if (raw.startsWith("["))
711
- return raw.replace(/^\[(.+?)(~?=)"(.*)"\]$/, (_, n, s, i) => `[${e(n)}${s}"${e(i)}"]`);
712
- else
713
- return `.${e(raw)}`;
719
+ if (raw.startsWith("[") && attributifyRe.test(raw))
720
+ return raw.replace(attributifyRe, (_, n, s, i) => `[${e(n)}${s}"${e(i)}"]`);
721
+ return `.${e(raw)}`;
714
722
  }
715
723
 
716
- export { BetterMap, 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 };
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.21.1",
3
+ "version": "0.22.2",
4
4
  "description": "The instant on-demand Atomic CSS engine.",
5
5
  "keywords": [
6
6
  "unocss",