@pikacss/core 0.0.40 → 0.0.42

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
@@ -752,6 +752,12 @@ function normalizeVariableName(name) {
752
752
 
753
753
  //#endregion
754
754
  //#region src/internal/engine.ts
755
+ const DEFAULT_PREFLIGHTS_LAYER = "preflights";
756
+ const DEFAULT_UTILITIES_LAYER = "utilities";
757
+ const DEFAULT_LAYERS = {
758
+ [DEFAULT_PREFLIGHTS_LAYER]: 1,
759
+ [DEFAULT_UTILITIES_LAYER]: 10
760
+ };
755
761
  async function createEngine(config = {}) {
756
762
  log.debug("Creating engine with config:", config);
757
763
  const corePlugins = [
@@ -771,6 +777,8 @@ async function createEngine(config = {}) {
771
777
  log.debug("Engine config resolved with prefix:", resolvedConfig.prefix);
772
778
  resolvedConfig = await hooks.configureResolvedConfig(resolvedConfig.plugins, resolvedConfig);
773
779
  let engine = new Engine(resolvedConfig);
780
+ engine.appendAutocompleteExtraProperties("__layer");
781
+ engine.appendAutocompletePropertyValues("__layer", "Autocomplete['Layer']");
774
782
  log.debug("Engine instance created");
775
783
  engine = await hooks.configureEngine(engine.config.plugins, engine);
776
784
  log.debug("Engine initialized successfully");
@@ -863,17 +871,39 @@ var Engine = class {
863
871
  async renderPreflights(isFormatted) {
864
872
  log.debug("Rendering preflights...");
865
873
  const lineEnd = isFormatted ? "\n" : "";
866
- const results = await Promise.all(this.config.preflights.map(async (p) => {
867
- const result = await p(this, isFormatted);
868
- if (typeof result === "string") return result;
869
- return renderPreflightDefinition({
870
- engine: this,
871
- preflightDefinition: result,
872
- isFormatted
873
- });
874
+ const rendered = await Promise.all(this.config.preflights.map(async ({ layer, fn }) => {
875
+ const result = await fn(this, isFormatted);
876
+ return {
877
+ layer,
878
+ css: typeof result === "string" ? result : await renderPreflightDefinition({
879
+ engine: this,
880
+ preflightDefinition: result,
881
+ isFormatted
882
+ })
883
+ };
874
884
  }));
875
- log.debug(`Rendered ${results.length} preflights`);
876
- return results.join(lineEnd);
885
+ log.debug(`Rendered ${rendered.length} preflights`);
886
+ const unlayeredParts = [];
887
+ const layerGroups = /* @__PURE__ */ new Map();
888
+ for (const { layer, css } of rendered) if (layer == null) unlayeredParts.push(css);
889
+ else {
890
+ if (!layerGroups.has(layer)) layerGroups.set(layer, []);
891
+ layerGroups.get(layer).push(css);
892
+ }
893
+ const outputParts = [];
894
+ if (unlayeredParts.length > 0) {
895
+ const unlayeredContent = unlayeredParts.join(lineEnd);
896
+ const { defaultPreflightsLayer } = this.config;
897
+ if (defaultPreflightsLayer in this.config.layers) outputParts.push(`@layer ${defaultPreflightsLayer} {${lineEnd}${unlayeredContent}${lineEnd}}`);
898
+ else outputParts.push(unlayeredContent);
899
+ }
900
+ const configLayerOrder = sortLayerNames(this.config.layers);
901
+ const orderedLayerNames = [...configLayerOrder.filter((name) => layerGroups.has(name)), ...[...layerGroups.keys()].filter((name) => !configLayerOrder.includes(name))];
902
+ for (const layerName of orderedLayerNames) {
903
+ const content = layerGroups.get(layerName).join(lineEnd);
904
+ outputParts.push(`@layer ${layerName} {${lineEnd}${content}${lineEnd}}`);
905
+ }
906
+ return outputParts.join(lineEnd);
877
907
  }
878
908
  async renderAtomicStyles(isFormatted, options = {}) {
879
909
  log.debug("Rendering atomic styles...");
@@ -884,19 +914,45 @@ var Engine = class {
884
914
  atomicStyles,
885
915
  isPreview,
886
916
  isFormatted,
887
- defaultSelector: this.config.defaultSelector
917
+ defaultSelector: this.config.defaultSelector,
918
+ layers: this.config.layers,
919
+ defaultUtilitiesLayer: this.config.defaultUtilitiesLayer
888
920
  });
889
921
  }
922
+ renderLayerOrderDeclaration() {
923
+ const { layers } = this.config;
924
+ if (Object.keys(layers).length === 0) return "";
925
+ return `@layer ${sortLayerNames(layers).join(", ")};`;
926
+ }
890
927
  };
891
928
  function calcAtomicStyleRenderingWeight(style, defaultSelector) {
892
929
  const { selector } = style.content;
893
930
  return selector.length === 1 && selector[0] === defaultSelector ? 0 : selector.length;
894
931
  }
932
+ function sortLayerNames(layers) {
933
+ return Object.entries(layers).sort((a, b) => a[1] - b[1] || a[0].localeCompare(b[0])).map(([name]) => name);
934
+ }
935
+ function isWithLayer(p) {
936
+ if (typeof p !== "object" || p === null) return false;
937
+ const record = p;
938
+ return typeof record.layer === "string" && "preflight" in record;
939
+ }
895
940
  function resolvePreflight(preflight) {
896
- return typeof preflight === "function" ? preflight : () => preflight;
941
+ if (isWithLayer(preflight)) {
942
+ const inner = preflight.preflight;
943
+ const fn = typeof inner === "function" ? inner : () => inner;
944
+ return {
945
+ layer: preflight.layer,
946
+ fn
947
+ };
948
+ }
949
+ return { fn: typeof preflight === "function" ? preflight : () => preflight };
897
950
  }
898
951
  async function resolveEngineConfig(config) {
899
952
  const { prefix = "", defaultSelector = `.${ATOMIC_STYLE_ID_PLACEHOLDER}`, plugins = [], preflights = [] } = config;
953
+ const layers = Object.assign({}, DEFAULT_LAYERS, config.layers);
954
+ const defaultPreflightsLayer = config.defaultPreflightsLayer ?? DEFAULT_PREFLIGHTS_LAYER;
955
+ const defaultUtilitiesLayer = config.defaultUtilitiesLayer ?? DEFAULT_UTILITIES_LAYER;
900
956
  log.debug(`Resolving engine config with prefix: "${prefix}", plugins: ${plugins.length}, preflights: ${preflights.length}`);
901
957
  const resolvedConfig = {
902
958
  rawConfig: config,
@@ -904,6 +960,9 @@ async function resolveEngineConfig(config) {
904
960
  prefix,
905
961
  defaultSelector,
906
962
  preflights: [],
963
+ layers,
964
+ defaultPreflightsLayer,
965
+ defaultUtilitiesLayer,
907
966
  autocomplete: {
908
967
  selectors: /* @__PURE__ */ new Set(),
909
968
  styleItemStrings: /* @__PURE__ */ new Set(),
@@ -922,7 +981,8 @@ function getAtomicStyleId({ content, prefix, stored }) {
922
981
  const key = serialize([
923
982
  content.selector,
924
983
  content.property,
925
- content.value
984
+ content.value,
985
+ content.layer
926
986
  ]);
927
987
  const cached = stored.get(key);
928
988
  if (cached != null) {
@@ -938,29 +998,51 @@ function getAtomicStyleId({ content, prefix, stored }) {
938
998
  function optimizeAtomicStyleContents(list) {
939
999
  const map = /* @__PURE__ */ new Map();
940
1000
  list.forEach((content) => {
941
- const key = serialize([content.selector, content.property]);
1001
+ const key = serialize([
1002
+ content.selector,
1003
+ content.property,
1004
+ content.layer
1005
+ ]);
942
1006
  map.delete(key);
943
1007
  if (content.value == null) return;
944
- map.set(key, content);
1008
+ map.set(key, { ...content });
945
1009
  });
946
1010
  return [...map.values()];
947
1011
  }
1012
+ function extractLayerFromStyleItem(item) {
1013
+ const record = item;
1014
+ const layer = typeof record.__layer === "string" ? record.__layer : void 0;
1015
+ if (layer == null) return {
1016
+ layer: void 0,
1017
+ definition: item
1018
+ };
1019
+ const { __layer: _, ...rest } = record;
1020
+ return {
1021
+ layer,
1022
+ definition: rest
1023
+ };
1024
+ }
948
1025
  async function resolveStyleItemList({ itemList, transformStyleItems, extractStyleDefinition }) {
949
1026
  const unknown = /* @__PURE__ */ new Set();
950
1027
  const list = [];
951
1028
  for (const styleItem of await transformStyleItems(itemList)) if (typeof styleItem === "string") unknown.add(styleItem);
952
- else list.push(...await extractStyleDefinition(styleItem));
1029
+ else {
1030
+ const { layer, definition } = extractLayerFromStyleItem(styleItem);
1031
+ const extracted = await extractStyleDefinition(definition);
1032
+ if (layer != null) extracted.forEach((c) => c.layer = layer);
1033
+ list.push(...extracted);
1034
+ }
953
1035
  return {
954
1036
  unknown,
955
1037
  contents: optimizeAtomicStyleContents(list)
956
1038
  };
957
1039
  }
958
- function renderAtomicStyles(payload) {
959
- const { atomicStyles, isPreview, isFormatted, defaultSelector } = payload;
1040
+ function sortAtomicStyles(styles, defaultSelector) {
1041
+ return [...styles].sort((a, b) => calcAtomicStyleRenderingWeight(a, defaultSelector) - calcAtomicStyleRenderingWeight(b, defaultSelector));
1042
+ }
1043
+ function renderAtomicStylesCss({ atomicStyles, isPreview, isFormatted }) {
960
1044
  const blocks = /* @__PURE__ */ new Map();
961
- Array.from(atomicStyles).sort((a, b) => {
962
- return calcAtomicStyleRenderingWeight(a, defaultSelector) - calcAtomicStyleRenderingWeight(b, defaultSelector);
963
- }).forEach(({ id, content: { selector, property, value } }) => {
1045
+ atomicStyles.forEach(({ id, content: { selector, property, value } }) => {
964
1046
  if (selector.some((s) => s.includes(ATOMIC_STYLE_ID_PLACEHOLDER)) === false || value == null) return;
965
1047
  const renderObject = {
966
1048
  selector: isPreview ? selector : selector.map((s) => s.replace(ATOMIC_STYLE_ID_PLACEHOLDER_RE_GLOBAL, id)),
@@ -982,6 +1064,47 @@ function renderAtomicStyles(payload) {
982
1064
  });
983
1065
  return renderCSSStyleBlocks(blocks, isFormatted);
984
1066
  }
1067
+ function renderAtomicStyles(payload) {
1068
+ const { atomicStyles, isPreview, isFormatted, defaultSelector, layers, defaultUtilitiesLayer } = payload;
1069
+ const sortedStyles = sortAtomicStyles(atomicStyles, defaultSelector);
1070
+ if (layers == null) return renderAtomicStylesCss({
1071
+ atomicStyles: sortedStyles,
1072
+ isPreview,
1073
+ isFormatted
1074
+ });
1075
+ const layerOrder = sortLayerNames(layers);
1076
+ const lineEnd = isFormatted ? "\n" : "";
1077
+ const unlayeredStyles = [];
1078
+ const layerGroups = new Map(layerOrder.map((name) => [name, []]));
1079
+ const candidateDefaultLayer = defaultUtilitiesLayer ?? layerOrder[layerOrder.length - 1];
1080
+ const defaultLayer = candidateDefaultLayer != null && layerGroups.has(candidateDefaultLayer) ? candidateDefaultLayer : layerOrder[layerOrder.length - 1];
1081
+ for (const style of sortedStyles) {
1082
+ const layer = style.content.layer;
1083
+ if (layer != null && layerGroups.has(layer)) layerGroups.get(layer).push(style);
1084
+ else if (layer != null) {
1085
+ log.warn(`Unknown layer "${layer}" encountered in atomic style; falling back to unlayered output.`);
1086
+ unlayeredStyles.push(style);
1087
+ } else if (defaultLayer != null) layerGroups.get(defaultLayer).push(style);
1088
+ else unlayeredStyles.push(style);
1089
+ }
1090
+ const parts = [];
1091
+ if (unlayeredStyles.length > 0) parts.push(renderAtomicStylesCss({
1092
+ atomicStyles: unlayeredStyles,
1093
+ isPreview,
1094
+ isFormatted
1095
+ }));
1096
+ for (const layerName of layerOrder) {
1097
+ const styles = layerGroups.get(layerName);
1098
+ if (styles.length === 0) continue;
1099
+ const innerCss = renderAtomicStylesCss({
1100
+ atomicStyles: styles,
1101
+ isPreview,
1102
+ isFormatted
1103
+ });
1104
+ parts.push(`@layer ${layerName} {${lineEnd}${innerCss}${lineEnd}}`);
1105
+ }
1106
+ return parts.join(lineEnd);
1107
+ }
985
1108
  async function _renderPreflightDefinition({ engine, preflightDefinition, blocks = /* @__PURE__ */ new Map() }) {
986
1109
  for (const [selector, propertiesOrDefinition] of Object.entries(preflightDefinition)) {
987
1110
  if (propertiesOrDefinition == null) continue;
@@ -1070,4 +1193,5 @@ exports.defineShortcut = defineShortcut;
1070
1193
  exports.defineStyleDefinition = defineStyleDefinition;
1071
1194
  exports.defineVariables = defineVariables;
1072
1195
  exports.log = log;
1073
- exports.renderCSSStyleBlocks = renderCSSStyleBlocks;
1196
+ exports.renderCSSStyleBlocks = renderCSSStyleBlocks;
1197
+ exports.sortLayerNames = sortLayerNames;
package/dist/index.d.cts CHANGED
@@ -26,7 +26,7 @@ interface DynamicRule<T> {
26
26
  createResolved: (matched: RegExpMatchArray) => Awaitable<T>;
27
27
  }
28
28
  declare abstract class AbstractResolver<T> {
29
- protected _resolvedResultsMap: Map<string, ResolvedResult<T>>;
29
+ _resolvedResultsMap: Map<string, ResolvedResult<T>>;
30
30
  staticRulesMap: Map<string, StaticRule<T>>;
31
31
  dynamicRulesMap: Map<string, DynamicRule<T>>;
32
32
  onResolved: (string: string, type: 'static' | 'dynamic', result: ResolvedResult<T>) => void;
@@ -269,6 +269,7 @@ interface _Autocomplete {
269
269
  StyleItemString: UnionString;
270
270
  ExtraProperty: UnionString;
271
271
  ExtraCssProperty: UnionString;
272
+ Layer: UnionString;
272
273
  PropertiesValue: Record<string, unknown>;
273
274
  CssPropertiesValue: Record<string, UnionString | UnionNumber>;
274
275
  }
@@ -278,6 +279,7 @@ type EmptyAutocomplete = DefineAutocomplete<{
278
279
  StyleItemString: never;
279
280
  ExtraProperty: never;
280
281
  ExtraCssProperty: never;
282
+ Layer: never;
281
283
  PropertiesValue: never;
282
284
  CssPropertiesValue: never;
283
285
  }>;
@@ -323,21 +325,25 @@ declare class Engine {
323
325
  atomicStyleIds?: string[];
324
326
  isPreview?: boolean;
325
327
  }): Promise<string>;
328
+ renderLayerOrderDeclaration(): string;
326
329
  }
330
+ declare function sortLayerNames(layers: Record<string, number>): string[];
327
331
  //#endregion
328
332
  //#region src/internal/plugin.d.ts
329
- interface EnginePluginHooksOptions {
330
- configureRawConfig?: (config: EngineConfig$1) => Awaitable<EngineConfig$1 | void>;
331
- rawConfigConfigured?: (config: EngineConfig$1) => void;
332
- configureResolvedConfig?: (resolvedConfig: ResolvedEngineConfig) => Awaitable<ResolvedEngineConfig | void>;
333
- configureEngine?: (engine: Engine) => Awaitable<void>;
334
- transformSelectors?: (selectors: string[]) => Awaitable<string[] | void>;
335
- transformStyleItems?: (styleItems: ResolvedStyleItem[]) => Awaitable<ResolvedStyleItem[] | void>;
336
- transformStyleDefinitions?: (styleDefinitions: ResolvedStyleDefinition[]) => Awaitable<ResolvedStyleDefinition[] | void>;
337
- preflightUpdated?: () => void;
338
- atomicStyleAdded?: (atomicStyle: AtomicStyle) => void;
339
- autocompleteConfigUpdated?: () => void;
340
- }
333
+ type DefineHooks<Hooks extends Record<string, [type: 'sync' | 'async', payload: any, returnValue?: any]>> = Hooks;
334
+ type EngineHooksDefinition = DefineHooks<{
335
+ configureRawConfig: ['async', config: EngineConfig$1];
336
+ rawConfigConfigured: ['sync', config: EngineConfig$1, void];
337
+ configureResolvedConfig: ['async', resolvedConfig: ResolvedEngineConfig];
338
+ configureEngine: ['async', engine: Engine];
339
+ transformSelectors: ['async', selectors: string[]];
340
+ transformStyleItems: ['async', styleItems: ResolvedStyleItem[]];
341
+ transformStyleDefinitions: ['async', styleDefinitions: ResolvedStyleDefinition[]];
342
+ preflightUpdated: ['sync', void];
343
+ atomicStyleAdded: ['sync', AtomicStyle];
344
+ autocompleteConfigUpdated: ['sync', void];
345
+ }>;
346
+ type EnginePluginHooksOptions = { [K in keyof EngineHooksDefinition]?: EngineHooksDefinition[K][0] extends 'async' ? (...params: EngineHooksDefinition[K][1] extends void ? [] : [payload: EngineHooksDefinition[K][1]]) => Awaitable<EngineHooksDefinition[K][1] | void> : (...params: EngineHooksDefinition[K][1] extends void ? [] : [payload: EngineHooksDefinition[K][1]]) => EngineHooksDefinition[K][1] | void };
341
347
  interface EnginePlugin extends EnginePluginHooksOptions {
342
348
  name: string;
343
349
  order?: 'pre' | 'post';
@@ -353,7 +359,7 @@ type CSSProperty = keyof CSSProperties;
353
359
  type PropertyValue<T> = T | [value: T, fallback: T[]] | Nullish;
354
360
  type Properties_CSS = { [Key in keyof CSSProperties]?: PropertyValue<Exclude<UnionString | UnionNumber | GetValue<CSSProperties, Key> | GetValue<ResolvedAutocomplete['CssPropertiesValue'], ToKebab<Key>> | GetValue<ResolvedAutocomplete['CssPropertiesValue'], FromKebab<Key>> | GetValue<ResolvedAutocomplete['CssPropertiesValue'], '*'>, Nullish>> };
355
361
  type Properties_ExtraCSS = { [Key in keyof ResolvedAutocomplete['ExtraCssProperty']]?: PropertyValue<Exclude<UnionString | UnionNumber | GetValue<CSSProperties, Key & string> | GetValue<ResolvedAutocomplete['CssPropertiesValue'], ToKebab<Key & string>> | GetValue<ResolvedAutocomplete['CssPropertiesValue'], FromKebab<Key & string>> | GetValue<ResolvedAutocomplete['CssPropertiesValue'], '*'>, Nullish>> };
356
- type Properties_Extra = { [Key in keyof ResolvedAutocomplete['ExtraProperty']]?: GetValue<ResolvedAutocomplete['PropertiesValue'], Key & string> };
362
+ type Properties_Extra = { [Key in ResolvedAutocomplete['ExtraProperty']]?: GetValue<ResolvedAutocomplete['PropertiesValue'], Key & string> };
357
363
  interface Properties extends Properties_CSS, Properties_ExtraCSS, Properties_Extra {}
358
364
  type CSSPseudos = `${'$'}${CSS.Pseudos}`;
359
365
  type CSSBlockAtRules = Exclude<CSS.AtRules, '@charset' | 'import' | '@namespace'>;
@@ -372,11 +378,13 @@ interface ExtractedStyleContent {
372
378
  selector: string[];
373
379
  property: string;
374
380
  value: string[] | Nullish;
381
+ layer?: string;
375
382
  }
376
383
  interface StyleContent {
377
384
  selector: string[];
378
385
  property: string;
379
386
  value: string[];
387
+ layer?: string;
380
388
  }
381
389
  interface AtomicStyle {
382
390
  id: string;
@@ -393,6 +401,7 @@ type CSSStyleBlocks = Map<string, CSSStyleBlockBody>;
393
401
  //#endregion
394
402
  //#region src/internal/types/resolved.d.ts
395
403
  type ResolvedAutocomplete = ResolveFrom<PikaAugment, 'Autocomplete', _Autocomplete, EmptyAutocomplete>;
404
+ type ResolvedLayerName = IsNever<ResolvedAutocomplete['Layer']> extends true ? UnionString : ResolvedAutocomplete['Layer'];
396
405
  type ResolvedSelector = ResolveFrom<PikaAugment, 'Selector', string, string>;
397
406
  type ResolvedProperties = ResolveFrom<PikaAugment, 'Properties', any, InternalProperties>;
398
407
  type ResolvedCSSProperties = Omit<ResolvedProperties, ResolvedAutocomplete['ExtraProperty']>;
@@ -402,13 +411,23 @@ type ResolvedStyleItem = ResolveFrom<PikaAugment, 'StyleItem', any, InternalStyl
402
411
  //#region src/internal/types/preflight.d.ts
403
412
  type PreflightDefinition = { [selector in UnionString | ResolvedSelector]?: ResolvedCSSProperties | PreflightDefinition };
404
413
  type PreflightFn = (engine: Engine, isFormatted: boolean) => Awaitable<string | PreflightDefinition>;
414
+ interface WithLayer<T extends string | PreflightDefinition | PreflightFn> {
415
+ layer: string;
416
+ preflight: T;
417
+ }
418
+ interface ResolvedPreflight {
419
+ layer?: string;
420
+ fn: PreflightFn;
421
+ }
405
422
  /**
406
- * PreflightConfig can be a string or a function that returns a string.
423
+ * Preflight can be a string, object, function, or a layer-wrapped variant.
407
424
  *
408
- * 1. A string is a static preflight style.
409
- * 2. A function is a dynamic preflight style that can use the engine instance to generate styles.
425
+ * 1. A `string` is a static preflight style injected verbatim.
426
+ * 2. A `PreflightDefinition` is a JS object describing CSS rules.
427
+ * 3. A `PreflightFn` is a dynamic preflight that receives the engine instance.
428
+ * 4. A `WithLayer` wrapper assigns any of the above to a specific CSS `@layer`.
410
429
  */
411
- type Preflight = string | PreflightDefinition | PreflightFn;
430
+ type Preflight = string | PreflightDefinition | PreflightFn | WithLayer<string | PreflightDefinition | PreflightFn>;
412
431
  //#endregion
413
432
  //#region src/internal/types/engine.d.ts
414
433
  interface EngineConfig$1 {
@@ -470,14 +489,44 @@ interface EngineConfig$1 {
470
489
  * ```
471
490
  */
472
491
  preflights?: Preflight[];
492
+ /**
493
+ * Configure CSS @layer order. Keys are layer names, values are order numbers (lower = earlier).
494
+ * Merged on top of the default layers `{ preflights: 1, utilities: 10 }`, so any keys not
495
+ * specified here will keep their default order values.
496
+ *
497
+ * @default { preflights: 1, utilities: 10 }
498
+ * @example
499
+ * ```ts
500
+ * {
501
+ * layers: { base: 0, components: 5, utilities: 10 }
502
+ * }
503
+ * ```
504
+ */
505
+ layers?: Record<string, number>;
506
+ /**
507
+ * The layer name that unlayered preflights are automatically wrapped into.
508
+ *
509
+ * @default 'preflights'
510
+ */
511
+ defaultPreflightsLayer?: string;
512
+ /**
513
+ * The layer name that atomic styles without an explicit `__layer` are placed into.
514
+ *
515
+ * @default 'utilities'
516
+ */
517
+ defaultUtilitiesLayer?: string;
473
518
  }
474
519
  interface ResolvedEngineConfig {
475
520
  rawConfig: EngineConfig$1;
476
521
  prefix: string;
477
522
  defaultSelector: string;
478
523
  plugins: EnginePlugin[];
479
- preflights: PreflightFn[];
524
+ preflights: ResolvedPreflight[];
480
525
  autocomplete: ResolvedAutocompleteConfig;
526
+ /** Always contains at least the default layers (`preflights` and `utilities`). */
527
+ layers: Record<string, number>;
528
+ defaultPreflightsLayer: string;
529
+ defaultUtilitiesLayer: string;
481
530
  }
482
531
  //#endregion
483
532
  //#region src/internal/plugins/keyframes.d.ts
@@ -585,4 +634,4 @@ declare function defineSelector(selector: Selector): Selector;
585
634
  declare function defineShortcut(shortcut: Shortcut): Shortcut;
586
635
  declare function defineVariables(variables: VariablesDefinition): VariablesDefinition;
587
636
  //#endregion
588
- export { Arrayable, Awaitable, type CSSProperty, type CSSSelector, type CSSStyleBlockBody, type CSSStyleBlocks, type DefineAutocomplete, type Engine, type EngineConfig$1 as EngineConfig, type EnginePlugin, FromKebab, GetValue, IsEqual, IsNever, Keyframes, KeyframesConfig, KeyframesProgress, Nullish, type PikaAugment, type Properties, ResolveFrom, Selector, SelectorsConfig, Shortcut, ShortcutsConfig, Simplify, type StyleDefinition, type StyleItem, ToKebab, UnionNumber, UnionString, UnionToIntersection, Variable, VariableAutocomplete, VariableObject, VariablesConfig, VariablesDefinition, appendAutocompleteCssPropertyValues, appendAutocompleteExtraCssProperties, appendAutocompleteExtraProperties, appendAutocompletePropertyValues, appendAutocompleteSelectors, appendAutocompleteStyleItemStrings, createEngine, createLogger, defineEngineConfig, defineEnginePlugin, defineKeyframes, definePreflight, defineSelector, defineShortcut, defineStyleDefinition, defineVariables, extractUsedVarNames, important, keyframes, log, normalizeVariableName, renderCSSStyleBlocks, resolveSelectorConfig, selectors$1 as selectors, shortcuts, variables };
637
+ export { Arrayable, Awaitable, type CSSProperty, type CSSSelector, type CSSStyleBlockBody, type CSSStyleBlocks, type DefineAutocomplete, type Engine, type EngineConfig$1 as EngineConfig, type EnginePlugin, FromKebab, GetValue, IsEqual, IsNever, Keyframes, KeyframesConfig, KeyframesProgress, Nullish, type PikaAugment, type Preflight, type PreflightDefinition, type PreflightFn, type Properties, ResolveFrom, type ResolvedLayerName, type ResolvedPreflight, Selector, SelectorsConfig, Shortcut, ShortcutsConfig, Simplify, type StyleDefinition, type StyleItem, ToKebab, UnionNumber, UnionString, UnionToIntersection, Variable, VariableAutocomplete, VariableObject, VariablesConfig, VariablesDefinition, type WithLayer, appendAutocompleteCssPropertyValues, appendAutocompleteExtraCssProperties, appendAutocompleteExtraProperties, appendAutocompletePropertyValues, appendAutocompleteSelectors, appendAutocompleteStyleItemStrings, createEngine, createLogger, defineEngineConfig, defineEnginePlugin, defineKeyframes, definePreflight, defineSelector, defineShortcut, defineStyleDefinition, defineVariables, extractUsedVarNames, important, keyframes, log, normalizeVariableName, renderCSSStyleBlocks, resolveSelectorConfig, selectors$1 as selectors, shortcuts, sortLayerNames, variables };
package/dist/index.d.mts CHANGED
@@ -26,7 +26,7 @@ interface DynamicRule<T> {
26
26
  createResolved: (matched: RegExpMatchArray) => Awaitable<T>;
27
27
  }
28
28
  declare abstract class AbstractResolver<T> {
29
- protected _resolvedResultsMap: Map<string, ResolvedResult<T>>;
29
+ _resolvedResultsMap: Map<string, ResolvedResult<T>>;
30
30
  staticRulesMap: Map<string, StaticRule<T>>;
31
31
  dynamicRulesMap: Map<string, DynamicRule<T>>;
32
32
  onResolved: (string: string, type: 'static' | 'dynamic', result: ResolvedResult<T>) => void;
@@ -269,6 +269,7 @@ interface _Autocomplete {
269
269
  StyleItemString: UnionString;
270
270
  ExtraProperty: UnionString;
271
271
  ExtraCssProperty: UnionString;
272
+ Layer: UnionString;
272
273
  PropertiesValue: Record<string, unknown>;
273
274
  CssPropertiesValue: Record<string, UnionString | UnionNumber>;
274
275
  }
@@ -278,6 +279,7 @@ type EmptyAutocomplete = DefineAutocomplete<{
278
279
  StyleItemString: never;
279
280
  ExtraProperty: never;
280
281
  ExtraCssProperty: never;
282
+ Layer: never;
281
283
  PropertiesValue: never;
282
284
  CssPropertiesValue: never;
283
285
  }>;
@@ -323,21 +325,25 @@ declare class Engine {
323
325
  atomicStyleIds?: string[];
324
326
  isPreview?: boolean;
325
327
  }): Promise<string>;
328
+ renderLayerOrderDeclaration(): string;
326
329
  }
330
+ declare function sortLayerNames(layers: Record<string, number>): string[];
327
331
  //#endregion
328
332
  //#region src/internal/plugin.d.ts
329
- interface EnginePluginHooksOptions {
330
- configureRawConfig?: (config: EngineConfig$1) => Awaitable<EngineConfig$1 | void>;
331
- rawConfigConfigured?: (config: EngineConfig$1) => void;
332
- configureResolvedConfig?: (resolvedConfig: ResolvedEngineConfig) => Awaitable<ResolvedEngineConfig | void>;
333
- configureEngine?: (engine: Engine) => Awaitable<void>;
334
- transformSelectors?: (selectors: string[]) => Awaitable<string[] | void>;
335
- transformStyleItems?: (styleItems: ResolvedStyleItem[]) => Awaitable<ResolvedStyleItem[] | void>;
336
- transformStyleDefinitions?: (styleDefinitions: ResolvedStyleDefinition[]) => Awaitable<ResolvedStyleDefinition[] | void>;
337
- preflightUpdated?: () => void;
338
- atomicStyleAdded?: (atomicStyle: AtomicStyle) => void;
339
- autocompleteConfigUpdated?: () => void;
340
- }
333
+ type DefineHooks<Hooks extends Record<string, [type: 'sync' | 'async', payload: any, returnValue?: any]>> = Hooks;
334
+ type EngineHooksDefinition = DefineHooks<{
335
+ configureRawConfig: ['async', config: EngineConfig$1];
336
+ rawConfigConfigured: ['sync', config: EngineConfig$1, void];
337
+ configureResolvedConfig: ['async', resolvedConfig: ResolvedEngineConfig];
338
+ configureEngine: ['async', engine: Engine];
339
+ transformSelectors: ['async', selectors: string[]];
340
+ transformStyleItems: ['async', styleItems: ResolvedStyleItem[]];
341
+ transformStyleDefinitions: ['async', styleDefinitions: ResolvedStyleDefinition[]];
342
+ preflightUpdated: ['sync', void];
343
+ atomicStyleAdded: ['sync', AtomicStyle];
344
+ autocompleteConfigUpdated: ['sync', void];
345
+ }>;
346
+ type EnginePluginHooksOptions = { [K in keyof EngineHooksDefinition]?: EngineHooksDefinition[K][0] extends 'async' ? (...params: EngineHooksDefinition[K][1] extends void ? [] : [payload: EngineHooksDefinition[K][1]]) => Awaitable<EngineHooksDefinition[K][1] | void> : (...params: EngineHooksDefinition[K][1] extends void ? [] : [payload: EngineHooksDefinition[K][1]]) => EngineHooksDefinition[K][1] | void };
341
347
  interface EnginePlugin extends EnginePluginHooksOptions {
342
348
  name: string;
343
349
  order?: 'pre' | 'post';
@@ -353,7 +359,7 @@ type CSSProperty = keyof CSSProperties;
353
359
  type PropertyValue<T> = T | [value: T, fallback: T[]] | Nullish;
354
360
  type Properties_CSS = { [Key in keyof CSSProperties]?: PropertyValue<Exclude<UnionString | UnionNumber | GetValue<CSSProperties, Key> | GetValue<ResolvedAutocomplete['CssPropertiesValue'], ToKebab<Key>> | GetValue<ResolvedAutocomplete['CssPropertiesValue'], FromKebab<Key>> | GetValue<ResolvedAutocomplete['CssPropertiesValue'], '*'>, Nullish>> };
355
361
  type Properties_ExtraCSS = { [Key in keyof ResolvedAutocomplete['ExtraCssProperty']]?: PropertyValue<Exclude<UnionString | UnionNumber | GetValue<CSSProperties, Key & string> | GetValue<ResolvedAutocomplete['CssPropertiesValue'], ToKebab<Key & string>> | GetValue<ResolvedAutocomplete['CssPropertiesValue'], FromKebab<Key & string>> | GetValue<ResolvedAutocomplete['CssPropertiesValue'], '*'>, Nullish>> };
356
- type Properties_Extra = { [Key in keyof ResolvedAutocomplete['ExtraProperty']]?: GetValue<ResolvedAutocomplete['PropertiesValue'], Key & string> };
362
+ type Properties_Extra = { [Key in ResolvedAutocomplete['ExtraProperty']]?: GetValue<ResolvedAutocomplete['PropertiesValue'], Key & string> };
357
363
  interface Properties extends Properties_CSS, Properties_ExtraCSS, Properties_Extra {}
358
364
  type CSSPseudos = `${'$'}${CSS.Pseudos}`;
359
365
  type CSSBlockAtRules = Exclude<CSS.AtRules, '@charset' | 'import' | '@namespace'>;
@@ -372,11 +378,13 @@ interface ExtractedStyleContent {
372
378
  selector: string[];
373
379
  property: string;
374
380
  value: string[] | Nullish;
381
+ layer?: string;
375
382
  }
376
383
  interface StyleContent {
377
384
  selector: string[];
378
385
  property: string;
379
386
  value: string[];
387
+ layer?: string;
380
388
  }
381
389
  interface AtomicStyle {
382
390
  id: string;
@@ -393,6 +401,7 @@ type CSSStyleBlocks = Map<string, CSSStyleBlockBody>;
393
401
  //#endregion
394
402
  //#region src/internal/types/resolved.d.ts
395
403
  type ResolvedAutocomplete = ResolveFrom<PikaAugment, 'Autocomplete', _Autocomplete, EmptyAutocomplete>;
404
+ type ResolvedLayerName = IsNever<ResolvedAutocomplete['Layer']> extends true ? UnionString : ResolvedAutocomplete['Layer'];
396
405
  type ResolvedSelector = ResolveFrom<PikaAugment, 'Selector', string, string>;
397
406
  type ResolvedProperties = ResolveFrom<PikaAugment, 'Properties', any, InternalProperties>;
398
407
  type ResolvedCSSProperties = Omit<ResolvedProperties, ResolvedAutocomplete['ExtraProperty']>;
@@ -402,13 +411,23 @@ type ResolvedStyleItem = ResolveFrom<PikaAugment, 'StyleItem', any, InternalStyl
402
411
  //#region src/internal/types/preflight.d.ts
403
412
  type PreflightDefinition = { [selector in UnionString | ResolvedSelector]?: ResolvedCSSProperties | PreflightDefinition };
404
413
  type PreflightFn = (engine: Engine, isFormatted: boolean) => Awaitable<string | PreflightDefinition>;
414
+ interface WithLayer<T extends string | PreflightDefinition | PreflightFn> {
415
+ layer: string;
416
+ preflight: T;
417
+ }
418
+ interface ResolvedPreflight {
419
+ layer?: string;
420
+ fn: PreflightFn;
421
+ }
405
422
  /**
406
- * PreflightConfig can be a string or a function that returns a string.
423
+ * Preflight can be a string, object, function, or a layer-wrapped variant.
407
424
  *
408
- * 1. A string is a static preflight style.
409
- * 2. A function is a dynamic preflight style that can use the engine instance to generate styles.
425
+ * 1. A `string` is a static preflight style injected verbatim.
426
+ * 2. A `PreflightDefinition` is a JS object describing CSS rules.
427
+ * 3. A `PreflightFn` is a dynamic preflight that receives the engine instance.
428
+ * 4. A `WithLayer` wrapper assigns any of the above to a specific CSS `@layer`.
410
429
  */
411
- type Preflight = string | PreflightDefinition | PreflightFn;
430
+ type Preflight = string | PreflightDefinition | PreflightFn | WithLayer<string | PreflightDefinition | PreflightFn>;
412
431
  //#endregion
413
432
  //#region src/internal/types/engine.d.ts
414
433
  interface EngineConfig$1 {
@@ -470,14 +489,44 @@ interface EngineConfig$1 {
470
489
  * ```
471
490
  */
472
491
  preflights?: Preflight[];
492
+ /**
493
+ * Configure CSS @layer order. Keys are layer names, values are order numbers (lower = earlier).
494
+ * Merged on top of the default layers `{ preflights: 1, utilities: 10 }`, so any keys not
495
+ * specified here will keep their default order values.
496
+ *
497
+ * @default { preflights: 1, utilities: 10 }
498
+ * @example
499
+ * ```ts
500
+ * {
501
+ * layers: { base: 0, components: 5, utilities: 10 }
502
+ * }
503
+ * ```
504
+ */
505
+ layers?: Record<string, number>;
506
+ /**
507
+ * The layer name that unlayered preflights are automatically wrapped into.
508
+ *
509
+ * @default 'preflights'
510
+ */
511
+ defaultPreflightsLayer?: string;
512
+ /**
513
+ * The layer name that atomic styles without an explicit `__layer` are placed into.
514
+ *
515
+ * @default 'utilities'
516
+ */
517
+ defaultUtilitiesLayer?: string;
473
518
  }
474
519
  interface ResolvedEngineConfig {
475
520
  rawConfig: EngineConfig$1;
476
521
  prefix: string;
477
522
  defaultSelector: string;
478
523
  plugins: EnginePlugin[];
479
- preflights: PreflightFn[];
524
+ preflights: ResolvedPreflight[];
480
525
  autocomplete: ResolvedAutocompleteConfig;
526
+ /** Always contains at least the default layers (`preflights` and `utilities`). */
527
+ layers: Record<string, number>;
528
+ defaultPreflightsLayer: string;
529
+ defaultUtilitiesLayer: string;
481
530
  }
482
531
  //#endregion
483
532
  //#region src/internal/plugins/keyframes.d.ts
@@ -585,4 +634,4 @@ declare function defineSelector(selector: Selector): Selector;
585
634
  declare function defineShortcut(shortcut: Shortcut): Shortcut;
586
635
  declare function defineVariables(variables: VariablesDefinition): VariablesDefinition;
587
636
  //#endregion
588
- export { Arrayable, Awaitable, type CSSProperty, type CSSSelector, type CSSStyleBlockBody, type CSSStyleBlocks, type DefineAutocomplete, type Engine, type EngineConfig$1 as EngineConfig, type EnginePlugin, FromKebab, GetValue, IsEqual, IsNever, Keyframes, KeyframesConfig, KeyframesProgress, Nullish, type PikaAugment, type Properties, ResolveFrom, Selector, SelectorsConfig, Shortcut, ShortcutsConfig, Simplify, type StyleDefinition, type StyleItem, ToKebab, UnionNumber, UnionString, UnionToIntersection, Variable, VariableAutocomplete, VariableObject, VariablesConfig, VariablesDefinition, appendAutocompleteCssPropertyValues, appendAutocompleteExtraCssProperties, appendAutocompleteExtraProperties, appendAutocompletePropertyValues, appendAutocompleteSelectors, appendAutocompleteStyleItemStrings, createEngine, createLogger, defineEngineConfig, defineEnginePlugin, defineKeyframes, definePreflight, defineSelector, defineShortcut, defineStyleDefinition, defineVariables, extractUsedVarNames, important, keyframes, log, normalizeVariableName, renderCSSStyleBlocks, resolveSelectorConfig, selectors$1 as selectors, shortcuts, variables };
637
+ export { Arrayable, Awaitable, type CSSProperty, type CSSSelector, type CSSStyleBlockBody, type CSSStyleBlocks, type DefineAutocomplete, type Engine, type EngineConfig$1 as EngineConfig, type EnginePlugin, FromKebab, GetValue, IsEqual, IsNever, Keyframes, KeyframesConfig, KeyframesProgress, Nullish, type PikaAugment, type Preflight, type PreflightDefinition, type PreflightFn, type Properties, ResolveFrom, type ResolvedLayerName, type ResolvedPreflight, Selector, SelectorsConfig, Shortcut, ShortcutsConfig, Simplify, type StyleDefinition, type StyleItem, ToKebab, UnionNumber, UnionString, UnionToIntersection, Variable, VariableAutocomplete, VariableObject, VariablesConfig, VariablesDefinition, type WithLayer, appendAutocompleteCssPropertyValues, appendAutocompleteExtraCssProperties, appendAutocompleteExtraProperties, appendAutocompletePropertyValues, appendAutocompleteSelectors, appendAutocompleteStyleItemStrings, createEngine, createLogger, defineEngineConfig, defineEnginePlugin, defineKeyframes, definePreflight, defineSelector, defineShortcut, defineStyleDefinition, defineVariables, extractUsedVarNames, important, keyframes, log, normalizeVariableName, renderCSSStyleBlocks, resolveSelectorConfig, selectors$1 as selectors, shortcuts, sortLayerNames, variables };
package/dist/index.mjs CHANGED
@@ -751,6 +751,12 @@ function normalizeVariableName(name) {
751
751
 
752
752
  //#endregion
753
753
  //#region src/internal/engine.ts
754
+ const DEFAULT_PREFLIGHTS_LAYER = "preflights";
755
+ const DEFAULT_UTILITIES_LAYER = "utilities";
756
+ const DEFAULT_LAYERS = {
757
+ [DEFAULT_PREFLIGHTS_LAYER]: 1,
758
+ [DEFAULT_UTILITIES_LAYER]: 10
759
+ };
754
760
  async function createEngine(config = {}) {
755
761
  log.debug("Creating engine with config:", config);
756
762
  const corePlugins = [
@@ -770,6 +776,8 @@ async function createEngine(config = {}) {
770
776
  log.debug("Engine config resolved with prefix:", resolvedConfig.prefix);
771
777
  resolvedConfig = await hooks.configureResolvedConfig(resolvedConfig.plugins, resolvedConfig);
772
778
  let engine = new Engine(resolvedConfig);
779
+ engine.appendAutocompleteExtraProperties("__layer");
780
+ engine.appendAutocompletePropertyValues("__layer", "Autocomplete['Layer']");
773
781
  log.debug("Engine instance created");
774
782
  engine = await hooks.configureEngine(engine.config.plugins, engine);
775
783
  log.debug("Engine initialized successfully");
@@ -862,17 +870,39 @@ var Engine = class {
862
870
  async renderPreflights(isFormatted) {
863
871
  log.debug("Rendering preflights...");
864
872
  const lineEnd = isFormatted ? "\n" : "";
865
- const results = await Promise.all(this.config.preflights.map(async (p) => {
866
- const result = await p(this, isFormatted);
867
- if (typeof result === "string") return result;
868
- return renderPreflightDefinition({
869
- engine: this,
870
- preflightDefinition: result,
871
- isFormatted
872
- });
873
+ const rendered = await Promise.all(this.config.preflights.map(async ({ layer, fn }) => {
874
+ const result = await fn(this, isFormatted);
875
+ return {
876
+ layer,
877
+ css: typeof result === "string" ? result : await renderPreflightDefinition({
878
+ engine: this,
879
+ preflightDefinition: result,
880
+ isFormatted
881
+ })
882
+ };
873
883
  }));
874
- log.debug(`Rendered ${results.length} preflights`);
875
- return results.join(lineEnd);
884
+ log.debug(`Rendered ${rendered.length} preflights`);
885
+ const unlayeredParts = [];
886
+ const layerGroups = /* @__PURE__ */ new Map();
887
+ for (const { layer, css } of rendered) if (layer == null) unlayeredParts.push(css);
888
+ else {
889
+ if (!layerGroups.has(layer)) layerGroups.set(layer, []);
890
+ layerGroups.get(layer).push(css);
891
+ }
892
+ const outputParts = [];
893
+ if (unlayeredParts.length > 0) {
894
+ const unlayeredContent = unlayeredParts.join(lineEnd);
895
+ const { defaultPreflightsLayer } = this.config;
896
+ if (defaultPreflightsLayer in this.config.layers) outputParts.push(`@layer ${defaultPreflightsLayer} {${lineEnd}${unlayeredContent}${lineEnd}}`);
897
+ else outputParts.push(unlayeredContent);
898
+ }
899
+ const configLayerOrder = sortLayerNames(this.config.layers);
900
+ const orderedLayerNames = [...configLayerOrder.filter((name) => layerGroups.has(name)), ...[...layerGroups.keys()].filter((name) => !configLayerOrder.includes(name))];
901
+ for (const layerName of orderedLayerNames) {
902
+ const content = layerGroups.get(layerName).join(lineEnd);
903
+ outputParts.push(`@layer ${layerName} {${lineEnd}${content}${lineEnd}}`);
904
+ }
905
+ return outputParts.join(lineEnd);
876
906
  }
877
907
  async renderAtomicStyles(isFormatted, options = {}) {
878
908
  log.debug("Rendering atomic styles...");
@@ -883,19 +913,45 @@ var Engine = class {
883
913
  atomicStyles,
884
914
  isPreview,
885
915
  isFormatted,
886
- defaultSelector: this.config.defaultSelector
916
+ defaultSelector: this.config.defaultSelector,
917
+ layers: this.config.layers,
918
+ defaultUtilitiesLayer: this.config.defaultUtilitiesLayer
887
919
  });
888
920
  }
921
+ renderLayerOrderDeclaration() {
922
+ const { layers } = this.config;
923
+ if (Object.keys(layers).length === 0) return "";
924
+ return `@layer ${sortLayerNames(layers).join(", ")};`;
925
+ }
889
926
  };
890
927
  function calcAtomicStyleRenderingWeight(style, defaultSelector) {
891
928
  const { selector } = style.content;
892
929
  return selector.length === 1 && selector[0] === defaultSelector ? 0 : selector.length;
893
930
  }
931
+ function sortLayerNames(layers) {
932
+ return Object.entries(layers).sort((a, b) => a[1] - b[1] || a[0].localeCompare(b[0])).map(([name]) => name);
933
+ }
934
+ function isWithLayer(p) {
935
+ if (typeof p !== "object" || p === null) return false;
936
+ const record = p;
937
+ return typeof record.layer === "string" && "preflight" in record;
938
+ }
894
939
  function resolvePreflight(preflight) {
895
- return typeof preflight === "function" ? preflight : () => preflight;
940
+ if (isWithLayer(preflight)) {
941
+ const inner = preflight.preflight;
942
+ const fn = typeof inner === "function" ? inner : () => inner;
943
+ return {
944
+ layer: preflight.layer,
945
+ fn
946
+ };
947
+ }
948
+ return { fn: typeof preflight === "function" ? preflight : () => preflight };
896
949
  }
897
950
  async function resolveEngineConfig(config) {
898
951
  const { prefix = "", defaultSelector = `.${ATOMIC_STYLE_ID_PLACEHOLDER}`, plugins = [], preflights = [] } = config;
952
+ const layers = Object.assign({}, DEFAULT_LAYERS, config.layers);
953
+ const defaultPreflightsLayer = config.defaultPreflightsLayer ?? DEFAULT_PREFLIGHTS_LAYER;
954
+ const defaultUtilitiesLayer = config.defaultUtilitiesLayer ?? DEFAULT_UTILITIES_LAYER;
899
955
  log.debug(`Resolving engine config with prefix: "${prefix}", plugins: ${plugins.length}, preflights: ${preflights.length}`);
900
956
  const resolvedConfig = {
901
957
  rawConfig: config,
@@ -903,6 +959,9 @@ async function resolveEngineConfig(config) {
903
959
  prefix,
904
960
  defaultSelector,
905
961
  preflights: [],
962
+ layers,
963
+ defaultPreflightsLayer,
964
+ defaultUtilitiesLayer,
906
965
  autocomplete: {
907
966
  selectors: /* @__PURE__ */ new Set(),
908
967
  styleItemStrings: /* @__PURE__ */ new Set(),
@@ -921,7 +980,8 @@ function getAtomicStyleId({ content, prefix, stored }) {
921
980
  const key = serialize([
922
981
  content.selector,
923
982
  content.property,
924
- content.value
983
+ content.value,
984
+ content.layer
925
985
  ]);
926
986
  const cached = stored.get(key);
927
987
  if (cached != null) {
@@ -937,29 +997,51 @@ function getAtomicStyleId({ content, prefix, stored }) {
937
997
  function optimizeAtomicStyleContents(list) {
938
998
  const map = /* @__PURE__ */ new Map();
939
999
  list.forEach((content) => {
940
- const key = serialize([content.selector, content.property]);
1000
+ const key = serialize([
1001
+ content.selector,
1002
+ content.property,
1003
+ content.layer
1004
+ ]);
941
1005
  map.delete(key);
942
1006
  if (content.value == null) return;
943
- map.set(key, content);
1007
+ map.set(key, { ...content });
944
1008
  });
945
1009
  return [...map.values()];
946
1010
  }
1011
+ function extractLayerFromStyleItem(item) {
1012
+ const record = item;
1013
+ const layer = typeof record.__layer === "string" ? record.__layer : void 0;
1014
+ if (layer == null) return {
1015
+ layer: void 0,
1016
+ definition: item
1017
+ };
1018
+ const { __layer: _, ...rest } = record;
1019
+ return {
1020
+ layer,
1021
+ definition: rest
1022
+ };
1023
+ }
947
1024
  async function resolveStyleItemList({ itemList, transformStyleItems, extractStyleDefinition }) {
948
1025
  const unknown = /* @__PURE__ */ new Set();
949
1026
  const list = [];
950
1027
  for (const styleItem of await transformStyleItems(itemList)) if (typeof styleItem === "string") unknown.add(styleItem);
951
- else list.push(...await extractStyleDefinition(styleItem));
1028
+ else {
1029
+ const { layer, definition } = extractLayerFromStyleItem(styleItem);
1030
+ const extracted = await extractStyleDefinition(definition);
1031
+ if (layer != null) extracted.forEach((c) => c.layer = layer);
1032
+ list.push(...extracted);
1033
+ }
952
1034
  return {
953
1035
  unknown,
954
1036
  contents: optimizeAtomicStyleContents(list)
955
1037
  };
956
1038
  }
957
- function renderAtomicStyles(payload) {
958
- const { atomicStyles, isPreview, isFormatted, defaultSelector } = payload;
1039
+ function sortAtomicStyles(styles, defaultSelector) {
1040
+ return [...styles].sort((a, b) => calcAtomicStyleRenderingWeight(a, defaultSelector) - calcAtomicStyleRenderingWeight(b, defaultSelector));
1041
+ }
1042
+ function renderAtomicStylesCss({ atomicStyles, isPreview, isFormatted }) {
959
1043
  const blocks = /* @__PURE__ */ new Map();
960
- Array.from(atomicStyles).sort((a, b) => {
961
- return calcAtomicStyleRenderingWeight(a, defaultSelector) - calcAtomicStyleRenderingWeight(b, defaultSelector);
962
- }).forEach(({ id, content: { selector, property, value } }) => {
1044
+ atomicStyles.forEach(({ id, content: { selector, property, value } }) => {
963
1045
  if (selector.some((s) => s.includes(ATOMIC_STYLE_ID_PLACEHOLDER)) === false || value == null) return;
964
1046
  const renderObject = {
965
1047
  selector: isPreview ? selector : selector.map((s) => s.replace(ATOMIC_STYLE_ID_PLACEHOLDER_RE_GLOBAL, id)),
@@ -981,6 +1063,47 @@ function renderAtomicStyles(payload) {
981
1063
  });
982
1064
  return renderCSSStyleBlocks(blocks, isFormatted);
983
1065
  }
1066
+ function renderAtomicStyles(payload) {
1067
+ const { atomicStyles, isPreview, isFormatted, defaultSelector, layers, defaultUtilitiesLayer } = payload;
1068
+ const sortedStyles = sortAtomicStyles(atomicStyles, defaultSelector);
1069
+ if (layers == null) return renderAtomicStylesCss({
1070
+ atomicStyles: sortedStyles,
1071
+ isPreview,
1072
+ isFormatted
1073
+ });
1074
+ const layerOrder = sortLayerNames(layers);
1075
+ const lineEnd = isFormatted ? "\n" : "";
1076
+ const unlayeredStyles = [];
1077
+ const layerGroups = new Map(layerOrder.map((name) => [name, []]));
1078
+ const candidateDefaultLayer = defaultUtilitiesLayer ?? layerOrder[layerOrder.length - 1];
1079
+ const defaultLayer = candidateDefaultLayer != null && layerGroups.has(candidateDefaultLayer) ? candidateDefaultLayer : layerOrder[layerOrder.length - 1];
1080
+ for (const style of sortedStyles) {
1081
+ const layer = style.content.layer;
1082
+ if (layer != null && layerGroups.has(layer)) layerGroups.get(layer).push(style);
1083
+ else if (layer != null) {
1084
+ log.warn(`Unknown layer "${layer}" encountered in atomic style; falling back to unlayered output.`);
1085
+ unlayeredStyles.push(style);
1086
+ } else if (defaultLayer != null) layerGroups.get(defaultLayer).push(style);
1087
+ else unlayeredStyles.push(style);
1088
+ }
1089
+ const parts = [];
1090
+ if (unlayeredStyles.length > 0) parts.push(renderAtomicStylesCss({
1091
+ atomicStyles: unlayeredStyles,
1092
+ isPreview,
1093
+ isFormatted
1094
+ }));
1095
+ for (const layerName of layerOrder) {
1096
+ const styles = layerGroups.get(layerName);
1097
+ if (styles.length === 0) continue;
1098
+ const innerCss = renderAtomicStylesCss({
1099
+ atomicStyles: styles,
1100
+ isPreview,
1101
+ isFormatted
1102
+ });
1103
+ parts.push(`@layer ${layerName} {${lineEnd}${innerCss}${lineEnd}}`);
1104
+ }
1105
+ return parts.join(lineEnd);
1106
+ }
984
1107
  async function _renderPreflightDefinition({ engine, preflightDefinition, blocks = /* @__PURE__ */ new Map() }) {
985
1108
  for (const [selector, propertiesOrDefinition] of Object.entries(preflightDefinition)) {
986
1109
  if (propertiesOrDefinition == null) continue;
@@ -1052,4 +1175,4 @@ function defineVariables(variables$1) {
1052
1175
  /* c8 ignore end */
1053
1176
 
1054
1177
  //#endregion
1055
- export { appendAutocompleteCssPropertyValues, appendAutocompleteExtraCssProperties, appendAutocompleteExtraProperties, appendAutocompletePropertyValues, appendAutocompleteSelectors, appendAutocompleteStyleItemStrings, createEngine, createLogger, defineEngineConfig, defineEnginePlugin, defineKeyframes, definePreflight, defineSelector, defineShortcut, defineStyleDefinition, defineVariables, log, renderCSSStyleBlocks };
1178
+ export { appendAutocompleteCssPropertyValues, appendAutocompleteExtraCssProperties, appendAutocompleteExtraProperties, appendAutocompletePropertyValues, appendAutocompleteSelectors, appendAutocompleteStyleItemStrings, createEngine, createLogger, defineEngineConfig, defineEnginePlugin, defineKeyframes, definePreflight, defineSelector, defineShortcut, defineStyleDefinition, defineVariables, log, renderCSSStyleBlocks, sortLayerNames };
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@pikacss/core",
3
3
  "type": "module",
4
- "version": "0.0.40",
4
+ "version": "0.0.42",
5
5
  "author": "DevilTea <ch19980814@gmail.com>",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/pikacss/pikacss.github.io.git",
9
+ "url": "https://github.com/pikacss/pikacss.git",
10
10
  "directory": "packages/core"
11
11
  },
12
12
  "bugs": {
13
- "url": "https://github.com/pikacss/pikacss.github.io/issues"
13
+ "url": "https://github.com/pikacss/pikacss/issues"
14
14
  },
15
15
  "keywords": [
16
16
  "pikacss",
package/README.md DELETED
@@ -1,238 +0,0 @@
1
- # @pikacss/core
2
-
3
- The core Atomic CSS-in-JS engine of PikaCSS.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- pnpm add @pikacss/core
9
- ```
10
-
11
- ## Quick Start
12
-
13
- ```typescript
14
- import { createEngine, defineEngineConfig } from '@pikacss/core'
15
-
16
- const config = defineEngineConfig({
17
- // Engine configuration
18
- prefix: 'pk-',
19
- defaultSelector: '.%',
20
- plugins: []
21
- })
22
-
23
- // createEngine is async and returns a fully initialized engine
24
- const engine = await createEngine(config)
25
- ```
26
-
27
- ## Features
28
-
29
- - ⚡ High-performance Atomic CSS-in-JS engine
30
- - 🎯 Type-safe with full TypeScript support
31
- - 🔌 Extensible plugin system with hooks
32
- - 🎨 Built-in support for shortcuts, selectors, variables, keyframes, and important rules
33
- - 🔧 Fully configurable with type-safe helpers
34
- - 🌐 Framework-agnostic core (zero dependencies except csstype)
35
-
36
- ## Usage for Integration Developers
37
-
38
- ### Creating an Engine
39
-
40
- ```typescript
41
- import { createEngine, defineEngineConfig } from '@pikacss/core'
42
-
43
- const config = defineEngineConfig({
44
- // Prefix for generated atomic CSS class names
45
- prefix: 'pk-',
46
-
47
- // Default selector format (% will be replaced with atomic ID)
48
- defaultSelector: '.%',
49
-
50
- // Plugins to extend functionality
51
- plugins: [],
52
-
53
- // Global CSS preflights
54
- preflights: [],
55
- })
56
-
57
- // createEngine is async - it returns a fully initialized engine
58
- const engine = await createEngine(config)
59
- ```
60
-
61
- ### Engine Methods and Properties
62
-
63
- The `Engine` instance provides methods and sub-systems for managing CSS generation:
64
-
65
- ```typescript
66
- // Add global CSS preflight
67
- engine.addPreflight('* { box-sizing: border-box; }')
68
-
69
- // Process style items and get atomic class IDs
70
- const classNames = await engine.use({ color: 'red' }, { display: 'flex' })
71
-
72
- // Render generated preflights
73
- const preflightCSS = await engine.renderPreflights(true)
74
-
75
- // Render generated atomic styles
76
- const atomicCSS = await engine.renderAtomicStyles(true)
77
-
78
- // Access sub-systems (provided by built-in plugins)
79
- engine.variables // { store: Map, add: (variables) => void }
80
- engine.keyframes // { store: Map, add: (...keyframes) => void }
81
- engine.selectors // { resolver: SelectorResolver, add: (...selectors) => void }
82
- engine.shortcuts // { resolver: ShortcutResolver, add: (...shortcuts) => void }
83
-
84
- // Access configuration
85
- engine.config // ResolvedEngineConfig
86
-
87
- // Autocomplete helpers
88
- engine.appendAutocompleteSelectors('hover', 'focus')
89
- engine.appendAutocompleteStyleItemStrings('flex-center')
90
- ```
91
-
92
- ### Configuration
93
-
94
- Use `defineEngineConfig` for type-safe configuration:
95
-
96
- ```typescript
97
- import { defineEngineConfig } from '@pikacss/core'
98
-
99
- export default defineEngineConfig({
100
- // Prefix for atomic class IDs
101
- prefix: 'pk-',
102
-
103
- // Default selector format (% = atomic ID)
104
- defaultSelector: '.%',
105
-
106
- // Global CSS preflights (string or function)
107
- preflights: [
108
- ':root { --primary: #3b82f6; }',
109
- // Or function:
110
- (engine, isFormatted) => '/* Generated CSS */'
111
- ],
112
-
113
- // Shortcuts configuration
114
- shortcuts: {
115
- shortcuts: [
116
- ['flex-center', {
117
- display: 'flex',
118
- alignItems: 'center',
119
- justifyContent: 'center'
120
- }],
121
- ]
122
- },
123
-
124
- // Plugins to extend functionality
125
- plugins: []
126
- })
127
- ```
128
-
129
- ## API
130
-
131
- ### Main Exports
132
-
133
- ```typescript
134
- // Engine creation (async)
135
- export function createEngine(config?: EngineConfig): Promise<Engine>
136
-
137
- // Type-safe config helpers
138
- export function defineEngineConfig(config: EngineConfig): EngineConfig
139
- export function defineEnginePlugin(plugin: EnginePlugin): EnginePlugin
140
- export function defineStyleDefinition(def: StyleDefinition): StyleDefinition
141
- export function definePreflight(preflight: Preflight): Preflight
142
- export function defineKeyframes(keyframes: Keyframes): Keyframes
143
- export function defineSelector(selector: Selector): Selector
144
- export function defineShortcut(shortcut: Shortcut): Shortcut
145
- export function defineVariables(variables: VariablesDefinition): VariablesDefinition
146
-
147
- // Utilities
148
- export {
149
- appendAutocompleteCssPropertyValues,
150
- appendAutocompleteExtraCssProperties,
151
- appendAutocompleteExtraProperties,
152
- appendAutocompletePropertyValues,
153
- appendAutocompleteSelectors,
154
- appendAutocompleteStyleItemStrings,
155
- createLogger,
156
- log,
157
- renderCSSStyleBlocks,
158
- }
159
- ```
160
-
161
- ### Engine Instance
162
-
163
- The `Engine` instance provides:
164
-
165
- **Core methods:**
166
- - `engine.addPreflight(css)` - Add global CSS preflight
167
- - `engine.use(...styleItems)` - Process style items and return atomic class IDs
168
- - `engine.renderPreflights(isFormatted)` - Render all preflight CSS
169
- - `engine.renderAtomicStyles(isFormatted, options?)` - Render atomic style CSS
170
-
171
- **Sub-systems (provided by built-in plugins):**
172
- - `engine.variables` - CSS variables management with `store` and `add()`
173
- - `engine.keyframes` - CSS keyframes management with `store` and `add()`
174
- - `engine.selectors` - CSS selectors management with `resolver` and `add()`
175
- - `engine.shortcuts` - CSS shortcuts management with `resolver` and `add()`
176
-
177
- **Properties:**
178
- - `engine.config` - Resolved engine configuration
179
- - `engine.store` - Internal storage for atomic styles and IDs
180
- - `engine.extract` - Style extraction function
181
-
182
- ## Plugin Development
183
-
184
- Create custom plugins to extend PikaCSS using the `EnginePlugin` interface:
185
-
186
- ```typescript
187
- /* eslint-disable pikacss/pika-module-augmentation */
188
- import type { EnginePlugin } from '@pikacss/core'
189
- import { defineEnginePlugin } from '@pikacss/core'
190
-
191
- export function myPlugin(): EnginePlugin {
192
- return defineEnginePlugin({
193
- name: 'my-plugin',
194
-
195
- // Optional: Control execution order ('pre' | 'post')
196
- order: 'pre',
197
-
198
- // Hook into engine lifecycle
199
- async configureEngine(engine) {
200
- // Add global CSS
201
- engine.addPreflight('/* plugin styles */')
202
-
203
- // Add custom shortcuts
204
- engine.shortcuts.add([
205
- 'my-shortcut',
206
- { display: 'flex', gap: '1rem' }
207
- ])
208
-
209
- // Add custom selectors
210
- engine.selectors.add(['hover', '$:hover'])
211
- },
212
-
213
- // Transform style definitions
214
- async transformStyleDefinitions(definitions) {
215
- // Modify or add style definitions
216
- return definitions
217
- },
218
-
219
- // Other available hooks:
220
- // - configureRawConfig(config)
221
- // - rawConfigConfigured(config)
222
- // - configureResolvedConfig(config)
223
- // - transformSelectors(selectors)
224
- // - transformStyleItems(styleItems)
225
- // - preflightUpdated()
226
- // - atomicStyleAdded(atomicStyle)
227
- // - autocompleteConfigUpdated()
228
- })
229
- }
230
- ```
231
-
232
- ## Documentation
233
-
234
- For complete documentation, visit: [PikaCSS Documentation](https://pikacss.github.io/pikacss/)
235
-
236
- ## License
237
-
238
- MIT © DevilTea