@pikacss/core 0.0.28 → 0.0.29

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
@@ -277,7 +277,7 @@ function keyframes() {
277
277
  return defineEnginePlugin({
278
278
  name: "core:keyframes",
279
279
  rawConfigConfigured(config) {
280
- resolveKeyframesConfig = createResolveConfigFn$1({
280
+ resolveKeyframesConfig = createResolveConfigFn({
281
281
  pruneUnused: config.keyframes?.pruneUnused
282
282
  });
283
283
  configList = config.keyframes?.keyframes ?? [];
@@ -300,7 +300,7 @@ function keyframes() {
300
300
  }
301
301
  };
302
302
  engine.keyframes.add(...configList);
303
- engine.addPreflight((engine2, isFormatted) => {
303
+ engine.addPreflight((engine2) => {
304
304
  const maybeUsedName = /* @__PURE__ */ new Set();
305
305
  engine2.store.atomicStyles.forEach(({ content: { property, value } }) => {
306
306
  if (property === "animationName") {
@@ -316,30 +316,22 @@ function keyframes() {
316
316
  });
317
317
  }
318
318
  });
319
- return renderCSSStyleBlocks(
320
- new Map(Array.from(engine2.keyframes.store.entries()).filter(([name, { pruneUnused }]) => pruneUnused === false || maybeUsedName.has(name)).map(([name, { frames }]) => [
321
- `@keyframes ${name}`,
322
- {
323
- properties: [],
324
- children: new Map(Object.entries(frames).map(([frame, properties]) => [
325
- frame,
326
- {
327
- properties: Object.entries(properties).filter(([_, value]) => isNotNullish(value)).flatMap(([property, value]) => {
328
- if (Array.isArray(value))
329
- return value.map((v) => ({ property, value: String(v) }));
330
- return { property, value: String(value) };
331
- })
332
- }
333
- ]))
334
- }
335
- ])),
336
- isFormatted
337
- );
319
+ const maybeUsedKeyframes = Array.from(engine2.keyframes.store.values()).filter(({ name, frames, pruneUnused }) => (pruneUnused === false || maybeUsedName.has(name)) && frames != null);
320
+ const preflightDefinition = {};
321
+ maybeUsedKeyframes.forEach(({ name, frames }) => {
322
+ preflightDefinition[`@keyframes ${name}`] = Object.fromEntries(
323
+ Object.entries(frames).map(([frame, properties]) => [
324
+ frame,
325
+ properties
326
+ ])
327
+ );
328
+ });
329
+ return preflightDefinition;
338
330
  });
339
331
  }
340
332
  });
341
333
  }
342
- function createResolveConfigFn$1({
334
+ function createResolveConfigFn({
343
335
  pruneUnused: defaultPruneUnused = true
344
336
  } = {}) {
345
337
  return function resolveKeyframesConfig(config) {
@@ -686,67 +678,92 @@ function resolveShortcutConfig(config) {
686
678
  }
687
679
 
688
680
  function variables() {
689
- let resolveVariableConfig;
690
- let configList;
681
+ let resolveVariables;
682
+ let rawVariables;
683
+ let safeSet;
691
684
  return defineEnginePlugin({
692
685
  name: "core:variables",
693
686
  rawConfigConfigured(config) {
694
- resolveVariableConfig = createResolveConfigFn({
687
+ resolveVariables = createResolveVariablesFn({
695
688
  pruneUnused: config.variables?.pruneUnused
696
689
  });
697
- configList = config.variables?.variables ?? [];
690
+ rawVariables = config.variables?.variables ?? {};
691
+ safeSet = new Set(config.variables?.safeList ?? []);
698
692
  },
699
693
  configureEngine(engine) {
700
694
  engine.variables = {
701
695
  store: /* @__PURE__ */ new Map(),
702
- add: (...list) => {
703
- list.forEach((config) => {
704
- const resolved = resolveVariableConfig(config);
705
- const { name: _name, value, autocomplete: { asValueOf, asProperty } } = resolved;
706
- const name = normalizeVariableName(_name);
696
+ add: (variables2) => {
697
+ const list = resolveVariables(variables2);
698
+ list.forEach((resolved) => {
699
+ const { name, value, autocomplete: { asValueOf, asProperty } } = resolved;
707
700
  asValueOf.forEach((p) => {
708
701
  if (p !== "-")
709
702
  engine.appendAutocompleteCssPropertyValues(p, `var(${name})`);
710
703
  });
711
704
  if (asProperty)
712
705
  engine.appendAutocompleteExtraCssProperties(name);
713
- if (value != null)
714
- engine.variables.store.set(name, resolved);
706
+ if (value != null) {
707
+ const list2 = engine.variables.store.get(name) ?? [];
708
+ list2.push(resolved);
709
+ engine.variables.store.set(name, list2);
710
+ }
715
711
  });
716
712
  engine.notifyPreflightUpdated();
717
713
  }
718
714
  };
719
- engine.variables.add(...configList);
720
- engine.addPreflight((engine2, isFormatted) => {
715
+ engine.variables.add(rawVariables);
716
+ engine.addPreflight(async (engine2) => {
721
717
  const used = /* @__PURE__ */ new Set();
722
718
  engine2.store.atomicStyles.forEach(({ content: { value } }) => {
723
719
  value.flatMap(extractUsedVarNames).forEach((name) => used.add(normalizeVariableName(name)));
724
720
  });
725
- return renderCSSStyleBlocks(
726
- /* @__PURE__ */ new Map([[
727
- ":root",
728
- {
729
- properties: Array.from(engine2.variables.store.entries()).filter(([name, { pruneUnused, value }]) => (pruneUnused === false || used.has(name)) && value != null).map(([name, { value }]) => ({ property: name, value }))
730
- }
731
- ]]),
732
- isFormatted
733
- );
721
+ const usedVariables = Array.from(engine2.variables.store.values()).flat().filter(({ name, pruneUnused, value }) => (safeSet.has(name) || pruneUnused === false || used.has(name)) && value != null);
722
+ const preflightDefinition = {};
723
+ for (const { name, value, selector: _selector } of usedVariables) {
724
+ const selector = await engine2.pluginHooks.transformSelectors(engine2.config.plugins, _selector);
725
+ let current = preflightDefinition;
726
+ selector.forEach((s) => {
727
+ current[s] ||= {};
728
+ current = current[s];
729
+ });
730
+ Object.assign(current, { [name]: value });
731
+ }
732
+ return preflightDefinition;
734
733
  });
735
734
  }
736
735
  });
737
736
  }
738
- function createResolveConfigFn({
737
+ function createResolveVariablesFn({
739
738
  pruneUnused: defaultPruneUnused = true
740
739
  } = {}) {
741
- return function resolveVariableConfig(config) {
742
- if (typeof config === "string")
743
- return { name: config, value: null, autocomplete: { asValueOf: ["*"], asProperty: true }, pruneUnused: defaultPruneUnused };
744
- if (Array.isArray(config)) {
745
- const [name2, value2, { asValueOf: asValueOf2 = "*", asProperty: asProperty2 = true } = {}, pruneUnused2 = defaultPruneUnused] = config;
746
- return { name: name2, value: value2, autocomplete: { asValueOf: [asValueOf2].flat(), asProperty: asProperty2 }, pruneUnused: pruneUnused2 };
740
+ function _resolveVariables(variables2, levels, result) {
741
+ for (const [key, value] of Object.entries(variables2)) {
742
+ if (key.startsWith("--")) {
743
+ const isObject = typeof value === "object" && value !== null && !Array.isArray(value);
744
+ const {
745
+ value: varValue,
746
+ autocomplete = {},
747
+ pruneUnused = defaultPruneUnused
748
+ } = isObject ? value : { value };
749
+ result.push({
750
+ name: key,
751
+ value: varValue,
752
+ selector: levels.length > 0 ? levels : [":root"],
753
+ autocomplete: {
754
+ asValueOf: autocomplete.asValueOf ? [autocomplete.asValueOf].flat() : ["*"],
755
+ asProperty: autocomplete.asProperty ?? true
756
+ },
757
+ pruneUnused
758
+ });
759
+ } else {
760
+ _resolveVariables(value, [...levels, key], result);
761
+ }
747
762
  }
748
- const { name, value, autocomplete: { asValueOf = "*", asProperty = true } = {}, pruneUnused = defaultPruneUnused } = config;
749
- return { name, value, autocomplete: { asValueOf: [asValueOf].flat(), asProperty }, pruneUnused };
763
+ return result;
764
+ }
765
+ return function resolveVariables(variables2) {
766
+ return _resolveVariables(variables2, [], []);
750
767
  };
751
768
  }
752
769
  const VAR_NAME_RE = /var\((--[\w-]+)/g;
@@ -800,6 +817,7 @@ async function createEngine(config = {}) {
800
817
  }
801
818
  class Engine {
802
819
  config;
820
+ pluginHooks = hooks;
803
821
  extract;
804
822
  store = {
805
823
  atomicStyleIds: /* @__PURE__ */ new Map(),
@@ -878,13 +896,13 @@ class Engine {
878
896
  }
879
897
  async renderPreflights(isFormatted) {
880
898
  const lineEnd = isFormatted ? "\n" : "";
881
- return (await Promise.all(this.config.preflights.map((p) => {
882
- const result = p(this, isFormatted);
899
+ return (await Promise.all(this.config.preflights.map(async (p) => {
900
+ const result = await p(this, isFormatted);
883
901
  if (typeof result === "string")
884
902
  return result;
885
- return renderPreflight({
903
+ return renderPreflightDefinition({
886
904
  engine: this,
887
- preflight: result,
905
+ preflightDefinition: result,
888
906
  isFormatted
889
907
  });
890
908
  }))).join(lineEnd);
@@ -1008,7 +1026,7 @@ function renderAtomicStyles(payload) {
1008
1026
  });
1009
1027
  return renderCSSStyleBlocks(blocks, isFormatted);
1010
1028
  }
1011
- async function _renderPreflight({
1029
+ async function _renderPreflightDefinition({
1012
1030
  engine,
1013
1031
  preflightDefinition,
1014
1032
  blocks = /* @__PURE__ */ new Map()
@@ -1041,7 +1059,7 @@ async function _renderPreflight({
1041
1059
  } else {
1042
1060
  currentBlockBody.children ||= /* @__PURE__ */ new Map();
1043
1061
  currentBlockBody.children.set(k, currentBlockBody.children.get(k) || { properties: [] });
1044
- _renderPreflight({
1062
+ _renderPreflightDefinition({
1045
1063
  engine,
1046
1064
  preflightDefinition: { [k]: v },
1047
1065
  blocks: currentBlockBody.children
@@ -1051,11 +1069,11 @@ async function _renderPreflight({
1051
1069
  }
1052
1070
  return blocks;
1053
1071
  }
1054
- async function renderPreflight(payload) {
1055
- const { engine, preflight, isFormatted } = payload;
1056
- const blocks = await _renderPreflight({
1072
+ async function renderPreflightDefinition(payload) {
1073
+ const { engine, preflightDefinition, isFormatted } = payload;
1074
+ const blocks = await _renderPreflightDefinition({
1057
1075
  engine,
1058
- preflightDefinition: preflight
1076
+ preflightDefinition
1059
1077
  });
1060
1078
  return renderCSSStyleBlocks(blocks, isFormatted);
1061
1079
  }
package/dist/index.d.cts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as _pikacss_core from '@pikacss/core';
1
2
  import * as CSS from 'csstype';
2
3
 
3
4
  interface ImportantConfig {
@@ -188,6 +189,8 @@ declare class ShortcutResolver extends AbstractResolver<StyleItem$1[]> {
188
189
  resolve(shortcut: string): Promise<StyleItem$1[]>;
189
190
  }
190
191
 
192
+ type ResolvedCSSProperty = keyof ResolvedCSSProperties;
193
+ type ResolvedCSSVarProperty = ResolvedCSSProperty extends infer T ? T extends `--${string}` ? T : never : never;
191
194
  interface VariableAutocomplete {
192
195
  /**
193
196
  * Specify the properties that the variable can be used as a value of.
@@ -202,39 +205,59 @@ interface VariableAutocomplete {
202
205
  */
203
206
  asProperty?: boolean;
204
207
  }
205
- type Variable = string | [name: string, value?: string, autocomplete?: VariableAutocomplete, pruneUnused?: boolean] | {
206
- name: string;
207
- value?: string;
208
+ interface VariableObject {
209
+ value?: ResolvedCSSProperties[`--${string}`];
208
210
  autocomplete?: VariableAutocomplete;
209
211
  pruneUnused?: boolean;
212
+ }
213
+ type Variable = ResolvedCSSProperties[`--${string}`] | VariableObject;
214
+ type VariablesDefinition = {
215
+ [key in UnionString | ResolvedSelector | (`--${string}` & {}) | ResolvedCSSVarProperty]?: Variable | VariablesDefinition;
210
216
  };
211
217
  interface VariablesConfig {
212
218
  /**
213
219
  * Define CSS variables with support for static values and autocomplete configuration.
214
220
  *
215
- * @default []
221
+ * @default {}
216
222
  * @example
217
223
  * ```ts
218
224
  * {
219
- * variables: [
220
- * // Basic usage
221
- * ['primary', '#ff0000'],
222
- * // With autocomplete configuration
223
- * ['accent', '#00ff00', {
224
- * asValueOf: ['color', 'background-color'],
225
- * asProperty: true
226
- * }]
227
- * ]
225
+ * variables: {
226
+ * // The variable with value "null" will not be included in the final CSS, but can be used in autocompletion.
227
+ * '--external-var': null,
228
+ *
229
+ * '--color-bg': '#fff',
230
+ * '--color-text': '#000',
231
+ *
232
+ * '[data-theme="dark"]': {
233
+ * '--color-bg': '#000',
234
+ * '--color-text': '#fff',
235
+ * },
236
+ * },
228
237
  * }
229
238
  * ```
230
239
  */
231
- variables: Variable[];
240
+ variables: VariablesDefinition;
232
241
  /**
233
242
  * Whether to prune unused variables from the final CSS.
234
243
  *
235
244
  * @default true
236
245
  */
237
246
  pruneUnused?: boolean;
247
+ /**
248
+ * A list of CSS variables that should always be included in the final CSS, you can use this to prevent certain variables from being pruned.
249
+ *
250
+ * @default []
251
+ * @example
252
+ * ```ts
253
+ * {
254
+ * variables: {
255
+ * safeList: ['--external-var', '--color-bg', '--color-text'],
256
+ * },
257
+ * }
258
+ * ```
259
+ */
260
+ safeList?: ((`--${string}` & {}) | ResolvedCSSVarProperty)[];
238
261
  }
239
262
  declare module '@pikacss/core' {
240
263
  interface EngineConfig {
@@ -242,14 +265,15 @@ declare module '@pikacss/core' {
242
265
  }
243
266
  interface Engine {
244
267
  variables: {
245
- store: Map<string, ResolvedVariableConfig>;
246
- add: (...list: Variable[]) => void;
268
+ store: Map<string, ResolvedVariable[]>;
269
+ add: (variables: VariablesDefinition) => void;
247
270
  };
248
271
  }
249
272
  }
250
- interface ResolvedVariableConfig {
273
+ interface ResolvedVariable {
251
274
  name: string;
252
- value: string | Nullish;
275
+ value: PropertyValue;
276
+ selector: string[];
253
277
  pruneUnused: boolean;
254
278
  autocomplete: {
255
279
  asValueOf: string[];
@@ -273,42 +297,6 @@ type FromKebab<T extends string> = T extends `--${string}` ? T : T extends `-${i
273
297
  type GetValue<Obj extends Record<string, any>, K extends string> = (IsEqual<Obj, object> | IsEqual<Obj, {}> | IsEqual<Obj[K], unknown>) extends false ? Obj[K] : never;
274
298
  type ResolveFrom<T, Key extends string, I, Fallback extends I> = Key extends keyof T ? T[Key] extends I ? T[Key] : Fallback : Fallback;
275
299
 
276
- interface PikaAugment {
277
- }
278
- type PropertyValue = string | number | [value: string | number, fallback: (string | number)[]] | Nullish;
279
- type Properties$1 = Record<string, PropertyValue>;
280
- interface StyleDefinition$1 {
281
- [K: string]: PropertyValue | StyleDefinition$1 | StyleItem$1[];
282
- }
283
- type StyleItem$1 = string | StyleDefinition$1;
284
- interface ExtractedStyleContent {
285
- selector: string[];
286
- property: string;
287
- value: string[] | Nullish;
288
- }
289
- interface StyleContent {
290
- selector: string[];
291
- property: string;
292
- value: string[];
293
- }
294
- interface AtomicStyle {
295
- id: string;
296
- content: StyleContent;
297
- }
298
- interface CSSStyleBlockBody {
299
- properties: {
300
- property: string;
301
- value: string;
302
- }[];
303
- children?: CSSStyleBlocks;
304
- }
305
- type CSSStyleBlocks = Map<string, CSSStyleBlockBody>;
306
- type ResolvedSelector = ResolveFrom<PikaAugment, 'Selector', string, string>;
307
- type ResolvedCSSProperty = ResolveFrom<PikaAugment, 'CSSProperty', string, string>;
308
- type ResolvedProperties = ResolveFrom<PikaAugment, 'Properties', any, Properties$1>;
309
- type ResolvedStyleDefinition = ResolveFrom<PikaAugment, 'StyleDefinition', any, StyleDefinition$1>;
310
- type ResolvedStyleItem = ResolveFrom<PikaAugment, 'StyleItem', any, StyleItem$1>;
311
-
312
300
  interface ResolvedAutocompleteConfig {
313
301
  selectors: Set<string>;
314
302
  styleItemStrings: Set<string>;
@@ -334,7 +322,6 @@ type EmptyAutocomplete = DefineAutocomplete<{
334
322
  PropertiesValue: never;
335
323
  CssPropertiesValue: never;
336
324
  }>;
337
- type ResolvedAutocomplete = ResolveFrom<PikaAugment, 'Autocomplete', _Autocomplete, EmptyAutocomplete>;
338
325
 
339
326
  type DefineHooks<Hooks extends Record<string, [type: 'sync' | 'async', payload: any, returnValue?: any]>> = Hooks;
340
327
  type EngineHooksDefinition = DefineHooks<{
@@ -358,10 +345,48 @@ interface EnginePlugin extends EnginePluginHooksOptions {
358
345
  }
359
346
  declare function defineEnginePlugin(plugin: EnginePlugin): EnginePlugin;
360
347
 
348
+ interface PikaAugment {
349
+ }
350
+ type PropertyValue = string | number | [value: string | number, fallback: (string | number)[]] | Nullish;
351
+ type Properties$1 = Record<string, PropertyValue>;
352
+ interface StyleDefinition$1 {
353
+ [K: string]: PropertyValue | StyleDefinition$1 | StyleItem$1[];
354
+ }
355
+ type StyleItem$1 = string | StyleDefinition$1;
356
+ interface ExtractedStyleContent {
357
+ selector: string[];
358
+ property: string;
359
+ value: string[] | Nullish;
360
+ }
361
+ interface StyleContent {
362
+ selector: string[];
363
+ property: string;
364
+ value: string[];
365
+ }
366
+ interface AtomicStyle {
367
+ id: string;
368
+ content: StyleContent;
369
+ }
370
+ interface CSSStyleBlockBody {
371
+ properties: {
372
+ property: string;
373
+ value: string;
374
+ }[];
375
+ children?: CSSStyleBlocks;
376
+ }
377
+ type CSSStyleBlocks = Map<string, CSSStyleBlockBody>;
378
+
379
+ type ResolvedAutocomplete = ResolveFrom<PikaAugment, 'Autocomplete', _Autocomplete, EmptyAutocomplete>;
380
+ type ResolvedSelector = ResolveFrom<PikaAugment, 'Selector', string, string>;
381
+ type ResolvedProperties = ResolveFrom<PikaAugment, 'Properties', any, Properties$1>;
382
+ type ResolvedCSSProperties = Omit<ResolvedProperties, ResolvedAutocomplete['ExtraProperty']>;
383
+ type ResolvedStyleDefinition = ResolveFrom<PikaAugment, 'StyleDefinition', any, StyleDefinition$1>;
384
+ type ResolvedStyleItem = ResolveFrom<PikaAugment, 'StyleItem', any, StyleItem$1>;
385
+
361
386
  type PreflightDefinition = {
362
- [selector in UnionString | ResolvedSelector]?: ResolvedProperties | PreflightDefinition;
387
+ [selector in UnionString | ResolvedSelector]?: ResolvedCSSProperties | PreflightDefinition;
363
388
  };
364
- type PreflightFn = (engine: Engine, isFormatted: boolean) => string | PreflightDefinition;
389
+ type PreflightFn = (engine: Engine, isFormatted: boolean) => Awaitable<string | PreflightDefinition>;
365
390
  /**
366
391
  * PreflightConfig can be a string or a function that returns a string.
367
392
  *
@@ -445,6 +470,18 @@ declare function defineEngineConfig(config: EngineConfig): EngineConfig;
445
470
  declare function createEngine(config?: EngineConfig): Promise<Engine>;
446
471
  declare class Engine {
447
472
  config: ResolvedEngineConfig;
473
+ pluginHooks: {
474
+ configureRawConfig: (plugins: _pikacss_core.EnginePlugin[], payload: EngineConfig) => Promise<EngineConfig>;
475
+ rawConfigConfigured: (plugins: _pikacss_core.EnginePlugin[], payload: EngineConfig) => void;
476
+ configureResolvedConfig: (plugins: _pikacss_core.EnginePlugin[], payload: ResolvedEngineConfig) => Promise<ResolvedEngineConfig>;
477
+ configureEngine: (plugins: _pikacss_core.EnginePlugin[], payload: Engine) => Promise<Engine>;
478
+ transformSelectors: (plugins: _pikacss_core.EnginePlugin[], payload: string[]) => Promise<string[]>;
479
+ transformStyleItems: (plugins: _pikacss_core.EnginePlugin[], payload: StyleItem$1[]) => Promise<StyleItem$1[]>;
480
+ transformStyleDefinitions: (plugins: _pikacss_core.EnginePlugin[], payload: StyleDefinition$1[]) => Promise<StyleDefinition$1[]>;
481
+ preflightUpdated: (plugins: _pikacss_core.EnginePlugin[]) => void;
482
+ atomicStyleAdded: (plugins: _pikacss_core.EnginePlugin[], payload: AtomicStyle) => AtomicStyle;
483
+ autocompleteConfigUpdated: (plugins: _pikacss_core.EnginePlugin[]) => void;
484
+ };
448
485
  extract: ExtractFn;
449
486
  store: {
450
487
  atomicStyleIds: Map<string, string>;
package/dist/index.d.mts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as _pikacss_core from '@pikacss/core';
1
2
  import * as CSS from 'csstype';
2
3
 
3
4
  interface ImportantConfig {
@@ -188,6 +189,8 @@ declare class ShortcutResolver extends AbstractResolver<StyleItem$1[]> {
188
189
  resolve(shortcut: string): Promise<StyleItem$1[]>;
189
190
  }
190
191
 
192
+ type ResolvedCSSProperty = keyof ResolvedCSSProperties;
193
+ type ResolvedCSSVarProperty = ResolvedCSSProperty extends infer T ? T extends `--${string}` ? T : never : never;
191
194
  interface VariableAutocomplete {
192
195
  /**
193
196
  * Specify the properties that the variable can be used as a value of.
@@ -202,39 +205,59 @@ interface VariableAutocomplete {
202
205
  */
203
206
  asProperty?: boolean;
204
207
  }
205
- type Variable = string | [name: string, value?: string, autocomplete?: VariableAutocomplete, pruneUnused?: boolean] | {
206
- name: string;
207
- value?: string;
208
+ interface VariableObject {
209
+ value?: ResolvedCSSProperties[`--${string}`];
208
210
  autocomplete?: VariableAutocomplete;
209
211
  pruneUnused?: boolean;
212
+ }
213
+ type Variable = ResolvedCSSProperties[`--${string}`] | VariableObject;
214
+ type VariablesDefinition = {
215
+ [key in UnionString | ResolvedSelector | (`--${string}` & {}) | ResolvedCSSVarProperty]?: Variable | VariablesDefinition;
210
216
  };
211
217
  interface VariablesConfig {
212
218
  /**
213
219
  * Define CSS variables with support for static values and autocomplete configuration.
214
220
  *
215
- * @default []
221
+ * @default {}
216
222
  * @example
217
223
  * ```ts
218
224
  * {
219
- * variables: [
220
- * // Basic usage
221
- * ['primary', '#ff0000'],
222
- * // With autocomplete configuration
223
- * ['accent', '#00ff00', {
224
- * asValueOf: ['color', 'background-color'],
225
- * asProperty: true
226
- * }]
227
- * ]
225
+ * variables: {
226
+ * // The variable with value "null" will not be included in the final CSS, but can be used in autocompletion.
227
+ * '--external-var': null,
228
+ *
229
+ * '--color-bg': '#fff',
230
+ * '--color-text': '#000',
231
+ *
232
+ * '[data-theme="dark"]': {
233
+ * '--color-bg': '#000',
234
+ * '--color-text': '#fff',
235
+ * },
236
+ * },
228
237
  * }
229
238
  * ```
230
239
  */
231
- variables: Variable[];
240
+ variables: VariablesDefinition;
232
241
  /**
233
242
  * Whether to prune unused variables from the final CSS.
234
243
  *
235
244
  * @default true
236
245
  */
237
246
  pruneUnused?: boolean;
247
+ /**
248
+ * A list of CSS variables that should always be included in the final CSS, you can use this to prevent certain variables from being pruned.
249
+ *
250
+ * @default []
251
+ * @example
252
+ * ```ts
253
+ * {
254
+ * variables: {
255
+ * safeList: ['--external-var', '--color-bg', '--color-text'],
256
+ * },
257
+ * }
258
+ * ```
259
+ */
260
+ safeList?: ((`--${string}` & {}) | ResolvedCSSVarProperty)[];
238
261
  }
239
262
  declare module '@pikacss/core' {
240
263
  interface EngineConfig {
@@ -242,14 +265,15 @@ declare module '@pikacss/core' {
242
265
  }
243
266
  interface Engine {
244
267
  variables: {
245
- store: Map<string, ResolvedVariableConfig>;
246
- add: (...list: Variable[]) => void;
268
+ store: Map<string, ResolvedVariable[]>;
269
+ add: (variables: VariablesDefinition) => void;
247
270
  };
248
271
  }
249
272
  }
250
- interface ResolvedVariableConfig {
273
+ interface ResolvedVariable {
251
274
  name: string;
252
- value: string | Nullish;
275
+ value: PropertyValue;
276
+ selector: string[];
253
277
  pruneUnused: boolean;
254
278
  autocomplete: {
255
279
  asValueOf: string[];
@@ -273,42 +297,6 @@ type FromKebab<T extends string> = T extends `--${string}` ? T : T extends `-${i
273
297
  type GetValue<Obj extends Record<string, any>, K extends string> = (IsEqual<Obj, object> | IsEqual<Obj, {}> | IsEqual<Obj[K], unknown>) extends false ? Obj[K] : never;
274
298
  type ResolveFrom<T, Key extends string, I, Fallback extends I> = Key extends keyof T ? T[Key] extends I ? T[Key] : Fallback : Fallback;
275
299
 
276
- interface PikaAugment {
277
- }
278
- type PropertyValue = string | number | [value: string | number, fallback: (string | number)[]] | Nullish;
279
- type Properties$1 = Record<string, PropertyValue>;
280
- interface StyleDefinition$1 {
281
- [K: string]: PropertyValue | StyleDefinition$1 | StyleItem$1[];
282
- }
283
- type StyleItem$1 = string | StyleDefinition$1;
284
- interface ExtractedStyleContent {
285
- selector: string[];
286
- property: string;
287
- value: string[] | Nullish;
288
- }
289
- interface StyleContent {
290
- selector: string[];
291
- property: string;
292
- value: string[];
293
- }
294
- interface AtomicStyle {
295
- id: string;
296
- content: StyleContent;
297
- }
298
- interface CSSStyleBlockBody {
299
- properties: {
300
- property: string;
301
- value: string;
302
- }[];
303
- children?: CSSStyleBlocks;
304
- }
305
- type CSSStyleBlocks = Map<string, CSSStyleBlockBody>;
306
- type ResolvedSelector = ResolveFrom<PikaAugment, 'Selector', string, string>;
307
- type ResolvedCSSProperty = ResolveFrom<PikaAugment, 'CSSProperty', string, string>;
308
- type ResolvedProperties = ResolveFrom<PikaAugment, 'Properties', any, Properties$1>;
309
- type ResolvedStyleDefinition = ResolveFrom<PikaAugment, 'StyleDefinition', any, StyleDefinition$1>;
310
- type ResolvedStyleItem = ResolveFrom<PikaAugment, 'StyleItem', any, StyleItem$1>;
311
-
312
300
  interface ResolvedAutocompleteConfig {
313
301
  selectors: Set<string>;
314
302
  styleItemStrings: Set<string>;
@@ -334,7 +322,6 @@ type EmptyAutocomplete = DefineAutocomplete<{
334
322
  PropertiesValue: never;
335
323
  CssPropertiesValue: never;
336
324
  }>;
337
- type ResolvedAutocomplete = ResolveFrom<PikaAugment, 'Autocomplete', _Autocomplete, EmptyAutocomplete>;
338
325
 
339
326
  type DefineHooks<Hooks extends Record<string, [type: 'sync' | 'async', payload: any, returnValue?: any]>> = Hooks;
340
327
  type EngineHooksDefinition = DefineHooks<{
@@ -358,10 +345,48 @@ interface EnginePlugin extends EnginePluginHooksOptions {
358
345
  }
359
346
  declare function defineEnginePlugin(plugin: EnginePlugin): EnginePlugin;
360
347
 
348
+ interface PikaAugment {
349
+ }
350
+ type PropertyValue = string | number | [value: string | number, fallback: (string | number)[]] | Nullish;
351
+ type Properties$1 = Record<string, PropertyValue>;
352
+ interface StyleDefinition$1 {
353
+ [K: string]: PropertyValue | StyleDefinition$1 | StyleItem$1[];
354
+ }
355
+ type StyleItem$1 = string | StyleDefinition$1;
356
+ interface ExtractedStyleContent {
357
+ selector: string[];
358
+ property: string;
359
+ value: string[] | Nullish;
360
+ }
361
+ interface StyleContent {
362
+ selector: string[];
363
+ property: string;
364
+ value: string[];
365
+ }
366
+ interface AtomicStyle {
367
+ id: string;
368
+ content: StyleContent;
369
+ }
370
+ interface CSSStyleBlockBody {
371
+ properties: {
372
+ property: string;
373
+ value: string;
374
+ }[];
375
+ children?: CSSStyleBlocks;
376
+ }
377
+ type CSSStyleBlocks = Map<string, CSSStyleBlockBody>;
378
+
379
+ type ResolvedAutocomplete = ResolveFrom<PikaAugment, 'Autocomplete', _Autocomplete, EmptyAutocomplete>;
380
+ type ResolvedSelector = ResolveFrom<PikaAugment, 'Selector', string, string>;
381
+ type ResolvedProperties = ResolveFrom<PikaAugment, 'Properties', any, Properties$1>;
382
+ type ResolvedCSSProperties = Omit<ResolvedProperties, ResolvedAutocomplete['ExtraProperty']>;
383
+ type ResolvedStyleDefinition = ResolveFrom<PikaAugment, 'StyleDefinition', any, StyleDefinition$1>;
384
+ type ResolvedStyleItem = ResolveFrom<PikaAugment, 'StyleItem', any, StyleItem$1>;
385
+
361
386
  type PreflightDefinition = {
362
- [selector in UnionString | ResolvedSelector]?: ResolvedProperties | PreflightDefinition;
387
+ [selector in UnionString | ResolvedSelector]?: ResolvedCSSProperties | PreflightDefinition;
363
388
  };
364
- type PreflightFn = (engine: Engine, isFormatted: boolean) => string | PreflightDefinition;
389
+ type PreflightFn = (engine: Engine, isFormatted: boolean) => Awaitable<string | PreflightDefinition>;
365
390
  /**
366
391
  * PreflightConfig can be a string or a function that returns a string.
367
392
  *
@@ -445,6 +470,18 @@ declare function defineEngineConfig(config: EngineConfig): EngineConfig;
445
470
  declare function createEngine(config?: EngineConfig): Promise<Engine>;
446
471
  declare class Engine {
447
472
  config: ResolvedEngineConfig;
473
+ pluginHooks: {
474
+ configureRawConfig: (plugins: _pikacss_core.EnginePlugin[], payload: EngineConfig) => Promise<EngineConfig>;
475
+ rawConfigConfigured: (plugins: _pikacss_core.EnginePlugin[], payload: EngineConfig) => void;
476
+ configureResolvedConfig: (plugins: _pikacss_core.EnginePlugin[], payload: ResolvedEngineConfig) => Promise<ResolvedEngineConfig>;
477
+ configureEngine: (plugins: _pikacss_core.EnginePlugin[], payload: Engine) => Promise<Engine>;
478
+ transformSelectors: (plugins: _pikacss_core.EnginePlugin[], payload: string[]) => Promise<string[]>;
479
+ transformStyleItems: (plugins: _pikacss_core.EnginePlugin[], payload: StyleItem$1[]) => Promise<StyleItem$1[]>;
480
+ transformStyleDefinitions: (plugins: _pikacss_core.EnginePlugin[], payload: StyleDefinition$1[]) => Promise<StyleDefinition$1[]>;
481
+ preflightUpdated: (plugins: _pikacss_core.EnginePlugin[]) => void;
482
+ atomicStyleAdded: (plugins: _pikacss_core.EnginePlugin[], payload: AtomicStyle) => AtomicStyle;
483
+ autocompleteConfigUpdated: (plugins: _pikacss_core.EnginePlugin[]) => void;
484
+ };
448
485
  extract: ExtractFn;
449
486
  store: {
450
487
  atomicStyleIds: Map<string, string>;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as _pikacss_core from '@pikacss/core';
1
2
  import * as CSS from 'csstype';
2
3
 
3
4
  interface ImportantConfig {
@@ -188,6 +189,8 @@ declare class ShortcutResolver extends AbstractResolver<StyleItem$1[]> {
188
189
  resolve(shortcut: string): Promise<StyleItem$1[]>;
189
190
  }
190
191
 
192
+ type ResolvedCSSProperty = keyof ResolvedCSSProperties;
193
+ type ResolvedCSSVarProperty = ResolvedCSSProperty extends infer T ? T extends `--${string}` ? T : never : never;
191
194
  interface VariableAutocomplete {
192
195
  /**
193
196
  * Specify the properties that the variable can be used as a value of.
@@ -202,39 +205,59 @@ interface VariableAutocomplete {
202
205
  */
203
206
  asProperty?: boolean;
204
207
  }
205
- type Variable = string | [name: string, value?: string, autocomplete?: VariableAutocomplete, pruneUnused?: boolean] | {
206
- name: string;
207
- value?: string;
208
+ interface VariableObject {
209
+ value?: ResolvedCSSProperties[`--${string}`];
208
210
  autocomplete?: VariableAutocomplete;
209
211
  pruneUnused?: boolean;
212
+ }
213
+ type Variable = ResolvedCSSProperties[`--${string}`] | VariableObject;
214
+ type VariablesDefinition = {
215
+ [key in UnionString | ResolvedSelector | (`--${string}` & {}) | ResolvedCSSVarProperty]?: Variable | VariablesDefinition;
210
216
  };
211
217
  interface VariablesConfig {
212
218
  /**
213
219
  * Define CSS variables with support for static values and autocomplete configuration.
214
220
  *
215
- * @default []
221
+ * @default {}
216
222
  * @example
217
223
  * ```ts
218
224
  * {
219
- * variables: [
220
- * // Basic usage
221
- * ['primary', '#ff0000'],
222
- * // With autocomplete configuration
223
- * ['accent', '#00ff00', {
224
- * asValueOf: ['color', 'background-color'],
225
- * asProperty: true
226
- * }]
227
- * ]
225
+ * variables: {
226
+ * // The variable with value "null" will not be included in the final CSS, but can be used in autocompletion.
227
+ * '--external-var': null,
228
+ *
229
+ * '--color-bg': '#fff',
230
+ * '--color-text': '#000',
231
+ *
232
+ * '[data-theme="dark"]': {
233
+ * '--color-bg': '#000',
234
+ * '--color-text': '#fff',
235
+ * },
236
+ * },
228
237
  * }
229
238
  * ```
230
239
  */
231
- variables: Variable[];
240
+ variables: VariablesDefinition;
232
241
  /**
233
242
  * Whether to prune unused variables from the final CSS.
234
243
  *
235
244
  * @default true
236
245
  */
237
246
  pruneUnused?: boolean;
247
+ /**
248
+ * A list of CSS variables that should always be included in the final CSS, you can use this to prevent certain variables from being pruned.
249
+ *
250
+ * @default []
251
+ * @example
252
+ * ```ts
253
+ * {
254
+ * variables: {
255
+ * safeList: ['--external-var', '--color-bg', '--color-text'],
256
+ * },
257
+ * }
258
+ * ```
259
+ */
260
+ safeList?: ((`--${string}` & {}) | ResolvedCSSVarProperty)[];
238
261
  }
239
262
  declare module '@pikacss/core' {
240
263
  interface EngineConfig {
@@ -242,14 +265,15 @@ declare module '@pikacss/core' {
242
265
  }
243
266
  interface Engine {
244
267
  variables: {
245
- store: Map<string, ResolvedVariableConfig>;
246
- add: (...list: Variable[]) => void;
268
+ store: Map<string, ResolvedVariable[]>;
269
+ add: (variables: VariablesDefinition) => void;
247
270
  };
248
271
  }
249
272
  }
250
- interface ResolvedVariableConfig {
273
+ interface ResolvedVariable {
251
274
  name: string;
252
- value: string | Nullish;
275
+ value: PropertyValue;
276
+ selector: string[];
253
277
  pruneUnused: boolean;
254
278
  autocomplete: {
255
279
  asValueOf: string[];
@@ -273,42 +297,6 @@ type FromKebab<T extends string> = T extends `--${string}` ? T : T extends `-${i
273
297
  type GetValue<Obj extends Record<string, any>, K extends string> = (IsEqual<Obj, object> | IsEqual<Obj, {}> | IsEqual<Obj[K], unknown>) extends false ? Obj[K] : never;
274
298
  type ResolveFrom<T, Key extends string, I, Fallback extends I> = Key extends keyof T ? T[Key] extends I ? T[Key] : Fallback : Fallback;
275
299
 
276
- interface PikaAugment {
277
- }
278
- type PropertyValue = string | number | [value: string | number, fallback: (string | number)[]] | Nullish;
279
- type Properties$1 = Record<string, PropertyValue>;
280
- interface StyleDefinition$1 {
281
- [K: string]: PropertyValue | StyleDefinition$1 | StyleItem$1[];
282
- }
283
- type StyleItem$1 = string | StyleDefinition$1;
284
- interface ExtractedStyleContent {
285
- selector: string[];
286
- property: string;
287
- value: string[] | Nullish;
288
- }
289
- interface StyleContent {
290
- selector: string[];
291
- property: string;
292
- value: string[];
293
- }
294
- interface AtomicStyle {
295
- id: string;
296
- content: StyleContent;
297
- }
298
- interface CSSStyleBlockBody {
299
- properties: {
300
- property: string;
301
- value: string;
302
- }[];
303
- children?: CSSStyleBlocks;
304
- }
305
- type CSSStyleBlocks = Map<string, CSSStyleBlockBody>;
306
- type ResolvedSelector = ResolveFrom<PikaAugment, 'Selector', string, string>;
307
- type ResolvedCSSProperty = ResolveFrom<PikaAugment, 'CSSProperty', string, string>;
308
- type ResolvedProperties = ResolveFrom<PikaAugment, 'Properties', any, Properties$1>;
309
- type ResolvedStyleDefinition = ResolveFrom<PikaAugment, 'StyleDefinition', any, StyleDefinition$1>;
310
- type ResolvedStyleItem = ResolveFrom<PikaAugment, 'StyleItem', any, StyleItem$1>;
311
-
312
300
  interface ResolvedAutocompleteConfig {
313
301
  selectors: Set<string>;
314
302
  styleItemStrings: Set<string>;
@@ -334,7 +322,6 @@ type EmptyAutocomplete = DefineAutocomplete<{
334
322
  PropertiesValue: never;
335
323
  CssPropertiesValue: never;
336
324
  }>;
337
- type ResolvedAutocomplete = ResolveFrom<PikaAugment, 'Autocomplete', _Autocomplete, EmptyAutocomplete>;
338
325
 
339
326
  type DefineHooks<Hooks extends Record<string, [type: 'sync' | 'async', payload: any, returnValue?: any]>> = Hooks;
340
327
  type EngineHooksDefinition = DefineHooks<{
@@ -358,10 +345,48 @@ interface EnginePlugin extends EnginePluginHooksOptions {
358
345
  }
359
346
  declare function defineEnginePlugin(plugin: EnginePlugin): EnginePlugin;
360
347
 
348
+ interface PikaAugment {
349
+ }
350
+ type PropertyValue = string | number | [value: string | number, fallback: (string | number)[]] | Nullish;
351
+ type Properties$1 = Record<string, PropertyValue>;
352
+ interface StyleDefinition$1 {
353
+ [K: string]: PropertyValue | StyleDefinition$1 | StyleItem$1[];
354
+ }
355
+ type StyleItem$1 = string | StyleDefinition$1;
356
+ interface ExtractedStyleContent {
357
+ selector: string[];
358
+ property: string;
359
+ value: string[] | Nullish;
360
+ }
361
+ interface StyleContent {
362
+ selector: string[];
363
+ property: string;
364
+ value: string[];
365
+ }
366
+ interface AtomicStyle {
367
+ id: string;
368
+ content: StyleContent;
369
+ }
370
+ interface CSSStyleBlockBody {
371
+ properties: {
372
+ property: string;
373
+ value: string;
374
+ }[];
375
+ children?: CSSStyleBlocks;
376
+ }
377
+ type CSSStyleBlocks = Map<string, CSSStyleBlockBody>;
378
+
379
+ type ResolvedAutocomplete = ResolveFrom<PikaAugment, 'Autocomplete', _Autocomplete, EmptyAutocomplete>;
380
+ type ResolvedSelector = ResolveFrom<PikaAugment, 'Selector', string, string>;
381
+ type ResolvedProperties = ResolveFrom<PikaAugment, 'Properties', any, Properties$1>;
382
+ type ResolvedCSSProperties = Omit<ResolvedProperties, ResolvedAutocomplete['ExtraProperty']>;
383
+ type ResolvedStyleDefinition = ResolveFrom<PikaAugment, 'StyleDefinition', any, StyleDefinition$1>;
384
+ type ResolvedStyleItem = ResolveFrom<PikaAugment, 'StyleItem', any, StyleItem$1>;
385
+
361
386
  type PreflightDefinition = {
362
- [selector in UnionString | ResolvedSelector]?: ResolvedProperties | PreflightDefinition;
387
+ [selector in UnionString | ResolvedSelector]?: ResolvedCSSProperties | PreflightDefinition;
363
388
  };
364
- type PreflightFn = (engine: Engine, isFormatted: boolean) => string | PreflightDefinition;
389
+ type PreflightFn = (engine: Engine, isFormatted: boolean) => Awaitable<string | PreflightDefinition>;
365
390
  /**
366
391
  * PreflightConfig can be a string or a function that returns a string.
367
392
  *
@@ -445,6 +470,18 @@ declare function defineEngineConfig(config: EngineConfig): EngineConfig;
445
470
  declare function createEngine(config?: EngineConfig): Promise<Engine>;
446
471
  declare class Engine {
447
472
  config: ResolvedEngineConfig;
473
+ pluginHooks: {
474
+ configureRawConfig: (plugins: _pikacss_core.EnginePlugin[], payload: EngineConfig) => Promise<EngineConfig>;
475
+ rawConfigConfigured: (plugins: _pikacss_core.EnginePlugin[], payload: EngineConfig) => void;
476
+ configureResolvedConfig: (plugins: _pikacss_core.EnginePlugin[], payload: ResolvedEngineConfig) => Promise<ResolvedEngineConfig>;
477
+ configureEngine: (plugins: _pikacss_core.EnginePlugin[], payload: Engine) => Promise<Engine>;
478
+ transformSelectors: (plugins: _pikacss_core.EnginePlugin[], payload: string[]) => Promise<string[]>;
479
+ transformStyleItems: (plugins: _pikacss_core.EnginePlugin[], payload: StyleItem$1[]) => Promise<StyleItem$1[]>;
480
+ transformStyleDefinitions: (plugins: _pikacss_core.EnginePlugin[], payload: StyleDefinition$1[]) => Promise<StyleDefinition$1[]>;
481
+ preflightUpdated: (plugins: _pikacss_core.EnginePlugin[]) => void;
482
+ atomicStyleAdded: (plugins: _pikacss_core.EnginePlugin[], payload: AtomicStyle) => AtomicStyle;
483
+ autocompleteConfigUpdated: (plugins: _pikacss_core.EnginePlugin[]) => void;
484
+ };
448
485
  extract: ExtractFn;
449
486
  store: {
450
487
  atomicStyleIds: Map<string, string>;
package/dist/index.mjs CHANGED
@@ -275,7 +275,7 @@ function keyframes() {
275
275
  return defineEnginePlugin({
276
276
  name: "core:keyframes",
277
277
  rawConfigConfigured(config) {
278
- resolveKeyframesConfig = createResolveConfigFn$1({
278
+ resolveKeyframesConfig = createResolveConfigFn({
279
279
  pruneUnused: config.keyframes?.pruneUnused
280
280
  });
281
281
  configList = config.keyframes?.keyframes ?? [];
@@ -298,7 +298,7 @@ function keyframes() {
298
298
  }
299
299
  };
300
300
  engine.keyframes.add(...configList);
301
- engine.addPreflight((engine2, isFormatted) => {
301
+ engine.addPreflight((engine2) => {
302
302
  const maybeUsedName = /* @__PURE__ */ new Set();
303
303
  engine2.store.atomicStyles.forEach(({ content: { property, value } }) => {
304
304
  if (property === "animationName") {
@@ -314,30 +314,22 @@ function keyframes() {
314
314
  });
315
315
  }
316
316
  });
317
- return renderCSSStyleBlocks(
318
- new Map(Array.from(engine2.keyframes.store.entries()).filter(([name, { pruneUnused }]) => pruneUnused === false || maybeUsedName.has(name)).map(([name, { frames }]) => [
319
- `@keyframes ${name}`,
320
- {
321
- properties: [],
322
- children: new Map(Object.entries(frames).map(([frame, properties]) => [
323
- frame,
324
- {
325
- properties: Object.entries(properties).filter(([_, value]) => isNotNullish(value)).flatMap(([property, value]) => {
326
- if (Array.isArray(value))
327
- return value.map((v) => ({ property, value: String(v) }));
328
- return { property, value: String(value) };
329
- })
330
- }
331
- ]))
332
- }
333
- ])),
334
- isFormatted
335
- );
317
+ const maybeUsedKeyframes = Array.from(engine2.keyframes.store.values()).filter(({ name, frames, pruneUnused }) => (pruneUnused === false || maybeUsedName.has(name)) && frames != null);
318
+ const preflightDefinition = {};
319
+ maybeUsedKeyframes.forEach(({ name, frames }) => {
320
+ preflightDefinition[`@keyframes ${name}`] = Object.fromEntries(
321
+ Object.entries(frames).map(([frame, properties]) => [
322
+ frame,
323
+ properties
324
+ ])
325
+ );
326
+ });
327
+ return preflightDefinition;
336
328
  });
337
329
  }
338
330
  });
339
331
  }
340
- function createResolveConfigFn$1({
332
+ function createResolveConfigFn({
341
333
  pruneUnused: defaultPruneUnused = true
342
334
  } = {}) {
343
335
  return function resolveKeyframesConfig(config) {
@@ -684,67 +676,92 @@ function resolveShortcutConfig(config) {
684
676
  }
685
677
 
686
678
  function variables() {
687
- let resolveVariableConfig;
688
- let configList;
679
+ let resolveVariables;
680
+ let rawVariables;
681
+ let safeSet;
689
682
  return defineEnginePlugin({
690
683
  name: "core:variables",
691
684
  rawConfigConfigured(config) {
692
- resolveVariableConfig = createResolveConfigFn({
685
+ resolveVariables = createResolveVariablesFn({
693
686
  pruneUnused: config.variables?.pruneUnused
694
687
  });
695
- configList = config.variables?.variables ?? [];
688
+ rawVariables = config.variables?.variables ?? {};
689
+ safeSet = new Set(config.variables?.safeList ?? []);
696
690
  },
697
691
  configureEngine(engine) {
698
692
  engine.variables = {
699
693
  store: /* @__PURE__ */ new Map(),
700
- add: (...list) => {
701
- list.forEach((config) => {
702
- const resolved = resolveVariableConfig(config);
703
- const { name: _name, value, autocomplete: { asValueOf, asProperty } } = resolved;
704
- const name = normalizeVariableName(_name);
694
+ add: (variables2) => {
695
+ const list = resolveVariables(variables2);
696
+ list.forEach((resolved) => {
697
+ const { name, value, autocomplete: { asValueOf, asProperty } } = resolved;
705
698
  asValueOf.forEach((p) => {
706
699
  if (p !== "-")
707
700
  engine.appendAutocompleteCssPropertyValues(p, `var(${name})`);
708
701
  });
709
702
  if (asProperty)
710
703
  engine.appendAutocompleteExtraCssProperties(name);
711
- if (value != null)
712
- engine.variables.store.set(name, resolved);
704
+ if (value != null) {
705
+ const list2 = engine.variables.store.get(name) ?? [];
706
+ list2.push(resolved);
707
+ engine.variables.store.set(name, list2);
708
+ }
713
709
  });
714
710
  engine.notifyPreflightUpdated();
715
711
  }
716
712
  };
717
- engine.variables.add(...configList);
718
- engine.addPreflight((engine2, isFormatted) => {
713
+ engine.variables.add(rawVariables);
714
+ engine.addPreflight(async (engine2) => {
719
715
  const used = /* @__PURE__ */ new Set();
720
716
  engine2.store.atomicStyles.forEach(({ content: { value } }) => {
721
717
  value.flatMap(extractUsedVarNames).forEach((name) => used.add(normalizeVariableName(name)));
722
718
  });
723
- return renderCSSStyleBlocks(
724
- /* @__PURE__ */ new Map([[
725
- ":root",
726
- {
727
- properties: Array.from(engine2.variables.store.entries()).filter(([name, { pruneUnused, value }]) => (pruneUnused === false || used.has(name)) && value != null).map(([name, { value }]) => ({ property: name, value }))
728
- }
729
- ]]),
730
- isFormatted
731
- );
719
+ const usedVariables = Array.from(engine2.variables.store.values()).flat().filter(({ name, pruneUnused, value }) => (safeSet.has(name) || pruneUnused === false || used.has(name)) && value != null);
720
+ const preflightDefinition = {};
721
+ for (const { name, value, selector: _selector } of usedVariables) {
722
+ const selector = await engine2.pluginHooks.transformSelectors(engine2.config.plugins, _selector);
723
+ let current = preflightDefinition;
724
+ selector.forEach((s) => {
725
+ current[s] ||= {};
726
+ current = current[s];
727
+ });
728
+ Object.assign(current, { [name]: value });
729
+ }
730
+ return preflightDefinition;
732
731
  });
733
732
  }
734
733
  });
735
734
  }
736
- function createResolveConfigFn({
735
+ function createResolveVariablesFn({
737
736
  pruneUnused: defaultPruneUnused = true
738
737
  } = {}) {
739
- return function resolveVariableConfig(config) {
740
- if (typeof config === "string")
741
- return { name: config, value: null, autocomplete: { asValueOf: ["*"], asProperty: true }, pruneUnused: defaultPruneUnused };
742
- if (Array.isArray(config)) {
743
- const [name2, value2, { asValueOf: asValueOf2 = "*", asProperty: asProperty2 = true } = {}, pruneUnused2 = defaultPruneUnused] = config;
744
- return { name: name2, value: value2, autocomplete: { asValueOf: [asValueOf2].flat(), asProperty: asProperty2 }, pruneUnused: pruneUnused2 };
738
+ function _resolveVariables(variables2, levels, result) {
739
+ for (const [key, value] of Object.entries(variables2)) {
740
+ if (key.startsWith("--")) {
741
+ const isObject = typeof value === "object" && value !== null && !Array.isArray(value);
742
+ const {
743
+ value: varValue,
744
+ autocomplete = {},
745
+ pruneUnused = defaultPruneUnused
746
+ } = isObject ? value : { value };
747
+ result.push({
748
+ name: key,
749
+ value: varValue,
750
+ selector: levels.length > 0 ? levels : [":root"],
751
+ autocomplete: {
752
+ asValueOf: autocomplete.asValueOf ? [autocomplete.asValueOf].flat() : ["*"],
753
+ asProperty: autocomplete.asProperty ?? true
754
+ },
755
+ pruneUnused
756
+ });
757
+ } else {
758
+ _resolveVariables(value, [...levels, key], result);
759
+ }
745
760
  }
746
- const { name, value, autocomplete: { asValueOf = "*", asProperty = true } = {}, pruneUnused = defaultPruneUnused } = config;
747
- return { name, value, autocomplete: { asValueOf: [asValueOf].flat(), asProperty }, pruneUnused };
761
+ return result;
762
+ }
763
+ return function resolveVariables(variables2) {
764
+ return _resolveVariables(variables2, [], []);
748
765
  };
749
766
  }
750
767
  const VAR_NAME_RE = /var\((--[\w-]+)/g;
@@ -798,6 +815,7 @@ async function createEngine(config = {}) {
798
815
  }
799
816
  class Engine {
800
817
  config;
818
+ pluginHooks = hooks;
801
819
  extract;
802
820
  store = {
803
821
  atomicStyleIds: /* @__PURE__ */ new Map(),
@@ -876,13 +894,13 @@ class Engine {
876
894
  }
877
895
  async renderPreflights(isFormatted) {
878
896
  const lineEnd = isFormatted ? "\n" : "";
879
- return (await Promise.all(this.config.preflights.map((p) => {
880
- const result = p(this, isFormatted);
897
+ return (await Promise.all(this.config.preflights.map(async (p) => {
898
+ const result = await p(this, isFormatted);
881
899
  if (typeof result === "string")
882
900
  return result;
883
- return renderPreflight({
901
+ return renderPreflightDefinition({
884
902
  engine: this,
885
- preflight: result,
903
+ preflightDefinition: result,
886
904
  isFormatted
887
905
  });
888
906
  }))).join(lineEnd);
@@ -1006,7 +1024,7 @@ function renderAtomicStyles(payload) {
1006
1024
  });
1007
1025
  return renderCSSStyleBlocks(blocks, isFormatted);
1008
1026
  }
1009
- async function _renderPreflight({
1027
+ async function _renderPreflightDefinition({
1010
1028
  engine,
1011
1029
  preflightDefinition,
1012
1030
  blocks = /* @__PURE__ */ new Map()
@@ -1039,7 +1057,7 @@ async function _renderPreflight({
1039
1057
  } else {
1040
1058
  currentBlockBody.children ||= /* @__PURE__ */ new Map();
1041
1059
  currentBlockBody.children.set(k, currentBlockBody.children.get(k) || { properties: [] });
1042
- _renderPreflight({
1060
+ _renderPreflightDefinition({
1043
1061
  engine,
1044
1062
  preflightDefinition: { [k]: v },
1045
1063
  blocks: currentBlockBody.children
@@ -1049,11 +1067,11 @@ async function _renderPreflight({
1049
1067
  }
1050
1068
  return blocks;
1051
1069
  }
1052
- async function renderPreflight(payload) {
1053
- const { engine, preflight, isFormatted } = payload;
1054
- const blocks = await _renderPreflight({
1070
+ async function renderPreflightDefinition(payload) {
1071
+ const { engine, preflightDefinition, isFormatted } = payload;
1072
+ const blocks = await _renderPreflightDefinition({
1055
1073
  engine,
1056
- preflightDefinition: preflight
1074
+ preflightDefinition
1057
1075
  });
1058
1076
  return renderCSSStyleBlocks(blocks, isFormatted);
1059
1077
  }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.0.28",
7
+ "version": "0.0.29",
8
8
  "author": "DevilTea <ch19980814@gmail.com>",
9
9
  "license": "MIT",
10
10
  "repository": {