tailwind-to-style 3.1.2 → 3.2.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/README.md +535 -282
- package/dist/core/tws.cjs +984 -0
- package/dist/core/tws.d.ts +14 -0
- package/dist/core/tws.esm.js +981 -0
- package/dist/core/tws.esm.js.map +1 -0
- package/dist/core/twsx.cjs +9068 -0
- package/dist/core/twsx.d.ts +26 -0
- package/dist/core/twsx.esm.js +9066 -0
- package/dist/core/twsx.esm.js.map +1 -0
- package/dist/core/twsxVariants.cjs +9542 -0
- package/dist/core/twsxVariants.d.ts +85 -0
- package/dist/core/twsxVariants.esm.js +9541 -0
- package/dist/core/twsxVariants.esm.js.map +1 -0
- package/dist/cx.cjs +115 -0
- package/dist/cx.d.ts +41 -0
- package/dist/cx.esm.js +111 -0
- package/dist/cx.esm.js.map +1 -0
- package/dist/index.cjs +623 -242
- package/dist/index.d.ts +103 -20
- package/dist/index.esm.js +619 -243
- package/dist/index.esm.js.map +1 -0
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/utils/index.cjs +1797 -0
- package/dist/utils/index.d.ts +44 -0
- package/dist/utils/index.esm.js +1795 -0
- package/dist/utils/index.esm.js.map +1 -0
- package/package.json +51 -7
- package/types/core/tws.d.ts +14 -0
- package/types/core/twsx.d.ts +26 -0
- package/types/core/twsxVariants.d.ts +85 -0
- package/types/cx.d.ts +41 -0
- package/types/index.d.ts +382 -0
- package/types/utils/index.d.ts +44 -0
- package/README.v2-backup.md +0 -2456
package/dist/index.esm.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* tailwind-to-style v3.
|
|
2
|
+
* tailwind-to-style v3.2.0
|
|
3
3
|
* Runtime Tailwind CSS to inline styles converter
|
|
4
|
-
* Core only: tws, twsx, configure
|
|
5
4
|
*
|
|
6
5
|
* @author Bigetion
|
|
7
6
|
* @license MIT
|
|
@@ -1795,23 +1794,24 @@ class Logger {
|
|
|
1795
1794
|
}
|
|
1796
1795
|
}
|
|
1797
1796
|
|
|
1798
|
-
// Create singleton instance with
|
|
1799
|
-
//
|
|
1800
|
-
let
|
|
1797
|
+
// Create singleton instance with silent defaults
|
|
1798
|
+
// Can be enabled via TWSX_LOG_LEVEL environment variable
|
|
1799
|
+
let logLevel = "silent";
|
|
1801
1800
|
try {
|
|
1802
|
-
// Safe check with optional chaining equivalent
|
|
1803
1801
|
if (typeof process !== "undefined" && process && process.env) {
|
|
1804
|
-
|
|
1802
|
+
// Allow explicit log level override via environment variable
|
|
1803
|
+
// e.g., TWSX_LOG_LEVEL=debug or TWSX_LOG_LEVEL=warn
|
|
1804
|
+
logLevel = process.env.TWSX_LOG_LEVEL || "silent";
|
|
1805
1805
|
}
|
|
1806
|
-
} catch
|
|
1807
|
-
// Silently fail - in browser environment, default to
|
|
1808
|
-
|
|
1806
|
+
} catch {
|
|
1807
|
+
// Silently fail - in browser environment, default to silent
|
|
1808
|
+
logLevel = "silent";
|
|
1809
1809
|
}
|
|
1810
|
-
const logger = new Logger(
|
|
1810
|
+
const logger = new Logger(logLevel);
|
|
1811
1811
|
|
|
1812
|
-
/**
|
|
1813
|
-
* User Configuration Management
|
|
1814
|
-
* Handles theme extensions and custom plugin registration
|
|
1812
|
+
/**
|
|
1813
|
+
* User Configuration Management
|
|
1814
|
+
* Handles theme extensions and custom plugin registration
|
|
1815
1815
|
*/
|
|
1816
1816
|
|
|
1817
1817
|
|
|
@@ -1823,8 +1823,8 @@ function setClearConfigCache(fn) {
|
|
|
1823
1823
|
clearConfigCache$1 = fn;
|
|
1824
1824
|
}
|
|
1825
1825
|
|
|
1826
|
-
/**
|
|
1827
|
-
* User configuration state
|
|
1826
|
+
/**
|
|
1827
|
+
* User configuration state
|
|
1828
1828
|
*/
|
|
1829
1829
|
let userConfig = {
|
|
1830
1830
|
theme: {
|
|
@@ -1847,11 +1847,11 @@ let userConfig = {
|
|
|
1847
1847
|
// Cache for extended theme to avoid redundant lookups
|
|
1848
1848
|
const extendedThemeCache = new Map();
|
|
1849
1849
|
|
|
1850
|
-
/**
|
|
1851
|
-
* Deep merge two objects
|
|
1852
|
-
* @param {Object} target - Target object
|
|
1853
|
-
* @param {Object} source - Source object
|
|
1854
|
-
* @returns {Object} Merged object
|
|
1850
|
+
/**
|
|
1851
|
+
* Deep merge two objects
|
|
1852
|
+
* @param {Object} target - Target object
|
|
1853
|
+
* @param {Object} source - Source object
|
|
1854
|
+
* @returns {Object} Merged object
|
|
1855
1855
|
*/
|
|
1856
1856
|
function deepMerge(target, source) {
|
|
1857
1857
|
const result = {
|
|
@@ -1867,31 +1867,31 @@ function deepMerge(target, source) {
|
|
|
1867
1867
|
return result;
|
|
1868
1868
|
}
|
|
1869
1869
|
|
|
1870
|
-
/**
|
|
1871
|
-
* Configure tailwind-to-style with custom theme and plugins
|
|
1872
|
-
* @param {Object} config - Configuration object
|
|
1873
|
-
* @param {Object} [config.theme] - Theme configuration
|
|
1874
|
-
* @param {Object} [config.theme.extend] - Theme extensions
|
|
1875
|
-
* @param {Array} [config.plugins] - Array of plugins
|
|
1876
|
-
* @param {Object} [config.corePlugins] - Core plugins to enable/disable
|
|
1877
|
-
* @param {string} [config.prefix] - Prefix for all classes
|
|
1878
|
-
*
|
|
1879
|
-
* @example
|
|
1880
|
-
* configure({
|
|
1881
|
-
* theme: {
|
|
1882
|
-
* extend: {
|
|
1883
|
-
* colors: {
|
|
1884
|
-
* brand: {
|
|
1885
|
-
* 500: '#3B82F6',
|
|
1886
|
-
* },
|
|
1887
|
-
* },
|
|
1888
|
-
* spacing: {
|
|
1889
|
-
* 128: '32rem',
|
|
1890
|
-
* },
|
|
1891
|
-
* },
|
|
1892
|
-
* },
|
|
1893
|
-
* plugins: [myCustomPlugin],
|
|
1894
|
-
* });
|
|
1870
|
+
/**
|
|
1871
|
+
* Configure tailwind-to-style with custom theme and plugins
|
|
1872
|
+
* @param {Object} config - Configuration object
|
|
1873
|
+
* @param {Object} [config.theme] - Theme configuration
|
|
1874
|
+
* @param {Object} [config.theme.extend] - Theme extensions
|
|
1875
|
+
* @param {Array} [config.plugins] - Array of plugins
|
|
1876
|
+
* @param {Object} [config.corePlugins] - Core plugins to enable/disable
|
|
1877
|
+
* @param {string} [config.prefix] - Prefix for all classes
|
|
1878
|
+
*
|
|
1879
|
+
* @example
|
|
1880
|
+
* configure({
|
|
1881
|
+
* theme: {
|
|
1882
|
+
* extend: {
|
|
1883
|
+
* colors: {
|
|
1884
|
+
* brand: {
|
|
1885
|
+
* 500: '#3B82F6',
|
|
1886
|
+
* },
|
|
1887
|
+
* },
|
|
1888
|
+
* spacing: {
|
|
1889
|
+
* 128: '32rem',
|
|
1890
|
+
* },
|
|
1891
|
+
* },
|
|
1892
|
+
* },
|
|
1893
|
+
* plugins: [myCustomPlugin],
|
|
1894
|
+
* });
|
|
1895
1895
|
*/
|
|
1896
1896
|
function configure() {
|
|
1897
1897
|
let config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -1902,6 +1902,32 @@ function configure() {
|
|
|
1902
1902
|
return;
|
|
1903
1903
|
}
|
|
1904
1904
|
|
|
1905
|
+
// Validate config structure
|
|
1906
|
+
const validTopKeys = ['theme', 'plugins', 'corePlugins', 'prefix', 'styled'];
|
|
1907
|
+
const invalidKeys = Object.keys(config).filter(k => !validTopKeys.includes(k));
|
|
1908
|
+
if (invalidKeys.length > 0) {
|
|
1909
|
+
logger.warn(`configure: Unrecognized config keys: ${invalidKeys.join(', ')}. ` + `Valid keys are: ${validTopKeys.join(', ')}`);
|
|
1910
|
+
}
|
|
1911
|
+
if (config.theme) {
|
|
1912
|
+
if (typeof config.theme !== 'object' || Array.isArray(config.theme)) {
|
|
1913
|
+
logger.warn('configure: theme must be an object');
|
|
1914
|
+
return;
|
|
1915
|
+
}
|
|
1916
|
+
const validThemeKeys = ['extend', 'colors', 'spacing', 'borderRadius', 'fontSize', 'fontFamily', 'screens', 'breakpoints'];
|
|
1917
|
+
const invalidThemeKeys = Object.keys(config.theme).filter(k => !validThemeKeys.includes(k) && typeof config.theme[k] !== 'object');
|
|
1918
|
+
if (invalidThemeKeys.length > 0) {
|
|
1919
|
+
logger.warn(`configure: Unrecognized theme keys: ${invalidThemeKeys.join(', ')}. ` + `Common keys are: ${validThemeKeys.join(', ')}`);
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
if (config.plugins !== undefined && !Array.isArray(config.plugins)) {
|
|
1923
|
+
logger.warn('configure: plugins must be an array');
|
|
1924
|
+
return;
|
|
1925
|
+
}
|
|
1926
|
+
if (config.prefix !== undefined && typeof config.prefix !== 'string') {
|
|
1927
|
+
logger.warn('configure: prefix must be a string');
|
|
1928
|
+
return;
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1905
1931
|
// Clear extended theme cache when config changes
|
|
1906
1932
|
extendedThemeCache.clear();
|
|
1907
1933
|
|
|
@@ -1953,9 +1979,9 @@ function configure() {
|
|
|
1953
1979
|
}
|
|
1954
1980
|
}
|
|
1955
1981
|
|
|
1956
|
-
/**
|
|
1957
|
-
* Get current user configuration
|
|
1958
|
-
* @returns {Object} Current configuration
|
|
1982
|
+
/**
|
|
1983
|
+
* Get current user configuration
|
|
1984
|
+
* @returns {Object} Current configuration
|
|
1959
1985
|
*/
|
|
1960
1986
|
function getConfig() {
|
|
1961
1987
|
return {
|
|
@@ -1963,8 +1989,8 @@ function getConfig() {
|
|
|
1963
1989
|
};
|
|
1964
1990
|
}
|
|
1965
1991
|
|
|
1966
|
-
/**
|
|
1967
|
-
* Reset configuration to defaults
|
|
1992
|
+
/**
|
|
1993
|
+
* Reset configuration to defaults
|
|
1968
1994
|
*/
|
|
1969
1995
|
function resetConfig() {
|
|
1970
1996
|
userConfig = {
|
|
@@ -1980,10 +2006,10 @@ function resetConfig() {
|
|
|
1980
2006
|
logger.info("Configuration reset to defaults");
|
|
1981
2007
|
}
|
|
1982
2008
|
|
|
1983
|
-
/**
|
|
1984
|
-
* Get extended theme value
|
|
1985
|
-
* @param {string} key - Theme key (e.g., 'colors', 'spacing')
|
|
1986
|
-
* @returns {Object} Extended theme values
|
|
2009
|
+
/**
|
|
2010
|
+
* Get extended theme value
|
|
2011
|
+
* @param {string} key - Theme key (e.g., 'colors', 'spacing')
|
|
2012
|
+
* @returns {Object} Extended theme values
|
|
1987
2013
|
*/
|
|
1988
2014
|
function getExtendedTheme(key) {
|
|
1989
2015
|
// Check cache first
|
|
@@ -1997,17 +2023,17 @@ function getExtendedTheme(key) {
|
|
|
1997
2023
|
return result;
|
|
1998
2024
|
}
|
|
1999
2025
|
|
|
2000
|
-
/**
|
|
2001
|
-
* Get all registered plugins
|
|
2002
|
-
* @returns {Array} Array of plugins
|
|
2026
|
+
/**
|
|
2027
|
+
* Get all registered plugins
|
|
2028
|
+
* @returns {Array} Array of plugins
|
|
2003
2029
|
*/
|
|
2004
2030
|
function getPlugins() {
|
|
2005
2031
|
return userConfig.plugins;
|
|
2006
2032
|
}
|
|
2007
2033
|
|
|
2008
|
-
/**
|
|
2009
|
-
* Get configured prefix
|
|
2010
|
-
* @returns {string} Prefix string
|
|
2034
|
+
/**
|
|
2035
|
+
* Get configured prefix
|
|
2036
|
+
* @returns {string} Prefix string
|
|
2011
2037
|
*/
|
|
2012
2038
|
function getPrefix() {
|
|
2013
2039
|
return userConfig.prefix;
|
|
@@ -2522,9 +2548,9 @@ function staggerAnimations(elements, animationName) {
|
|
|
2522
2548
|
});
|
|
2523
2549
|
}
|
|
2524
2550
|
|
|
2525
|
-
/**
|
|
2526
|
-
* Animation Generator
|
|
2527
|
-
* Generates animation utility classes with dynamic inline animations
|
|
2551
|
+
/**
|
|
2552
|
+
* Animation Generator
|
|
2553
|
+
* Generates animation utility classes with dynamic inline animations
|
|
2528
2554
|
*/
|
|
2529
2555
|
|
|
2530
2556
|
function generator$2I() {
|
|
@@ -7242,9 +7268,9 @@ function generator$d() {
|
|
|
7242
7268
|
return responsiveCssString;
|
|
7243
7269
|
}
|
|
7244
7270
|
|
|
7245
|
-
/**
|
|
7246
|
-
* Transition Delay Generator
|
|
7247
|
-
* Generates transition-delay utility classes
|
|
7271
|
+
/**
|
|
7272
|
+
* Transition Delay Generator
|
|
7273
|
+
* Generates transition-delay utility classes
|
|
7248
7274
|
*/
|
|
7249
7275
|
|
|
7250
7276
|
function generator$c() {
|
|
@@ -7273,9 +7299,9 @@ function generator$c() {
|
|
|
7273
7299
|
return responsiveCssString;
|
|
7274
7300
|
}
|
|
7275
7301
|
|
|
7276
|
-
/**
|
|
7277
|
-
* Transition Duration Generator
|
|
7278
|
-
* Generates transition-duration utility classes
|
|
7302
|
+
/**
|
|
7303
|
+
* Transition Duration Generator
|
|
7304
|
+
* Generates transition-duration utility classes
|
|
7279
7305
|
*/
|
|
7280
7306
|
|
|
7281
7307
|
function generator$b() {
|
|
@@ -7304,9 +7330,9 @@ function generator$b() {
|
|
|
7304
7330
|
return responsiveCssString;
|
|
7305
7331
|
}
|
|
7306
7332
|
|
|
7307
|
-
/**
|
|
7308
|
-
* Transition Property Generator
|
|
7309
|
-
* Generates transition-property utility classes
|
|
7333
|
+
/**
|
|
7334
|
+
* Transition Property Generator
|
|
7335
|
+
* Generates transition-property utility classes
|
|
7310
7336
|
*/
|
|
7311
7337
|
|
|
7312
7338
|
function generator$a() {
|
|
@@ -7346,9 +7372,9 @@ function generator$a() {
|
|
|
7346
7372
|
return responsiveCssString;
|
|
7347
7373
|
}
|
|
7348
7374
|
|
|
7349
|
-
/**
|
|
7350
|
-
* Transition Timing Function Generator
|
|
7351
|
-
* Generates transition-timing-function utility classes (ease)
|
|
7375
|
+
/**
|
|
7376
|
+
* Transition Timing Function Generator
|
|
7377
|
+
* Generates transition-timing-function utility classes (ease)
|
|
7352
7378
|
*/
|
|
7353
7379
|
|
|
7354
7380
|
function generator$9() {
|
|
@@ -7987,6 +8013,108 @@ const patterns = {
|
|
|
7987
8013
|
...fontFamily
|
|
7988
8014
|
};
|
|
7989
8015
|
|
|
8016
|
+
/**
|
|
8017
|
+
* CX - Conditional Class Name Builder
|
|
8018
|
+
*
|
|
8019
|
+
* A lightweight utility for conditionally joining Tailwind class names.
|
|
8020
|
+
* Similar to `clsx`/`classnames` but designed specifically for tailwind-to-style.
|
|
8021
|
+
*
|
|
8022
|
+
* @module cx
|
|
8023
|
+
*/
|
|
8024
|
+
|
|
8025
|
+
/**
|
|
8026
|
+
* Conditionally join class names into a single string.
|
|
8027
|
+
*
|
|
8028
|
+
* Accepts strings, objects (key=className, value=condition), arrays, and nested combinations.
|
|
8029
|
+
* Falsy values (null, undefined, false, 0, '') are ignored.
|
|
8030
|
+
*
|
|
8031
|
+
* @param {...(string|Object|Array|boolean|null|undefined)} args - Class name inputs
|
|
8032
|
+
* @returns {string} Joined class names string
|
|
8033
|
+
*
|
|
8034
|
+
* @example
|
|
8035
|
+
* // Strings
|
|
8036
|
+
* cx('bg-blue-500', 'text-white')
|
|
8037
|
+
* // → 'bg-blue-500 text-white'
|
|
8038
|
+
*
|
|
8039
|
+
* @example
|
|
8040
|
+
* // Conditionals
|
|
8041
|
+
* cx('p-4', isActive && 'bg-blue-500', isDisabled && 'opacity-50')
|
|
8042
|
+
* // → 'p-4 bg-blue-500' (if isActive=true, isDisabled=false)
|
|
8043
|
+
*
|
|
8044
|
+
* @example
|
|
8045
|
+
* // Object syntax
|
|
8046
|
+
* cx('p-4', { 'bg-blue-500': isActive, 'opacity-50': isDisabled, 'cursor-pointer': true })
|
|
8047
|
+
* // → 'p-4 bg-blue-500 cursor-pointer'
|
|
8048
|
+
*
|
|
8049
|
+
* @example
|
|
8050
|
+
* // Arrays (nested)
|
|
8051
|
+
* cx(['p-4', 'bg-white'], isActive && ['ring-2', 'ring-blue-500'])
|
|
8052
|
+
* // → 'p-4 bg-white ring-2 ring-blue-500'
|
|
8053
|
+
*
|
|
8054
|
+
* @example
|
|
8055
|
+
* // Mixed
|
|
8056
|
+
* cx(
|
|
8057
|
+
* 'base-class',
|
|
8058
|
+
* condition && 'conditional-class',
|
|
8059
|
+
* { 'object-class': true, 'ignored-class': false },
|
|
8060
|
+
* ['array-class-1', 'array-class-2']
|
|
8061
|
+
* )
|
|
8062
|
+
*/
|
|
8063
|
+
function cx() {
|
|
8064
|
+
const classes = [];
|
|
8065
|
+
for (let i = 0; i < arguments.length; i++) {
|
|
8066
|
+
const arg = i < 0 || arguments.length <= i ? undefined : arguments[i];
|
|
8067
|
+
|
|
8068
|
+
// Skip falsy values
|
|
8069
|
+
if (!arg) continue;
|
|
8070
|
+
const type = typeof arg;
|
|
8071
|
+
if (type === 'string') {
|
|
8072
|
+
classes.push(arg);
|
|
8073
|
+
} else if (Array.isArray(arg)) {
|
|
8074
|
+
// Recursively process arrays
|
|
8075
|
+
const inner = cx(...arg);
|
|
8076
|
+
if (inner) classes.push(inner);
|
|
8077
|
+
} else if (type === 'object') {
|
|
8078
|
+
// Object: keys are class names, values are conditions
|
|
8079
|
+
const keys = Object.keys(arg);
|
|
8080
|
+
for (let j = 0; j < keys.length; j++) {
|
|
8081
|
+
if (arg[keys[j]]) {
|
|
8082
|
+
classes.push(keys[j]);
|
|
8083
|
+
}
|
|
8084
|
+
}
|
|
8085
|
+
}
|
|
8086
|
+
}
|
|
8087
|
+
return classes.join(' ');
|
|
8088
|
+
}
|
|
8089
|
+
|
|
8090
|
+
/**
|
|
8091
|
+
* Create a cx function bound with base classes.
|
|
8092
|
+
* Useful for component-level class composition.
|
|
8093
|
+
*
|
|
8094
|
+
* @param {...(string|Object|Array)} baseArgs - Base class arguments always included
|
|
8095
|
+
* @returns {Function} A cx function pre-filled with base classes
|
|
8096
|
+
*
|
|
8097
|
+
* @example
|
|
8098
|
+
* const btnClasses = cx.with('px-4 py-2 rounded font-medium transition-colors')
|
|
8099
|
+
*
|
|
8100
|
+
* btnClasses('bg-blue-500 text-white')
|
|
8101
|
+
* // → 'px-4 py-2 rounded font-medium transition-colors bg-blue-500 text-white'
|
|
8102
|
+
*
|
|
8103
|
+
* btnClasses({ 'opacity-50 cursor-not-allowed': isDisabled })
|
|
8104
|
+
* // → 'px-4 py-2 rounded font-medium transition-colors opacity-50 cursor-not-allowed'
|
|
8105
|
+
*/
|
|
8106
|
+
cx.with = function () {
|
|
8107
|
+
for (var _len = arguments.length, baseArgs = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
8108
|
+
baseArgs[_key] = arguments[_key];
|
|
8109
|
+
}
|
|
8110
|
+
return function () {
|
|
8111
|
+
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
8112
|
+
args[_key2] = arguments[_key2];
|
|
8113
|
+
}
|
|
8114
|
+
return cx(...baseArgs, ...args);
|
|
8115
|
+
};
|
|
8116
|
+
};
|
|
8117
|
+
|
|
7990
8118
|
/**
|
|
7991
8119
|
* Web Animations API Integration
|
|
7992
8120
|
* Dynamic animations without keyframes injection
|
|
@@ -8308,16 +8436,89 @@ function applyDynamicAnimation(element, templateName) {
|
|
|
8308
8436
|
return animationName;
|
|
8309
8437
|
}
|
|
8310
8438
|
|
|
8439
|
+
// ============================================================================
|
|
8440
|
+
// SSR (Server-Side Rendering) Support
|
|
8441
|
+
// Detect environment once at module load for zero-cost runtime checks
|
|
8442
|
+
// ============================================================================
|
|
8443
|
+
const IS_BROWSER = typeof window !== "undefined" && typeof document !== "undefined";
|
|
8444
|
+
const IS_SERVER = !IS_BROWSER;
|
|
8445
|
+
|
|
8446
|
+
// SSR CSS collector - accumulates CSS strings during server rendering
|
|
8447
|
+
let _ssrCollectedCss = [];
|
|
8448
|
+
let _ssrCollecting = false;
|
|
8449
|
+
|
|
8450
|
+
/**
|
|
8451
|
+
* Start collecting CSS for SSR. Call before rendering.
|
|
8452
|
+
* @returns {void}
|
|
8453
|
+
* @example
|
|
8454
|
+
* import { startSSR, stopSSR } from 'tailwind-to-style'
|
|
8455
|
+
* startSSR()
|
|
8456
|
+
* const html = renderToString(<App />)
|
|
8457
|
+
* const css = stopSSR()
|
|
8458
|
+
* // Inject css into <head> of your HTML response
|
|
8459
|
+
*/
|
|
8460
|
+
function startSSR() {
|
|
8461
|
+
_ssrCollectedCss = [];
|
|
8462
|
+
_ssrCollecting = true;
|
|
8463
|
+
}
|
|
8464
|
+
|
|
8465
|
+
/**
|
|
8466
|
+
* Stop collecting CSS and return all collected CSS as a single string.
|
|
8467
|
+
* @returns {string} All CSS collected during SSR
|
|
8468
|
+
*/
|
|
8469
|
+
function stopSSR() {
|
|
8470
|
+
_ssrCollecting = false;
|
|
8471
|
+
const css = _ssrCollectedCss.join('\n');
|
|
8472
|
+
_ssrCollectedCss = [];
|
|
8473
|
+
return css;
|
|
8474
|
+
}
|
|
8475
|
+
|
|
8476
|
+
/**
|
|
8477
|
+
* Get collected CSS without stopping collection.
|
|
8478
|
+
* @returns {string} Currently collected CSS
|
|
8479
|
+
*/
|
|
8480
|
+
function getSSRStyles() {
|
|
8481
|
+
return _ssrCollectedCss.join('\n');
|
|
8482
|
+
}
|
|
8483
|
+
|
|
8484
|
+
// ============================================================================
|
|
8485
|
+
// Bounded Caches (prevent memory leaks in long-running SPAs)
|
|
8486
|
+
// ============================================================================
|
|
8487
|
+
const MAX_CACHE_SIZE = 5000;
|
|
8488
|
+
const MAX_SET_SIZE = 10000;
|
|
8489
|
+
|
|
8311
8490
|
// Global registry to track injected keyframes (prevents duplication)
|
|
8312
8491
|
const _injectedKeyframes = new Set();
|
|
8313
8492
|
|
|
8314
|
-
// Global cache Maps
|
|
8493
|
+
// Global cache Maps with bounded eviction
|
|
8315
8494
|
const _twsxInputCache = new Map();
|
|
8316
8495
|
const _twsxVariantsResultCache = new Map();
|
|
8317
8496
|
|
|
8318
8497
|
// WeakMap for object identity-based caching (fast lookup for repeated objects)
|
|
8319
8498
|
const _objectIdentityCache = new WeakMap();
|
|
8320
8499
|
|
|
8500
|
+
/** Evict oldest entries from a Map when it exceeds maxSize */
|
|
8501
|
+
function evictMap(map) {
|
|
8502
|
+
let maxSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : MAX_CACHE_SIZE;
|
|
8503
|
+
if (map.size <= maxSize) return;
|
|
8504
|
+
const excess = map.size - maxSize;
|
|
8505
|
+
const iter = map.keys();
|
|
8506
|
+
for (let i = 0; i < excess; i++) {
|
|
8507
|
+
map.delete(iter.next().value);
|
|
8508
|
+
}
|
|
8509
|
+
}
|
|
8510
|
+
|
|
8511
|
+
/** Evict oldest entries from a Set when it exceeds maxSize */
|
|
8512
|
+
function evictSet(set) {
|
|
8513
|
+
let maxSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : MAX_SET_SIZE;
|
|
8514
|
+
if (set.size <= maxSize) return;
|
|
8515
|
+
const excess = set.size - maxSize;
|
|
8516
|
+
const iter = set.values();
|
|
8517
|
+
for (let i = 0; i < excess; i++) {
|
|
8518
|
+
set.delete(iter.next().value);
|
|
8519
|
+
}
|
|
8520
|
+
}
|
|
8521
|
+
|
|
8321
8522
|
// Mapping of animation names to their keyframe definitions
|
|
8322
8523
|
const BUILTIN_KEYFRAMES = {
|
|
8323
8524
|
spin: {
|
|
@@ -8386,7 +8587,7 @@ function generateMinifiedKeyframes(animationNames) {
|
|
|
8386
8587
|
for (const [percentage, styles] of Object.entries(keyframe)) {
|
|
8387
8588
|
css += `${percentage}{`;
|
|
8388
8589
|
for (const [prop, value] of Object.entries(styles)) {
|
|
8389
|
-
const cssProp = prop.replace(
|
|
8590
|
+
const cssProp = prop.replace(UPPERCASE_LETTER_REGEX, "-$1").toLowerCase();
|
|
8390
8591
|
css += `${cssProp}:${value};`;
|
|
8391
8592
|
}
|
|
8392
8593
|
css += "}";
|
|
@@ -8395,6 +8596,93 @@ function generateMinifiedKeyframes(animationNames) {
|
|
|
8395
8596
|
}
|
|
8396
8597
|
return css;
|
|
8397
8598
|
}
|
|
8599
|
+
|
|
8600
|
+
// ============================================================================
|
|
8601
|
+
// PRE-COMPILED REGEX CONSTANTS (Performance Optimization)
|
|
8602
|
+
// Pre-compiling regex patterns provides 50-100x performance improvement
|
|
8603
|
+
// by avoiding repeated regex object creation in hot code paths
|
|
8604
|
+
// ============================================================================
|
|
8605
|
+
|
|
8606
|
+
// Class parsing (includes . for decimal values like p-0.5)
|
|
8607
|
+
const CLASS_PARSER_REGEX = /[\w.\-\/]+(?:\/\d+)?(?:\[[^\]]+\])?/g;
|
|
8608
|
+
|
|
8609
|
+
// Opacity modifiers
|
|
8610
|
+
const OPACITY_MODIFIER_REGEX = /\/(\d+)$/;
|
|
8611
|
+
const OPACITY_PROP_REGEXES = {
|
|
8612
|
+
"--text-opacity": /--text-opacity\s*:\s*[\d.]+/gi,
|
|
8613
|
+
"--bg-opacity": /--bg-opacity\s*:\s*[\d.]+/gi,
|
|
8614
|
+
"--border-opacity": /--border-opacity\s*:\s*[\d.]+/gi,
|
|
8615
|
+
"--ring-opacity": /--ring-opacity\s*:\s*[\d.]+/gi,
|
|
8616
|
+
"--divide-opacity": /--divide-opacity\s*:\s*[\d.]+/gi,
|
|
8617
|
+
"--placeholder-opacity": /--placeholder-opacity\s*:\s*[\d.]+/gi,
|
|
8618
|
+
"--text-decoration-opacity": /--text-decoration-opacity\s*:\s*[\d.]+/gi,
|
|
8619
|
+
"--outline-opacity": /--outline-opacity\s*:\s*[\d.]+/gi,
|
|
8620
|
+
"--accent-opacity": /--accent-opacity\s*:\s*[\d.]+/gi,
|
|
8621
|
+
"--caret-opacity": /--caret-opacity\s*:\s*[\d.]+/gi
|
|
8622
|
+
};
|
|
8623
|
+
|
|
8624
|
+
// CSS parsing
|
|
8625
|
+
const CSS_CLASS_REGEX = /([a-zA-Z0-9\-_\\/.]+)\s*{\s*([^}]+)\s*}/g;
|
|
8626
|
+
const DOUBLE_BACKSLASH_REGEX = /\\\\/g;
|
|
8627
|
+
const LEADING_UNDERSCORE_REGEX = /^_/;
|
|
8628
|
+
const MULTIPLE_SPACES_REGEX = /\s+/g;
|
|
8629
|
+
|
|
8630
|
+
// Bracket encoding/decoding
|
|
8631
|
+
const BRACKET_CONTENT_REGEX = /\[([^\]]+)\]/g;
|
|
8632
|
+
const OPENING_PAREN_REGEX = /\(/g;
|
|
8633
|
+
const CLOSING_PAREN_REGEX = /\)/g;
|
|
8634
|
+
const ENCODED_PAREN_OPEN_REGEX = /__P__/g;
|
|
8635
|
+
const ENCODED_PAREN_CLOSE_REGEX = /__C__/g;
|
|
8636
|
+
|
|
8637
|
+
// Variant expansion
|
|
8638
|
+
const DIRECTIVE_GROUP_REGEX = /(\w+)\(([^()]+)\)/g;
|
|
8639
|
+
const VARIANT_GROUP_REGEX = /(\w+):\(([^()]+(?:\((?:[^()]+)\))?[^()]*)\)/g;
|
|
8640
|
+
const WHITESPACE_SPLIT_REGEX = /\s+/;
|
|
8641
|
+
const VARIANT_COLON_SPLIT_REGEX = /:/;
|
|
8642
|
+
|
|
8643
|
+
// CSS variable resolution — supports nested parens in fallback (e.g. rgba(...))
|
|
8644
|
+
const CSS_VAR_REGEX = /var\((--[\w-]+)(?:,\s*((?:[^()]+|\([^()]*\))*))?\)/g;
|
|
8645
|
+
const CAMEL_CASE_REGEX = /-([a-z])/g;
|
|
8646
|
+
|
|
8647
|
+
// Animation detection
|
|
8648
|
+
const ANIMATION_NAME_REGEX = /animation(?:-name)?:\s*([a-zA-Z0-9-]+)/gi;
|
|
8649
|
+
|
|
8650
|
+
// Custom class detection
|
|
8651
|
+
const CUSTOM_VALUE_BRACKET_REGEX = /\[([^\]]+)\]/;
|
|
8652
|
+
const CUSTOM_VALUE_FULL_REGEX = /^(.+?)\[(.+)\]$/;
|
|
8653
|
+
|
|
8654
|
+
// String splitting (CSS declarations)
|
|
8655
|
+
const CSS_SEMICOLON_SPLIT_REGEX = /;/;
|
|
8656
|
+
const CSS_COLON_SPLIT_REGEX = /:/;
|
|
8657
|
+
|
|
8658
|
+
// Selector variants
|
|
8659
|
+
const SELECTOR_VARIANT_REGEX = /c-(first|last|odd|even|\d+|not\([^)]+\))/g;
|
|
8660
|
+
const NOT_SELECTOR_REGEX = /^not\(([^)]+)\)$/;
|
|
8661
|
+
const DIGIT_ONLY_REGEX = /^\d+$/;
|
|
8662
|
+
|
|
8663
|
+
// Color property regex patterns (pre-compiled for each color property)
|
|
8664
|
+
// Used in processOpacityModifier for 50-100x performance improvement
|
|
8665
|
+
const COLOR_PROPERTIES = ["color", "background-color", "border-color", "text-decoration-color", "outline-color", "fill", "stroke", "caret-color", "accent-color"];
|
|
8666
|
+
|
|
8667
|
+
// Pre-compile regex patterns for each color property
|
|
8668
|
+
const COLOR_REGEX_PATTERNS = new Map();
|
|
8669
|
+
for (const prop of COLOR_PROPERTIES) {
|
|
8670
|
+
const escapedProp = prop.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8671
|
+
COLOR_REGEX_PATTERNS.set(prop, {
|
|
8672
|
+
rgb: new RegExp(`(${escapedProp}\\s*:\\s*)rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)`, "gi"),
|
|
8673
|
+
rgba: new RegExp(`(${escapedProp}\\s*:\\s*)rgba\\((\\d+),\\s*(\\d+),\\s*(\\d+),\\s*[\\d.]+\\)`, "gi"),
|
|
8674
|
+
hsl: new RegExp(`(${escapedProp}\\s*:\\s*)hsl\\((\\d+),\\s*([\\d.]+%),\\s*([\\d.]+%)\\)`, "gi"),
|
|
8675
|
+
hsla: new RegExp(`(${escapedProp}\\s*:\\s*)hsla\\((\\d+),\\s*([\\d.]+%),\\s*([\\d.]+%),\\s*[\\d.]+\\)`, "gi"),
|
|
8676
|
+
hex: new RegExp(`(${escapedProp}\\s*:\\s*)(#[0-9a-fA-F]{3,6})`, "gi")
|
|
8677
|
+
});
|
|
8678
|
+
}
|
|
8679
|
+
|
|
8680
|
+
// CSS property name conversion
|
|
8681
|
+
const UPPERCASE_LETTER_REGEX = /([A-Z])/g;
|
|
8682
|
+
|
|
8683
|
+
// Escape characters
|
|
8684
|
+
const ESCAPE_SLASH_REGEX = /\//g;
|
|
8685
|
+
const ESCAPE_DOT_REGEX = /\./g;
|
|
8398
8686
|
const plugins = {
|
|
8399
8687
|
accentColor: generator$2N,
|
|
8400
8688
|
accessibility: generator$2M,
|
|
@@ -8593,36 +8881,55 @@ function parseCustomClassWithPatterns(className) {
|
|
|
8593
8881
|
|
|
8594
8882
|
/**
|
|
8595
8883
|
* Resolve all CSS custom properties (var) in a CSS string and output only clear CSS (no custom property)
|
|
8884
|
+
* Optimized with for loops and indexOf for 2-3x better performance
|
|
8596
8885
|
* @param {string} cssString
|
|
8597
8886
|
* @returns {string} e.g. 'color: rgba(255,255,255,1); background: #fff;'
|
|
8598
8887
|
*/
|
|
8599
8888
|
function resolveCssToClearCss(cssString) {
|
|
8600
8889
|
const customVars = {};
|
|
8601
8890
|
const props = {};
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8891
|
+
|
|
8892
|
+
// Split by semicolon and process declarations
|
|
8893
|
+
const declarations = cssString.split(CSS_SEMICOLON_SPLIT_REGEX);
|
|
8894
|
+
for (let i = 0; i < declarations.length; i++) {
|
|
8895
|
+
const decl = declarations[i];
|
|
8896
|
+
if (!decl) continue;
|
|
8897
|
+
const colonIndex = decl.indexOf(":");
|
|
8898
|
+
if (colonIndex === -1) continue;
|
|
8899
|
+
const key = decl.substring(0, colonIndex).trim();
|
|
8900
|
+
const value = decl.substring(colonIndex + 1).trim();
|
|
8901
|
+
if (!key || !value) continue;
|
|
8605
8902
|
if (key.startsWith("--")) {
|
|
8606
8903
|
customVars[key] = value;
|
|
8607
8904
|
} else {
|
|
8608
8905
|
props[key] = value;
|
|
8609
8906
|
}
|
|
8610
|
-
}
|
|
8611
|
-
|
|
8612
|
-
|
|
8907
|
+
}
|
|
8908
|
+
|
|
8909
|
+
// Replace var(--foo) in all values using pre-compiled regex
|
|
8910
|
+
const propKeys = Object.keys(props);
|
|
8911
|
+
for (let i = 0; i < propKeys.length; i++) {
|
|
8912
|
+
const key = propKeys[i];
|
|
8613
8913
|
let val = props[key];
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8914
|
+
if (val.includes("var(")) {
|
|
8915
|
+
CSS_VAR_REGEX.lastIndex = 0;
|
|
8916
|
+
val = val.replace(CSS_VAR_REGEX, (m, varName) => customVars[varName] !== undefined ? customVars[varName] : m);
|
|
8917
|
+
props[key] = val;
|
|
8918
|
+
}
|
|
8919
|
+
}
|
|
8920
|
+
|
|
8617
8921
|
// Build CSS string - INCLUDE CSS variables so they can be resolved later
|
|
8618
|
-
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
|
|
8624
|
-
|
|
8625
|
-
|
|
8922
|
+
let result = "";
|
|
8923
|
+
const varKeys = Object.keys(customVars);
|
|
8924
|
+
for (let i = 0; i < varKeys.length; i++) {
|
|
8925
|
+
const key = varKeys[i];
|
|
8926
|
+
result += `${key}: ${customVars[key]}; `;
|
|
8927
|
+
}
|
|
8928
|
+
for (let i = 0; i < propKeys.length; i++) {
|
|
8929
|
+
const key = propKeys[i];
|
|
8930
|
+
result += `${key}: ${props[key]}; `;
|
|
8931
|
+
}
|
|
8932
|
+
return result.trim();
|
|
8626
8933
|
}
|
|
8627
8934
|
|
|
8628
8935
|
// Cache for getConfigOptions - use LRU cache
|
|
@@ -8671,24 +8978,27 @@ function generateTailwindCssString() {
|
|
|
8671
8978
|
const {
|
|
8672
8979
|
corePlugins = {}
|
|
8673
8980
|
} = configOptions;
|
|
8674
|
-
const corePluginKeys = Object.keys(corePlugins);
|
|
8675
8981
|
let cssString = "";
|
|
8676
|
-
Object.keys(plugins)
|
|
8677
|
-
|
|
8678
|
-
|
|
8679
|
-
|
|
8680
|
-
|
|
8982
|
+
const pluginNames = Object.keys(plugins);
|
|
8983
|
+
|
|
8984
|
+
// Optimized loop - check corePlugins directly instead of indexOf
|
|
8985
|
+
for (let i = 0; i < pluginNames.length; i++) {
|
|
8986
|
+
const pluginName = pluginNames[i];
|
|
8987
|
+
// Skip if plugin is explicitly disabled in corePlugins
|
|
8988
|
+
if (corePlugins.hasOwnProperty(pluginName) && !corePlugins[pluginName]) {
|
|
8989
|
+
continue;
|
|
8681
8990
|
}
|
|
8682
|
-
|
|
8991
|
+
cssString += plugins[pluginName](configOptions);
|
|
8992
|
+
}
|
|
8683
8993
|
return cssString;
|
|
8684
8994
|
}
|
|
8685
8995
|
function convertCssToObject(cssString) {
|
|
8686
8996
|
const obj = {};
|
|
8687
|
-
const regex = /([a-zA-Z0-9\-_\\/.]+)\s*{\s*([^}]+)\s*}/g;
|
|
8688
8997
|
let match;
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
const
|
|
8998
|
+
CSS_CLASS_REGEX.lastIndex = 0; // Reset global regex
|
|
8999
|
+
while ((match = CSS_CLASS_REGEX.exec(cssString)) !== null) {
|
|
9000
|
+
const className = match[1].replace(DOUBLE_BACKSLASH_REGEX, "\\").replace(LEADING_UNDERSCORE_REGEX, "");
|
|
9001
|
+
const cssRules = match[2].trim().replace(MULTIPLE_SPACES_REGEX, " ");
|
|
8692
9002
|
obj[className] = cssRules;
|
|
8693
9003
|
}
|
|
8694
9004
|
|
|
@@ -8734,8 +9044,9 @@ const encodeBracketCache = new LRUCache(1000);
|
|
|
8734
9044
|
function encodeBracketValues(input) {
|
|
8735
9045
|
if (!input) return input;
|
|
8736
9046
|
if (encodeBracketCache.has(input)) return encodeBracketCache.get(input);
|
|
8737
|
-
|
|
8738
|
-
|
|
9047
|
+
BRACKET_CONTENT_REGEX.lastIndex = 0; // Reset global regex
|
|
9048
|
+
const result = input.replace(BRACKET_CONTENT_REGEX, (_, content) => {
|
|
9049
|
+
const encoded = encodeURIComponent(content).replace(OPENING_PAREN_REGEX, "__P__").replace(CLOSING_PAREN_REGEX, "__C__");
|
|
8739
9050
|
return `[${encoded}]`;
|
|
8740
9051
|
});
|
|
8741
9052
|
encodeBracketCache.set(input, result);
|
|
@@ -8745,14 +9056,15 @@ const decodeBracketCache = new LRUCache(1000);
|
|
|
8745
9056
|
function decodeBracketValues(input) {
|
|
8746
9057
|
if (!input) return input;
|
|
8747
9058
|
if (decodeBracketCache.has(input)) return decodeBracketCache.get(input);
|
|
8748
|
-
const result = decodeURIComponent(input).replace(
|
|
9059
|
+
const result = decodeURIComponent(input).replace(ENCODED_PAREN_OPEN_REGEX, "(").replace(ENCODED_PAREN_CLOSE_REGEX, ")");
|
|
8749
9060
|
decodeBracketCache.set(input, result);
|
|
8750
9061
|
return result;
|
|
8751
9062
|
}
|
|
8752
9063
|
function replaceSelector(selector) {
|
|
8753
|
-
|
|
8754
|
-
|
|
8755
|
-
|
|
9064
|
+
SELECTOR_VARIANT_REGEX.lastIndex = 0; // Reset global regex
|
|
9065
|
+
return selector.replace(SELECTOR_VARIANT_REGEX, (_, raw) => {
|
|
9066
|
+
if (DIGIT_ONLY_REGEX.test(raw)) return selectorVariants.number(raw);
|
|
9067
|
+
const notMatch = raw.match(NOT_SELECTOR_REGEX);
|
|
8756
9068
|
if (notMatch) return selectorVariants.not(notMatch[1]);
|
|
8757
9069
|
if (selectorVariants[raw]) return selectorVariants[raw]();
|
|
8758
9070
|
return raw;
|
|
@@ -8785,17 +9097,20 @@ function resolveVariants(selector, variants) {
|
|
|
8785
9097
|
};
|
|
8786
9098
|
}
|
|
8787
9099
|
function inlineStyleToJson(styleString) {
|
|
8788
|
-
const styles = styleString.split(
|
|
9100
|
+
const styles = styleString.split(CSS_SEMICOLON_SPLIT_REGEX).filter(style => style.trim() !== "");
|
|
8789
9101
|
const styleObject = {};
|
|
8790
9102
|
const cssVariables = {};
|
|
8791
9103
|
|
|
8792
9104
|
// First pass: collect CSS variables
|
|
8793
|
-
styles.
|
|
8794
|
-
const
|
|
9105
|
+
for (let i = 0; i < styles.length; i++) {
|
|
9106
|
+
const parts = styles[i].split(CSS_COLON_SPLIT_REGEX, 2);
|
|
9107
|
+
if (parts.length !== 2) continue;
|
|
9108
|
+
const key = parts[0].trim();
|
|
9109
|
+
const value = parts[1].trim();
|
|
8795
9110
|
if (key && key.startsWith("--")) {
|
|
8796
9111
|
cssVariables[key] = value;
|
|
8797
9112
|
}
|
|
8798
|
-
}
|
|
9113
|
+
}
|
|
8799
9114
|
|
|
8800
9115
|
// Helper to resolve CSS variables recursively
|
|
8801
9116
|
const resolveVariables = value => {
|
|
@@ -8804,7 +9119,8 @@ function inlineStyleToJson(styleString) {
|
|
|
8804
9119
|
let maxIterations = 10; // Prevent infinite loops
|
|
8805
9120
|
|
|
8806
9121
|
while (resolved.includes("var(") && maxIterations-- > 0) {
|
|
8807
|
-
|
|
9122
|
+
CSS_VAR_REGEX.lastIndex = 0; // Reset global regex
|
|
9123
|
+
resolved = resolved.replace(CSS_VAR_REGEX, (match, variable, fallback) => {
|
|
8808
9124
|
return cssVariables[variable] || fallback || match;
|
|
8809
9125
|
});
|
|
8810
9126
|
}
|
|
@@ -8812,13 +9128,16 @@ function inlineStyleToJson(styleString) {
|
|
|
8812
9128
|
};
|
|
8813
9129
|
|
|
8814
9130
|
// Second pass: create style object with resolved values
|
|
8815
|
-
styles.
|
|
8816
|
-
const
|
|
9131
|
+
for (let i = 0; i < styles.length; i++) {
|
|
9132
|
+
const parts = styles[i].split(CSS_COLON_SPLIT_REGEX, 2);
|
|
9133
|
+
if (parts.length !== 2) continue;
|
|
9134
|
+
const key = parts[0].trim();
|
|
9135
|
+
const value = parts[1].trim();
|
|
8817
9136
|
if (key && value && !key.startsWith("--")) {
|
|
8818
|
-
const camelCaseKey = key.replace(
|
|
9137
|
+
const camelCaseKey = key.replace(CAMEL_CASE_REGEX, (_, letter) => letter.toUpperCase());
|
|
8819
9138
|
styleObject[camelCaseKey] = resolveVariables(value);
|
|
8820
9139
|
}
|
|
8821
|
-
}
|
|
9140
|
+
}
|
|
8822
9141
|
return styleObject;
|
|
8823
9142
|
}
|
|
8824
9143
|
|
|
@@ -8868,98 +9187,77 @@ function separateAndResolveCSS(arr) {
|
|
|
8868
9187
|
|
|
8869
9188
|
// Process CSS resolution
|
|
8870
9189
|
const cssProperties = {};
|
|
8871
|
-
arr.
|
|
8872
|
-
|
|
9190
|
+
for (let i = 0; i < arr.length; i++) {
|
|
9191
|
+
const item = arr[i];
|
|
9192
|
+
if (!item) continue;
|
|
8873
9193
|
try {
|
|
8874
|
-
const declarations = item.split(
|
|
8875
|
-
declarations.
|
|
9194
|
+
const declarations = item.split(CSS_SEMICOLON_SPLIT_REGEX);
|
|
9195
|
+
for (let j = 0; j < declarations.length; j++) {
|
|
9196
|
+
const declaration = declarations[j].trim();
|
|
9197
|
+
if (!declaration) continue;
|
|
8876
9198
|
const colonIndex = declaration.indexOf(":");
|
|
8877
|
-
if (colonIndex === -1)
|
|
9199
|
+
if (colonIndex === -1) continue;
|
|
8878
9200
|
const key = declaration.substring(0, colonIndex).trim();
|
|
8879
9201
|
const value = declaration.substring(colonIndex + 1).trim();
|
|
8880
9202
|
if (key && value) {
|
|
8881
9203
|
// Prioritize more specific values (e.g., !important)
|
|
8882
9204
|
if (value.includes("!important") || !cssProperties[key]) {
|
|
8883
9205
|
cssProperties[key] = value;
|
|
9206
|
+
} else if (key === "--gradient-color-stops" && value.includes("--gradient-via-color") && !cssProperties[key].includes("--gradient-via-color")) {
|
|
9207
|
+
// Allow 3-stop gradient (with via) to overwrite 2-stop version
|
|
9208
|
+
cssProperties[key] = value;
|
|
8884
9209
|
}
|
|
8885
9210
|
}
|
|
8886
|
-
}
|
|
9211
|
+
}
|
|
8887
9212
|
} catch (error) {
|
|
8888
9213
|
logger.warn("Error processing CSS declaration:", item, error);
|
|
8889
9214
|
}
|
|
8890
|
-
}
|
|
9215
|
+
}
|
|
8891
9216
|
const resolvedProperties = {
|
|
8892
9217
|
...cssProperties
|
|
8893
9218
|
};
|
|
9219
|
+
|
|
9220
|
+
/**
|
|
9221
|
+
* Optimized CSS variable resolution using regex-based approach
|
|
9222
|
+
* 2-3x faster than manual char-by-char parsing
|
|
9223
|
+
* Handles nested var() with fallback values
|
|
9224
|
+
*/
|
|
8894
9225
|
const resolveValue = function (value, variables) {
|
|
8895
9226
|
let maxDepth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;
|
|
8896
9227
|
if (!value || !value.includes("var(") || maxDepth <= 0) return value;
|
|
8897
9228
|
try {
|
|
8898
9229
|
let resolved = value;
|
|
8899
|
-
let hasVariables = true;
|
|
8900
|
-
let depth = 0;
|
|
8901
9230
|
|
|
8902
|
-
//
|
|
8903
|
-
|
|
9231
|
+
// Iteratively resolve variables until no more changes or max depth reached
|
|
9232
|
+
for (let depth = 0; depth < maxDepth; depth++) {
|
|
8904
9233
|
const before = resolved;
|
|
8905
9234
|
|
|
8906
|
-
//
|
|
8907
|
-
|
|
8908
|
-
let i = 0;
|
|
8909
|
-
while (i < resolved.length) {
|
|
8910
|
-
// Look for var(
|
|
8911
|
-
if (resolved.substr(i, 4) === "var(") {
|
|
8912
|
-
i += 4;
|
|
8913
|
-
|
|
8914
|
-
// Extract variable name
|
|
8915
|
-
let varName = "";
|
|
8916
|
-
while (i < resolved.length && resolved[i] !== "," && resolved[i] !== ")") {
|
|
8917
|
-
varName += resolved[i];
|
|
8918
|
-
i++;
|
|
8919
|
-
}
|
|
9235
|
+
// Use pre-compiled regex for better performance
|
|
9236
|
+
CSS_VAR_REGEX.lastIndex = 0;
|
|
8920
9237
|
|
|
8921
|
-
|
|
8922
|
-
|
|
8923
|
-
|
|
8924
|
-
i++; // skip comma
|
|
8925
|
-
// Parse fallback - count parentheses
|
|
8926
|
-
let parenCount = 1; // We're inside var()
|
|
8927
|
-
while (i < resolved.length && parenCount > 0) {
|
|
8928
|
-
if (resolved[i] === "(") parenCount++;else if (resolved[i] === ")") {
|
|
8929
|
-
parenCount--;
|
|
8930
|
-
if (parenCount === 0) break;
|
|
8931
|
-
}
|
|
8932
|
-
fallback += resolved[i];
|
|
8933
|
-
i++;
|
|
8934
|
-
}
|
|
8935
|
-
}
|
|
9238
|
+
// Replace all var() occurrences
|
|
9239
|
+
resolved = resolved.replace(CSS_VAR_REGEX, (match, varName, fallback) => {
|
|
9240
|
+
const trimmedVarName = varName.trim();
|
|
8936
9241
|
|
|
8937
|
-
|
|
8938
|
-
|
|
9242
|
+
// Try to resolve from variables
|
|
9243
|
+
if (variables[trimmedVarName] !== undefined) {
|
|
9244
|
+
return variables[trimmedVarName];
|
|
9245
|
+
}
|
|
8939
9246
|
|
|
8940
|
-
|
|
8941
|
-
|
|
8942
|
-
|
|
8943
|
-
result += resolvedVar;
|
|
8944
|
-
} else if (fallback) {
|
|
8945
|
-
result += fallback.trim();
|
|
8946
|
-
} else {
|
|
8947
|
-
// Keep original if can't resolve
|
|
8948
|
-
result += `var(${varName}`;
|
|
8949
|
-
if (fallback) result += `,${fallback}`;
|
|
8950
|
-
result += ")";
|
|
8951
|
-
}
|
|
8952
|
-
} else {
|
|
8953
|
-
result += resolved[i];
|
|
8954
|
-
i++;
|
|
9247
|
+
// Use fallback if provided
|
|
9248
|
+
if (fallback !== undefined) {
|
|
9249
|
+
return fallback.trim();
|
|
8955
9250
|
}
|
|
8956
|
-
}
|
|
8957
|
-
resolved = result;
|
|
8958
|
-
hasVariables = resolved.includes("var(");
|
|
8959
|
-
depth++;
|
|
8960
9251
|
|
|
8961
|
-
|
|
9252
|
+
// Keep original if can't resolve
|
|
9253
|
+
return match;
|
|
9254
|
+
});
|
|
9255
|
+
|
|
9256
|
+
// Break if no changes (fully resolved or unresolvable)
|
|
8962
9257
|
if (before === resolved) break;
|
|
9258
|
+
|
|
9259
|
+
// Break if no more var() references
|
|
9260
|
+
if (!resolved.includes("var(")) break;
|
|
8963
9261
|
}
|
|
8964
9262
|
return resolved;
|
|
8965
9263
|
} catch (error) {
|
|
@@ -8968,30 +9266,39 @@ function separateAndResolveCSS(arr) {
|
|
|
8968
9266
|
}
|
|
8969
9267
|
};
|
|
8970
9268
|
|
|
8971
|
-
// Resolve variables recursively - multiple passes
|
|
9269
|
+
// Resolve variables recursively - multiple passes with optimized loop
|
|
8972
9270
|
let maxPasses = 5;
|
|
8973
9271
|
let hasUnresolved = true;
|
|
8974
9272
|
while (hasUnresolved && maxPasses-- > 0) {
|
|
8975
9273
|
hasUnresolved = false;
|
|
8976
|
-
Object.keys(resolvedProperties)
|
|
9274
|
+
const propKeys = Object.keys(resolvedProperties);
|
|
9275
|
+
for (let i = 0; i < propKeys.length; i++) {
|
|
9276
|
+
const key = propKeys[i];
|
|
8977
9277
|
const resolved = resolveValue(resolvedProperties[key], resolvedProperties);
|
|
8978
9278
|
if (resolved !== resolvedProperties[key]) {
|
|
8979
9279
|
resolvedProperties[key] = resolved;
|
|
8980
9280
|
hasUnresolved = true;
|
|
8981
9281
|
}
|
|
8982
|
-
}
|
|
9282
|
+
}
|
|
8983
9283
|
}
|
|
8984
9284
|
|
|
8985
|
-
// Remove CSS variables after resolution
|
|
8986
|
-
Object.keys(resolvedProperties)
|
|
9285
|
+
// Remove CSS variables after resolution using optimized loop
|
|
9286
|
+
const allKeys = Object.keys(resolvedProperties);
|
|
9287
|
+
for (let i = 0; i < allKeys.length; i++) {
|
|
9288
|
+
const key = allKeys[i];
|
|
8987
9289
|
if (key.startsWith("--")) {
|
|
8988
9290
|
delete resolvedProperties[key];
|
|
8989
9291
|
}
|
|
8990
|
-
}
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
8994
|
-
|
|
9292
|
+
}
|
|
9293
|
+
|
|
9294
|
+
// Build result string with optimized loop (faster than map/join)
|
|
9295
|
+
let result = "";
|
|
9296
|
+
const finalKeys = Object.keys(resolvedProperties);
|
|
9297
|
+
for (let i = 0; i < finalKeys.length; i++) {
|
|
9298
|
+
const key = finalKeys[i];
|
|
9299
|
+
result += `${key}: ${resolvedProperties[key]}; `;
|
|
9300
|
+
}
|
|
9301
|
+
result = result.trim();
|
|
8995
9302
|
cssResolutionCache.set(cacheKey, result);
|
|
8996
9303
|
performanceMonitor.end(marker);
|
|
8997
9304
|
return result;
|
|
@@ -9009,7 +9316,7 @@ function separateAndResolveCSS(arr) {
|
|
|
9009
9316
|
* @returns {string} Modified CSS declaration with opacity applied
|
|
9010
9317
|
*/
|
|
9011
9318
|
function processOpacityModifier(className, cssDeclaration) {
|
|
9012
|
-
const opacityMatch =
|
|
9319
|
+
const opacityMatch = OPACITY_MODIFIER_REGEX.exec(className);
|
|
9013
9320
|
if (!opacityMatch) return cssDeclaration;
|
|
9014
9321
|
const opacityValue = parseInt(opacityMatch[1], 10);
|
|
9015
9322
|
if (opacityValue < 0 || opacityValue > 100) return cssDeclaration;
|
|
@@ -9018,37 +9325,39 @@ function processOpacityModifier(className, cssDeclaration) {
|
|
|
9018
9325
|
// Handle Tailwind's CSS custom property pattern
|
|
9019
9326
|
let modifiedDeclaration = cssDeclaration;
|
|
9020
9327
|
|
|
9021
|
-
// Replace opacity custom properties
|
|
9022
|
-
const
|
|
9023
|
-
|
|
9024
|
-
|
|
9025
|
-
modifiedDeclaration = modifiedDeclaration.replace(
|
|
9026
|
-
}
|
|
9328
|
+
// Replace opacity custom properties using pre-compiled regexes
|
|
9329
|
+
for (const prop in OPACITY_PROP_REGEXES) {
|
|
9330
|
+
const regex = OPACITY_PROP_REGEXES[prop];
|
|
9331
|
+
regex.lastIndex = 0; // Reset global regex
|
|
9332
|
+
modifiedDeclaration = modifiedDeclaration.replace(regex, `${prop}: ${alphaValue}`);
|
|
9333
|
+
}
|
|
9334
|
+
|
|
9335
|
+
// Also handle direct color values using pre-compiled regex patterns
|
|
9336
|
+
for (const prop of COLOR_PROPERTIES) {
|
|
9337
|
+
const patterns = COLOR_REGEX_PATTERNS.get(prop);
|
|
9338
|
+
if (!patterns) continue;
|
|
9027
9339
|
|
|
9028
|
-
|
|
9029
|
-
|
|
9030
|
-
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
const hslRegex = new RegExp(`(${prop}\\s*:\\s*)hsl\\((\\d+),\\s*([\\d.]+%),\\s*([\\d.]+%)\\)`, "gi");
|
|
9035
|
-
const hslaRegex = new RegExp(`(${prop}\\s*:\\s*)hsla\\((\\d+),\\s*([\\d.]+%),\\s*([\\d.]+%),\\s*[\\d.]+\\)`, "gi");
|
|
9340
|
+
// Reset all regex lastIndex for reuse
|
|
9341
|
+
patterns.rgb.lastIndex = 0;
|
|
9342
|
+
patterns.rgba.lastIndex = 0;
|
|
9343
|
+
patterns.hsl.lastIndex = 0;
|
|
9344
|
+
patterns.hsla.lastIndex = 0;
|
|
9345
|
+
patterns.hex.lastIndex = 0;
|
|
9036
9346
|
|
|
9037
9347
|
// Convert rgb to rgba with opacity
|
|
9038
|
-
modifiedDeclaration = modifiedDeclaration.replace(
|
|
9348
|
+
modifiedDeclaration = modifiedDeclaration.replace(patterns.rgb, `$1rgba($2, $3, $4, ${alphaValue})`);
|
|
9039
9349
|
|
|
9040
9350
|
// Update existing rgba opacity
|
|
9041
|
-
modifiedDeclaration = modifiedDeclaration.replace(
|
|
9351
|
+
modifiedDeclaration = modifiedDeclaration.replace(patterns.rgba, `$1rgba($2, $3, $4, ${alphaValue})`);
|
|
9042
9352
|
|
|
9043
9353
|
// Convert hsl to hsla with opacity
|
|
9044
|
-
modifiedDeclaration = modifiedDeclaration.replace(
|
|
9354
|
+
modifiedDeclaration = modifiedDeclaration.replace(patterns.hsl, `$1hsla($2, $3, $4, ${alphaValue})`);
|
|
9045
9355
|
|
|
9046
9356
|
// Update existing hsla opacity
|
|
9047
|
-
modifiedDeclaration = modifiedDeclaration.replace(
|
|
9357
|
+
modifiedDeclaration = modifiedDeclaration.replace(patterns.hsla, `$1hsla($2, $3, $4, ${alphaValue})`);
|
|
9048
9358
|
|
|
9049
|
-
// Handle hex colors
|
|
9050
|
-
|
|
9051
|
-
modifiedDeclaration = modifiedDeclaration.replace(hexRegex, (match, propPart, hexColor) => {
|
|
9359
|
+
// Handle hex colors - convert to rgba
|
|
9360
|
+
modifiedDeclaration = modifiedDeclaration.replace(patterns.hex, (match, propPart, hexColor) => {
|
|
9052
9361
|
// Convert hex to rgba
|
|
9053
9362
|
const hex = hexColor.replace("#", "");
|
|
9054
9363
|
let r, g, b;
|
|
@@ -9063,7 +9372,7 @@ function processOpacityModifier(className, cssDeclaration) {
|
|
|
9063
9372
|
}
|
|
9064
9373
|
return `${propPart}rgba(${r}, ${g}, ${b}, ${alphaValue})`;
|
|
9065
9374
|
});
|
|
9066
|
-
}
|
|
9375
|
+
}
|
|
9067
9376
|
return modifiedDeclaration;
|
|
9068
9377
|
}
|
|
9069
9378
|
|
|
@@ -9078,14 +9387,15 @@ function tws(classNames, convertToJson) {
|
|
|
9078
9387
|
try {
|
|
9079
9388
|
// Initialize CSS object using singleton cache
|
|
9080
9389
|
const cssObject = tailwindCache.getOrGenerate(generateTailwindCssString, convertCssToObject);
|
|
9081
|
-
if (
|
|
9390
|
+
if (!classNames || typeof classNames !== "string" || classNames.trim() === "") {
|
|
9082
9391
|
performanceMonitor.end(totalMarker);
|
|
9083
9392
|
return convertToJson ? {} : "";
|
|
9084
9393
|
}
|
|
9085
9394
|
let classes;
|
|
9086
9395
|
try {
|
|
9087
9396
|
const parseMarker = performanceMonitor.start("tws:parse");
|
|
9088
|
-
|
|
9397
|
+
CLASS_PARSER_REGEX.lastIndex = 0; // Reset global regex
|
|
9398
|
+
classes = classNames.match(CLASS_PARSER_REGEX);
|
|
9089
9399
|
performanceMonitor.end(parseMarker);
|
|
9090
9400
|
|
|
9091
9401
|
// If no valid classes are found
|
|
@@ -9106,7 +9416,7 @@ function tws(classNames, convertToJson) {
|
|
|
9106
9416
|
// Extract base class name without opacity modifier
|
|
9107
9417
|
// Only remove /digits if it's an opacity modifier (not a fraction like w-2/3)
|
|
9108
9418
|
// Opacity modifiers are typically /0-100, fractions are /2, /3, /4, /5, /6, /12
|
|
9109
|
-
const opacityMatch =
|
|
9419
|
+
const opacityMatch = OPACITY_MODIFIER_REGEX.exec(className);
|
|
9110
9420
|
let baseClassName = className;
|
|
9111
9421
|
let hasOpacityModifier = false;
|
|
9112
9422
|
if (opacityMatch) {
|
|
@@ -9130,7 +9440,7 @@ function tws(classNames, convertToJson) {
|
|
|
9130
9440
|
}
|
|
9131
9441
|
return resolveCssToClearCss(result);
|
|
9132
9442
|
} else if (baseClassName.includes("[")) {
|
|
9133
|
-
const match =
|
|
9443
|
+
const match = CUSTOM_VALUE_BRACKET_REGEX.exec(baseClassName);
|
|
9134
9444
|
if (match) {
|
|
9135
9445
|
const customValue = match[1];
|
|
9136
9446
|
const baseKey = baseClassName.split("[")[0];
|
|
@@ -9200,14 +9510,17 @@ const performanceMonitor = {
|
|
|
9200
9510
|
|
|
9201
9511
|
// Utility functions for class expansion
|
|
9202
9512
|
function expandDirectiveGroups(str) {
|
|
9203
|
-
|
|
9513
|
+
DIRECTIVE_GROUP_REGEX.lastIndex = 0; // Reset global regex
|
|
9514
|
+
return str.replace(DIRECTIVE_GROUP_REGEX, (_, directive, content) => {
|
|
9204
9515
|
// Special handling for dark mode syntax: dark:(classes)
|
|
9205
9516
|
if (directive === "dark") {
|
|
9206
|
-
return content.trim().split(
|
|
9517
|
+
return content.trim().split(WHITESPACE_SPLIT_REGEX).map(cls => `dark:${cls}`).join(" ");
|
|
9207
9518
|
}
|
|
9208
|
-
return content.trim().split(
|
|
9519
|
+
return content.trim().split(WHITESPACE_SPLIT_REGEX).map(val => {
|
|
9209
9520
|
if (val.includes(":")) {
|
|
9210
|
-
const
|
|
9521
|
+
const parts = val.split(VARIANT_COLON_SPLIT_REGEX);
|
|
9522
|
+
const variant = parts[0];
|
|
9523
|
+
const v = parts[1];
|
|
9211
9524
|
const prefix = v.startsWith("-") ? "-" : "";
|
|
9212
9525
|
const value = v.startsWith("-") ? v.slice(1) : v;
|
|
9213
9526
|
return `${variant}:${prefix}${directive}-${value}`;
|
|
@@ -9220,8 +9533,9 @@ function expandDirectiveGroups(str) {
|
|
|
9220
9533
|
}
|
|
9221
9534
|
function expandVariants(str) {
|
|
9222
9535
|
let parent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
|
|
9223
|
-
|
|
9224
|
-
|
|
9536
|
+
VARIANT_GROUP_REGEX.lastIndex = 0; // Reset global regex
|
|
9537
|
+
return str.replace(VARIANT_GROUP_REGEX, (_, variant, content) => {
|
|
9538
|
+
return content.trim().split(WHITESPACE_SPLIT_REGEX).map(c => {
|
|
9225
9539
|
if (/\w+:\(.*\)/.test(c)) {
|
|
9226
9540
|
return expandVariants(c, parent ? `${parent}:${variant}` : variant);
|
|
9227
9541
|
}
|
|
@@ -9280,7 +9594,7 @@ function processClass(cls, selector, styles) {
|
|
|
9280
9594
|
|
|
9281
9595
|
// Extract base class name without opacity modifier for CSS lookup
|
|
9282
9596
|
// Only remove /digits if it's an opacity modifier (not a fraction like w-2/3)
|
|
9283
|
-
const opacityMatch =
|
|
9597
|
+
const opacityMatch = OPACITY_MODIFIER_REGEX.exec(pureClassName);
|
|
9284
9598
|
let baseClassName = pureClassName;
|
|
9285
9599
|
let hasOpacityModifier = false;
|
|
9286
9600
|
if (opacityMatch) {
|
|
@@ -9298,9 +9612,9 @@ function processClass(cls, selector, styles) {
|
|
|
9298
9612
|
|
|
9299
9613
|
// Get cssObject from singleton cache
|
|
9300
9614
|
const cssObject = tailwindCache.getOrGenerate(generateTailwindCssString, convertCssToObject);
|
|
9301
|
-
let declarations = cssObject[baseClassName] || cssObject[baseClassName.replace(
|
|
9615
|
+
let declarations = cssObject[baseClassName] || cssObject[baseClassName.replace(ESCAPE_SLASH_REGEX, "\\$1")] || cssObject[baseClassName.replace(ESCAPE_DOT_REGEX, "\\.")];
|
|
9302
9616
|
if (!declarations && baseClassName.includes("[")) {
|
|
9303
|
-
const match =
|
|
9617
|
+
const match = CUSTOM_VALUE_FULL_REGEX.exec(baseClassName);
|
|
9304
9618
|
if (match) {
|
|
9305
9619
|
const [, prefix, dynamicValue] = match;
|
|
9306
9620
|
const customKey = `${prefix}custom`;
|
|
@@ -9343,8 +9657,8 @@ function processNestedSelectors(nested, selector, styles, walk) {
|
|
|
9343
9657
|
const nestedVal = nested[nestedSel];
|
|
9344
9658
|
if (nestedSel === "@css" && typeof nestedVal === "object") {
|
|
9345
9659
|
// For @css directive, use raw CSS values without any processing
|
|
9346
|
-
const cssDeclarations = Object.entries(nestedVal).map(
|
|
9347
|
-
let [key, value] =
|
|
9660
|
+
const cssDeclarations = Object.entries(nestedVal).map(_ref => {
|
|
9661
|
+
let [key, value] = _ref;
|
|
9348
9662
|
// Convert camelCase to kebab-case (e.g., borderTopColor -> border-top-color)
|
|
9349
9663
|
const cssKey = key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
9350
9664
|
// Ensure CSS values are properly formatted and not processed through Tailwind conversion
|
|
@@ -9394,6 +9708,17 @@ function walkStyleTree(selector, val, styles, walk) {
|
|
|
9394
9708
|
processNestedSelectors(nested, selector, styles, walk);
|
|
9395
9709
|
} else if (typeof val === "string") {
|
|
9396
9710
|
if (val.trim() === "") return;
|
|
9711
|
+
// Handle @css string directive: '@css { ... }'
|
|
9712
|
+
const trimmedVal = val.trim();
|
|
9713
|
+
if (trimmedVal.startsWith('@css')) {
|
|
9714
|
+
const cssMatch = trimmedVal.match(/^@css\s*\{([\s\S]*)\}\s*$/);
|
|
9715
|
+
if (cssMatch) {
|
|
9716
|
+
const rawCss = cssMatch[1].trim();
|
|
9717
|
+
styles[selector] = styles[selector] || '';
|
|
9718
|
+
styles[selector] += rawCss.split(';').filter(d => d.trim()).map(d => d.trim() + ';').join(' ') + '\n';
|
|
9719
|
+
return;
|
|
9720
|
+
}
|
|
9721
|
+
}
|
|
9397
9722
|
walk(selector, [expandGroupedClass(val)]);
|
|
9398
9723
|
} else if (typeof val === "object" && val !== null) {
|
|
9399
9724
|
const {
|
|
@@ -9410,8 +9735,8 @@ function walkStyleTree(selector, val, styles, walk) {
|
|
|
9410
9735
|
// Check if this is a @css object within the current object
|
|
9411
9736
|
if (val["@css"] && typeof val["@css"] === "object") {
|
|
9412
9737
|
// Handle object with @css directive - process the @css part specially
|
|
9413
|
-
const cssDeclarations = Object.entries(val["@css"]).map(
|
|
9414
|
-
let [key, value] =
|
|
9738
|
+
const cssDeclarations = Object.entries(val["@css"]).map(_ref2 => {
|
|
9739
|
+
let [key, value] = _ref2;
|
|
9415
9740
|
// Convert camelCase to kebab-case (e.g., borderTopColor -> border-top-color)
|
|
9416
9741
|
const cssKey = key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
9417
9742
|
// Keep CSS values intact without any processing
|
|
@@ -9662,6 +9987,17 @@ function twsxNoCache(obj) {
|
|
|
9662
9987
|
let baseClass = "";
|
|
9663
9988
|
const nested = {};
|
|
9664
9989
|
if (typeof val === "string") {
|
|
9990
|
+
// Handle @css string directive: '@css { ... }'
|
|
9991
|
+
const trimmedVal = val.trim();
|
|
9992
|
+
if (trimmedVal.startsWith('@css')) {
|
|
9993
|
+
const cssMatch = trimmedVal.match(/^@css\s*\{([\s\S]*)\}\s*$/);
|
|
9994
|
+
if (cssMatch) {
|
|
9995
|
+
const rawCss = cssMatch[1].trim();
|
|
9996
|
+
styles[selector] = styles[selector] || '';
|
|
9997
|
+
styles[selector] += rawCss.split(';').filter(d => d.trim()).map(d => d.trim() + ';').join(' ') + '\n';
|
|
9998
|
+
continue;
|
|
9999
|
+
}
|
|
10000
|
+
}
|
|
9665
10001
|
// Check if this is a @css property value - if so, don't process through expandGroupedClass
|
|
9666
10002
|
if (selector.includes(" @css ")) {
|
|
9667
10003
|
// This is a CSS property value from @css flattening - keep as-is
|
|
@@ -9691,9 +10027,9 @@ function twsxNoCache(obj) {
|
|
|
9691
10027
|
|
|
9692
10028
|
// Scan CSS for animation names (support camelCase like fadeIn, slideUp)
|
|
9693
10029
|
const usedAnimations = new Set();
|
|
9694
|
-
|
|
10030
|
+
ANIMATION_NAME_REGEX.lastIndex = 0; // Reset global regex
|
|
9695
10031
|
let match;
|
|
9696
|
-
while ((match =
|
|
10032
|
+
while ((match = ANIMATION_NAME_REGEX.exec(cssString)) !== null) {
|
|
9697
10033
|
const animName = match[1];
|
|
9698
10034
|
// Check both original case and lowercase
|
|
9699
10035
|
if (BUILTIN_KEYFRAMES[animName]) {
|
|
@@ -9744,7 +10080,7 @@ function twsxNoCache(obj) {
|
|
|
9744
10080
|
for (const [percentage, styles] of Object.entries(keyframe)) {
|
|
9745
10081
|
customKeyframesCSS += `${percentage}{`;
|
|
9746
10082
|
for (const [prop, value] of Object.entries(styles)) {
|
|
9747
|
-
const cssProp = prop.replace(
|
|
10083
|
+
const cssProp = prop.replace(UPPERCASE_LETTER_REGEX, "-$1").toLowerCase();
|
|
9748
10084
|
customKeyframesCSS += `${cssProp}:${value};`;
|
|
9749
10085
|
}
|
|
9750
10086
|
customKeyframesCSS += "}";
|
|
@@ -10350,7 +10686,7 @@ function twsx(obj) {
|
|
|
10350
10686
|
const {
|
|
10351
10687
|
inject = true
|
|
10352
10688
|
} = options;
|
|
10353
|
-
if (inject &&
|
|
10689
|
+
if (inject && (IS_BROWSER || _ssrCollecting)) {
|
|
10354
10690
|
autoInjectCss(cached);
|
|
10355
10691
|
}
|
|
10356
10692
|
return cached;
|
|
@@ -10359,6 +10695,7 @@ function twsx(obj) {
|
|
|
10359
10695
|
// Cache miss: call original twsxNoCache and cache result
|
|
10360
10696
|
const result = twsxNoCache(obj, options);
|
|
10361
10697
|
_twsxInputCache.set(cacheKey, result);
|
|
10698
|
+
evictMap(_twsxInputCache);
|
|
10362
10699
|
return result;
|
|
10363
10700
|
}
|
|
10364
10701
|
|
|
@@ -10394,6 +10731,7 @@ function twsxVariants(className) {
|
|
|
10394
10731
|
// Cache miss: call original twsxVariantsNoCache and cache result
|
|
10395
10732
|
const result = twsxVariantsNoCache(className, config);
|
|
10396
10733
|
_twsxVariantsResultCache.set(cacheKey, result);
|
|
10734
|
+
evictMap(_twsxVariantsResultCache);
|
|
10397
10735
|
return result;
|
|
10398
10736
|
}
|
|
10399
10737
|
|
|
@@ -10411,25 +10749,64 @@ function getCssHash(str) {
|
|
|
10411
10749
|
return hash;
|
|
10412
10750
|
}
|
|
10413
10751
|
|
|
10414
|
-
// Enhanced auto-inject CSS with performance monitoring
|
|
10752
|
+
// Enhanced auto-inject CSS with performance monitoring & SSR support
|
|
10415
10753
|
const injectedCssHashSet = new Set();
|
|
10416
10754
|
function autoInjectCss(cssString) {
|
|
10417
10755
|
const marker = performanceMonitor.start("css:inject");
|
|
10418
10756
|
try {
|
|
10419
|
-
|
|
10757
|
+
// SSR mode: collect CSS strings instead of DOM injection
|
|
10758
|
+
if (_ssrCollecting) {
|
|
10420
10759
|
const cssHash = getCssHash(cssString);
|
|
10421
10760
|
if (injectedCssHashSet.has(cssHash)) {
|
|
10422
10761
|
performanceMonitor.end(marker);
|
|
10423
10762
|
return;
|
|
10424
10763
|
}
|
|
10425
10764
|
injectedCssHashSet.add(cssHash);
|
|
10765
|
+
evictSet(injectedCssHashSet);
|
|
10766
|
+
_ssrCollectedCss.push(cssString);
|
|
10767
|
+
performanceMonitor.end(marker);
|
|
10768
|
+
return;
|
|
10769
|
+
}
|
|
10770
|
+
if (IS_BROWSER) {
|
|
10771
|
+
const cssHash = getCssHash(cssString);
|
|
10772
|
+
if (injectedCssHashSet.has(cssHash)) {
|
|
10773
|
+
performanceMonitor.end(marker);
|
|
10774
|
+
return;
|
|
10775
|
+
}
|
|
10776
|
+
injectedCssHashSet.add(cssHash);
|
|
10777
|
+
evictSet(injectedCssHashSet);
|
|
10426
10778
|
let styleTag = document.getElementById("twsx-auto-style");
|
|
10427
10779
|
if (!styleTag) {
|
|
10428
10780
|
styleTag = document.createElement("style");
|
|
10429
10781
|
styleTag.id = "twsx-auto-style";
|
|
10782
|
+
styleTag.setAttribute("data-twsx", "");
|
|
10430
10783
|
document.head.appendChild(styleTag);
|
|
10431
10784
|
}
|
|
10432
|
-
|
|
10785
|
+
|
|
10786
|
+
// Use insertRule for better performance (avoids full stylesheet reparse)
|
|
10787
|
+
try {
|
|
10788
|
+
const sheet = styleTag.sheet;
|
|
10789
|
+
if (sheet) {
|
|
10790
|
+
// Split CSS by closing brace to insert individual rules
|
|
10791
|
+
const rules = cssString.split('}').filter(r => r.trim());
|
|
10792
|
+
for (const rule of rules) {
|
|
10793
|
+
const trimmed = rule.trim();
|
|
10794
|
+
if (trimmed) {
|
|
10795
|
+
try {
|
|
10796
|
+
sheet.insertRule(trimmed + '}', sheet.cssRules.length);
|
|
10797
|
+
} catch (e) {
|
|
10798
|
+
// Fallback for complex rules (e.g., @keyframes, @media)
|
|
10799
|
+
styleTag.textContent += `\n${trimmed}}`;
|
|
10800
|
+
}
|
|
10801
|
+
}
|
|
10802
|
+
}
|
|
10803
|
+
} else {
|
|
10804
|
+
styleTag.textContent += `\n${cssString}`;
|
|
10805
|
+
}
|
|
10806
|
+
} catch (e) {
|
|
10807
|
+
// Ultimate fallback
|
|
10808
|
+
styleTag.textContent += `\n${cssString}`;
|
|
10809
|
+
}
|
|
10433
10810
|
|
|
10434
10811
|
// Log injection stats periodically
|
|
10435
10812
|
if (injectedCssHashSet.size % 10 === 0) {
|
|
@@ -10499,6 +10876,5 @@ const performanceUtils = {
|
|
|
10499
10876
|
}
|
|
10500
10877
|
};
|
|
10501
10878
|
|
|
10502
|
-
|
|
10503
|
-
|
|
10504
|
-
export { DYNAMIC_TEMPLATES, INLINE_ANIMATIONS, LRUCache, Logger, TwsError, animateElement, applyDynamicAnimation, applyInlineAnimation, applyWebAnimation, chainAnimations, clearConfigCache, configure, createDynamicAnimation, createPlugin, createTemplateAnimation, createUtilityPlugin, createVariantPlugin, debouncedTws, debouncedTwsx, getConfig, getTailwindCache, handleError, initWebAnimations, logger, onError, performanceUtils, resetConfig, resetTailwindCache, staggerAnimations, tws, twsx, twsxVariants };
|
|
10879
|
+
export { DYNAMIC_TEMPLATES, INLINE_ANIMATIONS, IS_BROWSER, IS_SERVER, LRUCache, Logger, TwsError, animateElement, applyDynamicAnimation, applyInlineAnimation, applyWebAnimation, chainAnimations, clearConfigCache, configure, createDynamicAnimation, createPlugin, createTemplateAnimation, createUtilityPlugin, createVariantPlugin, cx, debouncedTws, debouncedTwsx, getConfig, getSSRStyles, getTailwindCache, handleError, initWebAnimations, logger, onError, performanceUtils, resetConfig, resetTailwindCache, staggerAnimations, startSSR, stopSSR, tws, twsx, twsxVariants };
|
|
10880
|
+
//# sourceMappingURL=index.esm.js.map
|