@bookklik/senangstart-css 0.2.3 → 0.2.5

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 (135) hide show
  1. package/dist/senangstart-css.js +100 -6
  2. package/dist/senangstart-css.min.js +26 -22
  3. package/dist/senangstart-tw.js +537 -0
  4. package/dist/senangstart-tw.min.js +2 -0
  5. package/docs/.vitepress/config.js +6 -0
  6. package/docs/guide/cdn.md +1 -1
  7. package/docs/ms/guide/cdn.md +1 -1
  8. package/docs/ms/reference/layout/position.md +4 -4
  9. package/docs/ms/reference/layout/z-index.md +8 -8
  10. package/docs/ms/reference/space/gap.md +1 -1
  11. package/docs/ms/reference/space/height.md +1 -1
  12. package/docs/ms/reference/space/margin.md +1 -1
  13. package/docs/ms/reference/space/padding.md +1 -1
  14. package/docs/ms/reference/space/scale-reference.md +46 -17
  15. package/docs/ms/reference/space/width.md +1 -1
  16. package/docs/ms/reference/space.md +1 -1
  17. package/docs/ms/reference/spacing.md +103 -21
  18. package/docs/ms/reference/visual/animation-fill.md +8 -8
  19. package/docs/ms/reference/visual/backdrop-blur.md +4 -4
  20. package/docs/ms/reference/visual/backdrop-brightness.md +8 -8
  21. package/docs/ms/reference/visual/backdrop-grayscale.md +6 -6
  22. package/docs/ms/reference/visual/backdrop-sepia.md +6 -6
  23. package/docs/ms/reference/visual/background-clip.md +2 -2
  24. package/docs/ms/reference/visual/background-image.md +4 -4
  25. package/docs/ms/reference/visual/filter-brightness.md +4 -4
  26. package/docs/ms/reference/visual/filter-contrast.md +4 -4
  27. package/docs/ms/reference/visual/filter-drop-shadow.md +6 -6
  28. package/docs/ms/reference/visual/filter-grayscale.md +4 -4
  29. package/docs/ms/reference/visual/filter-hue-rotate.md +4 -4
  30. package/docs/ms/reference/visual/filter-invert.md +2 -2
  31. package/docs/ms/reference/visual/filter-saturate.md +4 -4
  32. package/docs/ms/reference/visual/filter-sepia.md +4 -4
  33. package/docs/ms/reference/visual/font-family.md +2 -2
  34. package/docs/ms/reference/visual/gradient-from.md +57 -0
  35. package/docs/ms/reference/visual/gradient-to.md +57 -0
  36. package/docs/ms/reference/visual/gradient-via.md +54 -0
  37. package/docs/ms/reference/visual/letter-spacing.md +2 -2
  38. package/docs/ms/reference/visual/line-clamp.md +2 -2
  39. package/docs/ms/reference/visual/line-height.md +2 -2
  40. package/docs/ms/reference/visual/outline.md +2 -2
  41. package/docs/ms/reference/visual/ring-color.md +29 -0
  42. package/docs/ms/reference/visual/ring-offset.md +30 -0
  43. package/docs/ms/reference/visual/ring.md +62 -0
  44. package/docs/ms/reference/visual/stroke-width.md +6 -6
  45. package/docs/ms/reference/visual/stroke.md +4 -4
  46. package/docs/ms/reference/visual/text-indent.md +2 -2
  47. package/docs/ms/reference/visual/text-overflow.md +2 -2
  48. package/docs/ms/reference/visual/text-size.md +84 -84
  49. package/docs/ms/reference/visual/text-wrap.md +2 -2
  50. package/docs/ms/reference/visual/transform-backface.md +4 -4
  51. package/docs/ms/reference/visual/transform-perspective-origin.md +6 -6
  52. package/docs/ms/reference/visual/transform-perspective.md +6 -6
  53. package/docs/ms/reference/visual/transform-rotate-3d.md +6 -6
  54. package/docs/ms/reference/visual/transform-style.md +4 -4
  55. package/docs/ms/reference/visual/transform-translate-z.md +6 -6
  56. package/docs/ms/reference/visual/transform-translate.md +2 -2
  57. package/docs/ms/reference/visual/whitespace.md +2 -2
  58. package/docs/ms/reference/visual/word-break.md +2 -2
  59. package/docs/public/assets/senangstart-css.min.js +213 -1545
  60. package/docs/public/llms.txt +1718 -0
  61. package/docs/reference/layout/position.md +4 -4
  62. package/docs/reference/layout/z-index.md +8 -8
  63. package/docs/reference/space/gap.md +1 -1
  64. package/docs/reference/space/height.md +1 -1
  65. package/docs/reference/space/margin.md +1 -1
  66. package/docs/reference/space/padding.md +1 -1
  67. package/docs/reference/space/scale-reference.md +46 -17
  68. package/docs/reference/space/width.md +1 -1
  69. package/docs/reference/space.md +1 -1
  70. package/docs/reference/spacing.md +103 -21
  71. package/docs/reference/visual/animation-fill.md +8 -8
  72. package/docs/reference/visual/backdrop-blur.md +4 -4
  73. package/docs/reference/visual/backdrop-brightness.md +8 -8
  74. package/docs/reference/visual/backdrop-grayscale.md +6 -6
  75. package/docs/reference/visual/backdrop-sepia.md +6 -6
  76. package/docs/reference/visual/background-clip.md +2 -2
  77. package/docs/reference/visual/background-image.md +4 -4
  78. package/docs/reference/visual/filter-brightness.md +4 -4
  79. package/docs/reference/visual/filter-contrast.md +4 -4
  80. package/docs/reference/visual/filter-drop-shadow.md +6 -6
  81. package/docs/reference/visual/filter-grayscale.md +4 -4
  82. package/docs/reference/visual/filter-hue-rotate.md +4 -4
  83. package/docs/reference/visual/filter-invert.md +2 -2
  84. package/docs/reference/visual/filter-saturate.md +4 -4
  85. package/docs/reference/visual/filter-sepia.md +4 -4
  86. package/docs/reference/visual/font-family.md +2 -2
  87. package/docs/reference/visual/gradient-from.md +57 -0
  88. package/docs/reference/visual/gradient-to.md +57 -0
  89. package/docs/reference/visual/gradient-via.md +54 -0
  90. package/docs/reference/visual/letter-spacing.md +2 -2
  91. package/docs/reference/visual/line-clamp.md +2 -2
  92. package/docs/reference/visual/line-height.md +2 -2
  93. package/docs/reference/visual/outline.md +2 -2
  94. package/docs/reference/visual/ring-color.md +29 -0
  95. package/docs/reference/visual/ring-offset.md +30 -0
  96. package/docs/reference/visual/ring.md +62 -0
  97. package/docs/reference/visual/stroke-width.md +6 -6
  98. package/docs/reference/visual/stroke.md +4 -4
  99. package/docs/reference/visual/text-indent.md +2 -2
  100. package/docs/reference/visual/text-overflow.md +2 -2
  101. package/docs/reference/visual/text-size.md +84 -84
  102. package/docs/reference/visual/text-wrap.md +2 -2
  103. package/docs/reference/visual/transform-backface.md +4 -4
  104. package/docs/reference/visual/transform-perspective-origin.md +6 -6
  105. package/docs/reference/visual/transform-perspective.md +6 -6
  106. package/docs/reference/visual/transform-rotate-3d.md +6 -6
  107. package/docs/reference/visual/transform-style.md +4 -4
  108. package/docs/reference/visual/transform-translate-z.md +6 -6
  109. package/docs/reference/visual/transform-translate.md +2 -2
  110. package/docs/reference/visual/whitespace.md +2 -2
  111. package/docs/reference/visual/word-break.md +2 -2
  112. package/package.json +4 -2
  113. package/playground/tw-convertor.html +103 -589
  114. package/scripts/build-dist.js +45 -3
  115. package/scripts/bundle-jit.js +3 -3
  116. package/scripts/convert-tailwind.js +180 -1
  117. package/scripts/generate-llms-txt.js +264 -0
  118. package/src/cdn/{jit.js → senangstart-engine.js} +97 -8
  119. package/src/cdn/tw-conversion-engine.js +632 -0
  120. package/src/compiler/generators/css.js +27 -0
  121. package/src/config/defaults.js +37 -11
  122. package/src/core/constants.js +37 -8
  123. package/src/definitions/layout-positioning.js +6 -6
  124. package/src/definitions/space.js +46 -5
  125. package/src/definitions/visual-backgrounds.js +113 -15
  126. package/src/definitions/visual-borders.js +81 -2
  127. package/src/definitions/visual-filters.js +16 -16
  128. package/src/definitions/visual-svg.js +5 -5
  129. package/src/definitions/visual-transform3d.js +16 -16
  130. package/src/definitions/visual-transforms.js +1 -1
  131. package/src/definitions/visual-transitions.js +4 -4
  132. package/src/definitions/visual-typography.js +6 -6
  133. package/src/definitions/visual.js +4 -4
  134. package/tests/unit/compiler/generators/css.test.js +192 -0
  135. package/tests/unit/convert-tailwind.test.js +8 -0
