app-studio 0.7.9 → 0.7.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app-studio.cjs.development.js +296 -261
- package/dist/app-studio.cjs.development.js.map +1 -1
- package/dist/app-studio.cjs.production.min.js +1 -1
- package/dist/app-studio.esm.js +296 -261
- package/dist/app-studio.esm.js.map +1 -1
- package/dist/app-studio.umd.development.js +296 -261
- package/dist/app-studio.umd.development.js.map +1 -1
- package/dist/app-studio.umd.production.min.js +1 -1
- package/dist/utils/vendorPrefixes.d.ts +12 -2
- package/package.json +2 -1
package/dist/app-studio.esm.js
CHANGED
|
@@ -783,91 +783,44 @@ const LIGHT_PREFIX = 'light-';
|
|
|
783
783
|
const DARK_PREFIX = 'dark-';
|
|
784
784
|
const TRANSPARENT = 'transparent';
|
|
785
785
|
// --- CSS Variable Injection Helper ---
|
|
786
|
+
// Optimized: single-pass processing, minimal string allocations, minified output
|
|
786
787
|
const generateCSSVariables = (theme, lightColors, darkColors) => {
|
|
787
|
-
const
|
|
788
|
-
const
|
|
789
|
-
const
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
const
|
|
795
|
-
const
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
processObject(lightColors.palette, 'color', variables);
|
|
807
|
-
processObject(lightColors.main, 'light-color', lightVariables);
|
|
808
|
-
processObject(lightColors.palette, 'light-color', lightVariables);
|
|
809
|
-
processObject(darkColors.main, 'dark-color', darkVariables);
|
|
810
|
-
processObject(darkColors.palette, 'dark-color', darkVariables);
|
|
811
|
-
// We collect the names that need mapping
|
|
812
|
-
const genericColorVars = [];
|
|
813
|
-
const collectGenericNames = (obj, prefix) => {
|
|
814
|
-
Object.keys(obj).forEach(key => {
|
|
815
|
-
const value = obj[key];
|
|
816
|
-
const variableName = `${prefix}-${key}`.replace(/\./g, '-');
|
|
817
|
-
if (typeof value === 'object' && value !== null) {
|
|
818
|
-
collectGenericNames(value, variableName);
|
|
819
|
-
} else {
|
|
820
|
-
genericColorVars.push(variableName);
|
|
821
|
-
}
|
|
822
|
-
});
|
|
823
|
-
};
|
|
824
|
-
collectGenericNames(lightColors.main, 'color');
|
|
825
|
-
collectGenericNames(lightColors.palette, 'color');
|
|
826
|
-
// 3. Process Theme variables (references)
|
|
827
|
-
// Theme config uses dash notation (color-blue-500, theme-primary)
|
|
828
|
-
const processTheme = (obj, prefix) => {
|
|
829
|
-
Object.keys(obj).forEach(key => {
|
|
830
|
-
const value = obj[key];
|
|
831
|
-
const variableName = `${prefix}-${key}`;
|
|
832
|
-
if (typeof value === 'object' && value !== null) {
|
|
833
|
-
processTheme(value, variableName);
|
|
834
|
-
} else if (typeof value === 'string') {
|
|
835
|
-
if (value.startsWith('color-') || value.startsWith('theme-')) {
|
|
836
|
-
// Convert 'color-blue-500' -> 'var(--color-blue-500)'
|
|
837
|
-
themeVariables.push(`--${variableName}: var(--${value});`);
|
|
838
|
-
} else {
|
|
839
|
-
themeVariables.push(`--${variableName}: ${value};`);
|
|
840
|
-
}
|
|
788
|
+
const rootVars = [];
|
|
789
|
+
const lightMappings = [];
|
|
790
|
+
const darkMappings = [];
|
|
791
|
+
// Single-pass helper: generates base, light, dark vars and theme-switch mappings together
|
|
792
|
+
const processColors = (lightObj, darkObj, prefix) => {
|
|
793
|
+
const keys = Object.keys(lightObj);
|
|
794
|
+
for (let i = 0; i < keys.length; i++) {
|
|
795
|
+
const key = keys[i];
|
|
796
|
+
const lightValue = lightObj[key];
|
|
797
|
+
const darkValue = darkObj?.[key];
|
|
798
|
+
const varName = `${prefix}-${key}`;
|
|
799
|
+
if (typeof lightValue === 'object' && lightValue !== null) {
|
|
800
|
+
processColors(lightValue, darkValue, varName);
|
|
801
|
+
} else if (typeof lightValue === 'string' || typeof lightValue === 'number') {
|
|
802
|
+
// :root gets base + light/dark prefixed vars
|
|
803
|
+
rootVars.push(`--${varName}:${lightValue};--light-${varName}:${lightValue};--dark-${varName}:${darkValue ?? lightValue}`);
|
|
804
|
+
// Theme-switching selectors
|
|
805
|
+
lightMappings.push(`--${varName}:var(--light-${varName})`);
|
|
806
|
+
darkMappings.push(`--${varName}:var(--dark-${varName})`);
|
|
841
807
|
}
|
|
842
|
-
});
|
|
843
|
-
};
|
|
844
|
-
processTheme(theme, 'theme');
|
|
845
|
-
// 4. Construct CSS
|
|
846
|
-
// :root has all primitives
|
|
847
|
-
// [data-theme='light'] maps color vars to light primitives
|
|
848
|
-
// [data-theme='dark'] maps color vars to dark primitives
|
|
849
|
-
const lightMappings = genericColorVars.map(name => `--${name}: var(--light-${name});`).join('\n ');
|
|
850
|
-
const darkMappings = genericColorVars.map(name => `--${name}: var(--dark-${name});`).join('\n ');
|
|
851
|
-
const css = `
|
|
852
|
-
:root {
|
|
853
|
-
/* Primitives */
|
|
854
|
-
${variables.join('\n ')}
|
|
855
|
-
${lightVariables.join('\n ')}
|
|
856
|
-
${darkVariables.join('\n ')}
|
|
857
|
-
|
|
858
|
-
/* Theme Variables (Structural) */
|
|
859
|
-
${themeVariables.join('\n ')}
|
|
860
808
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
809
|
+
};
|
|
810
|
+
processColors(lightColors.main, darkColors.main, 'color');
|
|
811
|
+
processColors(lightColors.palette, darkColors.palette, 'color');
|
|
812
|
+
// Process theme variables
|
|
813
|
+
const themeVars = [];
|
|
814
|
+
const themeKeys = Object.keys(theme);
|
|
815
|
+
for (let i = 0; i < themeKeys.length; i++) {
|
|
816
|
+
const key = themeKeys[i];
|
|
817
|
+
const value = theme[key];
|
|
818
|
+
if (typeof value === 'string') {
|
|
819
|
+
themeVars.push(value.startsWith('color-') || value.startsWith('theme-') ? `--theme-${key}:var(--${value})` : `--theme-${key}:${value}`);
|
|
868
820
|
}
|
|
869
|
-
|
|
870
|
-
|
|
821
|
+
}
|
|
822
|
+
// Build minified CSS (no unnecessary whitespace)
|
|
823
|
+
return `:root{${rootVars.join(';')};${themeVars.join(';')}}[data-theme='light']{${lightMappings.join(';')}}[data-theme='dark']{${darkMappings.join(';')}}`;
|
|
871
824
|
};
|
|
872
825
|
// --- Default Configuration ---
|
|
873
826
|
// Theme values use dash notation (color-X or color-X-shade)
|
|
@@ -1774,9 +1727,10 @@ function propertyToKebabCase(property) {
|
|
|
1774
1727
|
return vendorPrefixToKebabCase(property);
|
|
1775
1728
|
}
|
|
1776
1729
|
// Comprehensive list of CSS properties that should be converted to classes
|
|
1730
|
+
// NOTE: Uses a static set instead of document.createElement('div').style
|
|
1731
|
+
// to avoid DOM access at module load time (breaks SSR, adds startup overhead).
|
|
1732
|
+
// The manual list below is comprehensive and covers all commonly used CSS properties.
|
|
1777
1733
|
const cssProperties = /*#__PURE__*/new Set([
|
|
1778
|
-
// Standard CSS properties
|
|
1779
|
-
... /*#__PURE__*/Object.keys(/*#__PURE__*/document.createElement('div').style),
|
|
1780
1734
|
// Box model
|
|
1781
1735
|
'margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft', 'marginHorizontal', 'marginVertical', 'padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'paddingHorizontal', 'paddingVertical', 'width', 'height', 'minWidth', 'minHeight', 'maxWidth', 'maxHeight',
|
|
1782
1736
|
// Positioning
|
|
@@ -1805,22 +1759,71 @@ const cssProperties = /*#__PURE__*/new Set([
|
|
|
1805
1759
|
'textJustify', 'lineClamp', 'textIndent', 'perspective']);
|
|
1806
1760
|
// Common React event handlers that should not be treated as style props
|
|
1807
1761
|
const commonEventHandlers = /*#__PURE__*/new Set(['onClick', 'onChange', 'onSubmit', 'onFocus', 'onBlur', 'onKeyDown', 'onKeyUp', 'onKeyPress', 'onMouseDown', 'onMouseUp', 'onMouseMove', 'onMouseEnter', 'onMouseLeave', 'onTouchStart', 'onTouchEnd', 'onTouchMove', 'onScroll', 'onWheel', 'onDrag', 'onDragStart', 'onDragEnd', 'onDrop']);
|
|
1762
|
+
// Cache for CSS.supports results to avoid repeated DOM queries
|
|
1763
|
+
const cssSupportCache = /*#__PURE__*/new Map();
|
|
1764
|
+
// Non-hyphenated HTML/SVG attributes that must never be treated as style props.
|
|
1765
|
+
// Hyphenated attributes (aria-*, data-*, etc.) are caught by a prefix/hyphen check below.
|
|
1766
|
+
const htmlOnlyAttributes = /*#__PURE__*/new Set([
|
|
1767
|
+
// Accessibility
|
|
1768
|
+
'role', 'tabIndex',
|
|
1769
|
+
// Global HTML attributes
|
|
1770
|
+
'id', 'title', 'lang', 'dir', 'hidden', 'draggable', 'contentEditable', 'spellCheck', 'nonce', 'slot', 'is', 'inputMode', 'enterKeyHint', 'autofocus', 'autoFocus', 'translate',
|
|
1771
|
+
// Form attributes
|
|
1772
|
+
'autoComplete', 'name', 'disabled', 'readOnly', 'required', 'checked', 'selected', 'multiple', 'value', 'defaultValue', 'defaultChecked', 'placeholder', 'htmlFor', 'type', 'accept', 'maxLength', 'minLength', 'pattern', 'noValidate', 'formAction', 'formEncType', 'formMethod', 'formNoValidate', 'formTarget',
|
|
1773
|
+
// Link/navigation attributes
|
|
1774
|
+
'href', 'target', 'rel', 'download', 'referrerPolicy', 'integrity', 'crossOrigin',
|
|
1775
|
+
// Form container attributes
|
|
1776
|
+
'action', 'method', 'encType',
|
|
1777
|
+
// Media attributes
|
|
1778
|
+
'autoPlay', 'controls', 'loop', 'muted', 'playsInline', 'poster', 'preload', 'mediaGroup',
|
|
1779
|
+
// Image/embed attributes
|
|
1780
|
+
'loading', 'decoding', 'sizes', 'srcDoc', 'srcLang', 'srcSet', 'useMap',
|
|
1781
|
+
// Table attributes
|
|
1782
|
+
'colSpan', 'rowSpan', 'cols', 'rows', 'headers', 'scope', 'span',
|
|
1783
|
+
// Iframe/embed attributes
|
|
1784
|
+
'sandbox', 'allowFullScreen', 'frameBorder', 'scrolling', 'seamless', 'allow',
|
|
1785
|
+
// Interactive attributes
|
|
1786
|
+
'open', 'cite', 'dateTime', 'reversed', 'start', 'high', 'low', 'optimum', 'wrap', 'shape', 'size', 'summary',
|
|
1787
|
+
// Script/resource attributes
|
|
1788
|
+
'async', 'defer', 'noModule', 'charSet', 'httpEquiv', 'manifest',
|
|
1789
|
+
// Microdata/RDFa attributes
|
|
1790
|
+
'about', 'datatype', 'inlist', 'prefix', 'property', 'resource', 'typeof', 'vocab', 'itemProp', 'itemScope', 'itemType', 'itemID', 'itemRef',
|
|
1791
|
+
// Deprecated but still used
|
|
1792
|
+
'classID', 'contextMenu', 'keyParams', 'keyType', 'kind', 'label', 'list', 'profile', 'radioGroup', 'wmode', 'capture', 'challenge', 'scoped', 'step', 'form',
|
|
1793
|
+
// SVG-only attributes (not CSS properties)
|
|
1794
|
+
'viewBox', 'preserveAspectRatio', 'xmlns', 'xlinkHref', 'xmlBase', 'xmlLang', 'xmlSpace', 'd', 'pathLength', 'points', 'markerEnd', 'markerMid', 'markerStart', 'clipPathUnits', 'gradientUnits', 'gradientTransform', 'patternUnits', 'patternTransform', 'patternContentUnits', 'spreadMethod', 'startOffset', 'stdDeviation', 'stitchTiles', 'surfaceScale', 'textLength', 'lengthAdjust', 'maskUnits', 'maskContentUnits', 'filterUnits', 'primitiveUnits', 'numOctaves', 'baseFrequency', 'seed', 'result', 'in2', 'values', 'keyTimes', 'keySplines', 'repeatCount', 'repeatDur', 'calcMode', 'attributeName', 'attributeType', 'begin', 'dur', 'end', 'by']);
|
|
1808
1795
|
// Improved style prop detection
|
|
1809
1796
|
const isStyleProp = prop => {
|
|
1810
1797
|
// First check if it's a common event handler (these should never be treated as style props)
|
|
1811
1798
|
if (commonEventHandlers.has(prop)) {
|
|
1812
1799
|
return false;
|
|
1813
1800
|
}
|
|
1801
|
+
// HTML attributes should never be treated as style props
|
|
1802
|
+
if (htmlOnlyAttributes.has(prop)) {
|
|
1803
|
+
return false;
|
|
1804
|
+
}
|
|
1805
|
+
// Any prop containing a hyphen is an HTML attribute (aria-*, data-*, accept-charset, etc.)
|
|
1806
|
+
// In React, CSS properties are always camelCase — only CSS custom properties use hyphens (--*),
|
|
1807
|
+
// and data-style-* is a special convention handled separately below.
|
|
1808
|
+
if (prop.includes('-') && !prop.startsWith('--') && !prop.startsWith('data-style-')) {
|
|
1809
|
+
return false;
|
|
1810
|
+
}
|
|
1814
1811
|
// Check if it's a valid CSS property or custom style prop
|
|
1815
1812
|
if (cssProperties.has(prop) || extraKeys.has(prop) || prop.startsWith('--') || prop.startsWith('data-style-') && !includeKeys.has(prop)) {
|
|
1816
1813
|
return true;
|
|
1817
1814
|
}
|
|
1818
1815
|
// Check if it's a valid CSS property using CSS.supports (browser environment)
|
|
1816
|
+
// Results are cached to avoid repeated CSS.supports calls
|
|
1819
1817
|
if (typeof CSS !== 'undefined' && CSS.supports) {
|
|
1818
|
+
const cached = cssSupportCache.get(prop);
|
|
1819
|
+
if (cached !== undefined) return cached;
|
|
1820
1820
|
try {
|
|
1821
1821
|
const kebabProp = vendorPrefixToKebabCase(prop);
|
|
1822
|
-
|
|
1822
|
+
const result = CSS.supports(kebabProp, 'inherit');
|
|
1823
|
+
cssSupportCache.set(prop, result);
|
|
1824
|
+
return result;
|
|
1823
1825
|
} catch {
|
|
1826
|
+
cssSupportCache.set(prop, false);
|
|
1824
1827
|
return false;
|
|
1825
1828
|
}
|
|
1826
1829
|
}
|
|
@@ -1954,67 +1957,25 @@ const generateKeyframes = animation => {
|
|
|
1954
1957
|
|
|
1955
1958
|
/**
|
|
1956
1959
|
* Mapping of standard CSS properties to their vendor-prefixed equivalents.
|
|
1957
|
-
*
|
|
1958
|
-
*
|
|
1960
|
+
*
|
|
1961
|
+
* Optimized for modern browsers (Chrome 100+, Safari 15+, Firefox 91+).
|
|
1962
|
+
* Most properties no longer need vendor prefixes in these browsers.
|
|
1963
|
+
* Only -webkit- prefixes are kept where still needed by Safari/WebKit.
|
|
1964
|
+
*
|
|
1965
|
+
* Removed prefixes:
|
|
1966
|
+
* - -moz- (Firefox 91+ supports all standard properties unprefixed)
|
|
1967
|
+
* - -ms- (IE/Edge Legacy no longer supported)
|
|
1968
|
+
* - -o- (Opera uses Blink engine, same as Chrome)
|
|
1969
|
+
* - -webkit- for animation, transform, transition, flexbox, boxShadow,
|
|
1970
|
+
* boxSizing, columns, borderImage, backgroundSize, backgroundOrigin,
|
|
1971
|
+
* perspective, hyphens (all unprefixed in Safari 15+)
|
|
1959
1972
|
*/
|
|
1960
|
-
// Properties that
|
|
1973
|
+
// Properties that still need vendor prefixes in modern browsers
|
|
1961
1974
|
const vendorPrefixedProperties = {
|
|
1962
|
-
//
|
|
1963
|
-
|
|
1964
|
-
animationDelay: ['-webkit-animation-delay', '-moz-animation-delay', '-o-animation-delay'],
|
|
1965
|
-
animationDirection: ['-webkit-animation-direction', '-moz-animation-direction', '-o-animation-direction'],
|
|
1966
|
-
animationDuration: ['-webkit-animation-duration', '-moz-animation-duration', '-o-animation-duration'],
|
|
1967
|
-
animationFillMode: ['-webkit-animation-fill-mode', '-moz-animation-fill-mode', '-o-animation-fill-mode'],
|
|
1968
|
-
animationIterationCount: ['-webkit-animation-iteration-count', '-moz-animation-iteration-count', '-o-animation-iteration-count'],
|
|
1969
|
-
animationName: ['-webkit-animation-name', '-moz-animation-name', '-o-animation-name'],
|
|
1970
|
-
animationPlayState: ['-webkit-animation-play-state', '-moz-animation-play-state', '-o-animation-play-state'],
|
|
1971
|
-
animationTimingFunction: ['-webkit-animation-timing-function', '-moz-animation-timing-function', '-o-animation-timing-function'],
|
|
1972
|
-
// Transform properties
|
|
1973
|
-
transform: ['-webkit-transform', '-moz-transform', '-ms-transform', '-o-transform'],
|
|
1974
|
-
transformOrigin: ['-webkit-transform-origin', '-moz-transform-origin', '-ms-transform-origin', '-o-transform-origin'],
|
|
1975
|
-
transformStyle: ['-webkit-transform-style', '-moz-transform-style', '-ms-transform-style'],
|
|
1976
|
-
// Transition properties
|
|
1977
|
-
transition: ['-webkit-transition', '-moz-transition', '-ms-transition', '-o-transition'],
|
|
1978
|
-
transitionDelay: ['-webkit-transition-delay', '-moz-transition-delay', '-ms-transition-delay', '-o-transition-delay'],
|
|
1979
|
-
transitionDuration: ['-webkit-transition-duration', '-moz-transition-duration', '-ms-transition-duration', '-o-transition-duration'],
|
|
1980
|
-
transitionProperty: ['-webkit-transition-property', '-moz-transition-property', '-ms-transition-property', '-o-transition-property'],
|
|
1981
|
-
transitionTimingFunction: ['-webkit-transition-timing-function', '-moz-transition-timing-function', '-ms-transition-timing-function', '-o-transition-timing-function'],
|
|
1982
|
-
// Flexbox properties
|
|
1983
|
-
flex: ['-webkit-flex', '-ms-flex'],
|
|
1984
|
-
flexBasis: ['-webkit-flex-basis', '-ms-flex-basis'],
|
|
1985
|
-
flexDirection: ['-webkit-flex-direction', '-ms-flex-direction'],
|
|
1986
|
-
flexFlow: ['-webkit-flex-flow', '-ms-flex-flow'],
|
|
1987
|
-
flexGrow: ['-webkit-flex-grow', '-ms-flex-positive'],
|
|
1988
|
-
flexShrink: ['-webkit-flex-shrink', '-ms-flex-negative'],
|
|
1989
|
-
flexWrap: ['-webkit-flex-wrap', '-ms-flex-wrap'],
|
|
1990
|
-
justifyContent: ['-webkit-justify-content', '-ms-flex-pack'],
|
|
1991
|
-
alignItems: ['-webkit-align-items', '-ms-flex-align'],
|
|
1992
|
-
alignContent: ['-webkit-align-content', '-ms-flex-line-pack'],
|
|
1993
|
-
alignSelf: ['-webkit-align-self', '-ms-flex-item-align'],
|
|
1994
|
-
order: ['-webkit-order', '-ms-flex-order'],
|
|
1995
|
-
// Other commonly prefixed properties
|
|
1996
|
-
appearance: ['-webkit-appearance', '-moz-appearance', '-ms-appearance'],
|
|
1997
|
-
backfaceVisibility: ['-webkit-backface-visibility', '-moz-backface-visibility'],
|
|
1998
|
-
backgroundClip: ['-webkit-background-clip', '-moz-background-clip'],
|
|
1999
|
-
backgroundOrigin: ['-webkit-background-origin', '-moz-background-origin'],
|
|
2000
|
-
backgroundSize: ['-webkit-background-size', '-moz-background-size', '-o-background-size'],
|
|
2001
|
-
borderImage: ['-webkit-border-image', '-moz-border-image', '-o-border-image'],
|
|
2002
|
-
boxShadow: ['-webkit-box-shadow', '-moz-box-shadow'],
|
|
2003
|
-
boxSizing: ['-webkit-box-sizing', '-moz-box-sizing'],
|
|
2004
|
-
columns: ['-webkit-columns', '-moz-columns'],
|
|
2005
|
-
columnCount: ['-webkit-column-count', '-moz-column-count'],
|
|
2006
|
-
columnGap: ['-webkit-column-gap', '-moz-column-gap'],
|
|
2007
|
-
columnRule: ['-webkit-column-rule', '-moz-column-rule'],
|
|
2008
|
-
columnWidth: ['-webkit-column-width', '-moz-column-width'],
|
|
2009
|
-
filter: ['-webkit-filter'],
|
|
2010
|
-
fontSmoothing: ['-webkit-font-smoothing', '-moz-osx-font-smoothing'],
|
|
2011
|
-
hyphens: ['-webkit-hyphens', '-moz-hyphens', '-ms-hyphens'],
|
|
1975
|
+
// Properties that still need -webkit- in Safari
|
|
1976
|
+
backgroundClip: ['-webkit-background-clip'],
|
|
2012
1977
|
maskImage: ['-webkit-mask-image'],
|
|
2013
|
-
|
|
2014
|
-
perspectiveOrigin: ['-webkit-perspective-origin', '-moz-perspective-origin'],
|
|
2015
|
-
textSizeAdjust: ['-webkit-text-size-adjust', '-moz-text-size-adjust', '-ms-text-size-adjust'],
|
|
2016
|
-
userSelect: ['-webkit-user-select', '-moz-user-select', '-ms-user-select'],
|
|
2017
|
-
// Special webkit-only properties
|
|
1978
|
+
// Webkit-only properties (no unprefixed equivalent)
|
|
2018
1979
|
textFillColor: ['-webkit-text-fill-color'],
|
|
2019
1980
|
textStroke: ['-webkit-text-stroke'],
|
|
2020
1981
|
textStrokeColor: ['-webkit-text-stroke-color'],
|
|
@@ -2254,20 +2215,18 @@ const ValueUtils = {
|
|
|
2254
2215
|
return processStyleProperty(property, value, getColor);
|
|
2255
2216
|
},
|
|
2256
2217
|
normalizeCssValue(value) {
|
|
2218
|
+
const str = typeof value === 'string' ? value : String(value);
|
|
2257
2219
|
// Handle CSS variables in values
|
|
2258
|
-
if (
|
|
2259
|
-
//
|
|
2260
|
-
return `var-${
|
|
2220
|
+
if (str.charCodeAt(0) === 45 && str.charCodeAt(1) === 45) {
|
|
2221
|
+
// starts with '--'
|
|
2222
|
+
return `var-${str.substring(2)}`;
|
|
2261
2223
|
}
|
|
2262
2224
|
// Handle vendor-prefixed values
|
|
2263
|
-
if (
|
|
2264
|
-
|
|
2265
|
-
const prefix = '-webkit-';
|
|
2266
|
-
const rest = value.substring(prefix.length);
|
|
2267
|
-
const normalizedRest = rest.replace(/\./g, 'p').replace(/\s+/g, '-').replace(/[^a-zA-Z0-9\-]/g, '').replace(/%/g, 'pct').replace(/vw/g, 'vw').replace(/vh/g, 'vh').replace(/em/g, 'em').replace(/rem/g, 'rem');
|
|
2268
|
-
return `webkit-${normalizedRest}`;
|
|
2225
|
+
if (str.startsWith('-webkit-')) {
|
|
2226
|
+
return `webkit-${str.substring(8).replace(/\./g, 'p').replace(/\s+/g, '-').replace(/[^a-zA-Z0-9-]/g, '')}`;
|
|
2269
2227
|
}
|
|
2270
|
-
|
|
2228
|
+
// Single-pass normalization: replace dots with 'p', spaces with '-', strip non-alphanumeric
|
|
2229
|
+
return str.replace(/\./g, 'p').replace(/\s+/g, '-').replace(/[^a-zA-Z0-9-]/g, '');
|
|
2271
2230
|
},
|
|
2272
2231
|
generateUniqueClassName(css) {
|
|
2273
2232
|
if (rawCssCache.has(css)) {
|
|
@@ -2631,21 +2590,24 @@ function processStyles(styles, context, modifier, getColor, mediaQueries, device
|
|
|
2631
2590
|
devices = {};
|
|
2632
2591
|
}
|
|
2633
2592
|
const classes = [];
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
}
|
|
2593
|
+
const activeManager = manager || utilityClassManager;
|
|
2594
|
+
// Pre-compute media queries for this modifier (only done once per call)
|
|
2595
|
+
let mediaQueriesForClass = [];
|
|
2596
|
+
if (context === 'media') {
|
|
2597
|
+
if (mediaQueries[modifier]) {
|
|
2598
|
+
mediaQueriesForClass = [mediaQueries[modifier]];
|
|
2599
|
+
} else if (devices[modifier]) {
|
|
2600
|
+
mediaQueriesForClass = devices[modifier].map(mq => mediaQueries[mq]).filter(mq => mq);
|
|
2643
2601
|
}
|
|
2602
|
+
}
|
|
2603
|
+
const keys = Object.keys(styles);
|
|
2604
|
+
for (let i = 0; i < keys.length; i++) {
|
|
2605
|
+
const value = styles[keys[i]];
|
|
2644
2606
|
if (value !== undefined && value !== '') {
|
|
2645
|
-
const classNames =
|
|
2607
|
+
const classNames = activeManager.getClassNames(keys[i], value, context, modifier, getColor, mediaQueriesForClass);
|
|
2646
2608
|
classes.push(...classNames);
|
|
2647
2609
|
}
|
|
2648
|
-
}
|
|
2610
|
+
}
|
|
2649
2611
|
return classes;
|
|
2650
2612
|
}
|
|
2651
2613
|
// Add a function to handle nested pseudo-classes
|
|
@@ -2764,6 +2726,7 @@ function processEventStyles(eventName, eventStyles, getColor, manager) {
|
|
|
2764
2726
|
const extractUtilityClasses = (props, getColor, mediaQueries, devices, manager) => {
|
|
2765
2727
|
const classes = [];
|
|
2766
2728
|
const computedStyles = {};
|
|
2729
|
+
const activeManager = manager || utilityClassManager;
|
|
2767
2730
|
// Handle widthHeight (shorthand for both width and height)
|
|
2768
2731
|
if (props.widthHeight || props.height !== undefined && props.width !== undefined && props.height === props.width) {
|
|
2769
2732
|
const widthHeightValue = props.widthHeight || props.width;
|
|
@@ -2771,21 +2734,30 @@ const extractUtilityClasses = (props, getColor, mediaQueries, devices, manager)
|
|
|
2771
2734
|
computedStyles.width = formattedValue;
|
|
2772
2735
|
computedStyles.height = formattedValue;
|
|
2773
2736
|
}
|
|
2774
|
-
// Handle padding and margin shorthands
|
|
2775
|
-
const
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
}
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2737
|
+
// Handle padding and margin shorthands (inlined to avoid Object.entries overhead)
|
|
2738
|
+
const ph = props.paddingHorizontal;
|
|
2739
|
+
if (ph !== undefined) {
|
|
2740
|
+
const v = typeof ph === 'number' ? `${ph}px` : ph;
|
|
2741
|
+
computedStyles.paddingLeft = v;
|
|
2742
|
+
computedStyles.paddingRight = v;
|
|
2743
|
+
}
|
|
2744
|
+
const pv = props.paddingVertical;
|
|
2745
|
+
if (pv !== undefined) {
|
|
2746
|
+
const v = typeof pv === 'number' ? `${pv}px` : pv;
|
|
2747
|
+
computedStyles.paddingTop = v;
|
|
2748
|
+
computedStyles.paddingBottom = v;
|
|
2749
|
+
}
|
|
2750
|
+
const mh = props.marginHorizontal;
|
|
2751
|
+
if (mh !== undefined) {
|
|
2752
|
+
const v = typeof mh === 'number' ? `${mh}px` : mh;
|
|
2753
|
+
computedStyles.marginLeft = v;
|
|
2754
|
+
computedStyles.marginRight = v;
|
|
2755
|
+
}
|
|
2756
|
+
const mv = props.marginVertical;
|
|
2757
|
+
if (mv !== undefined) {
|
|
2758
|
+
const v = typeof mv === 'number' ? `${mv}px` : mv;
|
|
2759
|
+
computedStyles.marginTop = v;
|
|
2760
|
+
computedStyles.marginBottom = v;
|
|
2789
2761
|
}
|
|
2790
2762
|
// Handle shadows
|
|
2791
2763
|
if (props.shadow !== undefined) {
|
|
@@ -2814,80 +2786,103 @@ const extractUtilityClasses = (props, getColor, mediaQueries, devices, manager)
|
|
|
2814
2786
|
const animations = Array.isArray(props.animate) ? props.animate : [props.animate];
|
|
2815
2787
|
Object.assign(computedStyles, AnimationUtils.processAnimations(animations, manager));
|
|
2816
2788
|
}
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
color: 'white',
|
|
2820
|
-
modeWithBg: 'overlay'
|
|
2821
|
-
};
|
|
2822
|
-
const setBlend = (props, style) => {
|
|
2789
|
+
// Handle default blend
|
|
2790
|
+
if (props.blend === true) {
|
|
2823
2791
|
if (props.bgColor) {
|
|
2824
|
-
|
|
2825
|
-
|
|
2792
|
+
computedStyles.mixBlendMode = 'overlay';
|
|
2793
|
+
computedStyles.color = 'white';
|
|
2826
2794
|
} else {
|
|
2827
|
-
|
|
2828
|
-
|
|
2795
|
+
computedStyles.mixBlendMode = 'difference';
|
|
2796
|
+
computedStyles.color = 'white';
|
|
2829
2797
|
}
|
|
2830
|
-
};
|
|
2831
|
-
// Handle default blend
|
|
2832
|
-
if (props.blend === true) {
|
|
2833
|
-
setBlend(props, computedStyles);
|
|
2834
|
-
Object.keys(props).forEach(property => {
|
|
2835
|
-
if (props[property]?.color === undefined && (property.startsWith('_') || property === 'on' || property === 'media')) {
|
|
2836
|
-
setBlend(props[property], props[property]);
|
|
2837
|
-
}
|
|
2838
|
-
});
|
|
2839
2798
|
}
|
|
2840
|
-
// Process base styles
|
|
2799
|
+
// Process base computed styles
|
|
2841
2800
|
classes.push(...processStyles(computedStyles, 'base', '', getColor, {}, {}, manager));
|
|
2842
|
-
//
|
|
2843
|
-
const
|
|
2844
|
-
|
|
2845
|
-
|
|
2801
|
+
// SINGLE PASS over props: classify each prop into style, event, or underscore
|
|
2802
|
+
const propKeys = Object.keys(props);
|
|
2803
|
+
for (let i = 0; i < propKeys.length; i++) {
|
|
2804
|
+
const property = propKeys[i];
|
|
2805
|
+
const value = props[property];
|
|
2806
|
+
// Handle underscore-prefixed event properties (_hover, _focus, etc.)
|
|
2807
|
+
if (property.charCodeAt(0) === 95 && property.length > 1) {
|
|
2808
|
+
// 95 = '_'
|
|
2846
2809
|
const eventName = property.substring(1);
|
|
2847
|
-
|
|
2810
|
+
classes.push(...processEventStyles(eventName, value, getColor, manager));
|
|
2811
|
+
// Handle blend for underscore props
|
|
2812
|
+
if (props.blend === true && value?.color === undefined) {
|
|
2813
|
+
if (props.bgColor) {
|
|
2814
|
+
value.mixBlendMode = 'overlay';
|
|
2815
|
+
value.color = 'white';
|
|
2816
|
+
} else {
|
|
2817
|
+
value.mixBlendMode = 'difference';
|
|
2818
|
+
value.color = 'white';
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
continue;
|
|
2848
2822
|
}
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
const value = props[property];
|
|
2823
|
+
// Skip non-style props
|
|
2824
|
+
if (property === 'style' || property === 'css') continue;
|
|
2825
|
+
if (property === 'on') {
|
|
2826
|
+
// Process event-based styles
|
|
2854
2827
|
if (typeof value === 'object' && value !== null) {
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
}
|
|
2828
|
+
const events = Object.keys(value);
|
|
2829
|
+
for (let j = 0; j < events.length; j++) {
|
|
2830
|
+
classes.push(...processEventStyles(events[j], value[events[j]], getColor, manager));
|
|
2831
|
+
}
|
|
2832
|
+
// Handle blend for 'on' prop
|
|
2833
|
+
if (props.blend === true && value?.color === undefined) {
|
|
2834
|
+
if (props.bgColor) {
|
|
2835
|
+
value.mixBlendMode = 'overlay';
|
|
2836
|
+
value.color = 'white';
|
|
2837
|
+
} else {
|
|
2838
|
+
value.mixBlendMode = 'difference';
|
|
2839
|
+
value.color = 'white';
|
|
2840
|
+
}
|
|
2865
2841
|
}
|
|
2866
|
-
} else if (value !== undefined && value !== '') {
|
|
2867
|
-
// Direct style property
|
|
2868
|
-
classes.push(...(manager || utilityClassManager).getClassNames(property, value, 'base', '', getColor, []));
|
|
2869
2842
|
}
|
|
2843
|
+
continue;
|
|
2870
2844
|
}
|
|
2871
|
-
|
|
2845
|
+
if (property === 'media') {
|
|
2846
|
+
// Process media query styles
|
|
2847
|
+
if (typeof value === 'object' && value !== null) {
|
|
2848
|
+
const screens = Object.keys(value);
|
|
2849
|
+
for (let j = 0; j < screens.length; j++) {
|
|
2850
|
+
classes.push(...processStyles(value[screens[j]], 'media', screens[j], getColor, mediaQueries, devices, manager));
|
|
2851
|
+
}
|
|
2852
|
+
// Handle blend for 'media' prop
|
|
2853
|
+
if (props.blend === true && value?.color === undefined) {
|
|
2854
|
+
if (props.bgColor) {
|
|
2855
|
+
value.mixBlendMode = 'overlay';
|
|
2856
|
+
value.color = 'white';
|
|
2857
|
+
} else {
|
|
2858
|
+
value.mixBlendMode = 'difference';
|
|
2859
|
+
value.color = 'white';
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2863
|
+
continue;
|
|
2864
|
+
}
|
|
2865
|
+
// Standard style props
|
|
2866
|
+
if (isStyleProp(property)) {
|
|
2867
|
+
if (value !== undefined && value !== '') {
|
|
2868
|
+
if (typeof value === 'object' && value !== null) {
|
|
2869
|
+
// Object-style props are not directly processed as base styles
|
|
2870
|
+
continue;
|
|
2871
|
+
}
|
|
2872
|
+
classes.push(...activeManager.getClassNames(property, value, 'base', '', getColor, []));
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2872
2876
|
// Handle raw CSS - uses 'override' context for higher specificity
|
|
2873
2877
|
if (props.css) {
|
|
2874
2878
|
if (typeof props.css === 'object') {
|
|
2875
|
-
// Object-style CSS gets processed with override context for higher priority
|
|
2876
|
-
Object.assign(computedStyles, props.css);
|
|
2877
2879
|
classes.push(...processStyles(props.css, 'override', '', getColor, {}, {}, manager));
|
|
2878
2880
|
} else if (typeof props.css === 'string') {
|
|
2879
|
-
// String-style CSS gets its own class in override context
|
|
2880
2881
|
const uniqueClassName = ValueUtils.generateUniqueClassName(props.css);
|
|
2881
|
-
|
|
2882
|
+
activeManager.injectRule(`.${uniqueClassName} { ${props.css} }`, 'override');
|
|
2882
2883
|
classes.push(uniqueClassName);
|
|
2883
2884
|
}
|
|
2884
2885
|
}
|
|
2885
|
-
// Process underscore-prefixed event properties
|
|
2886
|
-
if (Object.keys(underscoreProps).length > 0) {
|
|
2887
|
-
Object.keys(underscoreProps).forEach(event => {
|
|
2888
|
-
classes.push(...processEventStyles(event, underscoreProps[event], getColor, manager));
|
|
2889
|
-
});
|
|
2890
|
-
}
|
|
2891
2886
|
return classes;
|
|
2892
2887
|
};
|
|
2893
2888
|
|
|
@@ -2954,27 +2949,47 @@ const AnalyticsProvider = _ref => {
|
|
|
2954
2949
|
}, children);
|
|
2955
2950
|
};
|
|
2956
2951
|
|
|
2952
|
+
// Set of special prop names that affect CSS generation
|
|
2953
|
+
const styleRelevantProps = /*#__PURE__*/new Set(['on', 'media', 'animate', 'css', 'shadow', 'blend', 'widthHeight', 'paddingHorizontal', 'paddingVertical', 'marginHorizontal', 'marginVertical']);
|
|
2954
|
+
// Skip these props from hash computation
|
|
2955
|
+
const skipHashProps = /*#__PURE__*/new Set(['children', 'ref', 'key', 'style']);
|
|
2956
|
+
/**
|
|
2957
|
+
* Fast serialization of a value for hashing purposes.
|
|
2958
|
+
* Avoids JSON.stringify overhead for common cases (strings, numbers, booleans).
|
|
2959
|
+
*/
|
|
2960
|
+
function fastSerialize(value) {
|
|
2961
|
+
if (value === null) return 'n';
|
|
2962
|
+
const t = typeof value;
|
|
2963
|
+
if (t === 'string') return `s${value}`;
|
|
2964
|
+
if (t === 'number') return `d${value}`;
|
|
2965
|
+
if (t === 'boolean') return value ? 'T' : 'F';
|
|
2966
|
+
// Fall back to JSON.stringify only for complex objects
|
|
2967
|
+
return JSON.stringify(value);
|
|
2968
|
+
}
|
|
2957
2969
|
/**
|
|
2958
2970
|
* Computes a stable hash of style-relevant props.
|
|
2959
|
-
*
|
|
2971
|
+
* Optimized: avoids sorting, uses fast serialization, feeds directly to hash.
|
|
2960
2972
|
*/
|
|
2961
2973
|
function hashStyleProps(props) {
|
|
2962
2974
|
// Build a deterministic string representation of style-relevant props
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2975
|
+
// We use a single string accumulator instead of array + join
|
|
2976
|
+
let hashInput = '';
|
|
2977
|
+
const keys = Object.keys(props);
|
|
2978
|
+
for (let i = 0; i < keys.length; i++) {
|
|
2979
|
+
const key = keys[i];
|
|
2966
2980
|
// Skip non-style props that don't affect CSS generation
|
|
2967
|
-
if (key
|
|
2981
|
+
if (skipHashProps.has(key)) continue;
|
|
2968
2982
|
// Include style-relevant props
|
|
2969
|
-
if (isStyleProp(key) || key.
|
|
2983
|
+
if (isStyleProp(key) || key.charCodeAt(0) === 95 ||
|
|
2984
|
+
// starts with '_'
|
|
2985
|
+
styleRelevantProps.has(key)) {
|
|
2970
2986
|
const value = props[key];
|
|
2971
2987
|
if (value !== undefined) {
|
|
2972
|
-
|
|
2973
|
-
parts.push(`${key}:${JSON.stringify(value)}`);
|
|
2988
|
+
hashInput += `|${key}:${fastSerialize(value)}`;
|
|
2974
2989
|
}
|
|
2975
2990
|
}
|
|
2976
2991
|
}
|
|
2977
|
-
return hash(
|
|
2992
|
+
return hash(hashInput);
|
|
2978
2993
|
}
|
|
2979
2994
|
/**
|
|
2980
2995
|
* Custom hook that memoizes style extraction based on a stable hash of props.
|
|
@@ -2984,8 +2999,9 @@ function useStableStyleMemo(propsToProcess, getColor, mediaQueries, devices, man
|
|
|
2984
2999
|
const cacheRef = useRef(null);
|
|
2985
3000
|
// Compute hash directly — no useMemo since propsToProcess is always a new
|
|
2986
3001
|
// reference (from destructuring), so the memo deps would always change.
|
|
2987
|
-
|
|
2988
|
-
const
|
|
3002
|
+
// Theme hash uses Object.values() concatenation instead of JSON.stringify
|
|
3003
|
+
const themeHash = theme ? hash(Object.values(theme).join('|')) : '';
|
|
3004
|
+
const currentHash = hashStyleProps(propsToProcess) + '|' + themeHash;
|
|
2989
3005
|
// Only recompute classes if hash changed
|
|
2990
3006
|
if (!cacheRef.current || cacheRef.current.hash !== currentHash) {
|
|
2991
3007
|
const classes = extractUtilityClasses(propsToProcess, getColor, mediaQueries, devices, manager);
|
|
@@ -3162,18 +3178,24 @@ const Element = /*#__PURE__*/React.memo(/*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
3162
3178
|
after,
|
|
3163
3179
|
...otherProps
|
|
3164
3180
|
} = rest;
|
|
3165
|
-
//
|
|
3166
|
-
Object.keys(otherProps)
|
|
3167
|
-
|
|
3181
|
+
// Single pass: add event handlers and non-style props together
|
|
3182
|
+
const otherKeys = Object.keys(otherProps);
|
|
3183
|
+
for (let i = 0; i < otherKeys.length; i++) {
|
|
3184
|
+
const key = otherKeys[i];
|
|
3185
|
+
// Event handlers: start with "on" + uppercase letter
|
|
3186
|
+
if (key.charCodeAt(0) === 111 &&
|
|
3187
|
+
// 'o'
|
|
3188
|
+
key.charCodeAt(1) === 110 &&
|
|
3189
|
+
// 'n'
|
|
3190
|
+
key.length > 2 && key.charCodeAt(2) >= 65 && key.charCodeAt(2) <= 90 // uppercase A-Z
|
|
3191
|
+
) {
|
|
3168
3192
|
newProps[key] = otherProps[key];
|
|
3169
3193
|
}
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
Object.keys(otherProps).forEach(key => {
|
|
3173
|
-
if (!excludedKeys.has(key) && !isStyleProp(key) || includeKeys.has(key)) {
|
|
3194
|
+
// Non-style props (pass through to DOM)
|
|
3195
|
+
else if (!excludedKeys.has(key) && !isStyleProp(key) || includeKeys.has(key)) {
|
|
3174
3196
|
newProps[key] = otherProps[key];
|
|
3175
3197
|
}
|
|
3176
|
-
}
|
|
3198
|
+
}
|
|
3177
3199
|
if (style) {
|
|
3178
3200
|
newProps.style = style;
|
|
3179
3201
|
}
|
|
@@ -3260,11 +3282,17 @@ const Span = /*#__PURE__*/React.forwardRef((props, ref) => (/*#__PURE__*/React.c
|
|
|
3260
3282
|
ref: ref
|
|
3261
3283
|
}))));
|
|
3262
3284
|
|
|
3263
|
-
const Image = /*#__PURE__*/React.forwardRef((props, ref) =>
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
}
|
|
3285
|
+
const Image = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
3286
|
+
const imageProps = {
|
|
3287
|
+
...props,
|
|
3288
|
+
alt: props.alt || ''
|
|
3289
|
+
};
|
|
3290
|
+
return /*#__PURE__*/React.createElement(Element, Object.assign({
|
|
3291
|
+
as: "img"
|
|
3292
|
+
}, imageProps, {
|
|
3293
|
+
ref: ref
|
|
3294
|
+
}));
|
|
3295
|
+
});
|
|
3268
3296
|
const ImageBackground = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
3269
3297
|
let {
|
|
3270
3298
|
src,
|
|
@@ -3363,11 +3391,18 @@ const Input = /*#__PURE__*/React.forwardRef((props, ref) => (/*#__PURE__*/React.
|
|
|
3363
3391
|
}, props, {
|
|
3364
3392
|
ref: ref
|
|
3365
3393
|
}))));
|
|
3366
|
-
const Button = /*#__PURE__*/React.forwardRef((props, ref) =>
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
}
|
|
3394
|
+
const Button = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
3395
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
3396
|
+
if (!props.children && !props['aria-label']) {
|
|
3397
|
+
console.warn('Accessibility Warning: Button is missing an accessible name. If it is an icon-only button, please provide an `aria-label`.');
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
return /*#__PURE__*/React.createElement(Element, Object.assign({
|
|
3401
|
+
as: "button"
|
|
3402
|
+
}, props, {
|
|
3403
|
+
ref: ref
|
|
3404
|
+
}));
|
|
3405
|
+
});
|
|
3371
3406
|
|
|
3372
3407
|
// animations.ts
|
|
3373
3408
|
const fadeIn = function (_temp) {
|