tailwind-to-style 2.7.0 → 2.7.2

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/README.md CHANGED
@@ -79,8 +79,8 @@ This will apply the Tailwind classes directly as inline styles in the React comp
79
79
 
80
80
  #### Features of `twsx`:
81
81
  - Allows **nested styles** similar to SCSS, enabling more complex CSS structures.
82
- - **Grouping**: Supports grouping utilities inside parentheses, making the code more readable and modular.
83
- - Fully supports **responsive variants** (`sm`, `md`, `lg`, etc.).
82
+ - **Grouping**: Supports grouping utilities inside parentheses, including responsive variants.
83
+ - Supports **responsive variants** (`sm`, `md`, `lg`, etc.) when used within Tailwind utility classes or in grouping syntax.
84
84
  - Handles **state variants** like `hover`, `focus`, and more.
85
85
  - Supports **dynamic utilities** such as `w-[300px]`, `bg-[rgba(0,0,0,0.5)]`.
86
86
  - **@css directive**: Apply custom CSS properties directly for more complex styles like transitions and animations.
@@ -232,6 +232,62 @@ console.log(styles);
232
232
  }
233
233
  ```
234
234
 
235
+ #### Responsive Variants:
236
+
237
+ Responsive variants work within Tailwind utility classes and in grouping syntax:
238
+
239
+ ```javascript
240
+ const styles = twsx({
241
+ ".responsive-card": [
242
+ "w-full md:w-1/2 lg:w-1/3 p-4 bg-white",
243
+ {
244
+ "&:hover": "shadow-lg transform:scale-105"
245
+ }
246
+ ],
247
+ ".grouped-responsive": "text-sm md:(text-lg px-6) lg:(text-xl px-8)"
248
+ });
249
+ ```
250
+
251
+ **Output**:
252
+ ```css
253
+ .responsive-card {
254
+ width: 100%;
255
+ padding: 1rem;
256
+ background-color: white;
257
+ }
258
+ @media (min-width: 768px) {
259
+ .responsive-card {
260
+ width: 50%;
261
+ }
262
+ }
263
+ @media (min-width: 1024px) {
264
+ .responsive-card {
265
+ width: 33.333333%;
266
+ }
267
+ }
268
+ .responsive-card:hover {
269
+ box-shadow: 0 10px 15px rgba(0,0,0,0.1);
270
+ transform: scale(1.05);
271
+ }
272
+ .grouped-responsive {
273
+ font-size: 0.875rem;
274
+ }
275
+ @media (min-width: 768px) {
276
+ .grouped-responsive {
277
+ font-size: 1.125rem;
278
+ padding-left: 1.5rem;
279
+ padding-right: 1.5rem;
280
+ }
281
+ }
282
+ @media (min-width: 1024px) {
283
+ .grouped-responsive {
284
+ font-size: 1.25rem;
285
+ padding-left: 2rem;
286
+ padding-right: 2rem;
287
+ }
288
+ }
289
+ ```
290
+
235
291
  #### `@css` Direct CSS Properties:
236
292
 
237
293
  With the `@css` feature, you can directly add CSS properties that aren't available as Tailwind utilities or when you need more complex CSS values like transitions, animations, or custom properties.
@@ -285,7 +341,7 @@ The `@css` feature is particularly helpful for properties that require complex v
285
341
 
286
342
  #### Advanced `@css` Examples:
287
343
 
288
- You can combine `@css` with responsive and state variants:
344
+ You can combine `@css` with state variants:
289
345
 
290
346
  ```javascript
291
347
  const styles = twsx({
@@ -293,20 +349,18 @@ const styles = twsx({
293
349
  "bg-white rounded-lg shadow-xl",
294
350
  {
295
351
  "@css": {
296
- transform: "translateY(0)",
297
- transition: "transform 0.3s ease-out, opacity 0.2s ease-in-out",
352
+ transform: "translateX(0px)",
353
+ transition: "all 0.3s ease-out",
298
354
  "will-change": "transform, opacity"
299
355
  },
300
356
  "&.hidden": [
301
357
  "opacity-0",
302
358
  {
303
359
  "@css": {
304
- transform: "translateY(-20px)"
360
+ transform: "translateX(-100px)"
305
361
  }
306
362
  }
307
- ],
308
- "md:@css width": "500px",
309
- "lg:@css width": "700px"
363
+ ]
310
364
  }
311
365
  ]
312
366
  });
