tailwind-styled-v4 4.0.0 → 5.0.1

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 (194) hide show
  1. package/CHANGELOG.md +398 -0
  2. package/LICENSE +21 -0
  3. package/README.md +532 -0
  4. package/dist/analyzer.d.mts +114 -0
  5. package/dist/analyzer.d.ts +114 -0
  6. package/dist/analyzer.js +1555 -0
  7. package/dist/analyzer.js.map +1 -0
  8. package/dist/analyzer.mjs +1544 -0
  9. package/dist/analyzer.mjs.map +1 -0
  10. package/dist/animate.d.mts +46 -0
  11. package/dist/animate.d.ts +41 -112
  12. package/dist/animate.js +792 -235
  13. package/dist/animate.js.map +1 -1
  14. package/dist/animate.mjs +782 -0
  15. package/dist/animate.mjs.map +1 -0
  16. package/dist/atomic.d.mts +18 -0
  17. package/dist/atomic.d.ts +18 -0
  18. package/dist/atomic.js +191 -0
  19. package/dist/atomic.js.map +1 -0
  20. package/dist/atomic.mjs +185 -0
  21. package/dist/atomic.mjs.map +1 -0
  22. package/dist/cli.d.mts +1 -0
  23. package/dist/cli.d.ts +1 -0
  24. package/dist/cli.js +6063 -0
  25. package/dist/cli.js.map +1 -0
  26. package/dist/cli.mjs +6053 -0
  27. package/dist/cli.mjs.map +1 -0
  28. package/dist/{compiler.d.cts → compiler.d.mts} +503 -210
  29. package/dist/compiler.d.ts +503 -210
  30. package/dist/compiler.js +1549 -566
  31. package/dist/compiler.js.map +1 -1
  32. package/dist/{compiler.cjs → compiler.mjs} +1476 -627
  33. package/dist/compiler.mjs.map +1 -0
  34. package/dist/dashboard.d.mts +272 -0
  35. package/dist/dashboard.d.ts +272 -0
  36. package/dist/dashboard.js +249 -0
  37. package/dist/dashboard.js.map +1 -0
  38. package/dist/dashboard.mjs +239 -0
  39. package/dist/dashboard.mjs.map +1 -0
  40. package/dist/devtools.js +336 -211
  41. package/dist/devtools.js.map +1 -1
  42. package/dist/{devtools.cjs → devtools.mjs} +331 -220
  43. package/dist/devtools.mjs.map +1 -0
  44. package/dist/engine.d.mts +84 -0
  45. package/dist/engine.d.ts +84 -0
  46. package/dist/engine.js +3014 -0
  47. package/dist/engine.js.map +1 -0
  48. package/dist/engine.mjs +3005 -0
  49. package/dist/engine.mjs.map +1 -0
  50. package/dist/{index.d.cts → index.d.mts} +75 -4
  51. package/dist/index.d.ts +75 -4
  52. package/dist/index.js +1341 -149
  53. package/dist/index.js.map +1 -1
  54. package/dist/index.mjs +2162 -0
  55. package/dist/index.mjs.map +1 -0
  56. package/dist/liveTokenEngine-DYN3Zale.d.mts +34 -0
  57. package/dist/liveTokenEngine-DYN3Zale.d.ts +34 -0
  58. package/dist/next.d.mts +55 -0
  59. package/dist/next.d.ts +30 -20
  60. package/dist/next.js +6947 -149
  61. package/dist/next.js.map +1 -1
  62. package/dist/next.mjs +7050 -0
  63. package/dist/next.mjs.map +1 -0
  64. package/dist/plugin.d.mts +90 -0
  65. package/dist/plugin.d.ts +90 -0
  66. package/dist/plugin.js +185 -0
  67. package/dist/plugin.js.map +1 -0
  68. package/dist/plugin.mjs +174 -0
  69. package/dist/plugin.mjs.map +1 -0
  70. package/dist/pluginRegistry.d.mts +83 -0
  71. package/dist/pluginRegistry.d.ts +83 -0
  72. package/dist/pluginRegistry.js +303 -0
  73. package/dist/pluginRegistry.js.map +1 -0
  74. package/dist/pluginRegistry.mjs +298 -0
  75. package/dist/pluginRegistry.mjs.map +1 -0
  76. package/dist/{preset.d.cts → preset.d.mts} +29 -2
  77. package/dist/preset.d.ts +29 -2
  78. package/dist/preset.js +318 -21
  79. package/dist/preset.js.map +1 -1
  80. package/dist/preset.mjs +414 -0
  81. package/dist/preset.mjs.map +1 -0
  82. package/dist/rspack.d.mts +33 -0
  83. package/dist/rspack.d.ts +33 -0
  84. package/dist/rspack.js +55 -0
  85. package/dist/rspack.js.map +1 -0
  86. package/dist/rspack.mjs +45 -0
  87. package/dist/rspack.mjs.map +1 -0
  88. package/dist/runtime.d.mts +62 -0
  89. package/dist/runtime.d.ts +62 -0
  90. package/dist/runtime.js +207 -0
  91. package/dist/runtime.js.map +1 -0
  92. package/dist/runtime.mjs +188 -0
  93. package/dist/runtime.mjs.map +1 -0
  94. package/dist/runtimeCss.d.mts +65 -0
  95. package/dist/runtimeCss.d.ts +65 -0
  96. package/dist/runtimeCss.js +188 -0
  97. package/dist/runtimeCss.js.map +1 -0
  98. package/dist/runtimeCss.mjs +173 -0
  99. package/dist/runtimeCss.mjs.map +1 -0
  100. package/dist/scanner.d.mts +25 -0
  101. package/dist/scanner.d.ts +25 -0
  102. package/dist/scanner.js +717 -0
  103. package/dist/scanner.js.map +1 -0
  104. package/dist/scanner.mjs +703 -0
  105. package/dist/scanner.mjs.map +1 -0
  106. package/dist/shared.d.mts +85 -0
  107. package/dist/shared.d.ts +85 -0
  108. package/dist/shared.js +255 -0
  109. package/dist/shared.js.map +1 -0
  110. package/dist/shared.mjs +233 -0
  111. package/dist/shared.mjs.map +1 -0
  112. package/dist/storybookAddon.d.mts +108 -0
  113. package/dist/storybookAddon.d.ts +108 -0
  114. package/dist/storybookAddon.js +95 -0
  115. package/dist/storybookAddon.js.map +1 -0
  116. package/dist/storybookAddon.mjs +88 -0
  117. package/dist/storybookAddon.mjs.map +1 -0
  118. package/dist/svelte.d.mts +114 -0
  119. package/dist/svelte.d.ts +114 -0
  120. package/dist/svelte.js +67 -0
  121. package/dist/svelte.js.map +1 -0
  122. package/dist/svelte.mjs +59 -0
  123. package/dist/svelte.mjs.map +1 -0
  124. package/dist/testing.d.mts +185 -0
  125. package/dist/testing.d.ts +185 -0
  126. package/dist/testing.js +173 -0
  127. package/dist/testing.js.map +1 -0
  128. package/dist/testing.mjs +158 -0
  129. package/dist/testing.mjs.map +1 -0
  130. package/dist/{theme.d.cts → theme.d.mts} +18 -11
  131. package/dist/theme.d.ts +18 -11
  132. package/dist/theme.js +205 -19
  133. package/dist/theme.js.map +1 -1
  134. package/dist/theme.mjs +311 -0
  135. package/dist/theme.mjs.map +1 -0
  136. package/dist/types-DXr2PmGP.d.mts +31 -0
  137. package/dist/types-DXr2PmGP.d.ts +31 -0
  138. package/dist/vite.d.mts +51 -0
  139. package/dist/vite.d.ts +35 -6
  140. package/dist/vite.js +4254 -57
  141. package/dist/vite.js.map +1 -1
  142. package/dist/vite.mjs +4281 -0
  143. package/dist/vite.mjs.map +1 -0
  144. package/dist/vue.d.mts +89 -0
  145. package/dist/vue.d.ts +89 -0
  146. package/dist/vue.js +104 -0
  147. package/dist/vue.js.map +1 -0
  148. package/dist/vue.mjs +96 -0
  149. package/dist/vue.mjs.map +1 -0
  150. package/package.json +173 -67
  151. package/dist/animate.cjs +0 -252
  152. package/dist/animate.cjs.map +0 -1
  153. package/dist/animate.d.cts +0 -117
  154. package/dist/astTransform-ua-eapqs.d.cts +0 -41
  155. package/dist/astTransform-ua-eapqs.d.ts +0 -41
  156. package/dist/compiler.cjs.map +0 -1
  157. package/dist/css.cjs +0 -71
  158. package/dist/css.cjs.map +0 -1
  159. package/dist/css.d.cts +0 -45
  160. package/dist/css.d.ts +0 -45
  161. package/dist/css.js +0 -62
  162. package/dist/css.js.map +0 -1
  163. package/dist/devtools.cjs.map +0 -1
  164. package/dist/index.cjs +0 -1058
  165. package/dist/index.cjs.map +0 -1
  166. package/dist/next.cjs +0 -268
  167. package/dist/next.cjs.map +0 -1
  168. package/dist/next.d.cts +0 -45
  169. package/dist/plugins.cjs +0 -396
  170. package/dist/plugins.cjs.map +0 -1
  171. package/dist/plugins.d.cts +0 -231
  172. package/dist/plugins.d.ts +0 -231
  173. package/dist/plugins.js +0 -381
  174. package/dist/plugins.js.map +0 -1
  175. package/dist/preset.cjs +0 -129
  176. package/dist/preset.cjs.map +0 -1
  177. package/dist/theme.cjs +0 -154
  178. package/dist/theme.cjs.map +0 -1
  179. package/dist/turbopackLoader.cjs +0 -2689
  180. package/dist/turbopackLoader.cjs.map +0 -1
  181. package/dist/turbopackLoader.d.cts +0 -22
  182. package/dist/turbopackLoader.d.ts +0 -22
  183. package/dist/turbopackLoader.js +0 -2681
  184. package/dist/turbopackLoader.js.map +0 -1
  185. package/dist/vite.cjs +0 -105
  186. package/dist/vite.cjs.map +0 -1
  187. package/dist/vite.d.cts +0 -22
  188. package/dist/webpackLoader.cjs +0 -2670
  189. package/dist/webpackLoader.cjs.map +0 -1
  190. package/dist/webpackLoader.d.cts +0 -24
  191. package/dist/webpackLoader.d.ts +0 -24
  192. package/dist/webpackLoader.js +0 -2662
  193. package/dist/webpackLoader.js.map +0 -1
  194. /package/dist/{devtools.d.cts → devtools.d.mts} +0 -0
