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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -0
  3. package/dist/_shared/diagnostics.d.ts +312 -0
  4. package/dist/_shared/diagnostics.js +360 -0
  5. package/dist/build-runtime-CJ_nQEaZ.js +5065 -0
  6. package/dist/codemod/index.d.ts +2 -0
  7. package/dist/codemod/index.js +176520 -0
  8. package/dist/contract/index.d.ts +677 -0
  9. package/dist/contract/index.js +341 -0
  10. package/dist/eslint/index.d.ts +90 -0
  11. package/dist/eslint/index.js +1047 -0
  12. package/dist/guards/index.d.ts +78 -0
  13. package/dist/guards/index.js +118 -0
  14. package/dist/html/index.d.ts +151 -0
  15. package/dist/html/index.js +1244 -0
  16. package/dist/index-BIBd_iPD.d.ts +951 -0
  17. package/dist/lit/index.d.ts +862 -0
  18. package/dist/lit/index.js +4893 -0
  19. package/dist/preact/index.d.ts +796 -0
  20. package/dist/preact/index.js +5043 -0
  21. package/dist/react/index.d.ts +28 -0
  22. package/dist/react/index.js +205 -0
  23. package/dist/react/legacy.d.ts +29 -0
  24. package/dist/react/legacy.js +80 -0
  25. package/dist/solid/index.d.ts +728 -0
  26. package/dist/solid/index.js +4821 -0
  27. package/dist/svelte/Polymorphic.svelte +190 -0
  28. package/dist/svelte/_polymorphic-runtime.d.ts +102 -0
  29. package/dist/svelte/_polymorphic-runtime.js +371 -0
  30. package/dist/svelte/index.d.ts +994 -0
  31. package/dist/svelte/index.js +4482 -0
  32. package/dist/tailwind/index.d.ts +197 -0
  33. package/dist/tailwind/index.js +767 -0
  34. package/dist/tailwind/safelist.css +20 -0
  35. package/dist/ts-plugin/index.cjs +166 -0
  36. package/dist/ts-plugin/index.d.cts +9 -0
  37. package/dist/utils/index.d.ts +19 -0
  38. package/dist/utils/index.js +21 -0
  39. package/dist/vite-plugin/index.d.ts +200 -0
  40. package/dist/vite-plugin/index.js +2106 -0
  41. package/dist/vue/index.d.ts +729 -0
  42. package/dist/vue/index.js +4945 -0
  43. package/dist/web/index.d.ts +832 -0
  44. package/dist/web/index.js +4868 -0
  45. 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 };