@@ -318,26 +372,24 @@ const styles = twsx({
318
372
  background-color: white;
319
373
  border-radius: 0.5rem;
320
374
  box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
321
- transform: translateY(0);
322
- transition: transform 0.3s ease-out, opacity 0.2s ease-in-out;
375
+ transform: translateX(0px);
376
+ transition: all 0.3s ease-out;
323
377
  will-change: transform, opacity;
324
378
  }
325
379
  .modal.hidden {
326
380
  opacity: 0;
327
- transform: translateY(-20px);
328
- }
329
- @media (min-width: 768px) {
330
- .modal {
331
- width: 500px;
332
- }
333
- }
334
- @media (min-width: 1024px) {
335
- .modal {
336
- width: 700px;
337
- }
381
+ transform: translateX(-100px);
338
382
  }
339
383
  ```
340
384
 
385
+ For responsive styles, you can use standard Tailwind responsive utilities within your classes:
386
+
387
+ ```javascript
388
+ const styles = twsx({
389
+ ".responsive-box": "w-full md:w-1/2 lg:w-1/3 p-4 bg-blue-500"
390
+ });
391
+ ```
392
+
341
393
  The `@css` feature provides a powerful way to bridge the gap between Tailwind's utility classes and custom CSS when needed, without leaving the `twsx` syntax.
342
394
 
343
395
  ### Inject Option (Browser Only)
@@ -430,9 +482,9 @@ const complexStyles = twsx({
430
482
  ".hero": [
431
483
  "bg-gradient-to-br from-indigo-900 to-purple-900 min-h-screen",
432
484
  {
433
- "h1": "text-6xl font-bold text-white",
434
- "@media (max-width: 768px)": {
435
- "h1": "text-4xl"
485
+ "h1": "text-6xl font-bold text-white md:text-4xl",
486
+ "@css": {
487
+ transition: "font-size 0.3s ease-in-out"
436
488
  }
437
489
  }
438
490
  ]
@@ -1,5 +1,5 @@
1
1
  /**
2
- * tailwind-to-style v2.7.0
2
+ * tailwind-to-style v2.7.2
3
3
  * Convert tailwind classes to inline style
4
4
  *
5
5
  * @author Bigetion
@@ -6342,13 +6342,13 @@ var tailwindToStyle = (function (exports) {
6342
6342
  }).join(" ");
6343
6343
  }
6344
6344
 
6345
- // Cache untuk getConfigOptions
6345
+ // Cache for getConfigOptions
6346
6346
  const configOptionsCache = new Map();
6347
6347
  const cacheKey = options => JSON.stringify(options);
6348
6348
  function generateTailwindCssString() {
6349
6349
  let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
6350
6350
  const pluginKeys = Object.keys(plugins);
6351
- // Menggunakan cache untuk mencegah pemrosesan ulang yang tidak perlu
6351
+ // Use cache to prevent unnecessary reprocessing
6352
6352
  const key = cacheKey(options);
6353
6353
  if (!configOptionsCache.has(key)) {
6354
6354
  configOptionsCache.set(key, getConfigOptions(options, pluginKeys));
@@ -6409,7 +6409,7 @@ var tailwindToStyle = (function (exports) {
6409
6409
  number: arg => `> :nth-child(${arg})`
6410
6410
  };
6411
6411
 
6412
- // Mengoptimalkan encoding/decoding bracket values dengan memoization
6412
+ // Optimize encoding/decoding bracket values with memoization
6413
6413
  const encodeBracketCache = new Map();
6414
6414
  function encodeBracketValues(input) {
6415
6415
  if (!input) return input;
@@ -6476,7 +6476,7 @@ var tailwindToStyle = (function (exports) {
6476
6476
  return styleObject;
6477
6477
  }
6478
6478
 
6479
- // Cache untuk CSS resolusi
6479
+ // Cache for CSS resolution
6480
6480
  const cssResolutionCache = new Map();
6481
6481
 
6482
6482
  // Enhanced cache management with performance monitoring
@@ -6484,7 +6484,7 @@ var tailwindToStyle = (function (exports) {
6484
6484
  let maxSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000;
6485
6485
  if (cache.size > maxSize) {
6486
6486
  const cleanupMarker = performanceMonitor.start("cache:cleanup");
6487
- // Hapus 20% entri yang paling lama
6487
+ // Remove 20% of the oldest entries
6488
6488
  const entriesToRemove = Math.floor(cache.size * 0.2);
6489
6489
  const keys = Array.from(cache.keys()).slice(0, entriesToRemove);
6490
6490
  keys.forEach(key => cache.delete(key));
@@ -6523,14 +6523,14 @@ var tailwindToStyle = (function (exports) {
6523
6523
  function separateAndResolveCSS(arr) {
6524
6524
  const marker = performanceMonitor.start("css:resolve");
6525
6525
  try {
6526
- // Perbaiki: cacheKey harus unik untuk setiap input array
6526
+ // Fix: cacheKey must be unique for each input array
6527
6527
  const cacheKey = Array.isArray(arr) ? arr.join("|") : String(arr);
6528
6528
  if (cssResolutionCache.has(cacheKey)) {
6529
6529
  performanceMonitor.end(marker);
6530
6530
  return cssResolutionCache.get(cacheKey);
6531
6531
  }
6532
6532
 
6533
- // Batasi ukuran cache untuk menghindari memory leak
6533
+ // Limit cache size to avoid memory leaks
6534
6534
  limitCacheSize(cssResolutionCache);
6535
6535
  const cssProperties = {};
6536
6536
  arr.forEach(item => {
@@ -6543,7 +6543,7 @@ var tailwindToStyle = (function (exports) {
6543
6543
  const key = declaration.substring(0, colonIndex).trim();
6544
6544
  const value = declaration.substring(colonIndex + 1).trim();
6545
6545
  if (key && value) {
6546
- // Prioritaskan nilai yang lebih spesifik (misalnya !important)
6546
+ // Prioritize more specific values (e.g., !important)
6547
6547
  if (value.includes("!important") || !cssProperties[key]) {
6548
6548
  cssProperties[key] = value;
6549
6549
  }
@@ -6594,10 +6594,75 @@ var tailwindToStyle = (function (exports) {
6594
6594
  }
6595
6595
 
6596
6596
  /**
6597
- * Mengkonversi string kelas Tailwind menjadi inline styles CSS atau objek JSON
6598
- * @param {string} classNames - String berisi kelas Tailwind yang akan dikonversi
6599
- * @param {boolean} convertToJson - Jika true, hasil akan menjadi objek JSON, jika false menjadi string CSS
6600
- * @returns {string|Object} String CSS inline atau objek style JSON
6597
+ * Process opacity modifier from class name (e.g., text-red-500/50 -> 50% opacity)
6598
+ * @param {string} className - Class name with potential opacity modifier
6599
+ * @param {string} cssDeclaration - CSS declaration to modify
6600
+ * @returns {string} Modified CSS declaration with opacity applied
6601
+ */
6602
+ function processOpacityModifier(className, cssDeclaration) {
6603
+ const opacityMatch = className.match(/\/(\d+)$/);
6604
+ if (!opacityMatch) return cssDeclaration;
6605
+ const opacityValue = parseInt(opacityMatch[1], 10);
6606
+ if (opacityValue < 0 || opacityValue > 100) return cssDeclaration;
6607
+ const alphaValue = (opacityValue / 100).toString();
6608
+
6609
+ // Handle Tailwind's CSS custom property pattern
6610
+ let modifiedDeclaration = cssDeclaration;
6611
+
6612
+ // Replace opacity custom properties
6613
+ const opacityProperties = ['--text-opacity', '--bg-opacity', '--border-opacity', '--ring-opacity', '--divide-opacity', '--placeholder-opacity', '--text-decoration-opacity', '--outline-opacity', '--accent-opacity', '--caret-opacity'];
6614
+ opacityProperties.forEach(prop => {
6615
+ const propRegex = new RegExp(`${prop}\\s*:\\s*[\\d.]+`, 'gi');
6616
+ modifiedDeclaration = modifiedDeclaration.replace(propRegex, `${prop}: ${alphaValue}`);
6617
+ });
6618
+
6619
+ // Also handle direct color values that might not use CSS variables
6620
+ const colorProperties = ['color', 'background-color', 'border-color', 'text-decoration-color', 'outline-color', 'fill', 'stroke', 'caret-color', 'accent-color'];
6621
+ colorProperties.forEach(prop => {
6622
+ // Match rgb(), rgba(), hsl(), hsla() functions
6623
+ const rgbRegex = new RegExp(`(${prop}\\s*:\\s*)rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)`, 'gi');
6624
+ const rgbaRegex = new RegExp(`(${prop}\\s*:\\s*)rgba\\((\\d+),\\s*(\\d+),\\s*(\\d+),\\s*[\\d.]+\\)`, 'gi');
6625
+ const hslRegex = new RegExp(`(${prop}\\s*:\\s*)hsl\\((\\d+),\\s*([\\d.]+%),\\s*([\\d.]+%)\\)`, 'gi');
6626
+ const hslaRegex = new RegExp(`(${prop}\\s*:\\s*)hsla\\((\\d+),\\s*([\\d.]+%),\\s*([\\d.]+%),\\s*[\\d.]+\\)`, 'gi');
6627
+
6628
+ // Convert rgb to rgba with opacity
6629
+ modifiedDeclaration = modifiedDeclaration.replace(rgbRegex, `$1rgba($2, $3, $4, ${alphaValue})`);
6630
+
6631
+ // Update existing rgba opacity
6632
+ modifiedDeclaration = modifiedDeclaration.replace(rgbaRegex, `$1rgba($2, $3, $4, ${alphaValue})`);
6633
+
6634
+ // Convert hsl to hsla with opacity
6635
+ modifiedDeclaration = modifiedDeclaration.replace(hslRegex, `$1hsla($2, $3, $4, ${alphaValue})`);
6636
+
6637
+ // Update existing hsla opacity
6638
+ modifiedDeclaration = modifiedDeclaration.replace(hslaRegex, `$1hsla($2, $3, $4, ${alphaValue})`);
6639
+
6640
+ // Handle hex colors
6641
+ const hexRegex = new RegExp(`(${prop}\\s*:\\s*)(#[0-9a-fA-F]{3,6})`, 'gi');
6642
+ modifiedDeclaration = modifiedDeclaration.replace(hexRegex, (match, propPart, hexColor) => {
6643
+ // Convert hex to rgba
6644
+ const hex = hexColor.replace('#', '');
6645
+ let r, g, b;
6646
+ if (hex.length === 3) {
6647
+ r = parseInt(hex[0] + hex[0], 16);
6648
+ g = parseInt(hex[1] + hex[1], 16);
6649
+ b = parseInt(hex[2] + hex[2], 16);
6650
+ } else {
6651
+ r = parseInt(hex.substring(0, 2), 16);
6652
+ g = parseInt(hex.substring(2, 4), 16);
6653
+ b = parseInt(hex.substring(4, 6), 16);
6654
+ }
6655
+ return `${propPart}rgba(${r}, ${g}, ${b}, ${alphaValue})`;
6656
+ });
6657
+ });
6658
+ return modifiedDeclaration;
6659
+ }
6660
+
6661
+ /**
6662
+ * Convert Tailwind class string to inline CSS styles or JSON object
6663
+ * @param {string} classNames - String containing Tailwind classes to convert
6664
+ * @param {boolean} convertToJson - If true, result will be JSON object, if false becomes CSS string
6665
+ * @returns {string|Object} Inline CSS string or style JSON object
6601
6666
  */
