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