app-studio 0.6.49 → 0.6.51

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 +704 -467
  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 +697 -468
  5. package/dist/app-studio.esm.js.map +1 -1
  6. package/dist/app-studio.umd.development.js +708 -471
  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,137 @@ 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
+
870
+ [data-theme='light'] {
871
+ ${lightMappings}
872
+ }
873
+
874
+ [data-theme='dark'] {
875
+ ${darkMappings}
876
+ }
877
+ `;
878
+ return css;
879
+ };
738
880
  // --- Default Configuration ---
739
881
  const defaultThemeMain = {
740
882
  primary: `${COLOR_PREFIX}black`,
@@ -743,12 +885,7 @@ const defaultThemeMain = {
743
885
  error: `${COLOR_PREFIX}red.500`,
744
886
  warning: `${COLOR_PREFIX}orange.500`,
745
887
  disabled: `${COLOR_PREFIX}gray.500`,
746
- loading: `${COLOR_PREFIX}dark.500`,
747
- blend: {
748
- mode: 'difference',
749
- color: 'white',
750
- modeWithBg: 'exclusion'
751
- }
888
+ loading: `${COLOR_PREFIX}dark.500`
752
889
  };
753
890
  const defaultLightColorConfig = {
754
891
  main: defaultLightColors,
@@ -777,6 +914,44 @@ const useTheme = () => {
777
914
  }
778
915
  return context;
779
916
  };
917
+ // --- Helper Function to Convert Color to RGBA with Alpha ---
918
+ /**
919
+ * Converts a color (hex, rgb, or rgba) to rgba format with specified alpha.
920
+ * @param color - The base color in hex, rgb, or rgba format
921
+ * @param alpha - Alpha value on a 0-1000 scale (e.g., 200 = 0.2 opacity)
922
+ * @returns RGBA color string
923
+ */
924
+ const convertToRgba = (color, alpha) => {
925
+ // Normalize alpha to 0-1 range
926
+ const normalizedAlpha = Math.max(0, Math.min(1000, alpha)) / 1000;
927
+ // Handle hex colors (#RGB or #RRGGBB)
928
+ if (color.startsWith('#')) {
929
+ let hex = color.slice(1);
930
+ // Convert shorthand hex to full form
931
+ if (hex.length === 3) {
932
+ hex = hex.split('').map(char => char + char).join('');
933
+ }
934
+ const r = parseInt(hex.slice(0, 2), 16);
935
+ const g = parseInt(hex.slice(2, 4), 16);
936
+ const b = parseInt(hex.slice(4, 6), 16);
937
+ return `rgba(${r}, ${g}, ${b}, ${normalizedAlpha})`;
938
+ }
939
+ // Handle rgb/rgba colors
940
+ if (color.startsWith('rgb')) {
941
+ // Extract the values from rgb() or rgba()
942
+ const match = color.match(/rgba?\(([^)]+)\)/);
943
+ if (match) {
944
+ const values = match[1].split(',').map(v => v.trim());
945
+ const r = values[0];
946
+ const g = values[1];
947
+ const b = values[2];
948
+ return `rgba(${r}, ${g}, ${b}, ${normalizedAlpha})`;
949
+ }
950
+ }
951
+ // If color format is not recognized, return as-is
952
+ console.warn(`Unable to convert color "${color}" to rgba format`);
953
+ return color;
954
+ };
780
955
  // --- Deep Merge Function (remains the same, assuming it works as intended) ---
781
956
  // Consider using a library like `lodash.merge` or `deepmerge` if complexity grows
782
957
  // or edge cases (like merging arrays) need different handling.
@@ -811,7 +986,8 @@ const ThemeProvider = _ref => {
811
986
  mode: initialMode = 'light',
812
987
  dark: darkOverride = {},
813
988
  light: lightOverride = {},
814
- children
989
+ children,
990
+ strict = false
815
991
  } = _ref;
816
992
  const [themeMode, setThemeMode] = React.useState(initialMode);
817
993
  const colorCache = React.useRef(new Map()).current;
@@ -830,110 +1006,125 @@ const ThemeProvider = _ref => {
830
1006
  dark: deepMerge(defaultDarkColorConfig, darkOverride)
831
1007
  }), [lightOverride, darkOverride]);
832
1008
  const currentColors = React.useMemo(() => themeColors[themeMode], [themeColors, themeMode]);
1009
+ // --- Helper function to resolve color tokens to actual values ---
1010
+ const resolveColorToken = React.useCallback(token => {
1011
+ if (!token || typeof token !== 'string') return String(token);
1012
+ if (token === TRANSPARENT) return token;
1013
+ const colors = currentColors;
1014
+ // Resolve color.* tokens
1015
+ if (token.startsWith(COLOR_PREFIX)) {
1016
+ const keys = token.substring(COLOR_PREFIX.length).split('.');
1017
+ if (keys.length === 1) {
1018
+ // e.g., "color.blue" -> main color
1019
+ const colorValue = colors.main[keys[0]];
1020
+ return typeof colorValue === 'string' ? colorValue : token;
1021
+ } else if (keys.length === 2) {
1022
+ // e.g., "color.blue.500" -> palette color
1023
+ const [colorName, shade] = keys;
1024
+ const shadeValue = colors.palette[colorName]?.[Number(shade)];
1025
+ return typeof shadeValue === 'string' ? shadeValue : token;
1026
+ } else if (keys.length === 3) {
1027
+ // e.g., "color.blue.500.200" -> palette color with alpha
1028
+ // Use color-mix() to apply alpha via CSS variables
1029
+ const [colorName, shade, alphaStr] = keys;
1030
+ const alpha = parseInt(alphaStr, 10);
1031
+ if (!isNaN(alpha)) {
1032
+ const percentage = Math.round(alpha / 1000 * 100);
1033
+ return `color-mix(in srgb, var(--color-${colorName}-${shade}) ${percentage}%, transparent)`;
1034
+ }
1035
+ }
1036
+ }
1037
+ // Resolve theme.* tokens (recursive resolution)
1038
+ if (token.startsWith(THEME_PREFIX)) {
1039
+ const themeKey = token.substring(THEME_PREFIX.length);
1040
+ const themeValue = mergedTheme[themeKey];
1041
+ if (typeof themeValue === 'string') {
1042
+ return resolveColorToken(themeValue);
1043
+ }
1044
+ }
1045
+ return token;
1046
+ }, [currentColors, mergedTheme]);
1047
+ // The mode is now handled by the data-attribute on the container
833
1048
  // --- Memoized getColor function - Revised for Robustness ---
834
1049
  const getColor = React.useCallback((name, override) => {
835
1050
  if (!name || typeof name !== 'string') return String(name); // Handle invalid input
836
1051
  if (name === TRANSPARENT) return name;
837
- // 1. Determine the effective mode for this specific lookup
1052
+ // 1. Check for optimization (CSS vars) if no overrides
1053
+ // This allows instant theme switching via CSS variables without re-render
1054
+ if (!override || Object.keys(override).length === 0) {
1055
+ if (name.startsWith(THEME_PREFIX)) {
1056
+ return `var(--${name.replace(/\./g, '-')})`;
1057
+ }
1058
+ if (name.startsWith(COLOR_PREFIX)) {
1059
+ const parts = name.split('.');
1060
+ // Simple lookup (e.g. color.blue or color.blue.500)
1061
+ if (parts.length < 4) {
1062
+ return `var(--${name.replace(/\./g, '-')})`;
1063
+ }
1064
+ }
1065
+ }
1066
+ // 2. Manual Resolution (Fallback for overrides or complex keys)
838
1067
  const effectiveMode = override?.themeMode ?? themeMode;
839
1068
  const needCache = override && Object.keys(override).length === 0;
840
- // 2. Create a cache key based on the name and the *effective* mode
841
1069
  const cacheKey = `${name}-${effectiveMode}`;
842
- if (colorCache.has(cacheKey) && needCache) {
1070
+ if (needCache && colorCache.has(cacheKey)) {
843
1071
  return colorCache.get(cacheKey);
844
1072
  }
1073
+ // Strict Mode Check
1074
+ if (strict && !name.startsWith(COLOR_PREFIX) && !name.startsWith(THEME_PREFIX) && !name.startsWith('light.') && !name.startsWith('dark.')) {
1075
+ console.warn(`[Theme] Strict mode enabled: '${name}' is not a valid color token.`);
1076
+ }
845
1077
  // 3. Select the correct color set (light/dark) based on the effective mode
846
1078
  const colorsToUse = themeColors[effectiveMode];
847
1079
  if (!colorsToUse) {
848
1080
  console.warn(`Color set for mode "${effectiveMode}" not found.`);
849
- return name; // Fallback if colors for the mode don't exist
1081
+ return name;
850
1082
  }
851
- let resolvedColor = name; // Default fallback is the original name
1083
+ let resolvedColor = name;
852
1084
  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
1085
+ // Resolve "light.*" or "dark.*" paths directly
1086
+ if (name.startsWith('light.') || name.startsWith('dark.')) {
1087
+ const prefixLength = name.startsWith('light.') ? 6 : 5;
883
1088
  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
- // );
1089
+ return `var(--${modifiedName.replace(/\./g, '-')})`;
1090
+ }
1091
+ // Resolve "color.*" paths
1092
+ if (name.startsWith(COLOR_PREFIX)) {
896
1093
  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
1094
+ if (keys.length === 3) {
1095
+ // e.g. "color.black.900.200" (alpha)
1096
+ const [colorName, variant, alphaStr] = keys;
1097
+ const palette = deepMerge(colorsToUse.palette, override?.colors?.palette || {});
1098
+ const shadeValue = palette?.[colorName]?.[variant];
1099
+ const alpha = parseInt(alphaStr, 10);
1100
+ if (typeof shadeValue === 'string' && !isNaN(alpha)) {
1101
+ resolvedColor = convertToRgba(shadeValue, alpha);
907
1102
  }
908
1103
  } else if (keys.length === 2) {
909
- // e.g., "color.blue.500"
1104
+ // e.g. "color.blue.500"
910
1105
  const [colorName, variant] = keys;
911
1106
  const palette = deepMerge(colorsToUse.palette, override?.colors?.palette || {});
912
1107
  const shadeValue = palette?.[colorName]?.[variant];
913
1108
  if (typeof shadeValue === 'string') {
914
1109
  resolvedColor = shadeValue;
915
- } else {
916
- console.warn(`Palette color "${name}" not found in ${effectiveMode} mode.`);
917
- resolvedColor = name; // Fallback on unexpected error
918
1110
  }
919
- } else {
920
- console.warn(`Invalid color format: "${name}". Expected 'color.name' or 'color.name.shade'.`);
921
- resolvedColor = name; // Fallback on unexpected error
1111
+ } else if (keys.length === 1) {
1112
+ // e.g. "color.blue"
1113
+ const [colorName] = keys;
1114
+ const main = deepMerge(colorsToUse.main, override?.colors?.main || {});
1115
+ const colorValue = main?.[colorName];
1116
+ if (typeof colorValue === 'string') {
1117
+ resolvedColor = colorValue;
1118
+ }
922
1119
  }
923
1120
  }
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
1121
  } catch (e) {
928
- console.error(`Error resolving color "${name}" for mode "${effectiveMode}":`, e);
929
- resolvedColor = name; // Fallback on unexpected error
1122
+ console.error(`Error resolving color "${name}"`, e);
1123
+ resolvedColor = name;
930
1124
  }
931
- // Cache the result (the resolved color or the original name if failed)
932
1125
  if (needCache) colorCache.set(cacheKey, resolvedColor);
933
1126
  return resolvedColor;
934
- },
935
- // Dependencies: mergedTheme, themeColors, themeMode (for default), colorCache
936
- [mergedTheme, themeColors, themeMode, colorCache]);
1127
+ }, [mergedTheme, themeColors, themeMode, colorCache, strict]);
937
1128
  // --- Memoize Context Value ---
938
1129
  const contextValue = React.useMemo(() => ({
939
1130
  getColor,
@@ -941,13 +1132,16 @@ const ThemeProvider = _ref => {
941
1132
  colors: currentColors,
942
1133
  themeMode,
943
1134
  setThemeMode
944
- }), [getColor, mergedTheme, currentColors, themeMode] // Exclude setThemeMode (stable)
945
- );
1135
+ }), [getColor, mergedTheme, currentColors, themeMode]);
946
1136
  return /*#__PURE__*/React__default.createElement(ThemeContext.Provider, {
947
1137
  value: contextValue
948
- }, /*#__PURE__*/React__default.createElement("div", {
1138
+ }, /*#__PURE__*/React__default.createElement("style", null, generateCSSVariables(mergedTheme, themeColors.light, themeColors.dark)), /*#__PURE__*/React__default.createElement("div", {
1139
+ "data-theme": themeMode,
949
1140
  style: {
950
- backgroundColor: 'white'
1141
+ backgroundColor: 'white',
1142
+ width: "100%",
1143
+ height: "100%",
1144
+ transition: "background-color 0.2s, color 0.2s"
951
1145
  }
952
1146
  }, children));
953
1147
  };
@@ -1061,7 +1255,101 @@ const ResponsiveProvider = _ref => {
1061
1255
  }, children);
1062
1256
  };
1063
1257
 
1258
+ const Shadows = {
1259
+ 0: {
1260
+ shadowColor: '#000',
1261
+ shadowOffset: {
1262
+ width: 1,
1263
+ height: 2
1264
+ },
1265
+ shadowOpacity: 0.18,
1266
+ shadowRadius: 1.0
1267
+ },
1268
+ 1: {
1269
+ shadowColor: '#000',
1270
+ shadowOffset: {
1271
+ width: 2,
1272
+ height: 2
1273
+ },
1274
+ shadowOpacity: 0.2,
1275
+ shadowRadius: 1.41
1276
+ },
1277
+ 2: {
1278
+ shadowColor: '#000',
1279
+ shadowOffset: {
1280
+ width: 3,
1281
+ height: 3
1282
+ },
1283
+ shadowOpacity: 0.22,
1284
+ shadowRadius: 2.22
1285
+ },
1286
+ 3: {
1287
+ shadowColor: '#000',
1288
+ shadowOffset: {
1289
+ width: 4,
1290
+ height: 4
1291
+ },
1292
+ shadowOpacity: 0.23,
1293
+ shadowRadius: 2.62
1294
+ },
1295
+ 4: {
1296
+ shadowColor: '#000',
1297
+ shadowOffset: {
1298
+ width: 5,
1299
+ height: 5
1300
+ },
1301
+ shadowOpacity: 0.25,
1302
+ shadowRadius: 3.84
1303
+ },
1304
+ 5: {
1305
+ shadowColor: '#000',
1306
+ shadowOffset: {
1307
+ width: 6,
1308
+ height: 6
1309
+ },
1310
+ shadowOpacity: 0.27,
1311
+ shadowRadius: 4.65
1312
+ },
1313
+ 6: {
1314
+ shadowColor: '#000',
1315
+ shadowOffset: {
1316
+ width: 7,
1317
+ height: 7
1318
+ },
1319
+ shadowOpacity: 0.29,
1320
+ shadowRadius: 4.65
1321
+ },
1322
+ 7: {
1323
+ shadowColor: '#000',
1324
+ shadowOffset: {
1325
+ width: 8,
1326
+ height: 8
1327
+ },
1328
+ shadowOpacity: 0.3,
1329
+ shadowRadius: 4.65
1330
+ },
1331
+ 8: {
1332
+ shadowColor: '#000',
1333
+ shadowOffset: {
1334
+ width: 9,
1335
+ height: 9
1336
+ },
1337
+ shadowOpacity: 0.32,
1338
+ shadowRadius: 5.46
1339
+ },
1340
+ 9: {
1341
+ shadowColor: '#000',
1342
+ shadowOffset: {
1343
+ width: 10,
1344
+ height: 10
1345
+ },
1346
+ shadowOpacity: 0.34,
1347
+ shadowRadius: 6.27
1348
+ }
1349
+ };
1350
+
1064
1351
  // List of numeric properties that don't need 'px' suffix
1352
+ const NumberProps = /*#__PURE__*/new Set(['numberOfLines', 'fontWeight', 'timeStamp', 'flex', 'flexGrow', 'flexShrink', 'order', 'zIndex', 'aspectRatio', 'shadowOpacity', 'shadowRadius', 'scale', 'opacity', 'min', 'max', 'now']);
1065
1353
  // Keys to exclude when passing props to the component
1066
1354
  const excludedKeys = /*#__PURE__*/new Set([
1067
1355
  // Standard styling props
@@ -1080,37 +1368,7 @@ const vendorPrefixToKebabCase = property => {
1080
1368
  if (property.startsWith('--')) {
1081
1369
  return property;
1082
1370
  }
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();
1371
+ return hyphenate(property);
1114
1372
  };
1115
1373
  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
1374
  // Vendor-prefixed properties that need pixel values
@@ -1124,22 +1382,7 @@ const numericCssProperties = /*#__PURE__*/new Set(['border-bottom-left-radius',
1124
1382
  * @returns The property name in kebab-case with appropriate vendor prefixes
1125
1383
  */
1126
1384
  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();
1385
+ return vendorPrefixToKebabCase(property);
1143
1386
  }
1144
1387
  // Comprehensive list of CSS properties that should be converted to classes
1145
1388
  const cssProperties = /*#__PURE__*/new Set([
@@ -1178,13 +1421,19 @@ const isStyleProp = prop => {
1178
1421
  return false;
1179
1422
  }
1180
1423
  // 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);
1424
+ if (cssProperties.has(prop) || extraKeys.has(prop) || prop.startsWith('--') || prop.startsWith('data-style-') && !includeKeys.has(prop)) {
1425
+ return true;
1426
+ }
1427
+ // Check if it's a valid CSS property using CSS.supports (browser environment)
1428
+ if (typeof CSS !== 'undefined' && CSS.supports) {
1429
+ try {
1430
+ const kebabProp = vendorPrefixToKebabCase(prop);
1431
+ return CSS.supports(kebabProp, 'inherit');
1432
+ } catch {
1433
+ return false;
1434
+ }
1435
+ }
1436
+ return false;
1188
1437
  };
1189
1438
  /**
1190
1439
  * Enhances styleObjectToCss to handle vendor prefixed properties
@@ -1208,101 +1457,53 @@ function styleObjectToCss(styleObject) {
1208
1457
  const toKebabCase = str => {
1209
1458
  return vendorPrefixToKebabCase(str);
1210
1459
  };
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
1460
+ // Process and normalize style properties
1461
+ const processStyleProperty = (property, value, getColor) => {
1462
+ // Handle null or undefined values
1463
+ if (value == null) {
1464
+ return '';
1465
+ }
1466
+ // Handle custom CSS properties (variables)
1467
+ if (property.startsWith('--')) {
1468
+ // For CSS variables, we pass the value as is
1469
+ return value;
1470
+ }
1471
+ // Convert kebab-case property to check against numericCssProperties
1472
+ const kebabProperty = toKebabCase(property);
1473
+ // Convert numbers to pixels for appropriate properties
1474
+ if (typeof value === 'number') {
1475
+ // Check if this is a property that should have px units
1476
+ // First check the property as is, then check with vendor prefixes removed
1477
+ const shouldAddPx = !NumberProps.has(property) && (numericCssProperties.has(kebabProperty) ||
1478
+ // Check if it's a vendor-prefixed property that needs px
1479
+ (/^-(webkit|moz|ms|o)-/.test(kebabProperty) || /^-(Webkit|Moz|Ms|O)-/.test(kebabProperty)) && numericCssProperties.has(kebabProperty.replace(/^-(webkit|moz|ms|o|Webkit|Moz|Ms|O)-/, '')));
1480
+ if (shouldAddPx) {
1481
+ return `${value}px`;
1482
+ }
1483
+ return value;
1304
1484
  }
1485
+ // Handle color properties directly
1486
+ if (property.toLowerCase().indexOf('color') >= 0 || property === 'fill' || property === 'stroke') {
1487
+ return getColor(value);
1488
+ }
1489
+ // Handle properties that might contain color values (borders, gradients, shadows, etc.)
1490
+ if (typeof value === 'string' && value.length > 3) {
1491
+ if (hasColorToken(value)) {
1492
+ return replaceColorTokens(value, token => getColor(token));
1493
+ }
1494
+ }
1495
+ // Handle arrays (e.g., for transforms)
1496
+ if (Array.isArray(value)) {
1497
+ return value.join(' ');
1498
+ }
1499
+ // Handle objects (e.g., for gradients or transforms)
1500
+ if (typeof value === 'object') {
1501
+ return JSON.stringify(value);
1502
+ }
1503
+ return value;
1305
1504
  };
1505
+ // Export the set of valid style properties
1506
+ const StyleProps = /*#__PURE__*/Array.from(cssProperties);
1306
1507
 
1307
1508
  /* eslint-disable @typescript-eslint/no-unused-vars */
1308
1509
  let keyframesCounter = 0;
@@ -1447,6 +1648,19 @@ const needsVendorPrefix = property => {
1447
1648
  return property in vendorPrefixedProperties;
1448
1649
  };
1449
1650
 
1651
+ /**
1652
+ * Simple, fast hash function (djb2) for generating deterministic class names.
1653
+ */
1654
+ function hash(str) {
1655
+ let hash = 5381;
1656
+ let i = str.length;
1657
+ while (i) {
1658
+ hash = hash * 33 ^ str.charCodeAt(--i);
1659
+ }
1660
+ // Convert to unsigned 32-bit integer and then to base 36 string
1661
+ return (hash >>> 0).toString(36);
1662
+ }
1663
+
1450
1664
  /* eslint-disable @typescript-eslint/no-unused-vars */
1451
1665
  // Implement a simple LRU cache for classCache
1452
1666
  class LRUCache {
@@ -1540,7 +1754,18 @@ const EVENT_TO_PSEUDO = {
1540
1754
  firstLine: 'first-line',
1541
1755
  selection: 'selection',
1542
1756
  backdrop: 'backdrop',
1543
- marker: 'marker'
1757
+ marker: 'marker',
1758
+ // Group modifiers
1759
+ groupHover: 'group-hover',
1760
+ groupFocus: 'group-focus',
1761
+ groupActive: 'group-active',
1762
+ groupDisabled: 'group-disabled',
1763
+ // Peer modifiers
1764
+ peerHover: 'peer-hover',
1765
+ peerFocus: 'peer-focus',
1766
+ peerActive: 'peer-active',
1767
+ peerDisabled: 'peer-disabled',
1768
+ peerChecked: 'peer-checked'
1544
1769
  };
1545
1770
  /**
1546
1771
  * Utility functions for animation handling
@@ -1559,7 +1784,7 @@ const AnimationUtils = {
1559
1784
  }
1560
1785
  return `${ms}ms`;
1561
1786
  },
1562
- processAnimations(animations) {
1787
+ processAnimations(animations, manager) {
1563
1788
  const result = {
1564
1789
  names: [],
1565
1790
  durations: [],
@@ -1578,8 +1803,9 @@ const AnimationUtils = {
1578
1803
  keyframesName,
1579
1804
  keyframes
1580
1805
  } = generateKeyframes(animation);
1581
- if (keyframes && typeof document !== 'undefined') {
1582
- utilityClassManager.injectRule(keyframes);
1806
+ if (keyframes) {
1807
+ // Use provided manager or fall back to global
1808
+ (manager || utilityClassManager).injectRule(keyframes);
1583
1809
  }
1584
1810
  result.names.push(keyframesName);
1585
1811
  const durationMs = this.parseDuration(animation.duration || '0s');
@@ -1619,67 +1845,8 @@ const AnimationUtils = {
1619
1845
  */
1620
1846
  const ValueUtils = {
1621
1847
  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;
1848
+ // Use the shared processStyleProperty function which now contains the robust regex logic
1849
+ return processStyleProperty(property, value, getColor);
1683
1850
  },
1684
1851
  normalizeCssValue(value) {
1685
1852
  // Handle CSS variables in values
@@ -1701,7 +1868,7 @@ const ValueUtils = {
1701
1868
  if (rawCssCache.has(css)) {
1702
1869
  return rawCssCache.get(css);
1703
1870
  }
1704
- const shortName = Math.random().toString(36).substring(7);
1871
+ const shortName = hash(css);
1705
1872
  const newClassName = `raw-css-${shortName}`;
1706
1873
  rawCssCache.set(css, newClassName);
1707
1874
  return newClassName;
@@ -1714,6 +1881,7 @@ class UtilityClassManager {
1714
1881
  }
1715
1882
  this.styleSheets = new Map();
1716
1883
  this.mainDocument = null;
1884
+ this.serverRules = new Map();
1717
1885
  this.propertyShorthand = propertyShorthand;
1718
1886
  this.classCache = new LRUCache(maxCacheSize);
1719
1887
  if (typeof document !== 'undefined') {
@@ -1788,9 +1956,14 @@ class UtilityClassManager {
1788
1956
  if (context === void 0) {
1789
1957
  context = 'base';
1790
1958
  }
1791
- // Inject to main document
1959
+ // Inject to main document or cache for server
1792
1960
  if (this.mainDocument) {
1793
1961
  this.injectRuleToDocument(cssRule, context, this.mainDocument);
1962
+ } else {
1963
+ if (!this.serverRules.has(context)) {
1964
+ this.serverRules.set(context, []);
1965
+ }
1966
+ this.serverRules.get(context)?.push(cssRule);
1794
1967
  }
1795
1968
  // Inject to all other documents
1796
1969
  for (const document of this.getAllRegisteredDocuments()) {
@@ -1799,6 +1972,17 @@ class UtilityClassManager {
1799
1972
  }
1800
1973
  }
1801
1974
  }
1975
+ getServerStyles() {
1976
+ const contexts = ['base', 'pseudo', 'media', 'modifier'];
1977
+ let css = '';
1978
+ contexts.forEach(context => {
1979
+ const rules = this.serverRules.get(context);
1980
+ if (rules) {
1981
+ css += rules.join('\n') + '\n';
1982
+ }
1983
+ });
1984
+ return css;
1985
+ }
1802
1986
  getAllRegisteredDocuments() {
1803
1987
  return Array.from(this.styleSheets.keys());
1804
1988
  }
@@ -1863,13 +2047,32 @@ class UtilityClassManager {
1863
2047
  const pseudoClassName = `${baseClassName}--${modifier}`;
1864
2048
  classNames = [pseudoClassName];
1865
2049
  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'
2050
+ // Format CSS rules for group and peer modifiers
2051
+ if (modifier.startsWith('group-')) {
2052
+ const groupState = modifier.replace('group-', '');
2053
+ cssProperties.forEach(prefixedProperty => {
2054
+ rules.push({
2055
+ rule: `.group:${groupState} .${escapedClassName} { ${prefixedProperty}: ${valueForCss}; }`,
2056
+ context: 'pseudo'
2057
+ });
1871
2058
  });
1872
- });
2059
+ } else if (modifier.startsWith('peer-')) {
2060
+ const peerState = modifier.replace('peer-', '');
2061
+ cssProperties.forEach(prefixedProperty => {
2062
+ rules.push({
2063
+ rule: `.peer:${peerState} ~ .${escapedClassName} { ${prefixedProperty}: ${valueForCss}; }`,
2064
+ context: 'pseudo'
2065
+ });
2066
+ });
2067
+ } else {
2068
+ // Standard pseudo-class
2069
+ cssProperties.forEach(prefixedProperty => {
2070
+ rules.push({
2071
+ rule: `.${escapedClassName}:${modifier} { ${prefixedProperty}: ${valueForCss}; }`,
2072
+ context: 'pseudo'
2073
+ });
2074
+ });
2075
+ }
1873
2076
  } else if (context === 'media' && modifier) {
1874
2077
  const mediaClassName = `${modifier}--${baseClassName}`;
1875
2078
  classNames = [mediaClassName];
@@ -2007,7 +2210,7 @@ const utilityClassManager = /*#__PURE__*/new UtilityClassManager(propertyShortha
2007
2210
  /**
2008
2211
  * Process styles for various contexts (base, pseudo, media)
2009
2212
  */
2010
- function processStyles(styles, context, modifier, getColor, mediaQueries, devices) {
2213
+ function processStyles(styles, context, modifier, getColor, mediaQueries, devices, manager) {
2011
2214
  if (context === void 0) {
2012
2215
  context = 'base';
2013
2216
  }
@@ -2032,14 +2235,14 @@ function processStyles(styles, context, modifier, getColor, mediaQueries, device
2032
2235
  }
2033
2236
  }
2034
2237
  if (value !== undefined && value !== '') {
2035
- const classNames = utilityClassManager.getClassNames(property, value, context, modifier, getColor, mediaQueriesForClass);
2238
+ const classNames = (manager || utilityClassManager).getClassNames(property, value, context, modifier, getColor, mediaQueriesForClass);
2036
2239
  classes.push(...classNames);
2037
2240
  }
2038
2241
  });
2039
2242
  return classes;
2040
2243
  }
2041
2244
  // Add a function to handle nested pseudo-classes
2042
- function processPseudoStyles(styles, parentPseudo, getColor) {
2245
+ function processPseudoStyles(styles, parentPseudo, getColor, manager) {
2043
2246
  if (parentPseudo === void 0) {
2044
2247
  parentPseudo = '';
2045
2248
  }
@@ -2055,7 +2258,7 @@ function processPseudoStyles(styles, parentPseudo, getColor) {
2055
2258
  // Construct the combined pseudo selector
2056
2259
  const combinedPseudo = parentPseudo ? `${parentPseudo}::${pseudo}` : `${pseudo}`;
2057
2260
  // Process the nested styles with the combined pseudo
2058
- classes.push(...processPseudoStyles(value, combinedPseudo, getColor));
2261
+ classes.push(...processPseudoStyles(value, combinedPseudo, getColor, manager));
2059
2262
  }
2060
2263
  } else if (typeof value !== 'object' || value === null) {
2061
2264
  // This is a regular CSS property
@@ -2067,7 +2270,7 @@ function processPseudoStyles(styles, parentPseudo, getColor) {
2067
2270
  const processedValue = ValueUtils.formatValue(value, key, getColor);
2068
2271
  // Create and inject the rule
2069
2272
  const rule = `.${escapedClassName}::${parentPseudo} { ${propertyToKebabCase(key)}: ${processedValue}; }`;
2070
- utilityClassManager.injectRule(rule, 'pseudo');
2273
+ (manager || utilityClassManager).injectRule(rule, 'pseudo');
2071
2274
  classes.push(escapedClassName);
2072
2275
  }
2073
2276
  }
@@ -2077,7 +2280,7 @@ function processPseudoStyles(styles, parentPseudo, getColor) {
2077
2280
  /**
2078
2281
  * Process event-based styles (hover, focus, etc.)
2079
2282
  */
2080
- function processEventStyles(eventName, eventStyles, getColor) {
2283
+ function processEventStyles(eventName, eventStyles, getColor, manager) {
2081
2284
  const classes = [];
2082
2285
  // Handle string shorthand (e.g., _hover: "color.red.500")
2083
2286
  if (typeof eventStyles === 'string') {
@@ -2097,7 +2300,7 @@ function processEventStyles(eventName, eventStyles, getColor) {
2097
2300
  // Process animations if present
2098
2301
  if (animate) {
2099
2302
  const animations = Array.isArray(animate) ? animate : [animate];
2100
- const animationStyles = AnimationUtils.processAnimations(animations);
2303
+ const animationStyles = AnimationUtils.processAnimations(animations, manager);
2101
2304
  Object.assign(otherEventStyles, animationStyles);
2102
2305
  }
2103
2306
  // Process shadow if present
@@ -2133,7 +2336,7 @@ function processEventStyles(eventName, eventStyles, getColor) {
2133
2336
  const nestedPseudo = EVENT_TO_PSEUDO[nestedPseudoName];
2134
2337
  if (nestedPseudo) {
2135
2338
  const combinedPseudo = `${pseudo}::${nestedPseudo}`;
2136
- classes.push(...processPseudoStyles(otherEventStyles[nestedKey], combinedPseudo, getColor));
2339
+ classes.push(...processPseudoStyles(otherEventStyles[nestedKey], combinedPseudo, getColor, manager));
2137
2340
  }
2138
2341
  });
2139
2342
  // Remove processed nested pseudos
@@ -2146,12 +2349,12 @@ function processEventStyles(eventName, eventStyles, getColor) {
2146
2349
  if (Object.keys(otherEventStyles).length > 0) {
2147
2350
  const pseudo = EVENT_TO_PSEUDO[eventName];
2148
2351
  if (pseudo) {
2149
- classes.push(...processStyles(otherEventStyles, 'pseudo', pseudo, getColor));
2352
+ classes.push(...processStyles(otherEventStyles, 'pseudo', pseudo, getColor, {}, {}, manager));
2150
2353
  }
2151
2354
  }
2152
2355
  return classes;
2153
2356
  }
2154
- const extractUtilityClasses = (props, getColor, mediaQueries, devices) => {
2357
+ const extractUtilityClasses = (props, getColor, mediaQueries, devices, manager) => {
2155
2358
  const classes = [];
2156
2359
  const computedStyles = {};
2157
2360
  // Handle widthHeight (shorthand for both width and height)
@@ -2202,9 +2405,9 @@ const extractUtilityClasses = (props, getColor, mediaQueries, devices) => {
2202
2405
  // Handle animations
2203
2406
  if (props.animate) {
2204
2407
  const animations = Array.isArray(props.animate) ? props.animate : [props.animate];
2205
- Object.assign(computedStyles, AnimationUtils.processAnimations(animations));
2408
+ Object.assign(computedStyles, AnimationUtils.processAnimations(animations, manager));
2206
2409
  }
2207
- const blendConfig = props?.theme?.blend || {
2410
+ const blendConfig = {
2208
2411
  mode: 'difference',
2209
2412
  color: 'white',
2210
2413
  modeWithBg: 'overlay'
@@ -2219,7 +2422,7 @@ const extractUtilityClasses = (props, getColor, mediaQueries, devices) => {
2219
2422
  }
2220
2423
  };
2221
2424
  // Handle default blend
2222
- if (props.blend !== false && props.color === undefined && computedStyles.color === undefined && typeof props.children === 'string') {
2425
+ if (props.blend === true) {
2223
2426
  setBlend(props, computedStyles);
2224
2427
  Object.keys(props).forEach(property => {
2225
2428
  if (props[property]?.color === undefined && property.startsWith('_') && property.length > 1) {
@@ -2228,7 +2431,7 @@ const extractUtilityClasses = (props, getColor, mediaQueries, devices) => {
2228
2431
  });
2229
2432
  }
2230
2433
  // Process base styles
2231
- classes.push(...processStyles(computedStyles, 'base', '', getColor));
2434
+ classes.push(...processStyles(computedStyles, 'base', '', getColor, {}, {}, manager));
2232
2435
  // Collect underscore-prefixed properties (_hover, _focus, etc.)
2233
2436
  const underscoreProps = {};
2234
2437
  Object.keys(props).forEach(property => {
@@ -2245,17 +2448,17 @@ const extractUtilityClasses = (props, getColor, mediaQueries, devices) => {
2245
2448
  if (property === 'on') {
2246
2449
  // Process event-based styles
2247
2450
  Object.keys(value).forEach(event => {
2248
- classes.push(...processEventStyles(event, value[event], getColor));
2451
+ classes.push(...processEventStyles(event, value[event], getColor, manager));
2249
2452
  });
2250
2453
  } else if (property === 'media') {
2251
2454
  // Process media query styles
2252
2455
  Object.keys(value).forEach(screenOrDevice => {
2253
- classes.push(...processStyles(value[screenOrDevice], 'media', screenOrDevice, getColor, mediaQueries, devices));
2456
+ classes.push(...processStyles(value[screenOrDevice], 'media', screenOrDevice, getColor, mediaQueries, devices, manager));
2254
2457
  });
2255
2458
  }
2256
2459
  } else if (value !== undefined && value !== '') {
2257
2460
  // Direct style property
2258
- classes.push(...utilityClassManager.getClassNames(property, value, 'base', '', getColor, []));
2461
+ classes.push(...(manager || utilityClassManager).getClassNames(property, value, 'base', '', getColor, []));
2259
2462
  }
2260
2463
  }
2261
2464
  });
@@ -2264,23 +2467,69 @@ const extractUtilityClasses = (props, getColor, mediaQueries, devices) => {
2264
2467
  if (typeof props.css === 'object') {
2265
2468
  // Object-style CSS gets processed as regular styles
2266
2469
  Object.assign(computedStyles, props.css);
2267
- classes.push(...processStyles(props.css, 'base', '', getColor));
2470
+ classes.push(...processStyles(props.css, 'base', '', getColor, {}, {}, manager));
2268
2471
  } else if (typeof props.css === 'string') {
2269
2472
  // String-style CSS gets its own class
2270
2473
  const uniqueClassName = ValueUtils.generateUniqueClassName(props.css);
2271
- utilityClassManager.injectRule(`.${uniqueClassName} { ${props.css} }`);
2474
+ (manager || utilityClassManager).injectRule(`.${uniqueClassName} { ${props.css} }`);
2272
2475
  classes.push(uniqueClassName);
2273
2476
  }
2274
2477
  }
2275
2478
  // Process underscore-prefixed event properties
2276
2479
  if (Object.keys(underscoreProps).length > 0) {
2277
2480
  Object.keys(underscoreProps).forEach(event => {
2278
- classes.push(...processEventStyles(event, underscoreProps[event], getColor));
2481
+ classes.push(...processEventStyles(event, underscoreProps[event], getColor, manager));
2279
2482
  });
2280
2483
  }
2281
2484
  return classes;
2282
2485
  };
2283
2486
 
2487
+ const StyleRegistryContext = /*#__PURE__*/React.createContext({
2488
+ manager: utilityClassManager
2489
+ });
2490
+ /**
2491
+ * Hook to access the current style manager.
2492
+ */
2493
+ const useStyleRegistry = () => React.useContext(StyleRegistryContext);
2494
+ /**
2495
+ * Provider to wrap the app and manage styles.
2496
+ * When doing SSR, pass a new registry created via createStyleRegistry().
2497
+ */
2498
+ const StyleRegistry = _ref => {
2499
+ let {
2500
+ registry,
2501
+ children
2502
+ } = _ref;
2503
+ const value = React.useMemo(() => ({
2504
+ // If no registry provided, fallback to globalManager
2505
+ manager: registry || utilityClassManager
2506
+ }), [registry]);
2507
+ return /*#__PURE__*/React__default.createElement(StyleRegistryContext.Provider, {
2508
+ value: value
2509
+ }, children);
2510
+ };
2511
+ /**
2512
+ * Helper to create a new style registry (UtilityClassManager) instance.
2513
+ * Useful for SSR to create a fresh manager per request.
2514
+ */
2515
+ const createStyleRegistry = () => {
2516
+ return new UtilityClassManager(propertyShorthand, 10000);
2517
+ };
2518
+ /**
2519
+ * React hook to get the CSS string from the registry.
2520
+ * Note: This only works if you're using a fresh registry that collected styles.
2521
+ */
2522
+ const useServerInsertedHTML = registry => {
2523
+ return () => {
2524
+ return /*#__PURE__*/React__default.createElement("style", {
2525
+ id: "app-studio-server-css",
2526
+ dangerouslySetInnerHTML: {
2527
+ __html: registry.getServerStyles()
2528
+ }
2529
+ });
2530
+ };
2531
+ };
2532
+
2284
2533
  // analytics/AnalyticsContext.tsx
2285
2534
  // Create the context with a default no-op implementation
2286
2535
  const AnalyticsContext = /*#__PURE__*/React.createContext({});
@@ -2309,10 +2558,14 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
2309
2558
  }
2310
2559
  const {
2311
2560
  onPress,
2312
- blend,
2561
+ blend: initialBlend,
2313
2562
  animateOn = 'Both',
2314
2563
  ...rest
2315
2564
  } = props;
2565
+ let blend = initialBlend;
2566
+ if (blend !== false && props.color === undefined && typeof props.children === 'string' && (as === 'span' || as === 'div' || blend === true)) {
2567
+ blend = true;
2568
+ }
2316
2569
  const elementRef = React.useRef(null);
2317
2570
  const setRef = React.useCallback(node => {
2318
2571
  elementRef.current = node;
@@ -2333,6 +2586,9 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
2333
2586
  mediaQueries,
2334
2587
  devices
2335
2588
  } = useResponsiveContext();
2589
+ const {
2590
+ manager
2591
+ } = useStyleRegistry();
2336
2592
  const [isVisible, setIsVisible] = React.useState(false);
2337
2593
  React.useEffect(() => {
2338
2594
  if (!animateIn) {
@@ -2360,25 +2616,24 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
2360
2616
  React.useEffect(() => {
2361
2617
  if (animateIn && elementRef.current && isVisible) {
2362
2618
  const animations = Array.isArray(animateIn) ? animateIn : [animateIn];
2363
- const styles = AnimationUtils.processAnimations(animations);
2619
+ const styles = AnimationUtils.processAnimations(animations, manager);
2364
2620
  Object.assign(elementRef.current.style, styles);
2365
2621
  }
2366
- }, [animateIn, isVisible]);
2622
+ }, [animateIn, isVisible, manager]);
2367
2623
  React.useEffect(() => {
2368
2624
  const node = elementRef.current;
2369
2625
  return () => {
2370
2626
  if (animateOut && node) {
2371
2627
  const animations = Array.isArray(animateOut) ? animateOut : [animateOut];
2372
- const styles = AnimationUtils.processAnimations(animations);
2628
+ const styles = AnimationUtils.processAnimations(animations, manager);
2373
2629
  Object.assign(node.style, styles);
2374
2630
  }
2375
2631
  };
2376
- }, [animateOut]);
2632
+ }, [animateOut, manager]);
2377
2633
  const utilityClasses = React.useMemo(() => {
2378
2634
  const propsToProcess = {
2379
2635
  ...rest,
2380
- blend,
2381
- theme: props.theme || theme
2636
+ blend
2382
2637
  };
2383
2638
  // Apply view() timeline ONLY if animateOn='View' (not Both or Mount)
2384
2639
  if (animateOn === 'View' && propsToProcess.animate) {
@@ -2396,14 +2651,25 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
2396
2651
  return anim;
2397
2652
  });
2398
2653
  }
2399
- return extractUtilityClasses(propsToProcess, color => {
2400
- return getColor(color, {
2401
- colors: props.colors,
2402
- theme: props.theme,
2403
- themeMode: props.themeMode
2654
+ // Apply scroll() timeline if animateOn='Scroll'
2655
+ if (animateOn === 'Scroll' && propsToProcess.animate) {
2656
+ const animations = Array.isArray(propsToProcess.animate) ? propsToProcess.animate : [propsToProcess.animate];
2657
+ propsToProcess.animate = animations.map(anim => {
2658
+ // Only add timeline if not already specified
2659
+ if (!anim.timeline) {
2660
+ return {
2661
+ ...anim,
2662
+ timeline: 'scroll()',
2663
+ fillMode: anim.fillMode || 'both'
2664
+ };
2665
+ }
2666
+ return anim;
2404
2667
  });
2405
- }, mediaQueries, devices);
2406
- }, [rest, blend, animateOn, mediaQueries, devices, theme]);
2668
+ }
2669
+ return extractUtilityClasses(propsToProcess, color => {
2670
+ return getColor(color);
2671
+ }, mediaQueries, devices, manager);
2672
+ }, [rest, blend, animateOn, mediaQueries, devices, theme, manager]);
2407
2673
  const newProps = {
2408
2674
  ref: setRef
2409
2675
  };
@@ -2413,6 +2679,9 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
2413
2679
  if (utilityClasses.length > 0) {
2414
2680
  newProps.className = utilityClasses.join(' ');
2415
2681
  }
2682
+ if (props.className) {
2683
+ newProps.className = newProps.className ? `${newProps.className} ${props.className}` : props.className;
2684
+ }
2416
2685
  // Handle event tracking for onClick
2417
2686
  if (trackEvent && props.onClick) {
2418
2687
  let componentName;
@@ -2468,7 +2737,7 @@ const Element = /*#__PURE__*/React__default.memo(/*#__PURE__*/React.forwardRef((
2468
2737
  };
2469
2738
  }
2470
2739
  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));
2740
+ return children ? (/*#__PURE__*/React__default.createElement(Component, Object.assign({}, newProps), before, children, after)) : (/*#__PURE__*/React__default.createElement(Component, Object.assign({}, newProps)));
2472
2741
  }));
2473
2742
 
2474
2743
  const View = /*#__PURE__*/React__default.forwardRef((props, ref) => (/*#__PURE__*/React__default.createElement(Element, Object.assign({}, props, {
@@ -2502,7 +2771,7 @@ const HorizontalResponsive = /*#__PURE__*/React__default.forwardRef((_ref, ref)
2502
2771
  media: {
2503
2772
  ...media,
2504
2773
  mobile: {
2505
- ...media.mobile,
2774
+ ...media?.mobile,
2506
2775
  flexDirection: 'column'
2507
2776
  }
2508
2777
  }
@@ -2519,7 +2788,7 @@ const VerticalResponsive = /*#__PURE__*/React__default.forwardRef((_ref2, ref) =
2519
2788
  media: {
2520
2789
  ...media,
2521
2790
  mobile: {
2522
- ...media.mobile,
2791
+ ...media?.mobile,
2523
2792
  flexDirection: 'row'
2524
2793
  }
2525
2794
  }
@@ -2563,38 +2832,6 @@ const ImageBackground = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
2563
2832
  }));
2564
2833
  });
2565
2834
 
2566
- const normalizeHexColor = backgroundColor => {
2567
- if (!backgroundColor) {
2568
- return null;
2569
- }
2570
- const trimmed = backgroundColor.trim();
2571
- const withoutHash = trimmed.startsWith('#') ? trimmed.slice(1) : trimmed;
2572
- if (withoutHash.length === 3) {
2573
- if (!/^[0-9a-fA-F]{3}$/.test(withoutHash)) {
2574
- return null;
2575
- }
2576
- return `#${withoutHash.split('').map(char => char + char).join('')}`;
2577
- }
2578
- if (!/^[0-9a-fA-F]{6}$/.test(withoutHash)) {
2579
- return null;
2580
- }
2581
- return `#${withoutHash.toLowerCase()}`;
2582
- };
2583
- const getTextColorHex = backgroundColor => {
2584
- const normalized = normalizeHexColor(backgroundColor);
2585
- if (!normalized) {
2586
- return 'black';
2587
- }
2588
- // Simple luminance calculation to determine text color contrast
2589
- const color = normalized.replace('#', '');
2590
- const r = parseInt(color.substring(0, 2), 16);
2591
- const g = parseInt(color.substring(2, 4), 16);
2592
- const b = parseInt(color.substring(4, 6), 16);
2593
- const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
2594
- return luminance > 0.5 ? 'black' : 'white';
2595
- };
2596
- const getTextColor = backgroundColor => getTextColorHex(backgroundColor);
2597
-
2598
2835
  /**
2599
2836
  * Text View Component
2600
2837
  *
@@ -2614,21 +2851,15 @@ const TextView = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
2614
2851
  isSup = false,
2615
2852
  isStriked = false,
2616
2853
  bgColor,
2617
- backgroundColor: backgroundColorProp,
2618
- color,
2619
2854
  views,
2620
- blend,
2621
2855
  style,
2622
2856
  ...props
2623
2857
  } = _ref;
2858
+ console.log('props', props, children);
2624
2859
  // For sub/sup text, use inline display
2625
2860
  const noLineBreak = isSub || isSup ? {
2626
2861
  display: 'inline'
2627
2862
  } : {};
2628
- //
2629
- const containerBackgroundColor = views?.container?.backgroundColor;
2630
- const effectiveBackgroundColor = bgColor ?? backgroundColorProp ?? containerBackgroundColor;
2631
- const computedColor = color ?? (effectiveBackgroundColor ? getTextColor(effectiveBackgroundColor) : undefined);
2632
2863
  const finalChildren = toUpperCase ? React__default.Children.map(children, child => typeof child === 'string' ? child.toUpperCase() : child) : children;
2633
2864
  const styles = {
2634
2865
  ...style,
@@ -2644,9 +2875,6 @@ const TextView = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
2644
2875
  as: isSub ? 'sub' : isSup ? 'sup' : 'span',
2645
2876
  fontStyle: isItalic ? 'italic' : 'normal',
2646
2877
  textDecoration: isStriked ? 'line-through' : isUnderlined ? 'underline' : 'none',
2647
- color: computedColor,
2648
- blend,
2649
- backgroundColor: effectiveBackgroundColor,
2650
2878
  style: styles,
2651
2879
  ...noLineBreak,
2652
2880
  ...props,
@@ -2663,6 +2891,7 @@ const TextView = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
2663
2891
  top: isSup ? '-0.5em' : undefined
2664
2892
  }, views?.sup), finalChildren);
2665
2893
  }
2894
+ console.log('commonProps', commonProps, children);
2666
2895
  return /*#__PURE__*/React__default.createElement(Element, Object.assign({}, commonProps, {
2667
2896
  ref: ref
2668
2897
  }), finalChildren);
