tailwind-to-style 2.3.1 → 2.5.0
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/LICENSE +21 -0
- package/README.md +122 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +1013 -0
- package/index.js +895 -6326
- package/index.min.js +1 -1
- package/package.json +40 -4
|
@@ -0,0 +1,1013 @@
|
|
|
1
|
+
import { getConfigOptions } from "./utils/index";
|
|
2
|
+
|
|
3
|
+
import generateAccentColor from "./generators/accentColor";
|
|
4
|
+
import generateAccessibility from "./generators/accessibility";
|
|
5
|
+
import generateAlignContent from "./generators/alignContent";
|
|
6
|
+
import generateAlignItems from "./generators/alignItems";
|
|
7
|
+
import generateAlignSelf from "./generators/alignSelf";
|
|
8
|
+
import generateAppearance from "./generators/appearance";
|
|
9
|
+
import generateAspect from "./generators/aspect";
|
|
10
|
+
import generateBackgroundAttachment from "./generators/backgroundAttachment";
|
|
11
|
+
import generateBackgroundClip from "./generators/backgroundClip";
|
|
12
|
+
import generateBackgroundColor from "./generators/backgroundColor";
|
|
13
|
+
import generateBackgroundImage from "./generators/backgroundImage";
|
|
14
|
+
import generateBackgroundOpacity from "./generators/backgroundOpacity";
|
|
15
|
+
import generateBackgroundOrigin from "./generators/backgroundOrigin";
|
|
16
|
+
import generateBackgroundPosition from "./generators/backgroundPosition";
|
|
17
|
+
import generateBackgroundRepeat from "./generators/backgroundRepeat";
|
|
18
|
+
import generateBackgroundSize from "./generators/backgroundSize";
|
|
19
|
+
import generateBlur from "./generators/blur";
|
|
20
|
+
import generateBorderCollapse from "./generators/borderCollapse";
|
|
21
|
+
import generateBorderColor from "./generators/borderColor";
|
|
22
|
+
import generateBorderOpacity from "./generators/borderOpacity";
|
|
23
|
+
import generateBorderRadius from "./generators/borderRadius";
|
|
24
|
+
import generateBorderSpacing from "./generators/borderSpacing";
|
|
25
|
+
import generateBorderStyle from "./generators/borderStyle";
|
|
26
|
+
import generateBorderWidth from "./generators/borderWidth";
|
|
27
|
+
import generateBoxDecorationBreak from "./generators/boxDecorationBreak";
|
|
28
|
+
import generateBoxShadow from "./generators/boxShadow";
|
|
29
|
+
import generateBoxSizing from "./generators/boxSizing";
|
|
30
|
+
import generateBrightness from "./generators/brightness";
|
|
31
|
+
import generateCaptionSide from "./generators/captionSide";
|
|
32
|
+
import generateCaretColor from "./generators/caretColor";
|
|
33
|
+
import generateClear from "./generators/clear";
|
|
34
|
+
import generateContent from "./generators/content";
|
|
35
|
+
import generateContrast from "./generators/contrast";
|
|
36
|
+
import generateCursor from "./generators/cursor";
|
|
37
|
+
import generateDisplay from "./generators/display";
|
|
38
|
+
import generateDivideColor from "./generators/divideColor";
|
|
39
|
+
import generateDivideOpacity from "./generators/divideOpacity";
|
|
40
|
+
import generateDivideStyle from "./generators/divideStyle";
|
|
41
|
+
import generateDivideWidth from "./generators/divideWidth";
|
|
42
|
+
import generateDropShadow from "./generators/dropShadow";
|
|
43
|
+
import generateFill from "./generators/fill";
|
|
44
|
+
import generateFilter from "./generators/filter";
|
|
45
|
+
import generateFlex from "./generators/flex";
|
|
46
|
+
import generateFlexBasis from "./generators/flexBasis";
|
|
47
|
+
import generateFlexDirection from "./generators/flexDirection";
|
|
48
|
+
import generateFlexGrow from "./generators/flexGrow";
|
|
49
|
+
import generateFlexShrink from "./generators/flexShrink";
|
|
50
|
+
import generateFlexWrap from "./generators/flexWrap";
|
|
51
|
+
import generateFloat from "./generators/float";
|
|
52
|
+
import generateFontSize from "./generators/fontSize";
|
|
53
|
+
import generateFontSmoothing from "./generators/fontSmoothing";
|
|
54
|
+
import generateFontStyle from "./generators/fontStyle";
|
|
55
|
+
import generateFontVariantNumeric from "./generators/fontVariantNumeric";
|
|
56
|
+
import generateFontWeight from "./generators/fontWeight";
|
|
57
|
+
import generateGap from "./generators/gap";
|
|
58
|
+
import generateGradientColorStops from "./generators/gradientColorStops";
|
|
59
|
+
import generateGrayscale from "./generators/grayscale";
|
|
60
|
+
import generateGridAutoColumns from "./generators/gridAutoColumns";
|
|
61
|
+
import generateGridAutoFlow from "./generators/gridAutoFlow";
|
|
62
|
+
import generateGridAutoRows from "./generators/gridAutoRows";
|
|
63
|
+
import generateGridColumn from "./generators/gridColumn";
|
|
64
|
+
import generateGridColumnEnd from "./generators/gridColumnEnd";
|
|
65
|
+
import generateGridColumnStart from "./generators/gridColumnStart";
|
|
66
|
+
import generateGridRow from "./generators/gridRow";
|
|
67
|
+
import generateGridRowEnd from "./generators/gridRowEnd";
|
|
68
|
+
import generateGridRowStart from "./generators/gridRowStart";
|
|
69
|
+
import generateGridTemplateColumns from "./generators/gridTemplateColumns";
|
|
70
|
+
import generateGridTemplateRows from "./generators/gridTemplateRows";
|
|
71
|
+
import generateHeight from "./generators/height";
|
|
72
|
+
import generateHueRotate from "./generators/hueRotate";
|
|
73
|
+
import generateHyphens from "./generators/hyphens";
|
|
74
|
+
import generateInset from "./generators/inset";
|
|
75
|
+
import generateInvert from "./generators/invert";
|
|
76
|
+
import generateIsolation from "./generators/isolation";
|
|
77
|
+
import generateJustifyContent from "./generators/justifyContent";
|
|
78
|
+
import generateJustifyItems from "./generators/justifyItems";
|
|
79
|
+
import generateJustifySelf from "./generators/justifySelf";
|
|
80
|
+
import generateLetterSpacing from "./generators/letterSpacing";
|
|
81
|
+
import generateLineClamp from "./generators/lineClamp";
|
|
82
|
+
import generateLineHeight from "./generators/lineHeight";
|
|
83
|
+
import generateListStylePosition from "./generators/listStylePosition";
|
|
84
|
+
import generateListStyleType from "./generators/listStyleType";
|
|
85
|
+
import generateMargin from "./generators/margin";
|
|
86
|
+
import generateMaxHeight from "./generators/maxHeight";
|
|
87
|
+
import generateMaxWidth from "./generators/maxWidth";
|
|
88
|
+
import generateMinHeight from "./generators/minHeight";
|
|
89
|
+
import generateMinWidth from "./generators/minWidth";
|
|
90
|
+
import generateMixBlendMode from "./generators/mixBlendMode";
|
|
91
|
+
import generateObjectFit from "./generators/objectFit";
|
|
92
|
+
import generateObjectPosition from "./generators/objectPosition";
|
|
93
|
+
import generateOpacity from "./generators/opacity";
|
|
94
|
+
import generateOrder from "./generators/order";
|
|
95
|
+
import generateOutlineColor from "./generators/outlineColor";
|
|
96
|
+
import generateOutlineOffset from "./generators/outlineOffset";
|
|
97
|
+
import generateOutlineOpacity from "./generators/outlineOpacity";
|
|
98
|
+
import generateOutlineStyle from "./generators/outlineStyle";
|
|
99
|
+
import generateOutlineWidth from "./generators/outlineWidth";
|
|
100
|
+
import generateOverflow from "./generators/overflow";
|
|
101
|
+
import generateOverscrollBehavior from "./generators/overscrollBehavior";
|
|
102
|
+
import generatePadding from "./generators/padding";
|
|
103
|
+
import generatePlaceContent from "./generators/placeContent";
|
|
104
|
+
import generatePlaceItems from "./generators/placeItems";
|
|
105
|
+
import generatePlaceSelf from "./generators/placeSelf";
|
|
106
|
+
import generatePointerEvents from "./generators/pointerEvents";
|
|
107
|
+
import generatePosition from "./generators/position";
|
|
108
|
+
import generateResize from "./generators/resize";
|
|
109
|
+
import generateRingColor from "./generators/ringColor";
|
|
110
|
+
import generateRingOffsetColor from "./generators/ringOffsetColor";
|
|
111
|
+
import generateRingOffsetWidth from "./generators/ringOffsetWidth";
|
|
112
|
+
import generateRingOpacity from "./generators/ringOpacity";
|
|
113
|
+
import generateRingWidth from "./generators/ringWidth";
|
|
114
|
+
import generateSaturate from "./generators/saturate";
|
|
115
|
+
import generateRotate from "./generators/rotate";
|
|
116
|
+
import generateScale from "./generators/scale";
|
|
117
|
+
import generateScrollBehavior from "./generators/scrollBehavior";
|
|
118
|
+
import generateScrollMargin from "./generators/scrollMargin";
|
|
119
|
+
import generateScrollPadding from "./generators/scrollPadding";
|
|
120
|
+
import generateScrollSnapAlign from "./generators/scrollSnapAlign";
|
|
121
|
+
import generateScrollSnapStop from "./generators/scrollSnapStop";
|
|
122
|
+
import generateScrollSnapType from "./generators/scrollSnapType";
|
|
123
|
+
import generateSepia from "./generators/sepia";
|
|
124
|
+
import generateSize from "./generators/size";
|
|
125
|
+
import generateSkew from "./generators/skew";
|
|
126
|
+
import generateSpace from "./generators/space";
|
|
127
|
+
import generateStroke from "./generators/stroke";
|
|
128
|
+
import generateStrokeWidth from "./generators/strokeWidth";
|
|
129
|
+
import generateTableLayout from "./generators/tableLayout";
|
|
130
|
+
import generateTextAlign from "./generators/textAlign";
|
|
131
|
+
import generateTextColor from "./generators/textColor";
|
|
132
|
+
import generateTextDecoration from "./generators/textDecoration";
|
|
133
|
+
import generateTextDecorationColor from "./generators/textDecorationColor";
|
|
134
|
+
import generateTextDecorationStyle from "./generators/textDecorationStyle";
|
|
135
|
+
import generateTextDecorationThickness from "./generators/textDecorationThickness";
|
|
136
|
+
import generateTextIndent from "./generators/textIndent";
|
|
137
|
+
import generateTextOpacity from "./generators/textOpacity";
|
|
138
|
+
import generateTextOverflow from "./generators/textOverflow";
|
|
139
|
+
import generateTextShadowBlur from "./generators/textShadowBlur";
|
|
140
|
+
import generateTextShadowColor from "./generators/textShadowColor";
|
|
141
|
+
import generateTextShadowOpacity from "./generators/textShadowOpacity";
|
|
142
|
+
import generateTextShadowX from "./generators/textShadowX";
|
|
143
|
+
import generateTextShadowY from "./generators/textShadowY";
|
|
144
|
+
import generateTextTransform from "./generators/textTransform";
|
|
145
|
+
import generateTextUnderlineOffset from "./generators/textUnderlineOffset";
|
|
146
|
+
import generateTextWrap from "./generators/textWrap";
|
|
147
|
+
import generateTouchAction from "./generators/touchAction";
|
|
148
|
+
import generateTransform from "./generators/transform";
|
|
149
|
+
import generateTransformOrigin from "./generators/transformOrigin";
|
|
150
|
+
import generateTranslate from "./generators/translate";
|
|
151
|
+
import generateUserSelect from "./generators/userSelect";
|
|
152
|
+
import generateVerticalAlign from "./generators/verticalAlign";
|
|
153
|
+
import generateVisibility from "./generators/visibility";
|
|
154
|
+
import generateWhitespace from "./generators/whitespace";
|
|
155
|
+
import generateWidth from "./generators/width";
|
|
156
|
+
import generateWordBreak from "./generators/wordBreak";
|
|
157
|
+
import generateWillChange from "./generators/willChange";
|
|
158
|
+
import generateZIndex from "./generators/zIndex";
|
|
159
|
+
|
|
160
|
+
import patterns from "./patterns/index";
|
|
161
|
+
|
|
162
|
+
const plugins = {
|
|
163
|
+
accentColor: generateAccentColor,
|
|
164
|
+
accessibility: generateAccessibility,
|
|
165
|
+
alignContent: generateAlignContent,
|
|
166
|
+
alignItems: generateAlignItems,
|
|
167
|
+
alignSelf: generateAlignSelf,
|
|
168
|
+
appearance: generateAppearance,
|
|
169
|
+
aspect: generateAspect,
|
|
170
|
+
backgroundAttachment: generateBackgroundAttachment,
|
|
171
|
+
backgroundClip: generateBackgroundClip,
|
|
172
|
+
backgroundColor: generateBackgroundColor,
|
|
173
|
+
backgroundImage: generateBackgroundImage,
|
|
174
|
+
backgroundOpacity: generateBackgroundOpacity,
|
|
175
|
+
backgroundOrigin: generateBackgroundOrigin,
|
|
176
|
+
backgroundPosition: generateBackgroundPosition,
|
|
177
|
+
backgroundRepeat: generateBackgroundRepeat,
|
|
178
|
+
backgroundSize: generateBackgroundSize,
|
|
179
|
+
blur: generateBlur,
|
|
180
|
+
borderCollapse: generateBorderCollapse,
|
|
181
|
+
borderColor: generateBorderColor,
|
|
182
|
+
borderOpacity: generateBorderOpacity,
|
|
183
|
+
borderRadius: generateBorderRadius,
|
|
184
|
+
borderSpacing: generateBorderSpacing,
|
|
185
|
+
borderStyle: generateBorderStyle,
|
|
186
|
+
borderWidth: generateBorderWidth,
|
|
187
|
+
boxDecorationBreak: generateBoxDecorationBreak,
|
|
188
|
+
boxShadow: generateBoxShadow,
|
|
189
|
+
boxSizing: generateBoxSizing,
|
|
190
|
+
brightness: generateBrightness,
|
|
191
|
+
captionSide: generateCaptionSide,
|
|
192
|
+
caretColor: generateCaretColor,
|
|
193
|
+
clear: generateClear,
|
|
194
|
+
content: generateContent,
|
|
195
|
+
contrast: generateContrast,
|
|
196
|
+
cursor: generateCursor,
|
|
197
|
+
display: generateDisplay,
|
|
198
|
+
divideColor: generateDivideColor,
|
|
199
|
+
divideOpacity: generateDivideOpacity,
|
|
200
|
+
divideStyle: generateDivideStyle,
|
|
201
|
+
divideWidth: generateDivideWidth,
|
|
202
|
+
dropShadow: generateDropShadow,
|
|
203
|
+
fill: generateFill,
|
|
204
|
+
filter: generateFilter,
|
|
205
|
+
flex: generateFlex,
|
|
206
|
+
flexBasis: generateFlexBasis,
|
|
207
|
+
flexDirection: generateFlexDirection,
|
|
208
|
+
flexGrow: generateFlexGrow,
|
|
209
|
+
flexShrink: generateFlexShrink,
|
|
210
|
+
flexWrap: generateFlexWrap,
|
|
211
|
+
float: generateFloat,
|
|
212
|
+
fontSize: generateFontSize,
|
|
213
|
+
fontSmoothing: generateFontSmoothing,
|
|
214
|
+
fontStyle: generateFontStyle,
|
|
215
|
+
fontVariantNumeric: generateFontVariantNumeric,
|
|
216
|
+
fontWeight: generateFontWeight,
|
|
217
|
+
gap: generateGap,
|
|
218
|
+
gradientColorStops: generateGradientColorStops,
|
|
219
|
+
grayscale: generateGrayscale,
|
|
220
|
+
gridAutoColumns: generateGridAutoColumns,
|
|
221
|
+
gridAutoFlow: generateGridAutoFlow,
|
|
222
|
+
gridAutoRows: generateGridAutoRows,
|
|
223
|
+
gridColumn: generateGridColumn,
|
|
224
|
+
gridColumnEnd: generateGridColumnEnd,
|
|
225
|
+
gridColumnStart: generateGridColumnStart,
|
|
226
|
+
gridRow: generateGridRow,
|
|
227
|
+
gridRowEnd: generateGridRowEnd,
|
|
228
|
+
gridRowStart: generateGridRowStart,
|
|
229
|
+
gridTemplateColumns: generateGridTemplateColumns,
|
|
230
|
+
gridTemplateRows: generateGridTemplateRows,
|
|
231
|
+
height: generateHeight,
|
|
232
|
+
hueRotate: generateHueRotate,
|
|
233
|
+
hyphens: generateHyphens,
|
|
234
|
+
inset: generateInset,
|
|
235
|
+
invert: generateInvert,
|
|
236
|
+
isolation: generateIsolation,
|
|
237
|
+
justifyContent: generateJustifyContent,
|
|
238
|
+
justifyItems: generateJustifyItems,
|
|
239
|
+
justifySelf: generateJustifySelf,
|
|
240
|
+
letterSpacing: generateLetterSpacing,
|
|
241
|
+
lineClamp: generateLineClamp,
|
|
242
|
+
lineHeight: generateLineHeight,
|
|
243
|
+
listStylePosition: generateListStylePosition,
|
|
244
|
+
listStyleType: generateListStyleType,
|
|
245
|
+
margin: generateMargin,
|
|
246
|
+
maxHeight: generateMaxHeight,
|
|
247
|
+
maxWidth: generateMaxWidth,
|
|
248
|
+
minHeight: generateMinHeight,
|
|
249
|
+
minWidth: generateMinWidth,
|
|
250
|
+
objectFit: generateObjectFit,
|
|
251
|
+
mixBlendMode: generateMixBlendMode,
|
|
252
|
+
objectPosition: generateObjectPosition,
|
|
253
|
+
opacity: generateOpacity,
|
|
254
|
+
order: generateOrder,
|
|
255
|
+
outlineColor: generateOutlineColor,
|
|
256
|
+
outlineOffset: generateOutlineOffset,
|
|
257
|
+
outlineOpacity: generateOutlineOpacity,
|
|
258
|
+
outlineStyle: generateOutlineStyle,
|
|
259
|
+
outlineWidth: generateOutlineWidth,
|
|
260
|
+
overflow: generateOverflow,
|
|
261
|
+
overscrollBehavior: generateOverscrollBehavior,
|
|
262
|
+
padding: generatePadding,
|
|
263
|
+
placeContent: generatePlaceContent,
|
|
264
|
+
placeItems: generatePlaceItems,
|
|
265
|
+
placeSelf: generatePlaceSelf,
|
|
266
|
+
pointerEvents: generatePointerEvents,
|
|
267
|
+
position: generatePosition,
|
|
268
|
+
resize: generateResize,
|
|
269
|
+
ringColor: generateRingColor,
|
|
270
|
+
ringOffsetColor: generateRingOffsetColor,
|
|
271
|
+
ringOffsetWidth: generateRingOffsetWidth,
|
|
272
|
+
ringOpacity: generateRingOpacity,
|
|
273
|
+
ringWidth: generateRingWidth,
|
|
274
|
+
rotate: generateRotate,
|
|
275
|
+
saturate: generateSaturate,
|
|
276
|
+
scale: generateScale,
|
|
277
|
+
scrollBehavior: generateScrollBehavior,
|
|
278
|
+
scrollMargin: generateScrollMargin,
|
|
279
|
+
scrollPadding: generateScrollPadding,
|
|
280
|
+
scrollSnapAlign: generateScrollSnapAlign,
|
|
281
|
+
scrollSnapStop: generateScrollSnapStop,
|
|
282
|
+
scrollSnapType: generateScrollSnapType,
|
|
283
|
+
sepia: generateSepia,
|
|
284
|
+
size: generateSize,
|
|
285
|
+
skew: generateSkew,
|
|
286
|
+
space: generateSpace,
|
|
287
|
+
stroke: generateStroke,
|
|
288
|
+
strokeWidth: generateStrokeWidth,
|
|
289
|
+
tableLayout: generateTableLayout,
|
|
290
|
+
textAlign: generateTextAlign,
|
|
291
|
+
textColor: generateTextColor,
|
|
292
|
+
textDecoration: generateTextDecoration,
|
|
293
|
+
textDecorationColor: generateTextDecorationColor,
|
|
294
|
+
textDecorationStyle: generateTextDecorationStyle,
|
|
295
|
+
textDecorationThickness: generateTextDecorationThickness,
|
|
296
|
+
textIndent: generateTextIndent,
|
|
297
|
+
textOpacity: generateTextOpacity,
|
|
298
|
+
textOverflow: generateTextOverflow,
|
|
299
|
+
textShadowBlur: generateTextShadowBlur,
|
|
300
|
+
textShadowColor: generateTextShadowColor,
|
|
301
|
+
textShadowOpacity: generateTextShadowOpacity,
|
|
302
|
+
textShadowX: generateTextShadowX,
|
|
303
|
+
textShadowY: generateTextShadowY,
|
|
304
|
+
textTransform: generateTextTransform,
|
|
305
|
+
textUnderlineOffset: generateTextUnderlineOffset,
|
|
306
|
+
textWrap: generateTextWrap,
|
|
307
|
+
touchAction: generateTouchAction,
|
|
308
|
+
transform: generateTransform,
|
|
309
|
+
transformOrigin: generateTransformOrigin,
|
|
310
|
+
translate: generateTranslate,
|
|
311
|
+
userSelect: generateUserSelect,
|
|
312
|
+
verticalAlign: generateVerticalAlign,
|
|
313
|
+
visibility: generateVisibility,
|
|
314
|
+
whitespace: generateWhitespace,
|
|
315
|
+
width: generateWidth,
|
|
316
|
+
willChange: generateWillChange,
|
|
317
|
+
wordBreak: generateWordBreak,
|
|
318
|
+
zIndex: generateZIndex,
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
function parseCustomClassWithPatterns(className) {
|
|
322
|
+
for (const key in patterns) {
|
|
323
|
+
const { regex, cssProp, formatter } = patterns[key];
|
|
324
|
+
const match = className.match(regex);
|
|
325
|
+
if (match) {
|
|
326
|
+
const value = formatter(match[1]);
|
|
327
|
+
return `${cssProp}: ${value};`;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Cache untuk getConfigOptions
|
|
334
|
+
const configOptionsCache = new Map();
|
|
335
|
+
const cacheKey = (options) => JSON.stringify(options);
|
|
336
|
+
|
|
337
|
+
function generateTailwindCssString(options = {}) {
|
|
338
|
+
const pluginKeys = Object.keys(plugins);
|
|
339
|
+
// Menggunakan cache untuk mencegah pemrosesan ulang yang tidak perlu
|
|
340
|
+
const key = cacheKey(options);
|
|
341
|
+
if (!configOptionsCache.has(key)) {
|
|
342
|
+
configOptionsCache.set(key, getConfigOptions(options, pluginKeys));
|
|
343
|
+
limitCacheSize(configOptionsCache);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const configOptions = configOptionsCache.get(key);
|
|
347
|
+
const { corePlugins = {} } = configOptions;
|
|
348
|
+
const corePluginKeys = Object.keys(corePlugins);
|
|
349
|
+
|
|
350
|
+
let cssString = ``;
|
|
351
|
+
Object.keys(plugins).forEach((key) => {
|
|
352
|
+
if (corePluginKeys.indexOf(key) >= 0 && !corePlugins[key]) {
|
|
353
|
+
cssString += "";
|
|
354
|
+
} else {
|
|
355
|
+
cssString += plugins[key](configOptions);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
return cssString;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function convertCssToObject(cssString) {
|
|
362
|
+
const obj = {};
|
|
363
|
+
const regex = /([a-zA-Z0-9\-_\\/.]+)\s*{\s*([^}]+)\s*}/g;
|
|
364
|
+
let match;
|
|
365
|
+
|
|
366
|
+
while ((match = regex.exec(cssString)) !== null) {
|
|
367
|
+
const className = match[1].replace(/\\\\/g, "\\").replace(/^_/, "");
|
|
368
|
+
const cssRules = match[2].trim().replace(/\s+/g, " ");
|
|
369
|
+
obj[className] = cssRules;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return obj;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
let twString = null;
|
|
376
|
+
let cssObject = null;
|
|
377
|
+
|
|
378
|
+
if (!twString) {
|
|
379
|
+
twString = generateTailwindCssString().replace(/\s\s+/g, " ");
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (!cssObject) {
|
|
383
|
+
cssObject = convertCssToObject(twString);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const breakpoints = {
|
|
387
|
+
sm: "@media (min-width: 640px)",
|
|
388
|
+
md: "@media (min-width: 768px)",
|
|
389
|
+
lg: "@media (min-width: 1024px)",
|
|
390
|
+
xl: "@media (min-width: 1280px)",
|
|
391
|
+
"2xl": "@media (min-width: 1536px)",
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
const pseudoVariants = new Set([
|
|
395
|
+
"hover",
|
|
396
|
+
"focus",
|
|
397
|
+
"focus-within",
|
|
398
|
+
"active",
|
|
399
|
+
"visited",
|
|
400
|
+
"disabled",
|
|
401
|
+
"first",
|
|
402
|
+
"last",
|
|
403
|
+
"checked",
|
|
404
|
+
"invalid",
|
|
405
|
+
"required",
|
|
406
|
+
]);
|
|
407
|
+
|
|
408
|
+
const specialVariants = {
|
|
409
|
+
group: (state, sel) => `.group:${state} ${sel}`,
|
|
410
|
+
peer: (state, sel) => `.peer:${state} ~ ${sel}`,
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
const selectorVariants = {
|
|
414
|
+
first: () => `> :first-child`,
|
|
415
|
+
last: () => `> :last-child`,
|
|
416
|
+
odd: () => `> :nth-child(odd)`,
|
|
417
|
+
even: () => `> :nth-child(even)`,
|
|
418
|
+
not: (arg) => `> :not(${arg})`,
|
|
419
|
+
number: (arg) => `> :nth-child(${arg})`,
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
// Mengoptimalkan encoding/decoding bracket values dengan memoization
|
|
423
|
+
const encodeBracketCache = new Map();
|
|
424
|
+
function encodeBracketValues(input) {
|
|
425
|
+
if (!input) return input;
|
|
426
|
+
if (encodeBracketCache.has(input)) return encodeBracketCache.get(input);
|
|
427
|
+
|
|
428
|
+
const result = input.replace(/\[([^\]]+)\]/g, (_, content) => {
|
|
429
|
+
const encoded = encodeURIComponent(content)
|
|
430
|
+
.replace(/\(/g, "__P__")
|
|
431
|
+
.replace(/\)/g, "__C__");
|
|
432
|
+
return `[${encoded}]`;
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
encodeBracketCache.set(input, result);
|
|
436
|
+
limitCacheSize(encodeBracketCache);
|
|
437
|
+
return result;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const decodeBracketCache = new Map();
|
|
441
|
+
function decodeBracketValues(input) {
|
|
442
|
+
if (!input) return input;
|
|
443
|
+
if (decodeBracketCache.has(input)) return decodeBracketCache.get(input);
|
|
444
|
+
|
|
445
|
+
const result = decodeURIComponent(input)
|
|
446
|
+
.replace(/__P__/g, "(")
|
|
447
|
+
.replace(/__C__/g, ")");
|
|
448
|
+
|
|
449
|
+
decodeBracketCache.set(input, result);
|
|
450
|
+
limitCacheSize(decodeBracketCache);
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function replaceSelector(selector) {
|
|
455
|
+
return selector.replace(
|
|
456
|
+
/c-(first|last|odd|even|\d+|not\([^)]+\))/g,
|
|
457
|
+
(_, raw) => {
|
|
458
|
+
if (/^\d+$/.test(raw)) return selectorVariants.number(raw);
|
|
459
|
+
const notMatch = raw.match(/^not\(([^)]+)\)$/);
|
|
460
|
+
if (notMatch) return selectorVariants.not(notMatch[1]);
|
|
461
|
+
if (selectorVariants[raw]) return selectorVariants[raw]();
|
|
462
|
+
return raw;
|
|
463
|
+
}
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function resolveVariants(selector, variants) {
|
|
468
|
+
let media = null;
|
|
469
|
+
let finalSelector = selector;
|
|
470
|
+
|
|
471
|
+
for (const v of variants) {
|
|
472
|
+
if (breakpoints[v]) {
|
|
473
|
+
media = breakpoints[v];
|
|
474
|
+
} else if (pseudoVariants.has(v)) {
|
|
475
|
+
finalSelector += `:${v}`;
|
|
476
|
+
} else {
|
|
477
|
+
for (const key in specialVariants) {
|
|
478
|
+
if (v.startsWith(`${key}-`)) {
|
|
479
|
+
const state = v.slice(key.length + 1);
|
|
480
|
+
finalSelector = specialVariants[key](state, finalSelector);
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return { media, finalSelector };
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
function inlineStyleToJson(styleString) {
|
|
491
|
+
const styles = styleString.split(";").filter((style) => style.trim() !== "");
|
|
492
|
+
const styleObject = {};
|
|
493
|
+
|
|
494
|
+
styles.forEach((style) => {
|
|
495
|
+
const [key, value] = style.split(":").map((s) => s.trim());
|
|
496
|
+
if (key && value) {
|
|
497
|
+
const camelCaseKey = key.replace(/-([a-z])/g, (_, letter) =>
|
|
498
|
+
letter.toUpperCase()
|
|
499
|
+
);
|
|
500
|
+
styleObject[camelCaseKey] = value;
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
return styleObject;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Cache untuk CSS resolusi
|
|
508
|
+
const cssResolutionCache = new Map();
|
|
509
|
+
|
|
510
|
+
function separateAndResolveCSS(arr) {
|
|
511
|
+
// Membuat kunci cache const cacheKey = arr.join('|');
|
|
512
|
+
if (cssResolutionCache.has(cacheKey)) {
|
|
513
|
+
return cssResolutionCache.get(cacheKey);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Batasi ukuran cache untuk menghindari memory leak
|
|
517
|
+
limitCacheSize(cssResolutionCache);
|
|
518
|
+
|
|
519
|
+
const cssProperties = {};
|
|
520
|
+
arr.forEach((item) => {
|
|
521
|
+
if (!item) return;
|
|
522
|
+
|
|
523
|
+
const declarations = item
|
|
524
|
+
.split(";")
|
|
525
|
+
.map((decl) => decl.trim())
|
|
526
|
+
.filter((decl) => decl);
|
|
527
|
+
|
|
528
|
+
declarations.forEach((declaration) => {
|
|
529
|
+
const colonIndex = declaration.indexOf(':');
|
|
530
|
+
if (colonIndex === -1) return;
|
|
531
|
+
|
|
532
|
+
const key = declaration.substring(0, colonIndex).trim();
|
|
533
|
+
const value = declaration.substring(colonIndex + 1).trim();
|
|
534
|
+
|
|
535
|
+
if (key && value) {
|
|
536
|
+
// Prioritaskan nilai yang lebih spesifik (misalnya !important)
|
|
537
|
+
if (value.includes('!important') || !cssProperties[key]) {
|
|
538
|
+
cssProperties[key] = value;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
const resolvedProperties = { ...cssProperties };
|
|
545
|
+
|
|
546
|
+
const resolveValue = (value, variables) => {
|
|
547
|
+
if (!value || !value.includes('var(')) return value;
|
|
548
|
+
|
|
549
|
+
return value.replace(
|
|
550
|
+
/var\((--[a-zA-Z0-9-]+)(?:,\s*([^)]+))?\)/g,
|
|
551
|
+
(match, variable, fallback) => {
|
|
552
|
+
return variables[variable] || fallback || match;
|
|
553
|
+
}
|
|
554
|
+
);
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
// Resolve variables
|
|
558
|
+
Object.keys(resolvedProperties).forEach((key) => {
|
|
559
|
+
resolvedProperties[key] = resolveValue(
|
|
560
|
+
resolvedProperties[key],
|
|
561
|
+
resolvedProperties
|
|
562
|
+
);
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
// Remove CSS variables after resolution
|
|
566
|
+
Object.keys(resolvedProperties).forEach((key) => {
|
|
567
|
+
if (key.startsWith("--")) {
|
|
568
|
+
delete resolvedProperties[key];
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
const result = Object.entries(resolvedProperties)
|
|
573
|
+
.map(([key, value]) => `${key}: ${value};`)
|
|
574
|
+
.join(" ");
|
|
575
|
+
|
|
576
|
+
cssResolutionCache.set(cacheKey, result);
|
|
577
|
+
return result;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Fungsi untuk membatasi ukuran cache untuk mencegah memory leak
|
|
581
|
+
function limitCacheSize(cache, maxSize = 1000) {
|
|
582
|
+
if (cache.size > maxSize) {
|
|
583
|
+
// Hapus 20% entri yang paling lama
|
|
584
|
+
const entriesToRemove = Math.floor(cache.size * 0.2);
|
|
585
|
+
const keys = Array.from(cache.keys()).slice(0, entriesToRemove);
|
|
586
|
+
keys.forEach(key => cache.delete(key));
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Implementasi fungsi debounce untuk mengoptimalkan panggilan berulang
|
|
591
|
+
function debounce(func, wait = 100) {
|
|
592
|
+
let timeout;
|
|
593
|
+
return function(...args) {
|
|
594
|
+
const context = this;
|
|
595
|
+
clearTimeout(timeout);
|
|
596
|
+
timeout = setTimeout(() => func.apply(context, args), wait);
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Mengkonversi string kelas Tailwind menjadi inline styles CSS atau objek JSON
|
|
602
|
+
* @param {string} classNames - String berisi kelas Tailwind yang akan dikonversi
|
|
603
|
+
* @param {boolean} convertToJson - Jika true, hasil akan menjadi objek JSON, jika false menjadi string CSS
|
|
604
|
+
* @returns {string|Object} String CSS inline atau objek style JSON
|
|
605
|
+
*/
|
|
606
|
+
export function tws(classNames, convertToJson) {
|
|
607
|
+
if (
|
|
608
|
+
[
|
|
609
|
+
!classNames,
|
|
610
|
+
typeof classNames !== "string",
|
|
611
|
+
classNames.trim() === "",
|
|
612
|
+
].includes(true)
|
|
613
|
+
) {
|
|
614
|
+
return convertToJson ? {} : "";
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
let classes;
|
|
618
|
+
try {
|
|
619
|
+
classes = classNames.match(/[\w-]+\[[^\]]+\]|[\w-]+\.\d+|[\w-]+/g);
|
|
620
|
+
|
|
621
|
+
// Jika tidak ada class yang valid ditemukan
|
|
622
|
+
if (!classes || classes.length === 0) {
|
|
623
|
+
console.warn(`No valid Tailwind classes found in input: "${classNames}"`);
|
|
624
|
+
return convertToJson ? {} : "";
|
|
625
|
+
}
|
|
626
|
+
} catch (error) {
|
|
627
|
+
console.error(`Error parsing Tailwind classes: ${error.message}`);
|
|
628
|
+
return convertToJson ? {} : "";
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
let cssResult = classes.map((className) => {
|
|
632
|
+
if (cssObject[className]) {
|
|
633
|
+
return cssObject[className];
|
|
634
|
+
} else if (className.includes("[")) {
|
|
635
|
+
const match = className.match(/\[([^\]]+)\]/);
|
|
636
|
+
if (match) {
|
|
637
|
+
const customValue = match[1];
|
|
638
|
+
const baseKey = className.split("[")[0];
|
|
639
|
+
if (cssObject[`${baseKey}custom`]) {
|
|
640
|
+
return cssObject[`${baseKey}custom`].replace(
|
|
641
|
+
/custom_value/g,
|
|
642
|
+
customValue
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return "";
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
cssResult = separateAndResolveCSS(cssResult);
|
|
651
|
+
|
|
652
|
+
if (convertToJson) {
|
|
653
|
+
cssResult = inlineStyleToJson(cssResult);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return cssResult;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Menghasilkan string CSS dari objek style dengan sintaks mirip SCSS
|
|
661
|
+
* Mendukung nested selectors, state variants, responsive variants, dan @css directives
|
|
662
|
+
* @param {Object} obj - Objek dengan format style mirip SCSS
|
|
663
|
+
* @returns {string} String CSS yang dihasilkan
|
|
664
|
+
*/
|
|
665
|
+
export function twsx(obj) {
|
|
666
|
+
if (!obj || typeof obj !== 'object') {
|
|
667
|
+
console.warn('twsx: Expected an object but received:', obj);
|
|
668
|
+
return '';
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const styles = {};
|
|
672
|
+
|
|
673
|
+
function expandGroupedClass(input) {
|
|
674
|
+
function expandDirectiveGroups(str) {
|
|
675
|
+
return str.replace(/(\w+)\(([^()]+)\)/g, (_, directive, content) => {
|
|
676
|
+
return content
|
|
677
|
+
.trim()
|
|
678
|
+
.split(/\s+/)
|
|
679
|
+
.map((val) => {
|
|
680
|
+
if (val.includes(":")) {
|
|
681
|
+
const [variant, v] = val.split(":");
|
|
682
|
+
const prefix = v.startsWith("-") ? "-" : "";
|
|
683
|
+
const value = v.startsWith("-") ? v.slice(1) : v;
|
|
684
|
+
return `${variant}:${prefix}${directive}-${value}`;
|
|
685
|
+
}
|
|
686
|
+
const prefix = val.startsWith("-") ? "-" : "";
|
|
687
|
+
const value = val.startsWith("-") ? val.slice(1) : val;
|
|
688
|
+
return `${prefix}${directive}-${value}`;
|
|
689
|
+
})
|
|
690
|
+
.join(" ");
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
function expandVariants(str, parent = "") {
|
|
695
|
+
return str.replace(
|
|
696
|
+
/(\w+):\(([^()]+(?:\((?:[^()]+)\))?[^()]*)\)/g,
|
|
697
|
+
(_, variant, content) => {
|
|
698
|
+
return content
|
|
699
|
+
.trim()
|
|
700
|
+
.split(/\s+/)
|
|
701
|
+
.map((c) => {
|
|
702
|
+
if (/\w+:\(.*\)/.test(c)) {
|
|
703
|
+
return expandVariants(
|
|
704
|
+
c,
|
|
705
|
+
parent ? `${parent}:${variant}` : variant
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
return `${parent ? `${parent}:${variant}` : variant}:${c}`;
|
|
709
|
+
})
|
|
710
|
+
.join(" ");
|
|
711
|
+
}
|
|
712
|
+
);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
let result = encodeBracketValues(input);
|
|
716
|
+
let prev;
|
|
717
|
+
|
|
718
|
+
do {
|
|
719
|
+
prev = result;
|
|
720
|
+
result = expandVariants(result);
|
|
721
|
+
result = expandDirectiveGroups(result);
|
|
722
|
+
} while (result !== prev);
|
|
723
|
+
|
|
724
|
+
return result;
|
|
725
|
+
} function walk(selector, val) {
|
|
726
|
+
if (!selector || typeof selector !== 'string') {
|
|
727
|
+
console.warn('Invalid selector in walk function:', selector);
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
const { baseSelector, cssProperty } = parseSelector(selector);
|
|
732
|
+
if (
|
|
733
|
+
cssProperty &&
|
|
734
|
+
typeof val === "object" &&
|
|
735
|
+
Array.isArray(val) &&
|
|
736
|
+
val.length > 0
|
|
737
|
+
) {
|
|
738
|
+
const cssValue = val[0];
|
|
739
|
+
if (typeof cssValue === "string") {
|
|
740
|
+
styles[baseSelector] = styles[baseSelector] || "";
|
|
741
|
+
styles[baseSelector] += `${cssProperty}: ${cssValue};\n`;
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
if (Array.isArray(val)) {
|
|
747
|
+
const [base, nested] = val;
|
|
748
|
+
|
|
749
|
+
if (typeof base !== "string") {
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
for (const cls of base.split(" ")) {
|
|
754
|
+
if (cls.trim() === "") continue;
|
|
755
|
+
|
|
756
|
+
const [rawVariants, className] = cls.includes(":")
|
|
757
|
+
? [cls.split(":").slice(0, -1), cls.split(":").slice(-1)[0]]
|
|
758
|
+
: [[], cls];
|
|
759
|
+
|
|
760
|
+
let isImportant = false;
|
|
761
|
+
let pureClassName = className;
|
|
762
|
+
|
|
763
|
+
if (className.startsWith("!")) {
|
|
764
|
+
isImportant = true;
|
|
765
|
+
pureClassName = className.slice(1);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
const { media, finalSelector } = resolveVariants(selector, rawVariants);
|
|
769
|
+
|
|
770
|
+
let declarations =
|
|
771
|
+
cssObject[pureClassName] ||
|
|
772
|
+
cssObject[pureClassName.replace(/(\/)/g, "\\$1")] ||
|
|
773
|
+
cssObject[pureClassName.replace(/\./g, "\\.")];
|
|
774
|
+
|
|
775
|
+
if (!declarations && pureClassName.includes("[")) {
|
|
776
|
+
const match = pureClassName.match(/^(.+?)\[(.+)\]$/);
|
|
777
|
+
if (match) {
|
|
778
|
+
const [, prefix, dynamicValue] = match;
|
|
779
|
+
const customKey = `${prefix}custom`;
|
|
780
|
+
const template = cssObject[customKey];
|
|
781
|
+
if (template) {
|
|
782
|
+
declarations = template.replace(
|
|
783
|
+
/custom_value/g,
|
|
784
|
+
decodeBracketValues(dynamicValue)
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
if (!declarations) {
|
|
791
|
+
declarations = parseCustomClassWithPatterns(pureClassName);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
if (!declarations) {
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
if (isImportant) {
|
|
799
|
+
declarations = declarations.replace(
|
|
800
|
+
/([^:;]+):([^;]+)(;?)/g,
|
|
801
|
+
(_, prop, value) => {
|
|
802
|
+
return prop.trim().startsWith("--")
|
|
803
|
+
? `${prop}:${value};`
|
|
804
|
+
: `${prop}:${value.trim()} !important;`;
|
|
805
|
+
}
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
const isSpaceOrDivide = [
|
|
810
|
+
"space-x-",
|
|
811
|
+
"-space-x-",
|
|
812
|
+
"space-y-",
|
|
813
|
+
"-space-y-",
|
|
814
|
+
"divide-",
|
|
815
|
+
].some((prefix) => pureClassName.startsWith(prefix));
|
|
816
|
+
|
|
817
|
+
const expandedSelector = replaceSelector(finalSelector);
|
|
818
|
+
const targetSelector = isSpaceOrDivide
|
|
819
|
+
? `${expandedSelector} > :not([hidden]) ~ :not([hidden])`
|
|
820
|
+
: expandedSelector;
|
|
821
|
+
|
|
822
|
+
if (media) {
|
|
823
|
+
styles[media] = styles[media] || {};
|
|
824
|
+
styles[media][targetSelector] = styles[media][targetSelector] || "";
|
|
825
|
+
styles[media][targetSelector] += declarations + "\n";
|
|
826
|
+
} else {
|
|
827
|
+
styles[targetSelector] = styles[targetSelector] || "";
|
|
828
|
+
styles[targetSelector] += declarations + "\n";
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
for (const nestedSel in nested) {
|
|
833
|
+
const nestedVal = nested[nestedSel];
|
|
834
|
+
if (nestedSel === "@css" && typeof nestedVal === "object") {
|
|
835
|
+
const cssDeclarations = Object.entries(nestedVal)
|
|
836
|
+
.map(([key, value]) => `${key}: ${value};`)
|
|
837
|
+
.join(" ");
|
|
838
|
+
|
|
839
|
+
if (selector in styles) {
|
|
840
|
+
styles[selector] += cssDeclarations + "\n";
|
|
841
|
+
} else {
|
|
842
|
+
styles[selector] = cssDeclarations + "\n";
|
|
843
|
+
}
|
|
844
|
+
continue;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
const combinedSel = nestedSel.includes("&")
|
|
848
|
+
? nestedSel.replace(/&/g, selector)
|
|
849
|
+
: `${selector} ${nestedSel}`;
|
|
850
|
+
walk(combinedSel, nestedVal);
|
|
851
|
+
}
|
|
852
|
+
} else if (typeof val === "string") {
|
|
853
|
+
if (val.trim() === "") return;
|
|
854
|
+
|
|
855
|
+
walk(selector, [expandGroupedClass(val)]);
|
|
856
|
+
} else if (typeof val === "object" && val !== null) {
|
|
857
|
+
const { baseSelector, cssProperty } = parseSelector(selector);
|
|
858
|
+
if (cssProperty) {
|
|
859
|
+
const cssValue = Object.values(val).join(" ");
|
|
860
|
+
styles[baseSelector] = styles[baseSelector] || "";
|
|
861
|
+
styles[baseSelector] += `${cssProperty}: ${cssValue};\n`;
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
const cssDeclarations = Object.entries(val)
|
|
866
|
+
.map(([key, value]) => `${key}: ${value};`)
|
|
867
|
+
.join(" ");
|
|
868
|
+
|
|
869
|
+
if (selector in styles) {
|
|
870
|
+
styles[selector] += cssDeclarations + "\n";
|
|
871
|
+
} else {
|
|
872
|
+
styles[selector] = cssDeclarations + "\n";
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// Menambahkan memoization untuk parseSelector
|
|
878
|
+
const parseSelectorCache = new Map();
|
|
879
|
+
function parseSelector(selector) {
|
|
880
|
+
if (parseSelectorCache.has(selector)) {
|
|
881
|
+
return parseSelectorCache.get(selector);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
let result;
|
|
885
|
+
if (selector.includes('@css')) {
|
|
886
|
+
const parts = selector.split('@css');
|
|
887
|
+
const baseSelector = parts[0].trim();
|
|
888
|
+
const cssProperty = parts[1]?.trim();
|
|
889
|
+
result = { baseSelector, cssProperty };
|
|
890
|
+
} else {
|
|
891
|
+
result = { baseSelector: selector, cssProperty: null };
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
parseSelectorCache.set(selector, result);
|
|
895
|
+
limitCacheSize(parseSelectorCache);
|
|
896
|
+
return result;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
function isSelectorObject(val) {
|
|
900
|
+
return typeof val === "object" && val !== null && !Array.isArray(val);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
function flatten(obj, parentSelector = "") {
|
|
904
|
+
const result = {};
|
|
905
|
+
|
|
906
|
+
for (const selector in obj) {
|
|
907
|
+
const val = obj[selector];
|
|
908
|
+
const currentSelector = parentSelector
|
|
909
|
+
? selector.includes("&")
|
|
910
|
+
? selector.replace(/&/g, parentSelector)
|
|
911
|
+
: `${parentSelector} ${selector}`
|
|
912
|
+
: selector;
|
|
913
|
+
|
|
914
|
+
if (typeof val === "string") {
|
|
915
|
+
result[currentSelector] = val;
|
|
916
|
+
} else if (Array.isArray(val)) {
|
|
917
|
+
const flatArray = [];
|
|
918
|
+
for (const item of val) {
|
|
919
|
+
if (typeof item === "string") {
|
|
920
|
+
flatArray.push(item);
|
|
921
|
+
} else if (isSelectorObject(item)) {
|
|
922
|
+
const nested = flatten(item, currentSelector);
|
|
923
|
+
Object.assign(result, nested);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
if (flatArray.length > 0) {
|
|
927
|
+
result[currentSelector] = result[currentSelector] || [];
|
|
928
|
+
result[currentSelector].push(...flatArray);
|
|
929
|
+
}
|
|
930
|
+
} else if (isSelectorObject(val)) {
|
|
931
|
+
const nested = flatten(val, currentSelector);
|
|
932
|
+
Object.assign(result, nested);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return result;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
const flattened = flatten(obj);
|
|
940
|
+
|
|
941
|
+
for (const selector in flattened) {
|
|
942
|
+
let val = flattened[selector];
|
|
943
|
+
let baseClass = "";
|
|
944
|
+
let nested = {};
|
|
945
|
+
|
|
946
|
+
if (typeof val === "string") {
|
|
947
|
+
baseClass = expandGroupedClass(val);
|
|
948
|
+
} else if (Array.isArray(val)) {
|
|
949
|
+
for (const item of val) {
|
|
950
|
+
if (typeof item === "string") {
|
|
951
|
+
baseClass += (baseClass ? " " : "") + expandGroupedClass(item);
|
|
952
|
+
} else if (typeof item === "object" && item !== null) {
|
|
953
|
+
Object.assign(nested, item);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
walk(selector, [baseClass, nested]);
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
let cssString = "";
|
|
962
|
+
|
|
963
|
+
const baseStyles = [];
|
|
964
|
+
const mediaStyles = [];
|
|
965
|
+
|
|
966
|
+
for (const sel in styles) {
|
|
967
|
+
if (!sel.startsWith("@media")) {
|
|
968
|
+
baseStyles.push({ sel, css: styles[sel] });
|
|
969
|
+
} else {
|
|
970
|
+
mediaStyles.push({ sel, content: styles[sel] });
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
for (const { sel, css } of baseStyles) {
|
|
975
|
+
cssString += `${sel}{${css.trim().replace(/\n/g, "")}}`;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
function mediaPriority(sel) {
|
|
979
|
+
const match = sel.match(/@media \(min-width: (\d+)px\)/);
|
|
980
|
+
return match ? parseInt(match[1], 10) : 99999;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
mediaStyles.sort((a, b) => mediaPriority(a.sel) - mediaPriority(b.sel));
|
|
984
|
+
|
|
985
|
+
for (const { sel, content } of mediaStyles) {
|
|
986
|
+
cssString += `${sel}{`;
|
|
987
|
+
for (const subSel in content) {
|
|
988
|
+
cssString += `${subSel}{${content[subSel].trim().replace(/\n/g, "")}}`;
|
|
989
|
+
}
|
|
990
|
+
cssString += `}`;
|
|
991
|
+
}
|
|
992
|
+
return cssString.trim();
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
// Daftarkan versi debounced dari fungsi-fungsi export
|
|
996
|
+
/**
|
|
997
|
+
* Versi debounced dari fungsi tws
|
|
998
|
+
* Membantu mengoptimalkan performa ketika memanggil tws berulang kali
|
|
999
|
+
* @param {string} classNames - String berisi kelas Tailwind yang akan dikonversi
|
|
1000
|
+
* @param {boolean} convertToJson - Jika true, hasil akan menjadi objek JSON, jika false menjadi string CSS
|
|
1001
|
+
* @returns {string|Object} String CSS inline atau objek style JSON
|
|
1002
|
+
*/
|
|
1003
|
+
export const debouncedTws = debounce(tws);
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* Versi debounced dari fungsi twsx
|
|
1007
|
+
* Membantu mengoptimalkan performa ketika memanggil twsx berulang kali
|
|
1008
|
+
* @param {Object} obj - Objek dengan format style mirip SCSS
|
|
1009
|
+
* @returns {string} String CSS yang dihasilkan
|
|
1010
|
+
*/
|
|
1011
|
+
export const debouncedTwsx = debounce(twsx);
|
|
1012
|
+
|
|
1013
|
+
|