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,767 @@
|
|
|
1
|
+
import { clsx } from "clsx";
|
|
2
|
+
import { ConsoleReporter, DefaultPolicy, DiagnosticCategory, DiagnosticCode, Diagnostics, Severity } from "../_shared/diagnostics.js";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
//#region ../../lib/foundation/src/iterate.ts
|
|
5
|
+
function find(iterable, callback) {
|
|
6
|
+
for (const value of iterable) {
|
|
7
|
+
const result = callback(value);
|
|
8
|
+
if (result != null) return result;
|
|
9
|
+
}
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
function some(iterable, predicate) {
|
|
13
|
+
for (const value of iterable) if (predicate(value)) return true;
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
function every(iterable, predicate) {
|
|
17
|
+
let index = 0;
|
|
18
|
+
for (const value of iterable) if (!predicate(value, index++)) return false;
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
function* filter(iterable, predicate) {
|
|
22
|
+
let index = 0;
|
|
23
|
+
for (const value of iterable) if (predicate(value, index++)) yield value;
|
|
24
|
+
}
|
|
25
|
+
function* map(iterable, callback) {
|
|
26
|
+
let index = 0;
|
|
27
|
+
for (const value of iterable) yield callback(value, index++);
|
|
28
|
+
}
|
|
29
|
+
function forEach(iterable, callback) {
|
|
30
|
+
let index = 0;
|
|
31
|
+
for (const value of iterable) callback(value, index++);
|
|
32
|
+
}
|
|
33
|
+
function reduce(iterable, initial, callback) {
|
|
34
|
+
let accumulator = initial;
|
|
35
|
+
let index = 0;
|
|
36
|
+
for (const value of iterable) accumulator = callback(accumulator, value, index++);
|
|
37
|
+
return accumulator;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Transforms an iterable into a Record.
|
|
41
|
+
*
|
|
42
|
+
* The callback returns a `[key, value]` tuple for each element. Returning
|
|
43
|
+
* `null` aborts the collection and causes `collect()` to return `null`.
|
|
44
|
+
*/
|
|
45
|
+
function collect(iterable, callback) {
|
|
46
|
+
const result = {};
|
|
47
|
+
let index = 0;
|
|
48
|
+
for (const value of iterable) {
|
|
49
|
+
const entry = callback(value, index++);
|
|
50
|
+
if (entry === null) return null;
|
|
51
|
+
result[entry[0]] = entry[1];
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
function findLast(value, callback) {
|
|
56
|
+
for (let index = value.length - 1; index >= 0; index--) {
|
|
57
|
+
const result = callback(value[index], index);
|
|
58
|
+
if (result != null) return result;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
function* items(collection) {
|
|
63
|
+
for (let i = 0; i < collection.length; i++) {
|
|
64
|
+
const item = collection.item(i);
|
|
65
|
+
if (item !== null) yield item;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function nodeList(list) {
|
|
69
|
+
return { *[Symbol.iterator]() {
|
|
70
|
+
for (let i = 0; i < list.length; i++) {
|
|
71
|
+
const node = list.item(i);
|
|
72
|
+
if (node !== null) yield node;
|
|
73
|
+
}
|
|
74
|
+
} };
|
|
75
|
+
}
|
|
76
|
+
function mapEntries(m) {
|
|
77
|
+
return m.entries();
|
|
78
|
+
}
|
|
79
|
+
function set(s) {
|
|
80
|
+
return s.values();
|
|
81
|
+
}
|
|
82
|
+
function hasOwn(object, key) {
|
|
83
|
+
return Object.hasOwn(object, key);
|
|
84
|
+
}
|
|
85
|
+
function* entries(object) {
|
|
86
|
+
for (const key in object) {
|
|
87
|
+
if (!hasOwn(object, key)) continue;
|
|
88
|
+
yield [key, object[key]];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function* keys(object) {
|
|
92
|
+
for (const [key] of entries(object)) yield key;
|
|
93
|
+
}
|
|
94
|
+
function* values(object) {
|
|
95
|
+
for (const [, value] of entries(object)) yield value;
|
|
96
|
+
}
|
|
97
|
+
function mapValues(object, callback) {
|
|
98
|
+
const result = {};
|
|
99
|
+
for (const [key, value] of entries(object)) result[key] = callback(value, key);
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
function forEachEntry(object, callback) {
|
|
103
|
+
for (const [key, value] of entries(object)) callback(key, value);
|
|
104
|
+
}
|
|
105
|
+
function forEachKey(object, callback) {
|
|
106
|
+
for (const key of keys(object)) callback(key);
|
|
107
|
+
}
|
|
108
|
+
function forEachValue(object, callback) {
|
|
109
|
+
for (const value of values(object)) callback(value);
|
|
110
|
+
}
|
|
111
|
+
function forEachSet(s, callback) {
|
|
112
|
+
for (const value of s) callback(value);
|
|
113
|
+
}
|
|
114
|
+
const iterate = Object.freeze({
|
|
115
|
+
entries,
|
|
116
|
+
filter,
|
|
117
|
+
find,
|
|
118
|
+
findLast,
|
|
119
|
+
forEach,
|
|
120
|
+
forEachEntry,
|
|
121
|
+
forEachKey,
|
|
122
|
+
forEachSet,
|
|
123
|
+
forEachValue,
|
|
124
|
+
items,
|
|
125
|
+
keys,
|
|
126
|
+
map,
|
|
127
|
+
mapEntries,
|
|
128
|
+
mapValues,
|
|
129
|
+
nodeList,
|
|
130
|
+
reduce,
|
|
131
|
+
collect,
|
|
132
|
+
set,
|
|
133
|
+
some,
|
|
134
|
+
every,
|
|
135
|
+
values
|
|
136
|
+
});
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region ../../lib/foundation/src/assert-never.ts
|
|
139
|
+
function assertNever(value) {
|
|
140
|
+
throw new Error(`Unexpected value: ${String(value)}`);
|
|
141
|
+
}
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region ../../lib/foundation/src/cn.ts
|
|
144
|
+
function cn(...inputs) {
|
|
145
|
+
return clsx(...inputs);
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
//#region ../../lib/foundation/src/lru-cache.ts
|
|
149
|
+
/**
|
|
150
|
+
* A bounded cache that evicts the least recently used entry once `maxSize` is
|
|
151
|
+
* exceeded. Backed by a single `Map`, relying on its insertion-order iteration:
|
|
152
|
+
* `get()` promotes a hit to most-recently-used by deleting and re-inserting the
|
|
153
|
+
* key (moving it to the tail), and `set()` evicts the head (oldest) key when
|
|
154
|
+
* over capacity.
|
|
155
|
+
*
|
|
156
|
+
* Consolidates a pattern that was hand-rolled independently in three places
|
|
157
|
+
* (`StaticClassResolver`, `VariantClassResolver`, `AriaPolicyEngine#planCache`)
|
|
158
|
+
* before this existed.
|
|
159
|
+
*/
|
|
160
|
+
var LRUCache = class {
|
|
161
|
+
#maxSize;
|
|
162
|
+
#store = /* @__PURE__ */ new Map();
|
|
163
|
+
constructor(maxSize) {
|
|
164
|
+
if (!Number.isInteger(maxSize) || maxSize < 1) throw new RangeError("LRUCache maxSize must be a positive integer.");
|
|
165
|
+
this.#maxSize = maxSize;
|
|
166
|
+
}
|
|
167
|
+
get(key) {
|
|
168
|
+
if (!this.#store.has(key)) return void 0;
|
|
169
|
+
const value = this.#store.get(key);
|
|
170
|
+
this.#store.delete(key);
|
|
171
|
+
this.#store.set(key, value);
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
set(key, value) {
|
|
175
|
+
this.#store.delete(key);
|
|
176
|
+
this.#store.set(key, value);
|
|
177
|
+
if (this.#store.size > this.#maxSize) {
|
|
178
|
+
const lru = this.#store.keys().next().value;
|
|
179
|
+
if (lru !== void 0) this.#store.delete(lru);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
has(key) {
|
|
183
|
+
return this.#store.has(key);
|
|
184
|
+
}
|
|
185
|
+
delete(key) {
|
|
186
|
+
return this.#store.delete(key);
|
|
187
|
+
}
|
|
188
|
+
get size() {
|
|
189
|
+
return this.#store.size;
|
|
190
|
+
}
|
|
191
|
+
clear() {
|
|
192
|
+
this.#store.clear();
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region ../../lib/foundation/src/type-guards.ts
|
|
197
|
+
function isString(value) {
|
|
198
|
+
return typeof value === "string";
|
|
199
|
+
}
|
|
200
|
+
//#endregion
|
|
201
|
+
//#region ../../lib/primitive/src/constants/html/void-tags.ts
|
|
202
|
+
/**
|
|
203
|
+
* HTML void elements.
|
|
204
|
+
*
|
|
205
|
+
* Void elements cannot have child nodes and therefore all share the same
|
|
206
|
+
* empty content model — a WHATWG-stable fact, not a praxis-kit opinion.
|
|
207
|
+
* Single source of truth shared by the contract engine's built-in void-tag
|
|
208
|
+
* children contract (`@praxis-kit/core`'s `VOID_TAGS` re-export) and the
|
|
209
|
+
* Tailwind pipeline's flex/grid-on-void-tag warning, so the two can't drift.
|
|
210
|
+
*/
|
|
211
|
+
const VOID_TAGS = [
|
|
212
|
+
"area",
|
|
213
|
+
"base",
|
|
214
|
+
"br",
|
|
215
|
+
"col",
|
|
216
|
+
"embed",
|
|
217
|
+
"hr",
|
|
218
|
+
"img",
|
|
219
|
+
"input",
|
|
220
|
+
"link",
|
|
221
|
+
"meta",
|
|
222
|
+
"param",
|
|
223
|
+
"source",
|
|
224
|
+
"track",
|
|
225
|
+
"wbr"
|
|
226
|
+
];
|
|
227
|
+
//#endregion
|
|
228
|
+
//#region ../../lib/styling/src/cva.ts
|
|
229
|
+
function cva$1(base, config) {
|
|
230
|
+
const fn = cva(base, config);
|
|
231
|
+
return (props) => cn(fn(props));
|
|
232
|
+
}
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region ../../lib/styling/src/static-class-resolver.ts
|
|
235
|
+
var StaticClassResolver = class {
|
|
236
|
+
#baseClass;
|
|
237
|
+
#cache = new LRUCache(200);
|
|
238
|
+
#resolveTag;
|
|
239
|
+
constructor(baseClass, tagMap) {
|
|
240
|
+
this.#baseClass = Array.isArray(baseClass) ? baseClass.join(" ") : baseClass;
|
|
241
|
+
this.#resolveTag = tagMap ? (tag) => {
|
|
242
|
+
const extra = tagMap[tag];
|
|
243
|
+
if (!extra) return this.#baseClass;
|
|
244
|
+
const extraStr = Array.isArray(extra) ? extra.join(" ") : extra;
|
|
245
|
+
return `${this.#baseClass} ${extraStr}`;
|
|
246
|
+
} : () => this.#baseClass;
|
|
247
|
+
}
|
|
248
|
+
resolve(tag, skipTagMap = false) {
|
|
249
|
+
if (typeof tag !== "string" || skipTagMap) return this.#baseClass;
|
|
250
|
+
const cached = this.#cache.get(tag);
|
|
251
|
+
if (cached !== void 0) return cached;
|
|
252
|
+
const result = this.#resolveTag(tag);
|
|
253
|
+
this.#cache.set(tag, result);
|
|
254
|
+
return result;
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
//#endregion
|
|
258
|
+
//#region ../../lib/styling/src/variant-class-resolver.ts
|
|
259
|
+
/**
|
|
260
|
+
* Runtime CVA class resolution with LRU + precomputed-map caching.
|
|
261
|
+
*
|
|
262
|
+
* Distinct from `variant-pass/` — `createVariantPass` is a composable pipeline stage for
|
|
263
|
+
* build-time / plugin use (a `VariantConfig` → classes function), while this is the memoized
|
|
264
|
+
* runtime resolver `createClassPipeline` calls per render.
|
|
265
|
+
*
|
|
266
|
+
* The precomputed map (`compileVariantLookup`, injected by the vite plugin) covers the
|
|
267
|
+
* **no-recipe** combinations only — its keys are variant props alone, whereas this resolver's
|
|
268
|
+
* cache keys are `recipe | variant props`, so a recipe-active call never hits a precomputed
|
|
269
|
+
* entry and falls through to `#compute`. Recipe resolution stays fully runtime by design.
|
|
270
|
+
*/
|
|
271
|
+
var VariantClassResolver = class VariantClassResolver {
|
|
272
|
+
#cvaFn;
|
|
273
|
+
#recipeMap;
|
|
274
|
+
#variantKeys;
|
|
275
|
+
#precomputedClasses;
|
|
276
|
+
#cache = new LRUCache(1e3);
|
|
277
|
+
constructor(cvaFn, recipeMap, variantKeys, precomputedClasses) {
|
|
278
|
+
this.#cvaFn = cvaFn ?? null;
|
|
279
|
+
this.#recipeMap = Object.freeze(recipeMap ?? {});
|
|
280
|
+
this.#variantKeys = variantKeys ?? null;
|
|
281
|
+
this.#precomputedClasses = precomputedClasses ?? null;
|
|
282
|
+
}
|
|
283
|
+
resolve({ props, recipe }) {
|
|
284
|
+
const normalizedKey = recipe ?? "__none__";
|
|
285
|
+
const cacheKey = this.#createCacheKey(props, normalizedKey);
|
|
286
|
+
if (this.#precomputedClasses !== null) {
|
|
287
|
+
const precomputed = this.#precomputedClasses[cacheKey];
|
|
288
|
+
if (precomputed !== void 0) return precomputed;
|
|
289
|
+
}
|
|
290
|
+
const cached = this.#cache.get(cacheKey);
|
|
291
|
+
if (cached !== void 0) return cached;
|
|
292
|
+
const result = this.#compute(props, recipe);
|
|
293
|
+
this.#cache.set(cacheKey, result);
|
|
294
|
+
return result;
|
|
295
|
+
}
|
|
296
|
+
#compute(props, recipe) {
|
|
297
|
+
if (!this.#cvaFn) return "";
|
|
298
|
+
if (recipe === void 0) return this.#cvaFn(props);
|
|
299
|
+
const preset = this.#recipeMap[recipe];
|
|
300
|
+
if (!preset) return this.#cvaFn(props);
|
|
301
|
+
return this.#cvaFn({
|
|
302
|
+
...preset,
|
|
303
|
+
...props
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
#createCacheKey(props, recipe) {
|
|
307
|
+
if (this.#variantKeys !== null) {
|
|
308
|
+
let key = recipe;
|
|
309
|
+
iterate.forEachSet(this.#variantKeys, (k) => {
|
|
310
|
+
if (k in props) key += `|${k}:${VariantClassResolver.#serializeValue(props[k])}`;
|
|
311
|
+
});
|
|
312
|
+
return key;
|
|
313
|
+
}
|
|
314
|
+
let key = recipe;
|
|
315
|
+
iterate.forEach(Object.keys(props).sort(), (k) => {
|
|
316
|
+
key += `|${k}:${VariantClassResolver.#serializeValue(props[k])}`;
|
|
317
|
+
});
|
|
318
|
+
return key;
|
|
319
|
+
}
|
|
320
|
+
static #serializeValue(value) {
|
|
321
|
+
if (value === void 0) return "u";
|
|
322
|
+
if (value === null) return "n";
|
|
323
|
+
if (typeof value === "boolean") return `b:${value}`;
|
|
324
|
+
if (typeof value === "string") return `s:${value}`;
|
|
325
|
+
return `x:${String(value)}`;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
//#endregion
|
|
329
|
+
//#region ../../lib/styling/src/create-class-pipeline.ts
|
|
330
|
+
function createClassPipeline(resolved) {
|
|
331
|
+
const baseClass = resolved.baseClassName ?? "";
|
|
332
|
+
const cvaFn = resolved.variants ? cva$1("", {
|
|
333
|
+
variants: resolved.variants,
|
|
334
|
+
defaultVariants: resolved.defaultVariants,
|
|
335
|
+
compoundVariants: resolved.compoundVariants
|
|
336
|
+
}) : null;
|
|
337
|
+
const variantKeys = resolved.variants ? new Set(Object.keys(resolved.variants)) : void 0;
|
|
338
|
+
const staticResolver = new StaticClassResolver(baseClass, resolved.tagMap);
|
|
339
|
+
const variantResolver = new VariantClassResolver(cvaFn, resolved.recipeMap, variantKeys, resolved.precomputedClasses);
|
|
340
|
+
return function resolveClasses(tag, props, className, recipe) {
|
|
341
|
+
const staticClasses = staticResolver.resolve(tag, recipe !== void 0);
|
|
342
|
+
const variantClasses = variantResolver.resolve({
|
|
343
|
+
props,
|
|
344
|
+
recipe
|
|
345
|
+
});
|
|
346
|
+
if (!className) return (staticClasses && variantClasses ? `${staticClasses} ${variantClasses}` : staticClasses || variantClasses) || void 0;
|
|
347
|
+
return cn(staticClasses, variantClasses, className);
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
//#endregion
|
|
351
|
+
//#region ../../lib/pipeline-kit/src/core/compose-pipelines.ts
|
|
352
|
+
/** Chains two pipelines: `first`'s output feeds `second`'s single argument. The result is
|
|
353
|
+
* itself a Pipeline<TArgs, TOutput> — it can be passed right back into composePipelines as
|
|
354
|
+
* either `first` or `second` of a further composition. That closure-under-composition is the
|
|
355
|
+
* point: pipeline segments nest without a special "composed pipeline" type of their own. */
|
|
356
|
+
function composePipelines(first, second) {
|
|
357
|
+
return (...args) => second(first(...args));
|
|
358
|
+
}
|
|
359
|
+
//#endregion
|
|
360
|
+
//#region ../../lib/tailwind/src/class-builder.ts
|
|
361
|
+
var ClassBuilder = class {
|
|
362
|
+
build(tokens) {
|
|
363
|
+
const layout = [];
|
|
364
|
+
const normal = [];
|
|
365
|
+
iterate.forEach(tokens, (token) => {
|
|
366
|
+
switch (token.kind) {
|
|
367
|
+
case "layout":
|
|
368
|
+
layout.push(token.raw);
|
|
369
|
+
break;
|
|
370
|
+
case "utility":
|
|
371
|
+
case "gap":
|
|
372
|
+
case "item":
|
|
373
|
+
case "shared":
|
|
374
|
+
case "conditional":
|
|
375
|
+
normal.push(token.raw);
|
|
376
|
+
break;
|
|
377
|
+
default: throw assertNever(token);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
return [...this.#dedupe(layout).toSorted(), ...this.#dedupe(normal)].join(" ");
|
|
381
|
+
}
|
|
382
|
+
#dedupe(arr) {
|
|
383
|
+
return [...new Set(arr)];
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
//#endregion
|
|
387
|
+
//#region ../../lib/tailwind/src/layout-keys.ts
|
|
388
|
+
/**
|
|
389
|
+
* Canonical list of reserved layout prop names.
|
|
390
|
+
*
|
|
391
|
+
* This array is the single source of truth for every supported CSS `display`
|
|
392
|
+
* value exposed as a boolean prop. The `LayoutKey` type is derived directly
|
|
393
|
+
* from this list.
|
|
394
|
+
*
|
|
395
|
+
* To add a new display mode:
|
|
396
|
+
* 1. Add the display value here.
|
|
397
|
+
* 2. Register its layout family in `LAYOUT_FAMILY_MAP`.
|
|
398
|
+
*
|
|
399
|
+
* Prop names intentionally match the corresponding Tailwind/CSS display
|
|
400
|
+
* utilities, so no additional prop-to-class mapping is required.
|
|
401
|
+
*/
|
|
402
|
+
const layoutKeys = [
|
|
403
|
+
"flex",
|
|
404
|
+
"inline-flex",
|
|
405
|
+
"grid",
|
|
406
|
+
"inline-grid",
|
|
407
|
+
"block",
|
|
408
|
+
"inline-block",
|
|
409
|
+
"inline",
|
|
410
|
+
"hidden",
|
|
411
|
+
"contents",
|
|
412
|
+
"flow-root",
|
|
413
|
+
"list-item",
|
|
414
|
+
"table",
|
|
415
|
+
"inline-table",
|
|
416
|
+
"table-caption",
|
|
417
|
+
"table-cell",
|
|
418
|
+
"table-column",
|
|
419
|
+
"table-column-group",
|
|
420
|
+
"table-footer-group",
|
|
421
|
+
"table-header-group",
|
|
422
|
+
"table-row-group",
|
|
423
|
+
"table-row"
|
|
424
|
+
];
|
|
425
|
+
//#endregion
|
|
426
|
+
//#region ../../lib/tailwind/src/constants.ts
|
|
427
|
+
const LAYOUT_OWNED_KEYS = new Set(layoutKeys);
|
|
428
|
+
const LAYOUT_FAMILY_MAP = {
|
|
429
|
+
flex: "flex",
|
|
430
|
+
"inline-flex": "flex",
|
|
431
|
+
grid: "grid",
|
|
432
|
+
"inline-grid": "grid",
|
|
433
|
+
block: "none",
|
|
434
|
+
"inline-block": "none",
|
|
435
|
+
inline: "none",
|
|
436
|
+
hidden: "none",
|
|
437
|
+
contents: "none",
|
|
438
|
+
"flow-root": "none",
|
|
439
|
+
"list-item": "none",
|
|
440
|
+
table: "none",
|
|
441
|
+
"inline-table": "none",
|
|
442
|
+
"table-caption": "none",
|
|
443
|
+
"table-cell": "none",
|
|
444
|
+
"table-column": "none",
|
|
445
|
+
"table-column-group": "none",
|
|
446
|
+
"table-footer-group": "none",
|
|
447
|
+
"table-header-group": "none",
|
|
448
|
+
"table-row-group": "none",
|
|
449
|
+
"table-row": "none"
|
|
450
|
+
};
|
|
451
|
+
const EMPTY_SET = /* @__PURE__ */ new Set();
|
|
452
|
+
const COMPOUND_META_KEYS = /* @__PURE__ */ new Set(["class"]);
|
|
453
|
+
//#endregion
|
|
454
|
+
//#region ../../lib/tailwind/src/class-classifier.ts
|
|
455
|
+
const CONDITIONALS = {
|
|
456
|
+
"[&.flex": "flex",
|
|
457
|
+
"[&.grid": "grid"
|
|
458
|
+
};
|
|
459
|
+
const ITEM_PREFIXES = [
|
|
460
|
+
/^order/,
|
|
461
|
+
/^grow/,
|
|
462
|
+
/^shrink/,
|
|
463
|
+
/^basis-/,
|
|
464
|
+
/^self-/,
|
|
465
|
+
/^place-self-/,
|
|
466
|
+
/^justify-self-/,
|
|
467
|
+
/^col-/,
|
|
468
|
+
/^row-/
|
|
469
|
+
];
|
|
470
|
+
const SHARED_PREFIXES = [
|
|
471
|
+
/^justify-(?!items-|self-)/,
|
|
472
|
+
/^content-(normal|center|start|end|between|around|evenly|stretch)$/,
|
|
473
|
+
/^items-/,
|
|
474
|
+
/^place-content-/,
|
|
475
|
+
/^place-items-/
|
|
476
|
+
];
|
|
477
|
+
var ClassClassifier = class ClassClassifier {
|
|
478
|
+
static #getBaseUtility(token) {
|
|
479
|
+
let depth = 0;
|
|
480
|
+
return iterate.findLast(token, (char, index) => {
|
|
481
|
+
if (char === "]") depth++;
|
|
482
|
+
else if (char === "[") depth--;
|
|
483
|
+
else if (char === ":" && depth === 0 && token[index - 1] !== "\\") return token.slice(index + 1);
|
|
484
|
+
return null;
|
|
485
|
+
}) ?? token;
|
|
486
|
+
}
|
|
487
|
+
classify(token) {
|
|
488
|
+
const base = ClassClassifier.#getBaseUtility(token);
|
|
489
|
+
if (LAYOUT_OWNED_KEYS.has(base)) return {
|
|
490
|
+
kind: "layout",
|
|
491
|
+
value: base,
|
|
492
|
+
raw: token
|
|
493
|
+
};
|
|
494
|
+
const conditional = iterate.find(Object.entries(CONDITIONALS), ([prefix, requires]) => {
|
|
495
|
+
return token.startsWith(prefix) ? {
|
|
496
|
+
kind: "conditional",
|
|
497
|
+
requires,
|
|
498
|
+
raw: token
|
|
499
|
+
} : null;
|
|
500
|
+
});
|
|
501
|
+
if (conditional !== null) return conditional;
|
|
502
|
+
if (base === "gap" || base.startsWith("gap-")) return {
|
|
503
|
+
kind: "gap",
|
|
504
|
+
raw: token
|
|
505
|
+
};
|
|
506
|
+
if (ITEM_PREFIXES.some((rule) => rule.test(base))) return {
|
|
507
|
+
kind: "item",
|
|
508
|
+
raw: token
|
|
509
|
+
};
|
|
510
|
+
if (SHARED_PREFIXES.some((rule) => rule.test(base))) return {
|
|
511
|
+
kind: "shared",
|
|
512
|
+
raw: token
|
|
513
|
+
};
|
|
514
|
+
return {
|
|
515
|
+
kind: "utility",
|
|
516
|
+
base,
|
|
517
|
+
raw: token
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
//#endregion
|
|
522
|
+
//#region ../../lib/tailwind/src/dependency-evaluator.ts
|
|
523
|
+
var DependencyEvaluator = class {
|
|
524
|
+
rules;
|
|
525
|
+
constructor(rules) {
|
|
526
|
+
this.rules = rules;
|
|
527
|
+
}
|
|
528
|
+
evaluate(token, state) {
|
|
529
|
+
switch (token.kind) {
|
|
530
|
+
case "layout": return token.value === state.mode;
|
|
531
|
+
case "conditional": return token.requires === state.family;
|
|
532
|
+
case "utility": return iterate.find(Object.keys(this.rules), (layout) => this.rules[layout].some((rule) => rule.test(token.base)) ? state.family === layout : null) ?? true;
|
|
533
|
+
case "item": return true;
|
|
534
|
+
case "gap":
|
|
535
|
+
case "shared": return state.family !== "none";
|
|
536
|
+
default: throw assertNever(token);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
//#endregion
|
|
541
|
+
//#region ../../lib/tailwind/src/dependency-rules.ts
|
|
542
|
+
const defaultDependencyRules = {
|
|
543
|
+
flex: [/^flex-/],
|
|
544
|
+
grid: [
|
|
545
|
+
/^grid-/,
|
|
546
|
+
/^auto-cols-/,
|
|
547
|
+
/^auto-rows-/,
|
|
548
|
+
/^justify-items-/
|
|
549
|
+
]
|
|
550
|
+
};
|
|
551
|
+
//#endregion
|
|
552
|
+
//#region ../../lib/tailwind/src/diagnostics.ts
|
|
553
|
+
const TailwindDiagnostics = {
|
|
554
|
+
multipleDisplayProps(active) {
|
|
555
|
+
return {
|
|
556
|
+
code: DiagnosticCode.TailwindMultipleDisplayProps,
|
|
557
|
+
category: DiagnosticCategory.Contract,
|
|
558
|
+
message: `[createTailwindPipeline] Multiple display props set (${active.join(", ")}); "${active[0]}" takes precedence.`
|
|
559
|
+
};
|
|
560
|
+
},
|
|
561
|
+
reservedLayoutLiteral(reserved) {
|
|
562
|
+
return {
|
|
563
|
+
code: DiagnosticCode.TailwindReservedLayoutLiteral,
|
|
564
|
+
category: DiagnosticCategory.Contract,
|
|
565
|
+
message: `[createTailwindPipeline] Reserved display class(es) ${reserved.map((r) => `"${r}"`).join(", ")} found in resolved classes. The display mode is controlled by the display props (flex, inline-flex, grid, block, hidden, etc.), not by class strings.`
|
|
566
|
+
};
|
|
567
|
+
},
|
|
568
|
+
deadVariantClass(dim, value, mode, classStr) {
|
|
569
|
+
return {
|
|
570
|
+
code: DiagnosticCode.TailwindDeadVariantClass,
|
|
571
|
+
category: DiagnosticCategory.Contract,
|
|
572
|
+
message: `[createTailwindPipeline] Variant "${dim}=${value}" contributes only classes stripped under layout mode "${mode}" ("${classStr}") — it produces nothing in this mode.`
|
|
573
|
+
};
|
|
574
|
+
},
|
|
575
|
+
layoutOnVoidTag(tag, mode) {
|
|
576
|
+
return {
|
|
577
|
+
code: DiagnosticCode.TailwindLayoutOnVoidTag,
|
|
578
|
+
category: DiagnosticCategory.Contract,
|
|
579
|
+
message: `[createTailwindPipeline] "${mode}" sets <${tag}>'s inner display, but <${tag}> is a void element and can never have children — there is nothing for a flex/grid formatting context to apply to, so "${mode}" (and any gap-* utility) has no effect here.`
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
//#endregion
|
|
584
|
+
//#region ../../lib/tailwind/src/layout-state.ts
|
|
585
|
+
/**
|
|
586
|
+
* The resolved display mode for a single render.
|
|
587
|
+
*
|
|
588
|
+
* Mode is owned by the display props; a display class literal in the resolved
|
|
589
|
+
* class string is a reserved-literal authoring mistake. Defaults to `'none'`
|
|
590
|
+
* when no prop is set.
|
|
591
|
+
*
|
|
592
|
+
* `family` is derived from mode: `'flex'` for flex/inline-flex, `'grid'` for
|
|
593
|
+
* grid/inline-grid, `'none'` for all other values (and when no prop is set).
|
|
594
|
+
* The evaluator uses family — not mode — for utility and gap filtering.
|
|
595
|
+
*/
|
|
596
|
+
var LayoutState = class {
|
|
597
|
+
#mode;
|
|
598
|
+
#family;
|
|
599
|
+
constructor(mode) {
|
|
600
|
+
this.#mode = mode;
|
|
601
|
+
this.#family = mode === "none" ? "none" : LAYOUT_FAMILY_MAP[mode];
|
|
602
|
+
Object.freeze(this);
|
|
603
|
+
}
|
|
604
|
+
get mode() {
|
|
605
|
+
return this.#mode;
|
|
606
|
+
}
|
|
607
|
+
get family() {
|
|
608
|
+
return this.#family;
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
//#endregion
|
|
612
|
+
//#region ../../lib/tailwind/src/create-tailwind-pipeline.ts
|
|
613
|
+
const DEV = process.env.NODE_ENV !== "production";
|
|
614
|
+
const devDiagnostics = new Diagnostics(new ConsoleReporter(), new DefaultPolicy({
|
|
615
|
+
reportThreshold: Severity.Warning,
|
|
616
|
+
throwThreshold: Severity.Fatal
|
|
617
|
+
}));
|
|
618
|
+
const classifier = new ClassClassifier();
|
|
619
|
+
const evaluator = new DependencyEvaluator(defaultDependencyRules);
|
|
620
|
+
const builder = new ClassBuilder();
|
|
621
|
+
const VOID_TAG_SET = new Set(VOID_TAGS);
|
|
622
|
+
function normalizeVariantValue(value) {
|
|
623
|
+
if (isString(value)) return value;
|
|
624
|
+
return value.join(" ");
|
|
625
|
+
}
|
|
626
|
+
function resolveLayout(diagnostics, props) {
|
|
627
|
+
const active = [];
|
|
628
|
+
iterate.forEach(layoutKeys, (key) => {
|
|
629
|
+
if (props[key]) active.push(key);
|
|
630
|
+
});
|
|
631
|
+
if (DEV && active.length > 1) diagnostics.warn(TailwindDiagnostics.multipleDisplayProps(active));
|
|
632
|
+
return active[0] ?? "none";
|
|
633
|
+
}
|
|
634
|
+
function warnLayoutOnVoidTag(diagnostics, tag, state) {
|
|
635
|
+
if (state.family === "none" || !isString(tag) || !VOID_TAG_SET.has(tag)) return;
|
|
636
|
+
diagnostics.warn(TailwindDiagnostics.layoutOnVoidTag(tag, state.mode));
|
|
637
|
+
}
|
|
638
|
+
function warnReservedLayoutLiterals(diagnostics, tokens) {
|
|
639
|
+
const reserved = [];
|
|
640
|
+
iterate.forEach(tokens, (token) => {
|
|
641
|
+
if (token.kind === "layout") reserved.push(token.raw);
|
|
642
|
+
});
|
|
643
|
+
if (reserved.length === 0) return;
|
|
644
|
+
diagnostics.warn(TailwindDiagnostics.reservedLayoutLiteral(reserved));
|
|
645
|
+
}
|
|
646
|
+
function getVariantConfig(options) {
|
|
647
|
+
return options.variants;
|
|
648
|
+
}
|
|
649
|
+
function getCompoundVariants(options) {
|
|
650
|
+
return options.compoundVariants ?? [];
|
|
651
|
+
}
|
|
652
|
+
function classifyTokens(className) {
|
|
653
|
+
return className.split(/\s+/).filter(Boolean).map(classifier.classify);
|
|
654
|
+
}
|
|
655
|
+
function compoundDimensions(compounds) {
|
|
656
|
+
if (compounds.length === 0) return EMPTY_SET;
|
|
657
|
+
const dims = /* @__PURE__ */ new Set();
|
|
658
|
+
iterate.forEach(compounds, (compound) => {
|
|
659
|
+
iterate.forEachKey(compound, (key) => {
|
|
660
|
+
if (!COMPOUND_META_KEYS.has(key)) dims.add(key);
|
|
661
|
+
});
|
|
662
|
+
});
|
|
663
|
+
return dims;
|
|
664
|
+
}
|
|
665
|
+
function getDefaultVariants(options) {
|
|
666
|
+
return options.defaultVariants;
|
|
667
|
+
}
|
|
668
|
+
function resolveActiveSelection(options, variants, props, recipe) {
|
|
669
|
+
const preset = recipe ? options.recipeMap?.[recipe] : void 0;
|
|
670
|
+
const defaults = getDefaultVariants(options);
|
|
671
|
+
const selection = {};
|
|
672
|
+
iterate.forEachKey(variants, (dim) => {
|
|
673
|
+
const value = props[dim] ?? preset?.[dim] ?? defaults?.[dim];
|
|
674
|
+
if (value !== void 0 && value !== null) selection[dim] = String(value);
|
|
675
|
+
});
|
|
676
|
+
return selection;
|
|
677
|
+
}
|
|
678
|
+
function warnDeadVariants(diagnostics, options, compoundDims, props, recipe, state) {
|
|
679
|
+
const variants = getVariantConfig(options);
|
|
680
|
+
if (!variants) return;
|
|
681
|
+
const selection = resolveActiveSelection(options, variants, props, recipe);
|
|
682
|
+
iterate.forEachEntry(selection, (dim, value) => {
|
|
683
|
+
if (compoundDims.has(dim)) return;
|
|
684
|
+
const raw = variants[dim]?.[value];
|
|
685
|
+
if (raw == null) return;
|
|
686
|
+
const classStr = normalizeVariantValue(raw);
|
|
687
|
+
const tokens = classifyTokens(classStr);
|
|
688
|
+
if (tokens.length === 0) return;
|
|
689
|
+
if (tokens.every((t) => !evaluator.evaluate(t, state))) diagnostics.warn(TailwindDiagnostics.deadVariantClass(dim, value, state.mode, classStr));
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Layout-aware class pipeline for Tailwind CSS utility class strings.
|
|
694
|
+
*
|
|
695
|
+
* This is a `ClassPluginFactory` — the runtime calls it with the component's
|
|
696
|
+
* resolved pipeline options and strict mode. Do NOT call it yourself; pass the
|
|
697
|
+
* function reference as `styling.plugin` and let the runtime invoke it.
|
|
698
|
+
*
|
|
699
|
+
* @example
|
|
700
|
+
* ```ts
|
|
701
|
+
* // CORRECT — pass the reference; the runtime calls it
|
|
702
|
+
* createContractComponent({
|
|
703
|
+
* tag: 'div',
|
|
704
|
+
* styling: {
|
|
705
|
+
* base: 'items-center',
|
|
706
|
+
* plugin: createTailwindPipeline,
|
|
707
|
+
* },
|
|
708
|
+
* })
|
|
709
|
+
*
|
|
710
|
+
* // WRONG — calling it manually produces a ClassPlugin where a ClassPluginFactory is expected
|
|
711
|
+
* createContractComponent({
|
|
712
|
+
* tag: 'div',
|
|
713
|
+
* styling: {
|
|
714
|
+
* plugin: createTailwindPipeline({ base: 'items-center' }, false),
|
|
715
|
+
* },
|
|
716
|
+
* })
|
|
717
|
+
* ```
|
|
718
|
+
*
|
|
719
|
+
* With the plugin active, pass any display prop (`flex`, `inline-flex`, `grid`,
|
|
720
|
+
* `inline-grid`, `block`, `hidden`, etc.) as a boolean to control the display
|
|
721
|
+
* mode. The pipeline injects the display class and strips conflicting utilities:
|
|
722
|
+
* flex-family modes strip `grid-*`; grid-family modes strip `flex-*`; all other
|
|
723
|
+
* display values (and no prop) strip both `flex-*` and `grid-*`.
|
|
724
|
+
*/
|
|
725
|
+
function createTailwindPipeline(options, diagnostics) {
|
|
726
|
+
const innerPipeline = createClassPipeline(options);
|
|
727
|
+
const compoundDims = compoundDimensions(getCompoundVariants(options));
|
|
728
|
+
const resolveLayoutContext = (tag, props, className, recipe) => {
|
|
729
|
+
const mode = resolveLayout(devDiagnostics, props);
|
|
730
|
+
const tokens = classifyTokens(innerPipeline(tag, props, className, recipe) ?? "");
|
|
731
|
+
const state = new LayoutState(mode);
|
|
732
|
+
const filtered = tokens.filter((token) => evaluator.evaluate(token, state));
|
|
733
|
+
if (DEV) warnLayoutOnVoidTag(devDiagnostics, tag, state);
|
|
734
|
+
return {
|
|
735
|
+
mode,
|
|
736
|
+
state,
|
|
737
|
+
filtered,
|
|
738
|
+
tokens,
|
|
739
|
+
props,
|
|
740
|
+
recipe
|
|
741
|
+
};
|
|
742
|
+
};
|
|
743
|
+
const buildClassString = (ctx) => {
|
|
744
|
+
const built = builder.build(ctx.filtered);
|
|
745
|
+
if (ctx.mode === "none") return built;
|
|
746
|
+
return ctx.filtered.some((t) => t.kind === "layout" && t.value === ctx.mode) ? built : cn(ctx.mode, built);
|
|
747
|
+
};
|
|
748
|
+
const emitDiagnosticsFromContext = (ctx) => {
|
|
749
|
+
if (!DEV) return;
|
|
750
|
+
warnReservedLayoutLiterals(diagnostics, ctx.tokens);
|
|
751
|
+
warnDeadVariants(diagnostics, options, compoundDims, ctx.props, ctx.recipe, ctx.state);
|
|
752
|
+
};
|
|
753
|
+
const combined = (ctx) => {
|
|
754
|
+
const built = buildClassString(ctx);
|
|
755
|
+
emitDiagnosticsFromContext(ctx);
|
|
756
|
+
return built;
|
|
757
|
+
};
|
|
758
|
+
const mainPipeline = composePipelines(resolveLayoutContext, combined);
|
|
759
|
+
return {
|
|
760
|
+
ownedKeys: LAYOUT_OWNED_KEYS,
|
|
761
|
+
pipeline(tag, props, className, recipe) {
|
|
762
|
+
return mainPipeline(tag, props, className, recipe);
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
//#endregion
|
|
767
|
+
export { createTailwindPipeline, layoutKeys };
|