@@ -5518,16 +5747,19 @@ exports.Scroll = Scroll;
5518
5747
  exports.Shadows = Shadows;
5519
5748
  exports.Skeleton = Skeleton;
5520
5749
  exports.Span = Span;
5750
+ exports.StyleRegistry = StyleRegistry;
5521
5751
  exports.Text = Text;
5522
5752
  exports.ThemeContext = ThemeContext;
5523
5753
  exports.ThemeProvider = ThemeProvider;
5524
5754
  exports.Typography = Typography;
5755
+ exports.UtilityClassManager = UtilityClassManager;
5525
5756
  exports.Vertical = Vertical;
5526
5757
  exports.VerticalResponsive = VerticalResponsive;
5527
5758
  exports.View = View;
5528
5759
  exports.animateOnView = animateOnView;
5529
5760
  exports.blurInOnView = blurInOnView;
5530
5761
  exports.blurOutOnView = blurOutOnView;
5762
+ exports.createStyleRegistry = createStyleRegistry;
5531
5763
  exports.createViewAnimation = createViewAnimation;
5532
5764
  exports.debounce = debounce;
5533
5765
  exports.deepMerge = deepMerge;
@@ -5543,11 +5775,14 @@ exports.fadeOutOnView = fadeOutOnView;
5543
5775
  exports.flipXOnView = flipXOnView;