@@ -0,0 +1,158 @@
1
+ /* tailwind-styled-v4 v5.0.1 | MIT | https://github.com/dictionar32/tailwind-styled-v4 */
2
+
3
+ // packages/testing/src/index.ts
4
+ function toHaveClass(className) {
5
+ return (value) => {
6
+ const pass = Boolean(value?.classList?.contains(className));
7
+ return {
8
+ pass,
9
+ message: () => `expected element ${pass ? "not " : ""}to contain class '${className}'`
10
+ };
11
+ };
12
+ }
13
+ function toHaveClasses(classNames) {
14
+ return (value) => {
15
+ if (!value) return { pass: false, message: () => "element is null or undefined" };
16
+ const missing = classNames.filter((c) => !value.classList.contains(c));
17
+ const pass = missing.length === 0;
18
+ return {
19
+ pass,
20
+ message: () => pass ? `expected element not to have all classes: ${classNames.join(", ")}` : `expected element to have classes: ${missing.join(", ")}`
21
+ };
22
+ };
23
+ }
24
+ function toNotHaveClass(className) {
25
+ return (value) => {
26
+ if (!value) return { pass: false, message: () => "element is null or undefined" };
27
+ const pass = !value.classList.contains(className);
28
+ return {
29
+ pass,
30
+ message: () => `expected element ${pass ? "" : "not "}to have class '${className}'`
31
+ };
32
+ };
33
+ }
34
+ var tailwindMatchers = { toHaveClass, toHaveClasses, toNotHaveClass };
35
+ function expectClasses(element, classes) {
36
+ if (!element) throw new Error("expectClasses: element is null or undefined");
37
+ const missing = classes.filter((c) => !element.classList.contains(c));
38
+ if (missing.length > 0) {
39
+ throw new Error(
40
+ `Expected element to have classes: ${missing.join(", ")}
41
+ Actual classes: ${element.className}`
42
+ );
43
+ }
44
+ }
45
+ function expectNoClasses(element, classes) {
46
+ if (!element) throw new Error("expectNoClasses: element is null or undefined");
47
+ const found = classes.filter((c) => element.classList.contains(c));
48
+ if (found.length > 0) {
49
+ throw new Error(
50
+ `Expected element NOT to have classes: ${found.join(", ")}
51
+ Actual classes: ${element.className}`
52
+ );
53
+ }
54
+ }
55
+ function getClassList(element) {
56
+ if (!element) return [];
57
+ return Array.from(element.classList).sort();
58
+ }
59
+ function snapshotVariants(render, variants) {
60
+ return variants.map((variant) => ({
61
+ variant,
62
+ output: render(variant)
63
+ }));
64
+ }
65
+ function expandVariantMatrix(matrix) {
66
+ const keys = Object.keys(matrix);
67
+ if (keys.length === 0) return [{}];
68
+ const result = [];
69
+ function walk(index, current) {
70
+ if (index >= keys.length) {
71
+ result.push({ ...current });
72
+ return;
73
+ }
74
+ const key = keys[index];
75
+ for (const value of matrix[key] ?? []) {
76
+ current[key] = value;
77
+ walk(index + 1, current);
78
+ }
79
+ }
80
+ walk(0, {});
81
+ return result;
82
+ }
83
+ function testAllVariants(matrix, testFn) {
84
+ const combinations = expandVariantMatrix(matrix);
85
+ for (const variant of combinations) {
86
+ testFn(variant);
87
+ }
88
+ }
89
+ function expectClassesEqual(actual, expected) {
90
+ const actualSet = new Set(actual.trim().split(/\s+/).filter(Boolean));
91
+ const expectedSet = new Set(expected.trim().split(/\s+/).filter(Boolean));
92
+ const missing = [...expectedSet].filter((c) => !actualSet.has(c));
93
+ const extra = [...actualSet].filter((c) => !expectedSet.has(c));
94
+ if (missing.length > 0 || extra.length > 0) {
95
+ const parts = [];
96
+ if (missing.length > 0) parts.push(`Missing: ${missing.join(", ")}`);
97
+ if (extra.length > 0) parts.push(`Extra: ${extra.join(", ")}`);
98
+ throw new Error(`Class mismatch:
99
+ ${parts.join("\n ")}`);
100
+ }
101
+ }
102
+ function expectEngineMetrics(metrics, expectations) {
103
+ if (expectations.minFiles !== void 0) {
104
+ const actual = metrics.totalFiles ?? 0;
105
+ if (actual < expectations.minFiles) {
106
+ throw new Error(
107
+ `Engine metrics: expected at least ${expectations.minFiles} files, got ${actual}`
108
+ );
109
+ }
110
+ }
111
+ if (expectations.maxBuildTimeMs !== void 0) {
112
+ const actual = metrics.buildTimeMs ?? 0;
113
+ if (actual > expectations.maxBuildTimeMs) {
114
+ throw new Error(
115
+ `Engine metrics: build took ${actual}ms, expected \u2264 ${expectations.maxBuildTimeMs}ms`
116
+ );
117
+ }
118
+ }
119
+ if (expectations.minUniqueClasses !== void 0) {
120
+ const actual = metrics.uniqueClasses ?? 0;
121
+ if (actual < expectations.minUniqueClasses) {
122
+ throw new Error(
123
+ `Engine metrics: expected at least ${expectations.minUniqueClasses} unique classes, got ${actual}`
124
+ );
125
+ }
126
+ }
127
+ if (expectations.cacheHitRateMin !== void 0) {
128
+ const hits = metrics.cacheHits ?? 0;
129
+ const total = hits + (metrics.cacheMisses ?? 0);
130
+ const rate = total > 0 ? hits / total : 0;
131
+ if (rate < expectations.cacheHitRateMin) {
132
+ throw new Error(
133
+ `Engine metrics: cache hit rate ${(rate * 100).toFixed(1)}%, expected \u2265 ${(expectations.cacheHitRateMin * 100).toFixed(1)}%`
134
+ );
135
+ }
136
+ }
137
+ }
138
+ function toHaveEngineMetrics(expectations) {
139
+ return (metrics) => {
140
+ try {
141
+ expectEngineMetrics(metrics, expectations);
142
+ return { pass: true, message: () => "engine metrics matched expectations" };
143
+ } catch (e) {
144
+ const msg = e instanceof Error ? e.message : String(e);
145
+ return { pass: false, message: () => msg };
146
+ }
147
+ };
148
+ }
149
+ var tailwindMatchersWithMetrics = {
150
+ toHaveClass,
151
+ toHaveClasses,
152
+ toNotHaveClass,
153
+ toHaveEngineMetrics
154
+ };
155
+
156
+ export { expandVariantMatrix, expectClasses, expectClassesEqual, expectEngineMetrics, expectNoClasses, getClassList, snapshotVariants, tailwindMatchers, tailwindMatchersWithMetrics, testAllVariants, toHaveClass, toHaveClasses, toHaveEngineMetrics, toNotHaveClass };
157
+ //# sourceMappingURL=testing.mjs.map
158
+ //# sourceMappingURL=testing.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../packages/testing/src/index.ts"],"names":[],"mappings":";;;AA6BO,SAAS,YAAY,SAAA,EAAmB;AAC7C,EAAA,OAAO,CAAC,KAAA,KAAmE;AACzE,IAAA,MAAM,OAAO,OAAA,CAAQ,KAAA,EAAO,SAAA,EAAW,QAAA,CAAS,SAAS,CAAC,CAAA;AAC1D,IAAA,OAAO;AAAA,MACL,IAAA;AAAA,MACA,SAAS,MAAM,CAAA,iBAAA,EAAoB,OAAO,MAAA,GAAS,EAAE,qBAAqB,SAAS,CAAA,CAAA;AAAA,KACrF;AAAA,EACF,CAAA;AACF;AASO,SAAS,cAAc,UAAA,EAAsB;AAClD,EAAA,OAAO,CAAC,KAAA,KAAsC;AAC5C,IAAA,IAAI,CAAC,OAAO,OAAO,EAAE,MAAM,KAAA,EAAO,OAAA,EAAS,MAAM,8BAAA,EAA+B;AAChF,IAAA,MAAM,OAAA,GAAU,UAAA,CAAW,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,KAAA,CAAM,SAAA,CAAU,QAAA,CAAS,CAAC,CAAC,CAAA;AACrE,IAAA,MAAM,IAAA,GAAO,QAAQ,MAAA,KAAW,CAAA;AAChC,IAAA,OAAO;AAAA,MACL,IAAA;AAAA,MACA,OAAA,EAAS,MACP,IAAA,GACI,CAAA,0CAAA,EAA6C,UAAA,CAAW,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,GAClE,CAAA,kCAAA,EAAqC,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,KAC/D;AAAA,EACF,CAAA;AACF;AAQO,SAAS,eAAe,SAAA,EAAmB;AAChD,EAAA,OAAO,CAAC,KAAA,KAAsC;AAC5C,IAAA,IAAI,CAAC,OAAO,OAAO,EAAE,MAAM,KAAA,EAAO,OAAA,EAAS,MAAM,8BAAA,EAA+B;AAChF,IAAA,MAAM,IAAA,GAAO,CAAC,KAAA,CAAM,SAAA,CAAU,SAAS,SAAS,CAAA;AAChD,IAAA,OAAO;AAAA,MACL,IAAA;AAAA,MACA,SAAS,MAAM,CAAA,iBAAA,EAAoB,OAAO,EAAA,GAAK,MAAM,kBAAkB,SAAS,CAAA,CAAA;AAAA,KAClF;AAAA,EACF,CAAA;AACF;AAGO,IAAM,gBAAA,GAAmB,EAAE,WAAA,EAAa,aAAA,EAAe,cAAA;AAYvD,SAAS,aAAA,CAAc,SAAqC,OAAA,EAAyB;AAC1F,EAAA,IAAI,CAAC,OAAA,EAAS,MAAM,IAAI,MAAM,6CAA6C,CAAA;AAC3E,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,OAAA,CAAQ,SAAA,CAAU,QAAA,CAAS,CAAC,CAAC,CAAA;AACpE,EAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,kCAAA,EAAqC,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC;AAAA,kBAAA,EAChC,QAAQ,SAAS,CAAA;AAAA,KAC1C;AAAA,EACF;AACF;AAQO,SAAS,eAAA,CAAgB,SAAqC,OAAA,EAAyB;AAC5F,EAAA,IAAI,CAAC,OAAA,EAAS,MAAM,IAAI,MAAM,+CAA+C,CAAA;AAC7E,EAAA,MAAM,KAAA,GAAQ,QAAQ,MAAA,CAAO,CAAC,MAAM,OAAA,CAAQ,SAAA,CAAU,QAAA,CAAS,CAAC,CAAC,CAAA;AACjE,EAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,sCAAA,EAAyC,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC;AAAA,kBAAA,EAClC,QAAQ,SAAS,CAAA;AAAA,KAC1C;AAAA,EACF;AACF;AASO,SAAS,aAAa,OAAA,EAA+C;AAC1E,EAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAC;AACtB,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,OAAA,CAAQ,SAAS,EAAE,IAAA,EAAK;AAC5C;AAsBO,SAAS,gBAAA,CAAoB,QAAgC,QAAA,EAAe;AACjF,EAAA,OAAO,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,MAAa;AAAA,IAChC,OAAA;AAAA,IACA,MAAA,EAAQ,OAAO,OAAO;AAAA,GACxB,CAAE,CAAA;AACJ;AAaO,SAAS,oBACd,MAAA,EACkD;AAClD,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA;AAC/B,EAAA,IAAI,KAAK,MAAA,KAAW,CAAA,EAAG,OAAO,CAAC,EAAE,CAAA;AAEjC,EAAA,MAAM,SAA2D,EAAC;AAElE,EAAA,SAAS,IAAA,CAAK,OAAe,OAAA,EAAoD;AAC/E,IAAA,IAAI,KAAA,IAAS,KAAK,MAAA,EAAQ;AACxB,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,GAAG,OAAA,EAAS,CAAA;AAC1B,MAAA;AAAA,IACF;AACA,IAAA,MAAM,GAAA,GAAM,KAAK,KAAK,CAAA;AACtB,IAAA,KAAA,MAAW,KAAA,IAAS,MAAA,CAAO,GAAG,CAAA,IAAK,EAAC,EAAG;AACrC,MAAA,OAAA,CAAQ,GAAG,CAAA,GAAI,KAAA;AACf,MAAA,IAAA,CAAK,KAAA,GAAQ,GAAG,OAAO,CAAA;AAAA,IACzB;AAAA,EACF;AAEA,EAAA,IAAA,CAAK,CAAA,EAAG,EAAE,CAAA;AACV,EAAA,OAAO,MAAA;AACT;AAeO,SAAS,eAAA,CACd,QACA,MAAA,EACM;AACN,EAAA,MAAM,YAAA,GAAe,oBAAoB,MAAM,CAAA;AAC/C,EAAA,KAAA,MAAW,WAAW,YAAA,EAAc;AAClC,IAAA,MAAA,CAAO,OAAO,CAAA;AAAA,EAChB;AACF;AAUO,SAAS,kBAAA,CAAmB,QAAgB,QAAA,EAAwB;AACzE,EAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAAI,MAAA,CAAO,IAAA,EAAK,CAAE,KAAA,CAAM,KAAK,CAAA,CAAE,MAAA,CAAO,OAAO,CAAC,CAAA;AACpE,EAAA,MAAM,WAAA,GAAc,IAAI,GAAA,CAAI,QAAA,CAAS,IAAA,EAAK,CAAE,KAAA,CAAM,KAAK,CAAA,CAAE,MAAA,CAAO,OAAO,CAAC,CAAA;AAExE,EAAA,MAAM,OAAA,GAAU,CAAC,GAAG,WAAW,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,SAAA,CAAU,GAAA,CAAI,CAAC,CAAC,CAAA;AAChE,EAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,SAAS,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,WAAA,CAAY,GAAA,CAAI,CAAC,CAAC,CAAA;AAE9D,EAAA,IAAI,OAAA,CAAQ,MAAA,GAAS,CAAA,IAAK,KAAA,CAAM,SAAS,CAAA,EAAG;AAC1C,IAAA,MAAM,QAAkB,EAAC;AACzB,IAAA,IAAI,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG,KAAA,CAAM,IAAA,CAAK,YAAY,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AACnE,IAAA,IAAI,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG,KAAA,CAAM,IAAA,CAAK,YAAY,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAC/D,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA;AAAA,EAAA,EAAsB,KAAA,CAAM,IAAA,CAAK,MAAM,CAAC,CAAA,CAAE,CAAA;AAAA,EAC5D;AACF;AAyBO,SAAS,mBAAA,CACd,SACA,YAAA,EAMM;AACN,EAAA,IAAI,YAAA,CAAa,aAAa,MAAA,EAAW;AACvC,IAAA,MAAM,MAAA,GAAS,QAAQ,UAAA,IAAc,CAAA;AACrC,IAAA,IAAI,MAAA,GAAS,aAAa,QAAA,EAAU;AAClC,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,kCAAA,EAAqC,YAAA,CAAa,QAAQ,CAAA,YAAA,EAAe,MAAM,CAAA;AAAA,OACjF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAI,YAAA,CAAa,mBAAmB,MAAA,EAAW;AAC7C,IAAA,MAAM,MAAA,GAAS,QAAQ,WAAA,IAAe,CAAA;AACtC,IAAA,IAAI,MAAA,GAAS,aAAa,cAAA,EAAgB;AACxC,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,2BAAA,EAA8B,MAAM,CAAA,oBAAA,EAAkB,YAAA,CAAa,cAAc,CAAA,EAAA;AAAA,OACnF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAI,YAAA,CAAa,qBAAqB,MAAA,EAAW;AAC/C,IAAA,MAAM,MAAA,GAAS,QAAQ,aAAA,IAAiB,CAAA;AACxC,IAAA,IAAI,MAAA,GAAS,aAAa,gBAAA,EAAkB;AAC1C,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,kCAAA,EAAqC,YAAA,CAAa,gBAAgB,CAAA,qBAAA,EAAwB,MAAM,CAAA;AAAA,OAClG;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAI,YAAA,CAAa,oBAAoB,MAAA,EAAW;AAC9C,IAAA,MAAM,IAAA,GAAO,QAAQ,SAAA,IAAa,CAAA;AAClC,IAAA,MAAM,KAAA,GAAQ,IAAA,IAAQ,OAAA,CAAQ,WAAA,IAAe,CAAA,CAAA;AAC7C,IAAA,MAAM,IAAA,GAAO,KAAA,GAAQ,CAAA,GAAI,IAAA,GAAO,KAAA,GAAQ,CAAA;AACxC,IAAA,IAAI,IAAA,GAAO,aAAa,eAAA,EAAiB;AACvC,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,+BAAA,EAAA,CAAmC,IAAA,GAAO,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAC,CAAA,mBAAA,EAAA,CAAkB,YAAA,CAAa,eAAA,GAAkB,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAAA,OAC3H;AAAA,IACF;AAAA,EACF;AACF;AAQO,SAAS,oBAAoB,YAAA,EAAyD;AAC3F,EAAA,OAAO,CAAC,OAAA,KAAmC;AACzC,IAAA,IAAI;AACF,MAAA,mBAAA,CAAoB,SAAS,YAAY,CAAA;AACzC,MAAA,OAAO,EAAE,IAAA,EAAM,IAAA,EAAM,OAAA,EAAS,MAAM,qCAAA,EAAsC;AAAA,IAC5E,SAAS,CAAA,EAAY;AACnB,MAAA,MAAM,MAAM,CAAA,YAAa,KAAA,GAAQ,CAAA,CAAE,OAAA,GAAU,OAAO,CAAC,CAAA;AACrD,MAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,MAAM,GAAA,EAAI;AAAA,IAC3C;AAAA,EACF,CAAA;AACF;AAGO,IAAM,2BAAA,GAA8B;AAAA,EACzC,WAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF","file":"testing.mjs","sourcesContent":["/**\n * tailwind-styled-v4 — Testing Utilities\n *\n * Integrasi dengan Jest / Vitest untuk test komponen tw().\n *\n * @example\n * // vitest.config.ts\n * import { tailwindStyledSetup } from '@tailwind-styled/testing'\n * export default defineConfig({ test: { setupFiles: ['@tailwind-styled/testing/setup'] } })\n *\n * // Button.test.ts\n * import { render } from '@testing-library/react'\n * import { expectClasses, getVariantClass } from '@tailwind-styled/testing'\n *\n * test('Button renders primary variant', () => {\n * const { container } = render(<Button intent=\"primary\" />)\n * expectClasses(container.firstChild, ['bg-blue-500', 'text-white'])\n * })\n */\n\n// ─── Jest/Vitest custom matchers ─────────────────────────────────────────────\n\n/**\n * Custom matcher: toHaveClass\n * Dipakai langsung atau via expect.extend(tailwindMatchers)\n *\n * @example\n * expect(element).toHaveClass('bg-blue-500')\n */\nexport function toHaveClass(className: string) {\n return (value: { classList?: { contains: (name: string) => boolean } }) => {\n const pass = Boolean(value?.classList?.contains(className))\n return {\n pass,\n message: () => `expected element ${pass ? \"not \" : \"\"}to contain class '${className}'`,\n }\n }\n}\n\n/**\n * Custom matcher: toHaveClasses\n * Cek beberapa class sekaligus\n *\n * @example\n * expect(element).toHaveClasses(['px-4', 'py-2', 'rounded'])\n */\nexport function toHaveClasses(classNames: string[]) {\n return (value: Element | null | undefined) => {\n if (!value) return { pass: false, message: () => \"element is null or undefined\" }\n const missing = classNames.filter((c) => !value.classList.contains(c))\n const pass = missing.length === 0\n return {\n pass,\n message: () =>\n pass\n ? `expected element not to have all classes: ${classNames.join(\", \")}`\n : `expected element to have classes: ${missing.join(\", \")}`,\n }\n }\n}\n\n/**\n * Custom matcher: toNotHaveClass\n *\n * @example\n * expect(element).toNotHaveClass('hidden')\n */\nexport function toNotHaveClass(className: string) {\n return (value: Element | null | undefined) => {\n if (!value) return { pass: false, message: () => \"element is null or undefined\" }\n const pass = !value.classList.contains(className)\n return {\n pass,\n message: () => `expected element ${pass ? \"\" : \"not \"}to have class '${className}'`,\n }\n }\n}\n\n/** Semua matchers — pakai dengan expect.extend(tailwindMatchers) */\nexport const tailwindMatchers = { toHaveClass, toHaveClasses, toNotHaveClass }\n\n// ─── Helper utilities ────────────────────────────────────────────────────────\n\n/**\n * Assert element punya semua class yang diharapkan.\n * Lebih ergonomis dari `expect(el).toHaveClasses([...])` untuk banyak class.\n *\n * @example\n * const { container } = render(<Button intent=\"primary\" size=\"lg\" />)\n * expectClasses(container.firstChild, ['bg-blue-500', 'text-white', 'h-12'])\n */\nexport function expectClasses(element: Element | null | undefined, classes: string[]): void {\n if (!element) throw new Error(\"expectClasses: element is null or undefined\")\n const missing = classes.filter((c) => !element.classList.contains(c))\n if (missing.length > 0) {\n throw new Error(\n `Expected element to have classes: ${missing.join(\", \")}\\n` +\n ` Actual classes: ${element.className}`\n )\n }\n}\n\n/**\n * Assert element tidak punya class tertentu.\n *\n * @example\n * expectNoClasses(container.firstChild, ['opacity-50', 'cursor-not-allowed'])\n */\nexport function expectNoClasses(element: Element | null | undefined, classes: string[]): void {\n if (!element) throw new Error(\"expectNoClasses: element is null or undefined\")\n const found = classes.filter((c) => element.classList.contains(c))\n if (found.length > 0) {\n throw new Error(\n `Expected element NOT to have classes: ${found.join(\", \")}\\n` +\n ` Actual classes: ${element.className}`\n )\n }\n}\n\n/**\n * Extract class list dari element sebagai sorted array.\n * Berguna untuk snapshot testing.\n *\n * @example\n * expect(getClassList(element)).toMatchSnapshot()\n */\nexport function getClassList(element: Element | null | undefined): string[] {\n if (!element) return []\n return Array.from(element.classList).sort()\n}\n\n// ─── Variant snapshot helpers ────────────────────────────────────────────────\n\n/**\n * Buat snapshot dari semua kombinasi variant.\n * Berguna untuk regression testing pada styled components.\n *\n * @example\n * const buttonVariants = snapshotVariants(\n * (props) => {\n * const { container } = render(<Button {...props} />)\n * return container.firstChild?.className ?? ''\n * },\n * [\n * { intent: 'primary', size: 'sm' },\n * { intent: 'primary', size: 'lg' },\n * { intent: 'danger', size: 'sm' },\n * ]\n * )\n * expect(buttonVariants).toMatchSnapshot()\n */\nexport function snapshotVariants<T>(render: (variant: T) => string, variants: T[]) {\n return variants.map((variant) => ({\n variant,\n output: render(variant),\n }))\n}\n\n/**\n * Generate semua kombinasi dari variant matrix.\n *\n * @example\n * const combinations = expandVariantMatrix({\n * intent: ['primary', 'danger'],\n * size: ['sm', 'md', 'lg'],\n * disabled: [true, false],\n * })\n * // → 2 × 3 × 2 = 12 kombinasi\n */\nexport function expandVariantMatrix(\n matrix: Record<string, Array<string | number | boolean>>\n): Array<Record<string, string | number | boolean>> {\n const keys = Object.keys(matrix)\n if (keys.length === 0) return [{}]\n\n const result: Array<Record<string, string | number | boolean>> = []\n\n function walk(index: number, current: Record<string, string | number | boolean>) {\n if (index >= keys.length) {\n result.push({ ...current })\n return\n }\n const key = keys[index]!\n for (const value of matrix[key] ?? []) {\n current[key] = value\n walk(index + 1, current)\n }\n }\n\n walk(0, {})\n return result\n}\n\n/**\n * Test semua kombinasi variant sekaligus — no missing coverage.\n *\n * @example\n * testAllVariants(\n * Button,\n * { intent: ['primary','danger'], size: ['sm','lg'] },\n * (el, variant) => {\n * expect(el).not.toBeNull()\n * if (variant.intent === 'primary') expectClasses(el, ['bg-blue-500'])\n * }\n * )\n */\nexport function testAllVariants(\n matrix: Record<string, Array<string | number | boolean>>,\n testFn: (variant: Record<string, string | number | boolean>) => void\n): void {\n const combinations = expandVariantMatrix(matrix)\n for (const variant of combinations) {\n testFn(variant)\n }\n}\n\n// ─── CSS-in-JS output assertions ─────────────────────────────────────────────\n\n/**\n * Bandingkan dua class string secara semantik (urutan tidak penting).\n *\n * @example\n * expectClassesEqual('px-4 py-2 bg-blue-500', 'bg-blue-500 px-4 py-2') // pass\n */\nexport function expectClassesEqual(actual: string, expected: string): void {\n const actualSet = new Set(actual.trim().split(/\\s+/).filter(Boolean))\n const expectedSet = new Set(expected.trim().split(/\\s+/).filter(Boolean))\n\n const missing = [...expectedSet].filter((c) => !actualSet.has(c))\n const extra = [...actualSet].filter((c) => !expectedSet.has(c))\n\n if (missing.length > 0 || extra.length > 0) {\n const parts: string[] = []\n if (missing.length > 0) parts.push(`Missing: ${missing.join(\", \")}`)\n if (extra.length > 0) parts.push(`Extra: ${extra.join(\", \")}`)\n throw new Error(`Class mismatch:\\n ${parts.join(\"\\n \")}`)\n }\n}\n\n// ─── Engine metrics matchers ──────────────────────────────────────────────────\n\nexport interface EngineMetricsSnapshot {\n totalFiles?: number\n uniqueClasses?: number\n buildTimeMs?: number\n cssBytes?: number\n cacheHits?: number\n cacheMisses?: number\n incrementalRuns?: number\n fullRescans?: number\n}\n\n/**\n * Assert engine metrics snapshot meets minimum thresholds.\n *\n * @example\n * const result = await engine.build()\n * expectEngineMetrics(metrics.snapshot(), {\n * totalFiles: 10,\n * buildTimeMs: 5000, // max\n * })\n */\nexport function expectEngineMetrics(\n metrics: EngineMetricsSnapshot,\n expectations: {\n minFiles?: number\n maxBuildTimeMs?: number\n minUniqueClasses?: number\n cacheHitRateMin?: number // 0–1\n }\n): void {\n if (expectations.minFiles !== undefined) {\n const actual = metrics.totalFiles ?? 0\n if (actual < expectations.minFiles) {\n throw new Error(\n `Engine metrics: expected at least ${expectations.minFiles} files, got ${actual}`\n )\n }\n }\n\n if (expectations.maxBuildTimeMs !== undefined) {\n const actual = metrics.buildTimeMs ?? 0\n if (actual > expectations.maxBuildTimeMs) {\n throw new Error(\n `Engine metrics: build took ${actual}ms, expected ≤ ${expectations.maxBuildTimeMs}ms`\n )\n }\n }\n\n if (expectations.minUniqueClasses !== undefined) {\n const actual = metrics.uniqueClasses ?? 0\n if (actual < expectations.minUniqueClasses) {\n throw new Error(\n `Engine metrics: expected at least ${expectations.minUniqueClasses} unique classes, got ${actual}`\n )\n }\n }\n\n if (expectations.cacheHitRateMin !== undefined) {\n const hits = metrics.cacheHits ?? 0\n const total = hits + (metrics.cacheMisses ?? 0)\n const rate = total > 0 ? hits / total : 0\n if (rate < expectations.cacheHitRateMin) {\n throw new Error(\n `Engine metrics: cache hit rate ${(rate * 100).toFixed(1)}%, expected ≥ ${(expectations.cacheHitRateMin * 100).toFixed(1)}%`\n )\n }\n }\n}\n\n/**\n * Custom Jest/Vitest matcher: toHaveEngineMetrics\n *\n * @example\n * expect(metrics).toHaveEngineMetrics({ minFiles: 1 })\n */\nexport function toHaveEngineMetrics(expectations: Parameters<typeof expectEngineMetrics>[1]) {\n return (metrics: EngineMetricsSnapshot) => {\n try {\n expectEngineMetrics(metrics, expectations)\n return { pass: true, message: () => \"engine metrics matched expectations\" }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e)\n return { pass: false, message: () => msg }\n }\n }\n}\n\n/** All matchers including engine metrics */\nexport const tailwindMatchersWithMetrics = {\n toHaveClass,\n toHaveClasses,\n toNotHaveClass,\n toHaveEngineMetrics,\n}\n"]}
@@ -1,15 +1,21 @@
1
+ export { L as LiveTokenEngineBridge, a as LiveTokenSet, T as TokenMap, b as TokenSubscriber, c as applyTokenSet, d as createUseTokens, g as generateTokenCssString, e as getToken, f as getTokens, l as liveToken, h as liveTokenEngine, s as setToken, i as setTokens, j as subscribeTokens, t as tokenRef, k as tokenVar } from './liveTokenEngine-DYN3Zale.mjs';
2
+
1
3
  /**
2
- * tailwind-styled-v4 — Multi-Theme Engine
4
+ * tailwind-styled-v5 — Multi-Theme Engine + Live Token Engine
3
5
  *
4
6
  * Enterprise-grade theming. Support light/dark/brand themes dengan
5
7
  * CSS variables. Zero runtime overhead — themes di-resolve via CSS.
6
8
  *
9
+ * Live token engine provides runtime token state management with
10
+ * CSS variable sync to document root.
11
+ *
7
12
  * Fitur:
8
13
  * - Multiple named themes (light, dark, brand, high-contrast)
9
14
  * - CSS variable output (Tailwind v4 compatible)
10
15
  * - Theme contract (TypeScript-safe — missing tokens = TS error)
11
16
  * - Per-component theme override
12
17
  * - White-label ready
18
+ * - Live token engine (runtime token state + CSS sync)
13
19
  *
14
20
  * @example
15
21
  * // 1. Define contract
@@ -35,17 +41,18 @@
35
41
  * // 4. Apply in layout
36
42
  * // <html data-theme="dark"> or inject CSS
37
43
  */
