@teacss/postcss 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,7 +1,7 @@
1
- MIT License
1
+ # MIT License
2
2
 
3
- Copyright (c) 2022 WorkOS
4
- Copyright (c) 2024 BillGO
3
+ Copyright (c) 2021-PRESENT Anthony Fu <https://github.com/antfu>
4
+ Copyright (c) 2026-PRESENT Billgo <hi@billgo.me>
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
7
  of this software and associated documentation files (the "Software"), to deal
@@ -19,4 +19,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
19
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
20
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
21
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- SOFTWARE.
22
+ SOFTWARE.
package/README.md CHANGED
@@ -1 +1,57 @@
1
- # @teacss/postcss-breakpoints
1
+ # @teacss/postcss
2
+
3
+ **PostCSS integration for TeaCSS.**
4
+
5
+ ## Purpose
6
+
7
+ The plugin runs TeaCSS during the PostCSS pipeline, transforms TeaCSS CSS
8
+ directives, and injects generated utilities into the current stylesheet.
9
+
10
+ Use this package when PostCSS is the application's CSS build boundary. It owns
11
+ TeaCSS's PostCSS plugin behavior and reports file and directory dependencies to
12
+ the surrounding runner; the runner remains responsible for file watching and
13
+ rebuilds. Projects whose Vite, Astro, Rsbuild, or Bun integration already owns
14
+ TeaCSS generation do not need to add this plugin as a second pipeline.
15
+
16
+ PostCSS is a host peer rather than a bundled runtime. Install one compatible
17
+ PostCSS 8 copy in the application:
18
+
19
+ ```sh
20
+ bun add teacss
21
+ bun add -d @teacss/postcss postcss
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```js
27
+ import { pluginTeacss } from "teacss/postcss";
28
+
29
+ export default {
30
+ plugins: [pluginTeacss()],
31
+ };
32
+ ```
33
+
34
+ ```css
35
+ @preset "standard";
36
+ @source "./src/**/*.{ts,tsx,html}";
37
+ @custom { --color-brand-500: #0f766e; }
38
+ @teacss;
39
+ ```
40
+
41
+ Use `@teacss;` to choose where generated utilities are injected.
42
+ When a stylesheet has multiple `@teacss` insertion points, each generated layer
43
+ is emitted at most once across bare, `all`, explicit, and negated layer forms.
44
+ Use `@custom {}` to define theme values in the CSS entry; PostCSS resolves
45
+ `theme("...")` in declaration values but does not provide an `@theme` at-rule.
46
+ The plugin reports both file dependencies and stable directory dependencies for
47
+ positive `@source` globs, so PostCSS runners can rebuild when a new matching file
48
+ is created. If a glob's static root does not exist yet, the directory dependency
49
+ falls back to its nearest existing parent. Relative `@source` globs resolve from
50
+ the CSS entry directory, including when the discovered entry is nested at
51
+ `src/index.css`.
52
+
53
+ ## Status
54
+
55
+ Pre-1.0. Install `@teacss/postcss` beside `teacss`, then use the stable
56
+ `teacss/postcss` facade subpath in applications. Integration authors may import
57
+ `@teacss/postcss` directly when they intentionally do not use the facade.
package/dist/esm.d.mts ADDED
@@ -0,0 +1,21 @@
1
+ import { UserConfig } from "@teacss/core";
2
+ import { Result, Root } from "postcss";
3
+ //#region src/types.d.ts
4
+ interface TeacssPostcssPluginOptions {
5
+ content?: (string | {
6
+ raw: string;
7
+ extension: string;
8
+ })[];
9
+ directiveMap?: {
10
+ apply?: string;
11
+ screen?: string;
12
+ teacss?: string;
13
+ };
14
+ cwd?: string;
15
+ configOrPath?: string | UserConfig;
16
+ }
17
+ //#endregion
18
+ //#region src/esm.d.ts
19
+ declare function createPlugin(options: TeacssPostcssPluginOptions): (root: Root, result: Result) => Promise<void>;
20
+ //#endregion
21
+ export { createPlugin };
package/dist/esm.mjs ADDED
@@ -0,0 +1,440 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import { dirname, extname, join, normalize, relative, resolve } from "node:path";
3
+ import process from "node:process";
4
+ import { createRecoveryConfigLoader, entryDiscoveryFiles, getConfigSourcesFromError } from "@teacss/config";
5
+ import { createGenerator, expandVariantGroup, splitClassTokens } from "@teacss/core";
6
+ import { hasIconFn, hasThemeFn } from "@teacss/rule-helpers";
7
+ import { defaultFilesystemGlobs } from "@teacss/runtime";
8
+ import postcss from "postcss";
9
+ import { glob, isDynamicPattern } from "tinyglobby";
10
+ import { formatMissingApplyTokens, missingApplyTokens, prepareApplyUtilities, renderStandaloneApplyUtility, resolveApplyTokens, resolveCssFunction, resolveScreenQuery } from "@teacss/directives/core";
11
+ import { generate, parse, walk } from "css-tree";
12
+ //#region src/apply.ts
13
+ async function parseApply(root, generator, directiveName) {
14
+ const rules = [];
15
+ const lastParentAfterNode = /* @__PURE__ */ new Map();
16
+ const applyHosts = /* @__PURE__ */ new Map();
17
+ root.walkAtRules(directiveName, (rule) => {
18
+ rules.push(rule);
19
+ });
20
+ const resolvedRules = await Promise.all(rules.map(async (rule) => {
21
+ const parsed = await resolveApplyTokens(splitClassTokens(expandVariantGroup(rule.params)), generator);
22
+ const missing = missingApplyTokens(parsed);
23
+ if (missing.length) throw rule.error(formatMissingApplyTokens(missing));
24
+ return {
25
+ parsed,
26
+ rule
27
+ };
28
+ }));
29
+ for (const { parsed, rule } of resolvedRules) {
30
+ const hostRule = rule.parent;
31
+ if (!hostRule) continue;
32
+ const source = rule.source;
33
+ const utils = prepareApplyUtilities(parsed, generator.parentOrders);
34
+ if (!utils.length) {
35
+ rule.remove();
36
+ continue;
37
+ }
38
+ const parentAfterNodes = [];
39
+ let applyHost;
40
+ for (const utility of utils) if (utility.kind === "standalone") {
41
+ if (!applyHost) {
42
+ applyHost = applyHosts.get(hostRule);
43
+ if (!applyHost) {
44
+ let prelude;
45
+ if (hostRule.type === "rule") prelude = parse(hostRule.selector, { context: "selectorList" });
46
+ else prelude = parse(hostRule.toString(), { context: "rule" }).prelude;
47
+ const selector = generate(prelude);
48
+ applyHost = {
49
+ prelude,
50
+ selector,
51
+ replacementSelector: selector
52
+ };
53
+ applyHosts.set(hostRule, applyHost);
54
+ }
55
+ }
56
+ const css = renderStandaloneApplyUtility(applyHost, utility);
57
+ const parsedCss = postcss.parse(css);
58
+ parsedCss.walkDecls((declaration) => {
59
+ declaration.source = source;
60
+ });
61
+ parentAfterNodes.push(...parsedCss.nodes);
62
+ } else {
63
+ const css = postcss.parse(utility.body);
64
+ css.walkDecls((declaration) => {
65
+ declaration.source = source;
66
+ });
67
+ hostRule.insertAfter(rule, css);
68
+ }
69
+ if (parentAfterNodes.length) {
70
+ const anchor = lastParentAfterNode.get(hostRule);
71
+ if (anchor) anchor.after(parentAfterNodes);
72
+ else hostRule.after(parentAfterNodes);
73
+ lastParentAfterNode.set(hostRule, parentAfterNodes.at(-1));
74
+ }
75
+ rule.remove();
76
+ if (hostRule.type === "rule" && !hostRule.nodes?.length) hostRule.remove();
77
+ }
78
+ }
79
+ //#endregion
80
+ //#region src/screen.ts
81
+ async function parseScreen(root, generator, directiveName) {
82
+ root.walkAtRules(directiveName, (rule) => {
83
+ const query = resolveScreenQuery(rule.params, generator.config.theme);
84
+ if (!query) return;
85
+ rule.name = "media";
86
+ rule.params = query;
87
+ });
88
+ }
89
+ //#endregion
90
+ //#region src/theme.ts
91
+ async function parseTheme(root, generator) {
92
+ const tasks = [];
93
+ root.walkDecls((decl) => {
94
+ if (!hasThemeFn(decl.value) && !hasIconFn(decl.value)) return;
95
+ tasks.push(transformDeclarationValue(decl.value, generator).then((value) => {
96
+ decl.value = value;
97
+ }));
98
+ });
99
+ await Promise.all(tasks);
100
+ }
101
+ async function transformDeclarationValue(value, generator) {
102
+ const replacements = [];
103
+ const tasks = [];
104
+ walk(parse(value, {
105
+ context: "value",
106
+ parseCustomProperty: true,
107
+ positions: true
108
+ }), function(node) {
109
+ if (node.type !== "Function" || node.name !== "theme" && node.name !== "icon" || !node.loc) return;
110
+ tasks.push(resolveCssFunction(generator, node, (start, end) => value.slice(start, end)).then((replacement) => {
111
+ if (replacement === void 0) return;
112
+ replacements.push({
113
+ start: node.loc.start.offset,
114
+ end: node.loc.end.offset,
115
+ value: replacement
116
+ });
117
+ }));
118
+ return this.skip;
119
+ });
120
+ await Promise.all(tasks);
121
+ return applyReplacements(value, replacements);
122
+ }
123
+ function applyReplacements(value, replacements) {
124
+ let output = value;
125
+ for (const replacement of replacements.sort((a, b) => b.start - a.start)) output = `${output.slice(0, replacement.start)}${replacement.value}${output.slice(replacement.end)}`;
126
+ return output;
127
+ }
128
+ //#endregion
129
+ //#region src/esm.ts
130
+ const DEFAULT_GENERATED_IGNORE = [
131
+ "**/dist/**",
132
+ "**/build/**",
133
+ "**/storybook-static/**"
134
+ ];
135
+ const MAX_CONFIG_STABILITY_ATTEMPTS = 5;
136
+ function stripQueryAndHash(id) {
137
+ return id.replace(/[?#].*$/, "");
138
+ }
139
+ async function existingDirectory(target) {
140
+ let current = target;
141
+ while (true) {
142
+ try {
143
+ if ((await stat(current)).isDirectory()) return current;
144
+ } catch (error) {
145
+ const code = error.code;
146
+ if (code !== "ENOENT" && code !== "ENOTDIR") throw error;
147
+ }
148
+ const parent = dirname(current);
149
+ if (parent === current) return current;
150
+ current = parent;
151
+ }
152
+ }
153
+ async function resolveDirectoryDependency(cwd, pattern, literal = false) {
154
+ if (pattern.startsWith("!")) return;
155
+ const absolute = resolve(cwd, pattern);
156
+ let staticPattern = pattern;
157
+ if (!literal) while (isDynamicPattern(staticPattern)) staticPattern = dirname(staticPattern);
158
+ let dir = resolve(cwd, staticPattern);
159
+ if (literal || staticPattern === pattern) dir = dirname(dir);
160
+ dir = await existingDirectory(dir);
161
+ return {
162
+ dir,
163
+ glob: relative(dir, absolute).replaceAll("\\", "/")
164
+ };
165
+ }
166
+ function fileSignature({ mtimeMs, ctimeMs, size, ino }) {
167
+ return `${mtimeMs}:${ctimeMs}:${size}:${ino}`;
168
+ }
169
+ async function readChangedFile(file, previousSignature) {
170
+ try {
171
+ const signature = fileSignature(await stat(file));
172
+ if (signature === previousSignature) return null;
173
+ return {
174
+ content: await readFile(file, "utf8"),
175
+ signature
176
+ };
177
+ } catch (error) {
178
+ if (error.code === "ENOENT") return;
179
+ throw error;
180
+ }
181
+ }
182
+ function replaceRuleWithCss(rule, generatedCss) {
183
+ const css = postcss.parse(generatedCss);
184
+ css.walkDecls((declaration) => {
185
+ declaration.source = rule.source;
186
+ });
187
+ rule.replaceWith(css);
188
+ }
189
+ function replaceTeacssAtRules(root, generation, directiveName) {
190
+ const emittedLayers = /* @__PURE__ */ new Set();
191
+ root.walkAtRules(directiveName, (rule) => {
192
+ if (!rule.params) {
193
+ const layers = generation.layers.filter((layer) => !emittedLayers.has(layer));
194
+ replaceRuleWithCss(rule, generation.getLayers(layers) || "");
195
+ for (const layer of layers) emittedLayers.add(layer);
196
+ return;
197
+ }
198
+ const excludeLayers = [];
199
+ const includeLayers = [];
200
+ for (const layer of rule.params.split(",")) {
201
+ const name = layer.trim();
202
+ if (!name) continue;
203
+ if (name.startsWith("!")) {
204
+ if (name.slice(1)) excludeLayers.push(name.slice(1));
205
+ } else includeLayers.push(name);
206
+ }
207
+ if (excludeLayers.length > 0 && includeLayers.length > 0) console.warn(`Warning: Mixing normal and negated layer names in "@${directiveName} ${rule.params}" is not recommended.`);
208
+ let layers = [];
209
+ if (includeLayers.length > 0) {
210
+ const included = includeLayers.includes("all") ? generation.layers : includeLayers;
211
+ layers = included.filter((layer, index) => generation.layers.includes(layer) && included.indexOf(layer) === index && !emittedLayers.has(layer));
212
+ } else if (excludeLayers.length > 0) layers = generation.layers.filter((layer) => !excludeLayers.includes(layer) && !emittedLayers.has(layer));
213
+ replaceRuleWithCss(rule, generation.getLayers(layers) || "");
214
+ for (const layer of layers) emittedLayers.add(layer);
215
+ });
216
+ }
217
+ function createPlugin(options) {
218
+ const { cwd = process.cwd(), configOrPath } = options;
219
+ const configTarget = typeof configOrPath === "string" ? resolve(cwd, configOrPath) : cwd;
220
+ const hasInlineConfig = Boolean(configOrPath && typeof configOrPath === "object");
221
+ const hasExplicitEntry = typeof configOrPath === "string" && extname(configTarget).toLowerCase() === ".css";
222
+ const inlineOptionContent = (options.content ?? []).map((content, idx) => {
223
+ if (typeof content === "string") return content;
224
+ const extension = content.extension.replace(/^\./, "") || "html";
225
+ return {
226
+ code: content.raw,
227
+ id: `__postcss_content_${idx}.${extension}`
228
+ };
229
+ });
230
+ const directiveMap = {
231
+ apply: "apply",
232
+ screen: "screen",
233
+ teacss: "teacss",
234
+ ...options.directiveMap
235
+ };
236
+ const loadConfig = createRecoveryConfigLoader();
237
+ let config;
238
+ const getConfig = () => {
239
+ config ??= loadConfig(cwd, configOrPath).catch((error) => {
240
+ config = void 0;
241
+ throw error;
242
+ });
243
+ return config;
244
+ };
245
+ const getConfigSourceFiles = (activeSources) => {
246
+ const files = new Set(activeSources);
247
+ if (hasInlineConfig) return files;
248
+ if (hasExplicitEntry) files.add(configTarget);
249
+ else for (const file of entryDiscoveryFiles) files.add(join(configTarget, file));
250
+ return files;
251
+ };
252
+ const getConfigSignature = async (activeSources) => {
253
+ if (hasInlineConfig) return "";
254
+ return (await Promise.all(Array.from(getConfigSourceFiles(activeSources)).sort().map(async (file) => {
255
+ try {
256
+ return `${file}:${fileSignature(await stat(file))}`;
257
+ } catch (error) {
258
+ if (error.code === "ENOENT") return `${file}:missing`;
259
+ throw error;
260
+ }
261
+ }))).join("|");
262
+ };
263
+ let generatorState;
264
+ let configRequestVersion = 0;
265
+ let pendingConfig;
266
+ async function getGeneratorState() {
267
+ const signature = await getConfigSignature(generatorState?.sources ?? []);
268
+ if (generatorState?.signature === signature) return generatorState;
269
+ if (pendingConfig?.signature === signature) return pendingConfig.promise;
270
+ const version = ++configRequestVersion;
271
+ const forceReload = Boolean(generatorState || pendingConfig || config);
272
+ let task;
273
+ task = (async () => {
274
+ let expectedSignature = signature;
275
+ let mustReload = forceReload;
276
+ let stableResolved;
277
+ let next;
278
+ for (let attempt = 0; attempt < MAX_CONFIG_STABILITY_ATTEMPTS; attempt++) {
279
+ const resolved = mustReload ? await loadConfig(cwd, configOrPath) : await getConfig();
280
+ const resolvedSignature = await getConfigSignature(resolved.sources);
281
+ if (resolvedSignature === expectedSignature) {
282
+ stableResolved = resolved;
283
+ next = {
284
+ generator: await createGenerator(resolved.config),
285
+ signature: resolvedSignature,
286
+ sources: resolved.sources,
287
+ entryDir: resolved.sources[0] ? dirname(resolved.sources[0]) : cwd,
288
+ fileMap: /* @__PURE__ */ new Map(),
289
+ fileClassMap: /* @__PURE__ */ new Map(),
290
+ scanRequestVersion: 0
291
+ };
292
+ break;
293
+ }
294
+ expectedSignature = resolvedSignature;
295
+ mustReload = true;
296
+ }
297
+ if (!stableResolved || !next) throw new Error(`TeaCSS config did not stabilize after ${MAX_CONFIG_STABILITY_ATTEMPTS} load attempts`);
298
+ if (configRequestVersion === version) {
299
+ config = Promise.resolve(stableResolved);
300
+ generatorState = next;
301
+ return next;
302
+ }
303
+ const latest = pendingConfig?.promise;
304
+ if (latest && latest !== task) return await latest;
305
+ return generatorState ?? next;
306
+ })();
307
+ pendingConfig = {
308
+ signature,
309
+ promise: task
310
+ };
311
+ try {
312
+ return await task;
313
+ } finally {
314
+ if (pendingConfig?.promise === task) pendingConfig = void 0;
315
+ }
316
+ }
317
+ const directiveNames = new Set(Object.values(directiveMap));
318
+ return async function plugin(root, result) {
319
+ const from = stripQueryAndHash(result.opts.from ?? "") || join(cwd, "__teacss_postcss_input.css");
320
+ let isTarget = false;
321
+ let isScanTarget = false;
322
+ root.walk((node) => {
323
+ if (node.type === "atrule") {
324
+ if (node.name === directiveMap.teacss) {
325
+ isTarget = true;
326
+ isScanTarget = true;
327
+ return false;
328
+ }
329
+ if (directiveNames.has(node.name)) isTarget = true;
330
+ } else if (!isTarget && node.type === "decl" && (hasThemeFn(node.value) || hasIconFn(node.value))) isTarget = true;
331
+ });
332
+ if (!isTarget) return;
333
+ const dependencyFiles = /* @__PURE__ */ new Set();
334
+ const dependencyDirectories = /* @__PURE__ */ new Set();
335
+ const addDependency = (file) => {
336
+ const normalized = normalize(file);
337
+ if (dependencyFiles.has(normalized)) return;
338
+ dependencyFiles.add(normalized);
339
+ result.messages.push({
340
+ type: "dependency",
341
+ plugin: directiveMap.teacss,
342
+ file: normalized,
343
+ parent: from
344
+ });
345
+ };
346
+ const addDirectoryDependency = async (base, pattern, literal = false) => {
347
+ const dependency = await resolveDirectoryDependency(base, pattern, literal);
348
+ if (!dependency) return;
349
+ const key = `${dependency.dir}\0${dependency.glob}`;
350
+ if (dependencyDirectories.has(key)) return;
351
+ dependencyDirectories.add(key);
352
+ result.messages.push({
353
+ type: "dir-dependency",
354
+ plugin: directiveMap.teacss,
355
+ ...dependency,
356
+ parent: from
357
+ });
358
+ };
359
+ let state;
360
+ try {
361
+ state = await getGeneratorState();
362
+ } catch (error) {
363
+ for (const file of getConfigSourcesFromError(error)) {
364
+ addDependency(file);
365
+ await addDirectoryDependency(cwd, file, true);
366
+ }
367
+ const message = error instanceof Error ? error.message : String(error);
368
+ throw new Error(`TeaCSS config not found: ${message}`);
369
+ }
370
+ const { generator } = state;
371
+ for (const file of getConfigSourceFiles(state.sources)) addDependency(file);
372
+ await parseApply(root, generator, directiveMap.apply);
373
+ await parseTheme(root, generator);
374
+ await parseScreen(root, generator, directiveMap.screen);
375
+ if (!isScanTarget) {
376
+ if (result.opts.from) addDependency(from);
377
+ return;
378
+ }
379
+ const scanRequestVersion = ++state.scanRequestVersion;
380
+ const fileMap = new Map(state.fileMap);
381
+ const fileClassMap = new Map(state.fileClassMap);
382
+ const configuredGlobs = generator.config.content?.filesystem;
383
+ const globs = configuredGlobs ?? defaultFilesystemGlobs;
384
+ const scanCwd = configuredGlobs === void 0 ? cwd : state.entryDir;
385
+ for (const pattern of globs) await addDirectoryDependency(scanCwd, pattern);
386
+ const ignore = [...globs.some((i) => i.includes("node_modules")) ? [] : ["**/node_modules/**"], ...configuredGlobs === void 0 ? DEFAULT_GENERATED_IGNORE : []];
387
+ const plainContent = [...inlineOptionContent, ...generator.config.content?.inline ?? []];
388
+ const entries = await glob(globs, {
389
+ cwd: scanCwd,
390
+ absolute: true,
391
+ ignore,
392
+ expandDirectories: false
393
+ });
394
+ const activeFiles = new Set(entries);
395
+ for (const file of fileMap.keys()) if (!activeFiles.has(file)) fileMap.delete(file);
396
+ for (const file of fileClassMap.keys()) if (!activeFiles.has(file)) fileClassMap.delete(file);
397
+ const classes = /* @__PURE__ */ new Set();
398
+ const inlineMatches = await Promise.all(plainContent.map(async (c, idx) => {
399
+ if (typeof c === "function") c = await c();
400
+ if (typeof c === "string") c = { code: c };
401
+ return (await generator.generate(c.code, {
402
+ id: c.id ?? `__plain_content_${idx}__`,
403
+ preflights: false,
404
+ safelist: false
405
+ })).matched;
406
+ }));
407
+ for (const matched of inlineMatches) for (const candidate of matched) classes.add(candidate);
408
+ const BATCH_SIZE = 500;
409
+ const scanFile = async (file) => {
410
+ addDependency(file);
411
+ const source = await readChangedFile(file, fileMap.get(file));
412
+ if (source === void 0) {
413
+ fileMap.delete(file);
414
+ fileClassMap.delete(file);
415
+ return;
416
+ }
417
+ if (source === null) return;
418
+ const { matched } = await generator.generate(source.content, {
419
+ id: file,
420
+ preflights: false,
421
+ safelist: false
422
+ });
423
+ fileClassMap.set(file, matched);
424
+ fileMap.set(file, source.signature);
425
+ };
426
+ for (let i = 0; i < entries.length; i += BATCH_SIZE) await Promise.all(entries.slice(i, i + BATCH_SIZE).map(scanFile));
427
+ for (const file of [...fileClassMap.keys()].sort()) {
428
+ const set = fileClassMap.get(file);
429
+ for (const candidate of set) classes.add(candidate);
430
+ }
431
+ const generation = await generator.generate(classes);
432
+ if (state.scanRequestVersion === scanRequestVersion) {
433
+ state.fileMap = fileMap;
434
+ state.fileClassMap = fileClassMap;
435
+ }
436
+ replaceTeacssAtRules(root, generation, directiveMap.teacss);
437
+ };
438
+ }
439
+ //#endregion
440
+ export { createPlugin };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,27 @@
1
- export { default as postcssBreakpoints } from '@teacss/postcss-breakpoints';
2
- export { default as postcssWhitespace } from '@teacss/postcss-whitespace';
3
- export { default as postcssAutoprefixer } from 'autoprefixer';
4
- export { default as postcssCombineDuplicatedSelectors } from 'postcss-combine-duplicated-selectors';
5
- export { default as postcssCustomMedia } from 'postcss-custom-media';
6
- export { default as postcssDiscardComments } from 'postcss-discard-comments';
7
- export { default as postcssDiscardDuplicates } from 'postcss-discard-duplicates';
8
- export { default as postcssDiscardEmpty } from 'postcss-discard-empty';
9
- export { default as postcssDiscardUnused } from 'postcss-discard-unused';
10
- export { default as postcssImport } from 'postcss-import';
11
- export { default as postcssNesting } from 'postcss-nesting';
1
+ import { Result, Root } from "postcss";
2
+ import { UserConfig } from "@teacss/core";
3
+ //#region src/types.d.ts
4
+ interface TeacssPostcssPluginOptions {
5
+ content?: (string | {
6
+ raw: string;
7
+ extension: string;
8
+ })[];
9
+ directiveMap?: {
10
+ apply?: string;
11
+ screen?: string;
12
+ teacss?: string;
13
+ };
14
+ cwd?: string;
15
+ configOrPath?: string | UserConfig;
16
+ }
17
+ //#endregion
18
+ //#region src/index.d.ts
19
+ declare function pluginTeacss(options?: TeacssPostcssPluginOptions): {
20
+ postcssPlugin: string;
21
+ plugins: ((root: Root, result: Result) => Promise<void>)[];
22
+ };
23
+ declare namespace pluginTeacss {
24
+ var postcss: boolean;
25
+ }
26
+ //#endregion
27
+ export { TeacssPostcssPluginOptions, pluginTeacss };