@bookklik/senangstart-css 0.2.3 → 0.2.4
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.
- package/dist/senangstart-css.js +18 -0
- package/dist/senangstart-css.min.js +7 -7
- package/dist/senangstart-tw.js +389 -0
- package/dist/senangstart-tw.min.js +2 -0
- package/docs/.vitepress/config.js +6 -0
- package/docs/ms/reference/visual/gradient-from.md +57 -0
- package/docs/ms/reference/visual/gradient-to.md +57 -0
- package/docs/ms/reference/visual/gradient-via.md +54 -0
- package/docs/ms/reference/visual/text-size.md +84 -84
- package/docs/public/assets/senangstart-css.min.js +209 -1545
- package/docs/reference/visual/gradient-from.md +57 -0
- package/docs/reference/visual/gradient-to.md +57 -0
- package/docs/reference/visual/gradient-via.md +54 -0
- package/docs/reference/visual/text-size.md +84 -84
- package/package.json +1 -1
- package/playground/tw-convertor.html +103 -589
- package/scripts/build-dist.js +43 -1
- package/scripts/convert-tailwind.js +24 -0
- package/src/cdn/jit.js +19 -0
- package/src/cdn/tw-conversion-engine.js +497 -0
- package/src/definitions/layout-positioning.js +6 -6
- package/src/definitions/visual-backgrounds.js +113 -15
- package/src/definitions/visual-borders.js +1 -1
- package/src/definitions/visual-filters.js +16 -16
- package/src/definitions/visual-svg.js +5 -5
- package/tests/unit/convert-tailwind.test.js +8 -0
package/scripts/build-dist.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import * as esbuild from 'esbuild';
|
|
9
|
-
import { mkdirSync, statSync } from 'fs';
|
|
9
|
+
import { mkdirSync, statSync, copyFileSync } from 'fs';
|
|
10
10
|
import { dirname, join } from 'path';
|
|
11
11
|
import { fileURLToPath } from 'url';
|
|
12
12
|
|
|
@@ -49,6 +49,48 @@ await esbuild.build({
|
|
|
49
49
|
const minSize = statSync(join(distDir, 'senangstart-css.min.js')).size;
|
|
50
50
|
console.log(`✓ Created senangstart-css.min.js (${(minSize / 1024).toFixed(1)} KB)`);
|
|
51
51
|
|
|
52
|
+
// Build Tailwind converter - unminified
|
|
53
|
+
await esbuild.build({
|
|
54
|
+
entryPoints: [join(root, 'src', 'cdn', 'tw-conversion-engine.js')],
|
|
55
|
+
bundle: true,
|
|
56
|
+
format: 'iife',
|
|
57
|
+
outfile: join(distDir, 'senangstart-tw.js'),
|
|
58
|
+
minify: false,
|
|
59
|
+
banner: {
|
|
60
|
+
js: '/* SenangStart CSS - Tailwind Converter v0.2.0 | MIT License */'
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const twUnminSize = statSync(join(distDir, 'senangstart-tw.js')).size;
|
|
65
|
+
console.log(`✓ Created senangstart-tw.js (${(twUnminSize / 1024).toFixed(1)} KB)`);
|
|
66
|
+
|
|
67
|
+
// Build Tailwind converter - minified
|
|
68
|
+
await esbuild.build({
|
|
69
|
+
entryPoints: [join(root, 'src', 'cdn', 'tw-conversion-engine.js')],
|
|
70
|
+
bundle: true,
|
|
71
|
+
format: 'iife',
|
|
72
|
+
outfile: join(distDir, 'senangstart-tw.min.js'),
|
|
73
|
+
minify: true,
|
|
74
|
+
banner: {
|
|
75
|
+
js: '/* SenangStart TW v0.2.0 | MIT */'
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const twMinSize = statSync(join(distDir, 'senangstart-tw.min.js')).size;
|
|
80
|
+
console.log(`✓ Created senangstart-tw.min.js (${(twMinSize / 1024).toFixed(1)} KB)`);
|
|
81
|
+
|
|
82
|
+
// Copy to docs/public/assets for VitePress
|
|
83
|
+
const docsAssetsDir = join(root, 'docs', 'public', 'assets');
|
|
84
|
+
mkdirSync(docsAssetsDir, { recursive: true });
|
|
85
|
+
copyFileSync(
|
|
86
|
+
join(distDir, 'senangstart-css.min.js'),
|
|
87
|
+
join(docsAssetsDir, 'senangstart-css.min.js')
|
|
88
|
+
);
|
|
89
|
+
console.log(`✓ Copied to docs/public/assets/senangstart-css.min.js`);
|
|
90
|
+
|
|
52
91
|
console.log('\n📦 Dist build complete!');
|
|
53
92
|
console.log(' dist/senangstart-css.js');
|
|
54
93
|
console.log(' dist/senangstart-css.min.js');
|
|
94
|
+
console.log(' dist/senangstart-tw.js');
|
|
95
|
+
console.log(' dist/senangstart-tw.min.js');
|
|
96
|
+
|
|
@@ -583,6 +583,30 @@ function convertClass(twClass, options = {}) {
|
|
|
583
583
|
return { category: 'visual', value: prefix + "opacity:" + opacityMatch[1] };
|
|
584
584
|
}
|
|
585
585
|
|
|
586
|
+
// Gradient direction (bg-gradient-to-*)
|
|
587
|
+
const bgGradientMatch = baseClass.match(/^bg-gradient-to-(t|tr|r|br|b|bl|l|tl)$/);
|
|
588
|
+
if (bgGradientMatch) {
|
|
589
|
+
return { category: 'visual', value: prefix + "bg-image:gradient-to-" + bgGradientMatch[1] };
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Gradient from-* (starting color)
|
|
593
|
+
const fromMatch = baseClass.match(/^from-(.+)$/);
|
|
594
|
+
if (fromMatch) {
|
|
595
|
+
return { category: 'visual', value: prefix + "from:" + fromMatch[1] };
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Gradient via-* (middle color)
|
|
599
|
+
const viaMatch = baseClass.match(/^via-(.+)$/);
|
|
600
|
+
if (viaMatch) {
|
|
601
|
+
return { category: 'visual', value: prefix + "via:" + viaMatch[1] };
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Gradient to-* (ending color) - Note: must come after bg-gradient-to-*
|
|
605
|
+
const toMatch = baseClass.match(/^to-(.+)$/);
|
|
606
|
+
if (toMatch) {
|
|
607
|
+
return { category: 'visual', value: prefix + "to:" + toMatch[1] };
|
|
608
|
+
}
|
|
609
|
+
|
|
586
610
|
return null;
|
|
587
611
|
}
|
|
588
612
|
|
package/src/cdn/jit.js
CHANGED
|
@@ -25,6 +25,9 @@ import { tokenize, parseToken } from '../core/tokenizer-core.js';
|
|
|
25
25
|
theme: {
|
|
26
26
|
spacing: {
|
|
27
27
|
'none': '0px',
|
|
28
|
+
'thin': '1px',
|
|
29
|
+
'regular': '2px',
|
|
30
|
+
'thick': '3px',
|
|
28
31
|
'tiny': '4px',
|
|
29
32
|
'small': '8px',
|
|
30
33
|
'medium': '16px',
|
|
@@ -1658,6 +1661,22 @@ img, video {
|
|
|
1658
1661
|
return `background-image: ${cssValue};`;
|
|
1659
1662
|
},
|
|
1660
1663
|
|
|
1664
|
+
// ============================================
|
|
1665
|
+
// GRADIENT COLOR STOPS
|
|
1666
|
+
// ============================================
|
|
1667
|
+
'from': () => {
|
|
1668
|
+
const color = isArbitrary ? value : `var(--c-${value})`;
|
|
1669
|
+
return `--tw-gradient-from: ${color}; --tw-gradient-to: transparent; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);`;
|
|
1670
|
+
},
|
|
1671
|
+
'via': () => {
|
|
1672
|
+
const color = isArbitrary ? value : `var(--c-${value})`;
|
|
1673
|
+
return `--tw-gradient-via: ${color}; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-via), var(--tw-gradient-to);`;
|
|
1674
|
+
},
|
|
1675
|
+
'to': () => {
|
|
1676
|
+
const color = isArbitrary ? value : `var(--c-${value})`;
|
|
1677
|
+
return `--tw-gradient-to: ${color};`;
|
|
1678
|
+
},
|
|
1679
|
+
|
|
1661
1680
|
// ============================================
|
|
1662
1681
|
// BACKDROP FILTER UTILITIES
|
|
1663
1682
|
// ============================================
|
|
@@ -0,0 +1,497 @@
|
|
|
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
|
+
const spacingScale = {
|
|
11
|
+
0: "none",
|
|
12
|
+
px: "[1px]",
|
|
13
|
+
0.5: "tiny",
|
|
14
|
+
1: "tiny",
|
|
15
|
+
1.5: "tiny",
|
|
16
|
+
2: "tiny",
|
|
17
|
+
2.5: "small",
|
|
18
|
+
3: "small",
|
|
19
|
+
3.5: "small",
|
|
20
|
+
4: "small",
|
|
21
|
+
5: "medium",
|
|
22
|
+
6: "medium",
|
|
23
|
+
7: "medium",
|
|
24
|
+
8: "big",
|
|
25
|
+
9: "big",
|
|
26
|
+
10: "big",
|
|
27
|
+
11: "big",
|
|
28
|
+
12: "giant",
|
|
29
|
+
14: "giant",
|
|
30
|
+
16: "giant",
|
|
31
|
+
20: "vast",
|
|
32
|
+
24: "vast",
|
|
33
|
+
28: "vast",
|
|
34
|
+
32: "vast",
|
|
35
|
+
36: "vast",
|
|
36
|
+
40: "vast",
|
|
37
|
+
44: "vast",
|
|
38
|
+
48: "vast",
|
|
39
|
+
52: "vast",
|
|
40
|
+
56: "vast",
|
|
41
|
+
60: "vast",
|
|
42
|
+
64: "vast",
|
|
43
|
+
72: "vast",
|
|
44
|
+
80: "vast",
|
|
45
|
+
96: "vast",
|
|
46
|
+
full: "[100%]",
|
|
47
|
+
screen: "[100vw]",
|
|
48
|
+
auto: "auto",
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const radiusScale = {
|
|
52
|
+
none: "none",
|
|
53
|
+
sm: "small",
|
|
54
|
+
"": "small",
|
|
55
|
+
md: "medium",
|
|
56
|
+
lg: "medium",
|
|
57
|
+
xl: "big",
|
|
58
|
+
"2xl": "big",
|
|
59
|
+
"3xl": "big",
|
|
60
|
+
full: "round",
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const shadowScale = {
|
|
64
|
+
sm: "small",
|
|
65
|
+
"": "small",
|
|
66
|
+
md: "medium",
|
|
67
|
+
lg: "big",
|
|
68
|
+
xl: "giant",
|
|
69
|
+
"2xl": "giant",
|
|
70
|
+
none: "none",
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const fontSizeScale = {
|
|
74
|
+
xs: "mini", // 0.75rem
|
|
75
|
+
sm: "small", // 0.875rem
|
|
76
|
+
base: "base", // 1rem
|
|
77
|
+
lg: "large", // 1.125rem
|
|
78
|
+
xl: "big", // 1.25rem
|
|
79
|
+
"2xl": "huge", // 1.5rem
|
|
80
|
+
"3xl": "grand", // 1.875rem
|
|
81
|
+
"4xl": "giant", // 2.25rem
|
|
82
|
+
"5xl": "mount", // 3rem
|
|
83
|
+
"6xl": "mega", // 3.75rem
|
|
84
|
+
"7xl": "giga", // 4.5rem
|
|
85
|
+
"8xl": "tera", // 6rem
|
|
86
|
+
"9xl": "hero", // 8rem
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const layoutMappings = {
|
|
90
|
+
container: "container",
|
|
91
|
+
flex: "flex",
|
|
92
|
+
"inline-flex": "inline-flex",
|
|
93
|
+
grid: "grid",
|
|
94
|
+
"inline-grid": "inline-grid",
|
|
95
|
+
block: "block",
|
|
96
|
+
"inline-block": "inline",
|
|
97
|
+
hidden: "hidden",
|
|
98
|
+
"flex-row": "row",
|
|
99
|
+
"flex-col": "col",
|
|
100
|
+
"flex-row-reverse": "row-reverse",
|
|
101
|
+
"flex-col-reverse": "col-reverse",
|
|
102
|
+
"flex-wrap": "wrap",
|
|
103
|
+
"flex-nowrap": "nowrap",
|
|
104
|
+
"flex-wrap-reverse": "wrap-reverse",
|
|
105
|
+
"flex-grow": "grow",
|
|
106
|
+
"flex-grow-0": "grow-0",
|
|
107
|
+
grow: "grow",
|
|
108
|
+
"grow-0": "grow-0",
|
|
109
|
+
"flex-shrink": "shrink",
|
|
110
|
+
"flex-shrink-0": "shrink-0",
|
|
111
|
+
shrink: "shrink",
|
|
112
|
+
"shrink-0": "shrink-0",
|
|
113
|
+
"flex-1": "flex:1",
|
|
114
|
+
"flex-auto": "flex:auto",
|
|
115
|
+
"flex-initial": "flex:initial",
|
|
116
|
+
"flex-none": "flex:none",
|
|
117
|
+
"justify-start": "justify:start",
|
|
118
|
+
"justify-end": "justify:end",
|
|
119
|
+
"justify-center": "justify:center",
|
|
120
|
+
"justify-between": "justify:between",
|
|
121
|
+
"justify-around": "justify:around",
|
|
122
|
+
"justify-evenly": "justify:evenly",
|
|
123
|
+
"items-start": "items:start",
|
|
124
|
+
"items-end": "items:end",
|
|
125
|
+
"items-center": "items:center",
|
|
126
|
+
"items-baseline": "items:baseline",
|
|
127
|
+
"items-stretch": "items:stretch",
|
|
128
|
+
"self-auto": "self:auto",
|
|
129
|
+
"self-start": "self:start",
|
|
130
|
+
"self-end": "self:end",
|
|
131
|
+
"self-center": "self:center",
|
|
132
|
+
"self-stretch": "self:stretch",
|
|
133
|
+
relative: "relative",
|
|
134
|
+
absolute: "absolute",
|
|
135
|
+
fixed: "fixed",
|
|
136
|
+
sticky: "sticky",
|
|
137
|
+
static: "static",
|
|
138
|
+
"overflow-auto": "overflow:auto",
|
|
139
|
+
"overflow-hidden": "overflow:hidden",
|
|
140
|
+
"overflow-visible": "overflow:visible",
|
|
141
|
+
"overflow-scroll": "overflow:scroll",
|
|
142
|
+
"object-contain": "object:contain",
|
|
143
|
+
"object-cover": "object:cover",
|
|
144
|
+
"object-fill": "object:fill",
|
|
145
|
+
"object-none": "object:none",
|
|
146
|
+
"object-scale-down": "object:scale-down",
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const visualKeywords = {
|
|
150
|
+
italic: "italic",
|
|
151
|
+
"not-italic": "not-italic",
|
|
152
|
+
antialiased: "antialiased",
|
|
153
|
+
uppercase: "uppercase",
|
|
154
|
+
lowercase: "lowercase",
|
|
155
|
+
capitalize: "capitalize",
|
|
156
|
+
"normal-case": "normal-case",
|
|
157
|
+
underline: "underline",
|
|
158
|
+
"line-through": "line-through",
|
|
159
|
+
"no-underline": "no-underline",
|
|
160
|
+
truncate: "truncate",
|
|
161
|
+
"cursor-pointer": "cursor:pointer",
|
|
162
|
+
"cursor-default": "cursor:default",
|
|
163
|
+
"cursor-not-allowed": "cursor:not-allowed",
|
|
164
|
+
"select-none": "select:none",
|
|
165
|
+
"select-text": "select:text",
|
|
166
|
+
"select-all": "select:all",
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// ============================
|
|
170
|
+
// HELPER FUNCTIONS
|
|
171
|
+
// ============================
|
|
172
|
+
|
|
173
|
+
function getSpacing(value, exact) {
|
|
174
|
+
if (exact) {
|
|
175
|
+
if (["full", "screen", "auto"].includes(value))
|
|
176
|
+
return spacingScale[value] || `[${value}]`;
|
|
177
|
+
return `tw-${value}`;
|
|
178
|
+
}
|
|
179
|
+
return spacingScale[value] || `[${value}]`;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ============================
|
|
183
|
+
// CONVERSION FUNCTIONS
|
|
184
|
+
// ============================
|
|
185
|
+
|
|
186
|
+
function convertClass(twClass, exact) {
|
|
187
|
+
// Handle prefixes (hover:, sm:, md:, etc.)
|
|
188
|
+
const prefixMatch = twClass.match(
|
|
189
|
+
/^(sm:|md:|lg:|xl:|2xl:|hover:|focus:|active:|disabled:|dark:)(.+)$/
|
|
190
|
+
);
|
|
191
|
+
let prefix = "",
|
|
192
|
+
baseClass = twClass;
|
|
193
|
+
if (prefixMatch) {
|
|
194
|
+
const rawPrefix = prefixMatch[1].slice(0, -1); // remove colon
|
|
195
|
+
if (['sm', 'md', 'lg', 'xl', '2xl'].includes(rawPrefix)) {
|
|
196
|
+
prefix = `tw-${rawPrefix}:`;
|
|
197
|
+
} else {
|
|
198
|
+
prefix = prefixMatch[1];
|
|
199
|
+
}
|
|
200
|
+
baseClass = prefixMatch[2];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Layout mappings
|
|
204
|
+
if (layoutMappings[baseClass])
|
|
205
|
+
return { cat: "layout", val: prefix + layoutMappings[baseClass] };
|
|
206
|
+
|
|
207
|
+
// Visual keywords
|
|
208
|
+
if (visualKeywords[baseClass])
|
|
209
|
+
return { cat: "visual", val: prefix + visualKeywords[baseClass] };
|
|
210
|
+
|
|
211
|
+
// Text color
|
|
212
|
+
const textColorMatch = baseClass.match(
|
|
213
|
+
/^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+)?)$/
|
|
214
|
+
);
|
|
215
|
+
if (textColorMatch)
|
|
216
|
+
return { cat: "visual", val: prefix + "text:" + textColorMatch[1] };
|
|
217
|
+
|
|
218
|
+
// Text alignment
|
|
219
|
+
if (
|
|
220
|
+
["text-left", "text-center", "text-right", "text-justify"].includes(
|
|
221
|
+
baseClass
|
|
222
|
+
)
|
|
223
|
+
)
|
|
224
|
+
return {
|
|
225
|
+
cat: "visual",
|
|
226
|
+
val: prefix + "text:" + baseClass.replace("text-", ""),
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
// Text size
|
|
230
|
+
const textSizeMatch = baseClass.match(
|
|
231
|
+
/^text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl)$/
|
|
232
|
+
);
|
|
233
|
+
if (textSizeMatch) {
|
|
234
|
+
const size = exact
|
|
235
|
+
? `tw-${textSizeMatch[1]}`
|
|
236
|
+
: fontSizeScale[textSizeMatch[1]] || textSizeMatch[1];
|
|
237
|
+
return { cat: "visual", val: prefix + "text-size:" + size };
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Background color
|
|
241
|
+
const bgMatch = baseClass.match(
|
|
242
|
+
/^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+)?)$/
|
|
243
|
+
);
|
|
244
|
+
if (bgMatch) return { cat: "visual", val: prefix + "bg:" + bgMatch[1] };
|
|
245
|
+
|
|
246
|
+
// Border color
|
|
247
|
+
const borderColorMatch = baseClass.match(
|
|
248
|
+
/^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+)?)$/
|
|
249
|
+
);
|
|
250
|
+
if (borderColorMatch)
|
|
251
|
+
return {
|
|
252
|
+
cat: "visual",
|
|
253
|
+
val: prefix + "border:" + borderColorMatch[1],
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// Padding
|
|
257
|
+
const paddingMatch = baseClass.match(/^p([trblxy])?-(.+)$/);
|
|
258
|
+
if (paddingMatch) {
|
|
259
|
+
const side = paddingMatch[1] ? "-" + paddingMatch[1] : "";
|
|
260
|
+
return {
|
|
261
|
+
cat: "space",
|
|
262
|
+
val: prefix + "p" + side + ":" + getSpacing(paddingMatch[2], exact),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Margin
|
|
267
|
+
const marginMatch = baseClass.match(
|
|
268
|
+
/^-?m([trblxy])?-(\d+\.?\d*|px|auto|full|screen)$/
|
|
269
|
+
);
|
|
270
|
+
if (marginMatch) {
|
|
271
|
+
const isNeg = baseClass.startsWith("-");
|
|
272
|
+
const side = marginMatch[1] ? "-" + marginMatch[1] : "";
|
|
273
|
+
let val = getSpacing(marginMatch[2], exact);
|
|
274
|
+
if (isNeg) val = "[-" + val + "]";
|
|
275
|
+
return { cat: "space", val: prefix + "m" + side + ":" + val };
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Gap
|
|
279
|
+
const gapMatch = baseClass.match(/^gap-([xy])?-?(.+)$/);
|
|
280
|
+
if (gapMatch) {
|
|
281
|
+
const axis = gapMatch[1] ? "-" + gapMatch[1] : "";
|
|
282
|
+
return {
|
|
283
|
+
cat: "space",
|
|
284
|
+
val: prefix + "g" + axis + ":" + getSpacing(gapMatch[2], exact),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Width/Height with special values
|
|
289
|
+
const widthMatch = baseClass.match(/^(min-w|max-w|w)-(.+)$/);
|
|
290
|
+
if (widthMatch) {
|
|
291
|
+
const prop = widthMatch[1];
|
|
292
|
+
const rawVal = widthMatch[2];
|
|
293
|
+
// Special width values
|
|
294
|
+
const specialWidthVals = { 'max': '[max-content]', 'min': '[min-content]', 'fit': '[fit-content]', 'prose': '[65ch]' };
|
|
295
|
+
const val = specialWidthVals[rawVal] || getSpacing(rawVal, exact);
|
|
296
|
+
return { cat: "space", val: prefix + prop + ":" + val };
|
|
297
|
+
}
|
|
298
|
+
const heightMatch = baseClass.match(/^(min-h|max-h|h)-(.+)$/);
|
|
299
|
+
if (heightMatch) {
|
|
300
|
+
const prop = heightMatch[1];
|
|
301
|
+
const rawVal = heightMatch[2];
|
|
302
|
+
const specialHeightVals = { 'screen': '[100vh]', 'svh': '[100svh]', 'lvh': '[100lvh]', 'dvh': '[100dvh]', 'max': '[max-content]', 'min': '[min-content]', 'fit': '[fit-content]' };
|
|
303
|
+
const val = specialHeightVals[rawVal] || getSpacing(rawVal, exact);
|
|
304
|
+
return { cat: "space", val: prefix + prop + ":" + val };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Border radius
|
|
308
|
+
const roundedMatch = baseClass.match(/^rounded(?:-(.+))?$/);
|
|
309
|
+
if (roundedMatch) {
|
|
310
|
+
const size = roundedMatch[1] || "";
|
|
311
|
+
const scale = exact
|
|
312
|
+
? size === ""
|
|
313
|
+
? "tw-DEFAULT"
|
|
314
|
+
: `tw-${size}`
|
|
315
|
+
: radiusScale[size] || "medium";
|
|
316
|
+
return { cat: "visual", val: prefix + "rounded:" + scale };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Shadow
|
|
320
|
+
const shadowMatch = baseClass.match(/^shadow(?:-(.+))?$/);
|
|
321
|
+
if (shadowMatch) {
|
|
322
|
+
const size = shadowMatch[1] || "";
|
|
323
|
+
const scale = exact
|
|
324
|
+
? size === ""
|
|
325
|
+
? "tw-DEFAULT"
|
|
326
|
+
: `tw-${size}`
|
|
327
|
+
: shadowScale[size] || "medium";
|
|
328
|
+
return { cat: "visual", val: prefix + "shadow:" + scale };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Font weight
|
|
332
|
+
const fontWeightMatch = baseClass.match(
|
|
333
|
+
/^font-(thin|extralight|light|normal|medium|semibold|bold|extrabold|black)$/
|
|
334
|
+
);
|
|
335
|
+
if (fontWeightMatch)
|
|
336
|
+
return { cat: "visual", val: prefix + "font:tw-" + fontWeightMatch[1] };
|
|
337
|
+
|
|
338
|
+
// Border width
|
|
339
|
+
const borderWidthMatch = baseClass.match(
|
|
340
|
+
/^border(?:-([trblxy]))?(?:-(\d+))?$/
|
|
341
|
+
);
|
|
342
|
+
if (
|
|
343
|
+
borderWidthMatch &&
|
|
344
|
+
(borderWidthMatch[2] ||
|
|
345
|
+
(!borderWidthMatch[1] && baseClass === "border"))
|
|
346
|
+
) {
|
|
347
|
+
const side = borderWidthMatch[1]
|
|
348
|
+
? "-" + borderWidthMatch[1] + "-w"
|
|
349
|
+
: "-w";
|
|
350
|
+
const width = borderWidthMatch[2] || "1";
|
|
351
|
+
return {
|
|
352
|
+
cat: "visual",
|
|
353
|
+
val: prefix + "border" + side + ":[" + width + "px]",
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Order
|
|
358
|
+
const orderMatch = baseClass.match(/^order-(\d+|first|last|none)$/);
|
|
359
|
+
if (orderMatch) {
|
|
360
|
+
return { cat: "layout", val: prefix + "order:" + orderMatch[1] };
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Grid columns
|
|
364
|
+
const gridColsMatch = baseClass.match(/^grid-cols-(\d+|none)$/);
|
|
365
|
+
if (gridColsMatch) {
|
|
366
|
+
return { cat: "layout", val: prefix + "grid-cols:" + gridColsMatch[1] };
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Column span
|
|
370
|
+
const colSpanMatch = baseClass.match(/^col-span-(\d+|full)$/);
|
|
371
|
+
if (colSpanMatch) {
|
|
372
|
+
return { cat: "layout", val: prefix + "col-span:" + colSpanMatch[1] };
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Grid rows
|
|
376
|
+
const gridRowsMatch = baseClass.match(/^grid-rows-(\d+|none)$/);
|
|
377
|
+
if (gridRowsMatch) {
|
|
378
|
+
return { cat: "layout", val: prefix + "grid-rows:" + gridRowsMatch[1] };
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Row span
|
|
382
|
+
const rowSpanMatch = baseClass.match(/^row-span-(\d+|full)$/);
|
|
383
|
+
if (rowSpanMatch) {
|
|
384
|
+
return { cat: "layout", val: prefix + "row-span:" + rowSpanMatch[1] };
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Opacity
|
|
388
|
+
const opacityMatch = baseClass.match(/^opacity-(\d+)$/);
|
|
389
|
+
if (opacityMatch) {
|
|
390
|
+
return { cat: "visual", val: prefix + "opacity:" + opacityMatch[1] };
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Gradient direction (bg-gradient-to-*)
|
|
394
|
+
const bgGradientMatch = baseClass.match(/^bg-gradient-to-(t|tr|r|br|b|bl|l|tl)$/);
|
|
395
|
+
if (bgGradientMatch) {
|
|
396
|
+
return { cat: "visual", val: prefix + "bg-image:gradient-to-" + bgGradientMatch[1] };
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Gradient from-* (starting color)
|
|
400
|
+
const fromMatch = baseClass.match(/^from-(.+)$/);
|
|
401
|
+
if (fromMatch) {
|
|
402
|
+
return { cat: "visual", val: prefix + "from:" + fromMatch[1] };
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Gradient via-* (middle color)
|
|
406
|
+
const viaMatch = baseClass.match(/^via-(.+)$/);
|
|
407
|
+
if (viaMatch) {
|
|
408
|
+
return { cat: "visual", val: prefix + "via:" + viaMatch[1] };
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Gradient to-* (ending color) - Note: must come after bg-gradient-to-*
|
|
412
|
+
const toMatch = baseClass.match(/^to-(.+)$/);
|
|
413
|
+
if (toMatch) {
|
|
414
|
+
return { cat: "visual", val: prefix + "to:" + toMatch[1] };
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function convertClasses(classString, exact) {
|
|
421
|
+
const classes = classString
|
|
422
|
+
.trim()
|
|
423
|
+
.split(/\s+/)
|
|
424
|
+
.filter((c) => c);
|
|
425
|
+
const layout = [],
|
|
426
|
+
space = [],
|
|
427
|
+
visual = [],
|
|
428
|
+
unknown = [];
|
|
429
|
+
|
|
430
|
+
for (const cls of classes) {
|
|
431
|
+
const result = convertClass(cls, exact);
|
|
432
|
+
if (result) {
|
|
433
|
+
if (result.cat === "layout") layout.push(result.val);
|
|
434
|
+
else if (result.cat === "space") space.push(result.val);
|
|
435
|
+
else if (result.cat === "visual") visual.push(result.val);
|
|
436
|
+
} else {
|
|
437
|
+
unknown.push(cls);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return { layout, space, visual, unknown };
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function convertHTML(html, exact) {
|
|
445
|
+
return html.replace(
|
|
446
|
+
/class=(['"])([^"']+)\1/g,
|
|
447
|
+
(match, quote, classValue) => {
|
|
448
|
+
const { layout, space, visual, unknown } = convertClasses(
|
|
449
|
+
classValue,
|
|
450
|
+
exact
|
|
451
|
+
);
|
|
452
|
+
const attrs = [];
|
|
453
|
+
if (layout.length) attrs.push(`layout="${layout.join(" ")}"`);
|
|
454
|
+
if (space.length) attrs.push(`space="${space.join(" ")}"`);
|
|
455
|
+
if (visual.length) attrs.push(`visual="${visual.join(" ")}"`);
|
|
456
|
+
if (unknown.length) attrs.push(`class="${unknown.join(" ")}"`);
|
|
457
|
+
return attrs.join(" ") || 'class=""';
|
|
458
|
+
}
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// ============================
|
|
463
|
+
// EXPORTS
|
|
464
|
+
// ============================
|
|
465
|
+
|
|
466
|
+
// Export for browser (IIFE global)
|
|
467
|
+
if (typeof window !== 'undefined') {
|
|
468
|
+
window.SenangStartTW = {
|
|
469
|
+
convertClass,
|
|
470
|
+
convertClasses,
|
|
471
|
+
convertHTML,
|
|
472
|
+
// Expose scales for customization
|
|
473
|
+
scales: {
|
|
474
|
+
spacing: spacingScale,
|
|
475
|
+
radius: radiusScale,
|
|
476
|
+
shadow: shadowScale,
|
|
477
|
+
fontSize: fontSizeScale,
|
|
478
|
+
},
|
|
479
|
+
mappings: {
|
|
480
|
+
layout: layoutMappings,
|
|
481
|
+
visual: visualKeywords,
|
|
482
|
+
},
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Export for ES modules
|
|
487
|
+
export {
|
|
488
|
+
convertClass,
|
|
489
|
+
convertClasses,
|
|
490
|
+
convertHTML,
|
|
491
|
+
spacingScale,
|
|
492
|
+
radiusScale,
|
|
493
|
+
shadowScale,
|
|
494
|
+
fontSizeScale,
|
|
495
|
+
layoutMappings,
|
|
496
|
+
visualKeywords,
|
|
497
|
+
};
|
|
@@ -33,7 +33,7 @@ export const position = {
|
|
|
33
33
|
descriptionMs: 'Elemen diletakkan relatif kepada aliran normal',
|
|
34
34
|
html: `<div layout="relative" space="p:medium" visual="bg:neutral-100 dark:bg:neutral-900 rounded:medium">
|
|
35
35
|
<span space="p:small" visual="bg:primary text:white rounded:small">Relative Container</span>
|
|
36
|
-
<span layout="absolute
|
|
36
|
+
<span layout="absolute top:0 right:0" space="p:tiny" visual="bg:danger text:white rounded:small">Abs</span>
|
|
37
37
|
</div>`,
|
|
38
38
|
highlightValue: 'relative'
|
|
39
39
|
},
|
|
@@ -43,7 +43,7 @@ export const position = {
|
|
|
43
43
|
description: 'Element sticks when scrolling past it',
|
|
44
44
|
descriptionMs: 'Elemen melekat apabila skrol melepasi',
|
|
45
45
|
html: `<div space="p:medium" visual="bg:neutral-100 dark:bg:neutral-900 rounded:medium">
|
|
46
|
-
<span layout="sticky
|
|
46
|
+
<span layout="sticky top:0" space="p:small" visual="bg:primary text:white rounded:small">Sticky Header</span>
|
|
47
47
|
</div>`,
|
|
48
48
|
highlightValue: 'sticky'
|
|
49
49
|
}
|
|
@@ -133,10 +133,10 @@ export const zIndex = {
|
|
|
133
133
|
description: 'Control stacking order of positioned elements',
|
|
134
134
|
descriptionMs: 'Kawal susunan tindanan elemen yang diletakkan',
|
|
135
135
|
html: `<div layout="relative" space="p:medium" visual="bg:neutral-100 dark:bg:neutral-900 rounded:medium" style="height: 80px;">
|
|
136
|
-
<span layout="absolute z:base
|
|
137
|
-
<span layout="absolute z:low
|
|
138
|
-
<span layout="absolute z:mid
|
|
139
|
-
<span layout="absolute z:high
|
|
136
|
+
<span layout="absolute z:base left:0 top:10px" space="p:small" visual="bg:neutral-400 text:white rounded:small">z:base</span>
|
|
137
|
+
<span layout="absolute z:low left:30px top:20px" space="p:small" visual="bg:neutral-500 text:white rounded:small">z:low</span>
|
|
138
|
+
<span layout="absolute z:mid left:60px top:30px" space="p:small" visual="bg:neutral-600 text:white rounded:small">z:mid</span>
|
|
139
|
+
<span layout="absolute z:high left:90px top:40px" space="p:small" visual="bg:primary text:white rounded:small">z:high</span>
|
|
140
140
|
</div>`,
|
|
141
141
|
highlightValue: 'z:high'
|
|
142
142
|
}
|