app-studio 0.6.49 → 0.6.50

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.
Files changed (40) hide show
  1. package/dist/app-studio.cjs.development.js +703 -428
  2. package/dist/app-studio.cjs.development.js.map +1 -1
  3. package/dist/app-studio.cjs.production.min.js +1 -1
  4. package/dist/app-studio.esm.js +696 -429
  5. package/dist/app-studio.esm.js.map +1 -1
  6. package/dist/app-studio.umd.development.js +707 -432
  7. package/dist/app-studio.umd.development.js.map +1 -1
  8. package/dist/app-studio.umd.production.min.js +1 -1
  9. package/dist/components/Form.d.ts +7 -7
  10. package/dist/components/Image.d.ts +3 -3
  11. package/dist/components/Text/Text.props.d.ts +1 -1
  12. package/dist/components/Text/Text.view.d.ts +1 -1
  13. package/dist/components/View.d.ts +11 -11
  14. package/dist/element/Animation.d.ts +2 -2
  15. package/dist/element/Element.d.ts +4 -99
  16. package/dist/element/Element.types.d.ts +114 -0
  17. package/dist/element/css.d.ts +7 -4
  18. package/dist/index.d.ts +2 -1
  19. package/dist/providers/StyleRegistry.d.ts +32 -0
  20. package/dist/providers/Theme.d.ts +2 -6
  21. package/dist/stories/AnimateOn.stories.d.ts +1 -1
  22. package/dist/stories/Animation.stories.d.ts +2 -2
  23. package/dist/stories/BorderColor.stories.d.ts +2 -2
  24. package/dist/stories/Color.stories.d.ts +2 -2
  25. package/dist/stories/ColorAlpha.stories.d.ts +5 -0
  26. package/dist/stories/CrossBrowserCompatibility.stories.d.ts +1 -1
  27. package/dist/stories/EmptyBeforeExample.stories.d.ts +1 -1
  28. package/dist/stories/EventHandlers.stories.d.ts +1 -1
  29. package/dist/stories/GradientColors.stories.d.ts +1 -1
  30. package/dist/stories/GroupPeer.stories.d.ts +7 -0
  31. package/dist/stories/Image.stories.d.ts +1 -1
  32. package/dist/stories/ScrollTimeline.stories.d.ts +6 -0
  33. package/dist/stories/VendorPrefix.stories.d.ts +1 -1
  34. package/dist/stories/View.stories.d.ts +1 -1
  35. package/dist/stories/ViewAnimation.stories.d.ts +1 -1
  36. package/dist/utils/colors.d.ts +14 -1
  37. package/dist/utils/constants.d.ts +1 -1
  38. package/dist/utils/hash.d.ts +4 -0
  39. package/docs/Theming.md +118 -3
  40. package/package.json +7 -4
@@ -7,32 +7,9 @@ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'defau
7
7
  var React = require('react');
8
8
  var React__default = _interopDefault(React);
9
9
  var Color = _interopDefault(require('color-convert'));
10
+ var hyphenate = _interopDefault(require('hyphenate-style-name'));
10
11
 