5544
5776
  exports.flipYOnView = flipYOnView;
5545
5777
  exports.getWindowInitialProps = getWindowInitialProps;
5778
+ exports.hasColorToken = hasColorToken;
5546
5779
  exports.isBrowser = isBrowser;
5547
5780
  exports.isDev = isDev;
5548
5781
  exports.isMobile = isMobile;
5549
5782
  exports.isProd = isProd;
5550
5783
  exports.isSSR = isSSR;
5784
+ exports.propertyShorthand = propertyShorthand;
5785
+ exports.replaceColorTokens = replaceColorTokens;
5551
5786
  exports.revealOnView = revealOnView;
5552
5787
  exports.rotateInOnView = rotateInOnView;
5553
5788
  exports.scaleDownOnView = scaleDownOnView;
@@ -5572,7 +5807,9 @@ exports.useResponsiveContext = useResponsiveContext;
5572
5807
  exports.useScroll = useScroll;
5573
5808
  exports.useScrollAnimation = useScrollAnimation;
5574
5809
  exports.useScrollDirection = useScrollDirection;
5810
+ exports.useServerInsertedHTML = useServerInsertedHTML;
5575
5811
  exports.useSmoothScroll = useSmoothScroll;
5812
+ exports.useStyleRegistry = useStyleRegistry;
5576
5813
  exports.useTheme = useTheme;
5577
5814
  exports.useWindowSize = useWindowSize;
5578
5815
  exports.utilityClassManager = utilityClassManager;