loopwind 0.9.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 (245) hide show
  1. package/FONTS.md +156 -0
  2. package/HELPERS_DEMO.md +134 -0
  3. package/PROJECT_STRUCTURE.md +286 -0
  4. package/PUBLISHING.md +171 -0
  5. package/README.md +1020 -0
  6. package/REGISTRY_SETUP.md +427 -0
  7. package/SHADCN_INTEGRATION.md +269 -0
  8. package/TAILWIND.md +228 -0
  9. package/TEMPLATE_SOURCES.md +363 -0
  10. package/_dsgn/templates/banner-hero/banner-hero.tsx +57 -0
  11. package/_dsgn/templates/banner-hero/meta.json +14 -0
  12. package/_dsgn/templates/composite-card/meta.json +16 -0
  13. package/_dsgn/templates/composite-card/template.tsx +44 -0
  14. package/_dsgn/templates/image/meta.json +13 -0
  15. package/_dsgn/templates/image/template.tsx +28 -0
  16. package/_dsgn/templates/kitchen-sink/meta.json +13 -0
  17. package/_dsgn/templates/kitchen-sink/template.tsx +72 -0
  18. package/_dsgn/templates/qr-card/meta.json +14 -0
  19. package/_dsgn/templates/qr-card/template.tsx +39 -0
  20. package/_dsgn/templates/test-parent/child/meta.json +11 -0
  21. package/_dsgn/templates/test-parent/child/template.tsx +27 -0
  22. package/_dsgn/templates/test-parent/meta.json +12 -0
  23. package/_dsgn/templates/test-parent/template.tsx +30 -0
  24. package/_dsgn/templates/test-sibling/meta.json +11 -0
  25. package/_dsgn/templates/test-sibling/template.tsx +20 -0
  26. package/_dsgn/templates/video/.tmp/template-1763421345296.mjs +43 -0
  27. package/_dsgn/templates/video/.tmp/template-1763421362228.mjs +43 -0
  28. package/_dsgn/templates/video/.tmp/template-1763421377706.mjs +43 -0
  29. package/_dsgn/templates/video/meta.json +17 -0
  30. package/_dsgn/templates/video/template.tsx +48 -0
  31. package/dist/cli.d.ts +3 -0
  32. package/dist/cli.d.ts.map +1 -0
  33. package/dist/cli.js +70 -0
  34. package/dist/cli.js.map +1 -0
  35. package/dist/commands/add.d.ts +6 -0
  36. package/dist/commands/add.d.ts.map +1 -0
  37. package/dist/commands/add.js +86 -0
  38. package/dist/commands/add.js.map +1 -0
  39. package/dist/commands/default.d.ts +2 -0
  40. package/dist/commands/default.d.ts.map +1 -0
  41. package/dist/commands/default.js +69 -0
  42. package/dist/commands/default.js.map +1 -0
  43. package/dist/commands/init.d.ts +2 -0
  44. package/dist/commands/init.d.ts.map +1 -0
  45. package/dist/commands/init.js +75 -0
  46. package/dist/commands/init.js.map +1 -0
  47. package/dist/commands/list.d.ts +2 -0
  48. package/dist/commands/list.d.ts.map +1 -0
  49. package/dist/commands/list.js +83 -0
  50. package/dist/commands/list.js.map +1 -0
  51. package/dist/commands/preview.d.ts +3 -0
  52. package/dist/commands/preview.d.ts.map +1 -0
  53. package/dist/commands/preview.js +296 -0
  54. package/dist/commands/preview.js.map +1 -0
  55. package/dist/commands/render.d.ts +10 -0
  56. package/dist/commands/render.d.ts.map +1 -0
  57. package/dist/commands/render.js +204 -0
  58. package/dist/commands/render.js.map +1 -0
  59. package/dist/commands/validate.d.ts +2 -0
  60. package/dist/commands/validate.d.ts.map +1 -0
  61. package/dist/commands/validate.js +107 -0
  62. package/dist/commands/validate.js.map +1 -0
  63. package/dist/default-templates/AGENTS.md +229 -0
  64. package/dist/default-templates/image/meta.json +13 -0
  65. package/dist/default-templates/image/template.d.ts +20 -0
  66. package/dist/default-templates/image/template.d.ts.map +1 -0
  67. package/dist/default-templates/image/template.js +18 -0
  68. package/dist/default-templates/image/template.js.map +1 -0
  69. package/dist/default-templates/image/template.tsx +20 -0
  70. package/dist/default-templates/image-template/meta.json +13 -0
  71. package/dist/default-templates/image-template/template.tsx +19 -0
  72. package/dist/default-templates/kitchen-sink/meta.json +13 -0
  73. package/dist/default-templates/kitchen-sink/template.tsx +64 -0
  74. package/dist/default-templates/page/meta.json +17 -0
  75. package/dist/default-templates/page/template.tsx +37 -0
  76. package/dist/default-templates/video/meta.json +17 -0
  77. package/dist/default-templates/video/template.d.ts +26 -0
  78. package/dist/default-templates/video/template.d.ts.map +1 -0
  79. package/dist/default-templates/video/template.js +33 -0
  80. package/dist/default-templates/video/template.js.map +1 -0
  81. package/dist/default-templates/video/template.tsx +37 -0
  82. package/dist/default-templates/video-template/meta.json +17 -0
  83. package/dist/default-templates/video-template/template.tsx +36 -0
  84. package/dist/default-templates/website/meta.json +16 -0
  85. package/dist/default-templates/website/pages/home.tsx +17 -0
  86. package/dist/default-templates/website/parts/footer.tsx +17 -0
  87. package/dist/default-templates/website/parts/header.tsx +17 -0
  88. package/dist/default-templates/website/template.tsx +17 -0
  89. package/dist/default-templates/website-template/meta.json +16 -0
  90. package/dist/default-templates/website-template/pages/home.tsx +16 -0
  91. package/dist/default-templates/website-template/parts/footer.tsx +16 -0
  92. package/dist/default-templates/website-template/parts/header.tsx +16 -0
  93. package/dist/default-templates/website-template/template.tsx +16 -0
  94. package/dist/lib/config.d.ts +34 -0
  95. package/dist/lib/config.d.ts.map +1 -0
  96. package/dist/lib/config.js +248 -0
  97. package/dist/lib/config.js.map +1 -0
  98. package/dist/lib/constants.d.ts +7 -0
  99. package/dist/lib/constants.d.ts.map +1 -0
  100. package/dist/lib/constants.js +12 -0
  101. package/dist/lib/constants.js.map +1 -0
  102. package/dist/lib/helpers.d.ts +29 -0
  103. package/dist/lib/helpers.d.ts.map +1 -0
  104. package/dist/lib/helpers.js +159 -0
  105. package/dist/lib/helpers.js.map +1 -0
  106. package/dist/lib/installer.d.ts +51 -0
  107. package/dist/lib/installer.d.ts.map +1 -0
  108. package/dist/lib/installer.js +215 -0
  109. package/dist/lib/installer.js.map +1 -0
  110. package/dist/lib/renderer.d.ts +51 -0
  111. package/dist/lib/renderer.d.ts.map +1 -0
  112. package/dist/lib/renderer.js +524 -0
  113. package/dist/lib/renderer.js.map +1 -0
  114. package/dist/lib/tailwind-config-loader.d.ts +47 -0
  115. package/dist/lib/tailwind-config-loader.d.ts.map +1 -0
  116. package/dist/lib/tailwind-config-loader.js +432 -0
  117. package/dist/lib/tailwind-config-loader.js.map +1 -0
  118. package/dist/lib/tailwind-detector.d.ts +36 -0
  119. package/dist/lib/tailwind-detector.d.ts.map +1 -0
  120. package/dist/lib/tailwind-detector.js +156 -0
  121. package/dist/lib/tailwind-detector.js.map +1 -0
  122. package/dist/lib/tailwind.d.ts +8 -0
  123. package/dist/lib/tailwind.d.ts.map +1 -0
  124. package/dist/lib/tailwind.js +994 -0
  125. package/dist/lib/tailwind.js.map +1 -0
  126. package/dist/lib/template-validator.d.ts +22 -0
  127. package/dist/lib/template-validator.d.ts.map +1 -0
  128. package/dist/lib/template-validator.js +174 -0
  129. package/dist/lib/template-validator.js.map +1 -0
  130. package/dist/lib/utils.d.ts +44 -0
  131. package/dist/lib/utils.d.ts.map +1 -0
  132. package/dist/lib/utils.js +207 -0
  133. package/dist/lib/utils.js.map +1 -0
  134. package/dist/lib/version-check.d.ts +16 -0
  135. package/dist/lib/version-check.d.ts.map +1 -0
  136. package/dist/lib/version-check.js +88 -0
  137. package/dist/lib/version-check.js.map +1 -0
  138. package/dist/lib/video-renderer.d.ts +32 -0
  139. package/dist/lib/video-renderer.d.ts.map +1 -0
  140. package/dist/lib/video-renderer.js +226 -0
  141. package/dist/lib/video-renderer.js.map +1 -0
  142. package/dist/sdk/index.d.ts +58 -0
  143. package/dist/sdk/index.d.ts.map +1 -0
  144. package/dist/sdk/index.js +119 -0
  145. package/dist/sdk/index.js.map +1 -0
  146. package/dist/sdk/template.d.ts +40 -0
  147. package/dist/sdk/template.d.ts.map +1 -0
  148. package/dist/sdk/template.js +60 -0
  149. package/dist/sdk/template.js.map +1 -0
  150. package/dist/types/config.d.ts +62 -0
  151. package/dist/types/config.d.ts.map +1 -0
  152. package/dist/types/config.js +47 -0
  153. package/dist/types/config.js.map +1 -0
  154. package/dist/types/template.d.ts +79 -0
  155. package/dist/types/template.d.ts.map +1 -0
  156. package/dist/types/template.js +2 -0
  157. package/dist/types/template.js.map +1 -0
  158. package/examples/nextjs-api/README.md +180 -0
  159. package/examples/nextjs-api/package.json +21 -0
  160. package/examples/nextjs-api/pages/api/intro-video.ts +53 -0
  161. package/examples/nextjs-api/pages/api/og-image.ts +50 -0
  162. package/netlify.toml +13 -0
  163. package/package.json +84 -0
  164. package/patches/satori+0.18.3.patch +13 -0
  165. package/test-templates/TESTS.md +63 -0
  166. package/test-templates/_dsgn/templates/absolute-spin/meta.json +7 -0
  167. package/test-templates/_dsgn/templates/absolute-spin/template.tsx +16 -0
  168. package/test-templates/_dsgn/templates/animated-intro/.tmp/template-1763468771640.mjs +7 -0
  169. package/test-templates/_dsgn/templates/animated-intro/meta.json +10 -0
  170. package/test-templates/_dsgn/templates/animated-intro/template.tsx +23 -0
  171. package/test-templates/_dsgn/templates/centered-spin/.tmp/template-1763468525386.mjs +7 -0
  172. package/test-templates/_dsgn/templates/centered-spin/meta.json +7 -0
  173. package/test-templates/_dsgn/templates/centered-spin/template.tsx +11 -0
  174. package/test-templates/_dsgn/templates/composite/.tmp/template-1763468815645.mjs +7 -0
  175. package/test-templates/_dsgn/templates/composite/meta.json +9 -0
  176. package/test-templates/_dsgn/templates/composite/template.tsx +23 -0
  177. package/test-templates/_dsgn/templates/easing-test/.tmp/template-1763468824501.mjs +7 -0
  178. package/test-templates/_dsgn/templates/easing-test/meta.json +7 -0
  179. package/test-templates/_dsgn/templates/easing-test/template.tsx +47 -0
  180. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466364336.mjs +10 -0
  181. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466584319.mjs +10 -0
  182. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466667797.mjs +10 -0
  183. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466746504.mjs +10 -0
  184. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763466930225.mjs +10 -0
  185. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467004552.mjs +10 -0
  186. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467060334.mjs +10 -0
  187. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467124493.mjs +10 -0
  188. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467174690.mjs +10 -0
  189. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467359134.mjs +10 -0
  190. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467451928.mjs +10 -0
  191. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467758275.mjs +10 -0
  192. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763467985201.mjs +10 -0
  193. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468020563.mjs +10 -0
  194. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468090428.mjs +10 -0
  195. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468211036.mjs +10 -0
  196. package/test-templates/_dsgn/templates/minimal-spin/.tmp/template-1763468394057.mjs +10 -0
  197. package/test-templates/_dsgn/templates/minimal-spin/meta.json +7 -0
  198. package/test-templates/_dsgn/templates/minimal-spin/template.tsx +13 -0
  199. package/test-templates/_dsgn/templates/no-origin-spin/meta.json +7 -0
  200. package/test-templates/_dsgn/templates/no-origin-spin/template.tsx +10 -0
  201. package/test-templates/_dsgn/templates/opacity-test/meta.json +7 -0
  202. package/test-templates/_dsgn/templates/opacity-test/template.tsx +9 -0
  203. package/test-templates/_dsgn/templates/qr-code/.tmp/template-1763468758954.mjs +17 -0
  204. package/test-templates/_dsgn/templates/qr-code/.tmp/template-1763468815672.mjs +17 -0
  205. package/test-templates/_dsgn/templates/qr-code/meta.json +9 -0
  206. package/test-templates/_dsgn/templates/qr-code/template.tsx +20 -0
  207. package/test-templates/_dsgn/templates/rotation-abs-test/meta.json +7 -0
  208. package/test-templates/_dsgn/templates/rotation-abs-test/template.tsx +15 -0
  209. package/test-templates/_dsgn/templates/rotation-corner/meta.json +7 -0
  210. package/test-templates/_dsgn/templates/rotation-corner/template.tsx +12 -0
  211. package/test-templates/_dsgn/templates/rotation-test/meta.json +7 -0
  212. package/test-templates/_dsgn/templates/rotation-test/template.tsx +12 -0
  213. package/test-templates/_dsgn/templates/shake-test/meta.json +7 -0
  214. package/test-templates/_dsgn/templates/shake-test/template.tsx +12 -0
  215. package/test-templates/_dsgn/templates/static-image/.tmp/template-1763468746271.mjs +7 -0
  216. package/test-templates/_dsgn/templates/static-image/meta.json +9 -0
  217. package/test-templates/_dsgn/templates/static-image/template.tsx +19 -0
  218. package/test-templates/_dsgn/templates/translate-test/meta.json +7 -0
  219. package/test-templates/_dsgn/templates/translate-test/template.tsx +9 -0
  220. package/test-templates/_dsgn/templates/video-loops/.tmp/template-1763468793192.mjs +15 -0
  221. package/test-templates/_dsgn/templates/video-loops/meta.json +9 -0
  222. package/test-templates/_dsgn/templates/video-loops/template.tsx +39 -0
  223. package/test-templates/_dsgn/templates/wrapped-spin/meta.json +7 -0
  224. package/test-templates/_dsgn/templates/wrapped-spin/template.tsx +17 -0
  225. package/test-templates/compare-svgs.mjs +30 -0
  226. package/test-templates/convert-frames.mjs +15 -0
  227. package/test-templates/debug-rotation.mjs +25 -0
  228. package/test-templates/run-tests.sh +39 -0
  229. package/test-templates/test-sdk.mjs +115 -0
  230. package/website/.astro/settings.json +5 -0
  231. package/website/.astro/types.d.ts +1 -0
  232. package/website/README.md +112 -0
  233. package/website/astro.config.mjs +18 -0
  234. package/website/dist/_astro/fonts.DHdiHGBO.css +1 -0
  235. package/website/dist/fonts/index.html +193 -0
  236. package/website/dist/helpers/index.html +166 -0
  237. package/website/dist/images/index.html +314 -0
  238. package/website/dist/index.html +219 -0
  239. package/website/dist/llm.txt +2448 -0
  240. package/website/dist/styling/index.html +365 -0
  241. package/website/dist/templates/index.html +124 -0
  242. package/website/dist/video/index.html +636 -0
  243. package/website/package-lock.json +7606 -0
  244. package/website/package.json +23 -0
  245. package/website/public/robots.txt +5 -0