11
12
  const defaultLightPalette = {
12
- whiteAlpha: {
13
- 50: 'rgba(255, 255, 255, 0.04)',
14
- 100: 'rgba(255, 255, 255, 0.06)',
15
- 200: 'rgba(255, 255, 255, 0.08)',
16
- 300: 'rgba(255, 255, 255, 0.16)',
17
- 400: 'rgba(255, 255, 255, 0.24)',
18
- 500: 'rgba(255, 255, 255, 0.36)',
19
- 600: 'rgba(255, 255, 255, 0.48)',
20
- 700: 'rgba(255, 255, 255, 0.64)',
21
- 800: 'rgba(255, 255, 255, 0.80)',
22
- 900: 'rgba(255, 255, 255, 0.92)'
23
- },
24
- blackAlpha: {
25
- 50: 'rgba(0, 0, 0, 0.04)',
26
- 100: 'rgba(0, 0, 0, 0.06)',
27
- 200: 'rgba(0, 0, 0, 0.08)',
28
- 300: 'rgba(0, 0, 0, 0.16)',
29
- 400: 'rgba(0, 0, 0, 0.24)',
30
- 500: 'rgba(0, 0, 0, 0.36)',
31
- 600: 'rgba(0, 0, 0, 0.48)',
32
- 700: 'rgba(0, 0, 0, 0.64)',
33
- 800: 'rgba(0, 0, 0, 0.80)',
34
- 900: 'rgba(0, 0, 0, 0.92)'
35
- },
36
13
  white: {
37
14
  50: 'rgba(255, 255, 255, 0.04)',
38
15
  100: 'rgba(255, 255, 255, 0.08)',
@@ -344,34 +321,70 @@ const defaultLightPalette = {
344
321
  700: '#334155',
345
322
  800: '#1e293b',
346
323
  900: '#0f172a'
324
+ },
325
+ slate: {
326
+ 50: '#f8fafc',
327
+ 100: '#f1f5f9',
328
+ 200: '#e2e8f0',
329
+ 300: '#cbd5e1',
330
+ 400: '#94a3b8',
331
+ 500: '#64748b',
332
+ 600: '#475569',
333
+ 700: '#334155',
334
+ 800: '#1e293b',
335
+ 900: '#0f172a'
336
+ },
337
+ zinc: {
338
+ 50: '#fafafa',
339
+ 100: '#f4f4f5',
340
+ 200: '#e4e4e7',
341
+ 300: '#d4d4d8',
342
+ 400: '#a1a1aa',
343
+ 500: '#71717a',
344
+ 600: '#52525b',
345
+ 700: '#3f3f46',
346
+ 800: '#27272a',
347
+ 900: '#18181b'
348
+ },
349
+ neutral: {
350
+ 50: '#fafafa',
351
+ 100: '#f5f5f5',
352
+ 200: '#e5e5e5',
353
+ 300: '#d4d4d4',
354
+ 400: '#a3a3a3',
355
+ 500: '#737373',
356
+ 600: '#525252',
357
+ 700: '#404040',
358
+ 800: '#262626',
359
+ 900: '#171717'
360
+ },
361
+ stone: {
362
+ 50: '#fafaf9',
363
+ 100: '#f5f5f4',
364
+ 200: '#e7e5e4',
365
+ 300: '#d6d3d1',
366
+ 400: '#a8a29e',
367
+ 500: '#78716c',
368
+ 600: '#57534e',
369
+ 700: '#44403c',
370
+ 800: '#292524',
371
+ 900: '#1c1917'
347
372
  }
348
373
  };
349
374
  const defaultDarkPalette = {
350
- whiteAlpha: {
351
- 50: 'rgba(255, 255, 255, 0.04)',
352
- 100: 'rgba(255, 255, 255, 0.06)',
353
- 200: 'rgba(255, 255, 255, 0.08)',
354
- 300: 'rgba(255, 255, 255, 0.16)',
355
- 400: 'rgba(255, 255, 255, 0.24)',
356
- 500: 'rgba(255, 255, 255, 0.36)',
357
- 600: 'rgba(255, 255, 255, 0.48)',
358
- 700: 'rgba(255, 255, 255, 0.64)',
359
- 800: 'rgba(255, 255, 255, 0.80)',
360
- 900: 'rgba(255, 255, 255, 0.92)'
361
- },
362
- blackAlpha: {
375
+ white: {
363
376
  50: 'rgba(0, 0, 0, 0.04)',
364
- 100: 'rgba(0, 0, 0, 0.06)',
365
- 200: 'rgba(0, 0, 0, 0.08)',
366
- 300: 'rgba(0, 0, 0, 0.16)',
367
- 400: 'rgba(0, 0, 0, 0.24)',
368
- 500: 'rgba(0, 0, 0, 0.36)',
369
- 600: 'rgba(0, 0, 0, 0.48)',
370
- 700: 'rgba(0, 0, 0, 0.64)',
371
- 800: 'rgba(0, 0, 0, 0.80)',
372
- 900: 'rgba(0, 0, 0, 0.92)'
377
+ 100: 'rgba(0, 0, 0, 0.08)',
378
+ 200: 'rgba(0, 0, 0, 0.16)',
379
+ 300: 'rgba(0, 0, 0, 0.24)',
380
+ 400: 'rgba(0, 0, 0, 0.36)',
381
+ 500: 'rgba(0, 0, 0, 0.48)',
382
+ 600: 'rgba(0, 0, 0, 0.64)',
383
+ 700: 'rgba(0, 0, 0, 0.80)',
384
+ 800: 'rgba(0, 0, 0, 0.92)',
385
+ 900: 'rgba(0, 0, 0, 1)'
373
386
  },
374
- white: {
387
+ black: {
375
388
  50: 'rgba(255, 255, 255, 0.04)',
376
389
  100: 'rgba(255, 255, 255, 0.08)',
377
390
  200: 'rgba(255, 255, 255, 0.16)',
@@ -383,18 +396,6 @@ const defaultDarkPalette = {
383
396
  800: 'rgba(255, 255, 255, 0.92)',
384
397
  900: 'rgba(255, 255, 255, 1)'
385
398
  },
386
- black: {
387
- 50: 'rgba(0, 0, 0, 0.04)',
388
- 100: 'rgba(0, 0, 0, 0.08)',
389
- 200: 'rgba(0, 0, 0, 0.16)',
390
- 300: 'rgba(0, 0, 0, 0.24)',
391
- 400: 'rgba(0, 0, 0, 0.36)',
392
- 500: 'rgba(0, 0, 0, 0.48)',
393
- 600: 'rgba(0, 0, 0, 0.64)',
394
- 700: 'rgba(0, 0, 0, 0.80)',
395
- 800: 'rgba(0, 0, 0, 0.92)',
396
- 900: 'rgba(0, 0, 0, 1)'
397
- },
398
399
  rose: {
399
400
  50: '#330517',
400
401
  100: '#4a031e',
@@ -682,6 +683,54 @@ const defaultDarkPalette = {
682
683
  700: '#e2e8f0',
683
684
  800: '#f1f5f9',
684
685
  900: '#f8fafc'
686
+ },
687
+ slate: {
688
+ 50: '#0f172a',
689
+ 100: '#1e293b',
690
+ 200: '#334155',
691
+ 300: '#475569',
692
+ 400: '#64748b',
693
+ 500: '#94a3b8',
694
+ 600: '#cbd5e1',
695
+ 700: '#e2e8f0',
696
+ 800: '#f1f5f9',
697
+ 900: '#f8fafc'
698
+ },
699
+ zinc: {
700
+ 50: '#18181b',
701
+ 100: '#27272a',
702
+ 200: '#3f3f46',
703
+ 300: '#52525b',
704
+ 400: '#71717a',
705
+ 500: '#a1a1aa',
706
+ 600: '#d4d4d8',
707
+ 700: '#e4e4e7',
708
+ 800: '#f4f4f5',
709
+ 900: '#fafafa'
710
+ },
711
+ neutral: {
712
+ 50: '#171717',
713
+ 100: '#262626',
714
+ 200: '#404040',
715
+ 300: '#525252',
716
+ 400: '#737373',
717
+ 500: '#a3a3a3',
718
+ 600: '#d4d4d4',
719
+ 700: '#e5e5e5',
720
+ 800: '#f5f5f5',
721
+ 900: '#fafafa'
722
+ },
723
+ stone: {
724
+ 50: '#1c1917',
725
+ 100: '#292524',
726
+ 200: '#44403c',
727
+ 300: '#57534e',
728
+ 400: '#78716c',
729
+ 500: '#a8a29e',
730
+ 600: '#d6d3d1',
731
+ 700: '#e7e5e4',
732
+ 800: '#f5f5f4',
733
+ 900: '#fafaf9'
685
734
  }
686
735
  };
687
736
  const defaultColors = {
@@ -697,44 +746,141 @@ const defaultColors = {
697
746
  orange: '#FFA500',
698
747
  brown: '#A52A2A',
699
748
  purple: '#800080',
700
- pink: '#FFC0CB',
701
- lime: '#00FF00',
702
- teal: '#008080',
703
- navy: '#000080',
704
- olive: '#808000',
705
- maroon: '#800000',
706
- gold: '#FFD700',
707
- silver: '#C0C0C0',
708
- indigo: '#4B0082',
709
- violet: '#EE82EE',
710
- beige: '#F5F5DC',
711
- turquoise: '#40E0D0',
712
- coral: '#FF7F50',
713
- chocolate: '#D2691E',
714
- skyBlue: '#87CEEB',
715
- plum: '#DDA0DD',
716
- darkGreen: '#006400',
717
- salmon: '#FA8072'
749
+ pink: '#FFC0CB'
718
750
  };
719
751
  const defaultLightColors = {
720
- ...defaultColors,
721
- dark: '#a1a1aa',
722
- white: '#FFFFFF',
723
- black: '#000000'
752
+ ...defaultColors
724
753
  };
725
754
  const defaultDarkColors = {
726
755
  ...defaultColors,
727
- dark: '#adb5bd',
728
756
  white: '#000000',
729
757
  black: '#FFFFFF'
730
758
  };
759
+ // Centralized regex for color token detection
760
+ // Matches color.x.y.z or theme.x.y
761
+ const COLOR_TOKEN_REGEX = /(color\.[a-zA-Z0-9.]+|theme\.[a-zA-Z0-9.]+)/g;
762
+ /**
763
+ * Checks if a value contains color tokens.
764
+ * @param value - The string to check.
765
+ * @returns True if the value contains color tokens.
766
+ */
767
+ const hasColorToken = value => {
768
+ return value.includes('color.') || value.includes('theme.');
769
+ };
770
+ /**
771
+ * Replaces color tokens in a string with values returned by a resolver function.
772
+ * @param value - The string containing color tokens.
773
+ * @param resolver - A function that takes a token and returns its replacement value.
774
+ * @returns The string with color tokens replaced.
775
+ */
776
+ const replaceColorTokens = (value, resolver) => {
777
+ if (!hasColorToken(value)) {
778
+ return value;
779
+ }
780
+ return value.replace(COLOR_TOKEN_REGEX, token => {
781
+ return resolver(token);
782
+ });
783
+ };
731
784
 
732
785
  // --- Constants ---
733
786
  const THEME_PREFIX = 'theme.';
734
787
  const COLOR_PREFIX = 'color.';
735
- const LIGHT_PREFIX = 'light.';
736
- const DARK_PREFIX = 'dark.';
737
788
  const TRANSPARENT = 'transparent';
789
+ // --- CSS Variable Injection Helper ---
790
+ const generateCSSVariables = (theme, lightColors, darkColors) => {
791
+ const variables = [];
792
+ const lightVariables = [];
793
+ const darkVariables = [];
794
+ const themeVariables = [];
795
+ // Helper to process object and generate variables
796
+ const processObject = (obj, prefix, targetArray) => {
797
+ Object.keys(obj).forEach(key => {
798
+ const value = obj[key];
799
+ const variableName = `${prefix}-${key}`.replace(/\./g, '-');
800
+ if (typeof value === 'object' && value !== null) {
801
+ processObject(value, variableName, targetArray);
802
+ } else if (typeof value === 'string' || typeof value === 'number') {
803
+ targetArray.push(`--${variableName}: ${value};`);
804
+ }
805
+ });
806
+ };
807
+ // 1. Generate ALL primitive variables (light and dark)
808
+ // We prefix them with --light-color-... and --dark-color-...
809
+ processObject(lightColors.main, 'color', variables);
810
+ processObject(lightColors.palette, 'color', variables);
811
+ processObject(lightColors.main, 'light-color', lightVariables);
812
+ processObject(lightColors.palette, 'light-color', lightVariables);
813
+ processObject(darkColors.main, 'dark-color', darkVariables);
814
+ processObject(darkColors.palette, 'dark-color', darkVariables);
815
+ // We collect the names that need mapping
816
+ const genericColorVars = [];
817
+ const collectGenericNames = (obj, prefix) => {
818
+ Object.keys(obj).forEach(key => {
819
+ const value = obj[key];
820
+ const variableName = `${prefix}-${key}`.replace(/\./g, '-');
821
+ if (typeof value === 'object' && value !== null) {
822
+ collectGenericNames(value, variableName);
823
+ } else {
824
+ genericColorVars.push(variableName);
825
+ }
826
+ });
827
+ };
828
+ collectGenericNames(lightColors.main, 'color');
829
+ collectGenericNames(lightColors.palette, 'color');
830
+ // 3. Process Theme variables (references)
831
+ const processTheme = (obj, prefix) => {
832
+ Object.keys(obj).forEach(key => {
833
+ const value = obj[key];
834
+ const variableName = `${prefix}-${key}`.replace(/\./g, '-');
835
+ if (typeof value === 'object' && value !== null) {
836
+ processTheme(value, variableName);
837
+ } else if (typeof value === 'string') {
838
+ if (value.startsWith(COLOR_PREFIX)) {
839
+ // Convert 'color.blue.500' -> 'var(--color-blue-500)'
840
+ // The underlying --color-blue-500 will change based on scope!
841
+ const refVar = value.replace(/\./g, '-');
842
+ themeVariables.push(`--${variableName}: var(--${refVar});`);
843
+ } else if (value.startsWith(THEME_PREFIX)) {
844
+ const refVar = value.replace(/\./g, '-');
845
+ themeVariables.push(`--${variableName}: var(--${refVar});`);
846
+ } else {
847
+ themeVariables.push(`--${variableName}: ${value};`);
848
+ }
849
+ }
850
+ });
851
+ };
852
+ processTheme(theme, 'theme');
853
+ // 4. Construct CSS
854
+ // :root has all primitives
855
+ // [data-theme='light'] maps color vars to light primitives
856
+ // [data-theme='dark'] maps color vars to dark primitives
857
+ const lightMappings = genericColorVars.map(name => `--${name}: var(--light-${name});`).join('\n ');
858
+ const darkMappings = genericColorVars.map(name => `--${name}: var(--dark-${name});`).join('\n ');
859
+ const css = `
860
+ :root {
861
+ /* Primitives */
862
+ ${variables.join('\n ')}
863
+ ${lightVariables.join('\n ')}
864
+ ${darkVariables.join('\n ')}
865
+
866
+ /* Theme Variables (Structural) */
867
+ ${themeVariables.join('\n ')}
868
+ }
869
+ .app-studio-theme-root {
870
+ width: 100%;
871
+ height: 100%;
872
+ transition: background-color 0.2s, color 0.2s;
873
+ }
874
+ [data-theme='light'] {
875
+ ${lightMappings}
876
+ }
877
+
878
+ [data-theme='dark'] {
879
+ ${darkMappings}
880
+ }
881
+ `;
882
+ return css;
883
+ };
738
884
  // --- Default Configuration ---
739
885
  const defaultThemeMain = {
740
886
  primary: `${COLOR_PREFIX}black`,
@@ -743,12 +889,7 @@ const defaultThemeMain = {
743
889
  error: `${COLOR_PREFIX}red.500`,
744
890
  warning: `${COLOR_PREFIX}orange.500`,
745
891
  disabled: `${COLOR_PREFIX}gray.500`,
746
- loading: `${COLOR_PREFIX}dark.500`,
747
- blend: {
748
- mode: 'difference',
749
- color: 'white',
750
- modeWithBg: 'exclusion'
751
- }
892
+ loading: `${COLOR_PREFIX}dark.500`
752
893
  };
753
894
  const defaultLightColorConfig = {
754
895
  main: defaultLightColors,
@@ -777,6 +918,44 @@ const useTheme = () => {
777
918
  }
778
919
  return context;
779
920
  };
921
+ // --- Helper Function to Convert Color to RGBA with Alpha ---
922
+ /**
923
+ * Converts a color (hex, rgb, or rgba) to rgba format with specified alpha.
924
+ * @param color - The base color in hex, rgb, or rgba format
925
+ * @param alpha - Alpha value on a 0-1000 scale (e.g., 200 = 0.2 opacity)
926
+ * @returns RGBA color string
927
+ */
928
+ const convertToRgba = (color, alpha) => {
929
+ // Normalize alpha to 0-1 range
930
+ const normalizedAlpha = Math.max(0, Math.min(1000, alpha)) / 1000;
931
+ // Handle hex colors (#RGB or #RRGGBB)
932
+ if (color.startsWith('#')) {
933
+ let hex = color.slice(1);
934
+ // Convert shorthand hex to full form
935
+ if (hex.length === 3) {
936
+ hex = hex.split('').map(char => char + char).join('');
937
+ }
938
+ const r = parseInt(hex.slice(0, 2), 16);
939
+ const g = parseInt(hex.slice(2, 4), 16);
940
+ const b = parseInt(hex.slice(4, 6), 16);
941
+ return `rgba(${r}, ${g}, ${b}, ${normalizedAlpha})`;
942
+ }
943
+ // Handle rgb/rgba colors
944
+ if (color.startsWith('rgb')) {
945
+ // Extract the values from rgb() or rgba()
946
+ const match = color.match(/rgba?\(([^)]+)\)/);
947
+ if (match) {
948
+ const values = match[1].split(',').map(v => v.trim());
949
+ const r = values[0];
950
+ const g = values[1];
951
+ const b = values[2];
952
+ return `rgba(${r}, ${g}, ${b}, ${normalizedAlpha})`;
953
+ }
954
+ }
955
+ // If color format is not recognized, return as-is
956
+ console.warn(`Unable to convert color "${color}" to rgba format`);
957
+ return color;
958
+ };
780
959
  // --- Deep Merge Function (remains the same, assuming it works as intended) ---
781
960
  // Consider using a library like `lodash.merge` or `deepmerge` if complexity grows
782
961
  // or edge cases (like merging arrays) need different handling.
@@ -811,7 +990,8 @@ const ThemeProvider = _ref => {
811
990
  mode: initialMode = 'light',
812
991
  dark: darkOverride = {},
813
992
  light: lightOverride = {},
814
- children
993
+ children,
994
+ strict = false
815
995
  } = _ref;
816
996
  const [themeMode, setThemeMode] = React.useState(initialMode);
817
997
  const colorCache = React.useRef(new Map()).current;
@@ -830,110 +1010,125 @@ const ThemeProvider = _ref => {
830
1010
  dark: deepMerge(defaultDarkColorConfig, darkOverride)
831
1011
  }), [lightOverride, darkOverride]);
832
1012
  const currentColors = React.useMemo(() => themeColors[themeMode], [themeColors, themeMode]);
1013
+ // --- Helper function to resolve color tokens to actual values ---
1014
+ const resolveColorToken = React.useCallback(token => {
1015
+ if (!token || typeof token !== 'string') return String(token);
1016
+ if (token === TRANSPARENT) return token;
1017
+ const colors = currentColors;
1018
+ // Resolve color.* tokens
1019
+ if (token.startsWith(COLOR_PREFIX)) {
1020
+ const keys = token.substring(COLOR_PREFIX.length).split('.');
1021
+ if (keys.length === 1) {
1022
+ // e.g., "color.blue" -> main color
1023
+ const colorValue = colors.main[keys[0]];
1024
+ return typeof colorValue === 'string' ? colorValue : token;
1025
+ } else if (keys.length === 2) {
1026
+ // e.g., "color.blue.500" -> palette color
1027
+ const [colorName, shade] = keys;
1028
+ const shadeValue = colors.palette[colorName]?.[Number(shade)];
1029
+ return typeof shadeValue === 'string' ? shadeValue : token;
1030
+ } else if (keys.length === 3) {
1031
+ // e.g., "color.blue.500.200" -> palette color with alpha
1032
+ // Use color-mix() to apply alpha via CSS variables
1033
+ const [colorName, shade, alphaStr] = keys;
1034
+ const alpha = parseInt(alphaStr, 10);
1035
+ if (!isNaN(alpha)) {
1036
+ const percentage = Math.round(alpha / 1000 * 100);
1037
+ return `color-mix(in srgb, var(--color-${colorName}-${shade}) ${percentage}%, transparent)`;
1038
+ }
1039
+ }
1040
+ }
1041
+ // Resolve theme.* tokens (recursive resolution)
1042
+ if (token.startsWith(THEME_PREFIX)) {
1043
+ const themeKey = token.substring(THEME_PREFIX.length);
1044
+ const themeValue = mergedTheme[themeKey];
1045
+ if (typeof themeValue === 'string') {
1046
+ return resolveColorToken(themeValue);
1047
+ }
1048
+ }
1049
+ return token;
1050
+ }, [currentColors, mergedTheme]);
1051
+ // The mode is now handled by the data-attribute on the container
833
1052
  // --- Memoized getColor function - Revised for Robustness ---
834
1053
  const getColor = React.useCallback((name, override) => {
835
1054
  if (!name || typeof name !== 'string') return String(name); // Handle invalid input
836
1055
  if (name === TRANSPARENT) return name;
837
- // 1. Determine the effective mode for this specific lookup
1056
+ // 1. Check for optimization (CSS vars) if no overrides
1057
+ // This allows instant theme switching via CSS variables without re-render
1058
+ if (!override || Object.keys(override).length === 0) {
1059
+ if (name.startsWith(THEME_PREFIX)) {
1060
+ return `var(--${name.replace(/\./g, '-')})`;
1061
+ }
1062
+ if (name.startsWith(COLOR_PREFIX)) {
1063
+ const parts = name.split('.');
1064
+ // Simple lookup (e.g. color.blue or color.blue.500)
1065
+ if (parts.length < 4) {
1066
+ return `var(--${name.replace(/\./g, '-')})`;
1067
+ }
1068
+ }
1069
+ }
1070
+ // 2. Manual Resolution (Fallback for overrides or complex keys)
838
1071
  const effectiveMode = override?.themeMode ?? themeMode;
839
1072
  const needCache = override && Object.keys(override).length === 0;
840
- // 2. Create a cache key based on the name and the *effective* mode
841
1073
  const cacheKey = `${name}-${effectiveMode}`;
842
- if (colorCache.has(cacheKey) && needCache) {
1074
+ if (needCache && colorCache.has(cacheKey)) {
843
1075
  return colorCache.get(cacheKey);
844
1076
  }
1077
+ // Strict Mode Check
1078
+ if (strict && !name.startsWith(COLOR_PREFIX) && !name.startsWith(THEME_PREFIX) && !name.startsWith('light.') && !name.startsWith('dark.')) {
1079
+ console.warn(`[Theme] Strict mode enabled: '${name}' is not a valid color token.`);
1080
+ }
845
1081
  // 3. Select the correct color set (light/dark) based on the effective mode
846
1082
  const colorsToUse = themeColors[effectiveMode];
847
1083
  if (!colorsToUse) {
848
1084
  console.warn(`Color set for mode "${effectiveMode}" not found.`);
849
- return name; // Fallback if colors for the mode don't exist
1085
+ return name;
850
1086
  }
851
- let resolvedColor = name; // Default fallback is the original name
1087
+ let resolvedColor = name;
852
1088
  try {
853
- // --- Resolve "theme.*" paths ---
854
- if (name.startsWith(THEME_PREFIX)) {
855
- // console.log(
856
- // `Resolving color "${name}" for mode "${effectiveMode}".`,
857
- // override
858
- // );
859
- const keys = name.substring(THEME_PREFIX.length).split('.');
860
- let value = deepMerge(mergedTheme, override?.theme || {});
861
- for (const key of keys) {
862
- if (value === undefined || value === null) break; // Stop if path breaks
863
- value = value[key];
864
- }
865
- if (typeof value === 'string' && value !== name) {
866
- // Recursively resolve if it points to another color string.
867
- // CRITICAL: Pass the *same* effectiveMode down.
868
- resolvedColor = getColor(value, override);
869
- } else if (value === undefined) {
870
- console.warn(`Theme path "${name}" not found.`);
871
- resolvedColor = name; // Fallback
872
- } else if (typeof value !== 'string') {
873
- console.warn(`Theme path "${name}" resolved to a non-string value.`);
874
- resolvedColor = name; // Fallback
875
- }
876
- // If value === name, it resolved to itself, keep fallback
877
- // --- Resolve "light.*" or "dark.*" paths directly ---
878
- } else if (name.startsWith(LIGHT_PREFIX) || name.startsWith(DARK_PREFIX)) {
879
- // Determine which mode to use based on the prefix
880
- const specificMode = name.startsWith(LIGHT_PREFIX) ? 'light' : 'dark';
881
- const prefixLength = name.startsWith(LIGHT_PREFIX) ? LIGHT_PREFIX.length : DARK_PREFIX.length;
882
- // Create a modified name with the color prefix instead
1089
+ // Resolve "light.*" or "dark.*" paths directly
1090
+ if (name.startsWith('light.') || name.startsWith('dark.')) {
1091
+ const prefixLength = name.startsWith('light.') ? 6 : 5;
883
1092
  const modifiedName = `${COLOR_PREFIX}${name.substring(prefixLength)}`;
884
- // Call getColor with the modified name and force the specific mode
885
- const specificOverride = {
886
- ...override,
887
- themeMode: specificMode
888
- };
889
- resolvedColor = getColor(modifiedName, specificOverride);
890
- // --- Resolve "color.*" paths ---
891
- } else if (name.startsWith(COLOR_PREFIX)) {
892
- // console.log(
893
- // `Resolving color "${name}" for mode "${effectiveMode}".`,
894
- // override
895
- // );
1093
+ return `var(--${modifiedName.replace(/\./g, '-')})`;
1094
+ }
1095
+ // Resolve "color.*" paths
1096
+ if (name.startsWith(COLOR_PREFIX)) {
896
1097
  const keys = name.substring(COLOR_PREFIX.length).split('.');
897
- if (keys.length === 1) {
898
- // e.g., "color.white"
899
- const colorName = keys[0];
900
- const main = deepMerge(colorsToUse.main, override?.colors?.main || {});
901
- const colorValue = main?.[colorName]; // Use optional chaining
902
- if (typeof colorValue === 'string') {
903
- resolvedColor = colorValue;
904
- } else {
905
- console.warn(`Singleton color "${name}" not found in ${effectiveMode} mode.`);
906
- resolvedColor = name; // Fallback on unexpected error
1098
+ if (keys.length === 3) {
1099
+ // e.g. "color.black.900.200" (alpha)
1100
+ const [colorName, variant, alphaStr] = keys;
1101
+ const palette = deepMerge(colorsToUse.palette, override?.colors?.palette || {});
1102
+ const shadeValue = palette?.[colorName]?.[variant];
1103
+ const alpha = parseInt(alphaStr, 10);
1104
+ if (typeof shadeValue === 'string' && !isNaN(alpha)) {
1105
+ resolvedColor = convertToRgba(shadeValue, alpha);
907
1106
  }
908
1107
  } else if (keys.length === 2) {
909
- // e.g., "color.blue.500"
1108
+ // e.g. "color.blue.500"
910
1109
  const [colorName, variant] = keys;
911
1110
  const palette = deepMerge(colorsToUse.palette, override?.colors?.palette || {});
912
1111
  const shadeValue = palette?.[colorName]?.[variant];
913
1112
  if (typeof shadeValue === 'string') {
914
1113
  resolvedColor = shadeValue;
915
- } else {
916
- console.warn(`Palette color "${name}" not found in ${effectiveMode} mode.`);
917
- resolvedColor = name; // Fallback on unexpected error
918
1114
  }
919
- } else {
920
- console.warn(`Invalid color format: "${name}". Expected 'color.name' or 'color.name.shade'.`);
921
- resolvedColor = name; // Fallback on unexpected error
1115
+ } else if (keys.length === 1) {
1116
+ // e.g. "color.blue"
1117
+ const [colorName] = keys;
1118
+ const main = deepMerge(colorsToUse.main, override?.colors?.main || {});
1119
+ const colorValue = main?.[colorName];
1120
+ if (typeof colorValue === 'string') {
1121
+ resolvedColor = colorValue;
1122
+ }
922
1123
  }
923
1124
  }
924
- // --- Direct Color Value ---
925
- // If it's not theme.*, light.*, dark.*, or color.*, assume it's a direct value ('red', '#fff').
926
- // resolvedColor remains 'name', which is correct.
927
1125
  } catch (e) {
928
- console.error(`Error resolving color "${name}" for mode "${effectiveMode}":`, e);
929
- resolvedColor = name; // Fallback on unexpected error
1126
+ console.error(`Error resolving color "${name}"`, e);
1127
+ resolvedColor = name;
930
1128
  }
931
- // Cache the result (the resolved color or the original name if failed)
932
1129
  if (needCache) colorCache.set(cacheKey, resolvedColor);
933
1130
  return resolvedColor;
934
- },
935
- // Dependencies: mergedTheme, themeColors, themeMode (for default), colorCache
936
- [mergedTheme, themeColors, themeMode, colorCache]);
1131
+ }, [mergedTheme, themeColors, themeMode, colorCache, strict]);
937
1132
  // --- Memoize Context Value ---
938
1133
  const contextValue = React.useMemo(() => ({
939
1134
  getColor,
@@ -941,15 +1136,12 @@ const ThemeProvider = _ref => {
941
1136
  colors: currentColors,
942
1137
  themeMode,
943
1138
  setThemeMode
944
- }), [getColor, mergedTheme, currentColors, themeMode] // Exclude setThemeMode (stable)
945
- );
1139
+ }), [getColor, mergedTheme, currentColors, themeMode]);
946
1140
  return /*#__PURE__*/React__default.createElement(ThemeContext.Provider, {
947
1141
  value: contextValue
948
- }, /*#__PURE__*/React__default.createElement("div", {
949
- style: {
950
- backgroundColor: 'white'
951
- }
952
- }, children));
1142
+ }, /*#__PURE__*/React__default.createElement("style", {
1143
+ "data-theme": themeMode
1144
+ }, generateCSSVariables(mergedTheme, themeColors.light, themeColors.dark)), children);
953
1145
  };
954
1146
 
955
1147
  // ResponsiveContext.tsx
@@ -1061,7 +1253,101 @@ const ResponsiveProvider = _ref => {
1061
1253
  }, children);
