@tenphi/tasty 0.0.0-snapshot.2f99c73

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 (242) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +261 -0
  3. package/dist/_virtual/_rolldown/runtime.js +8 -0
  4. package/dist/chunks/cacheKey.d.ts +1 -0
  5. package/dist/chunks/cacheKey.js +70 -0
  6. package/dist/chunks/cacheKey.js.map +1 -0
  7. package/dist/chunks/definitions.d.ts +37 -0
  8. package/dist/chunks/definitions.js +260 -0
  9. package/dist/chunks/definitions.js.map +1 -0
  10. package/dist/chunks/index.d.ts +3 -0
  11. package/dist/chunks/renderChunk.d.ts +2 -0
  12. package/dist/chunks/renderChunk.js +61 -0
  13. package/dist/chunks/renderChunk.js.map +1 -0
  14. package/dist/config.d.ts +279 -0
  15. package/dist/config.js +400 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/debug.d.ts +204 -0
  18. package/dist/debug.js +733 -0
  19. package/dist/debug.js.map +1 -0
  20. package/dist/hooks/index.d.ts +5 -0
  21. package/dist/hooks/useGlobalStyles.d.ts +27 -0
  22. package/dist/hooks/useGlobalStyles.js +56 -0
  23. package/dist/hooks/useGlobalStyles.js.map +1 -0
  24. package/dist/hooks/useKeyframes.d.ts +56 -0
  25. package/dist/hooks/useKeyframes.js +54 -0
  26. package/dist/hooks/useKeyframes.js.map +1 -0
  27. package/dist/hooks/useProperty.d.ts +79 -0
  28. package/dist/hooks/useProperty.js +91 -0
  29. package/dist/hooks/useProperty.js.map +1 -0
  30. package/dist/hooks/useRawCSS.d.ts +53 -0
  31. package/dist/hooks/useRawCSS.js +28 -0
  32. package/dist/hooks/useRawCSS.js.map +1 -0
  33. package/dist/hooks/useStyles.d.ts +40 -0
  34. package/dist/hooks/useStyles.js +169 -0
  35. package/dist/hooks/useStyles.js.map +1 -0
  36. package/dist/index.d.ts +38 -0
  37. package/dist/index.js +30 -0
  38. package/dist/injector/index.d.ts +157 -0
  39. package/dist/injector/index.js +154 -0
  40. package/dist/injector/index.js.map +1 -0
  41. package/dist/injector/injector.d.ts +139 -0
  42. package/dist/injector/injector.js +404 -0
  43. package/dist/injector/injector.js.map +1 -0
  44. package/dist/injector/sheet-manager.d.ts +127 -0
  45. package/dist/injector/sheet-manager.js +714 -0
  46. package/dist/injector/sheet-manager.js.map +1 -0
  47. package/dist/injector/types.d.ts +135 -0
  48. package/dist/keyframes/index.js +206 -0
  49. package/dist/keyframes/index.js.map +1 -0
  50. package/dist/parser/classify.js +319 -0
  51. package/dist/parser/classify.js.map +1 -0
  52. package/dist/parser/const.js +33 -0
  53. package/dist/parser/const.js.map +1 -0
  54. package/dist/parser/index.d.ts +3 -0
  55. package/dist/parser/index.js +4 -0
  56. package/dist/parser/lru.js +109 -0
  57. package/dist/parser/lru.js.map +1 -0
  58. package/dist/parser/parser.d.ts +25 -0
  59. package/dist/parser/parser.js +116 -0
  60. package/dist/parser/parser.js.map +1 -0
  61. package/dist/parser/tokenizer.js +69 -0
  62. package/dist/parser/tokenizer.js.map +1 -0
  63. package/dist/parser/types.d.ts +51 -0
  64. package/dist/parser/types.js +46 -0
  65. package/dist/parser/types.js.map +1 -0
  66. package/dist/pipeline/conditions.js +398 -0
  67. package/dist/pipeline/conditions.js.map +1 -0
  68. package/dist/pipeline/exclusive.d.ts +1 -0
  69. package/dist/pipeline/exclusive.js +231 -0
  70. package/dist/pipeline/exclusive.js.map +1 -0
  71. package/dist/pipeline/index.d.ts +53 -0
  72. package/dist/pipeline/index.js +642 -0
  73. package/dist/pipeline/index.js.map +1 -0
  74. package/dist/pipeline/materialize.js +894 -0
  75. package/dist/pipeline/materialize.js.map +1 -0
  76. package/dist/pipeline/parseStateKey.d.ts +1 -0
  77. package/dist/pipeline/parseStateKey.js +439 -0
  78. package/dist/pipeline/parseStateKey.js.map +1 -0
  79. package/dist/pipeline/simplify.js +557 -0
  80. package/dist/pipeline/simplify.js.map +1 -0
  81. package/dist/plugins/index.d.ts +2 -0
  82. package/dist/plugins/okhsl-plugin.d.ts +35 -0
  83. package/dist/plugins/okhsl-plugin.js +371 -0
  84. package/dist/plugins/okhsl-plugin.js.map +1 -0
  85. package/dist/plugins/types.d.ts +69 -0
  86. package/dist/properties/index.js +158 -0
  87. package/dist/properties/index.js.map +1 -0
  88. package/dist/states/index.d.ts +45 -0
  89. package/dist/states/index.js +416 -0
  90. package/dist/states/index.js.map +1 -0
  91. package/dist/static/index.d.ts +5 -0
  92. package/dist/static/index.js +5 -0
  93. package/dist/static/tastyStatic.d.ts +46 -0
  94. package/dist/static/tastyStatic.js +31 -0
  95. package/dist/static/tastyStatic.js.map +1 -0
  96. package/dist/static/types.d.ts +49 -0
  97. package/dist/static/types.js +24 -0
  98. package/dist/static/types.js.map +1 -0
  99. package/dist/styles/align.d.ts +15 -0
  100. package/dist/styles/align.js +14 -0
  101. package/dist/styles/align.js.map +1 -0
  102. package/dist/styles/border.d.ts +25 -0
  103. package/dist/styles/border.js +114 -0
  104. package/dist/styles/border.js.map +1 -0
  105. package/dist/styles/color.d.ts +14 -0
  106. package/dist/styles/color.js +23 -0
  107. package/dist/styles/color.js.map +1 -0
  108. package/dist/styles/createStyle.js +77 -0
  109. package/dist/styles/createStyle.js.map +1 -0
  110. package/dist/styles/dimension.js +97 -0
  111. package/dist/styles/dimension.js.map +1 -0
  112. package/dist/styles/display.d.ts +37 -0
  113. package/dist/styles/display.js +67 -0
  114. package/dist/styles/display.js.map +1 -0
  115. package/dist/styles/fade.d.ts +15 -0
  116. package/dist/styles/fade.js +58 -0
  117. package/dist/styles/fade.js.map +1 -0
  118. package/dist/styles/fill.d.ts +44 -0
  119. package/dist/styles/fill.js +51 -0
  120. package/dist/styles/fill.js.map +1 -0
  121. package/dist/styles/flow.d.ts +16 -0
  122. package/dist/styles/flow.js +12 -0
  123. package/dist/styles/flow.js.map +1 -0
  124. package/dist/styles/gap.d.ts +31 -0
  125. package/dist/styles/gap.js +37 -0
  126. package/dist/styles/gap.js.map +1 -0
  127. package/dist/styles/height.d.ts +17 -0
  128. package/dist/styles/height.js +20 -0
  129. package/dist/styles/height.js.map +1 -0
  130. package/dist/styles/index.d.ts +2 -0
  131. package/dist/styles/index.js +9 -0
  132. package/dist/styles/index.js.map +1 -0
  133. package/dist/styles/inset.d.ts +50 -0
  134. package/dist/styles/inset.js +142 -0
  135. package/dist/styles/inset.js.map +1 -0
  136. package/dist/styles/justify.d.ts +15 -0
  137. package/dist/styles/justify.js +14 -0
  138. package/dist/styles/justify.js.map +1 -0
  139. package/dist/styles/list.d.ts +16 -0
  140. package/dist/styles/list.js +98 -0
  141. package/dist/styles/list.js.map +1 -0
  142. package/dist/styles/margin.d.ts +28 -0
  143. package/dist/styles/margin.js +96 -0
  144. package/dist/styles/margin.js.map +1 -0
  145. package/dist/styles/outline.d.ts +29 -0
  146. package/dist/styles/outline.js +65 -0
  147. package/dist/styles/outline.js.map +1 -0
  148. package/dist/styles/padding.d.ts +28 -0
  149. package/dist/styles/padding.js +96 -0
  150. package/dist/styles/padding.js.map +1 -0
  151. package/dist/styles/predefined.d.ts +74 -0
  152. package/dist/styles/predefined.js +241 -0
  153. package/dist/styles/predefined.js.map +1 -0
  154. package/dist/styles/preset.d.ts +47 -0
  155. package/dist/styles/preset.js +126 -0
  156. package/dist/styles/preset.js.map +1 -0
  157. package/dist/styles/radius.d.ts +14 -0
  158. package/dist/styles/radius.js +51 -0
  159. package/dist/styles/radius.js.map +1 -0
  160. package/dist/styles/scrollbar.d.ts +21 -0
  161. package/dist/styles/scrollbar.js +105 -0
  162. package/dist/styles/scrollbar.js.map +1 -0
  163. package/dist/styles/shadow.d.ts +14 -0
  164. package/dist/styles/shadow.js +24 -0
  165. package/dist/styles/shadow.js.map +1 -0
  166. package/dist/styles/styledScrollbar.d.ts +47 -0
  167. package/dist/styles/styledScrollbar.js +38 -0
  168. package/dist/styles/styledScrollbar.js.map +1 -0
  169. package/dist/styles/transition.d.ts +14 -0
  170. package/dist/styles/transition.js +138 -0
  171. package/dist/styles/transition.js.map +1 -0
  172. package/dist/styles/types.d.ts +496 -0
  173. package/dist/styles/width.d.ts +17 -0
  174. package/dist/styles/width.js +20 -0
  175. package/dist/styles/width.js.map +1 -0
  176. package/dist/tasty.d.ts +983 -0
  177. package/dist/tasty.js +191 -0
  178. package/dist/tasty.js.map +1 -0
  179. package/dist/tokens/typography.d.ts +19 -0
  180. package/dist/tokens/typography.js +237 -0
  181. package/dist/tokens/typography.js.map +1 -0
  182. package/dist/types.d.ts +182 -0
  183. package/dist/utils/cache-wrapper.js +26 -0
  184. package/dist/utils/cache-wrapper.js.map +1 -0
  185. package/dist/utils/case-converter.js +8 -0
  186. package/dist/utils/case-converter.js.map +1 -0
  187. package/dist/utils/colors.d.ts +5 -0
  188. package/dist/utils/colors.js +9 -0
  189. package/dist/utils/colors.js.map +1 -0
  190. package/dist/utils/dotize.d.ts +26 -0
  191. package/dist/utils/dotize.js +122 -0
  192. package/dist/utils/dotize.js.map +1 -0
  193. package/dist/utils/filter-base-props.d.ts +15 -0
  194. package/dist/utils/filter-base-props.js +45 -0
  195. package/dist/utils/filter-base-props.js.map +1 -0
  196. package/dist/utils/get-display-name.d.ts +7 -0
  197. package/dist/utils/get-display-name.js +10 -0
  198. package/dist/utils/get-display-name.js.map +1 -0
  199. package/dist/utils/hsl-to-rgb.js +38 -0
  200. package/dist/utils/hsl-to-rgb.js.map +1 -0
  201. package/dist/utils/is-dev-env.js +19 -0
  202. package/dist/utils/is-dev-env.js.map +1 -0
  203. package/dist/utils/merge-styles.d.ts +7 -0
  204. package/dist/utils/merge-styles.js +146 -0
  205. package/dist/utils/merge-styles.js.map +1 -0
  206. package/dist/utils/mod-attrs.d.ts +8 -0
  207. package/dist/utils/mod-attrs.js +21 -0
  208. package/dist/utils/mod-attrs.js.map +1 -0
  209. package/dist/utils/okhsl-to-rgb.js +296 -0
  210. package/dist/utils/okhsl-to-rgb.js.map +1 -0
  211. package/dist/utils/process-tokens.d.ts +31 -0
  212. package/dist/utils/process-tokens.js +171 -0
  213. package/dist/utils/process-tokens.js.map +1 -0
  214. package/dist/utils/resolve-recipes.d.ts +17 -0
  215. package/dist/utils/resolve-recipes.js +143 -0
  216. package/dist/utils/resolve-recipes.js.map +1 -0
  217. package/dist/utils/string.js +8 -0
  218. package/dist/utils/string.js.map +1 -0
  219. package/dist/utils/styles.d.ts +183 -0
  220. package/dist/utils/styles.js +585 -0
  221. package/dist/utils/styles.js.map +1 -0
  222. package/dist/utils/typography.d.ts +36 -0
  223. package/dist/utils/typography.js +53 -0
  224. package/dist/utils/typography.js.map +1 -0
  225. package/dist/utils/warnings.d.ts +16 -0
  226. package/dist/utils/warnings.js +16 -0
  227. package/dist/utils/warnings.js.map +1 -0
  228. package/dist/zero/babel.d.ts +108 -0
  229. package/dist/zero/babel.js +282 -0
  230. package/dist/zero/babel.js.map +1 -0
  231. package/dist/zero/css-writer.d.ts +45 -0
  232. package/dist/zero/css-writer.js +74 -0
  233. package/dist/zero/css-writer.js.map +1 -0
  234. package/dist/zero/extractor.d.ts +25 -0
  235. package/dist/zero/extractor.js +150 -0
  236. package/dist/zero/extractor.js.map +1 -0
  237. package/dist/zero/index.d.ts +3 -0
  238. package/dist/zero/index.js +4 -0
  239. package/dist/zero/next.d.ts +60 -0
  240. package/dist/zero/next.js +78 -0
  241. package/dist/zero/next.js.map +1 -0
  242. package/package.json +133 -0