@@ -0,0 +1,994 @@
1
+ import { resolveColor, resolveSpacing, resolveFontSize, resolveBorderRadius, } from './tailwind-config-loader.js';
2
+ /**
3
+ * Tailwind class to style property mapping
4
+ * This is a simplified version - in production you'd parse the full Tailwind config
5
+ */
6
+ const TAILWIND_MAP = {
7
+ // Display
8
+ 'flex': { display: 'flex' },
9
+ 'inline-flex': { display: 'inline-flex' },
10
+ 'block': { display: 'block' },
11
+ 'inline-block': { display: 'inline-block' },
12
+ 'hidden': { display: 'none' },
13
+ 'contents': { display: 'contents' },
14
+ // Position
15
+ 'static': { position: 'static' },
16
+ 'relative': { position: 'relative' },
17
+ 'absolute': { position: 'absolute' },
18
+ // Overflow
19
+ 'overflow-visible': { overflow: 'visible' },
20
+ 'overflow-hidden': { overflow: 'hidden' },
21
+ // Flex Direction
22
+ 'flex-row': { flexDirection: 'row' },
23
+ 'flex-col': { flexDirection: 'column' },
24
+ 'flex-row-reverse': { flexDirection: 'row-reverse' },
25
+ 'flex-col-reverse': { flexDirection: 'column-reverse' },
26
+ // Flex Wrap
27
+ 'flex-wrap': { flexWrap: 'wrap' },
28
+ 'flex-nowrap': { flexWrap: 'nowrap' },
29
+ 'flex-wrap-reverse': { flexWrap: 'wrap-reverse' },
30
+ // Flex
31
+ 'flex-1': { flex: '1 1 0%' },
32
+ 'flex-auto': { flex: '1 1 auto' },
33
+ 'flex-initial': { flex: '0 1 auto' },
34
+ 'flex-none': { flex: 'none' },
35
+ // Justify Content
36
+ 'justify-start': { justifyContent: 'flex-start' },
37
+ 'justify-end': { justifyContent: 'flex-end' },
38
+ 'justify-center': { justifyContent: 'center' },
39
+ 'justify-between': { justifyContent: 'space-between' },
40
+ 'justify-around': { justifyContent: 'space-around' },
41
+ 'justify-evenly': { justifyContent: 'space-evenly' },
42
+ // Align Items
43
+ 'items-start': { alignItems: 'flex-start' },
44
+ 'items-end': { alignItems: 'flex-end' },
45
+ 'items-center': { alignItems: 'center' },
46
+ 'items-baseline': { alignItems: 'baseline' },
47
+ 'items-stretch': { alignItems: 'stretch' },
48
+ // Align Content
49
+ 'content-start': { alignContent: 'flex-start' },
50
+ 'content-end': { alignContent: 'flex-end' },
51
+ 'content-center': { alignContent: 'center' },
52
+ 'content-between': { alignContent: 'space-between' },
53
+ 'content-around': { alignContent: 'space-around' },
54
+ 'content-evenly': { alignContent: 'space-evenly' },
55
+ 'content-stretch': { alignContent: 'stretch' },
56
+ // Align Self
57
+ 'self-auto': { alignSelf: 'auto' },
58
+ 'self-start': { alignSelf: 'flex-start' },
59
+ 'self-end': { alignSelf: 'flex-end' },
60
+ 'self-center': { alignSelf: 'center' },
61
+ 'self-stretch': { alignSelf: 'stretch' },
62
+ 'self-baseline': { alignSelf: 'baseline' },
63
+ // Width & Height
64
+ 'w-full': { width: '100%' },
65
+ 'h-full': { height: '100%' },
66
+ 'w-screen': { width: '100vw' },
67
+ 'h-screen': { height: '100vh' },
68
+ 'w-auto': { width: 'auto' },
69
+ 'h-auto': { height: 'auto' },
70
+ // Max Width
71
+ 'max-w-none': { maxWidth: 'none' },
72
+ 'max-w-xs': { maxWidth: '20rem' },
73
+ 'max-w-sm': { maxWidth: '24rem' },
74
+ 'max-w-md': { maxWidth: '28rem' },
75
+ 'max-w-lg': { maxWidth: '32rem' },
76
+ 'max-w-xl': { maxWidth: '36rem' },
77
+ 'max-w-2xl': { maxWidth: '42rem' },
78
+ 'max-w-3xl': { maxWidth: '48rem' },
79
+ 'max-w-4xl': { maxWidth: '56rem' },
80
+ 'max-w-5xl': { maxWidth: '64rem' },
81
+ 'max-w-6xl': { maxWidth: '72rem' },
82
+ 'max-w-7xl': { maxWidth: '80rem' },
83
+ 'max-w-full': { maxWidth: '100%' },
84
+ // Min Width
85
+ 'min-w-0': { minWidth: '0' },
86
+ 'min-w-full': { minWidth: '100%' },
87
+ // Max Height
88
+ 'max-h-full': { maxHeight: '100%' },
89
+ 'max-h-screen': { maxHeight: '100vh' },
90
+ // Min Height
91
+ 'min-h-0': { minHeight: '0' },
92
+ 'min-h-full': { minHeight: '100%' },
93
+ 'min-h-screen': { minHeight: '100vh' },
94
+ // Text Alignment
95
+ 'text-left': { textAlign: 'left' },
96
+ 'text-center': { textAlign: 'center' },
97
+ 'text-right': { textAlign: 'right' },
98
+ 'text-justify': { textAlign: 'justify' },
99
+ // Text Transform
100
+ 'uppercase': { textTransform: 'uppercase' },
101
+ 'lowercase': { textTransform: 'lowercase' },
102
+ 'capitalize': { textTransform: 'capitalize' },
103
+ 'normal-case': { textTransform: 'none' },
104
+ // Text Decoration
105
+ 'underline': { textDecoration: 'underline' },
106
+ 'line-through': { textDecoration: 'line-through' },
107
+ 'no-underline': { textDecoration: 'none' },
108
+ // Text Overflow
109
+ 'truncate': { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
110
+ 'text-ellipsis': { textOverflow: 'ellipsis' },
111
+ 'text-clip': { textOverflow: 'clip' },
112
+ // White Space
113
+ 'whitespace-normal': { whiteSpace: 'normal' },
114
+ 'whitespace-nowrap': { whiteSpace: 'nowrap' },
115
+ 'whitespace-pre': { whiteSpace: 'pre' },
116
+ 'whitespace-pre-line': { whiteSpace: 'pre-line' },
117
+ 'whitespace-pre-wrap': { whiteSpace: 'pre-wrap' },
118
+ // Word Break
119
+ 'break-normal': { wordBreak: 'normal', overflowWrap: 'normal' },
120
+ 'break-words': { overflowWrap: 'break-word' },
121
+ 'break-all': { wordBreak: 'break-all' },
122
+ // Font Weight
123
+ 'font-thin': { fontWeight: 100 },
124
+ 'font-extralight': { fontWeight: 200 },
125
+ 'font-light': { fontWeight: 300 },
126
+ 'font-normal': { fontWeight: 400 },
127
+ 'font-medium': { fontWeight: 500 },
128
+ 'font-semibold': { fontWeight: 600 },
129
+ 'font-bold': { fontWeight: 700 },
130
+ 'font-extrabold': { fontWeight: 800 },
131
+ 'font-black': { fontWeight: 900 },
132
+ // Font Style
133
+ 'italic': { fontStyle: 'italic' },
134
+ 'not-italic': { fontStyle: 'normal' },
135
+ // Line Height
136
+ 'leading-none': { lineHeight: '1' },
137
+ 'leading-tight': { lineHeight: '1.25' },
138
+ 'leading-snug': { lineHeight: '1.375' },
139
+ 'leading-normal': { lineHeight: '1.5' },
140
+ 'leading-relaxed': { lineHeight: '1.625' },
141
+ 'leading-loose': { lineHeight: '2' },
142
+ // Letter Spacing
143
+ 'tracking-tighter': { letterSpacing: '-0.05em' },
144
+ 'tracking-tight': { letterSpacing: '-0.025em' },
145
+ 'tracking-normal': { letterSpacing: '0em' },
146
+ 'tracking-wide': { letterSpacing: '0.025em' },
147
+ 'tracking-wider': { letterSpacing: '0.05em' },
148
+ 'tracking-widest': { letterSpacing: '0.1em' },
149
+ // Object Fit
150
+ 'object-contain': { objectFit: 'contain' },
151
+ 'object-cover': { objectFit: 'cover' },
152
+ 'object-fill': { objectFit: 'fill' },
153
+ 'object-none': { objectFit: 'none' },
154
+ 'object-scale-down': { objectFit: 'scale-down' },
155
+ // Object Position
156
+ 'object-bottom': { objectPosition: 'bottom' },
157
+ 'object-center': { objectPosition: 'center' },
158
+ 'object-left': { objectPosition: 'left' },
159
+ 'object-left-bottom': { objectPosition: 'left bottom' },
160
+ 'object-left-top': { objectPosition: 'left top' },
161
+ 'object-right': { objectPosition: 'right' },
162
+ 'object-right-bottom': { objectPosition: 'right bottom' },
163
+ 'object-right-top': { objectPosition: 'right top' },
164
+ 'object-top': { objectPosition: 'top' },
165
+ // Background Size
166
+ 'bg-auto': { backgroundSize: 'auto' },
167
+ 'bg-cover': { backgroundSize: 'cover' },
168
+ 'bg-contain': { backgroundSize: 'contain' },
169
+ // Background Position
170
+ 'bg-bottom': { backgroundPosition: 'bottom' },
171
+ 'bg-center': { backgroundPosition: 'center' },
172
+ 'bg-left': { backgroundPosition: 'left' },
173
+ 'bg-left-bottom': { backgroundPosition: 'left bottom' },
174
+ 'bg-left-top': { backgroundPosition: 'left top' },
175
+ 'bg-right': { backgroundPosition: 'right' },
176
+ 'bg-right-bottom': { backgroundPosition: 'right bottom' },
177
+ 'bg-right-top': { backgroundPosition: 'right top' },
178
+ 'bg-top': { backgroundPosition: 'top' },
179
+ // Background Repeat
180
+ 'bg-repeat': { backgroundRepeat: 'repeat' },
181
+ 'bg-no-repeat': { backgroundRepeat: 'no-repeat' },
182
+ 'bg-repeat-x': { backgroundRepeat: 'repeat-x' },
183
+ 'bg-repeat-y': { backgroundRepeat: 'repeat-y' },
184
+ 'bg-repeat-round': { backgroundRepeat: 'round' },
185
+ 'bg-repeat-space': { backgroundRepeat: 'space' },
186
+ // Box Sizing
187
+ 'box-border': { boxSizing: 'border-box' },
188
+ 'box-content': { boxSizing: 'content-box' },
189
+ // Rounded
190
+ 'rounded': { borderRadius: '0.25rem' },
191
+ 'rounded-none': { borderRadius: '0' },
192
+ 'rounded-sm': { borderRadius: '0.125rem' },
193
+ 'rounded-md': { borderRadius: '0.375rem' },
194
+ 'rounded-lg': { borderRadius: '0.5rem' },
195
+ 'rounded-xl': { borderRadius: '0.75rem' },
196
+ 'rounded-2xl': { borderRadius: '1rem' },
197
+ 'rounded-3xl': { borderRadius: '1.5rem' },
198
+ 'rounded-full': { borderRadius: '9999px' },
199
+ // Colors - white/black
200
+ 'text-white': { color: '#ffffff' },
201
+ 'text-black': { color: '#000000' },
202
+ 'bg-white': { background: '#ffffff' },
203
+ 'bg-black': { background: '#000000' },
204
+ 'bg-transparent': { background: 'transparent' },
205
+ // Shadow
206
+ 'shadow-sm': { boxShadow: '0 1px 2px 0 rgb(0 0 0 / 0.05)' },
207
+ 'shadow': { boxShadow: '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)' },
208
+ 'shadow-md': { boxShadow: '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)' },
209
+ 'shadow-lg': { boxShadow: '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)' },
210
+ 'shadow-xl': { boxShadow: '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)' },
211
+ 'shadow-2xl': { boxShadow: '0 25px 50px -12px rgb(0 0 0 / 0.25)' },
212
+ 'shadow-inner': { boxShadow: 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)' },
213
+ 'shadow-none': { boxShadow: 'none' },
214
+ // Text Shadow
215
+ 'text-shadow-sm': { textShadow: '0 1px 2px rgb(0 0 0 / 0.5)' },
216
+ 'text-shadow': { textShadow: '0 2px 4px rgb(0 0 0 / 0.5)' },
217
+ 'text-shadow-md': { textShadow: '0 4px 8px rgb(0 0 0 / 0.5)' },
218
+ 'text-shadow-lg': { textShadow: '0 8px 16px rgb(0 0 0 / 0.5)' },
219
+ 'text-shadow-xl': { textShadow: '0 12px 24px rgb(0 0 0 / 0.5)' },
220
+ 'text-shadow-none': { textShadow: 'none' },
221
+ // Drop Shadow (filter-based)
222
+ 'drop-shadow-sm': { filter: 'drop-shadow(0 1px 1px rgb(0 0 0 / 0.05))' },
223
+ 'drop-shadow': { filter: 'drop-shadow(0 1px 2px rgb(0 0 0 / 0.1)) drop-shadow(0 1px 1px rgb(0 0 0 / 0.06))' },
224
+ 'drop-shadow-md': { filter: 'drop-shadow(0 4px 3px rgb(0 0 0 / 0.07)) drop-shadow(0 2px 2px rgb(0 0 0 / 0.06))' },
225
+ 'drop-shadow-lg': { filter: 'drop-shadow(0 10px 8px rgb(0 0 0 / 0.04)) drop-shadow(0 4px 3px rgb(0 0 0 / 0.1))' },
226
+ 'drop-shadow-xl': { filter: 'drop-shadow(0 20px 13px rgb(0 0 0 / 0.03)) drop-shadow(0 8px 5px rgb(0 0 0 / 0.08))' },
227
+ 'drop-shadow-2xl': { filter: 'drop-shadow(0 25px 25px rgb(0 0 0 / 0.15))' },
228
+ 'drop-shadow-none': { filter: 'drop-shadow(0 0 #0000)' },
229
+ // Blur
230
+ 'blur-none': { filter: 'blur(0)' },
231
+ 'blur-sm': { filter: 'blur(4px)' },
232
+ 'blur': { filter: 'blur(8px)' },
233
+ 'blur-md': { filter: 'blur(12px)' },
234
+ 'blur-lg': { filter: 'blur(16px)' },
235
+ 'blur-xl': { filter: 'blur(24px)' },
236
+ 'blur-2xl': { filter: 'blur(40px)' },
237
+ 'blur-3xl': { filter: 'blur(64px)' },
238
+ // Brightness
239
+ 'brightness-0': { filter: 'brightness(0)' },
240
+ 'brightness-50': { filter: 'brightness(.5)' },
241
+ 'brightness-75': { filter: 'brightness(.75)' },
242
+ 'brightness-90': { filter: 'brightness(.9)' },
243
+ 'brightness-95': { filter: 'brightness(.95)' },
244
+ 'brightness-100': { filter: 'brightness(1)' },
245
+ 'brightness-105': { filter: 'brightness(1.05)' },
246
+ 'brightness-110': { filter: 'brightness(1.1)' },
247
+ 'brightness-125': { filter: 'brightness(1.25)' },
248
+ 'brightness-150': { filter: 'brightness(1.5)' },
249
+ 'brightness-200': { filter: 'brightness(2)' },
250
+ // Contrast
251
+ 'contrast-0': { filter: 'contrast(0)' },
252
+ 'contrast-50': { filter: 'contrast(.5)' },
253
+ 'contrast-75': { filter: 'contrast(.75)' },
254
+ 'contrast-100': { filter: 'contrast(1)' },
255
+ 'contrast-125': { filter: 'contrast(1.25)' },
256
+ 'contrast-150': { filter: 'contrast(1.5)' },
257
+ 'contrast-200': { filter: 'contrast(2)' },
258
+ // Grayscale
259
+ 'grayscale-0': { filter: 'grayscale(0)' },
260
+ 'grayscale': { filter: 'grayscale(100%)' },
261
+ // Invert
262
+ 'invert-0': { filter: 'invert(0)' },
263
+ 'invert': { filter: 'invert(100%)' },
264
+ // Sepia
265
+ 'sepia-0': { filter: 'sepia(0)' },
266
+ 'sepia': { filter: 'sepia(100%)' },
267
+ // Saturate
268
+ 'saturate-0': { filter: 'saturate(0)' },
269
+ 'saturate-50': { filter: 'saturate(.5)' },
270
+ 'saturate-100': { filter: 'saturate(1)' },
271
+ 'saturate-150': { filter: 'saturate(1.5)' },
272
+ 'saturate-200': { filter: 'saturate(2)' },
273
+ // Hue Rotate
274
+ 'hue-rotate-0': { filter: 'hue-rotate(0deg)' },
275
+ 'hue-rotate-15': { filter: 'hue-rotate(15deg)' },
276
+ 'hue-rotate-30': { filter: 'hue-rotate(30deg)' },
277
+ 'hue-rotate-60': { filter: 'hue-rotate(60deg)' },
278
+ 'hue-rotate-90': { filter: 'hue-rotate(90deg)' },
279
+ 'hue-rotate-180': { filter: 'hue-rotate(180deg)' },
280
+ };
281
+ // Spacing map (margin, padding)
282
+ const SPACING_SCALE = {
283
+ '0': '0px',
284
+ '1': '0.25rem',
285
+ '2': '0.5rem',
286
+ '3': '0.75rem',
287
+ '4': '1rem',
288
+ '5': '1.25rem',
289
+ '6': '1.5rem',
290
+ '8': '2rem',
291
+ '10': '2.5rem',
292
+ '12': '3rem',
293
+ '16': '4rem',
294
+ '20': '5rem',
295
+ '24': '6rem',
296
+ '32': '8rem',
297
+ '40': '10rem',
298
+ '48': '12rem',
299
+ '56': '14rem',
300
+ '64': '16rem',
301
+ };
302
+ // Font size map
303
+ const FONT_SIZE_MAP = {
304
+ 'text-xs': { fontSize: '0.75rem', lineHeight: '1rem' },
305
+ 'text-sm': { fontSize: '0.875rem', lineHeight: '1.25rem' },
306
+ 'text-base': { fontSize: '1rem', lineHeight: '1.5rem' },
307
+ 'text-lg': { fontSize: '1.125rem', lineHeight: '1.75rem' },
308
+ 'text-xl': { fontSize: '1.25rem', lineHeight: '1.75rem' },
309
+ 'text-2xl': { fontSize: '1.5rem', lineHeight: '2rem' },
310
+ 'text-3xl': { fontSize: '1.875rem', lineHeight: '2.25rem' },
311
+ 'text-4xl': { fontSize: '2.25rem', lineHeight: '2.5rem' },
312
+ 'text-5xl': { fontSize: '3rem', lineHeight: '1' },
313
+ 'text-6xl': { fontSize: '3.75rem', lineHeight: '1' },
314
+ 'text-7xl': { fontSize: '4.5rem', lineHeight: '1' },
315
+ 'text-8xl': { fontSize: '6rem', lineHeight: '1' },
316
+ 'text-9xl': { fontSize: '8rem', lineHeight: '1' },
317
+ };
318
+ /**
319
+ * Parse a single Tailwind class to a style object
320
+ */
321
+ function parseClass(className, tailwindConfig = null, dsgnConfig = null) {
322
+ // Check static map first
323
+ if (TAILWIND_MAP[className]) {
324
+ return TAILWIND_MAP[className];
325
+ }
326
+ // Parse font sizes - try Tailwind config first
327
+ const fontSizeMatch = className.match(/^text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl)$/);
328
+ if (fontSizeMatch) {
329
+ const size = fontSizeMatch[1];
330
+ const configSize = resolveFontSize(size, tailwindConfig);
331
+ if (configSize) {
332
+ return configSize;
333
+ }
334
+ // Fall back to hardcoded
335
+ if (FONT_SIZE_MAP[className]) {
336
+ return FONT_SIZE_MAP[className];
337
+ }
338
+ }
339
+ // Parse padding/margin - try Tailwind config spacing first
340
+ const spacingMatch = className.match(/^(p|m)(x|y|t|b|l|r)?-(\d+|px)$/);
341
+ if (spacingMatch) {
342
+ const [, type, direction, value] = spacingMatch;
343
+ // Try Tailwind config spacing first
344
+ let size = resolveSpacing(value, tailwindConfig);
345
+ // Fall back to hardcoded scale
346
+ if (!size) {
347
+ size = SPACING_SCALE[value] || `${parseInt(value) * 0.25}rem`;
348
+ }
349
+ const prop = type === 'p' ? 'padding' : 'margin';
350
+ if (!direction) {
351
+ return { [prop]: size };
352
+ }
353
+ else if (direction === 'x') {
354
+ return { [`${prop}Left`]: size, [`${prop}Right`]: size };
355
+ }
356
+ else if (direction === 'y') {
357
+ return { [`${prop}Top`]: size, [`${prop}Bottom`]: size };
358
+ }
359
+ else {
360
+ const dirMap = { t: 'Top', b: 'Bottom', l: 'Left', r: 'Right' };
361
+ return { [`${prop}${dirMap[direction]}`]: size };
362
+ }
363
+ }
364
+ // Parse width/height - try Tailwind config spacing first
365
+ const sizeMatch = className.match(/^(w|h)-(\d+)$/);
366
+ if (sizeMatch) {
367
+ const [, prop, value] = sizeMatch;
368
+ let size = resolveSpacing(value, tailwindConfig);
369
+ if (!size) {
370
+ size = SPACING_SCALE[value] || `${parseInt(value) * 0.25}rem`;
371
+ }
372
+ return { [prop === 'w' ? 'width' : 'height']: size };
373
+ }
374
+ // Parse gap - try Tailwind config spacing first
375
+ const gapMatch = className.match(/^gap(-x|-y)?-(\d+)$/);
376
+ if (gapMatch) {
377
+ const [, direction, value] = gapMatch;
378
+ let size = resolveSpacing(value, tailwindConfig);
379
+ if (!size) {
380
+ size = SPACING_SCALE[value] || `${parseInt(value) * 0.25}rem`;
381
+ }
382
+ if (!direction) {
383
+ return { gap: size };
384
+ }
385
+ else if (direction === '-x') {
386
+ return { columnGap: size };
387
+ }
388
+ else if (direction === '-y') {
389
+ return { rowGap: size };
390
+ }
391
+ }
392
+ // Parse border radius - try Tailwind config first
393
+ const roundedMatch = className.match(/^rounded(?:-(sm|md|lg|xl|2xl|3xl|full))?$/);
394
+ if (roundedMatch) {
395
+ const value = roundedMatch[1] || 'DEFAULT';
396
+ const radius = resolveBorderRadius(value, tailwindConfig);
397
+ if (radius) {
398
+ return { borderRadius: radius };
399
+ }
400
+ // Fall back to hardcoded
401
+ if (TAILWIND_MAP[className]) {
402
+ return TAILWIND_MAP[className];
403
+ }
404
+ }
405
+ // Parse opacity
406
+ const opacityMatch = className.match(/^opacity-(\d+)$/);
407
+ if (opacityMatch) {
408
+ return { opacity: parseInt(opacityMatch[1]) / 100 };
409
+ }
410
+ // Parse background opacity
411
+ const bgOpacityMatch = className.match(/^bg-opacity-(\d+)$/);
412
+ if (bgOpacityMatch) {
413
+ return { __bgOpacity: parseInt(bgOpacityMatch[1]) / 100 };
414
+ }
415
+ // Parse text opacity
416
+ const textOpacityMatch = className.match(/^text-opacity-(\d+)$/);
417
+ if (textOpacityMatch) {
418
+ return { __textOpacity: parseInt(textOpacityMatch[1]) / 100 };
419
+ }
420
+ // Parse border opacity
421
+ const borderOpacityMatch = className.match(/^border-opacity-(\d+)$/);
422
+ if (borderOpacityMatch) {
423
+ return { __borderOpacity: parseInt(borderOpacityMatch[1]) / 100 };
424
+ }
425
+ // Parse flex-grow
426
+ const flexGrowMatch = className.match(/^flex-grow(?:-(\d+))?$/);
427
+ if (flexGrowMatch) {
428
+ const value = flexGrowMatch[1] || '1';
429
+ return { flexGrow: parseInt(value) };
430
+ }
431
+ // Parse flex-shrink
432
+ const flexShrinkMatch = className.match(/^flex-shrink(?:-(\d+))?$/);
433
+ if (flexShrinkMatch) {
434
+ const value = flexShrinkMatch[1] || '1';
435
+ return { flexShrink: parseInt(value) };
436
+ }
437
+ // Parse border width (must come before border color to avoid conflicts)
438
+ // Only matches: border, border-0, border-2, border-4, border-8, border-t-2, etc.
439
+ const borderWidthMatch = className.match(/^border(?:-(t|r|b|l|x|y))?(?:-(0|2|4|8))?$/);
440
+ if (borderWidthMatch) {
441
+ const [, side, width] = borderWidthMatch;
442
+ // border without side or width means default 1px border
443
+ if (!side && !width) {
444
+ // This will be handled by border color parser if it has a color
445
+ // Only return here if it's truly just "border"
446
+ if (className === 'border') {
447
+ return { borderWidth: '1px', borderStyle: 'solid' };
448
+ }
449
+ }
450
+ else {
451
+ // Has explicit side or width
452
+ const borderWidth = width ? `${width}px` : '1px';
453
+ if (!side) {
454
+ return { borderWidth, borderStyle: 'solid' };
455
+ }
456
+ else if (side === 'x') {
457
+ return { borderLeftWidth: borderWidth, borderRightWidth: borderWidth, borderStyle: 'solid' };
458
+ }
459
+ else if (side === 'y') {
460
+ return { borderTopWidth: borderWidth, borderBottomWidth: borderWidth, borderStyle: 'solid' };
461
+ }
462
+ else {
463
+ const sideMap = { t: 'Top', r: 'Right', b: 'Bottom', l: 'Left' };
464
+ return { [`border${sideMap[side]}Width`]: borderWidth, borderStyle: 'solid' };
465
+ }
466
+ }
467
+ }
468
+ // Parse positioning (top, right, bottom, left, inset)
469
+ const positionMatch = className.match(/^(top|right|bottom|left|inset)(?:-(x|y))?-(\d+|auto)$/);
470
+ if (positionMatch) {
471
+ const [, prop, axis, value] = positionMatch;
472
+ const size = value === 'auto' ? 'auto' : (resolveSpacing(value, tailwindConfig) || SPACING_SCALE[value] || `${parseInt(value) * 0.25}rem`);
473
+ if (prop === 'inset') {
474
+ if (!axis) {
475
+ return { top: size, right: size, bottom: size, left: size };
476
+ }
477
+ else if (axis === 'x') {
478
+ return { left: size, right: size };
479
+ }
480
+ else if (axis === 'y') {
481
+ return { top: size, bottom: size };
482
+ }
483
+ }
484
+ return { [prop]: size };
485
+ }
486
+ // Parse rotate
487
+ const rotateMatch = className.match(/^-?rotate-(\d+)$/);
488
+ if (rotateMatch) {
489
+ const degrees = className.startsWith('-') ? `-${rotateMatch[1]}` : rotateMatch[1];
490
+ return { transform: `rotate(${degrees}deg)` };
491
+ }
492
+ // Parse scale
493
+ const scaleMatch = className.match(/^scale(?:-(x|y))?-(\d+)$/);
494
+ if (scaleMatch) {
495
+ const [, axis, value] = scaleMatch;
496
+ const scale = parseInt(value) / 100;
497
+ if (!axis) {
498
+ return { transform: `scale(${scale})` };
499
+ }
500
+ else if (axis === 'x') {
501
+ return { transform: `scaleX(${scale})` };
502
+ }
503
+ else if (axis === 'y') {
504
+ return { transform: `scaleY(${scale})` };
505
+ }
506
+ }
507
+ // Parse translate (including arbitrary values like translate-x-[896px])
508
+ const translateMatch = className.match(/^-?translate-(x|y)-(\d+|1\/2|1\/3|2\/3|1\/4|3\/4|full|\[.+\])$/);
509
+ if (translateMatch) {
510
+ const isNegative = className.startsWith('-');
511
+ const [, axis, value] = translateMatch;
512
+ let size;
513
+ if (value.startsWith('[') && value.endsWith(']')) {
514
+ // Arbitrary value like [896px] or [50%]
515
+ size = value.slice(1, -1);
516
+ }
517
+ else if (value === '1/2')
518
+ size = '50%';
519
+ else if (value === '1/3')
520
+ size = '33.333333%';
521
+ else if (value === '2/3')
522
+ size = '66.666667%';
523
+ else if (value === '1/4')
524
+ size = '25%';
525
+ else if (value === '3/4')
526
+ size = '75%';
527
+ else if (value === 'full')
528
+ size = '100%';
529
+ else
530
+ size = resolveSpacing(value, tailwindConfig) || SPACING_SCALE[value] || `${parseInt(value) * 0.25}rem`;
531
+ if (isNegative && !size.startsWith('-'))
532
+ size = `-${size}`;
533
+ if (axis === 'x') {
534
+ return { transform: `translateX(${size})` };
535
+ }
536
+ else if (axis === 'y') {
537
+ return { transform: `translateY(${size})` };
538
+ }
539
+ }
540
+ // Parse skew
541
+ const skewMatch = className.match(/^-?skew-(x|y)-(\d+)$/);
542
+ if (skewMatch) {
543
+ const isNegative = className.startsWith('-');
544
+ const [, axis, degrees] = skewMatch;
545
+ const deg = isNegative ? `-${degrees}deg` : `${degrees}deg`;
546
+ if (axis === 'x') {
547
+ return { transform: `skewX(${deg})` };
548
+ }
549
+ else if (axis === 'y') {
550
+ return { transform: `skewY(${deg})` };
551
+ }
552
+ }
553
+ // Parse font family
554
+ const fontFamilyMatch = className.match(/^font-(sans|serif|mono)$/);
555
+ if (fontFamilyMatch) {
556
+ const fontType = fontFamilyMatch[1];
557
+ // Try to get font from dsgnConfig
558
+ if (dsgnConfig?.fonts?.[fontType]) {
559
+ const fontDef = dsgnConfig.fonts[fontType];
560
+ // Handle both formats: string[] or { family: string[], files: [...] }
561
+ let fontFamily;
562
+ if (Array.isArray(fontDef)) {
563
+ fontFamily = fontDef.join(', ');
564
+ }
565
+ else if (typeof fontDef === 'object' && fontDef.family) {
566
+ fontFamily = fontDef.family.join(', ');
567
+ }
568
+ else {
569
+ fontFamily = String(fontDef);
570
+ }
571
+ return { fontFamily };
572
+ }
573
+ // Fallback to system defaults
574
+ const fallbacks = {
575
+ 'sans': 'system-ui, -apple-system, sans-serif',
576
+ 'serif': 'Georgia, serif',
577
+ 'mono': 'monospace',
578
+ };
579
+ return { fontFamily: fallbacks[fontType] };
580
+ }
581
+ // Parse colors with optional opacity modifier (e.g., bg-primary/50, text-muted/80)
582
+ const bgMatch = className.match(/^bg-([\w-]+)(?:\/(\d+))?$/);
583
+ if (bgMatch) {
584
+ const colorName = bgMatch[1];
585
+ const opacityValue = bgMatch[2];
586
+ // Try Tailwind config
587
+ let color = resolveColor(colorName, tailwindConfig);
588
+ // Try dsgn.json
589
+ if (!color && dsgnConfig?.colors?.[colorName]) {
590
+ color = dsgnConfig.colors[colorName];
591
+ }
592
+ if (color) {
593
+ // Apply opacity modifier if present
594
+ if (opacityValue) {
595
+ const opacity = parseInt(opacityValue) / 100;
596
+ // Convert hex to rgba
597
+ const hex = color.replace('#', '');
598
+ const r = parseInt(hex.substring(0, 2), 16);
599
+ const g = parseInt(hex.substring(2, 4), 16);
600
+ const b = parseInt(hex.substring(4, 6), 16);
601
+ return { background: `rgba(${r}, ${g}, ${b}, ${opacity})` };
602
+ }
603
+ return { background: color };
604
+ }
605
+ }
606
+ const textMatch = className.match(/^text-([\w-]+)(?:\/(\d+))?$/);
607
+ if (textMatch) {
608
+ const colorName = textMatch[1];
609
+ const opacityValue = textMatch[2];
610
+ // Try Tailwind config
611
+ let color = resolveColor(colorName, tailwindConfig);
612
+ // Try dsgn.json
613
+ if (!color && dsgnConfig?.colors?.[colorName]) {
614
+ color = dsgnConfig.colors[colorName];
615
+ }
616
+ if (color) {
617
+ // Apply opacity modifier if present
618
+ if (opacityValue) {
619
+ const opacity = parseInt(opacityValue) / 100;
620
+ // Convert hex to rgba
621
+ const hex = color.replace('#', '');
622
+ const r = parseInt(hex.substring(0, 2), 16);
623
+ const g = parseInt(hex.substring(2, 4), 16);
624
+ const b = parseInt(hex.substring(4, 6), 16);
625
+ return { color: `rgba(${r}, ${g}, ${b}, ${opacity})` };
626
+ }
627
+ return { color: color };
628
+ }
629
+ }
630
+ // Parse border color with optional opacity
631
+ const borderMatch = className.match(/^border(?:-([\w-]+))?(?:\/(\d+))?$/);
632
+ if (borderMatch) {
633
+ const colorName = borderMatch[1];
634
+ const opacityValue = borderMatch[2];
635
+ // If no color specified, use default border
636
+ if (!colorName) {
637
+ let borderColor = dsgnConfig?.colors?.border || '#e5e7eb';
638
+ if (opacityValue) {
639
+ const opacity = parseInt(opacityValue) / 100;
640
+ const hex = borderColor.replace('#', '');
641
+ const r = parseInt(hex.substring(0, 2), 16);
642
+ const g = parseInt(hex.substring(2, 4), 16);
643
+ const b = parseInt(hex.substring(4, 6), 16);
644
+ return { borderWidth: '1px', borderStyle: 'solid', borderColor: `rgba(${r}, ${g}, ${b}, ${opacity})` };
645
+ }
646
+ return { borderWidth: '1px', borderStyle: 'solid', borderColor };
647
+ }
648
+ // Try Tailwind config
649
+ let color = resolveColor(colorName, tailwindConfig);
650
+ // Try dsgn.json
651
+ if (!color && dsgnConfig?.colors?.[colorName]) {
652
+ color = dsgnConfig.colors[colorName];
653
+ }
654
+ if (color) {
655
+ if (opacityValue) {
656
+ const opacity = parseInt(opacityValue) / 100;
657
+ const hex = color.replace('#', '');
658
+ const r = parseInt(hex.substring(0, 2), 16);
659
+ const g = parseInt(hex.substring(2, 4), 16);
660
+ const b = parseInt(hex.substring(4, 6), 16);
661
+ return { borderWidth: '1px', borderStyle: 'solid', borderColor: `rgba(${r}, ${g}, ${b}, ${opacity})` };
662
+ }
663
+ return { borderWidth: '1px', borderStyle: 'solid', borderColor: color };
664
+ }
665
+ }
666
+ // Note: Gradient classes need to be processed together
667
+ // We'll mark them for batch processing in the tw() function
668
+ const gradientMatch = className.match(/^bg-gradient-to-(t|b|l|r|tr|tl|br|bl)$/);
669
+ if (gradientMatch) {
670
+ return { __gradientDirection: className };
671
+ }
672
+ const gradientStopMatch = className.match(/^(from|via|to)-([\w-]+)(?:\/(\d+))?$/);
673
+ if (gradientStopMatch) {
674
+ const [, position, colorName, opacityValue] = gradientStopMatch;
675
+ // Try Tailwind config
676
+ let color = resolveColor(colorName, tailwindConfig);
677
+ // Try dsgn.json
678
+ if (!color && dsgnConfig?.colors?.[colorName]) {
679
+ color = dsgnConfig.colors[colorName];
680
+ }
681
+ if (color) {
682
+ let finalColor = color;
683
+ if (opacityValue) {
684
+ const opacity = parseInt(opacityValue) / 100;
685
+ const hex = color.replace('#', '');
686
+ const r = parseInt(hex.substring(0, 2), 16);
687
+ const g = parseInt(hex.substring(2, 4), 16);
688
+ const b = parseInt(hex.substring(4, 6), 16);
689
+ finalColor = `rgba(${r}, ${g}, ${b}, ${opacity})`;
690
+ }
691
+ return { [`__gradient${position.charAt(0).toUpperCase() + position.slice(1)}`]: finalColor };
692
+ }
693
+ }
694
+ return {};
695
+ }
696
+ /**
697
+ * Convert Tailwind classes to inline styles
698
+ * Usage: <div style={tw('flex items-center justify-between p-4')} />
699
+ */
700
+ /**
701
+ * Convert hex color to rgba
702
+ */
703
+ function hexToRgba(hex, opacity) {
704
+ const cleanHex = hex.replace('#', '');
705
+ const r = parseInt(cleanHex.substring(0, 2), 16);
706
+ const g = parseInt(cleanHex.substring(2, 4), 16);
707
+ const b = parseInt(cleanHex.substring(4, 6), 16);
708
+ return `rgba(${r}, ${g}, ${b}, ${opacity})`;
709
+ }
710
+ // Easing functions for animations
711
+ const easingFunctions = {
712
+ 'linear': (t) => t,
713
+ 'ease-in': (t) => t * t,
714
+ 'ease-out': (t) => t * (2 - t),
715
+ 'ease-in-out': (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
716
+ 'ease-in-cubic': (t) => t * t * t,
717
+ 'ease-out-cubic': (t) => (--t) * t * t + 1,
718
+ 'ease-in-out-cubic': (t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
719
+ 'ease-in-quart': (t) => t * t * t * t,
720
+ 'ease-out-quart': (t) => 1 - (--t) * t * t * t,
721
+ 'ease-in-out-quart': (t) => t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t,
722
+ };
723
+ /**
724
+ * Parse animation classes and return computed styles
725
+ * Supports:
726
+ * - Transition animations: animate-fade-in/0/1, animate-slide-left/0.2/0.8
727
+ * - Loop animations: animate-pulse/10, animate-bounce/20
728
+ */
729
+ function parseAnimationClass(className, context, easing) {
730
+ const { progress = 0, frame = 0 } = context;
731
+ const easeFn = easingFunctions[easing] || easingFunctions['ease-out'];
732
+ // Match transition animations: animate-{type}/start/end
733
+ // e.g., animate-fade-in/0/1, animate-slide-left/0.2/0.8
734
+ const transitionMatch = className.match(/^animate-([\w-]+)\/(\d*\.?\d+)\/(\d*\.?\d+)$/);
735
+ if (transitionMatch) {
736
+ const [, type, startStr, endStr] = transitionMatch;
737
+ const start = parseFloat(startStr);
738
+ const end = parseFloat(endStr);
739
+ // Calculate local progress within this animation's window
740
+ let localProgress = 0;
741
+ if (progress <= start) {
742
+ localProgress = 0;
743
+ }
744
+ else if (progress >= end) {
745
+ localProgress = 1;
746
+ }
747
+ else {
748
+ localProgress = (progress - start) / (end - start);
749
+ }
750
+ // Apply easing
751
+ const easedProgress = easeFn(localProgress);
752
+ // Generate styles based on animation type
753
+ switch (type) {
754
+ case 'fade-in':
755
+ return { opacity: easedProgress };
756
+ case 'fade-out':
757
+ return { opacity: 1 - easedProgress };
758
+ case 'slide-left':
759
+ return { transform: `translateX(${(1 - easedProgress) * -100}px)`, opacity: easedProgress };
760
+ case 'slide-right':
761
+ return { transform: `translateX(${(1 - easedProgress) * 100}px)`, opacity: easedProgress };
762
+ case 'slide-up':
763
+ return { transform: `translateY(${(1 - easedProgress) * 100}px)`, opacity: easedProgress };
764
+ case 'slide-down':
765
+ return { transform: `translateY(${(1 - easedProgress) * -100}px)`, opacity: easedProgress };
766
+ case 'scale-in':
767
+ return { transform: `scale(${0.5 + easedProgress * 0.5})`, opacity: easedProgress };
768
+ case 'scale-out':
769
+ return { transform: `scale(${1 + easedProgress * 0.5})`, opacity: 1 - easedProgress };
770
+ case 'rotate-in':
771
+ return { transform: `rotate(${(1 - easedProgress) * -180}deg)`, opacity: easedProgress };
772
+ case 'rotate-out':
773
+ return { transform: `rotate(${easedProgress * 180}deg)`, opacity: 1 - easedProgress };
774
+ // Compound fade + direction animations (more intuitive naming)
775
+ case 'fade-in-up':
776
+ return { transform: `translateY(${(1 - easedProgress) * 30}px)`, opacity: easedProgress };
777
+ case 'fade-in-down':
778
+ return { transform: `translateY(${(1 - easedProgress) * -30}px)`, opacity: easedProgress };
779
+ case 'fade-in-left':
780
+ return { transform: `translateX(${(1 - easedProgress) * -30}px)`, opacity: easedProgress };
781
+ case 'fade-in-right':
782
+ return { transform: `translateX(${(1 - easedProgress) * 30}px)`, opacity: easedProgress };
783
+ case 'fade-out-up':
784
+ return { transform: `translateY(${easedProgress * -30}px)`, opacity: 1 - easedProgress };
785
+ case 'fade-out-down':
786
+ return { transform: `translateY(${easedProgress * 30}px)`, opacity: 1 - easedProgress };
787
+ case 'fade-out-left':
788
+ return { transform: `translateX(${easedProgress * -30}px)`, opacity: 1 - easedProgress };
789
+ case 'fade-out-right':
790
+ return { transform: `translateX(${easedProgress * 30}px)`, opacity: 1 - easedProgress };
791
+ // Bounce entrance animations - using smooth sine-based bounce
792
+ case 'bounce-in': {
793
+ // Scale from 0 to 1 with overshoot
794
+ const bounce = easedProgress < 0.7
795
+ ? easedProgress / 0.7 * 1.1
796
+ : 1.1 - Math.sin((easedProgress - 0.7) / 0.3 * Math.PI / 2) * 0.1;
797
+ return { transform: `scale(${bounce})`, opacity: Math.min(1, easedProgress * 2) };
798
+ }
799
+ case 'bounce-in-up': {
800
+ // Start from below (50px), overshoot above (-8px), settle at 0
801
+ const bounceY = easedProgress < 0.7
802
+ ? (1 - easedProgress / 0.7) * 50 - (easedProgress / 0.7) * 8
803
+ : -8 + (easedProgress - 0.7) / 0.3 * 8;
804
+ return { transform: `translateY(${bounceY}px)`, opacity: Math.min(1, easedProgress * 2) };
805
+ }
806
+ case 'bounce-in-down': {
807
+ // Start from above (-50px), overshoot below (8px), settle at 0
808
+ const bounceY = easedProgress < 0.7
809
+ ? (1 - easedProgress / 0.7) * -50 + (easedProgress / 0.7) * 8
810
+ : 8 - (easedProgress - 0.7) / 0.3 * 8;
811
+ return { transform: `translateY(${bounceY}px)`, opacity: Math.min(1, easedProgress * 2) };
812
+ }
813
+ case 'bounce-in-left': {
814
+ // Start from left (-50px), overshoot right (8px), settle at 0
815
+ const bounceX = easedProgress < 0.7
816
+ ? (1 - easedProgress / 0.7) * -50 + (easedProgress / 0.7) * 8
817
+ : 8 - (easedProgress - 0.7) / 0.3 * 8;
818
+ return { transform: `translateX(${bounceX}px)`, opacity: Math.min(1, easedProgress * 2) };
819
+ }
820
+ case 'bounce-in-right': {
821
+ // Start from right (50px), overshoot left (-8px), settle at 0
822
+ const bounceX = easedProgress < 0.7
823
+ ? (1 - easedProgress / 0.7) * 50 - (easedProgress / 0.7) * 8
824
+ : -8 + (easedProgress - 0.7) / 0.3 * 8;
825
+ return { transform: `translateX(${bounceX}px)`, opacity: Math.min(1, easedProgress * 2) };
826
+ }
827
+ // Zoom animations
828
+ case 'zoom-in':
829
+ return { transform: `scale(${easedProgress})`, opacity: easedProgress };
830
+ case 'zoom-out':
831
+ return { transform: `scale(${2 - easedProgress})`, opacity: 1 - easedProgress };
832
+ // Flip animations
833
+ case 'flip-in-x':
834
+ return { transform: `perspective(400px) rotateX(${(1 - easedProgress) * 90}deg)`, opacity: easedProgress };
835
+ case 'flip-in-y':
836
+ return { transform: `perspective(400px) rotateY(${(1 - easedProgress) * 90}deg)`, opacity: easedProgress };
837
+ default:
838
+ return null;
839
+ }
840
+ }
841
+ // Match loop animations: animate-{type}/{frameLength}
842
+ // e.g., animate-pulse/10, animate-bounce/20
843
+ const loopMatch = className.match(/^animate-([\w-]+)\/(\d+)$/);
844
+ if (loopMatch) {
845
+ const [, type, frameLengthStr] = loopMatch;
846
+ const frameLength = parseInt(frameLengthStr);
847
+ // Calculate position within loop (0-1)
848
+ const loopProgress = (frame % frameLength) / frameLength;
849
+ switch (type) {
850
+ case 'pulse':
851
+ // Sine wave for smooth pulsing (0.5 to 1 to 0.5)
852
+ const pulseValue = 0.5 + Math.sin(loopProgress * Math.PI * 2) * 0.5;
853
+ return { opacity: pulseValue };
854
+ case 'bounce':
855
+ // Bounce effect using absolute sine
856
+ const bounceY = Math.abs(Math.sin(loopProgress * Math.PI)) * -20;
857
+ return { transform: `translateY(${bounceY}px)` };
858
+ case 'spin':
859
+ // Full rotation
860
+ const spinAngle = loopProgress * 360;
861
+ return { transform: `rotate(${spinAngle}deg)` };
862
+ case 'ping':
863
+ // Scale up and fade out, then reset
864
+ const pingScale = 1 + loopProgress;
865
+ const pingOpacity = 1 - loopProgress;
866
+ return { transform: `scale(${pingScale})`, opacity: pingOpacity };
867
+ case 'wiggle':
868
+ // Side to side wiggle
869
+ const wiggleX = Math.sin(loopProgress * Math.PI * 4) * 5;
870
+ return { transform: `translateX(${wiggleX}px)` };
871
+ case 'float':
872
+ // Gentle up and down floating
873
+ const floatY = Math.sin(loopProgress * Math.PI * 2) * 10;
874
+ return { transform: `translateY(${floatY}px)` };
875
+ default:
876
+ return null;
877
+ }
878
+ }
879
+ return null;
880
+ }
881
+ export function tw(classes, tailwindConfig = null, dsgnConfig = null, animationContext = {}) {
882
+ const classArray = classes.split(' ').filter(Boolean);
883
+ let styles = {};
884
+ let gradientData = {};
885
+ let transforms = [];
886
+ let filters = [];
887
+ let opacityModifiers = {};
888
+ let animationEasing = 'ease-out'; // Default easing
889
+ for (const className of classArray) {
890
+ // Check for easing modifiers first
891
+ if (easingFunctions[className]) {
892
+ animationEasing = className;
893
+ continue;
894
+ }
895
+ // Check for animation classes
896
+ const animationResult = parseAnimationClass(className, animationContext, animationEasing);
897
+ if (animationResult) {
898
+ if (animationResult.opacity !== undefined) {
899
+ styles.opacity = animationResult.opacity;
900
+ }
901
+ if (animationResult.transform) {
902
+ transforms.push(animationResult.transform);
903
+ }
904
+ if (animationResult.transformOrigin) {
905
+ styles.transformOrigin = animationResult.transformOrigin;
906
+ }
907
+ continue;
908
+ }
909
+ const parsed = parseClass(className, tailwindConfig, dsgnConfig);
910
+ // Collect gradient markers
911
+ if (parsed.__gradientDirection) {
912
+ gradientData.direction = parsed.__gradientDirection;
913
+ }
914
+ else if (parsed.__gradientFrom) {
915
+ gradientData.from = parsed.__gradientFrom;
916
+ }
917
+ else if (parsed.__gradientVia) {
918
+ gradientData.via = parsed.__gradientVia;
919
+ }
920
+ else if (parsed.__gradientTo) {
921
+ gradientData.to = parsed.__gradientTo;
922
+ }
923
+ else if (parsed.transform) {
924
+ // Collect transforms to combine them later
925
+ transforms.push(parsed.transform);
926
+ }
927
+ else if (parsed.filter) {
928
+ // Collect filters to combine them later
929
+ filters.push(parsed.filter);
930
+ }
931
+ else if (parsed.__bgOpacity !== undefined) {
932
+ opacityModifiers.bg = parsed.__bgOpacity;
933
+ }
934
+ else if (parsed.__textOpacity !== undefined) {
935
+ opacityModifiers.text = parsed.__textOpacity;
936
+ }
937
+ else if (parsed.__borderOpacity !== undefined) {
938
+ opacityModifiers.border = parsed.__borderOpacity;
939
+ }
940
+ else {
941
+ styles = { ...styles, ...parsed };
942
+ }
943
+ }
944
+ // Convert gradient data to backgroundImage if we have enough info
945
+ if (gradientData.direction && (gradientData.from || gradientData.to)) {
946
+ const directionMap = {
947
+ 'bg-gradient-to-t': 'to top',
948
+ 'bg-gradient-to-b': 'to bottom',
949
+ 'bg-gradient-to-l': 'to left',
950
+ 'bg-gradient-to-r': 'to right',
951
+ 'bg-gradient-to-tr': 'to top right',
952
+ 'bg-gradient-to-tl': 'to top left',
953
+ 'bg-gradient-to-br': 'to bottom right',
954
+ 'bg-gradient-to-bl': 'to bottom left',
955
+ };
956
+ const direction = directionMap[gradientData.direction] || 'to bottom';
957
+ const stops = [];
958
+ if (gradientData.from)
959
+ stops.push(gradientData.from);
960
+ if (gradientData.via)
961
+ stops.push(gradientData.via);
962
+ if (gradientData.to)
963
+ stops.push(gradientData.to);
964
+ // Build the linear-gradient
965
+ const gradient = `linear-gradient(${direction}, ${stops.join(', ')})`;
966
+ styles.backgroundImage = gradient;
967
+ }
968
+ // Combine multiple transforms
969
+ if (transforms.length > 0) {
970
+ styles.transform = transforms.join(' ');
971
+ }
972
+ // Combine multiple filters
973
+ if (filters.length > 0) {
974
+ styles.filter = filters.join(' ');
975
+ }
976
+ // Apply opacity modifiers
977
+ if (opacityModifiers.bg !== undefined && styles.background && typeof styles.background === 'string') {
978
+ if (styles.background.startsWith('#')) {
979
+ styles.background = hexToRgba(styles.background, opacityModifiers.bg);
980
+ }
981
+ }
982
+ if (opacityModifiers.text !== undefined && styles.color && typeof styles.color === 'string') {
983
+ if (styles.color.startsWith('#')) {
984
+ styles.color = hexToRgba(styles.color, opacityModifiers.text);
985
+ }
986
+ }
987
+ if (opacityModifiers.border !== undefined && styles.borderColor && typeof styles.borderColor === 'string') {
988
+ if (styles.borderColor.startsWith('#')) {
989
+ styles.borderColor = hexToRgba(styles.borderColor, opacityModifiers.border);
990
+ }
991
+ }
992
+ return styles;
993
+ }
994
+ //# sourceMappingURL=tailwind.js.map