1062
1254
  };
1063
1255
 
1256
+ const Shadows = {
1257
+ 0: {
1258
+ shadowColor: '#000',
1259
+ shadowOffset: {
1260
+ width: 1,
1261
+ height: 2
1262
+ },
1263
+ shadowOpacity: 0.18,
1264
+ shadowRadius: 1.0
1265
+ },
1266
+ 1: {
1267
+ shadowColor: '#000',
1268
+ shadowOffset: {
1269
+ width: 2,
1270
+ height: 2
1271
+ },
1272
+ shadowOpacity: 0.2,
1273
+ shadowRadius: 1.41
1274
+ },
1275
+ 2: {
1276
+ shadowColor: '#000',
1277
+ shadowOffset: {
1278
+ width: 3,
1279
+ height: 3
1280
+ },
1281
+ shadowOpacity: 0.22,
1282
+ shadowRadius: 2.22
1283
+ },
1284
+ 3: {
1285
+ shadowColor: '#000',
1286
+ shadowOffset: {
1287
+ width: 4,
1288
+ height: 4
1289
+ },
1290
+ shadowOpacity: 0.23,
1291
+ shadowRadius: 2.62
1292
+ },
1293
+ 4: {
1294
+ shadowColor: '#000',
1295
+ shadowOffset: {
1296
+ width: 5,
1297
+ height: 5
1298
+ },
1299
+ shadowOpacity: 0.25,
1300
+ shadowRadius: 3.84
1301
+ },
1302
+ 5: {
1303
+ shadowColor: '#000',
1304
+ shadowOffset: {
1305
+ width: 6,
1306
+ height: 6
1307
+ },
1308
+ shadowOpacity: 0.27,
1309
+ shadowRadius: 4.65
1310
+ },
1311
+ 6: {
1312
+ shadowColor: '#000',
1313
+ shadowOffset: {
1314
+ width: 7,
1315
+ height: 7
1316
+ },
1317
+ shadowOpacity: 0.29,
1318
+ shadowRadius: 4.65
1319
+ },
1320
+ 7: {
1321
+ shadowColor: '#000',
1322
+ shadowOffset: {
1323
+ width: 8,
1324
+ height: 8
1325
+ },
1326
+ shadowOpacity: 0.3,
1327
+ shadowRadius: 4.65
1328
+ },
1329
+ 8: {
1330
+ shadowColor: '#000',
1331
+ shadowOffset: {
1332
+ width: 9,
1333
+ height: 9
1334
+ },
1335
+ shadowOpacity: 0.32,
1336
+ shadowRadius: 5.46
1337
+ },
1338
+ 9: {
1339
+ shadowColor: '#000',
1340
+ shadowOffset: {
1341
+ width: 10,
1342
+ height: 10
1343
+ },
1344
+ shadowOpacity: 0.34,
1345
+ shadowRadius: 6.27
1346
+ }
1347
+ };
1348
+
1064
1349
  // List of numeric properties that don't need 'px' suffix