38
- type TokenMap = Record<string, Record<string, string>>;
39
- interface ThemeContract<T extends TokenMap> {
44
+
45
+ type ThemeTokenMap = Record<string, Record<string, string>>;
46
+ interface ThemeContract<T extends ThemeTokenMap> {
40
47
  _contract: T;
41
48
  _vars: ThemeVars<T>;
42
49
  }
43
- type ThemeVars<T extends TokenMap> = {
50
+ type ThemeVars<T extends ThemeTokenMap> = {
44
51
  [Group in keyof T]: {
45
52
  [Token in keyof T[Group]]: string;
46
53
  };
47
54
  };
48
- interface Theme<T extends TokenMap> {
55
+ interface Theme<T extends ThemeTokenMap> {
49
56
  name: string;
50
57
  contract: ThemeContract<T>;
51
58
  values: T;
@@ -70,7 +77,7 @@ interface Theme<T extends TokenMap> {
70
77
  * const Card = tw.div`bg-[${contract._vars.colors.bg}]`
71
78
  * // → tw.div`bg-[var(--colors-bg)]`
72
79
  */
73
- declare function defineThemeContract<T extends TokenMap>(shape: T): ThemeContract<T>;
80
+ declare function defineThemeContract<T extends ThemeTokenMap>(shape: T): ThemeContract<T>;
74
81
  /**
75
82
  * Create a typed theme that satisfies a contract.
76
83
  *
@@ -79,12 +86,12 @@ declare function defineThemeContract<T extends TokenMap>(shape: T): ThemeContrac
79
86
  * @param values - Token values (TypeScript enforces completeness)
80
87
  * @param asRoot - If true, use :root selector. Default: false (uses [data-theme])
81
88
  */
82
- declare function createTheme<T extends TokenMap>(contract: ThemeContract<T>, name: string, values: T, asRoot?: boolean): Theme<T>;
89
+ declare function createTheme<T extends ThemeTokenMap>(contract: ThemeContract<T>, name: string, values: T, asRoot?: boolean): Theme<T>;
83
90
  declare class ThemeRegistry {
84
91
  private themes;
85
92
  private defaultTheme;
86
93
  /** Register a theme */
87
- register<T extends TokenMap>(theme: Theme<T>, isDefault?: boolean): this;
94
+ register<T extends ThemeTokenMap>(theme: Theme<T>, isDefault?: boolean): this;
88
95
  /** Get a theme by name */
89
96
  get(name: string): Theme<any> | undefined;
90
97
  /** Get all theme names */
@@ -116,7 +123,7 @@ declare class ThemeRegistry {
116
123
  */
117
124
  current(target?: HTMLElement): string | null;
118
125
  }
119
- interface MultiThemeConfig<T extends TokenMap> {
126
+ interface MultiThemeConfig<T extends ThemeTokenMap> {
120
127
  contract: ThemeContract<T>;
121
128
  light: T;
122
129
  dark: T;
@@ -145,7 +152,7 @@ interface MultiThemeConfig<T extends TokenMap> {
145
152
  * // Use tokens in components:
146
153
  * const Card = tw.div`bg-[${vars.colors.bg}] text-[${vars.colors.fg}]`
147
154
  */
148
- declare function createMultiTheme<T extends TokenMap>(config: MultiThemeConfig<T>): {
155
+ declare function createMultiTheme<T extends ThemeTokenMap>(config: MultiThemeConfig<T>): {
149
156
  registry: ThemeRegistry;
150
157
  vars: ThemeVars<T>;
151
158
  light: Theme<T>;
@@ -178,4 +185,4 @@ interface DesignTokens {
178
185
  */
179
186
  declare function compileDesignTokens(tokens: DesignTokens, prefix?: string): string;
180
187
 
181
- export { type DesignTokens, type MultiThemeConfig, type Theme, type ThemeContract, ThemeRegistry, type ThemeVars, type TokenMap, compileDesignTokens, createMultiTheme, createTheme, defineThemeContract };
188
+ export { type DesignTokens, type MultiThemeConfig, type Theme, type ThemeContract, ThemeRegistry, type ThemeTokenMap, type ThemeVars, compileDesignTokens, createMultiTheme, createTheme, defineThemeContract };
package/dist/theme.d.ts CHANGED
@@ -1,15 +1,21 @@
1
+ export { L as LiveTokenEngineBridge, a as LiveTokenSet, T as TokenMap, b as TokenSubscriber, c as applyTokenSet, d as createUseTokens, g as generateTokenCssString, e as getToken, f as getTokens, l as liveToken, h as liveTokenEngine, s as setToken, i as setTokens, j as subscribeTokens, t as tokenRef, k as tokenVar } from './liveTokenEngine-DYN3Zale.js';
2
+
1
3
  /**
2
- * tailwind-styled-v4 — Multi-Theme Engine
4
+ * tailwind-styled-v5 — Multi-Theme Engine + Live Token Engine
3
5
  *
4
6
  * Enterprise-grade theming. Support light/dark/brand themes dengan
5
7
  * CSS variables. Zero runtime overhead — themes di-resolve via CSS.
6
8
  *
9
+ * Live token engine provides runtime token state management with
10
+ * CSS variable sync to document root.
11
+ *
7
12
  * Fitur:
8
13
  * - Multiple named themes (light, dark, brand, high-contrast)
9
14
  * - CSS variable output (Tailwind v4 compatible)
10
15
  * - Theme contract (TypeScript-safe — missing tokens = TS error)
11
16
  * - Per-component theme override
12
17
  * - White-label ready
18
+ * - Live token engine (runtime token state + CSS sync)
13
19
  *
14
20
  * @example
15
21
  * // 1. Define contract
@@ -35,17 +41,18 @@
35
41
  * // 4. Apply in layout
36
42
  * // <html data-theme="dark"> or inject CSS
37
43
  */
38
- type TokenMap = Record<string, Record<string, string>>;
39
- interface ThemeContract<T extends TokenMap> {
44
+
45
+ type ThemeTokenMap = Record<string, Record<string, string>>;
46
+ interface ThemeContract<T extends ThemeTokenMap> {
40
47
  _contract: T;
41
48
  _vars: ThemeVars<T>;
42
49
  }
43
- type ThemeVars<T extends TokenMap> = {
50
+ type ThemeVars<T extends ThemeTokenMap> = {
44
51
  [Group in keyof T]: {
45
52
  [Token in keyof T[Group]]: string;
46
53
  };
47
54
  };
48
- interface Theme<T extends TokenMap> {
55
+ interface Theme<T extends ThemeTokenMap> {
49
56
  name: string;
50
57
  contract: ThemeContract<T>;
51
58
  values: T;
@@ -70,7 +77,7 @@ interface Theme<T extends TokenMap> {
70
77
  * const Card = tw.div`bg-[${contract._vars.colors.bg}]`
71
78
  * // → tw.div`bg-[var(--colors-bg)]`
72
79
  */
73
- declare function defineThemeContract<T extends TokenMap>(shape: T): ThemeContract<T>;
80
+ declare function defineThemeContract<T extends ThemeTokenMap>(shape: T): ThemeContract<T>;
74
81
  /**
75
82
  * Create a typed theme that satisfies a contract.
76
83
  *
@@ -79,12 +86,12 @@ declare function defineThemeContract<T extends TokenMap>(shape: T): ThemeContrac
79
86
  * @param values - Token values (TypeScript enforces completeness)
80
87
  * @param asRoot - If true, use :root selector. Default: false (uses [data-theme])
81
88
  */
82
- declare function createTheme<T extends TokenMap>(contract: ThemeContract<T>, name: string, values: T, asRoot?: boolean): Theme<T>;
89
+ declare function createTheme<T extends ThemeTokenMap>(contract: ThemeContract<T>, name: string, values: T, asRoot?: boolean): Theme<T>;
83
90
  declare class ThemeRegistry {
84
91
  private themes;
85
92
  private defaultTheme;
86
93
  /** Register a theme */
87
- register<T extends TokenMap>(theme: Theme<T>, isDefault?: boolean): this;
94
+ register<T extends ThemeTokenMap>(theme: Theme<T>, isDefault?: boolean): this;
88
95
  /** Get a theme by name */
89
96
  get(name: string): Theme<any> | undefined;
90
97
  /** Get all theme names */
@@ -116,7 +123,7 @@ declare class ThemeRegistry {
116
123
  */
117
124
  current(target?: HTMLElement): string | null;
118
125
  }
119
- interface MultiThemeConfig<T extends TokenMap> {
126
+ interface MultiThemeConfig<T extends ThemeTokenMap> {
120
127
  contract: ThemeContract<T>;
121
128
  light: T;
122
129
  dark: T;
@@ -145,7 +152,7 @@ interface MultiThemeConfig<T extends TokenMap> {
145
152
  * // Use tokens in components:
146
153
  * const Card = tw.div`bg-[${vars.colors.bg}] text-[${vars.colors.fg}]`
147
154
  */
148
- declare function createMultiTheme<T extends TokenMap>(config: MultiThemeConfig<T>): {
155
+ declare function createMultiTheme<T extends ThemeTokenMap>(config: MultiThemeConfig<T>): {
149
156
  registry: ThemeRegistry;
150
157
  vars: ThemeVars<T>;
151
158
  light: Theme<T>;
@@ -178,4 +185,4 @@ interface DesignTokens {
178
185
  */
179
186
  declare function compileDesignTokens(tokens: DesignTokens, prefix?: string): string;
180
187
 
181
- export { type DesignTokens, type MultiThemeConfig, type Theme, type ThemeContract, ThemeRegistry, type ThemeVars, type TokenMap, compileDesignTokens, createMultiTheme, createTheme, defineThemeContract };
188
+ export { type DesignTokens, type MultiThemeConfig, type Theme, type ThemeContract, ThemeRegistry, type ThemeTokenMap, type ThemeVars, compileDesignTokens, createMultiTheme, createTheme, defineThemeContract };
package/dist/theme.js CHANGED
@@ -1,6 +1,170 @@
1
- /* tailwind-styled-v4 v4 | MIT | https://github.com/dictionar32/tailwind-styled-v4 */
1
+ 'use strict';
2
2
 
3
- // ../theme/src/index.ts
3
+ var React = require('react');
4
+ var module$1 = require('module');
5
+ var path = require('path');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var React__default = /*#__PURE__*/_interopDefault(React);
10
+ var path__default = /*#__PURE__*/_interopDefault(path);
11
+
12
+ /* tailwind-styled-v4 v5.0.1 | MIT | https://github.com/dictionar32/tailwind-styled-v4 */
13
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
14
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
15
+ }) : x)(function(x) {
16
+ if (typeof require !== "undefined") return require.apply(this, arguments);
17
+ throw Error('Dynamic require of "' + x + '" is not supported');
18
+ });
19
+ var _currentTokens = {};
20
+ var _subscribers = /* @__PURE__ */ new Set();
21
+ var _styleEl = null;
22
+ function tokenVar(name) {
23
+ const normalized = name.replace(/[^a-zA-Z0-9-]/g, "-").toLowerCase();
24
+ return `--tw-token-${normalized}`;
25
+ }
26
+ function tokenRef(name) {
27
+ return `var(${tokenVar(name)})`;
28
+ }
29
+ function buildRootCss(tokens) {
30
+ const vars = Object.entries(tokens).map(([name, value]) => ` ${tokenVar(name)}: ${value};`).join("\n");
31
+ return `:root {
32
+ ${vars}
33
+ }`;
34
+ }
35
+ function syncStyleEl() {
36
+ if (typeof document === "undefined") return;
37
+ if (!_styleEl) {
38
+ _styleEl = document.createElement("style");
39
+ _styleEl.id = "tw-live-tokens";
40
+ _styleEl.setAttribute("data-tw-tokens", "true");
41
+ document.head.appendChild(_styleEl);
42
+ }
43
+ _styleEl.textContent = buildRootCss(_currentTokens);
44
+ }
45
+ function notifySubscribers() {
46
+ const snapshot = { ..._currentTokens };
47
+ for (const subscriber of _subscribers) {
48
+ try {
49
+ subscriber(snapshot);
50
+ } catch {
51
+ }
52
+ }
53
+ }
54
+ function liveToken(tokens) {
55
+ _currentTokens = { ..._currentTokens, ...tokens };
56
+ syncStyleEl();
57
+ notifySubscribers();
58
+ const vars = {};
59
+ for (const name of Object.keys(tokens)) {
60
+ vars[name] = tokenRef(name);
61
+ }
62
+ return {
63
+ vars,
64
+ get(name) {
65
+ return _currentTokens[name];
66
+ },
67
+ set(name, value) {
68
+ setToken(name, value);
69
+ },
70
+ setAll(nextTokens) {
71
+ setTokens(nextTokens);
72
+ },
73
+ snapshot() {
74
+ return { ..._currentTokens };
75
+ }
76
+ };
77
+ }
78
+ function setToken(name, value) {
79
+ _currentTokens = { ..._currentTokens, [name]: value };
80
+ if (typeof document !== "undefined") {
81
+ document.documentElement.style.setProperty(tokenVar(name), value);
82
+ }
83
+ notifySubscribers();
84
+ }
85
+ function setTokens(tokens) {
86
+ _currentTokens = { ..._currentTokens, ...tokens };
87
+ if (typeof document !== "undefined") {
88
+ const root = document.documentElement;
89
+ for (const [name, value] of Object.entries(tokens)) {
90
+ root.style.setProperty(tokenVar(name), value);
91
+ }
92
+ }
93
+ notifySubscribers();
94
+ }
95
+ function applyTokenSet(tokens) {
96
+ if (typeof document !== "undefined") {
97
+ const root = document.documentElement;
98
+ for (const name of Object.keys(_currentTokens)) {
99
+ if (!(name in tokens)) {
100
+ root.style.removeProperty(tokenVar(name));
101
+ }
102
+ }
103
+ }
104
+ _currentTokens = { ...tokens };
105
+ syncStyleEl();
106
+ notifySubscribers();
107
+ }
108
+ function getToken(name) {
109
+ return _currentTokens[name];
110
+ }
111
+ function getTokens() {
112
+ return { ..._currentTokens };
113
+ }
114
+ function subscribeTokens(fn) {
115
+ _subscribers.add(fn);
116
+ return () => {
117
+ _subscribers.delete(fn);
118
+ };
119
+ }
120
+ function generateTokenCssString() {
121
+ return buildRootCss(_currentTokens);
122
+ }
123
+ function createUseTokens() {
124
+ return function useTokens() {
125
+ const [tokens, setTokensState] = React__default.default.useState({ ..._currentTokens });
126
+ React__default.default.useEffect(() => {
127
+ setTokensState({ ..._currentTokens });
128
+ return subscribeTokens((nextTokens) => setTokensState({ ...nextTokens }));
129
+ }, []);
130
+ return tokens;
131
+ };
132
+ }
133
+ var liveTokenEngine = {
134
+ getToken,
135
+ getTokens,
136
+ setToken,
137
+ applyTokenSet,
138
+ subscribeTokens,
139
+ subscribe: subscribeTokens
140
+ };
141
+ globalThis.__TW_TOKEN_ENGINE__ = liveTokenEngine;
142
+ if (typeof window !== "undefined") {
143
+ window.__TW_TOKEN_ENGINE__ = liveTokenEngine;
144
+ }
145
+ var _binding;
146
+ function getNativeThemeBinding() {
147
+ if (_binding !== void 0) return _binding;
148
+ if (process.env.TWS_NO_NATIVE === "1" || process.env.TWS_NO_RUST === "1") {
149
+ return _binding = null;
150
+ }
151
+ const runtimeDir = typeof __dirname === "string" ? __dirname : process.cwd();
152
+ const req = typeof __require === "function" ? __require : module$1.createRequire(path__default.default.join(runtimeDir, "noop.cjs"));
153
+ const candidates = [
154
+ path__default.default.resolve(process.cwd(), "native", "tailwind_styled_parser.node"),
155
+ path__default.default.resolve(runtimeDir, "..", "..", "..", "native", "tailwind_styled_parser.node")
156
+ ];
157
+ for (const c of candidates) {
158
+ try {
159
+ const mod = req(c);
160
+ if (mod?.compileTheme) return _binding = mod;
161
+ } catch {
162
+ }
163
+ }
164
+ return _binding = null;
165
+ }
166
+
167
+ // packages/theme/src/index.ts
4
168
  function defineThemeContract(shape) {
5
169
  const vars = {};
6
170
  for (const group in shape) {
@@ -12,6 +176,17 @@ function defineThemeContract(shape) {
12
176
  return { _contract: shape, _vars: vars };
13
177
  }
14
178
  function createTheme(contract, name, values, asRoot = false) {
179
+ const native = getNativeThemeBinding();
180
+ if (native?.compileTheme) {
181
+ const result = native.compileTheme(JSON.stringify(values), asRoot ? "light" : name, "");
182
+ if (result) {
183
+ const flatVars2 = {};
184
+ for (const token of result.tokens) {
185
+ flatVars2[token.cssVar] = token.value;
186
+ }
187
+ return { name, contract, values, css: result.css, vars: flatVars2, selector: result.selector };
188
+ }
189
+ }
15
190
  const flatVars = {};
16
191
  const cssLines = [];
17
192
  for (const group in values) {
@@ -26,14 +201,7 @@ function createTheme(contract, name, values, asRoot = false) {
26
201
  const css = `${selector} {
27
202
  ${cssLines.join("\n")}
28
203
  }`;
29
- return {
30
- name,
31
- contract,
32
- values,
33
- css,
34
- vars: flatVars,
35
- selector
36
- };
204
+ return { name, contract, values, css, vars: flatVars, selector };
37
205
  }
38
206
  var ThemeRegistry = class {
39
207
  constructor() {
@@ -71,8 +239,7 @@ var ThemeRegistry = class {
71
239
  * Get the CSS for a specific theme only.
72
240
  */
73
241
  getThemeCss(name) {
74
- var _a, _b;
75
- return (_b = (_a = this.themes.get(name)) == null ? void 0 : _a.css) != null ? _b : null;
242
+ return this.themes.get(name)?.css ?? null;
76
243
  }
77
244
  /**
78
245
  * Inject all theme CSS into document <head> (browser only).
@@ -103,19 +270,17 @@ var ThemeRegistry = class {
103
270
  * Get current active theme name from data-theme attribute.
104
271
  */
105
272
  current(target = document.documentElement) {
106
- var _a;
107
273
  if (typeof document === "undefined") return this.defaultTheme;
108
- return (_a = target.dataset.theme) != null ? _a : this.defaultTheme;
274
+ return target.dataset.theme ?? this.defaultTheme;
109
275
  }
110
276
  };
111
277
  function createMultiTheme(config) {
112
- var _a;
113
278
  const registry = new ThemeRegistry();
114
279
  const light = createTheme(config.contract, "light", config.light, true);
115
280
  const dark = createTheme(config.contract, "dark", config.dark, false);
116
281
  registry.register(light, true);
117
282
  registry.register(dark);
118
- for (const [name, values] of Object.entries((_a = config.extras) != null ? _a : {})) {
283
+ for (const [name, values] of Object.entries(config.extras ?? {})) {
119
284
  registry.register(createTheme(config.contract, name, values));
120
285
  }
121
286
  return {
@@ -126,10 +291,15 @@ function createMultiTheme(config) {
126
291
  };
127
292
  }
128
293
  function compileDesignTokens(tokens, prefix = "") {
294
+ const native = getNativeThemeBinding();
295
+ if (native?.compileTheme) {
296
+ const result = native.compileTheme(JSON.stringify(tokens), "default", prefix);
297
+ if (result) return result.css;
298
+ }
129
299
  const vars = [];
130
- function flatten(obj, path) {
300
+ function flatten(obj, path2) {
131
301
  for (const [key, value] of Object.entries(obj)) {
132
- const varPath = path ? `${path}-${key}` : key;
302
+ const varPath = path2 ? `${path2}-${key}` : key;
133
303
  if (typeof value === "string") {
134
304
  vars.push(` --${varPath}: ${value};`);
135
305
  } else {
@@ -143,6 +313,22 @@ ${vars.join("\n")}
143
313
  }`;
144
314
  }
145
315
 
146
- export { ThemeRegistry, compileDesignTokens, createMultiTheme, createTheme, defineThemeContract };
316
+ exports.ThemeRegistry = ThemeRegistry;
317
+ exports.applyTokenSet = applyTokenSet;
318
+ exports.compileDesignTokens = compileDesignTokens;
319
+ exports.createMultiTheme = createMultiTheme;
320
+ exports.createTheme = createTheme;
321
+ exports.createUseTokens = createUseTokens;
322
+ exports.defineThemeContract = defineThemeContract;
323
+ exports.generateTokenCssString = generateTokenCssString;
324
+ exports.getToken = getToken;
325
+ exports.getTokens = getTokens;
326
+ exports.liveToken = liveToken;
327
+ exports.liveTokenEngine = liveTokenEngine;
328
+ exports.setToken = setToken;
329
+ exports.setTokens = setTokens;
330
+ exports.subscribeTokens = subscribeTokens;
331
+ exports.tokenRef = tokenRef;
332
+ exports.tokenVar = tokenVar;
147
333
  //# sourceMappingURL=theme.js.map
148
334
  //# sourceMappingURL=theme.js.map