praxis-kit 0.1.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 +21 -0
- package/README.md +77 -0
- package/dist/_shared/diagnostics.d.ts +312 -0
- package/dist/_shared/diagnostics.js +360 -0
- package/dist/build-runtime-CJ_nQEaZ.js +5065 -0
- package/dist/codemod/index.d.ts +2 -0
- package/dist/codemod/index.js +176520 -0
- package/dist/contract/index.d.ts +677 -0
- package/dist/contract/index.js +341 -0
- package/dist/eslint/index.d.ts +90 -0
- package/dist/eslint/index.js +1047 -0
- package/dist/guards/index.d.ts +78 -0
- package/dist/guards/index.js +118 -0
- package/dist/html/index.d.ts +151 -0
- package/dist/html/index.js +1244 -0
- package/dist/index-BIBd_iPD.d.ts +951 -0
- package/dist/lit/index.d.ts +862 -0
- package/dist/lit/index.js +4893 -0
- package/dist/preact/index.d.ts +796 -0
- package/dist/preact/index.js +5043 -0
- package/dist/react/index.d.ts +28 -0
- package/dist/react/index.js +205 -0
- package/dist/react/legacy.d.ts +29 -0
- package/dist/react/legacy.js +80 -0
- package/dist/solid/index.d.ts +728 -0
- package/dist/solid/index.js +4821 -0
- package/dist/svelte/Polymorphic.svelte +190 -0
- package/dist/svelte/_polymorphic-runtime.d.ts +102 -0
- package/dist/svelte/_polymorphic-runtime.js +371 -0
- package/dist/svelte/index.d.ts +994 -0
- package/dist/svelte/index.js +4482 -0
- package/dist/tailwind/index.d.ts +197 -0
- package/dist/tailwind/index.js +767 -0
- package/dist/tailwind/safelist.css +20 -0
- package/dist/ts-plugin/index.cjs +166 -0
- package/dist/ts-plugin/index.d.cts +9 -0
- package/dist/utils/index.d.ts +19 -0
- package/dist/utils/index.js +21 -0
- package/dist/vite-plugin/index.d.ts +200 -0
- package/dist/vite-plugin/index.js +2106 -0
- package/dist/vue/index.d.ts +729 -0
- package/dist/vue/index.js +4945 -0
- package/dist/web/index.d.ts +832 -0
- package/dist/web/index.js +4868 -0
- package/package.json +258 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* `createTailwindPipeline` assembles display-mode classes (flex, inline-flex,
|
|
3
|
+
* grid, hidden, etc.) at runtime from boolean props — they never appear as a
|
|
4
|
+
* literal string anywhere in scanned source, so Tailwind v4's content
|
|
5
|
+
* detection never generates their CSS on its own.
|
|
6
|
+
*
|
|
7
|
+
* `@source inline(...)` forces Tailwind to generate these utilities
|
|
8
|
+
* regardless of what its scanner finds. This file is copied verbatim into
|
|
9
|
+
* `praxis-kit`'s published dist (see packages/kit/scripts/postbuild.mjs) and
|
|
10
|
+
* exposed as the `praxis-kit/tailwind.css` subpath — `@praxis-kit/tailwind`
|
|
11
|
+
* itself is a private, unpublished workspace package. Import it alongside
|
|
12
|
+
* `tailwindcss` in your app's main CSS entry point:
|
|
13
|
+
*
|
|
14
|
+
* @import "tailwindcss";
|
|
15
|
+
* @import "praxis-kit/tailwind.css";
|
|
16
|
+
*
|
|
17
|
+
* Keep this list in sync with `layout-keys.ts` — enforced by
|
|
18
|
+
* `tailwind-safelist.test.ts`.
|
|
19
|
+
*/
|
|
20
|
+
@source inline("flex inline-flex grid inline-grid block inline-block inline hidden contents flow-root list-item table inline-table table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row-group table-row");
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
//#region ../../plugins/typescript/src/ast.ts
|
|
2
|
+
function getObjectProperty(ts, obj, key) {
|
|
3
|
+
for (const prop of obj.properties) {
|
|
4
|
+
if (!ts.isPropertyAssignment(prop)) continue;
|
|
5
|
+
const name = prop.name;
|
|
6
|
+
if (ts.isIdentifier(name) && name.text === key) return prop;
|
|
7
|
+
if (ts.isStringLiteral(name) && name.text === key) return prop;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function asObjectLiteralExpression(ts, node) {
|
|
11
|
+
if (!node) return void 0;
|
|
12
|
+
return ts.isObjectLiteralExpression(node) ? node : void 0;
|
|
13
|
+
}
|
|
14
|
+
function asArrayLiteralExpression(ts, node) {
|
|
15
|
+
if (!node) return void 0;
|
|
16
|
+
return ts.isArrayLiteralExpression(node) ? node : void 0;
|
|
17
|
+
}
|
|
18
|
+
function asNumericValue(ts, node) {
|
|
19
|
+
if (!node) return void 0;
|
|
20
|
+
if (ts.isNumericLiteral(node)) return Number(node.text);
|
|
21
|
+
if (ts.isPrefixUnaryExpression(node) && (node.operator === ts.SyntaxKind.MinusToken || node.operator === ts.SyntaxKind.PlusToken) && ts.isNumericLiteral(node.operand)) {
|
|
22
|
+
const val = Number(node.operand.text);
|
|
23
|
+
return node.operator === ts.SyntaxKind.MinusToken ? -val : val;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function isFactoryCall(ts, node, names) {
|
|
27
|
+
const { expression } = node;
|
|
28
|
+
if (ts.isIdentifier(expression)) return names.has(expression.text);
|
|
29
|
+
if (ts.isPropertyAccessExpression(expression)) return names.has(expression.name.text);
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
function getFirstObjectArg(ts, node) {
|
|
33
|
+
const [first] = node.arguments;
|
|
34
|
+
if (!first) return void 0;
|
|
35
|
+
return ts.isObjectLiteralExpression(first) ? first : void 0;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region ../../plugins/typescript/src/diagnostics/walk-enforcement.ts
|
|
39
|
+
/**
|
|
40
|
+
* Walks a source file and calls `cb` for every factory call that has a
|
|
41
|
+
* statically-resolvable `enforcement` object literal argument.
|
|
42
|
+
*/
|
|
43
|
+
function walkEnforcement(ts, sourceFile, calleeNames, cb) {
|
|
44
|
+
function visit(node) {
|
|
45
|
+
if (ts.isCallExpression(node) && isFactoryCall(ts, node, calleeNames)) {
|
|
46
|
+
const arg = getFirstObjectArg(ts, node);
|
|
47
|
+
if (arg) {
|
|
48
|
+
const enfProp = getObjectProperty(ts, arg, "enforcement");
|
|
49
|
+
if (enfProp) {
|
|
50
|
+
const enf = asObjectLiteralExpression(ts, enfProp.initializer);
|
|
51
|
+
if (enf) cb(node, enf);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
ts.forEachChild(node, visit);
|
|
56
|
+
}
|
|
57
|
+
visit(sourceFile);
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region ../../plugins/typescript/src/diagnostics/no-enforcement-without-strict.ts
|
|
61
|
+
const MISSING_STRICT_CODE = 90001;
|
|
62
|
+
function checkNoEnforcementWithoutStrict(ts, sourceFile, calleeNames) {
|
|
63
|
+
const diagnostics = [];
|
|
64
|
+
walkEnforcement(ts, sourceFile, calleeNames, (_node, enf) => {
|
|
65
|
+
if (!(getObjectProperty(ts, enf, "strict") !== void 0)) for (const field of ["children", "aria"]) {
|
|
66
|
+
const fieldProp = getObjectProperty(ts, enf, field);
|
|
67
|
+
if (!fieldProp) continue;
|
|
68
|
+
if (field === "children") {
|
|
69
|
+
const arr = asArrayLiteralExpression(ts, fieldProp.initializer);
|
|
70
|
+
if (!arr || arr.elements.length === 0) continue;
|
|
71
|
+
}
|
|
72
|
+
const anchor = fieldProp.name;
|
|
73
|
+
diagnostics.push({
|
|
74
|
+
file: sourceFile,
|
|
75
|
+
start: anchor.getStart(sourceFile),
|
|
76
|
+
length: anchor.getWidth(sourceFile),
|
|
77
|
+
category: ts.DiagnosticCategory.Warning,
|
|
78
|
+
code: MISSING_STRICT_CODE,
|
|
79
|
+
messageText: `enforcement.${field} is defined but enforcement.strict is not explicitly set. Adapter defaults vary — declare strict explicitly so the behavior is clear at the call site.`,
|
|
80
|
+
source: "praxis-kit/ts-plugin"
|
|
81
|
+
});
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
return diagnostics;
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region ../../plugins/typescript/src/diagnostics/valid-cardinality.ts
|
|
89
|
+
const NEGATIVE_MIN_CODE = 90002;
|
|
90
|
+
const NEGATIVE_MAX_CODE = 90003;
|
|
91
|
+
const MAX_LESS_THAN_MIN_CODE = 90004;
|
|
92
|
+
function checkValidCardinality(ts, sourceFile, calleeNames) {
|
|
93
|
+
const diagnostics = [];
|
|
94
|
+
walkEnforcement(ts, sourceFile, calleeNames, (_, enf) => {
|
|
95
|
+
const childrenProp = getObjectProperty(ts, enf, "children");
|
|
96
|
+
if (!childrenProp) return;
|
|
97
|
+
const arr = asArrayLiteralExpression(ts, childrenProp.initializer);
|
|
98
|
+
if (!arr) return;
|
|
99
|
+
for (const element of arr.elements) {
|
|
100
|
+
if (!ts.isObjectLiteralExpression(element)) continue;
|
|
101
|
+
const cardProp = getObjectProperty(ts, element, "cardinality");
|
|
102
|
+
if (!cardProp) continue;
|
|
103
|
+
const card = asObjectLiteralExpression(ts, cardProp.initializer);
|
|
104
|
+
if (!card) continue;
|
|
105
|
+
const minProp = getObjectProperty(ts, card, "min");
|
|
106
|
+
const maxProp = getObjectProperty(ts, card, "max");
|
|
107
|
+
const min = minProp ? asNumericValue(ts, minProp.initializer) : void 0;
|
|
108
|
+
const max = maxProp ? asNumericValue(ts, maxProp.initializer) : void 0;
|
|
109
|
+
if (min !== void 0 && min < 0) diagnostics.push({
|
|
110
|
+
file: sourceFile,
|
|
111
|
+
start: minProp.getStart(sourceFile),
|
|
112
|
+
length: minProp.getWidth(sourceFile),
|
|
113
|
+
category: ts.DiagnosticCategory.Error,
|
|
114
|
+
code: NEGATIVE_MIN_CODE,
|
|
115
|
+
messageText: `cardinality.min must be >= 0 (got ${min}).`,
|
|
116
|
+
source: "praxis-kit/ts-plugin"
|
|
117
|
+
});
|
|
118
|
+
if (max !== void 0 && max < 0) diagnostics.push({
|
|
119
|
+
file: sourceFile,
|
|
120
|
+
start: maxProp.getStart(sourceFile),
|
|
121
|
+
length: maxProp.getWidth(sourceFile),
|
|
122
|
+
category: ts.DiagnosticCategory.Error,
|
|
123
|
+
code: NEGATIVE_MAX_CODE,
|
|
124
|
+
messageText: `cardinality.max must be >= 0 (got ${max}).`,
|
|
125
|
+
source: "praxis-kit/ts-plugin"
|
|
126
|
+
});
|
|
127
|
+
if (min !== void 0 && max !== void 0 && min >= 0 && max > 0 && max < min) diagnostics.push({
|
|
128
|
+
file: sourceFile,
|
|
129
|
+
start: cardProp.getStart(sourceFile),
|
|
130
|
+
length: cardProp.getWidth(sourceFile),
|
|
131
|
+
category: ts.DiagnosticCategory.Error,
|
|
132
|
+
code: MAX_LESS_THAN_MIN_CODE,
|
|
133
|
+
messageText: `cardinality.max (${max}) must be >= cardinality.min (${min}). This rule can never be satisfied.`,
|
|
134
|
+
source: "praxis-kit/ts-plugin"
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
return diagnostics;
|
|
139
|
+
}
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region ../../plugins/typescript/src/index.ts
|
|
142
|
+
const DEFAULT_CALLEE_NAMES = ["createContractComponent"];
|
|
143
|
+
function init(modules) {
|
|
144
|
+
const ts = modules.typescript;
|
|
145
|
+
function create(info) {
|
|
146
|
+
const calleeNames = new Set(info.config.calleeNames ?? DEFAULT_CALLEE_NAMES);
|
|
147
|
+
const proxy = Object.create(null);
|
|
148
|
+
for (const k of Object.keys(info.languageService)) {
|
|
149
|
+
const x = info.languageService[k];
|
|
150
|
+
Reflect.set(proxy, k, typeof x === "function" ? x.bind(info.languageService) : x);
|
|
151
|
+
}
|
|
152
|
+
proxy.getSemanticDiagnostics = (fileName) => {
|
|
153
|
+
const existing = info.languageService.getSemanticDiagnostics(fileName);
|
|
154
|
+
const program = info.languageService.getProgram();
|
|
155
|
+
if (!program) return existing;
|
|
156
|
+
const sourceFile = program.getSourceFile(fileName);
|
|
157
|
+
if (!sourceFile) return existing;
|
|
158
|
+
const extra = [...checkNoEnforcementWithoutStrict(ts, sourceFile, calleeNames), ...checkValidCardinality(ts, sourceFile, calleeNames)];
|
|
159
|
+
return [...existing, ...extra];
|
|
160
|
+
};
|
|
161
|
+
return proxy;
|
|
162
|
+
}
|
|
163
|
+
return { create };
|
|
164
|
+
}
|
|
165
|
+
module.exports = init;
|
|
166
|
+
//#endregion
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import tsserverlibrary from "typescript/lib/tsserverlibrary";
|
|
2
|
+
//#region ../../plugins/typescript/src/index.d.ts
|
|
3
|
+
type TS = typeof tsserverlibrary;
|
|
4
|
+
declare function init(modules: {
|
|
5
|
+
typescript: TS;
|
|
6
|
+
}): {
|
|
7
|
+
create: (info: tsserverlibrary.server.PluginCreateInfo) => tsserverlibrary.LanguageService;
|
|
8
|
+
};
|
|
9
|
+
export = init;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import "clsx";
|
|
2
|
+
import "../_shared/diagnostics.js";
|
|
3
|
+
import "type-fest";
|
|
4
|
+
//#region ../../lib/primitive/src/types/function-types.d.ts
|
|
5
|
+
/** A single-argument pure function — the shape `memoize()` wraps. */
|
|
6
|
+
type UnaryFn<T, R> = (arg: T) => R;
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region ../../lib/primitive/src/utils/memoize.d.ts
|
|
9
|
+
/**
|
|
10
|
+
* Caches the result of a pure, single-argument function in an unbounded `Map`.
|
|
11
|
+
*
|
|
12
|
+
* Best suited to functions that are expensive relative to a cache lookup and
|
|
13
|
+
* repeatedly called with a relatively small, bounded set of inputs (for
|
|
14
|
+
* example, a finite vocabulary of tokens or strings). Avoid memoizing
|
|
15
|
+
* unbounded or attacker-controlled input spaces, as the cache will grow
|
|
16
|
+
* without limit. Use `LRUCache` instead when cache size should remain bounded.
|
|
17
|
+
*/
|
|
18
|
+
export declare function memoize<T, R>(fn: UnaryFn<T, R>): UnaryFn<T, R>;
|
|
19
|
+
//#endregion
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region ../../lib/primitive/src/utils/memoize.ts
|
|
2
|
+
/**
|
|
3
|
+
* Caches the result of a pure, single-argument function in an unbounded `Map`.
|
|
4
|
+
*
|
|
5
|
+
* Best suited to functions that are expensive relative to a cache lookup and
|
|
6
|
+
* repeatedly called with a relatively small, bounded set of inputs (for
|
|
7
|
+
* example, a finite vocabulary of tokens or strings). Avoid memoizing
|
|
8
|
+
* unbounded or attacker-controlled input spaces, as the cache will grow
|
|
9
|
+
* without limit. Use `LRUCache` instead when cache size should remain bounded.
|
|
10
|
+
*/
|
|
11
|
+
function memoize(fn) {
|
|
12
|
+
const cache = /* @__PURE__ */ new Map();
|
|
13
|
+
return (arg) => {
|
|
14
|
+
if (cache.has(arg)) return cache.get(arg);
|
|
15
|
+
const result = fn(arg);
|
|
16
|
+
cache.set(arg, result);
|
|
17
|
+
return result;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { memoize };
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import "clsx";
|
|
3
|
+
import { DiagnosticCode } from "../_shared/diagnostics.js";
|
|
4
|
+
import { Plugin } from "vite";
|
|
5
|
+
import "type-fest";
|
|
6
|
+
//#region ../../lib/foundation/src/string-map.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* A string-keyed object whose values are of type `T`.
|
|
9
|
+
*/
|
|
10
|
+
type StringMap<T = unknown> = Record<string, T>;
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region ../../lib/primitive/src/types/aria-rule/severity.d.ts
|
|
13
|
+
type Severity = 'error' | 'warning' | (string & {});
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region ../../plugins/vite/src/types/plugin-options.d.ts
|
|
16
|
+
/** Options accepted by contractPlugin() and analyze(). */
|
|
17
|
+
type PluginOptions = {
|
|
18
|
+
/**
|
|
19
|
+
* Factory function names to look for.
|
|
20
|
+
* @default ['createPolymorphicComponent', 'createContractComponent']
|
|
21
|
+
*/
|
|
22
|
+
calleeNames?: string[];
|
|
23
|
+
/**
|
|
24
|
+
* Severity of cardinality violations in Vite build output.
|
|
25
|
+
* Matches the Severity vocabulary used by ValidationViolation.
|
|
26
|
+
* @default 'warning'
|
|
27
|
+
*/
|
|
28
|
+
severity?: Severity;
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region ../../plugins/vite/src/design-tokens.d.ts
|
|
32
|
+
type ComponentTokens = {
|
|
33
|
+
base: string[];
|
|
34
|
+
variantClasses: string[];
|
|
35
|
+
compoundClasses: string[];
|
|
36
|
+
tagClasses: string[];
|
|
37
|
+
};
|
|
38
|
+
type DesignTokenManifest = {
|
|
39
|
+
components: StringMap<ComponentTokens>;
|
|
40
|
+
allClasses: string[];
|
|
41
|
+
};
|
|
42
|
+
type DesignTokensOptions = {
|
|
43
|
+
/**
|
|
44
|
+
* Path where the manifest JSON is written, relative to the Vite project root.
|
|
45
|
+
* @default 'praxis-tokens.json'
|
|
46
|
+
*/
|
|
47
|
+
outFile?: string;
|
|
48
|
+
} & Pick<PluginOptions, 'calleeNames'>;
|
|
49
|
+
/**
|
|
50
|
+
* Vite plugin that collects every statically-declared class string from
|
|
51
|
+
* `createContractComponent` factory calls and writes a design token manifest
|
|
52
|
+
* to a JSON file on each build.
|
|
53
|
+
*
|
|
54
|
+
* The manifest contains per-component class lists and a flat `allClasses`
|
|
55
|
+
* union that can be used as a Tailwind content source to prevent purging of
|
|
56
|
+
* variant classes.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* // vite.config.ts
|
|
60
|
+
* import { designTokensPlugin } from 'praxis-kit/vite-plugin'
|
|
61
|
+
* export default { plugins: [designTokensPlugin({ outFile: 'praxis-tokens.json' })] }
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* // tailwind.config.js
|
|
65
|
+
* export default { content: ['./src/**', './praxis-tokens.json'] }
|
|
66
|
+
*/
|
|
67
|
+
export declare function designTokensPlugin(options?: DesignTokensOptions): Plugin;
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region ../../plugins/vite/src/index.d.ts
|
|
70
|
+
/**
|
|
71
|
+
* Vite plugin that performs static enforcement.children cardinality checks at
|
|
72
|
+
* build time for components created with createContractComponent.
|
|
73
|
+
*
|
|
74
|
+
* **Single-file scope:** Components defined and used in the same `.tsx` / `.jsx`
|
|
75
|
+
* file are validated during `transform`. JSX children containing expressions
|
|
76
|
+
* (`{...}`) are skipped — their count is unknowable at compile time.
|
|
77
|
+
*
|
|
78
|
+
* **Cross-file scope:** Components imported from other files are validated in
|
|
79
|
+
* `buildEnd` once the full constraint registry is populated. Only named imports
|
|
80
|
+
* whose source file was also transformed by this plugin are checked.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* // vite.config.ts
|
|
84
|
+
* import { contractPlugin } from 'praxis-kit/vite-plugin'
|
|
85
|
+
* export default { plugins: [contractPlugin()] }
|
|
86
|
+
*/
|
|
87
|
+
export declare function contractPlugin(options?: PluginOptions): Plugin;
|
|
88
|
+
/**
|
|
89
|
+
* Vite plugin that removes dead `styling.compounds` entries from factory calls
|
|
90
|
+
* at build time, reducing bundle size and eliminating unreachable CVA compound
|
|
91
|
+
* checks at runtime.
|
|
92
|
+
*
|
|
93
|
+
* A compound entry is dead when any of its conditions reference a variant key
|
|
94
|
+
* that does not exist in `styling.variants`, or a value that is not valid for
|
|
95
|
+
* that key. Only entries whose conditions are fully static (string/array
|
|
96
|
+
* literals) are pruned — dynamic conditions are left unchanged.
|
|
97
|
+
*
|
|
98
|
+
* Place before `contractPlugin` so the pruned source is what gets analyzed.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* // vite.config.ts
|
|
102
|
+
* import { compoundPrunePlugin, contractPlugin } from 'praxis-kit/vite-plugin'
|
|
103
|
+
* export default { plugins: [compoundPrunePlugin(), contractPlugin()] }
|
|
104
|
+
*/
|
|
105
|
+
export declare function compoundPrunePlugin(options?: Pick<PluginOptions, 'calleeNames'>): Plugin;
|
|
106
|
+
/**
|
|
107
|
+
* Vite plugin that pre-computes variant class strings at build time and injects
|
|
108
|
+
* them as a static `precomputedClasses` map into each factory call's `styling`
|
|
109
|
+
* object.
|
|
110
|
+
*
|
|
111
|
+
* At runtime, `VariantClassResolver` checks this map before calling CVA — a
|
|
112
|
+
* plain object lookup replaces a CVA invocation + LRU cache write for every
|
|
113
|
+
* statically-known combination. Only combinations that appear in the map are
|
|
114
|
+
* accelerated; invalid or dynamic variant values fall through to the existing
|
|
115
|
+
* compute path unchanged.
|
|
116
|
+
*
|
|
117
|
+
* Injection is skipped when:
|
|
118
|
+
* - `styling.variants` is absent or contains non-literal values
|
|
119
|
+
* - `styling.compounds` contains non-literal conditions or classes
|
|
120
|
+
* - The number of valid combinations exceeds 512
|
|
121
|
+
*
|
|
122
|
+
* Place after `compoundPrunePlugin` so the injected map reflects the live
|
|
123
|
+
* compound set.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* // vite.config.ts
|
|
127
|
+
* import { compoundPrunePlugin, classExtractPlugin, contractPlugin } from 'praxis-kit/vite-plugin'
|
|
128
|
+
* export default { plugins: [compoundPrunePlugin(), classExtractPlugin(), contractPlugin()] }
|
|
129
|
+
*/
|
|
130
|
+
export declare function classExtractPlugin(options?: Pick<PluginOptions, 'calleeNames'>): Plugin;
|
|
131
|
+
/**
|
|
132
|
+
* Vite plugin that transforms `asChild` JSX usage sites to the render-prop form
|
|
133
|
+
* at build time, eliminating the Slot/cloneElement/mergeProps runtime path.
|
|
134
|
+
*
|
|
135
|
+
* Only transforms sites where the transform is semantically safe:
|
|
136
|
+
* - Exactly one static child element
|
|
137
|
+
* - Child has no `className`, `style`, or event handler props
|
|
138
|
+
*
|
|
139
|
+
* Complex asChild patterns (conflicting props, dynamic children, Slottable
|
|
140
|
+
* siblings) are left unchanged and handled by the runtime Slot path.
|
|
141
|
+
*
|
|
142
|
+
* Place before `contractPlugin` so cardinality analysis sees the transformed
|
|
143
|
+
* source.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* // vite.config.ts
|
|
147
|
+
* import { slotTransformPlugin, contractPlugin } from 'praxis-kit/vite-plugin'
|
|
148
|
+
* export default { plugins: [slotTransformPlugin(), contractPlugin()] }
|
|
149
|
+
*/
|
|
150
|
+
export declare function slotTransformPlugin(): Plugin;
|
|
151
|
+
/**
|
|
152
|
+
* Vite plugin that replaces polymorphic component usage sites with direct
|
|
153
|
+
* element creation at build time, eliminating the runtime render pipeline for
|
|
154
|
+
* statically-analyzable usages.
|
|
155
|
+
*
|
|
156
|
+
* **Requires classExtractPlugin to run first** so that `precomputedClasses` is
|
|
157
|
+
* present in the factory call before this plugin reads it. Place after
|
|
158
|
+
* `classExtractPlugin` in the plugins array.
|
|
159
|
+
*
|
|
160
|
+
* A usage site is inlined when:
|
|
161
|
+
* - The component is defined in the same file or imported from a file already
|
|
162
|
+
* transformed by this plugin, with `precomputedClasses` injected
|
|
163
|
+
* - No `as`, `asChild`, `render`, or spread attributes at the site
|
|
164
|
+
* - All variant props are static string literals
|
|
165
|
+
* - `className` is absent or a static string literal
|
|
166
|
+
* - The factory config has no `defaults` or `enforcement`
|
|
167
|
+
*
|
|
168
|
+
* Cross-file inlining degrades gracefully when the definition file has not yet
|
|
169
|
+
* been transformed (dev mode ordering, barrel re-exports, aliased imports).
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* // vite.config.ts
|
|
173
|
+
* import { classExtractPlugin, staticCompositionPlugin } from 'praxis-kit/vite-plugin'
|
|
174
|
+
* export default { plugins: [classExtractPlugin(), staticCompositionPlugin()] }
|
|
175
|
+
*/
|
|
176
|
+
export declare function staticCompositionPlugin(options?: Pick<PluginOptions, 'calleeNames'>): Plugin;
|
|
177
|
+
/**
|
|
178
|
+
* Convenience plugin bundle that applies all three build-time rendering
|
|
179
|
+
* optimisations in the correct dependency order:
|
|
180
|
+
*
|
|
181
|
+
* 1. `slotTransformPlugin` — rewrites `asChild` → render-prop form,
|
|
182
|
+
* eliminating `cloneElement` for static sites
|
|
183
|
+
* 2. `classExtractPlugin` — injects `precomputedClasses` into factory
|
|
184
|
+
* calls for O(1) variant class resolution
|
|
185
|
+
* 3. `staticCompositionPlugin` — inlines same-file static usages into direct
|
|
186
|
+
* element creation, bypassing the runtime
|
|
187
|
+
* pipeline entirely
|
|
188
|
+
*
|
|
189
|
+
* Place before `contractPlugin` so cardinality analysis sees the transformed
|
|
190
|
+
* source. Especially effective for SSR builds where each component renders
|
|
191
|
+
* exactly once per request and eliminates per-render pipeline overhead.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* // vite.config.ts
|
|
195
|
+
* import { ssrOptimizePlugin, contractPlugin } from 'praxis-kit/vite-plugin'
|
|
196
|
+
* export default { plugins: [ssrOptimizePlugin(), contractPlugin()] }
|
|
197
|
+
*/
|
|
198
|
+
export declare function ssrOptimizePlugin(options?: Pick<PluginOptions, 'calleeNames'>): Plugin[];
|
|
199
|
+
//#endregion
|
|
200
|
+
export type { ComponentTokens, DesignTokenManifest, DesignTokensOptions, PluginOptions };
|