1350
+ const NumberProps = /*#__PURE__*/new Set(['numberOfLines', 'fontWeight', 'timeStamp', 'flex', 'flexGrow', 'flexShrink', 'order', 'zIndex', 'aspectRatio', 'shadowOpacity', 'shadowRadius', 'scale', 'opacity', 'min', 'max', 'now']);
1065
1351
  // Keys to exclude when passing props to the component
1066
1352
  const excludedKeys = /*#__PURE__*/new Set([
1067
1353
  // Standard styling props
@@ -1080,37 +1366,7 @@ const vendorPrefixToKebabCase = property => {
1080
1366
  if (property.startsWith('--')) {
1081
1367
  return property;
1082
1368
  }
1083
- // Comprehensive regex to match all vendor prefix patterns
1084
- // This handles:
1085
- // 1. Uppercase vendor prefixes (WebkitTransform)
1086
- // 2. Lowercase vendor prefixes (webkitTransform)
1087
- // 3. Mixed case vendor prefixes (webkitbackgroundClip)
1088
- // 4. All lowercase vendor prefixes (webkitbackgroundclip)
1089
- const vendorPrefixRegex = /^(webkit|moz|ms|o|Webkit|Moz|Ms|O)([A-Za-z])/;
1090
- if (vendorPrefixRegex.test(property)) {
1091
- // Extract the prefix and normalize it to lowercase
1092
- const prefixMatch = property.match(/^(webkit|moz|ms|o|Webkit|Moz|Ms|O)/i);
1093
- if (prefixMatch) {
1094
- const prefix = prefixMatch[0].toLowerCase();
1095
- const restOfProperty = property.slice(prefix.length);
1096
- // Convert the rest of the property to kebab case
1097
- let kebabRestOfProperty = restOfProperty;
1098
- // If the rest starts with an uppercase letter or has uppercase letters, convert to kebab case
1099
- if (/[A-Z]/.test(restOfProperty)) {
1100
- kebabRestOfProperty = restOfProperty.replace(/([A-Z])/g, '-$1').toLowerCase();
1101
- } else if (restOfProperty && restOfProperty[0] === restOfProperty[0].toLowerCase()) {
1102
- // If the rest starts with a lowercase letter, ensure proper kebab case
1103
- // This handles cases like webkitbackgroundclip
1104
- kebabRestOfProperty = restOfProperty.replace(/([A-Z])/g, '-$1').toLowerCase();
1105
- }
1106
- // Ensure we don't have double hyphens
1107
- kebabRestOfProperty = kebabRestOfProperty.replace(/^-/, '');
1108
- // Return the properly formatted vendor-prefixed property
1109
- return `-${prefix}-${kebabRestOfProperty}`;
1110
- }
1111
- }
1112
- // Regular camelCase to kebab-case
1113
- return property.replace(/([A-Z])/g, '-$1').toLowerCase();
1369
+ return hyphenate(property);
1114
1370
  };
1115
1371
  const numericCssProperties = /*#__PURE__*/new Set(['border-bottom-left-radius', 'border-bottom-right-radius', 'border-bottom-width', 'border-left-width', 'border-radius', 'border-right-width', 'border-spacing', 'border-top-left-radius', 'border-top-right-radius', 'border-top-width', 'border-width', 'bottom', 'column-gap', 'column-rule-width', 'column-width', 'font-size', 'gap', 'height', 'left', 'letter-spacing', 'line-height', 'margin', 'margin-bottom', 'margin-left', 'margin-right', 'margin-top', 'max-height', 'max-width', 'min-height', 'min-width', 'outline-offset', 'outline-width', 'padding', 'padding-bottom', 'padding-left', 'padding-right', 'padding-top', 'perspective', 'right', 'row-gap', 'text-indent', 'top', 'width',
1116
1372
  // Vendor-prefixed properties that need pixel values
@@ -1124,22 +1380,7 @@ const numericCssProperties = /*#__PURE__*/new Set(['border-bottom-left-radius',
1124
1380
  * @returns The property name in kebab-case with appropriate vendor prefixes
1125
1381
  */
1126
1382
  function propertyToKebabCase(property) {
1127
- // Handle special webkit, moz, ms prefixed properties
1128
- // Check for both lowercase and uppercase vendor prefixes
1129
- const vendorPrefixRegex = /^(webkit|moz|ms|o)([A-Z])/i;
1130
- if (vendorPrefixRegex.test(property)) {
1131
- const match = property.match(/^(webkit|moz|ms|o)/i);
1132
- if (match) {
1133
- // First convert the entire property to kebab case
1134
- let kebabProperty = property.replace(/([A-Z])/g, '-$1').toLowerCase();
1135
- // Then ensure the vendor prefix is correctly formatted
1136
- // This replaces patterns like "webkit-" with "-webkit-"
1137
- kebabProperty = kebabProperty.replace(/^(webkit|moz|ms|o)-/, '-$1-');
1138
- return kebabProperty;
1139
- }
1140
- }
1141
- // Standard property conversion to kebab-case
1142
- return property.replace(/([A-Z])/g, '-$1').toLowerCase();
1383
+ return vendorPrefixToKebabCase(property);
1143
1384
  }
1144
1385
  // Comprehensive list of CSS properties that should be converted to classes
1145
1386
  const cssProperties = /*#__PURE__*/new Set([
@@ -1178,13 +1419,19 @@ const isStyleProp = prop => {
1178
1419
  return false;
1179
1420
  }
1180
1421
  // Check if it's a valid CSS property or custom style prop
1181
- return cssProperties.has(prop) || extraKeys.has(prop) ||
1182
- // Check for vendor prefixes (both uppercase and lowercase)
1183
- /^(webkit|moz|ms|o)([A-Z])/i.test(prop) ||
1184
- // Check for custom properties
1185
- prop.startsWith('--') ||
1186
- // Check for data attributes that should be treated as styles
1187
- prop.startsWith('data-style-') && !includeKeys.has(prop);
1422
+ if (cssProperties.has(prop) || extraKeys.has(prop) || prop.startsWith('--') || prop.startsWith('data-style-') && !includeKeys.has(prop)) {
1423
+ return true;
1424
+ }
1425
+ // Check if it's a valid CSS property using CSS.supports (browser environment)
1426
+ if (typeof CSS !== 'undefined' && CSS.supports) {
1427
+ try {
1428
+ const kebabProp = vendorPrefixToKebabCase(prop);
1429
+ return CSS.supports(kebabProp, 'inherit');
1430
+ } catch {
1431
+ return false;
1432
+ }
1433
+ }
1434
+ return false;
1188
1435
  };
1189
1436
  /**
1190
1437
  * Enhances styleObjectToCss to handle vendor prefixed properties
@@ -1208,101 +1455,53 @@ function styleObjectToCss(styleObject) {
1208
1455
  const toKebabCase = str => {
1209
1456
  return vendorPrefixToKebabCase(str);
1210
1457
  };
1211
- // Export the set of valid style properties
1212
- const StyleProps = /*#__PURE__*/Array.from(cssProperties);
1213
-
1214
- const Shadows = {
1215
- 0: {
1216
- shadowColor: '#000',
1217
- shadowOffset: {
1218
- width: 1,
1219
- height: 2
1220
- },
1221
- shadowOpacity: 0.18,
1222
- shadowRadius: 1.0
1223
- },
1224
- 1: {
1225
- shadowColor: '#000',
1226
- shadowOffset: {
1227
- width: 2,
1228
- height: 2
1229
- },
1230
- shadowOpacity: 0.2,
1231
- shadowRadius: 1.41
1232
- },
1233
- 2: {
1234
- shadowColor: '#000',
1235
- shadowOffset: {
1236
- width: 3,
1237
- height: 3
1238
- },
1239
- shadowOpacity: 0.22,
1240
- shadowRadius: 2.22
1241
- },
1242
- 3: {
1243
- shadowColor: '#000',
1244
- shadowOffset: {
1245
- width: 4,
1246
- height: 4
1247
- },
1248
- shadowOpacity: 0.23,
1249
- shadowRadius: 2.62
1250
- },
1251
- 4: {
1252
- shadowColor: '#000',
1253
- shadowOffset: {
1254
- width: 5,
1255
- height: 5
1256
- },
1257
- shadowOpacity: 0.25,
1258
- shadowRadius: 3.84
1259
- },
1260
- 5: {
1261
- shadowColor: '#000',
1262
- shadowOffset: {
1263
- width: 6,
1264
- height: 6
1265
- },
1266
- shadowOpacity: 0.27,
1267
- shadowRadius: 4.65
1268
- },
1269
- 6: {
1270
- shadowColor: '#000',
1271
- shadowOffset: {
1272
- width: 7,
1273
- height: 7
1274
- },
1275
- shadowOpacity: 0.29,
1276
- shadowRadius: 4.65
1277
- },
1278
- 7: {
1279
- shadowColor: '#000',
1280
- shadowOffset: {
1281
- width: 8,
1282
- height: 8
1283
- },
1284
- shadowOpacity: 0.3,
1285
- shadowRadius: 4.65
1286
- },
1287
- 8: {
1288
- shadowColor: '#000',
1289
- shadowOffset: {
1290
- width: 9,
1291
- height: 9
1292
- },
1293
- shadowOpacity: 0.32,
1294
- shadowRadius: 5.46
1295
- },
1296
- 9: {
1297
- shadowColor: '#000',
1298
- shadowOffset: {
1299
- width: 10,
1300
- height: 10
1301
- },
1302
- shadowOpacity: 0.34,
1303
- shadowRadius: 6.27
1458
+ // Process and normalize style properties
1459
+ const processStyleProperty = (property, value, getColor) => {
1460
+ // Handle null or undefined values
1461
+ if (value == null) {
1462
+ return '';
1463
+ }
1464
+ // Handle custom CSS properties (variables)
1465
+ if (property.startsWith('--')) {
1466
+ // For CSS variables, we pass the value as is
1467
+ return value;
1304
1468
  }
1469
+ // Convert kebab-case property to check against numericCssProperties
1470
+ const kebabProperty = toKebabCase(property);
1471
+ // Convert numbers to pixels for appropriate properties
1472
+ if (typeof value === 'number') {
1473
+ // Check if this is a property that should have px units
1474
+ // First check the property as is, then check with vendor prefixes removed
1475
+ const shouldAddPx = !NumberProps.has(property) && (numericCssProperties.has(kebabProperty) ||
1476
+ // Check if it's a vendor-prefixed property that needs px
1477
+ (/^-(webkit|moz|ms|o)-/.test(kebabProperty) || /^-(Webkit|Moz|Ms|O)-/.test(kebabProperty)) && numericCssProperties.has(kebabProperty.replace(/^-(webkit|moz|ms|o|Webkit|Moz|Ms|O)-/, '')));
1478
+ if (shouldAddPx) {
1479
+ return `${value}px`;
1480
+ }
1481
+ return value;
1482
+ }
1483
+ // Handle color properties directly
1484
+ if (property.toLowerCase().indexOf('color') >= 0 || property === 'fill' || property === 'stroke') {
1485
+ return getColor(value);
1486
+ }
1487
+ // Handle properties that might contain color values (borders, gradients, shadows, etc.)
1488
+ if (typeof value === 'string' && value.length > 3) {
1489
+ if (hasColorToken(value)) {
1490
+ return replaceColorTokens(value, token => getColor(token));
1491
+ }
1492
+ }
1493
+ // Handle arrays (e.g., for transforms)
1494
+ if (Array.isArray(value)) {
1495
+ return value.join(' ');
1496
+ }
1497
+ // Handle objects (e.g., for gradients or transforms)
1498
+ if (typeof value === 'object') {
1499
+ return JSON.stringify(value);
1500
+ }
1501
+ return value;
1305
1502
  };
1503
+ // Export the set of valid style properties
1504
+ const StyleProps = /*#__PURE__*/Array.from(cssProperties);
1306
1505
 
1307
1506
  /* eslint-disable @typescript-eslint/no-unused-vars */
1308
1507
  let keyframesCounter = 0;
@@ -1447,6 +1646,19 @@ const needsVendorPrefix = property => {
1447
1646
  return property in vendorPrefixedProperties;
1448
1647
  };
1449
1648
 
1649
+ /**
1650
+ * Simple, fast hash function (djb2) for generating deterministic class names.
1651
+ */
1652
+ function hash(str) {
1653
+ let hash = 5381;
1654
+ let i = str.length;
1655
+ while (i) {
1656
+ hash = hash * 33 ^ str.charCodeAt(--i);
1657
+ }
1658
+ // Convert to unsigned 32-bit integer and then to base 36 string
1659
+ return (hash >>> 0).toString(36);
1660
+ }
1661
+
1450
1662
  /* eslint-disable @typescript-eslint/no-unused-vars */
1451
1663
  // Implement a simple LRU cache for classCache
1452
1664
  class LRUCache {
@@ -1540,7 +1752,18 @@ const EVENT_TO_PSEUDO = {
1540
1752
  firstLine: 'first-line',
1541
1753
  selection: 'selection',
1542
1754
  backdrop: 'backdrop',
1543
- marker: 'marker'
1755
+ marker: 'marker',
1756
+ // Group modifiers
1757
+ groupHover: 'group-hover',
1758
+ groupFocus: 'group-focus',
1759
+ groupActive: 'group-active',
1760
+ groupDisabled: 'group-disabled',
1761
+ // Peer modifiers
1762
+ peerHover: 'peer-hover',
1763
+ peerFocus: 'peer-focus',
1764
+ peerActive: 'peer-active',
1765
+ peerDisabled: 'peer-disabled',
1766
+ peerChecked: 'peer-checked'
1544
1767
  };
1545
1768
  /**
1546
1769
  * Utility functions for animation handling
@@ -1559,7 +1782,7 @@ const AnimationUtils = {
1559
1782
  }
1560
1783
  return `${ms}ms`;
1561
1784
  },
1562
- processAnimations(animations) {
1785
+ processAnimations(animations, manager) {
1563
1786
  const result = {
1564
1787
  names: [],
1565
1788
  durations: [],
@@ -1578,8 +1801,9 @@ const AnimationUtils = {
1578
1801
  keyframesName,
1579
1802
  keyframes
1580
1803
  } = generateKeyframes(animation);
1581
- if (keyframes && typeof document !== 'undefined') {
1582
- utilityClassManager.injectRule(keyframes);
1804
+ if (keyframes) {
1805
+ // Use provided manager or fall back to global
1806
+ (manager || utilityClassManager).injectRule(keyframes);
1583
1807
  }
1584
1808
  result.names.push(keyframesName);
1585
1809
  const durationMs = this.parseDuration(animation.duration || '0s');
@@ -1619,67 +1843,8 @@ const AnimationUtils = {
1619
1843
  */
1620
1844
  const ValueUtils = {
1621
1845
  formatValue(value, property, getColor) {
1622
- let processedValue = value;
1623
- // Handle custom CSS properties (variables)
1624
- if (property.startsWith('--')) {
1625
- // For CSS variables, we pass the value as is
1626
- return value;
1627
- }
1628
- // If the property is a color, convert it
1629
- if (property.toLowerCase().includes('color')) {
1630
- processedValue = getColor(value);
1631
- }
1632
- // Handle properties that might contain color values (borders, gradients, etc.)
1633
- if (typeof value === 'string' && value.length > 3) {
1634
- // Check if the value contains any color tokens
1635
- if (value.includes('color.') || value.includes('theme.')) {
1636
- // For gradients and complex values, we need to process color tokens within the string
1637
- // This handles cases like: "linear-gradient(135deg, color.blue.500, color.red.500)"
1638
- let processedString = value;
1639
- // Find all color tokens in the string
1640
- const colorTokenRegex = /(color\.[a-zA-Z0-9.]+|theme\.[a-zA-Z0-9.]+)/g;
1641
- const colorTokens = value.match(colorTokenRegex);
1642
- if (colorTokens) {
1643
- // Replace each color token with its processed value
1644
- colorTokens.forEach(token => {
1645
- const processedColor = getColor(token);
1646
- // Use a global replace to catch all instances of this token
1647
- // Escape all special regex characters in the token
1648
- const escapedToken = token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1649
- processedString = processedString.replace(new RegExp(escapedToken, 'g'), processedColor);
1650
- });
1651
- processedValue = processedString;
1652
- } else {
1653
- // Fallback to the old method for simpler cases (like borders)
1654
- // Parse property to extract color
1655
- const parts = value.split(' ');
1656
- // Check each part to see if it starts with 'color.' or 'theme.'
1657
- const processedParts = parts.map(part => {
1658
- if (part.startsWith('color.') || part.startsWith('theme.')) {
1659
- // Process the color part through getColor
1660
- return getColor(part);
1661
- }
1662
- return part;
1663
- });
1664
- // Reconstruct the value with processed parts
1665
- processedValue = processedParts.join(' ');
1666
- }
1667
- }
1668
- }
1669
- // Handle numeric values
1670
- if (typeof processedValue === 'number') {
1671
- // Convert property to kebab-case to check against numericCssProperties
1672
- const kebabProperty = toKebabCase(property);
1673
- // Check if this is a property that should have px units
1674
- // First check the property as is, then check with vendor prefixes removed
1675
- const shouldAddPx = numericCssProperties.has(kebabProperty) ||
1676
- // Check if it's a vendor-prefixed property that needs px
1677
- /^-(webkit|moz|ms|o)-/.test(kebabProperty) && numericCssProperties.has(kebabProperty.replace(/^-(webkit|moz|ms|o)-/, ''));
1678
- if (shouldAddPx) {
1679
- processedValue = `${processedValue}px`;
1680
- }
1681
- }
1682
- return processedValue;
1846
+ // Use the shared processStyleProperty function which now contains the robust regex logic
1847
+ return processStyleProperty(property, value, getColor);
1683
1848
  },
1684
1849
  normalizeCssValue(value) {
1685
1850
  // Handle CSS variables in values
@@ -1701,7 +1866,7 @@ const ValueUtils = {
1701
1866
  if (rawCssCache.has(css)) {
1702
1867
  return rawCssCache.get(css);
1703
1868
  }
1704
- const shortName = Math.random().toString(36).substring(7);
1869
+ const shortName = hash(css);
1705
1870
  const newClassName = `raw-css-${shortName}`;
1706
1871
  rawCssCache.set(css, newClassName);
1707
1872
  return newClassName;
@@ -1714,6 +1879,7 @@ class UtilityClassManager {
1714
1879
  }
1715
1880
  this.styleSheets = new Map();
1716
1881
  this.mainDocument = null;
1882
+ this.serverRules = new Map();
1717
1883
  this.propertyShorthand = propertyShorthand;
1718
1884
  this.classCache = new LRUCache(maxCacheSize);
1719
1885
  if (typeof document !== 'undefined') {
@@ -1788,9 +1954,14 @@ class UtilityClassManager {
1788
1954
  if (context === void 0) {
1789
1955
  context = 'base';
1790
1956
  }
1791
- // Inject to main document
1957
+ // Inject to main document or cache for server
1792
1958
  if (this.mainDocument) {
1793
1959
  this.injectRuleToDocument(cssRule, context, this.mainDocument);
1960
+ } else {
1961
+ if (!this.serverRules.has(context)) {
1962
+ this.serverRules.set(context, []);
1963
+ }
1964
+ this.serverRules.get(context)?.push(cssRule);
1794
1965
  }
1795
1966
  // Inject to all other documents
1796
1967
  for (const document of this.getAllRegisteredDocuments()) {
@@ -1799,6 +1970,17 @@ class UtilityClassManager {
1799
1970
  }
1800
1971
  }
1801
1972
  }
1973
+ getServerStyles() {
1974
+ const contexts = ['base', 'pseudo', 'media', 'modifier'];
1975
+ let css = '';
1976
+ contexts.forEach(context => {
1977
+ const rules = this.serverRules.get(context);
1978
+ if (rules) {
1979
+ css += rules.join('\n') + '\n';
1980
+ }
1981
+ });
1982
+ return css;
1983
+ }
1802
1984
  getAllRegisteredDocuments() {
1803
1985
  return Array.from(this.styleSheets.keys());
1804
1986
  }
@@ -1863,13 +2045,32 @@ class UtilityClassManager {
1863
2045
  const pseudoClassName = `${baseClassName}--${modifier}`;
1864
2046
  classNames = [pseudoClassName];
1865
2047
  const escapedClassName = this.escapeClassName(pseudoClassName);
1866
- // Add rules for all necessary vendor prefixes
1867
- cssProperties.forEach(prefixedProperty => {
1868
- rules.push({
1869
- rule: `.${escapedClassName}:${modifier} { ${prefixedProperty}: ${valueForCss}; }`,
1870
- context: 'pseudo'
2048
+ // Format CSS rules for group and peer modifiers
2049
+ if (modifier.startsWith('group-')) {
2050
+ const groupState = modifier.replace('group-', '');
2051
+ cssProperties.forEach(prefixedProperty => {
2052
+ rules.push({
2053
+ rule: `.group:${groupState} .${escapedClassName} { ${prefixedProperty}: ${valueForCss}; }`,
2054
+ context: 'pseudo'
2055
+ });
1871
2056
  });
1872
- });
2057
+ } else if (modifier.startsWith('peer-')) {
2058
+ const peerState = modifier.replace('peer-', '');
2059
+ cssProperties.forEach(prefixedProperty => {
2060
+ rules.push({
2061
+ rule: `.peer:${peerState} ~ .${escapedClassName} { ${prefixedProperty}: ${valueForCss}; }`,
2062
+ context: 'pseudo'
2063
+ });
2064
+ });
2065
+ } else {
2066
+ // Standard pseudo-class
2067
+ cssProperties.forEach(prefixedProperty => {
2068
+ rules.push({
2069
+ rule: `.${escapedClassName}:${modifier} { ${prefixedProperty}: ${valueForCss}; }`,
2070
+ context: 'pseudo'
2071
+ });
2072
+ });
2073
+ }
1873
2074
  } else if (context === 'media' && modifier) {
1874
2075
  const mediaClassName = `${modifier}--${baseClassName}`;
1875
2076
  classNames = [mediaClassName];
@@ -2007,7 +2208,7 @@ const utilityClassManager = /*#__PURE__*/new UtilityClassManager(propertyShortha
2007
2208
  /**
2008
2209
  * Process styles for various contexts (base, pseudo, media)
2009
2210
  */
2010
- function processStyles(styles, context, modifier, getColor, mediaQueries, devices) {
2211
+ function processStyles(styles, context, modifier, getColor, mediaQueries, devices, manager) {
2011
2212
  if (context === void 0) {
2012
2213
  context = 'base';
2013
2214
  }
@@ -2032,14 +2233,14 @@ function processStyles(styles, context, modifier, getColor, mediaQueries, device
2032
2233
  }
2033
2234
  }
2034
2235
  if (value !== undefined && value !== '') {
2035
- const classNames = utilityClassManager.getClassNames(property, value, context, modifier, getColor, mediaQueriesForClass);
2236
+ const classNames = (manager || utilityClassManager).getClassNames(property, value, context, modifier, getColor, mediaQueriesForClass);
2036
2237
  classes.push(...classNames);
2037
2238
  }
2038
2239
  });
2039
2240
  return classes;
2040
2241
  }
2041
2242
  // Add a function to handle nested pseudo-classes
2042
- function processPseudoStyles(styles, parentPseudo, getColor) {
2243
+ function processPseudoStyles(styles, parentPseudo, getColor, manager) {
2043
2244
  if (parentPseudo === void 0) {
2044
2245
  parentPseudo = '';
2045
2246
  }
@@ -2055,7 +2256,7 @@ function processPseudoStyles(styles, parentPseudo, getColor) {
2055
2256
  // Construct the combined pseudo selector
2056
2257
  const combinedPseudo = parentPseudo ? `${parentPseudo}::${pseudo}` : `${pseudo}`;
2057
2258
  // Process the nested styles with the combined pseudo
2058
- classes.push(...processPseudoStyles(value, combinedPseudo, getColor));
2259
+ classes.push(...processPseudoStyles(value, combinedPseudo, getColor, manager));
2059
2260
  }
2060
2261
  } else if (typeof value !== 'object' || value === null) {
2061
2262
  // This is a regular CSS property
@@ -2067,7 +2268,7 @@ function processPseudoStyles(styles, parentPseudo, getColor) {
2067
2268
  const processedValue = ValueUtils.formatValue(value, key, getColor);
2068
2269
  // Create and inject the rule
2069
2270
  const rule = `.${escapedClassName}::${parentPseudo} { ${propertyToKebabCase(key)}: ${processedValue}; }`;
2070
- utilityClassManager.injectRule(rule, 'pseudo');
2271
+ (manager || utilityClassManager).injectRule(rule, 'pseudo');
2071
2272
  classes.push(escapedClassName);
2072
2273
  }
2073
2274
  }
@@ -2077,7 +2278,7 @@ function processPseudoStyles(styles, parentPseudo, getColor) {
2077
2278
  /**
2078
2279
  * Process event-based styles (hover, focus, etc.)
2079
2280
  */
2080
- function processEventStyles(eventName, eventStyles, getColor) {
2281
+ function processEventStyles(eventName, eventStyles, getColor, manager) {
2081
2282
  const classes = [];
2082
2283
  // Handle string shorthand (e.g., _hover: "color.red.500")
2083
2284
  if (typeof eventStyles === 'string') {
@@ -2097,7 +2298,7 @@ function processEventStyles(eventName, eventStyles, getColor) {
2097
2298
  // Process animations if present
2098
2299
  if (animate) {
2099
2300
  const animations = Array.isArray(animate) ? animate : [animate];
2100
- const animationStyles = AnimationUtils.processAnimations(animations);
2301
+ const animationStyles = AnimationUtils.processAnimations(animations, manager);
2101
2302
  Object.assign(otherEventStyles, animationStyles);
2102
2303
  }
2103
2304
  // Process shadow if present
@@ -2133,7 +2334,7 @@ function processEventStyles(eventName, eventStyles, getColor) {
2133
2334
  const nestedPseudo = EVENT_TO_PSEUDO[nestedPseudoName];
2134
2335
  if (nestedPseudo) {
2135
2336
  const combinedPseudo = `${pseudo}::${nestedPseudo}`;
2136
- classes.push(...processPseudoStyles(otherEventStyles[nestedKey], combinedPseudo, getColor));
2337
+ classes.push(...processPseudoStyles(otherEventStyles[nestedKey], combinedPseudo, getColor, manager));
2137
2338
  }
2138
2339
  });
2139
2340
  // Remove processed nested pseudos
@@ -2146,12 +2347,12 @@ function processEventStyles(eventName, eventStyles, getColor) {
2146
2347
  if (Object.keys(otherEventStyles).length > 0) {
2147
2348
  const pseudo = EVENT_TO_PSEUDO[eventName];
2148
2349
  if (pseudo) {
2149
- classes.push(...processStyles(otherEventStyles, 'pseudo', pseudo, getColor));
2350
+ classes.push(...processStyles(otherEventStyles, 'pseudo', pseudo, getColor, {}, {}, manager));
2150
2351
  }
2151
2352
  }
2152
2353
  return classes;
2153
2354
  }
2154
- const extractUtilityClasses = (props, getColor, mediaQueries, devices) => {
2355
+ const extractUtilityClasses = (props, getColor, mediaQueries, devices, manager) => {
2155
2356
  const classes = [];
2156
2357
  const computedStyles = {};
2157
2358
  // Handle widthHeight (shorthand for both width and height)
@@ -2202,9 +2403,9 @@ const extractUtilityClasses = (props, getColor, mediaQueries, devices) => {
2202
2403
  // Handle animations
2203
2404
  if (props.animate) {
2204
2405
  const animations = Array.isArray(props.animate) ? props.animate : [props.animate];
2205
- Object.assign(computedStyles, AnimationUtils.processAnimations(animations));
2406
+ Object.assign(computedStyles, AnimationUtils.processAnimations(animations, manager));
2206
2407
  }
2207
- const blendConfig = props?.theme?.blend || {
2408
+ const blendConfig = {
2208
2409
  mode: 'difference',
2209
2410
  color: 'white',
2210
2411
  modeWithBg: 'overlay'
@@ -2219,7 +2420,7 @@ const extractUtilityClasses = (props, getColor, mediaQueries, devices) => {
2219
2420
  }
2220
2421
  };
2221
2422
  // Handle default blend
2222
- if (props.blend !== false && props.color === undefined && computedStyles.color === undefined && typeof props.children === 'string') {
2423
+ if (props.blend === true) {
2223
2424
  setBlend(props, computedStyles);
2224
2425
  Object.keys(props).forEach(property => {
2225
2426
  if (props[property]?.color === undefined && property.startsWith('_') && property.length > 1) {
@@ -2228,7 +2429,7 @@ const extractUtilityClasses = (props, getColor, mediaQueries, devices) => {
2228
2429
  });
2229
2430
  }
2230
2431
  // Process base styles
2231
- classes.push(...processStyles(computedStyles, 'base', '', getColor));
2432
+ classes.push(...processStyles(computedStyles, 'base', '', getColor, {}, {}, manager));
2232
2433
  // Collect underscore-prefixed properties (_hover, _focus, etc.)
2233
2434
  const underscoreProps = {};
2234
2435
  Object.keys(props).forEach(property => {
@@ -2245,17 +2446,17 @@ const extractUtilityClasses = (props, getColor, mediaQueries, devices) => {
2245
2446
  if (property === 'on') {
2246
2447
  // Process event-based styles
2247
2448
  Object.keys(value).forEach(event => {
2248
- classes.push(...processEventStyles(event, value[event], getColor));
2449
+ classes.push(...processEventStyles(event, value[event], getColor, manager));
2249
2450
  });
2250
2451
  } else if (property === 'media') {
2251
2452
  // Process media query styles
2252
2453
  Object.keys(value).forEach(screenOrDevice => {
2253
- classes.push(...processStyles(value[screenOrDevice], 'media', screenOrDevice, getColor, mediaQueries, devices));
2454
+ classes.push(...processStyles(value[screenOrDevice], 'media', screenOrDevice, getColor, mediaQueries, devices, manager));
2254
2455
  });
2255
2456
  }
2256
2457
  } else if (value !== undefined && value !== '') {
2257
2458
  // Direct style property
2258
- classes.push(...utilityClassManager.getClassNames(property, value, 'base', '', getColor, []));
2459
+ classes.push(...(manager || utilityClassManager).getClassNames(property, value, 'base', '', getColor, []));
2259
2460
  }
2260
2461
  }
2261
2462
  });
@@ -2264,23 +2465,69 @@ const extractUtilityClasses = (props, getColor, mediaQueries, devices) => {
2264
2465
  if (typeof props.css === 'object') {
2265
2466
  // Object-style CSS gets processed as regular styles
2266
2467
  Object.assign(computedStyles, props.css);
2267
- classes.push(...processStyles(props.css, 'base', '', getColor));
2468
+ classes.push(...processStyles(props.css, 'base', '', getColor, {}, {}, manager));
2268
2469
  } else if (typeof props.css === 'string') {
2269
2470
  // String-style CSS gets its own class
2270
2471
  const uniqueClassName = ValueUtils.generateUniqueClassName(props.css);
2271
- utilityClassManager.injectRule(`.${uniqueClassName} { ${props.css} }`);
2472
+ (manager || utilityClassManager).injectRule(`.${uniqueClassName} { ${props.css} }`);
2272
2473
  classes.push(uniqueClassName);
2273
2474
  }
2274
2475
  }
2275
2476
  // Process underscore-prefixed event properties
2276
2477
  if (Object.keys(underscoreProps).length > 0) {
2277
2478
  Object.keys(underscoreProps).forEach(event => {
2278
- classes.push(...processEventStyles(event, underscoreProps[event], getColor));
2479
+ classes.push(...processEventStyles(event, underscoreProps[event], getColor, manager));
2279
2480
  });
2280
2481
  }
2281
2482
  return classes;
2282
2483
  };
2283
2484
 
2485
+ const StyleRegistryContext = /*#__PURE__*/React.createContext({
2486
+ manager: utilityClassManager
2487
+ });
2488
+ /**
2489
+ * Hook to access the current style manager.
2490
+ */
2491
+ const useStyleRegistry = () => React.useContext(StyleRegistryContext);
2492
+ /**
2493
+ * Provider to wrap the app and manage styles.
2494
+ * When doing SSR, pass a new registry created via createStyleRegistry().
2495
+ */
2496
+ const StyleRegistry = _ref => {
2497
+ let {
2498
+ registry,
2499
+ children
2500
+ } = _ref;
2501
+ const value = React.useMemo(() => ({
2502
+ // If no registry provided, fallback to globalManager
2503
+ manager: registry || utilityClassManager
2504
+ }), [registry]);
2505
+ return /*#__PURE__*/React__default.createElement(StyleRegistryContext.Provider, {
2506
+ value: value
2507
+ }, children);
2508
+ };
2509
+ /**
2510
+ * Helper to create a new style registry (UtilityClassManager) instance.
2511
+ * Useful for SSR to create a fresh manager per request.
2512
+ */
2513
+ const createStyleRegistry = () => {
2514
+ return new UtilityClassManager(propertyShorthand, 10000);
2515
+ };
2516
+ /**
2517
+ * React hook to get the CSS string from the registry.
2518
+ * Note: This only works if you're using a fresh registry that collected styles.
2519
+ */
2520
+ const useServerInsertedHTML = registry => {
2521
+ return () => {
2522
+ return /*#__PURE__*/React__default.createElement("style", {
2523
+ id: "app-studio-server-css",
2524
+ dangerouslySetInnerHTML: {
2525
+ __html: registry.getServerStyles()
2526
+ }
2527
+ });
2528
+ };
2529
+ };
2530
+
2284
2531
  // analytics/AnalyticsContext.tsx
2285
2532
  // Create the context with a default no-op implementation
2286
2533
  const AnalyticsContext = /*#__PURE__*/React.createContext({});
@@ -2309,10 +2556,14 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
2309
2556
  }
2310
2557
  const {
2311
2558
  onPress,
2312
- blend,
2559
+ blend: initialBlend,
2313
2560
  animateOn = 'Both',
2314
2561
  ...rest
2315
2562
  } = props;
2563
+ let blend = initialBlend;
2564
+ if (blend !== false && props.color === undefined && typeof props.children === 'string' && (as === 'span' || as === 'div' || blend === true)) {
2565
+ blend = true;
2566
+ }
2316
2567
  const elementRef = React.useRef(null);
2317
2568
  const setRef = React.useCallback(node => {
2318
2569
  elementRef.current = node;
@@ -2333,6 +2584,9 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
2333
2584
  mediaQueries,
2334
2585
  devices
2335
2586
  } = useResponsiveContext();
2587
+ const {
2588
+ manager
2589
+ } = useStyleRegistry();
2336
2590
  const [isVisible, setIsVisible] = React.useState(false);
2337
2591
  React.useEffect(() => {
2338
2592
  if (!animateIn) {
@@ -2360,25 +2614,24 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
2360
2614
  React.useEffect(() => {
2361
2615
  if (animateIn && elementRef.current && isVisible) {
2362
2616
  const animations = Array.isArray(animateIn) ? animateIn : [animateIn];
2363
- const styles = AnimationUtils.processAnimations(animations);
2617
+ const styles = AnimationUtils.processAnimations(animations, manager);
2364
2618
  Object.assign(elementRef.current.style, styles);
2365
2619
  }
2366
- }, [animateIn, isVisible]);
2620
+ }, [animateIn, isVisible, manager]);
2367
2621
  React.useEffect(() => {
2368
2622
  const node = elementRef.current;
2369
2623
  return () => {
2370
2624
  if (animateOut && node) {
2371
2625
  const animations = Array.isArray(animateOut) ? animateOut : [animateOut];
2372
- const styles = AnimationUtils.processAnimations(animations);
2626
+ const styles = AnimationUtils.processAnimations(animations, manager);
2373
2627
  Object.assign(node.style, styles);
2374
2628
  }
2375
2629
  };
2376
- }, [animateOut]);
2630
+ }, [animateOut, manager]);
2377
2631
  const utilityClasses = React.useMemo(() => {
2378
2632
  const propsToProcess = {
2379
2633
  ...rest,
2380
- blend,
2381
- theme: props.theme || theme
2634
+ blend
2382
2635
  };
2383
2636
  // Apply view() timeline ONLY if animateOn='View' (not Both or Mount)
2384
2637
  if (animateOn === 'View' && propsToProcess.animate) {
@@ -2396,14 +2649,25 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
2396
2649
  return anim;
2397
2650
  });
2398
2651
  }
2399
- return extractUtilityClasses(propsToProcess, color => {
2400
- return getColor(color, {
2401
- colors: props.colors,
2402
- theme: props.theme,
2403
- themeMode: props.themeMode
2652
+ // Apply scroll() timeline if animateOn='Scroll'
2653
+ if (animateOn === 'Scroll' && propsToProcess.animate) {
2654
+ const animations = Array.isArray(propsToProcess.animate) ? propsToProcess.animate : [propsToProcess.animate];
2655
+ propsToProcess.animate = animations.map(anim => {
2656
+ // Only add timeline if not already specified
2657
+ if (!anim.timeline) {
2658
+ return {
2659
+ ...anim,
2660
+ timeline: 'scroll()',
2661
+ fillMode: anim.fillMode || 'both'
2662
+ };
2663
+ }
2664
+ return anim;
2404
2665
  });
2405
- }, mediaQueries, devices);
2406
- }, [rest, blend, animateOn, mediaQueries, devices, theme]);
2666
+ }
2667
+ return extractUtilityClasses(propsToProcess, color => {
2668
+ return getColor(color);
2669
+ }, mediaQueries, devices, manager);
2670
+ }, [rest, blend, animateOn, mediaQueries, devices, theme, manager]);
2407
2671
  const newProps = {
2408
2672
  ref: setRef
2409
2673
  };
@@ -2413,6 +2677,9 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
2413
2677
  if (utilityClasses.length > 0) {
2414
2678
  newProps.className = utilityClasses.join(' ');
2415
2679
  }
2680
+ if (props.className) {
2681
+ newProps.className = newProps.className ? `${newProps.className} ${props.className}` : props.className;
2682
+ }
2416
2683
  // Handle event tracking for onClick
2417
2684
  if (trackEvent && props.onClick) {
2418
2685
  let componentName;
@@ -2468,7 +2735,7 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
2468
2735
  };
2469
2736
  }
2470
2737
  const Component = as;
2471
- return children ? (/*#__PURE__*/React__default.createElement(Component, Object.assign({}, newProps), before, children, after)) : /*#__PURE__*/React__default.createElement(Component, Object.assign({}, newProps));
2738
+ return children ? (/*#__PURE__*/React__default.createElement(Component, Object.assign({}, newProps), before, children, after)) : (/*#__PURE__*/React__default.createElement(Component, Object.assign({}, newProps)));
2472
2739
  }));
2473
2740
 
2474
2741
  const View = /*#__PURE__*/React__default.forwardRef((props, ref) => (/*#__PURE__*/React__default.createElement(Element, Object.assign({}, props, {
@@ -2502,7 +2769,7 @@ const HorizontalResponsive = /*#__PURE__*/React__default.forwardRef((_ref, ref)
2502
2769
  media: {
2503
2770
  ...media,
2504
2771
  mobile: {
2505
- ...media.mobile,
2772
+ ...media?.mobile,
2506
2773
  flexDirection: 'column'
2507
2774
  }
2508
2775
  }
@@ -2519,7 +2786,7 @@ const VerticalResponsive = /*#__PURE__*/React__default.forwardRef((_ref2, ref) =
2519
2786
  media: {
2520
2787
  ...media,
2521
2788
  mobile: {
2522
- ...media.mobile,
2789
+ ...media?.mobile,
2523
2790
  flexDirection: 'row'
2524
2791
  }
2525
2792
  }
@@ -5518,16 +5785,19 @@ exports.Scroll = Scroll;
5518
5785
  exports.Shadows = Shadows;
5519
5786
  exports.Skeleton = Skeleton;
5520
5787
  exports.Span = Span;
5788
+ exports.StyleRegistry = StyleRegistry;
5521
5789
  exports.Text = Text;
5522
5790
  exports.ThemeContext = ThemeContext;
5523
5791
  exports.ThemeProvider = ThemeProvider;
5524
5792
  exports.Typography = Typography;
5793
+ exports.UtilityClassManager = UtilityClassManager;
5525
5794
  exports.Vertical = Vertical;
5526
5795
  exports.VerticalResponsive = VerticalResponsive;
5527
5796
  exports.View = View;
5528
5797
  exports.animateOnView = animateOnView;
5529
5798
  exports.blurInOnView = blurInOnView;
5530
5799
  exports.blurOutOnView = blurOutOnView;
5800
+ exports.createStyleRegistry = createStyleRegistry;
5531
5801
  exports.createViewAnimation = createViewAnimation;
5532
5802
  exports.debounce = debounce;
5533
5803
  exports.deepMerge = deepMerge;
@@ -5543,11 +5813,14 @@ exports.fadeOutOnView = fadeOutOnView;
5543
5813
  exports.flipXOnView = flipXOnView;
5544
5814
  exports.flipYOnView = flipYOnView;
5545
5815
  exports.getWindowInitialProps = getWindowInitialProps;
5816
+ exports.hasColorToken = hasColorToken;
5546
5817
  exports.isBrowser = isBrowser;
5547
5818
  exports.isDev = isDev;
5548
5819
  exports.isMobile = isMobile;
5549
5820
  exports.isProd = isProd;
5550
5821
  exports.isSSR = isSSR;
5822
+ exports.propertyShorthand = propertyShorthand;
5823
+ exports.replaceColorTokens = replaceColorTokens;
5551
5824
  exports.revealOnView = revealOnView;
5552
5825
  exports.rotateInOnView = rotateInOnView;
5553
5826
  exports.scaleDownOnView = scaleDownOnView;
@@ -5572,7 +5845,9 @@ exports.useResponsiveContext = useResponsiveContext;
5572
5845
  exports.useScroll = useScroll;
5573
5846
  exports.useScrollAnimation = useScrollAnimation;
5574
5847
  exports.useScrollDirection = useScrollDirection;
5848
+ exports.useServerInsertedHTML = useServerInsertedHTML;
5575
5849
  exports.useSmoothScroll = useSmoothScroll;
5850
+ exports.useStyleRegistry = useStyleRegistry;
5576
5851
  exports.useTheme = useTheme;
5577
5852
  exports.useWindowSize = useWindowSize;
5578
5853
  exports.utilityClassManager = utilityClassManager;