tailwind-to-style 3.1.3 → 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 +520 -304
- 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 +493 -223
- package/dist/index.d.ts +103 -20
- package/dist/index.esm.js +489 -224
- 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
|
|
@@ -1810,9 +1809,9 @@ try {
|
|
|
1810
1809
|
}
|
|
1811
1810
|
const logger = new Logger(logLevel);
|
|
1812
1811
|
|
|
1813
|
-
/**
|
|
1814
|
-
* User Configuration Management
|
|
1815
|
-
* Handles theme extensions and custom plugin registration
|
|
1812
|
+
/**
|
|
1813
|
+
* User Configuration Management
|
|
1814
|
+
* Handles theme extensions and custom plugin registration
|
|
1816
1815
|
*/
|
|
1817
1816
|
|
|
1818
1817
|
|
|
@@ -1824,8 +1823,8 @@ function setClearConfigCache(fn) {
|
|
|
1824
1823
|
clearConfigCache$1 = fn;
|
|
1825
1824
|
}
|
|
1826
1825
|
|
|
1827
|
-
/**
|
|
1828
|
-
* User configuration state
|
|
1826
|
+
/**
|
|
1827
|
+
* User configuration state
|
|
1829
1828
|
*/
|
|
1830
1829
|
let userConfig = {
|
|
1831
1830
|
theme: {
|
|
@@ -1848,11 +1847,11 @@ let userConfig = {
|
|
|
1848
1847
|
// Cache for extended theme to avoid redundant lookups
|
|
1849
1848
|
const extendedThemeCache = new Map();
|
|
1850
1849
|
|
|
1851
|
-
/**
|
|
1852
|
-
* Deep merge two objects
|
|
1853
|
-
* @param {Object} target - Target object
|
|
1854
|
-
* @param {Object} source - Source object
|
|
1855
|
-
* @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
|
|
1856
1855
|
*/
|
|
1857
1856
|
function deepMerge(target, source) {
|
|
1858
1857
|
const result = {
|
|
@@ -1868,31 +1867,31 @@ function deepMerge(target, source) {
|
|
|
1868
1867
|
return result;
|
|
1869
1868
|
}
|
|
1870
1869
|
|
|
1871
|
-
/**
|
|
1872
|
-
* Configure tailwind-to-style with custom theme and plugins
|
|
1873
|
-
* @param {Object} config - Configuration object
|
|
1874
|
-
* @param {Object} [config.theme] - Theme configuration
|
|
1875
|
-
* @param {Object} [config.theme.extend] - Theme extensions
|
|
1876
|
-
* @param {Array} [config.plugins] - Array of plugins
|
|
1877
|
-
* @param {Object} [config.corePlugins] - Core plugins to enable/disable
|
|
1878
|
-
* @param {string} [config.prefix] - Prefix for all classes
|
|
1879
|
-
*
|
|
1880
|
-
* @example
|
|
1881
|
-
* configure({
|
|
1882
|
-
* theme: {
|
|
1883
|
-
* extend: {
|
|
1884
|
-
* colors: {
|
|
1885
|
-
* brand: {
|
|
1886
|
-
* 500: '#3B82F6',
|
|
1887
|
-
* },
|
|
1888
|
-
* },
|
|
1889
|
-
* spacing: {
|
|
1890
|
-
* 128: '32rem',
|
|
1891
|
-
* },
|
|
1892
|
-
* },
|
|
1893
|
-
* },
|
|
1894
|
-
* plugins: [myCustomPlugin],
|
|
1895
|
-
* });
|
|
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
|
+
* });
|
|
1896
1895
|
*/
|
|
1897
1896
|
function configure() {
|
|
1898
1897
|
let config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -1903,6 +1902,32 @@ function configure() {
|
|
|
1903
1902
|
return;
|
|
1904
1903
|
}
|
|
1905
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
|
+
|
|
1906
1931
|
// Clear extended theme cache when config changes
|
|
1907
1932
|
extendedThemeCache.clear();
|
|
1908
1933
|
|
|
@@ -1954,9 +1979,9 @@ function configure() {
|
|
|
1954
1979
|
}
|
|
1955
1980
|
}
|
|
1956
1981
|
|
|
1957
|
-
/**
|
|
1958
|
-
* Get current user configuration
|
|
1959
|
-
* @returns {Object} Current configuration
|
|
1982
|
+
/**
|
|
1983
|
+
* Get current user configuration
|
|
1984
|
+
* @returns {Object} Current configuration
|
|
1960
1985
|
*/
|
|
1961
1986
|
function getConfig() {
|
|
1962
1987
|
return {
|
|
@@ -1964,8 +1989,8 @@ function getConfig() {
|
|
|
1964
1989
|
};
|
|
1965
1990
|
}
|
|
1966
1991
|
|
|
1967
|
-
/**
|
|
1968
|
-
* Reset configuration to defaults
|
|
1992
|
+
/**
|
|
1993
|
+
* Reset configuration to defaults
|
|
1969
1994
|
*/
|
|
1970
1995
|
function resetConfig() {
|
|
1971
1996
|
userConfig = {
|
|
@@ -1981,10 +2006,10 @@ function resetConfig() {
|
|
|
1981
2006
|
logger.info("Configuration reset to defaults");
|
|
1982
2007
|
}
|
|
1983
2008
|
|
|
1984
|
-
/**
|
|
1985
|
-
* Get extended theme value
|
|
1986
|
-
* @param {string} key - Theme key (e.g., 'colors', 'spacing')
|
|
1987
|
-
* @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
|
|
1988
2013
|
*/
|
|
1989
2014
|
function getExtendedTheme(key) {
|
|
1990
2015
|
// Check cache first
|
|
@@ -1998,17 +2023,17 @@ function getExtendedTheme(key) {
|
|
|
1998
2023
|
return result;
|
|
1999
2024
|
}
|
|
2000
2025
|
|
|
2001
|
-
/**
|
|
2002
|
-
* Get all registered plugins
|
|
2003
|
-
* @returns {Array} Array of plugins
|
|
2026
|
+
/**
|
|
2027
|
+
* Get all registered plugins
|
|
2028
|
+
* @returns {Array} Array of plugins
|
|
2004
2029
|
*/
|
|
2005
2030
|
function getPlugins() {
|
|
2006
2031
|
return userConfig.plugins;
|
|
2007
2032
|
}
|
|
2008
2033
|
|
|
2009
|
-
/**
|
|
2010
|
-
* Get configured prefix
|
|
2011
|
-
* @returns {string} Prefix string
|
|
2034
|
+
/**
|
|
2035
|
+
* Get configured prefix
|
|
2036
|
+
* @returns {string} Prefix string
|
|
2012
2037
|
*/
|
|
2013
2038
|
function getPrefix() {
|
|
2014
2039
|
return userConfig.prefix;
|
|
@@ -2523,9 +2548,9 @@ function staggerAnimations(elements, animationName) {
|
|
|
2523
2548
|
});
|
|
2524
2549
|
}
|
|
2525
2550
|
|
|
2526
|
-
/**
|
|
2527
|
-
* Animation Generator
|
|
2528
|
-
* Generates animation utility classes with dynamic inline animations
|
|
2551
|
+
/**
|
|
2552
|
+
* Animation Generator
|
|
2553
|
+
* Generates animation utility classes with dynamic inline animations
|
|
2529
2554
|
*/
|
|
2530
2555
|
|
|
2531
2556
|
function generator$2I() {
|
|
@@ -7243,9 +7268,9 @@ function generator$d() {
|
|
|
7243
7268
|
return responsiveCssString;
|
|
7244
7269
|
}
|
|
7245
7270
|
|
|
7246
|
-
/**
|
|
7247
|
-
* Transition Delay Generator
|
|
7248
|
-
* Generates transition-delay utility classes
|
|
7271
|
+
/**
|
|
7272
|
+
* Transition Delay Generator
|
|
7273
|
+
* Generates transition-delay utility classes
|
|
7249
7274
|
*/
|
|
7250
7275
|
|
|
7251
7276
|
function generator$c() {
|
|
@@ -7274,9 +7299,9 @@ function generator$c() {
|
|
|
7274
7299
|
return responsiveCssString;
|
|
7275
7300
|
}
|
|
7276
7301
|
|
|
7277
|
-
/**
|
|
7278
|
-
* Transition Duration Generator
|
|
7279
|
-
* Generates transition-duration utility classes
|
|
7302
|
+
/**
|
|
7303
|
+
* Transition Duration Generator
|
|
7304
|
+
* Generates transition-duration utility classes
|
|
7280
7305
|
*/
|
|
7281
7306
|
|
|
7282
7307
|
function generator$b() {
|
|
@@ -7305,9 +7330,9 @@ function generator$b() {
|
|
|
7305
7330
|
return responsiveCssString;
|
|
7306
7331
|
}
|
|
7307
7332
|
|
|
7308
|
-
/**
|
|
7309
|
-
* Transition Property Generator
|
|
7310
|
-
* Generates transition-property utility classes
|
|
7333
|
+
/**
|
|
7334
|
+
* Transition Property Generator
|
|
7335
|
+
* Generates transition-property utility classes
|
|
7311
7336
|
*/
|
|
7312
7337
|
|
|
7313
7338
|
function generator$a() {
|
|
@@ -7347,9 +7372,9 @@ function generator$a() {
|
|
|
7347
7372
|
return responsiveCssString;
|
|
7348
7373
|
}
|
|
7349
7374
|
|
|
7350
|
-
/**
|
|
7351
|
-
* Transition Timing Function Generator
|
|
7352
|
-
* Generates transition-timing-function utility classes (ease)
|
|
7375
|
+
/**
|
|
7376
|
+
* Transition Timing Function Generator
|
|
7377
|
+
* Generates transition-timing-function utility classes (ease)
|
|
7353
7378
|
*/
|
|
7354
7379
|
|
|
7355
7380
|
function generator$9() {
|
|
@@ -7988,6 +8013,108 @@ const patterns = {
|
|
|
7988
8013
|
...fontFamily
|
|
7989
8014
|
};
|
|
7990
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
|
+
|
|
7991
8118
|
/**
|
|
7992
8119
|
* Web Animations API Integration
|
|
7993
8120
|
* Dynamic animations without keyframes injection
|
|
@@ -8309,16 +8436,89 @@ function applyDynamicAnimation(element, templateName) {
|
|
|
8309
8436
|
return animationName;
|
|
8310
8437
|
}
|
|
8311
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
|
+
|
|
8312
8490
|
// Global registry to track injected keyframes (prevents duplication)
|
|
8313
8491
|
const _injectedKeyframes = new Set();
|
|
8314
8492
|
|
|
8315
|
-
// Global cache Maps
|
|
8493
|
+
// Global cache Maps with bounded eviction
|
|
8316
8494
|
const _twsxInputCache = new Map();
|
|
8317
8495
|
const _twsxVariantsResultCache = new Map();
|
|
8318
8496
|
|
|
8319
8497
|
// WeakMap for object identity-based caching (fast lookup for repeated objects)
|
|
8320
8498
|
const _objectIdentityCache = new WeakMap();
|
|
8321
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
|
+
|
|
8322
8522
|
// Mapping of animation names to their keyframe definitions
|
|
8323
8523
|
const BUILTIN_KEYFRAMES = {
|
|
8324
8524
|
spin: {
|
|
@@ -8403,8 +8603,8 @@ function generateMinifiedKeyframes(animationNames) {
|
|
|
8403
8603
|
// by avoiding repeated regex object creation in hot code paths
|
|
8404
8604
|
// ============================================================================
|
|
8405
8605
|
|
|
8406
|
-
// Class parsing
|
|
8407
|
-
const CLASS_PARSER_REGEX = /[\w
|
|
8606
|
+
// Class parsing (includes . for decimal values like p-0.5)
|
|
8607
|
+
const CLASS_PARSER_REGEX = /[\w.\-\/]+(?:\/\d+)?(?:\[[^\]]+\])?/g;
|
|
8408
8608
|
|
|
8409
8609
|
// Opacity modifiers
|
|
8410
8610
|
const OPACITY_MODIFIER_REGEX = /\/(\d+)$/;
|
|
@@ -8440,8 +8640,8 @@ const VARIANT_GROUP_REGEX = /(\w+):\(([^()]+(?:\((?:[^()]+)\))?[^()]*)\)/g;
|
|
|
8440
8640
|
const WHITESPACE_SPLIT_REGEX = /\s+/;
|
|
8441
8641
|
const VARIANT_COLON_SPLIT_REGEX = /:/;
|
|
8442
8642
|
|
|
8443
|
-
// CSS variable resolution
|
|
8444
|
-
const CSS_VAR_REGEX = /var\((--[\w-]+)(?:,\s*([^)]
|
|
8643
|
+
// CSS variable resolution — supports nested parens in fallback (e.g. rgba(...))
|
|
8644
|
+
const CSS_VAR_REGEX = /var\((--[\w-]+)(?:,\s*((?:[^()]+|\([^()]*\))*))?\)/g;
|
|
8445
8645
|
const CAMEL_CASE_REGEX = /-([a-z])/g;
|
|
8446
8646
|
|
|
8447
8647
|
// Animation detection
|
|
@@ -8679,11 +8879,11 @@ function parseCustomClassWithPatterns(className) {
|
|
|
8679
8879
|
return null;
|
|
8680
8880
|
}
|
|
8681
8881
|
|
|
8682
|
-
/**
|
|
8683
|
-
* Resolve all CSS custom properties (var) in a CSS string and output only clear CSS (no custom property)
|
|
8684
|
-
* Optimized with for loops and indexOf for 2-3x better performance
|
|
8685
|
-
* @param {string} cssString
|
|
8686
|
-
* @returns {string} e.g. 'color: rgba(255,255,255,1); background: #fff;'
|
|
8882
|
+
/**
|
|
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
|
|
8885
|
+
* @param {string} cssString
|
|
8886
|
+
* @returns {string} e.g. 'color: rgba(255,255,255,1); background: #fff;'
|
|
8687
8887
|
*/
|
|
8688
8888
|
function resolveCssToClearCss(cssString) {
|
|
8689
8889
|
const customVars = {};
|
|
@@ -8735,9 +8935,9 @@ function resolveCssToClearCss(cssString) {
|
|
|
8735
8935
|
// Cache for getConfigOptions - use LRU cache
|
|
8736
8936
|
const configOptionsCache = new LRUCache(500);
|
|
8737
8937
|
|
|
8738
|
-
/**
|
|
8739
|
-
* Clear config options cache (internal use)
|
|
8740
|
-
* Called when user configuration changes
|
|
8938
|
+
/**
|
|
8939
|
+
* Clear config options cache (internal use)
|
|
8940
|
+
* Called when user configuration changes
|
|
8741
8941
|
*/
|
|
8742
8942
|
function clearConfigCache() {
|
|
8743
8943
|
configOptionsCache.clear();
|
|
@@ -9003,6 +9203,9 @@ function separateAndResolveCSS(arr) {
|
|
|
9003
9203
|
// Prioritize more specific values (e.g., !important)
|
|
9004
9204
|
if (value.includes("!important") || !cssProperties[key]) {
|
|
9005
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;
|
|
9006
9209
|
}
|
|
9007
9210
|
}
|
|
9008
9211
|
}
|
|
@@ -9014,10 +9217,10 @@ function separateAndResolveCSS(arr) {
|
|
|
9014
9217
|
...cssProperties
|
|
9015
9218
|
};
|
|
9016
9219
|
|
|
9017
|
-
/**
|
|
9018
|
-
* Optimized CSS variable resolution using regex-based approach
|
|
9019
|
-
* 2-3x faster than manual char-by-char parsing
|
|
9020
|
-
* Handles nested var() with fallback values
|
|
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
|
|
9021
9224
|
*/
|
|
9022
9225
|
const resolveValue = function (value, variables) {
|
|
9023
9226
|
let maxDepth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;
|
|
@@ -9106,11 +9309,11 @@ function separateAndResolveCSS(arr) {
|
|
|
9106
9309
|
}
|
|
9107
9310
|
}
|
|
9108
9311
|
|
|
9109
|
-
/**
|
|
9110
|
-
* Process opacity modifier from class name (e.g., text-red-500/50 -> 50% opacity)
|
|
9111
|
-
* @param {string} className - Class name with potential opacity modifier
|
|
9112
|
-
* @param {string} cssDeclaration - CSS declaration to modify
|
|
9113
|
-
* @returns {string} Modified CSS declaration with opacity applied
|
|
9312
|
+
/**
|
|
9313
|
+
* Process opacity modifier from class name (e.g., text-red-500/50 -> 50% opacity)
|
|
9314
|
+
* @param {string} className - Class name with potential opacity modifier
|
|
9315
|
+
* @param {string} cssDeclaration - CSS declaration to modify
|
|
9316
|
+
* @returns {string} Modified CSS declaration with opacity applied
|
|
9114
9317
|
*/
|
|
9115
9318
|
function processOpacityModifier(className, cssDeclaration) {
|
|
9116
9319
|
const opacityMatch = OPACITY_MODIFIER_REGEX.exec(className);
|
|
@@ -9173,18 +9376,18 @@ function processOpacityModifier(className, cssDeclaration) {
|
|
|
9173
9376
|
return modifiedDeclaration;
|
|
9174
9377
|
}
|
|
9175
9378
|
|
|
9176
|
-
/**
|
|
9177
|
-
* Convert Tailwind class string to inline CSS styles or JSON object
|
|
9178
|
-
* @param {string} classNames - String containing Tailwind classes to convert
|
|
9179
|
-
* @param {boolean} convertToJson - If true, result will be JSON object, if false becomes CSS string
|
|
9180
|
-
* @returns {string|Object} Inline CSS string or style JSON object
|
|
9379
|
+
/**
|
|
9380
|
+
* Convert Tailwind class string to inline CSS styles or JSON object
|
|
9381
|
+
* @param {string} classNames - String containing Tailwind classes to convert
|
|
9382
|
+
* @param {boolean} convertToJson - If true, result will be JSON object, if false becomes CSS string
|
|
9383
|
+
* @returns {string|Object} Inline CSS string or style JSON object
|
|
9181
9384
|
*/
|
|
9182
9385
|
function tws(classNames, convertToJson) {
|
|
9183
9386
|
const totalMarker = performanceMonitor.start("tws:total");
|
|
9184
9387
|
try {
|
|
9185
9388
|
// Initialize CSS object using singleton cache
|
|
9186
9389
|
const cssObject = tailwindCache.getOrGenerate(generateTailwindCssString, convertCssToObject);
|
|
9187
|
-
if (
|
|
9390
|
+
if (!classNames || typeof classNames !== "string" || classNames.trim() === "") {
|
|
9188
9391
|
performanceMonitor.end(totalMarker);
|
|
9189
9392
|
return convertToJson ? {} : "";
|
|
9190
9393
|
}
|
|
@@ -9505,6 +9708,17 @@ function walkStyleTree(selector, val, styles, walk) {
|
|
|
9505
9708
|
processNestedSelectors(nested, selector, styles, walk);
|
|
9506
9709
|
} else if (typeof val === "string") {
|
|
9507
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
|
+
}
|
|
9508
9722
|
walk(selector, [expandGroupedClass(val)]);
|
|
9509
9723
|
} else if (typeof val === "object" && val !== null) {
|
|
9510
9724
|
const {
|
|
@@ -9681,13 +9895,13 @@ function generateCssString(styles) {
|
|
|
9681
9895
|
return cssString.trim();
|
|
9682
9896
|
}
|
|
9683
9897
|
|
|
9684
|
-
/**
|
|
9685
|
-
* Generate CSS string from style object with SCSS-like syntax (NO CACHE)
|
|
9686
|
-
* This is the original non-cached version. Use twsx() for cached version.
|
|
9687
|
-
* Supports nested selectors, state variants, responsive variants, and @css directives
|
|
9688
|
-
* @param {Object} obj - Object with SCSS-like style format
|
|
9689
|
-
* @param {Object} [options] - Additional options, e.g. { inject: true/false }
|
|
9690
|
-
* @returns {string} Generated CSS string
|
|
9898
|
+
/**
|
|
9899
|
+
* Generate CSS string from style object with SCSS-like syntax (NO CACHE)
|
|
9900
|
+
* This is the original non-cached version. Use twsx() for cached version.
|
|
9901
|
+
* Supports nested selectors, state variants, responsive variants, and @css directives
|
|
9902
|
+
* @param {Object} obj - Object with SCSS-like style format
|
|
9903
|
+
* @param {Object} [options] - Additional options, e.g. { inject: true/false }
|
|
9904
|
+
* @returns {string} Generated CSS string
|
|
9691
9905
|
*/
|
|
9692
9906
|
function twsxNoCache(obj) {
|
|
9693
9907
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -9773,6 +9987,17 @@ function twsxNoCache(obj) {
|
|
|
9773
9987
|
let baseClass = "";
|
|
9774
9988
|
const nested = {};
|
|
9775
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
|
+
}
|
|
9776
10001
|
// Check if this is a @css property value - if so, don't process through expandGroupedClass
|
|
9777
10002
|
if (selector.includes(" @css ")) {
|
|
9778
10003
|
// This is a CSS property value from @css flattening - keep as-is
|
|
@@ -9883,42 +10108,42 @@ function twsxNoCache(obj) {
|
|
|
9883
10108
|
}
|
|
9884
10109
|
}
|
|
9885
10110
|
|
|
9886
|
-
/**
|
|
9887
|
-
* Create a variant-based style generator (NO CACHE)
|
|
9888
|
-
* This is the original non-cached version. Use twsxVariants() for cached version.
|
|
9889
|
-
* Supports base styles, variants, compound variants, and default variants
|
|
9890
|
-
*
|
|
9891
|
-
* @param {Object} config - Configuration object
|
|
9892
|
-
* @param {string} config.base - Base Tailwind classes applied to all variants
|
|
9893
|
-
* @param {Object} config.variants - Variant definitions with their options
|
|
9894
|
-
* @param {Array} config.compoundVariants - Compound variant rules for multi-variant combinations
|
|
9895
|
-
* @param {Object} config.defaultVariants - Default variant values
|
|
9896
|
-
* @returns {Function} A function that accepts variant props and returns merged classes
|
|
9897
|
-
*
|
|
9898
|
-
* @example
|
|
9899
|
-
* const button = twsxVariantsNoCache({
|
|
9900
|
-
* base: 'px-4 py-2 rounded font-medium',
|
|
9901
|
-
* variants: {
|
|
9902
|
-
* color: {
|
|
9903
|
-
* primary: 'bg-blue-500 text-white',
|
|
9904
|
-
* secondary: 'bg-gray-500 text-white'
|
|
9905
|
-
* },
|
|
9906
|
-
* size: {
|
|
9907
|
-
* sm: 'text-sm',
|
|
9908
|
-
* lg: 'text-lg'
|
|
9909
|
-
* }
|
|
9910
|
-
* },
|
|
9911
|
-
* compoundVariants: [
|
|
9912
|
-
* { color: 'primary', size: 'lg', class: 'font-bold shadow-lg' }
|
|
9913
|
-
* ],
|
|
9914
|
-
* defaultVariants: {
|
|
9915
|
-
* color: 'primary',
|
|
9916
|
-
* size: 'sm'
|
|
9917
|
-
* }
|
|
9918
|
-
* });
|
|
9919
|
-
*
|
|
9920
|
-
* // Usage:
|
|
9921
|
-
* button({ color: 'primary', size: 'lg' }) // Returns merged classes
|
|
10111
|
+
/**
|
|
10112
|
+
* Create a variant-based style generator (NO CACHE)
|
|
10113
|
+
* This is the original non-cached version. Use twsxVariants() for cached version.
|
|
10114
|
+
* Supports base styles, variants, compound variants, and default variants
|
|
10115
|
+
*
|
|
10116
|
+
* @param {Object} config - Configuration object
|
|
10117
|
+
* @param {string} config.base - Base Tailwind classes applied to all variants
|
|
10118
|
+
* @param {Object} config.variants - Variant definitions with their options
|
|
10119
|
+
* @param {Array} config.compoundVariants - Compound variant rules for multi-variant combinations
|
|
10120
|
+
* @param {Object} config.defaultVariants - Default variant values
|
|
10121
|
+
* @returns {Function} A function that accepts variant props and returns merged classes
|
|
10122
|
+
*
|
|
10123
|
+
* @example
|
|
10124
|
+
* const button = twsxVariantsNoCache({
|
|
10125
|
+
* base: 'px-4 py-2 rounded font-medium',
|
|
10126
|
+
* variants: {
|
|
10127
|
+
* color: {
|
|
10128
|
+
* primary: 'bg-blue-500 text-white',
|
|
10129
|
+
* secondary: 'bg-gray-500 text-white'
|
|
10130
|
+
* },
|
|
10131
|
+
* size: {
|
|
10132
|
+
* sm: 'text-sm',
|
|
10133
|
+
* lg: 'text-lg'
|
|
10134
|
+
* }
|
|
10135
|
+
* },
|
|
10136
|
+
* compoundVariants: [
|
|
10137
|
+
* { color: 'primary', size: 'lg', class: 'font-bold shadow-lg' }
|
|
10138
|
+
* ],
|
|
10139
|
+
* defaultVariants: {
|
|
10140
|
+
* color: 'primary',
|
|
10141
|
+
* size: 'sm'
|
|
10142
|
+
* }
|
|
10143
|
+
* });
|
|
10144
|
+
*
|
|
10145
|
+
* // Usage:
|
|
10146
|
+
* button({ color: 'primary', size: 'lg' }) // Returns merged classes
|
|
9922
10147
|
*/
|
|
9923
10148
|
function twsxVariantsNoCache(className) {
|
|
9924
10149
|
let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -9930,11 +10155,11 @@ function twsxVariantsNoCache(className) {
|
|
|
9930
10155
|
nested = {}
|
|
9931
10156
|
} = config;
|
|
9932
10157
|
|
|
9933
|
-
/**
|
|
9934
|
-
* Check if a compound variant matches the current props
|
|
9935
|
-
* @param {Object} compound - Compound variant definition
|
|
9936
|
-
* @param {Object} props - Current variant props
|
|
9937
|
-
* @returns {boolean}
|
|
10158
|
+
/**
|
|
10159
|
+
* Check if a compound variant matches the current props
|
|
10160
|
+
* @param {Object} compound - Compound variant definition
|
|
10161
|
+
* @param {Object} props - Current variant props
|
|
10162
|
+
* @returns {boolean}
|
|
9938
10163
|
*/
|
|
9939
10164
|
function matchesCompoundVariant(compound, props) {
|
|
9940
10165
|
for (const key in compound) {
|
|
@@ -9955,19 +10180,19 @@ function twsxVariantsNoCache(className) {
|
|
|
9955
10180
|
return true;
|
|
9956
10181
|
}
|
|
9957
10182
|
|
|
9958
|
-
/**
|
|
9959
|
-
* Merge multiple class strings with conflict resolution
|
|
9960
|
-
* Later classes override earlier ones for the same CSS property
|
|
9961
|
-
* @param {...string} classStrings - Class strings to merge
|
|
9962
|
-
* @returns {string}
|
|
10183
|
+
/**
|
|
10184
|
+
* Merge multiple class strings with conflict resolution
|
|
10185
|
+
* Later classes override earlier ones for the same CSS property
|
|
10186
|
+
* @param {...string} classStrings - Class strings to merge
|
|
10187
|
+
* @returns {string}
|
|
9963
10188
|
*/
|
|
9964
10189
|
function mergeClasses() {
|
|
9965
10190
|
const result = [];
|
|
9966
10191
|
const propertyMap = new Map(); // Track index by conflict key
|
|
9967
10192
|
|
|
9968
|
-
/**
|
|
9969
|
-
* Extract conflict key from Tailwind class
|
|
9970
|
-
* Classes that affect the same CSS property should have the same key
|
|
10193
|
+
/**
|
|
10194
|
+
* Extract conflict key from Tailwind class
|
|
10195
|
+
* Classes that affect the same CSS property should have the same key
|
|
9971
10196
|
*/
|
|
9972
10197
|
function getConflictKey(cls) {
|
|
9973
10198
|
// Extract variant prefix (hover:, focus:, etc.)
|
|
@@ -10199,10 +10424,10 @@ function twsxVariantsNoCache(className) {
|
|
|
10199
10424
|
return result.filter(Boolean).join(" ");
|
|
10200
10425
|
}
|
|
10201
10426
|
|
|
10202
|
-
/**
|
|
10203
|
-
* Generate classes for a specific variant combination
|
|
10204
|
-
* @param {Object} props - Variant props
|
|
10205
|
-
* @returns {string} Merged Tailwind classes
|
|
10427
|
+
/**
|
|
10428
|
+
* Generate classes for a specific variant combination
|
|
10429
|
+
* @param {Object} props - Variant props
|
|
10430
|
+
* @returns {string} Merged Tailwind classes
|
|
10206
10431
|
*/
|
|
10207
10432
|
function generateClasses() {
|
|
10208
10433
|
let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -10318,10 +10543,10 @@ function twsxVariantsNoCache(className) {
|
|
|
10318
10543
|
}
|
|
10319
10544
|
}
|
|
10320
10545
|
|
|
10321
|
-
/**
|
|
10322
|
-
* Build class name string from props (for component usage)
|
|
10323
|
-
* @param {Object} props - Variant props
|
|
10324
|
-
* @returns {string} Class name string like "alert alert-warning" or "btn btn-outline-danger"
|
|
10546
|
+
/**
|
|
10547
|
+
* Build class name string from props (for component usage)
|
|
10548
|
+
* @param {Object} props - Variant props
|
|
10549
|
+
* @returns {string} Class name string like "alert alert-warning" or "btn btn-outline-danger"
|
|
10325
10550
|
*/
|
|
10326
10551
|
function buildClassName() {
|
|
10327
10552
|
let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -10363,10 +10588,10 @@ function twsxVariantsNoCache(className) {
|
|
|
10363
10588
|
// FAST HASHING UTILITIES FOR OBJECT CACHING
|
|
10364
10589
|
// ============================================================================
|
|
10365
10590
|
|
|
10366
|
-
/**
|
|
10367
|
-
* FNV-1a hash algorithm - Fast and good distribution for strings
|
|
10368
|
-
* @param {string} str - String to hash
|
|
10369
|
-
* @returns {number} 32-bit hash
|
|
10591
|
+
/**
|
|
10592
|
+
* FNV-1a hash algorithm - Fast and good distribution for strings
|
|
10593
|
+
* @param {string} str - String to hash
|
|
10594
|
+
* @returns {number} 32-bit hash
|
|
10370
10595
|
*/
|
|
10371
10596
|
function hashString(str) {
|
|
10372
10597
|
let hash = 2166136261; // FNV offset basis
|
|
@@ -10377,16 +10602,16 @@ function hashString(str) {
|
|
|
10377
10602
|
return hash >>> 0; // Convert to unsigned 32-bit
|
|
10378
10603
|
}
|
|
10379
10604
|
|
|
10380
|
-
/**
|
|
10381
|
-
* Fast deep hash for objects - Optimized for style objects
|
|
10382
|
-
* Strategy:
|
|
10383
|
-
* 1. Use object identity (WeakMap) for exact same object references
|
|
10384
|
-
* 2. For different objects, create stable hash from sorted keys + values
|
|
10385
|
-
* 3. Cache hash per object to avoid recomputation
|
|
10386
|
-
*
|
|
10387
|
-
* @param {any} obj - Object to hash
|
|
10388
|
-
* @param {Object} options - Additional options to include in hash
|
|
10389
|
-
* @returns {string} Hash key for caching
|
|
10605
|
+
/**
|
|
10606
|
+
* Fast deep hash for objects - Optimized for style objects
|
|
10607
|
+
* Strategy:
|
|
10608
|
+
* 1. Use object identity (WeakMap) for exact same object references
|
|
10609
|
+
* 2. For different objects, create stable hash from sorted keys + values
|
|
10610
|
+
* 3. Cache hash per object to avoid recomputation
|
|
10611
|
+
*
|
|
10612
|
+
* @param {any} obj - Object to hash
|
|
10613
|
+
* @param {Object} options - Additional options to include in hash
|
|
10614
|
+
* @returns {string} Hash key for caching
|
|
10390
10615
|
*/
|
|
10391
10616
|
function fastObjectHash(obj) {
|
|
10392
10617
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -10431,22 +10656,22 @@ function fastObjectHash(obj) {
|
|
|
10431
10656
|
return options && Object.keys(options).length > 0 ? `${hashKey}:${JSON.stringify(options)}` : hashKey;
|
|
10432
10657
|
}
|
|
10433
10658
|
|
|
10434
|
-
/**
|
|
10435
|
-
* 🚀 CACHED VERSION OF TWSX (DEFAULT)
|
|
10436
|
-
* Generate CSS string with input-level caching for repeated calls
|
|
10437
|
-
* Uses fast FNV-1a hash + WeakMap for 10-100x performance improvement
|
|
10438
|
-
*
|
|
10439
|
-
* @param {Object} obj - Object with SCSS-like style format
|
|
10440
|
-
* @param {Object} [options] - Additional options, e.g. { inject: true/false }
|
|
10441
|
-
* @returns {string} Generated CSS string
|
|
10442
|
-
*
|
|
10443
|
-
* @example
|
|
10444
|
-
* const styles = { '.btn': 'bg-blue-500 text-white p-4' };
|
|
10445
|
-
* twsx(styles); // First call: ~40ms
|
|
10446
|
-
* twsx(styles); // Cached: ~0.1ms (100x faster!)
|
|
10447
|
-
*
|
|
10448
|
-
* // For non-cached version (rare case):
|
|
10449
|
-
* twsxNoCache(styles);
|
|
10659
|
+
/**
|
|
10660
|
+
* 🚀 CACHED VERSION OF TWSX (DEFAULT)
|
|
10661
|
+
* Generate CSS string with input-level caching for repeated calls
|
|
10662
|
+
* Uses fast FNV-1a hash + WeakMap for 10-100x performance improvement
|
|
10663
|
+
*
|
|
10664
|
+
* @param {Object} obj - Object with SCSS-like style format
|
|
10665
|
+
* @param {Object} [options] - Additional options, e.g. { inject: true/false }
|
|
10666
|
+
* @returns {string} Generated CSS string
|
|
10667
|
+
*
|
|
10668
|
+
* @example
|
|
10669
|
+
* const styles = { '.btn': 'bg-blue-500 text-white p-4' };
|
|
10670
|
+
* twsx(styles); // First call: ~40ms
|
|
10671
|
+
* twsx(styles); // Cached: ~0.1ms (100x faster!)
|
|
10672
|
+
*
|
|
10673
|
+
* // For non-cached version (rare case):
|
|
10674
|
+
* twsxNoCache(styles);
|
|
10450
10675
|
*/
|
|
10451
10676
|
function twsx(obj) {
|
|
10452
10677
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -10461,7 +10686,7 @@ function twsx(obj) {
|
|
|
10461
10686
|
const {
|
|
10462
10687
|
inject = true
|
|
10463
10688
|
} = options;
|
|
10464
|
-
if (inject &&
|
|
10689
|
+
if (inject && (IS_BROWSER || _ssrCollecting)) {
|
|
10465
10690
|
autoInjectCss(cached);
|
|
10466
10691
|
}
|
|
10467
10692
|
return cached;
|
|
@@ -10470,27 +10695,28 @@ function twsx(obj) {
|
|
|
10470
10695
|
// Cache miss: call original twsxNoCache and cache result
|
|
10471
10696
|
const result = twsxNoCache(obj, options);
|
|
10472
10697
|
_twsxInputCache.set(cacheKey, result);
|
|
10698
|
+
evictMap(_twsxInputCache);
|
|
10473
10699
|
return result;
|
|
10474
10700
|
}
|
|
10475
10701
|
|
|
10476
|
-
/**
|
|
10477
|
-
* 🚀 CACHED VERSION OF TWSXVARIANTS (DEFAULT)
|
|
10478
|
-
* Create variant-based style generator with config-level caching
|
|
10479
|
-
* Uses fast FNV-1a hash for 10-100x performance improvement
|
|
10480
|
-
*
|
|
10481
|
-
* @param {string} className - Base class name
|
|
10482
|
-
* @param {Object} config - Configuration object (base, variants, compoundVariants, etc.)
|
|
10483
|
-
* @returns {Function} A function that accepts variant props and returns merged classes
|
|
10484
|
-
*
|
|
10485
|
-
* @example
|
|
10486
|
-
* const button = twsxVariants('btn', {
|
|
10487
|
-
* variants: { color: { primary: {...}, secondary: {...} } }
|
|
10488
|
-
* });
|
|
10489
|
-
* // First call: ~50ms to generate function
|
|
10490
|
-
* // Subsequent calls with same config: ~0.1ms (returns cached function)
|
|
10491
|
-
*
|
|
10492
|
-
* // For non-cached version (rare case):
|
|
10493
|
-
* twsxVariantsNoCache('btn', config);
|
|
10702
|
+
/**
|
|
10703
|
+
* 🚀 CACHED VERSION OF TWSXVARIANTS (DEFAULT)
|
|
10704
|
+
* Create variant-based style generator with config-level caching
|
|
10705
|
+
* Uses fast FNV-1a hash for 10-100x performance improvement
|
|
10706
|
+
*
|
|
10707
|
+
* @param {string} className - Base class name
|
|
10708
|
+
* @param {Object} config - Configuration object (base, variants, compoundVariants, etc.)
|
|
10709
|
+
* @returns {Function} A function that accepts variant props and returns merged classes
|
|
10710
|
+
*
|
|
10711
|
+
* @example
|
|
10712
|
+
* const button = twsxVariants('btn', {
|
|
10713
|
+
* variants: { color: { primary: {...}, secondary: {...} } }
|
|
10714
|
+
* });
|
|
10715
|
+
* // First call: ~50ms to generate function
|
|
10716
|
+
* // Subsequent calls with same config: ~0.1ms (returns cached function)
|
|
10717
|
+
*
|
|
10718
|
+
* // For non-cached version (rare case):
|
|
10719
|
+
* twsxVariantsNoCache('btn', config);
|
|
10494
10720
|
*/
|
|
10495
10721
|
function twsxVariants(className) {
|
|
10496
10722
|
let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -10505,6 +10731,7 @@ function twsxVariants(className) {
|
|
|
10505
10731
|
// Cache miss: call original twsxVariantsNoCache and cache result
|
|
10506
10732
|
const result = twsxVariantsNoCache(className, config);
|
|
10507
10733
|
_twsxVariantsResultCache.set(cacheKey, result);
|
|
10734
|
+
evictMap(_twsxVariantsResultCache);
|
|
10508
10735
|
return result;
|
|
10509
10736
|
}
|
|
10510
10737
|
|
|
@@ -10522,25 +10749,64 @@ function getCssHash(str) {
|
|
|
10522
10749
|
return hash;
|
|
10523
10750
|
}
|
|
10524
10751
|
|
|
10525
|
-
// Enhanced auto-inject CSS with performance monitoring
|
|
10752
|
+
// Enhanced auto-inject CSS with performance monitoring & SSR support
|
|
10526
10753
|
const injectedCssHashSet = new Set();
|
|
10527
10754
|
function autoInjectCss(cssString) {
|
|
10528
10755
|
const marker = performanceMonitor.start("css:inject");
|
|
10529
10756
|
try {
|
|
10530
|
-
|
|
10757
|
+
// SSR mode: collect CSS strings instead of DOM injection
|
|
10758
|
+
if (_ssrCollecting) {
|
|
10759
|
+
const cssHash = getCssHash(cssString);
|
|
10760
|
+
if (injectedCssHashSet.has(cssHash)) {
|
|
10761
|
+
performanceMonitor.end(marker);
|
|
10762
|
+
return;
|
|
10763
|
+
}
|
|
10764
|
+
injectedCssHashSet.add(cssHash);
|
|
10765
|
+
evictSet(injectedCssHashSet);
|
|
10766
|
+
_ssrCollectedCss.push(cssString);
|
|
10767
|
+
performanceMonitor.end(marker);
|
|
10768
|
+
return;
|
|
10769
|
+
}
|
|
10770
|
+
if (IS_BROWSER) {
|
|
10531
10771
|
const cssHash = getCssHash(cssString);
|
|
10532
10772
|
if (injectedCssHashSet.has(cssHash)) {
|
|
10533
10773
|
performanceMonitor.end(marker);
|
|
10534
10774
|
return;
|
|
10535
10775
|
}
|
|
10536
10776
|
injectedCssHashSet.add(cssHash);
|
|
10777
|
+
evictSet(injectedCssHashSet);
|
|
10537
10778
|
let styleTag = document.getElementById("twsx-auto-style");
|
|
10538
10779
|
if (!styleTag) {
|
|
10539
10780
|
styleTag = document.createElement("style");
|
|
10540
10781
|
styleTag.id = "twsx-auto-style";
|
|
10782
|
+
styleTag.setAttribute("data-twsx", "");
|
|
10541
10783
|
document.head.appendChild(styleTag);
|
|
10542
10784
|
}
|
|
10543
|
-
|
|
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
|
+
}
|
|
10544
10810
|
|
|
10545
10811
|
// Log injection stats periodically
|
|
10546
10812
|
if (injectedCssHashSet.size % 10 === 0) {
|
|
@@ -10555,19 +10821,19 @@ function autoInjectCss(cssString) {
|
|
|
10555
10821
|
}
|
|
10556
10822
|
|
|
10557
10823
|
// Enhanced debounced functions with performance monitoring configuration
|
|
10558
|
-
/**
|
|
10559
|
-
* Debounced version of tws function with performance monitoring
|
|
10560
|
-
* @param {string} classNames - String containing Tailwind classes to convert
|
|
10561
|
-
* @param {boolean} convertToJson - If true, result will be JSON object, if false becomes CSS string
|
|
10562
|
-
* @returns {string|Object} Inline CSS string or style JSON object
|
|
10824
|
+
/**
|
|
10825
|
+
* Debounced version of tws function with performance monitoring
|
|
10826
|
+
* @param {string} classNames - String containing Tailwind classes to convert
|
|
10827
|
+
* @param {boolean} convertToJson - If true, result will be JSON object, if false becomes CSS string
|
|
10828
|
+
* @returns {string|Object} Inline CSS string or style JSON object
|
|
10563
10829
|
*/
|
|
10564
10830
|
const debouncedTws = debounce(tws, 50); // Faster debounce for tws
|
|
10565
10831
|
|
|
10566
|
-
/**
|
|
10567
|
-
* Debounced version of twsx function with performance monitoring
|
|
10568
|
-
* @param {Object} obj - Object with SCSS-like style format
|
|
10569
|
-
* @param {Object} [options] - Additional options
|
|
10570
|
-
* @returns {string} Generated CSS string
|
|
10832
|
+
/**
|
|
10833
|
+
* Debounced version of twsx function with performance monitoring
|
|
10834
|
+
* @param {Object} obj - Object with SCSS-like style format
|
|
10835
|
+
* @param {Object} [options] - Additional options
|
|
10836
|
+
* @returns {string} Generated CSS string
|
|
10571
10837
|
*/
|
|
10572
10838
|
const debouncedTwsx = debounce(twsx, 100); // Standard debounce for twsx
|
|
10573
10839
|
|
|
@@ -10610,6 +10876,5 @@ const performanceUtils = {
|
|
|
10610
10876
|
}
|
|
10611
10877
|
};
|
|
10612
10878
|
|
|
10613
|
-
|
|
10614
|
-
|
|
10615
|
-
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
|