@@ -0,0 +1,74 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+
4
+ //#region src/zero/css-writer.ts
5
+ var CSSWriter = class {
6
+ cssBlocks = /* @__PURE__ */ new Map();
7
+ outputPath;
8
+ devMode;
9
+ constructor(outputPath, options = {}) {
10
+ this.outputPath = outputPath;
11
+ this.devMode = options.devMode ?? false;
12
+ }
13
+ /**
14
+ * Add CSS block with deduplication key
15
+ * @param key - Unique key for deduplication
16
+ * @param css - CSS content
17
+ * @param source - Optional source file path (used in devMode)
18
+ */
19
+ add(key, css, source) {
20
+ this.cssBlocks.set(key, {
21
+ css,
22
+ source
23
+ });
24
+ }
25
+ /**
26
+ * Check if a key already exists
27
+ */
28
+ has(key) {
29
+ return this.cssBlocks.has(key);
30
+ }
31
+ /**
32
+ * Get the number of CSS blocks
33
+ */
34
+ get size() {
35
+ return this.cssBlocks.size;
36
+ }
37
+ /**
38
+ * Write all collected CSS to the output file
39
+ */
40
+ write() {
41
+ const outputDir = path.dirname(this.outputPath);
42
+ if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir, { recursive: true });
43
+ const cssBlocks = [];
44
+ for (const block of this.cssBlocks.values()) if (this.devMode && block.source) cssBlocks.push(`/* from: ${block.source} */\n${block.css}`);
45
+ else cssBlocks.push(block.css);
46
+ const css = cssBlocks.join("\n\n");
47
+ fs.writeFileSync(this.outputPath, `/* Generated by @tenphi/tasty/zero - DO NOT EDIT */\n\n` + css);
48
+ }
49
+ /**
50
+ * Get all CSS as string (for testing or in-memory use)
51
+ */
52
+ getCSS() {
53
+ const cssBlocks = [];
54
+ for (const block of this.cssBlocks.values()) if (this.devMode && block.source) cssBlocks.push(`/* from: ${block.source} */\n${block.css}`);
55
+ else cssBlocks.push(block.css);
56
+ return cssBlocks.join("\n\n");
57
+ }
58
+ /**
59
+ * Clear all collected CSS
60
+ */
61
+ clear() {
62
+ this.cssBlocks.clear();
63
+ }
64
+ /**
65
+ * Get the output path
66
+ */
67
+ getOutputPath() {
68
+ return this.outputPath;
69
+ }
70
+ };
71
+
72
+ //#endregion
73
+ export { CSSWriter };
74
+ //# sourceMappingURL=css-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css-writer.js","names":[],"sources":["../../src/zero/css-writer.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\n\nexport interface CSSWriterOptions {\n /** Enable source comments in output (e.g., \"from: Button.tsx\") */\n devMode?: boolean;\n}\n\ninterface CSSBlock {\n css: string;\n source?: string;\n}\n\nexport class CSSWriter {\n private cssBlocks = new Map<string, CSSBlock>();\n private outputPath: string;\n private devMode: boolean;\n\n constructor(outputPath: string, options: CSSWriterOptions = {}) {\n this.outputPath = outputPath;\n this.devMode = options.devMode ?? false;\n }\n\n /**\n * Add CSS block with deduplication key\n * @param key - Unique key for deduplication\n * @param css - CSS content\n * @param source - Optional source file path (used in devMode)\n */\n add(key: string, css: string, source?: string): void {\n this.cssBlocks.set(key, { css, source });\n }\n\n /**\n * Check if a key already exists\n */\n has(key: string): boolean {\n return this.cssBlocks.has(key);\n }\n\n /**\n * Get the number of CSS blocks\n */\n get size(): number {\n return this.cssBlocks.size;\n }\n\n /**\n * Write all collected CSS to the output file\n */\n write(): void {\n const outputDir = path.dirname(this.outputPath);\n\n // Ensure directory exists\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n // Combine all CSS blocks with optional source comments\n const cssBlocks: string[] = [];\n for (const block of this.cssBlocks.values()) {\n if (this.devMode && block.source) {\n cssBlocks.push(`/* from: ${block.source} */\\n${block.css}`);\n } else {\n cssBlocks.push(block.css);\n }\n }\n const css = cssBlocks.join('\\n\\n');\n\n // Add header comment\n const header = `/* Generated by @tenphi/tasty/zero - DO NOT EDIT */\\n\\n`;\n\n fs.writeFileSync(this.outputPath, header + css);\n }\n\n /**\n * Get all CSS as string (for testing or in-memory use)\n */\n getCSS(): string {\n const cssBlocks: string[] = [];\n for (const block of this.cssBlocks.values()) {\n if (this.devMode && block.source) {\n cssBlocks.push(`/* from: ${block.source} */\\n${block.css}`);\n } else {\n cssBlocks.push(block.css);\n }\n }\n return cssBlocks.join('\\n\\n');\n }\n\n /**\n * Clear all collected CSS\n */\n clear(): void {\n this.cssBlocks.clear();\n }\n\n /**\n * Get the output path\n */\n getOutputPath(): string {\n return this.outputPath;\n }\n}\n"],"mappings":";;;;AAaA,IAAa,YAAb,MAAuB;CACrB,AAAQ,4BAAY,IAAI,KAAuB;CAC/C,AAAQ;CACR,AAAQ;CAER,YAAY,YAAoB,UAA4B,EAAE,EAAE;AAC9D,OAAK,aAAa;AAClB,OAAK,UAAU,QAAQ,WAAW;;;;;;;;CASpC,IAAI,KAAa,KAAa,QAAuB;AACnD,OAAK,UAAU,IAAI,KAAK;GAAE;GAAK;GAAQ,CAAC;;;;;CAM1C,IAAI,KAAsB;AACxB,SAAO,KAAK,UAAU,IAAI,IAAI;;;;;CAMhC,IAAI,OAAe;AACjB,SAAO,KAAK,UAAU;;;;;CAMxB,QAAc;EACZ,MAAM,YAAY,KAAK,QAAQ,KAAK,WAAW;AAG/C,MAAI,CAAC,GAAG,WAAW,UAAU,CAC3B,IAAG,UAAU,WAAW,EAAE,WAAW,MAAM,CAAC;EAI9C,MAAM,YAAsB,EAAE;AAC9B,OAAK,MAAM,SAAS,KAAK,UAAU,QAAQ,CACzC,KAAI,KAAK,WAAW,MAAM,OACxB,WAAU,KAAK,YAAY,MAAM,OAAO,OAAO,MAAM,MAAM;MAE3D,WAAU,KAAK,MAAM,IAAI;EAG7B,MAAM,MAAM,UAAU,KAAK,OAAO;AAKlC,KAAG,cAAc,KAAK,YAFP,4DAE4B,IAAI;;;;;CAMjD,SAAiB;EACf,MAAM,YAAsB,EAAE;AAC9B,OAAK,MAAM,SAAS,KAAK,UAAU,QAAQ,CACzC,KAAI,KAAK,WAAW,MAAM,OACxB,WAAU,KAAK,YAAY,MAAM,OAAO,OAAO,MAAM,MAAM;MAE3D,WAAU,KAAK,MAAM,IAAI;AAG7B,SAAO,UAAU,KAAK,OAAO;;;;;CAM/B,QAAc;AACZ,OAAK,UAAU,OAAO;;;;;CAMxB,gBAAwB;AACtB,SAAO,KAAK"}
@@ -0,0 +1,25 @@
1
+ import "../injector/types.js";
2
+ import { Styles } from "../styles/types.js";
3
+
4
+ //#region src/zero/extractor.d.ts
5
+ interface ExtractedChunk {
6
+ className: string;
7
+ css: string;
8
+ }
9
+ interface ExtractedSelector {
10
+ selector: string;
11
+ css: string;
12
+ }
13
+ /**
14
+ * Extract styles using chunking (for className mode).
15
+ * Returns multiple classes, one per chunk.
16
+ */
17
+ declare function extractStylesWithChunks(styles: Styles): ExtractedChunk[];
18
+ /**
19
+ * Extract styles for a specific selector (for global/selector mode).
20
+ * Returns a single CSS block.
21
+ */
22
+ declare function extractStylesForSelector(selector: string, styles: Styles): ExtractedSelector;
23
+ //#endregion
24
+ export { ExtractedChunk, ExtractedSelector, extractStylesForSelector, extractStylesWithChunks };
25
+ //# sourceMappingURL=extractor.d.ts.map
@@ -0,0 +1,150 @@
1
+ import { renderStyles } from "../pipeline/index.js";
2
+ import { categorizeStyleKeys } from "../chunks/definitions.js";
3
+ import { generateChunkCacheKey } from "../chunks/cacheKey.js";
4
+ import { renderStylesForChunk } from "../chunks/renderChunk.js";
5
+ import { extractAnimationNamesFromStyles, extractLocalKeyframes, filterUsedKeyframes, hasLocalKeyframes, mergeKeyframes } from "../keyframes/index.js";
6
+ import { createHash } from "crypto";
7
+
8
+ //#region src/zero/extractor.ts
9
+ /**
10
+ * Generate a deterministic className from a cache key using content hash.
11
+ * This ensures the same styles always produce the same className,
12
+ * regardless of build order or incremental compilation.
13
+ */
14
+ function generateClassName(cacheKey) {
15
+ return `ts${createHash("md5").update(cacheKey).digest("hex").slice(0, 6)}`;
16
+ }
17
+ /**
18
+ * Extract styles using chunking (for className mode).
19
+ * Returns multiple classes, one per chunk.
20
+ */
21
+ function extractStylesWithChunks(styles) {
22
+ const chunks = [];
23
+ const chunkMap = categorizeStyleKeys(styles);
24
+ for (const [chunkName, chunkStyleKeys] of chunkMap) {
25
+ if (chunkStyleKeys.length === 0) continue;
26
+ const cacheKey = generateChunkCacheKey(styles, chunkName, chunkStyleKeys);
27
+ const renderResult = renderStylesForChunk(styles, chunkName, chunkStyleKeys);
28
+ if (renderResult.rules.length === 0) continue;
29
+ const className = generateClassName(cacheKey);
30
+ const selector = `.${className}.${className}`;
31
+ const css = formatRulesToCSS(renderResult.rules, selector);
32
+ chunks.push({
33
+ className,
34
+ css
35
+ });
36
+ }
37
+ return chunks;
38
+ }
39
+ /**
40
+ * Extract styles for a specific selector (for global/selector mode).
41
+ * Returns a single CSS block.
42
+ */
43
+ function extractStylesForSelector(selector, styles) {
44
+ return {
45
+ selector,
46
+ css: formatRulesDirectly(renderStyles(styles, selector))
47
+ };
48
+ }
49
+ /**
50
+ * Format StyleResult[] to CSS string.
51
+ * Prefixes each rule's selector with the base selector.
52
+ * Used for chunked styles where rules have relative selectors.
53
+ */
54
+ function formatRulesToCSS(rules, baseSelector) {
55
+ return rules.map((rule) => {
56
+ let css = `${(Array.isArray(rule.selector) ? rule.selector : rule.selector ? rule.selector.split("|||") : [""]).map((part) => {
57
+ let selector;
58
+ if (!part) selector = baseSelector;
59
+ else if (part.startsWith(":") || part.startsWith("[")) selector = `${baseSelector}${part}`;
60
+ else if (part.startsWith(">") || part.startsWith("+") || part.startsWith("~")) selector = `${baseSelector}${part}`;
61
+ else selector = `${baseSelector}${part}`;
62
+ if (rule.rootPrefix) selector = `${rule.rootPrefix} ${selector}`;
63
+ return selector;
64
+ }).join(", ")} { ${rule.declarations} }`;
65
+ if (rule.atRules && rule.atRules.length > 0) for (const atRule of [...rule.atRules].reverse()) css = `${atRule} {\n ${css}\n}`;
66
+ return css;
67
+ }).join("\n\n");
68
+ }
69
+ /**
70
+ * Format StyleResult[] to CSS string directly without prefixing.
71
+ * Used for global styles where rules already have the full selector.
72
+ */
73
+ function formatRulesDirectly(rules) {
74
+ return rules.map((rule) => {
75
+ let css = `${rule.rootPrefix ? `${rule.rootPrefix} ${rule.selector}` : rule.selector} { ${rule.declarations} }`;
76
+ if (rule.atRules && rule.atRules.length > 0) for (const atRule of [...rule.atRules].reverse()) css = `${atRule} {\n ${css}\n}`;
77
+ return css;
78
+ }).join("\n\n");
79
+ }
80
+ /**
81
+ * Generate a deterministic keyframes name from content hash.
82
+ * This ensures the same keyframes content always produces the same name,
83
+ * enabling automatic deduplication across elements and files.
84
+ */
85
+ function generateKeyframesName(steps) {
86
+ const content = JSON.stringify(steps);
87
+ return `kf${createHash("md5").update(content).digest("hex").slice(0, 6)}`;
88
+ }
89
+ /**
90
+ * Extract keyframes that are used in styles.
91
+ * Merges local @keyframes with global keyframes, filters to only used ones.
92
+ * Generates hash-based names from content for automatic deduplication.
93
+ *
94
+ * @param styles - The styles object (may contain @keyframes and animation properties)
95
+ * @param globalKeyframes - Optional global keyframes from config
96
+ * @returns Keyframes to inject and name mapping for replacement
97
+ */
98
+ function extractKeyframesFromStyles(styles, globalKeyframes) {
99
+ const emptyResult = {
100
+ keyframes: [],
101
+ nameMap: /* @__PURE__ */ new Map()
102
+ };
103
+ const usedNames = extractAnimationNamesFromStyles(styles);
104
+ if (usedNames.size === 0) return emptyResult;
105
+ const usedKeyframes = filterUsedKeyframes(mergeKeyframes(hasLocalKeyframes(styles) ? extractLocalKeyframes(styles) : null, globalKeyframes ?? null), usedNames);
106
+ if (!usedKeyframes) return emptyResult;
107
+ const seenHashes = /* @__PURE__ */ new Set();
108
+ const nameMap = /* @__PURE__ */ new Map();
109
+ const keyframesToEmit = [];
110
+ for (const [originalName, steps] of Object.entries(usedKeyframes)) {
111
+ const hashedName = generateKeyframesName(steps);
112
+ nameMap.set(originalName, hashedName);
113
+ if (!seenHashes.has(hashedName)) {
114
+ seenHashes.add(hashedName);
115
+ const css = keyframesToCSS(hashedName, steps);
116
+ keyframesToEmit.push({
117
+ name: hashedName,
118
+ css
119
+ });
120
+ }
121
+ }
122
+ return {
123
+ keyframes: keyframesToEmit,
124
+ nameMap
125
+ };
126
+ }
127
+ /**
128
+ * Convert keyframes steps to CSS string.
129
+ */
130
+ function keyframesToCSS(name, steps) {
131
+ const stepRules = [];
132
+ for (const [key, value] of Object.entries(steps)) if (typeof value === "string") stepRules.push(`${key} { ${value.trim()} }`);
133
+ else if (value && typeof value === "object") {
134
+ const declarations = Object.entries(value).map(([prop, val]) => {
135
+ return `${camelToKebab(prop)}: ${val}`;
136
+ }).join("; ");
137
+ stepRules.push(`${key} { ${declarations} }`);
138
+ }
139
+ return `@keyframes ${name} { ${stepRules.join(" ")} }`;
140
+ }
141
+ /**
142
+ * Convert camelCase to kebab-case.
143
+ */
144
+ function camelToKebab(str) {
145
+ return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
146
+ }
147
+
148
+ //#endregion
149
+ export { extractKeyframesFromStyles, extractStylesForSelector, extractStylesWithChunks };
150
+ //# sourceMappingURL=extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.js","names":[],"sources":["../../src/zero/extractor.ts"],"sourcesContent":["import { createHash } from 'crypto';\n\nimport {\n categorizeStyleKeys,\n generateChunkCacheKey,\n renderStylesForChunk,\n} from '../chunks';\nimport type { KeyframesSteps } from '../injector/types';\nimport {\n extractAnimationNamesFromStyles,\n extractLocalKeyframes,\n filterUsedKeyframes,\n hasLocalKeyframes,\n mergeKeyframes,\n} from '../keyframes';\nimport type { StyleResult } from '../pipeline';\nimport { renderStyles } from '../pipeline';\nimport type { Styles } from '../styles/types';\n\nexport interface ExtractedChunk {\n className: string;\n css: string;\n}\n\nexport interface ExtractedSelector {\n selector: string;\n css: string;\n}\n\nexport interface ExtractedKeyframes {\n name: string;\n css: string;\n}\n\nexport interface KeyframesExtractionResult {\n /** Keyframes to inject (deduplicated by content) */\n keyframes: ExtractedKeyframes[];\n /** Map from original animation name to canonical name (for replacement) */\n nameMap: Map<string, string>;\n}\n\n/**\n * Generate a deterministic className from a cache key using content hash.\n * This ensures the same styles always produce the same className,\n * regardless of build order or incremental compilation.\n */\nfunction generateClassName(cacheKey: string): string {\n const hash = createHash('md5').update(cacheKey).digest('hex').slice(0, 6);\n return `ts${hash}`; // 'ts' prefix for \"tasty-static\" to distinguish from runtime 't' classes\n}\n\n/**\n * Extract styles using chunking (for className mode).\n * Returns multiple classes, one per chunk.\n */\nexport function extractStylesWithChunks(styles: Styles): ExtractedChunk[] {\n const chunks: ExtractedChunk[] = [];\n\n // Categorize style keys into chunks\n const chunkMap = categorizeStyleKeys(styles as Record<string, unknown>);\n\n for (const [chunkName, chunkStyleKeys] of chunkMap) {\n if (chunkStyleKeys.length === 0) continue;\n\n // Generate cache key for this chunk (used for className hash)\n const cacheKey = generateChunkCacheKey(styles, chunkName, chunkStyleKeys);\n\n // Render styles for this chunk\n const renderResult = renderStylesForChunk(\n styles,\n chunkName,\n chunkStyleKeys,\n );\n\n if (renderResult.rules.length === 0) continue;\n\n // Generate deterministic className from content hash\n const className = generateClassName(cacheKey);\n const selector = `.${className}.${className}`;\n\n // Format CSS\n const css = formatRulesToCSS(renderResult.rules, selector);\n\n chunks.push({ className, css });\n }\n\n return chunks;\n}\n\n/**\n * Extract styles for a specific selector (for global/selector mode).\n * Returns a single CSS block.\n */\nexport function extractStylesForSelector(\n selector: string,\n styles: Styles,\n): ExtractedSelector {\n // renderStyles with selector returns StyleResult[] with selectors already applied\n const rules = renderStyles(styles, selector);\n // Format without re-prefixing - rules already have the full selector\n const css = formatRulesDirectly(rules);\n\n return { selector, css };\n}\n\n/**\n * Format StyleResult[] to CSS string.\n * Prefixes each rule's selector with the base selector.\n * Used for chunked styles where rules have relative selectors.\n */\nfunction formatRulesToCSS(rules: StyleResult[], baseSelector: string): string {\n return rules\n .map((rule) => {\n // Handle selector as array (OR conditions) or string\n // Note: renderStyles without className joins array selectors with '|||' placeholder\n const selectorParts = Array.isArray(rule.selector)\n ? rule.selector\n : rule.selector\n ? rule.selector.split('|||')\n : [''];\n\n // Prefix each selector part with the base selector\n const fullSelector = selectorParts\n .map((part) => {\n // Build selector: [rootPrefix] baseSelector[part]\n let selector: string;\n\n // If part is empty, just use base selector\n if (!part) {\n selector = baseSelector;\n } else if (part.startsWith(':') || part.startsWith('[')) {\n // If part starts with a pseudo-class or pseudo-element, append to base\n selector = `${baseSelector}${part}`;\n } else if (\n part.startsWith('>') ||\n part.startsWith('+') ||\n part.startsWith('~')\n ) {\n // If part starts with >, +, ~ combinator, append with space\n selector = `${baseSelector}${part}`;\n } else {\n // Otherwise, combine base with part\n selector = `${baseSelector}${part}`;\n }\n\n // Prepend rootPrefix if present (for @root() states)\n if (rule.rootPrefix) {\n selector = `${rule.rootPrefix} ${selector}`;\n }\n\n return selector;\n })\n .join(', ');\n\n let css = `${fullSelector} { ${rule.declarations} }`;\n\n // Wrap in at-rules (in reverse order for proper nesting)\n if (rule.atRules && rule.atRules.length > 0) {\n for (const atRule of [...rule.atRules].reverse()) {\n css = `${atRule} {\\n ${css}\\n}`;\n }\n }\n\n return css;\n })\n .join('\\n\\n');\n}\n\n/**\n * Format StyleResult[] to CSS string directly without prefixing.\n * Used for global styles where rules already have the full selector.\n */\nfunction formatRulesDirectly(rules: StyleResult[]): string {\n return rules\n .map((rule) => {\n // Prepend rootPrefix if present (for @root() states)\n const selector = rule.rootPrefix\n ? `${rule.rootPrefix} ${rule.selector}`\n : rule.selector;\n\n let css = `${selector} { ${rule.declarations} }`;\n\n // Wrap in at-rules (in reverse order for proper nesting)\n if (rule.atRules && rule.atRules.length > 0) {\n for (const atRule of [...rule.atRules].reverse()) {\n css = `${atRule} {\\n ${css}\\n}`;\n }\n }\n\n return css;\n })\n .join('\\n\\n');\n}\n\n// Note: With hash-based className generation, counter management functions\n// are no longer needed. ClassNames are deterministic based on content.\n\n/**\n * Generate a deterministic keyframes name from content hash.\n * This ensures the same keyframes content always produces the same name,\n * enabling automatic deduplication across elements and files.\n */\nfunction generateKeyframesName(steps: KeyframesSteps): string {\n const content = JSON.stringify(steps);\n const hash = createHash('md5').update(content).digest('hex').slice(0, 6);\n return `kf${hash}`; // 'kf' prefix for \"keyframes\"\n}\n\n/**\n * Extract keyframes that are used in styles.\n * Merges local @keyframes with global keyframes, filters to only used ones.\n * Generates hash-based names from content for automatic deduplication.\n *\n * @param styles - The styles object (may contain @keyframes and animation properties)\n * @param globalKeyframes - Optional global keyframes from config\n * @returns Keyframes to inject and name mapping for replacement\n */\nexport function extractKeyframesFromStyles(\n styles: Styles,\n globalKeyframes?: Record<string, KeyframesSteps> | null,\n): KeyframesExtractionResult {\n const emptyResult: KeyframesExtractionResult = {\n keyframes: [],\n nameMap: new Map(),\n };\n\n // Extract animation names from styles\n const usedNames = extractAnimationNamesFromStyles(styles);\n if (usedNames.size === 0) return emptyResult;\n\n // Merge local and global keyframes\n const local = hasLocalKeyframes(styles)\n ? extractLocalKeyframes(styles)\n : null;\n const allKeyframes = mergeKeyframes(local, globalKeyframes ?? null);\n\n // Filter to only used keyframes\n const usedKeyframes = filterUsedKeyframes(allKeyframes, usedNames);\n if (!usedKeyframes) return emptyResult;\n\n // Generate hash-based names and collect unique keyframes\n const seenHashes = new Set<string>();\n const nameMap = new Map<string, string>();\n const keyframesToEmit: ExtractedKeyframes[] = [];\n\n for (const [originalName, steps] of Object.entries(usedKeyframes)) {\n const hashedName = generateKeyframesName(steps);\n\n // Always map original name to hashed name (for CSS replacement)\n nameMap.set(originalName, hashedName);\n\n // Only emit each unique keyframe once\n if (!seenHashes.has(hashedName)) {\n seenHashes.add(hashedName);\n const css = keyframesToCSS(hashedName, steps);\n keyframesToEmit.push({ name: hashedName, css });\n }\n }\n\n return { keyframes: keyframesToEmit, nameMap };\n}\n\n/**\n * Convert keyframes steps to CSS string.\n */\nfunction keyframesToCSS(name: string, steps: KeyframesSteps): string {\n const stepRules: string[] = [];\n\n for (const [key, value] of Object.entries(steps)) {\n if (typeof value === 'string') {\n // Raw CSS string\n stepRules.push(`${key} { ${value.trim()} }`);\n } else if (value && typeof value === 'object') {\n // Style map - convert to CSS declarations\n const declarations = Object.entries(value)\n .map(([prop, val]) => {\n const cssProperty = camelToKebab(prop);\n return `${cssProperty}: ${val}`;\n })\n .join('; ');\n stepRules.push(`${key} { ${declarations} }`);\n }\n }\n\n return `@keyframes ${name} { ${stepRules.join(' ')} }`;\n}\n\n/**\n * Convert camelCase to kebab-case.\n */\nfunction camelToKebab(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { ExtractedChunk, ExtractedSelector, extractStylesForSelector, extractStylesWithChunks } from "./extractor.js";
2
+ import { CSSWriter } from "./css-writer.js";
3
+ export { CSSWriter, type ExtractedChunk, type ExtractedSelector, extractStylesForSelector, extractStylesWithChunks };
@@ -0,0 +1,4 @@
1
+ import { extractStylesForSelector, extractStylesWithChunks } from "./extractor.js";
2
+ import { CSSWriter } from "./css-writer.js";
3
+
4
+ export { CSSWriter, extractStylesForSelector, extractStylesWithChunks };
@@ -0,0 +1,60 @@
1
+ //#region src/zero/next.d.ts
2
+ /**
3
+ * Next.js configuration wrapper for tasty-zero.
4
+ *
5
+ * Provides a convenient way to configure the Babel plugin for Next.js projects.
6
+ *
7
+ * @example
8
+ * ```javascript
9
+ * // next.config.js
10
+ * const { withTastyZero } = require('@tenphi/tasty/next');
11
+ *
12
+ * module.exports = withTastyZero({
13
+ * output: 'public/tasty.css',
14
+ * })({
15
+ * // your Next.js config
16
+ * });
17
+ * ```
18
+ */
19
+ interface WebpackConfigContext {
20
+ isServer: boolean;
21
+ dev: boolean;
22
+ buildId: string;
23
+ dir: string;
24
+ }
25
+ interface NextConfig {
26
+ webpack?: (config: any, context: WebpackConfigContext) => any;
27
+ [key: string]: unknown;
28
+ }
29
+ interface TastyZeroNextOptions {
30
+ /**
31
+ * Output path for CSS relative to project root.
32
+ * @default 'public/tasty.css'
33
+ */
34
+ output?: string;
35
+ /**
36
+ * Whether to enable the plugin.
37
+ * @default true
38
+ */
39
+ enabled?: boolean;
40
+ }
41
+ /**
42
+ * Next.js configuration wrapper for tasty-zero.
43
+ *
44
+ * @param options - Configuration options
45
+ * @returns A function that wraps the Next.js config
46
+ *
47
+ * @example
48
+ * ```javascript
49
+ * // next.config.js
50
+ * const { withTastyZero } = require('@tenphi/tasty/next');
51
+ *
52
+ * module.exports = withTastyZero()({
53
+ * reactStrictMode: true,
54
+ * });
55
+ * ```
56
+ */
57
+ declare function withTastyZero(options?: TastyZeroNextOptions): (nextConfig?: NextConfig) => NextConfig;
58
+ //#endregion
59
+ export { TastyZeroNextOptions, withTastyZero };
60
+ //# sourceMappingURL=next.d.ts.map
@@ -0,0 +1,78 @@
1
+ import { __require } from "../_virtual/_rolldown/runtime.js";
2
+ import * as path from "path";
3
+
4
+ //#region src/zero/next.ts
5
+ /**
6
+ * Next.js configuration wrapper for tasty-zero.
7
+ *
8
+ * Provides a convenient way to configure the Babel plugin for Next.js projects.
9
+ *
10
+ * @example
11
+ * ```javascript
12
+ * // next.config.js
13
+ * const { withTastyZero } = require('@tenphi/tasty/next');
14
+ *
15
+ * module.exports = withTastyZero({
16
+ * output: 'public/tasty.css',
17
+ * })({
18
+ * // your Next.js config
19
+ * });
20
+ * ```
21
+ */
22
+ /**
23
+ * Next.js configuration wrapper for tasty-zero.
24
+ *
25
+ * @param options - Configuration options
26
+ * @returns A function that wraps the Next.js config
27
+ *
28
+ * @example
29
+ * ```javascript
30
+ * // next.config.js
31
+ * const { withTastyZero } = require('@tenphi/tasty/next');
32
+ *
33
+ * module.exports = withTastyZero()({
34
+ * reactStrictMode: true,
35
+ * });
36
+ * ```
37
+ */
38
+ function withTastyZero(options = {}) {
39
+ const { output = "public/tasty.css", enabled = true } = options;
40
+ return (nextConfig = {}) => {
41
+ if (!enabled) return nextConfig;
42
+ return {
43
+ ...nextConfig,
44
+ webpack(config, context) {
45
+ const { isServer, dir } = context;
46
+ if (!isServer) {
47
+ const absoluteOutput = path.resolve(dir || process.cwd(), output);
48
+ const babelPluginConfig = [__require.resolve("./babel"), { output: absoluteOutput }];
49
+ const existingRule = config.module?.rules?.find((rule) => rule.use?.loader === "babel-loader" || rule.use?.some?.((u) => u.loader === "babel-loader"));
50
+ if (existingRule) {
51
+ const babelUse = Array.isArray(existingRule.use) ? existingRule.use.find((u) => u.loader === "babel-loader") : existingRule.use;
52
+ if (babelUse?.options) {
53
+ babelUse.options.plugins = babelUse.options.plugins || [];
54
+ babelUse.options.plugins.push(babelPluginConfig);
55
+ }
56
+ } else {
57
+ config.module = config.module || {};
58
+ config.module.rules = config.module.rules || [];
59
+ config.module.rules.push({
60
+ test: /\.(tsx?|jsx?)$/,
61
+ exclude: /node_modules/,
62
+ use: [{
63
+ loader: __require.resolve("babel-loader"),
64
+ options: { plugins: [babelPluginConfig] }
65
+ }]
66
+ });
67
+ }
68
+ }
69
+ if (typeof nextConfig.webpack === "function") return nextConfig.webpack(config, context);
70
+ return config;
71
+ }
72
+ };
73
+ };
74
+ }
75
+
76
+ //#endregion
77
+ export { withTastyZero };
78
+ //# sourceMappingURL=next.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next.js","names":[],"sources":["../../src/zero/next.ts"],"sourcesContent":["/**\n * Next.js configuration wrapper for tasty-zero.\n *\n * Provides a convenient way to configure the Babel plugin for Next.js projects.\n *\n * @example\n * ```javascript\n * // next.config.js\n * const { withTastyZero } = require('@tenphi/tasty/next');\n *\n * module.exports = withTastyZero({\n * output: 'public/tasty.css',\n * })({\n * // your Next.js config\n * });\n * ```\n */\n\nimport * as path from 'path';\n\n// Next.js types (inline to avoid requiring next as a dependency)\ninterface WebpackConfigContext {\n isServer: boolean;\n dev: boolean;\n buildId: string;\n dir: string;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any -- webpack config types are complex */\ninterface NextConfig {\n webpack?: (config: any, context: WebpackConfigContext) => any;\n [key: string]: unknown;\n}\n\nexport interface TastyZeroNextOptions {\n /**\n * Output path for CSS relative to project root.\n * @default 'public/tasty.css'\n */\n output?: string;\n\n /**\n * Whether to enable the plugin.\n * @default true\n */\n enabled?: boolean;\n}\n\n/**\n * Next.js configuration wrapper for tasty-zero.\n *\n * @param options - Configuration options\n * @returns A function that wraps the Next.js config\n *\n * @example\n * ```javascript\n * // next.config.js\n * const { withTastyZero } = require('@tenphi/tasty/next');\n *\n * module.exports = withTastyZero()({\n * reactStrictMode: true,\n * });\n * ```\n */\nexport function withTastyZero(options: TastyZeroNextOptions = {}) {\n const { output = 'public/tasty.css', enabled = true } = options;\n\n return (nextConfig: NextConfig = {}): NextConfig => {\n if (!enabled) {\n return nextConfig;\n }\n\n return {\n ...nextConfig,\n\n webpack(config: any, context: WebpackConfigContext) {\n const { isServer, dir } = context;\n\n // Only process on client build to avoid duplicate CSS generation\n if (!isServer) {\n // Get absolute output path\n const absoluteOutput = path.resolve(dir || process.cwd(), output);\n\n // Find existing babel-loader rule or add new one\n const babelPluginConfig = [\n require.resolve('./babel'),\n { output: absoluteOutput },\n ];\n\n // Add our plugin to the existing babel config or create new rule\n const existingRule = config.module?.rules?.find(\n (rule: any) =>\n rule.use?.loader === 'babel-loader' ||\n rule.use?.some?.((u: any) => u.loader === 'babel-loader'),\n );\n\n if (existingRule) {\n // Add to existing babel-loader\n const babelUse = Array.isArray(existingRule.use)\n ? existingRule.use.find((u: any) => u.loader === 'babel-loader')\n : existingRule.use;\n\n if (babelUse?.options) {\n babelUse.options.plugins = babelUse.options.plugins || [];\n babelUse.options.plugins.push(babelPluginConfig);\n }\n } else {\n // Add new rule for our plugin\n config.module = config.module || {};\n config.module.rules = config.module.rules || [];\n config.module.rules.push({\n test: /\\.(tsx?|jsx?)$/,\n exclude: /node_modules/,\n use: [\n {\n loader: require.resolve('babel-loader'),\n options: {\n plugins: [babelPluginConfig],\n },\n },\n ],\n });\n }\n }\n\n // Chain with existing webpack config\n if (typeof nextConfig.webpack === 'function') {\n return nextConfig.webpack(config, context);\n }\n\n return config;\n },\n };\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgEA,SAAgB,cAAc,UAAgC,EAAE,EAAE;CAChE,MAAM,EAAE,SAAS,oBAAoB,UAAU,SAAS;AAExD,SAAQ,aAAyB,EAAE,KAAiB;AAClD,MAAI,CAAC,QACH,QAAO;AAGT,SAAO;GACL,GAAG;GAEH,QAAQ,QAAa,SAA+B;IAClD,MAAM,EAAE,UAAU,QAAQ;AAG1B,QAAI,CAAC,UAAU;KAEb,MAAM,iBAAiB,KAAK,QAAQ,OAAO,QAAQ,KAAK,EAAE,OAAO;KAGjE,MAAM,oBAAoB,WAChB,QAAQ,UAAU,EAC1B,EAAE,QAAQ,gBAAgB,CAC3B;KAGD,MAAM,eAAe,OAAO,QAAQ,OAAO,MACxC,SACC,KAAK,KAAK,WAAW,kBACrB,KAAK,KAAK,QAAQ,MAAW,EAAE,WAAW,eAAe,CAC5D;AAED,SAAI,cAAc;MAEhB,MAAM,WAAW,MAAM,QAAQ,aAAa,IAAI,GAC5C,aAAa,IAAI,MAAM,MAAW,EAAE,WAAW,eAAe,GAC9D,aAAa;AAEjB,UAAI,UAAU,SAAS;AACrB,gBAAS,QAAQ,UAAU,SAAS,QAAQ,WAAW,EAAE;AACzD,gBAAS,QAAQ,QAAQ,KAAK,kBAAkB;;YAE7C;AAEL,aAAO,SAAS,OAAO,UAAU,EAAE;AACnC,aAAO,OAAO,QAAQ,OAAO,OAAO,SAAS,EAAE;AAC/C,aAAO,OAAO,MAAM,KAAK;OACvB,MAAM;OACN,SAAS;OACT,KAAK,CACH;QACE,kBAAgB,QAAQ,eAAe;QACvC,SAAS,EACP,SAAS,CAAC,kBAAkB,EAC7B;QACF,CACF;OACF,CAAC;;;AAKN,QAAI,OAAO,WAAW,YAAY,WAChC,QAAO,WAAW,QAAQ,QAAQ,QAAQ;AAG5C,WAAO;;GAEV"}
package/package.json ADDED
@@ -0,0 +1,133 @@
1
+ {
2
+ "name": "@tenphi/tasty",
3
+ "version": "0.0.0-snapshot.2f99c73",
4
+ "description": "A design-system-integrated styling system and DSL for concise, state-aware UI styling",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "import": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "./static": {
14
+ "import": {
15
+ "types": "./dist/static/index.d.ts",
16
+ "default": "./dist/static/index.js"
17
+ }
18
+ },
19
+ "./babel-plugin": {
20
+ "import": {
21
+ "types": "./dist/zero/babel.d.ts",
22
+ "default": "./dist/zero/babel.js"
23
+ }
24
+ },
25
+ "./zero": {
26
+ "import": {
27
+ "types": "./dist/zero/index.d.ts",
28
+ "default": "./dist/zero/index.js"
29
+ }
30
+ },
31
+ "./next": {
32
+ "import": {
33
+ "types": "./dist/zero/next.d.ts",
34
+ "default": "./dist/zero/next.js"
35
+ }
36
+ },
37
+ "./parser": {
38
+ "import": {
39
+ "types": "./dist/parser/index.d.ts",
40
+ "default": "./dist/parser/index.js"
41
+ }
42
+ }
43
+ },
44
+ "files": [
45
+ "dist"
46
+ ],
47
+ "sideEffects": false,
48
+ "engines": {
49
+ "node": ">=20"
50
+ },
51
+ "scripts": {
52
+ "build": "tsdown",
53
+ "test": "vitest run",
54
+ "test:watch": "vitest",
55
+ "test:coverage": "vitest run --coverage",
56
+ "typecheck": "tsc --noEmit",
57
+ "lint": "eslint src",
58
+ "lint:fix": "eslint src --fix",
59
+ "format": "prettier --write \"src/**/*.{ts,tsx}\"",
60
+ "format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
61
+ "prepublishOnly": "pnpm run build",
62
+ "changeset": "changeset",
63
+ "version": "changeset version",
64
+ "release": "changeset publish"
65
+ },
66
+ "repository": {
67
+ "type": "git",
68
+ "url": "git+https://github.com/tenphi/tasty.git"
69
+ },
70
+ "keywords": [
71
+ "css-in-js",
72
+ "styling",
73
+ "design-system",
74
+ "react",
75
+ "state-aware",
76
+ "zero-runtime",
77
+ "babel-plugin",
78
+ "typescript",
79
+ "dsl"
80
+ ],
81
+ "author": "Andrey Yamanov",
82
+ "license": "MIT",
83
+ "bugs": {
84
+ "url": "https://github.com/tenphi/tasty/issues"
85
+ },
86
+ "homepage": "https://github.com/tenphi/tasty#readme",
87
+ "peerDependencies": {
88
+ "@babel/core": "^7.24.0",
89
+ "react": "^18.0.0 || ^19.0.0"
90
+ },
91
+ "peerDependenciesMeta": {
92
+ "react": {
93
+ "optional": true
94
+ },
95
+ "@babel/core": {
96
+ "optional": true
97
+ }
98
+ },
99
+ "dependencies": {
100
+ "@babel/helper-plugin-utils": "^7.24.0",
101
+ "@babel/types": "^7.24.0",
102
+ "csstype": "^3.1.0",
103
+ "react-is": "^18.3.1"
104
+ },
105
+ "devDependencies": {
106
+ "@babel/core": "^7.24.0",
107
+ "@changesets/changelog-github": "^0.5.2",
108
+ "@changesets/cli": "^2.29.8",
109
+ "@eslint/js": "^10.0.1",
110
+ "@testing-library/jest-dom": "^6.9.1",
111
+ "@testing-library/react": "^16.3.2",
112
+ "@types/babel__core": "^7.20.5",
113
+ "@types/babel__helper-plugin-utils": "^7.10.3",
114
+ "@types/node": "^25.3.2",
115
+ "@types/react": "^19.0.0",
116
+ "@vitest/runner": "^4.0.18",
117
+ "eslint": "^10.0.0",
118
+ "eslint-config-prettier": "^10.1.8",
119
+ "jsdom": "^28.1.0",
120
+ "prettier": "^3.8.1",
121
+ "react": "^19.0.0",
122
+ "tsdown": "^0.20.3",
123
+ "typescript": "^5.9.3",
124
+ "typescript-eslint": "^8.56.0",
125
+ "vitest": "^4.0.18"
126
+ },
127
+ "pnpm": {
128
+ "onlyBuiltDependencies": [
129
+ "esbuild"
130
+ ]
131
+ },
132
+ "packageManager": "pnpm@10.29.3"
133
+ }