@@ -0,0 +1,632 @@
1
+ /**
2
+ * SenangStart CSS - Tailwind to SenangStart Conversion Engine
3
+ * Converts Tailwind CSS class syntax to SenangStart CSS attribute syntax
4
+ */
5
+
6
+ // ============================
7
+ // MAPPING SCALES
8
+ // ============================
9
+
10
+ // Spacing scale mapping Tailwind values to SenangStart semantic values
11
+ // Engine native values: none(0px), thin(1px), regular(2px), thick(3px), tiny(4px), tiny-2x(6px),
12
+ // small(8px), small-2x(10px), small-3x(12px), small-4x(14px),
13
+ // medium(16px), medium-2x(20px), medium-3x(24px), medium-4x(28px),
14
+ // large(32px), large-2x(36px), large-3x(40px), large-4x(44px),
15
+ // big(48px), big-2x(56px), big-3x(64px), big-4x(80px),
16
+ // giant(96px), giant-2x(112px), giant-3x(128px), giant-4x(144px),
17
+ // vast(160px), vast-2x(176px), vast-3x(192px), vast-4x(208px),
18
+ // vast-5x(224px), vast-6x(240px), vast-7x(256px), vast-8x(288px),
19
+ // vast-9x(320px), vast-10x(384px)
20
+ // Tailwind base: 4px per unit (1 = 0.25rem = 4px)
21
+ const spacingScale = {
22
+ 0: "none", // 0px → none
23
+ px: "thin", // 1px → thin
24
+ 0.5: "regular", // 2px → regular
25
+ 1: "tiny", // 4px → tiny
26
+ 1.5: "tiny-2x", // 6px → tiny-2x
27
+ 2: "small", // 8px → small
28
+ 2.5: "small-2x", // 10px → small-2x
29
+ 3: "small-3x", // 12px → small-3x
30
+ 3.5: "small-4x", // 14px → small-4x
31
+ 4: "medium", // 16px → medium
32
+ 5: "medium-2x", // 20px → medium-2x
33
+ 6: "medium-3x", // 24px → medium-3x
34
+ 7: "medium-4x", // 28px → medium-4x
35
+ 8: "large", // 32px → large
36
+ 9: "large-2x", // 36px → large-2x
37
+ 10: "large-3x", // 40px → large-3x
38
+ 11: "large-4x", // 44px → large-4x
39
+ 12: "big", // 48px → big
40
+ 14: "big-2x", // 56px → big-2x
41
+ 16: "big-3x", // 64px → big-3x
42
+ 20: "big-4x", // 80px → big-4x
43
+ 24: "giant", // 96px → giant
44
+ 28: "giant-2x", // 112px → giant-2x
45
+ 32: "giant-3x", // 128px → giant-3x
46
+ 36: "giant-4x", // 144px → giant-4x
47
+ 40: "vast", // 160px → vast
48
+ 44: "vast-2x", // 176px → vast-2x
49
+ 48: "vast-3x", // 192px → vast-3x
50
+ 52: "vast-4x", // 208px → vast-4x
51
+ 56: "vast-5x", // 224px → vast-5x
52
+ 60: "vast-6x", // 240px → vast-6x
53
+ 64: "vast-7x", // 256px → vast-7x
54
+ 72: "vast-8x", // 288px → vast-8x
55
+ 80: "vast-9x", // 320px → vast-9x
56
+ 96: "vast-10x", // 384px → vast-10x
57
+ full: "[100%]",
58
+ screen: "[100vw]",
59
+ auto: "auto",
60
+ };
61
+
62
+ // Radius scale mapping Tailwind values to SenangStart semantic values
63
+ // Engine native values: none(0px), small(4px), medium(8px), big(16px), round(9999px)
64
+ // Tailwind: none(0), sm(0.125rem=2px), DEFAULT(0.25rem=4px), md(0.375rem=6px),
65
+ // lg(0.5rem=8px), xl(0.75rem=12px), 2xl(1rem=16px), 3xl(1.5rem=24px), full(9999px)
66
+ const radiusScale = {
67
+ none: "none", // 0px → none
68
+ sm: "small", // 2px → small (closest to 4px)
69
+ "": "small", // 4px → small (Tailwind DEFAULT)
70
+ md: "small", // 6px → small (closest to 4px)
71
+ lg: "medium", // 8px → medium
72
+ xl: "medium", // 12px → medium (closest to 8px)
73
+ "2xl": "big", // 16px → big
74
+ "3xl": "big", // 24px → big (closest to 16px)
75
+ full: "round", // 9999px → round
76
+ };
77
+
78
+ // Shadow scale mapping Tailwind values to SenangStart semantic values
79
+ // Engine native values: none, small, medium, big, giant
80
+ const shadowScale = {
81
+ none: "none", // none → none
82
+ sm: "small", // small shadow → small
83
+ "": "small", // DEFAULT shadow → small
84
+ md: "medium", // medium shadow → medium
85
+ lg: "big", // large shadow → big
86
+ xl: "giant", // xl shadow → giant
87
+ "2xl": "giant", // 2xl shadow → giant
88
+ inner: "none", // inner shadow not directly supported
89
+ };
90
+
91
+ // Font size scale mapping Tailwind values to SenangStart semantic values
92
+ // Engine native values: mini(0.75rem), small(0.875rem), base(1rem), large(1.125rem),
93
+ // big(1.25rem), huge(1.5rem), grand(1.875rem), giant(2.25rem),
94
+ // mount(3rem), mega(3.75rem), giga(4.5rem), tera(6rem), hero(8rem)
95
+ const fontSizeScale = {
96
+ xs: "mini", // 0.75rem → mini
97
+ sm: "small", // 0.875rem → small
98
+ base: "base", // 1rem → base
99
+ lg: "large", // 1.125rem → large
100
+ xl: "big", // 1.25rem → big
101
+ "2xl": "huge", // 1.5rem → huge
102
+ "3xl": "grand", // 1.875rem → grand
103
+ "4xl": "giant", // 2.25rem → giant
104
+ "5xl": "mount", // 3rem → mount
105
+ "6xl": "mega", // 3.75rem → mega
106
+ "7xl": "giga", // 4.5rem → giga
107
+ "8xl": "tera", // 6rem → tera
108
+ "9xl": "hero", // 8rem → hero
109
+ };
110
+
111
+ const layoutMappings = {
112
+ container: "container",
113
+ flex: "flex",
114
+ "inline-flex": "inline-flex",
115
+ grid: "grid",
116
+ "inline-grid": "inline-grid",
117
+ block: "block",
118
+ "inline-block": "inline",
119
+ hidden: "hidden",
120
+ "flex-row": "row",
121
+ "flex-col": "col",
122
+ "flex-row-reverse": "row-reverse",
123
+ "flex-col-reverse": "col-reverse",
124
+ "flex-wrap": "wrap",
125
+ "flex-nowrap": "nowrap",
126
+ "flex-wrap-reverse": "wrap-reverse",
127
+ "flex-grow": "grow",
128
+ "flex-grow-0": "grow-0",
129
+ grow: "grow",
130
+ "grow-0": "grow-0",
131
+ "flex-shrink": "shrink",
132
+ "flex-shrink-0": "shrink-0",
133
+ shrink: "shrink",
134
+ "shrink-0": "shrink-0",
135
+ "flex-1": "flex:1",
136
+ "flex-auto": "flex:auto",
137
+ "flex-initial": "flex:initial",
138
+ "flex-none": "flex:none",
139
+ "justify-start": "justify:start",
140
+ "justify-end": "justify:end",
141
+ "justify-center": "justify:center",
142
+ "justify-between": "justify:between",
143
+ "justify-around": "justify:around",
144
+ "justify-evenly": "justify:evenly",
145
+ "items-start": "items:start",
146
+ "items-end": "items:end",
147
+ "items-center": "items:center",
148
+ "items-baseline": "items:baseline",
149
+ "items-stretch": "items:stretch",
150
+ "self-auto": "self:auto",
151
+ "self-start": "self:start",
152
+ "self-end": "self:end",
153
+ "self-center": "self:center",
154
+ "self-stretch": "self:stretch",
155
+ relative: "relative",
156
+ absolute: "absolute",
157
+ fixed: "fixed",
158
+ sticky: "sticky",
159
+ static: "static",
160
+ "overflow-auto": "overflow:auto",
161
+ "overflow-hidden": "overflow:hidden",
162
+ "overflow-visible": "overflow:visible",
163
+ "overflow-scroll": "overflow:scroll",
164
+ "object-contain": "object:contain",
165
+ "object-cover": "object:cover",
166
+ "object-fill": "object:fill",
167
+ "object-none": "object:none",
168
+ "object-scale-down": "object:scale-down",
169
+ };
170
+
171
+ const visualKeywords = {
172
+ italic: "italic",
173
+ "not-italic": "not-italic",
174
+ antialiased: "antialiased",
175
+ uppercase: "uppercase",
176
+ lowercase: "lowercase",
177
+ capitalize: "capitalize",
178
+ "normal-case": "normal-case",
179
+ underline: "underline",
180
+ "line-through": "line-through",
181
+ "no-underline": "no-underline",
182
+ truncate: "truncate",
183
+ "cursor-pointer": "cursor:pointer",
184
+ "cursor-default": "cursor:default",
185
+ "cursor-not-allowed": "cursor:not-allowed",
186
+ "select-none": "select:none",
187
+ "select-text": "select:text",
188
+ "select-all": "select:all",
189
+ };
190
+
191
+ // ============================
192
+ // HELPER FUNCTIONS
193
+ // ============================
194
+
195
+ function getSpacing(value, exact) {
196
+ // Check if it's already an arbitrary value with brackets
197
+ if (value.startsWith('[') && value.endsWith(']')) {
198
+ return value; // Return as-is, don't double-wrap
199
+ }
200
+ if (exact) {
201
+ if (["full", "screen", "auto"].includes(value))
202
+ return spacingScale[value] || `[${value}]`;
203
+ return `tw-${value}`;
204
+ }
205
+ return spacingScale[value] || `[${value}]`;
206
+ }
207
+
208
+ // Border width scale mapping Tailwind values to SenangStart semantic values
209
+ // Engine native values: none(0), thin(1px), regular(2px), thick(3px)
210
+ const borderWidthScale = {
211
+ 0: "none",
212
+ 1: "thin", // 1px → thin (was [1px])
213
+ 2: "regular", // 2px → regular
214
+ 3: "thick", // 3px → thick
215
+ 4: "tiny", // 4px → tiny
216
+ 8: "small", // 8px → small
217
+ };
218
+
219
+ function getBorderWidth(value, exact) {
220
+ if (exact) {
221
+ return `tw-${value}`;
222
+ }
223
+ return borderWidthScale[value] || `[${value}px]`;
224
+ }
225
+
226
+ // ============================
227
+ // CONVERSION FUNCTIONS
228
+ // ============================
229
+
230
+ function convertClass(twClass, exact) {
231
+ // Handle prefixes (hover:, sm:, md:, etc.)
232
+ const prefixMatch = twClass.match(
233
+ /^(sm:|md:|lg:|xl:|2xl:|hover:|focus:|focus-visible:|active:|disabled:|dark:)(.+)$/
234
+ );
235
+ let prefix = "",
236
+ baseClass = twClass;
237
+ if (prefixMatch) {
238
+ const rawPrefix = prefixMatch[1].slice(0, -1); // remove colon
239
+ if (['sm', 'md', 'lg', 'xl', '2xl'].includes(rawPrefix)) {
240
+ prefix = `tw-${rawPrefix}:`;
241
+ } else {
242
+ prefix = prefixMatch[1];
243
+ }
244
+ baseClass = prefixMatch[2];
245
+ }
246
+
247
+ // Layout mappings
248
+ if (layoutMappings[baseClass])
249
+ return { cat: "layout", val: prefix + layoutMappings[baseClass] };
250
+
251
+ // Visual keywords
252
+ if (visualKeywords[baseClass])
253
+ return { cat: "visual", val: prefix + visualKeywords[baseClass] };
254
+
255
+ // Text color
256
+ const textColorMatch = baseClass.match(
257
+ /^text-((?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose|white|black)(?:-\d+)?)$/
258
+ );
259
+ if (textColorMatch)
260
+ return { cat: "visual", val: prefix + "text:" + textColorMatch[1] };
261
+
262
+ // Text alignment
263
+ if (
264
+ ["text-left", "text-center", "text-right", "text-justify"].includes(
265
+ baseClass
266
+ )
267
+ )
268
+ return {
269
+ cat: "visual",
270
+ val: prefix + "text:" + baseClass.replace("text-", ""),
271
+ };
272
+
273
+ // Text size
274
+ const textSizeMatch = baseClass.match(
275
+ /^text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl)$/
276
+ );
277
+ if (textSizeMatch) {
278
+ const size = exact
279
+ ? `tw-${textSizeMatch[1]}`
280
+ : fontSizeScale[textSizeMatch[1]] || textSizeMatch[1];
281
+ return { cat: "visual", val: prefix + "text-size:" + size };
282
+ }
283
+
284
+ // Background color
285
+ const bgMatch = baseClass.match(
286
+ /^bg-((?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose|white|black)(?:-\d+)?|transparent|current|inherit)$/
287
+ );
288
+ if (bgMatch) {
289
+ const colorVal = bgMatch[1];
290
+ // Handle special values
291
+ if (colorVal === 'transparent') {
292
+ return { cat: "visual", val: prefix + "bg:[transparent]" };
293
+ }
294
+ if (colorVal === 'current') {
295
+ return { cat: "visual", val: prefix + "bg:[currentColor]" };
296
+ }
297
+ if (colorVal === 'inherit') {
298
+ return { cat: "visual", val: prefix + "bg:[inherit]" };
299
+ }
300
+ return { cat: "visual", val: prefix + "bg:" + colorVal };
301
+ }
302
+
303
+ // Border color
304
+ const borderColorMatch = baseClass.match(
305
+ /^border-((?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose|white|black)(?:-\d+)?)$/
306
+ );
307
+ if (borderColorMatch)
308
+ return {
309
+ cat: "visual",
310
+ val: prefix + "border:" + borderColorMatch[1],
311
+ };
312
+
313
+ // Padding
314
+ const paddingMatch = baseClass.match(/^p([trblxy])?-(.+)$/);
315
+ if (paddingMatch) {
316
+ const side = paddingMatch[1] ? "-" + paddingMatch[1] : "";
317
+ return {
318
+ cat: "space",
319
+ val: prefix + "p" + side + ":" + getSpacing(paddingMatch[2], exact),
320
+ };
321
+ }
322
+
323
+ // Margin
324
+ const marginMatch = baseClass.match(
325
+ /^-?m([trblxy])?-(\d+\.?\d*|px|auto|full|screen)$/
326
+ );
327
+ if (marginMatch) {
328
+ const isNeg = baseClass.startsWith("-");
329
+ const side = marginMatch[1] ? "-" + marginMatch[1] : "";
330
+ let val = getSpacing(marginMatch[2], exact);
331
+ if (isNeg) val = "[-" + val + "]";
332
+ return { cat: "space", val: prefix + "m" + side + ":" + val };
333
+ }
334
+
335
+ // Gap
336
+ const gapMatch = baseClass.match(/^gap-([xy])?-?(.+)$/);
337
+ if (gapMatch) {
338
+ const axis = gapMatch[1] ? "-" + gapMatch[1] : "";
339
+ return {
340
+ cat: "space",
341
+ val: prefix + "g" + axis + ":" + getSpacing(gapMatch[2], exact),
342
+ };
343
+ }
344
+
345
+ // Width/Height with special values
346
+ const widthMatch = baseClass.match(/^(min-w|max-w|w)-(.+)$/);
347
+ if (widthMatch) {
348
+ const prop = widthMatch[1];
349
+ const rawVal = widthMatch[2];
350
+ // Special width values
351
+ const specialWidthVals = { 'max': '[max-content]', 'min': '[min-content]', 'fit': '[fit-content]', 'prose': '[65ch]' };
352
+ const val = specialWidthVals[rawVal] || getSpacing(rawVal, exact);
353
+ return { cat: "space", val: prefix + prop + ":" + val };
354
+ }
355
+ const heightMatch = baseClass.match(/^(min-h|max-h|h)-(.+)$/);
356
+ if (heightMatch) {
357
+ const prop = heightMatch[1];
358
+ const rawVal = heightMatch[2];
359
+ const specialHeightVals = { 'screen': '[100vh]', 'svh': '[100svh]', 'lvh': '[100lvh]', 'dvh': '[100dvh]', 'max': '[max-content]', 'min': '[min-content]', 'fit': '[fit-content]' };
360
+ const val = specialHeightVals[rawVal] || getSpacing(rawVal, exact);
361
+ return { cat: "space", val: prefix + prop + ":" + val };
362
+ }
363
+
364
+ // Border radius
365
+ const roundedMatch = baseClass.match(/^rounded(?:-(.+))?$/);
366
+ if (roundedMatch) {
367
+ const size = roundedMatch[1] || "";
368
+ const scale = exact
369
+ ? size === ""
370
+ ? "tw-DEFAULT"
371
+ : `tw-${size}`
372
+ : radiusScale[size] || "medium";
373
+ return { cat: "visual", val: prefix + "rounded:" + scale };
374
+ }
375
+
376
+ // Shadow
377
+ const shadowMatch = baseClass.match(/^shadow(?:-(.+))?$/);
378
+ if (shadowMatch) {
379
+ const size = shadowMatch[1] || "";
380
+ const scale = exact
381
+ ? size === ""
382
+ ? "tw-DEFAULT"
383
+ : `tw-${size}`
384
+ : shadowScale[size] || "medium";
385
+ return { cat: "visual", val: prefix + "shadow:" + scale };
386
+ }
387
+
388
+ // Font weight
389
+ const fontWeightMatch = baseClass.match(
390
+ /^font-(thin|extralight|light|normal|medium|semibold|bold|extrabold|black)$/
391
+ );
392
+ if (fontWeightMatch)
393
+ return { cat: "visual", val: prefix + "font:tw-" + fontWeightMatch[1] };
394
+
395
+ // Border width
396
+ const borderWidthMatch = baseClass.match(
397
+ /^border(?:-([trblxy]))?(?:-(\d+))?$/
398
+ );
399
+ if (
400
+ borderWidthMatch &&
401
+ (borderWidthMatch[2] ||
402
+ (!borderWidthMatch[1] && baseClass === "border"))
403
+ ) {
404
+ const side = borderWidthMatch[1]
405
+ ? "-" + borderWidthMatch[1] + "-w"
406
+ : "-w";
407
+ const width = borderWidthMatch[2] || "1";
408
+ return {
409
+ cat: "visual",
410
+ val: prefix + "border" + side + ":" + getBorderWidth(width, exact),
411
+ };
412
+ }
413
+
414
+ // Positional properties (top-0, right-0, bottom-0, left-0, inset-0, etc.)
415
+ const positionMatch = baseClass.match(/^(top|right|bottom|left|inset|inset-x|inset-y)-(\d+|px|auto|full|\[.+\])$/);
416
+ if (positionMatch) {
417
+ const prop = positionMatch[1];
418
+ let val = positionMatch[2];
419
+ // Handle 0 specially
420
+ if (val === '0') {
421
+ val = 'none';
422
+ } else if (val.startsWith('[') && val.endsWith(']')) {
423
+ // Keep arbitrary values as-is
424
+ } else {
425
+ val = getSpacing(val, exact);
426
+ }
427
+ return { cat: "layout", val: prefix + prop + ":" + val };
428
+ }
429
+
430
+ // Outline none
431
+ if (baseClass === 'outline-none') {
432
+ return { cat: "visual", val: prefix + "outline:none" };
433
+ }
434
+
435
+ // Order
436
+ const orderMatch = baseClass.match(/^order-(\d+|first|last|none)$/);
437
+ if (orderMatch) {
438
+ return { cat: "layout", val: prefix + "order:" + orderMatch[1] };
439
+ }
440
+
441
+ // Grid columns
442
+ const gridColsMatch = baseClass.match(/^grid-cols-(\d+|none)$/);
443
+ if (gridColsMatch) {
444
+ return { cat: "layout", val: prefix + "grid-cols:" + gridColsMatch[1] };
445
+ }
446
+
447
+ // Column span
448
+ const colSpanMatch = baseClass.match(/^col-span-(\d+|full)$/);
449
+ if (colSpanMatch) {
450
+ return { cat: "layout", val: prefix + "col-span:" + colSpanMatch[1] };
451
+ }
452
+
453
+ // Grid rows
454
+ const gridRowsMatch = baseClass.match(/^grid-rows-(\d+|none)$/);
455
+ if (gridRowsMatch) {
456
+ return { cat: "layout", val: prefix + "grid-rows:" + gridRowsMatch[1] };
457
+ }
458
+
459
+ // Row span
460
+ const rowSpanMatch = baseClass.match(/^row-span-(\d+|full)$/);
461
+ if (rowSpanMatch) {
462
+ return { cat: "layout", val: prefix + "row-span:" + rowSpanMatch[1] };
463
+ }
464
+
465
+ // Opacity
466
+ const opacityMatch = baseClass.match(/^opacity-(\d+)$/);
467
+ if (opacityMatch) {
468
+ return { cat: "visual", val: prefix + "opacity:" + opacityMatch[1] };
469
+ }
470
+
471
+ // Gradient direction (bg-gradient-to-*)
472
+ const bgGradientMatch = baseClass.match(/^bg-gradient-to-(t|tr|r|br|b|bl|l|tl)$/);
473
+ if (bgGradientMatch) {
474
+ return { cat: "visual", val: prefix + "bg-image:gradient-to-" + bgGradientMatch[1] };
475
+ }
476
+
477
+ // Gradient from-* (starting color)
478
+ const fromMatch = baseClass.match(/^from-(.+)$/);
479
+ if (fromMatch) {
480
+ return { cat: "visual", val: prefix + "from:" + fromMatch[1] };
481
+ }
482
+
483
+ // Gradient via-* (middle color)
484
+ const viaMatch = baseClass.match(/^via-(.+)$/);
485
+ if (viaMatch) {
486
+ return { cat: "visual", val: prefix + "via:" + viaMatch[1] };
487
+ }
488
+
489
+ // Gradient to-* (ending color) - Note: must come after bg-gradient-to-*
490
+ const toMatch = baseClass.match(/^to-(.+)$/);
491
+ if (toMatch) {
492
+ return { cat: "visual", val: prefix + "to:" + toMatch[1] };
493
+ }
494
+
495
+ // Transition utilities
496
+ const transitionMatch = baseClass.match(/^transition(?:-(all|colors|opacity|shadow|transform|none))?$/);
497
+ if (transitionMatch) {
498
+ const type = transitionMatch[1] || 'all';
499
+ return { cat: "visual", val: prefix + "transition:" + type };
500
+ }
501
+
502
+ // Duration utilities
503
+ const durationMatch = baseClass.match(/^duration-(\d+)$/);
504
+ if (durationMatch) {
505
+ // Map Tailwind duration (ms) to SenangStart semantic values
506
+ const ms = parseInt(durationMatch[1]);
507
+ let durationVal;
508
+ if (ms <= 75) durationVal = 'instant';
509
+ else if (ms <= 100) durationVal = 'quick';
510
+ else if (ms <= 150) durationVal = 'fast';
511
+ else if (ms <= 200) durationVal = 'normal';
512
+ else if (ms <= 300) durationVal = 'slow';
513
+ else if (ms <= 500) durationVal = 'slower';
514
+ else durationVal = 'lazy';
515
+ return { cat: "visual", val: prefix + "duration:" + durationVal };
516
+ }
517
+
518
+ // Ease utilities
519
+ const easeMatch = baseClass.match(/^ease-(linear|in|out|in-out)$/);
520
+ if (easeMatch) {
521
+ return { cat: "visual", val: prefix + "ease:" + easeMatch[1] };
522
+ }
523
+
524
+ // Ring utilities - Convert to native ring utilities
525
+ // Tailwind ring-4 generates: box-shadow: 0 0 0 4px var(--tw-ring-color)
526
+ const ringMatch = baseClass.match(/^ring(?:-(\d+))?$/);
527
+ if (ringMatch) {
528
+ const width = ringMatch[1] || '3';
529
+ if (width === '0') {
530
+ return { cat: "visual", val: prefix + "ring:none" };
531
+ }
532
+ // Map Tailwind ring widths to SenangStart semantic values
533
+ const ringScale = {
534
+ '1': 'thin', '2': 'regular', '3': 'small', '4': 'medium', '8': 'big'
535
+ };
536
+ const scale = ringScale[width] || `[${width}px]`;
537
+ return { cat: "visual", val: prefix + "ring:" + scale };
538
+ }
539
+
540
+ // Ring offset - converts to native ring-offset utility
541
+ const ringOffsetMatch = baseClass.match(/^ring-offset-(\d+)$/);
542
+ if (ringOffsetMatch) {
543
+ return { cat: "visual", val: prefix + "ring-offset:" + ringOffsetMatch[1] };
544
+ }
545
+
546
+ // Ring color - converts to native ring-color utility
547
+ const ringColorMatch = baseClass.match(/^ring-((?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose|white|black)(?:-\d+)?)$/);
548
+ if (ringColorMatch) {
549
+ return { cat: "visual", val: prefix + "ring-color:" + ringColorMatch[1] };
550
+ }
551
+
552
+ return null;
553
+ }
554
+
555
+ function convertClasses(classString, exact) {
556
+ const classes = classString
557
+ .trim()
558
+ .split(/\s+/)
559
+ .filter((c) => c);
560
+ const layout = [],
561
+ space = [],
562
+ visual = [],
563
+ unknown = [];
564
+
565
+ for (const cls of classes) {
566
+ const result = convertClass(cls, exact);
567
+ if (result) {
568
+ if (result.cat === "layout") layout.push(result.val);
569
+ else if (result.cat === "space") space.push(result.val);
570
+ else if (result.cat === "visual") visual.push(result.val);
571
+ } else {
572
+ unknown.push(cls);
573
+ }
574
+ }
575
+
576
+ return { layout, space, visual, unknown };
577
+ }
578
+
579
+ function convertHTML(html, exact) {
580
+ return html.replace(
581
+ /class=(['"])([^"']+)\1/g,
582
+ (match, quote, classValue) => {
583
+ const { layout, space, visual, unknown } = convertClasses(
584
+ classValue,
585
+ exact
586
+ );
587
+ const attrs = [];
588
+ if (layout.length) attrs.push(`layout="${layout.join(" ")}"`);
589
+ if (space.length) attrs.push(`space="${space.join(" ")}"`);
590
+ if (visual.length) attrs.push(`visual="${visual.join(" ")}"`);
591
+ if (unknown.length) attrs.push(`class="${unknown.join(" ")}"`);
592
+ return attrs.join(" ") || 'class=""';
593
+ }
594
+ );
595
+ }
596
+
597
+ // ============================
598
+ // EXPORTS
599
+ // ============================
600
+
601
+ // Export for browser (IIFE global)
602
+ if (typeof window !== 'undefined') {
603
+ window.SenangStartTW = {
604
+ convertClass,
605
+ convertClasses,
606
+ convertHTML,
607
+ // Expose scales for customization
608
+ scales: {
609
+ spacing: spacingScale,
610
+ radius: radiusScale,
611
+ shadow: shadowScale,
612
+ fontSize: fontSizeScale,
613
+ },
614
+ mappings: {
615
+ layout: layoutMappings,
616
+ visual: visualKeywords,
617
+ },
618
+ };
619
+ }
620
+
621
+ // Export for ES modules
622
+ export {
623
+ convertClass,
624
+ convertClasses,
625
+ convertHTML,
626
+ spacingScale,
627
+ radiusScale,
628
+ shadowScale,
629
+ fontSizeScale,
630
+ layoutMappings,
631
+ visualKeywords,
632
+ };
@@ -1577,6 +1577,33 @@ function generateVisualRule(token, config) {
1577
1577
  return `transform: skewY(${cssValue});`;
1578
1578
  },
1579
1579
 
1580
+ // 3D Rotation (Rotate X/Y/Z)
1581
+ 'rotate-x': () => {
1582
+ const cssValue = isArbitrary ? value : `${value}deg`;
1583
+ return `transform: rotateX(${cssValue});`;
1584
+ },
1585
+
1586
+ 'rotate-y': () => {
1587
+ const cssValue = isArbitrary ? value : `${value}deg`;
1588
+ return `transform: rotateY(${cssValue});`;
1589
+ },
1590
+
1591
+ 'rotate-z': () => {
1592
+ const cssValue = isArbitrary ? value : `${value}deg`;
1593
+ return `transform: rotateZ(${cssValue});`;
1594
+ },
1595
+
1596
+ // 3D Translation (Translate Z)
1597
+ 'translate-z': () => {
1598
+ const translatePresets = {
1599
+ 'near': '50px',
1600
+ 'far': '-50px',
1601
+ '0': '0'
1602
+ };
1603
+ const cssValue = isArbitrary ? value : (translatePresets[value] || `var(--s-${value})`);
1604
+ return `transform: translateZ(${cssValue});`;
1605
+ },
1606
+
1580
1607
  // Transform Origin
1581
1608
  'origin': () => {
1582
1609
  const originMap = {