6602
6667
  function tws(classNames, convertToJson) {
6603
6668
  const totalMarker = performanceMonitor.start("tws:total");
@@ -6609,10 +6674,10 @@ var tailwindToStyle = (function (exports) {
6609
6674
  let classes;
6610
6675
  try {
6611
6676
  const parseMarker = performanceMonitor.start("tws:parse");
6612
- classes = classNames.match(/[\w-\/]+(?:\[[^\]]+\])?/g);
6677
+ classes = classNames.match(/[\w-\/]+(?:\/\d+)?(?:\[[^\]]+\])?/g);
6613
6678
  performanceMonitor.end(parseMarker);
6614
6679
 
6615
- // Jika tidak ada class yang valid ditemukan
6680
+ // If no valid classes are found
6616
6681
  if (!classes || classes.length === 0) {
6617
6682
  console.warn(`No valid Tailwind classes found in input: "${classNames}"`);
6618
6683
  performanceMonitor.end(totalMarker);
@@ -6627,16 +6692,27 @@ var tailwindToStyle = (function (exports) {
6627
6692
  // Process classes with performance monitoring
6628
6693
  const processMarker = performanceMonitor.start("tws:process");
6629
6694
  let cssResult = classes.map(className => {
6630
- let result = cssObject[className] || cssObject[className.replace(/(\/)/g, "\\$1")] || cssObject[className.replace(/\./g, "\\.")];
6695
+ // Extract base class name without opacity modifier
6696
+ const baseClassName = className.replace(/\/\d+$/, '');
6697
+ let result = cssObject[baseClassName] || cssObject[baseClassName.replace(/(\/)/g, "\\$1")] || cssObject[baseClassName.replace(/\./g, "\\.")];
6631
6698
  if (result) {
6699
+ // Apply opacity modifier if present
6700
+ if (className.includes('/') && /\/\d+$/.test(className)) {
6701
+ result = processOpacityModifier(className, result);
6702
+ }
6632
6703
  return resolveCssToClearCss(result);
6633
- } else if (className.includes("[")) {
6634
- const match = className.match(/\[([^\]]+)\]/);
6704
+ } else if (baseClassName.includes("[")) {
6705
+ const match = baseClassName.match(/\[([^\]]+)\]/);
6635
6706
  if (match) {
6636
6707
  const customValue = match[1];
6637
- const baseKey = className.split("[")[0];
6708
+ const baseKey = baseClassName.split("[")[0];
6638
6709
  if (cssObject[`${baseKey}custom`]) {
6639
- return cssObject[`${baseKey}custom`].replace(/custom_value/g, customValue);
6710
+ let customResult = cssObject[`${baseKey}custom`].replace(/custom_value/g, customValue);
6711
+ // Apply opacity modifier to custom values too
6712
+ if (className.includes('/') && /\/\d+$/.test(className)) {
6713
+ customResult = processOpacityModifier(className, customResult);
6714
+ }
6715
+ return customResult;
6640
6716
  }
6641
6717
  }
6642
6718
  }
@@ -6767,9 +6843,12 @@ var tailwindToStyle = (function (exports) {
6767
6843
  media,
6768
6844
  finalSelector
6769
6845
  } = resolveVariants(selector, rawVariants);
6770
- let declarations = cssObject[pureClassName] || cssObject[pureClassName.replace(/(\/)/g, "\\$1")] || cssObject[pureClassName.replace(/\./g, "\\.")];
6771
- if (!declarations && pureClassName.includes("[")) {
6772
- const match = pureClassName.match(/^(.+?)\[(.+)\]$/);
6846
+
6847
+ // Extract base class name without opacity modifier for CSS lookup
6848
+ const baseClassName = pureClassName.replace(/\/\d+$/, '');
6849
+ let declarations = cssObject[baseClassName] || cssObject[baseClassName.replace(/(\/)/g, "\\$1")] || cssObject[baseClassName.replace(/\./g, "\\.")];
6850
+ if (!declarations && baseClassName.includes("[")) {
6851
+ const match = baseClassName.match(/^(.+?)\[(.+)\]$/);
6773
6852
  if (match) {
6774
6853
  const [, prefix, dynamicValue] = match;
6775
6854
  const customKey = `${prefix}custom`;
@@ -6780,17 +6859,22 @@ var tailwindToStyle = (function (exports) {
6780
6859
  }
6781
6860
  }
6782
6861
  if (!declarations) {
6783
- declarations = parseCustomClassWithPatterns(pureClassName);
6862
+ declarations = parseCustomClassWithPatterns(baseClassName);
6784
6863
  }
6785
6864
  if (!declarations) {
6786
6865
  return;
6787
6866
  }
6867
+
6868
+ // Apply opacity modifier if present
6869
+ if (pureClassName.includes('/') && /\/\d+$/.test(pureClassName)) {
6870
+ declarations = processOpacityModifier(pureClassName, declarations);
6871
+ }
6788
6872
  if (isImportant) {
6789
6873
  declarations = declarations.replace(/([^:;]+):([^;]+)(;?)/g, (_, prop, value) => {
6790
6874
  return prop.trim().startsWith("--") ? `${prop}:${value};` : `${prop}:${value.trim()} !important;`;
6791
6875
  });
6792
6876
  }
6793
- const isSpaceOrDivide = ["space-x-", "-space-x-", "space-y-", "-space-y-", "divide-"].some(prefix => pureClassName.startsWith(prefix));
6877
+ const isSpaceOrDivide = ["space-x-", "-space-x-", "space-y-", "-space-y-", "divide-"].some(prefix => baseClassName.startsWith(prefix));
6794
6878
  const expandedSelector = replaceSelector(finalSelector);
6795
6879
  const targetSelector = isSpaceOrDivide ? `${expandedSelector} > :not([hidden]) ~ :not([hidden])` : expandedSelector;
6796
6880
  if (media) {
@@ -6958,11 +7042,11 @@ var tailwindToStyle = (function (exports) {
6958
7042
  }
6959
7043
 
6960
7044
  /**
6961
- * Menghasilkan string CSS dari objek style dengan sintaks mirip SCSS
6962
- * Mendukung nested selectors, state variants, responsive variants, dan @css directives
6963
- * @param {Object} obj - Objek dengan format style mirip SCSS
6964
- * @param {Object} [options] - Opsi tambahan, misal { inject: true/false }
6965
- * @returns {string} String CSS yang dihasilkan
7045
+ * Generate CSS string from style object with SCSS-like syntax
7046
+ * Supports nested selectors, state variants, responsive variants, and @css directives
7047
+ * @param {Object} obj - Object with SCSS-like style format
7048
+ * @param {Object} [options] - Additional options, e.g. { inject: true/false }
7049
+ * @returns {string} Generated CSS string
6966
7050
  */
6967
7051
  function twsx(obj) {
6968
7052
  let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -7022,7 +7106,7 @@ var tailwindToStyle = (function (exports) {
7022
7106
  }
7023
7107
  }
7024
7108
 
7025
- // Fungsi hashCode sederhana untuk deduplikasi CSS
7109
+ // Simple hashCode function for CSS deduplication
7026
7110
  function getCssHash(str) {
7027
7111
  let hash = 0,
7028
7112
  i,
@@ -7036,7 +7120,7 @@ var tailwindToStyle = (function (exports) {
7036
7120
  return hash;
7037
7121
  }
7038
7122
 
7039
- // Enhanced auto-inject CSS dengan performance monitoring
7123
+ // Enhanced auto-inject CSS with performance monitoring
7040
7124
  const injectedCssHashSet = new Set();
7041
7125
  function autoInjectCss(cssString) {
7042
7126
  const marker = performanceMonitor.start("css:inject");
@@ -7068,24 +7152,24 @@ var tailwindToStyle = (function (exports) {
7068
7152
  }
7069
7153
  }
7070
7154
 
7071
- // Enhanced debounced functions dengan konfigurasi performance monitoring
7155
+ // Enhanced debounced functions with performance monitoring configuration
7072
7156
  /**
7073
- * Versi debounced dari fungsi tws dengan performance monitoring
7074
- * @param {string} classNames - String berisi kelas Tailwind yang akan dikonversi
7075
- * @param {boolean} convertToJson - Jika true, hasil akan menjadi objek JSON, jika false menjadi string CSS
7076
- * @returns {string|Object} String CSS inline atau objek style JSON
7157
+ * Debounced version of tws function with performance monitoring
7158
+ * @param {string} classNames - String containing Tailwind classes to convert
7159
+ * @param {boolean} convertToJson - If true, result will be JSON object, if false becomes CSS string
7160
+ * @returns {string|Object} Inline CSS string or style JSON object
7077
7161
  */
7078
7162
  const debouncedTws = debounce(tws, 50); // Faster debounce for tws
7079
7163
 
7080
7164
  /**
7081
- * Versi debounced dari fungsi twsx dengan performance monitoring
7082
- * @param {Object} obj - Objek dengan format style mirip SCSS
7083
- * @param {Object} [options] - Opsi tambahan
7084
- * @returns {string} String CSS yang dihasilkan
7165
+ * Debounced version of twsx function with performance monitoring
7166
+ * @param {Object} obj - Object with SCSS-like style format
7167
+ * @param {Object} [options] - Additional options
7168
+ * @returns {string} Generated CSS string
7085
7169
  */
7086
7170
  const debouncedTwsx = debounce(twsx, 100); // Standard debounce for twsx
7087
7171
 
7088
- // Export performance utilities untuk debugging
7172
+ // Export performance utilities for debugging
7089
7173
  const performanceUtils = {
7090
7174
  getStats() {
7091
7175
  return {