@idealyst/components 1.1.7 → 1.1.9

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 (129) hide show
  1. package/package.json +3 -3
  2. package/plugin/web.js +280 -532
  3. package/src/Accordion/Accordion.native.tsx +8 -6
  4. package/src/Accordion/Accordion.styles.old.tsx +298 -0
  5. package/src/Accordion/Accordion.styles.tsx +102 -236
  6. package/src/Accordion/Accordion.web.tsx +1 -3
  7. package/src/ActivityIndicator/ActivityIndicator.styles.old.tsx +94 -0
  8. package/src/ActivityIndicator/ActivityIndicator.styles.tsx +44 -74
  9. package/src/Alert/Alert.native.tsx +16 -6
  10. package/src/Alert/Alert.styles.old.tsx +209 -0
  11. package/src/Alert/Alert.styles.tsx +67 -149
  12. package/src/Alert/Alert.web.tsx +3 -4
  13. package/src/Avatar/Avatar.styles.old.tsx +99 -0
  14. package/src/Avatar/Avatar.styles.tsx +35 -80
  15. package/src/Badge/Badge.styles.old.tsx +157 -0
  16. package/src/Badge/Badge.styles.tsx +61 -121
  17. package/src/Badge/Badge.web.tsx +8 -15
  18. package/src/Breadcrumb/Breadcrumb.styles.old.tsx +231 -0
  19. package/src/Breadcrumb/Breadcrumb.styles.tsx +83 -200
  20. package/src/Breadcrumb/Breadcrumb.web.tsx +31 -30
  21. package/src/Button/Button.native.tsx +14 -21
  22. package/src/Button/Button.styles.tsx +103 -140
  23. package/src/Button/Button.web.tsx +9 -19
  24. package/src/Card/Card.native.tsx +7 -11
  25. package/src/Card/Card.styles.old.tsx +160 -0
  26. package/src/Card/Card.styles.tsx +105 -142
  27. package/src/Card/Card.web.tsx +5 -4
  28. package/src/Checkbox/Checkbox.native.tsx +9 -5
  29. package/src/Checkbox/Checkbox.styles.old.tsx +271 -0
  30. package/src/Checkbox/Checkbox.styles.tsx +104 -216
  31. package/src/Checkbox/Checkbox.web.tsx +7 -8
  32. package/src/Chip/Chip.styles.old.tsx +184 -0
  33. package/src/Chip/Chip.styles.tsx +34 -72
  34. package/src/Chip/Chip.web.tsx +3 -5
  35. package/src/Dialog/Dialog.native.tsx +7 -4
  36. package/src/Dialog/Dialog.styles.old.tsx +202 -0
  37. package/src/Dialog/Dialog.styles.tsx +69 -133
  38. package/src/Dialog/Dialog.web.tsx +3 -3
  39. package/src/Dialog/types.ts +1 -1
  40. package/src/Divider/Divider.styles.old.tsx +172 -0
  41. package/src/Divider/Divider.styles.tsx +62 -84
  42. package/src/Icon/Icon.native.tsx +8 -8
  43. package/src/Icon/Icon.styles.old.tsx +81 -0
  44. package/src/Icon/Icon.styles.tsx +52 -66
  45. package/src/Icon/Icon.web.tsx +62 -21
  46. package/src/Icon/IconRegistry.native.ts +41 -0
  47. package/src/Icon/IconRegistry.ts +107 -0
  48. package/src/Icon/IconSvg/IconSvg.web.tsx +28 -5
  49. package/src/Icon/icon-resolver.ts +12 -43
  50. package/src/Icon/index.native.ts +2 -1
  51. package/src/Icon/index.ts +1 -0
  52. package/src/Icon/index.web.ts +1 -0
  53. package/src/Image/Image.styles.old.tsx +69 -0
  54. package/src/Image/Image.styles.tsx +46 -60
  55. package/src/Input/Input.native.tsx +138 -53
  56. package/src/Input/Input.styles.old.tsx +289 -0
  57. package/src/Input/Input.styles.tsx +134 -232
  58. package/src/Input/Input.web.tsx +5 -8
  59. package/src/List/List.native.tsx +5 -2
  60. package/src/List/List.styles.old.tsx +242 -0
  61. package/src/List/List.styles.tsx +179 -215
  62. package/src/List/ListItem.native.tsx +16 -11
  63. package/src/List/ListItem.web.tsx +26 -16
  64. package/src/Menu/Menu.styles.old.tsx +197 -0
  65. package/src/Menu/Menu.styles.tsx +68 -150
  66. package/src/Menu/MenuItem.native.tsx +5 -3
  67. package/src/Menu/MenuItem.styles.old.tsx +114 -0
  68. package/src/Menu/MenuItem.styles.tsx +57 -89
  69. package/src/Menu/MenuItem.web.tsx +10 -7
  70. package/src/Popover/Popover.native.tsx +10 -4
  71. package/src/Popover/Popover.styles.old.tsx +135 -0
  72. package/src/Popover/Popover.styles.tsx +51 -112
  73. package/src/Pressable/Pressable.styles.old.tsx +27 -0
  74. package/src/Pressable/Pressable.styles.tsx +35 -27
  75. package/src/Progress/Progress.styles.old.tsx +200 -0
  76. package/src/Progress/Progress.styles.tsx +75 -164
  77. package/src/RadioButton/RadioButton.native.tsx +4 -3
  78. package/src/RadioButton/RadioButton.styles.old.tsx +175 -0
  79. package/src/RadioButton/RadioButton.styles.tsx +83 -154
  80. package/src/RadioButton/RadioButton.web.tsx +2 -2
  81. package/src/SVGImage/SVGImage.styles.old.tsx +86 -0
  82. package/src/SVGImage/SVGImage.styles.tsx +35 -78
  83. package/src/Screen/Screen.native.tsx +19 -26
  84. package/src/Screen/Screen.styles.old.tsx +87 -0
  85. package/src/Screen/Screen.styles.tsx +103 -68
  86. package/src/Screen/Screen.web.tsx +2 -2
  87. package/src/Select/Select.native.tsx +42 -33
  88. package/src/Select/Select.styles.old.tsx +353 -0
  89. package/src/Select/Select.styles.tsx +214 -300
  90. package/src/Select/Select.web.tsx +45 -33
  91. package/src/Skeleton/Skeleton.styles.old.tsx +67 -0
  92. package/src/Skeleton/Skeleton.styles.tsx +29 -53
  93. package/src/Slider/Slider.styles.old.tsx +259 -0
  94. package/src/Slider/Slider.styles.tsx +153 -234
  95. package/src/Slider/Slider.web.tsx +2 -4
  96. package/src/Switch/Switch.native.tsx +9 -7
  97. package/src/Switch/Switch.styles.old.tsx +203 -0
  98. package/src/Switch/Switch.styles.tsx +101 -174
  99. package/src/Switch/Switch.web.tsx +7 -8
  100. package/src/TabBar/TabBar.native.tsx +3 -2
  101. package/src/TabBar/TabBar.styles.old.tsx +343 -0
  102. package/src/TabBar/TabBar.styles.tsx +145 -279
  103. package/src/Table/Table.native.tsx +180 -68
  104. package/src/Table/Table.styles.old.tsx +311 -0
  105. package/src/Table/Table.styles.tsx +140 -281
  106. package/src/Table/Table.web.tsx +169 -70
  107. package/src/Text/Text.native.tsx +1 -3
  108. package/src/Text/Text.style.demo.tsx +16 -0
  109. package/src/Text/Text.styles.old.tsx +219 -0
  110. package/src/Text/Text.styles.tsx +94 -84
  111. package/src/Text/Text.web.tsx +3 -2
  112. package/src/Text/index.ts +1 -0
  113. package/src/TextArea/TextArea.native.tsx +21 -8
  114. package/src/TextArea/TextArea.styles.old.tsx +213 -0
  115. package/src/TextArea/TextArea.styles.tsx +87 -187
  116. package/src/TextArea/TextArea.web.tsx +17 -6
  117. package/src/Tooltip/Tooltip.styles.old.tsx +82 -0
  118. package/src/Tooltip/Tooltip.styles.tsx +32 -56
  119. package/src/Video/Video.styles.old.tsx +51 -0
  120. package/src/Video/Video.styles.tsx +32 -44
  121. package/src/View/View.native.tsx +41 -13
  122. package/src/View/View.styles.old.tsx +125 -0
  123. package/src/View/View.styles.tsx +76 -106
  124. package/src/View/View.web.tsx +5 -21
  125. package/src/View/types.ts +31 -3
  126. package/src/examples/ButtonExamples.tsx +20 -0
  127. package/src/examples/CardExamples.tsx +0 -6
  128. package/src/extensions/extendComponent.ts +61 -0
  129. package/src/index.ts +1 -1
@@ -1,8 +1,27 @@
1
1
  import React, { forwardRef } from 'react';
2
- import { View as RNView, ScrollView as RNScrollView, ViewStyle } from 'react-native';
2
+ import { View as RNView, ScrollView as RNScrollView, ViewStyle, StyleSheet } from 'react-native';
3
+ import { useResponsiveStyle, ResponsiveStyle } from '@idealyst/theme';
3
4
  import { ViewProps } from './types';
4
5
  import { viewStyles } from './View.styles';
5
6
 
7
+ /**
8
+ * Check if a style object contains any responsive values
9
+ */
10
+ function hasResponsiveValues(style: any): style is ResponsiveStyle {
11
+ if (!style || typeof style !== 'object' || Array.isArray(style)) return false;
12
+ for (const key in style) {
13
+ const value = style[key];
14
+ if (value && typeof value === 'object' && !Array.isArray(value) && !('$$typeof' in value)) {
15
+ // Check if it looks like a breakpoint map (has breakpoint-like keys)
16
+ const keys = Object.keys(value);
17
+ if (keys.some(k => ['xs', 'sm', 'md', 'lg', 'xl'].includes(k))) {
18
+ return true;
19
+ }
20
+ }
21
+ }
22
+ return false;
23
+ }
24
+
6
25
  const View = forwardRef<RNView | RNScrollView, ViewProps>(({
7
26
  children,
8
27
  background = 'transparent',
@@ -26,6 +45,7 @@ const View = forwardRef<RNView | RNScrollView, ViewProps>(({
26
45
  testID,
27
46
  id,
28
47
  }, ref) => {
48
+ // Set active variants for this render
29
49
  viewStyles.useVariants({
30
50
  background,
31
51
  radius,
@@ -39,25 +59,33 @@ const View = forwardRef<RNView | RNScrollView, ViewProps>(({
39
59
  marginHorizontal,
40
60
  });
41
61
 
42
- const getStyles = (): ViewStyle => {
43
- const baseStyles: ViewStyle = {};
62
+ // Call style as function to get theme-reactive styles
63
+ const viewStyle = (viewStyles.view as any)({});
64
+
65
+ // Override styles for direct prop values
66
+ const overrideStyles: ViewStyle = {};
67
+ if (backgroundColor) overrideStyles.backgroundColor = backgroundColor;
68
+ if (borderRadius !== undefined) overrideStyles.borderRadius = borderRadius;
69
+ if (borderWidth !== undefined) overrideStyles.borderWidth = borderWidth;
70
+ if (borderColor) overrideStyles.borderColor = borderColor;
44
71
 
45
- if (backgroundColor) baseStyles.backgroundColor = backgroundColor;
46
- if (borderRadius !== undefined) baseStyles.borderRadius = borderRadius;
47
- if (borderWidth !== undefined) baseStyles.borderWidth = borderWidth;
48
- if (borderColor) baseStyles.borderColor = borderColor;
72
+ // Flatten style array if needed and check for responsive values
73
+ const flattenedStyle = Array.isArray(style) ? StyleSheet.flatten(style) : style;
49
74
 
50
- return baseStyles;
51
- };
75
+ // Resolve responsive values if present (this hook is reactive to breakpoint changes)
76
+ const resolvedStyle = useResponsiveStyle(
77
+ hasResponsiveValues(flattenedStyle) ? flattenedStyle : {}
78
+ );
52
79
 
53
- const viewStyle = (viewStyles.view as any)({});
80
+ // Use resolved style if responsive, otherwise use original
81
+ const finalStyle = hasResponsiveValues(flattenedStyle) ? resolvedStyle : style;
54
82
 
55
83
  if (scrollable) {
56
84
  return (
57
85
  <RNScrollView
58
86
  ref={ref as any}
59
- style={[{ flex: 1 }, style]}
60
- contentContainerStyle={[viewStyle, getStyles()]}
87
+ style={[viewStyle, { flex: 1 }, overrideStyles, finalStyle]}
88
+ contentContainerStyle={[viewStyle, overrideStyles]}
61
89
  testID={testID}
62
90
  nativeID={id}
63
91
  >
@@ -67,7 +95,7 @@ const View = forwardRef<RNView | RNScrollView, ViewProps>(({
67
95
  }
68
96
 
69
97
  return (
70
- <RNView ref={ref as any} style={[viewStyle, getStyles(), style]} testID={testID} nativeID={id}>
98
+ <RNView ref={ref as any} style={[viewStyle, overrideStyles, finalStyle]} testID={testID} nativeID={id}>
71
99
  {children}
72
100
  </RNView>
73
101
  );
@@ -0,0 +1,125 @@
1
+ import { StyleSheet } from 'react-native-unistyles';
2
+ import { Theme, StylesheetStyles, Surface } from '@idealyst/theme';
3
+ import {
4
+ buildGapVariants,
5
+ buildPaddingVariants,
6
+ buildPaddingVerticalVariants,
7
+ buildPaddingHorizontalVariants,
8
+ buildMarginVariants,
9
+ buildMarginVerticalVariants,
10
+ buildMarginHorizontalVariants,
11
+ } from '../utils/buildViewStyleVariants';
12
+ import { ViewBackgroundVariant, ViewBorderVariant, ViewRadiusVariant } from './types';
13
+ import { ViewStyleSize } from '../utils/viewStyleProps';
14
+ import { applyExtensions } from '../extensions/applyExtension';
15
+
16
+ type ViewVariants = {
17
+ background: ViewBackgroundVariant;
18
+ radius: ViewRadiusVariant;
19
+ border: ViewBorderVariant;
20
+ gap: ViewStyleSize;
21
+ padding: ViewStyleSize;
22
+ paddingVertical: ViewStyleSize;
23
+ paddingHorizontal: ViewStyleSize;
24
+ margin: ViewStyleSize;
25
+ marginVertical: ViewStyleSize;
26
+ marginHorizontal: ViewStyleSize;
27
+ };
28
+
29
+ export type ExpandedViewStyles = StylesheetStyles<keyof ViewVariants>;
30
+
31
+ export type ViewStylesheet = {
32
+ view: ExpandedViewStyles;
33
+ };
34
+
35
+ /**
36
+ * Create background variants for view
37
+ */
38
+ function createBackgroundVariants(theme: Theme) {
39
+ const variants: any = {
40
+ transparent: {
41
+ backgroundColor: 'transparent',
42
+ },
43
+ };
44
+
45
+ // Add all surface colors programmatically
46
+ for (const surface in theme.colors.surface) {
47
+ variants[surface] = {
48
+ backgroundColor: theme.colors.surface[surface as Surface],
49
+ };
50
+ }
51
+
52
+ return variants;
53
+ }
54
+
55
+ /**
56
+ * Create radius variants for view
57
+ */
58
+ function createRadiusVariants() {
59
+ return {
60
+ none: { borderRadius: 0 },
61
+ xs: { borderRadius: 2 },
62
+ sm: { borderRadius: 4 },
63
+ md: { borderRadius: 8 },
64
+ lg: { borderRadius: 12 },
65
+ xl: { borderRadius: 16 },
66
+ } as const;
67
+ }
68
+
69
+ /**
70
+ * Create border variants for view
71
+ */
72
+ function createBorderVariants(theme: Theme) {
73
+ return {
74
+ none: {
75
+ borderWidth: 0,
76
+ },
77
+ thin: {
78
+ borderWidth: 1,
79
+ borderStyle: 'solid',
80
+ borderColor: theme.colors['gray.300'],
81
+ },
82
+ thick: {
83
+ borderWidth: 2,
84
+ borderStyle: 'solid',
85
+ borderColor: theme.colors['gray.300'],
86
+ },
87
+ } as const;
88
+ }
89
+
90
+ /**
91
+ * Create dynamic view styles.
92
+ * Returns a function to ensure Unistyles can track theme changes.
93
+ * All styles must be dynamic functions (not static objects) to work with
94
+ * Unistyles' Babel transform and theme reactivity on native.
95
+ */
96
+ function createViewStyles(theme: Theme) {
97
+ return (_props?: {}) => ({
98
+ display: 'flex' as const,
99
+ variants: {
100
+ background: createBackgroundVariants(theme),
101
+ radius: createRadiusVariants(),
102
+ border: createBorderVariants(theme),
103
+ gap: buildGapVariants(theme),
104
+ padding: buildPaddingVariants(theme),
105
+ paddingVertical: buildPaddingVerticalVariants(theme),
106
+ paddingHorizontal: buildPaddingHorizontalVariants(theme),
107
+ margin: buildMarginVariants(theme),
108
+ marginVertical: buildMarginVerticalVariants(theme),
109
+ marginHorizontal: buildMarginHorizontalVariants(theme),
110
+ },
111
+ _web: {
112
+ display: 'flex',
113
+ flexDirection: 'column',
114
+ boxSizing: 'border-box',
115
+ },
116
+ });
117
+ }
118
+
119
+ // Styles use applyExtensions to enable theme extensions and ensure proper
120
+ // reactivity with Unistyles' native Shadow Tree updates.
121
+ export const viewStyles = StyleSheet.create((theme: Theme) => {
122
+ return applyExtensions('View', theme, {
123
+ view: createViewStyles(theme),
124
+ });
125
+ });
@@ -1,125 +1,95 @@
1
+ /**
2
+ * View styles using defineStyle with $iterator expansion.
3
+ */
1
4
  import { StyleSheet } from 'react-native-unistyles';
2
- import { Theme, StylesheetStyles, Surface } from '@idealyst/theme';
3
- import {
4
- buildGapVariants,
5
- buildPaddingVariants,
6
- buildPaddingVerticalVariants,
7
- buildPaddingHorizontalVariants,
8
- buildMarginVariants,
9
- buildMarginVerticalVariants,
10
- buildMarginHorizontalVariants,
11
- } from '../utils/buildViewStyleVariants';
5
+ import { defineStyle, ThemeStyleWrapper } from '@idealyst/theme';
6
+ import type { Theme as BaseTheme } from '@idealyst/theme';
12
7
  import { ViewBackgroundVariant, ViewBorderVariant, ViewRadiusVariant } from './types';
13
8
  import { ViewStyleSize } from '../utils/viewStyleProps';
14
- import { applyExtensions } from '../extensions/applyExtension';
15
9
 
16
- type ViewVariants = {
17
- background: ViewBackgroundVariant;
18
- radius: ViewRadiusVariant;
19
- border: ViewBorderVariant;
20
- gap: ViewStyleSize;
21
- padding: ViewStyleSize;
22
- paddingVertical: ViewStyleSize;
23
- paddingHorizontal: ViewStyleSize;
24
- margin: ViewStyleSize;
25
- marginVertical: ViewStyleSize;
26
- marginHorizontal: ViewStyleSize;
27
- };
10
+ // Required: Unistyles must see StyleSheet usage in original source to process this file
11
+ void StyleSheet;
28
12
 
29
- export type ExpandedViewStyles = StylesheetStyles<keyof ViewVariants>;
13
+ // Wrap theme for $iterator support
14
+ type Theme = ThemeStyleWrapper<BaseTheme>;
30
15
 
31
- export type ViewStylesheet = {
32
- view: ExpandedViewStyles;
16
+ export type ViewVariants = {
17
+ background: ViewBackgroundVariant;
18
+ radius: ViewRadiusVariant;
19
+ border: ViewBorderVariant;
20
+ gap: ViewStyleSize;
21
+ padding: ViewStyleSize;
22
+ paddingVertical: ViewStyleSize;
23
+ paddingHorizontal: ViewStyleSize;
24
+ margin: ViewStyleSize;
25
+ marginVertical: ViewStyleSize;
26
+ marginHorizontal: ViewStyleSize;
33
27
  };
34
28
 
35
- /**
36
- * Create background variants for view
37
- */
38
- function createBackgroundVariants(theme: Theme) {
39
- const variants: any = {
40
- transparent: {
41
- backgroundColor: 'transparent',
42
- },
43
- };
44
-
45
- // Add all surface colors programmatically
46
- for (const surface in theme.colors.surface) {
47
- variants[surface] = {
48
- backgroundColor: theme.colors.surface[surface as Surface],
49
- };
50
- }
51
-
52
- return variants;
53
- }
29
+ export type ViewDynamicProps = Partial<ViewVariants>;
54
30
 
55
31
  /**
56
- * Create radius variants for view
32
+ * View styles with $iterator expansion for spacing variants.
33
+ *
34
+ * NOTE: At least one top-level theme access is required for Unistyles to trace
35
+ * theme dependencies. We use a transparent borderColor as a marker.
57
36
  */
58
- function createRadiusVariants() {
59
- return {
60
- none: { borderRadius: 0 },
61
- xs: { borderRadius: 2 },
62
- sm: { borderRadius: 4 },
63
- md: { borderRadius: 8 },
64
- lg: { borderRadius: 12 },
65
- xl: { borderRadius: 16 },
66
- } as const;
67
- }
68
-
69
- /**
70
- * Create border variants for view
71
- */
72
- function createBorderVariants(theme: Theme) {
73
- return {
74
- none: {
75
- borderWidth: 0,
76
- },
77
- thin: {
78
- borderWidth: 1,
79
- borderStyle: 'solid',
80
- borderColor: theme.colors['gray.300'],
81
- },
82
- thick: {
83
- borderWidth: 2,
84
- borderStyle: 'solid',
85
- borderColor: theme.colors['gray.300'],
86
- },
87
- } as const;
88
- }
89
-
90
- // Style creators for extension support
91
- function createViewStyles(theme: Theme) {
92
- return () => ({
37
+ export const viewStyles = defineStyle('View', (theme: Theme) => ({
38
+ view: (_props: ViewDynamicProps) => ({
93
39
  display: 'flex' as const,
40
+ // Theme marker for Unistyles reactivity (invisible, overridden by variants)
41
+ borderColor: theme.colors.border.primary,
42
+ borderWidth: 0,
94
43
  variants: {
95
- background: createBackgroundVariants(theme),
96
- radius: createRadiusVariants(),
97
- border: createBorderVariants(theme),
98
- gap: buildGapVariants(theme),
99
- padding: buildPaddingVariants(theme),
100
- paddingVertical: buildPaddingVerticalVariants(theme),
101
- paddingHorizontal: buildPaddingHorizontalVariants(theme),
102
- margin: buildMarginVariants(theme),
103
- marginVertical: buildMarginVerticalVariants(theme),
104
- marginHorizontal: buildMarginHorizontalVariants(theme),
44
+ background: {
45
+ transparent: { backgroundColor: 'transparent' },
46
+ primary: { backgroundColor: theme.colors.surface.primary },
47
+ secondary: { backgroundColor: theme.colors.surface.secondary },
48
+ tertiary: { backgroundColor: theme.colors.surface.tertiary },
49
+ inverse: { backgroundColor: theme.colors.surface.inverse },
50
+ 'inverse-secondary': { backgroundColor: theme.colors.surface['inverse-secondary'] },
51
+ 'inverse-tertiary': { backgroundColor: theme.colors.surface['inverse-tertiary'] },
52
+ },
53
+ radius: {
54
+ none: { borderRadius: 0 },
55
+ xs: { borderRadius: 2 },
56
+ sm: { borderRadius: 4 },
57
+ md: { borderRadius: 8 },
58
+ lg: { borderRadius: 12 },
59
+ xl: { borderRadius: 16 },
60
+ },
61
+ border: {
62
+ none: { borderWidth: 0 },
63
+ thin: { borderWidth: 1, borderStyle: 'solid' as const, borderColor: theme.colors['gray.300'] },
64
+ thick: { borderWidth: 2, borderStyle: 'solid' as const, borderColor: theme.colors['gray.300'] },
65
+ },
66
+ // $iterator expands for each view size
67
+ gap: {
68
+ gap: theme.sizes.$view.spacing,
69
+ },
70
+ padding: {
71
+ padding: theme.sizes.$view.padding,
72
+ },
73
+ paddingVertical: {
74
+ paddingVertical: theme.sizes.$view.padding,
75
+ },
76
+ paddingHorizontal: {
77
+ paddingHorizontal: theme.sizes.$view.padding,
78
+ },
79
+ margin: {
80
+ margin: theme.sizes.$view.padding,
81
+ },
82
+ marginVertical: {
83
+ marginVertical: theme.sizes.$view.padding,
84
+ },
85
+ marginHorizontal: {
86
+ marginHorizontal: theme.sizes.$view.padding,
87
+ },
105
88
  },
106
89
  _web: {
107
90
  display: 'flex',
108
91
  flexDirection: 'column',
109
92
  boxSizing: 'border-box',
110
93
  },
111
- });
112
- }
113
-
114
- // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
115
- // transform on native cannot resolve function calls to extract variant structures.
116
- export const viewStyles = StyleSheet.create((theme: Theme) => {
117
- // Apply extensions to main visual elements
118
- const extended = applyExtensions('View', theme, {
119
- view: createViewStyles(theme),
120
- });
121
-
122
- return {
123
- ...extended,
124
- };
125
- });
94
+ }),
95
+ }));
@@ -1,6 +1,6 @@
1
1
  import React, { forwardRef, useMemo } from 'react';
2
- import { StyleSheet } from 'react-native';
3
2
  import { getWebProps } from 'react-native-unistyles/web';
3
+ import { useResponsiveStyle } from '@idealyst/theme';
4
4
  import { ViewProps } from './types';
5
5
  import { viewStyles } from './View.styles';
6
6
  import useMergeRefs from '../hooks/useMergeRefs';
@@ -41,31 +41,15 @@ const View = forwardRef<HTMLDivElement, ViewProps>(({
41
41
  marginHorizontal,
42
42
  });
43
43
 
44
- // Create dynamic styles based on custom props (overrides variants)
45
- const dynamicStyles: any = {};
46
-
47
- if (backgroundColor) dynamicStyles.backgroundColor = backgroundColor;
48
- if (borderRadius !== undefined) dynamicStyles.borderRadius = borderRadius;
49
- if (borderWidth !== undefined) dynamicStyles.borderWidth = borderWidth;
50
- if (borderColor) dynamicStyles.borderColor = borderColor;
51
-
52
- // Flatten style array to object (HTML divs don't support style arrays)
53
- const flattenedStyle = useMemo(() => {
54
- if (!style) return undefined;
55
- if (Array.isArray(style)) {
56
- return StyleSheet.flatten(style);
57
- }
58
- return style;
59
- }, [style]);
60
-
44
+ // Call style as function to get theme-reactive styles
61
45
  /** @ts-ignore */
62
- const webProps = getWebProps([(viewStyles.view as any)({}), dynamicStyles]);
63
-
46
+ const webProps = getWebProps((viewStyles.view as any)({}));
47
+
64
48
  const mergedRef = useMergeRefs(ref, webProps.ref);
65
49
 
66
50
  return (
67
51
  <div
68
- style={flattenedStyle as any}
52
+ style={style as any}
69
53
  {...webProps}
70
54
  ref={mergedRef}
71
55
  id={id}
package/src/View/types.ts CHANGED
@@ -1,8 +1,28 @@
1
- import { Size, Surface } from '@idealyst/theme';
1
+ import { Size, Surface, ResponsiveStyle } from '@idealyst/theme';
2
2
  import type { ReactNode } from 'react';
3
3
  import type { StyleProp, ViewStyle } from 'react-native';
4
4
  import { ContainerStyleProps } from '../utils/viewStyleProps';
5
5
 
6
+ /**
7
+ * Style prop type that accepts both regular styles and responsive styles.
8
+ * Responsive styles allow breakpoint-based values:
9
+ * @example
10
+ * ```tsx
11
+ * // Regular style
12
+ * <View style={{ flexDirection: 'column' }} />
13
+ *
14
+ * // Responsive style
15
+ * <View style={{ flexDirection: { xs: 'column', md: 'row' } }} />
16
+ *
17
+ * // Style array (native only)
18
+ * <View style={[styles.container, { padding: 10 }]} />
19
+ *
20
+ * // Web-only CSS properties
21
+ * <View style={{ display: 'inline-block' }} />
22
+ * ```
23
+ */
24
+ export type ViewStyleProp = StyleProp<ViewStyle> | ResponsiveStyle | React.CSSProperties;
25
+
6
26
  // Component-specific type aliases for future extensibility
7
27
  export type ViewBackgroundVariant = Surface | 'transparent';
8
28
  export type ViewRadiusVariant = Size | 'none';
@@ -50,9 +70,17 @@ export interface ViewProps extends ContainerStyleProps {
50
70
  borderColor?: string;
51
71
 
52
72
  /**
53
- * Additional styles (platform-specific)
73
+ * Additional styles. Supports responsive values for any property.
74
+ * @example
75
+ * ```tsx
76
+ * // Responsive flexDirection
77
+ * <View style={{ flexDirection: { xs: 'column', md: 'row' } }} />
78
+ *
79
+ * // Mix responsive and static values
80
+ * <View style={{ padding: { xs: 8, lg: 16 }, backgroundColor: '#fff' }} />
81
+ * ```
54
82
  */
55
- style?: React.CSSProperties | StyleProp<ViewStyle>;
83
+ style?: ViewStyleProp;
56
84
 
57
85
  /**
58
86
  * Enable scrollable content (uses ScrollView on native, overflow:auto on web)
@@ -1,11 +1,14 @@
1
1
  import React from 'react';
2
2
  import { Screen, View, Button, Text } from '@idealyst/components';
3
+ import { useUnistyles } from 'react-native-unistyles';
3
4
 
4
5
  export const ButtonExamples = () => {
5
6
  const handlePress = (buttonType: string) => {
6
7
  console.log(`Button pressed: ${buttonType}`);
7
8
  };
8
9
 
10
+ const { theme } = useUnistyles()
11
+
9
12
  return (
10
13
  <Screen background="primary">
11
14
  <View gap="xl">
@@ -41,6 +44,23 @@ export const ButtonExamples = () => {
41
44
  </View>
42
45
  </View>
43
46
 
47
+ {/* Show all intents in theme (including extended intents) */}
48
+ <View gap="md">
49
+ <Text typography="subtitle1">All Intents</Text>
50
+ <View style={{ flexDirection: 'row', gap: 12, flexWrap: 'wrap' }}>
51
+ { (Object.keys(theme.intents) as Array<keyof typeof theme.intents>).map((intent) => (
52
+ <Button
53
+ key={intent}
54
+ type="contained"
55
+ intent={intent}
56
+ onPress={() => handlePress(`intent-${intent}`)}
57
+ >
58
+ {intent.charAt(0).toUpperCase() + intent.slice(1)}
59
+ </Button>
60
+ )) }
61
+ </View>
62
+ </View>
63
+
44
64
  {/* Button Sizes */}
45
65
  <View gap="md">
46
66
  <Text typography="subtitle1">Sizes</Text>
@@ -17,12 +17,6 @@ export const CardExamples = () => {
17
17
  <View gap="md">
18
18
  <Text typography="subtitle1">Variants</Text>
19
19
  <View gap="sm" style={{ gap: 10 }}>
20
- <Card type="default" padding="md">
21
- <Text>Default Card</Text>
22
- <Text typography="caption" color="secondary">
23
- This is a default card with standard styling
24
- </Text>
25
- </Card>
26
20
 
27
21
  <Card type="outlined" padding="md">
28
22
  <Text>Outlined Card</Text>
@@ -1,4 +1,5 @@
1
1
  import { Theme } from '@idealyst/theme';
2
+ import { UnistylesRuntime } from 'react-native-unistyles';
2
3
  import {
3
4
  ComponentStyleElements,
4
5
  ComponentName,
@@ -18,6 +19,57 @@ const extensionRegistry = new Map<ComponentName, StyleExtension<any>[]>();
18
19
  */
19
20
  const replacementRegistry = new Map<ComponentName, StyleExtension<any>>();
20
21
 
22
+ /**
23
+ * Compute all extensions for a given theme.
24
+ * Returns an object with component names as keys and merged element extensions as values.
25
+ */
26
+ function computeExtensionsForTheme(theme: Theme): Record<string, Record<string, any>> {
27
+ const result: Record<string, Record<string, any>> = {};
28
+
29
+ for (const [component, extensions] of extensionRegistry) {
30
+ if (!extensions || extensions.length === 0) continue;
31
+
32
+ // Resolve all extensions (call functions with theme)
33
+ const resolved = extensions.map(ext =>
34
+ typeof ext === 'function' ? ext(theme) : ext
35
+ );
36
+
37
+ // Merge all extensions in order (later ones win)
38
+ result[component] = deepMergeAll(...resolved);
39
+ }
40
+
41
+ return result;
42
+ }
43
+
44
+ /**
45
+ * Update theme's __extensions to trigger Unistyles reactivity.
46
+ * This is called whenever extensions change.
47
+ */
48
+ function syncExtensionsToThemes(): void {
49
+ try {
50
+ // Update both light and dark themes with computed extensions
51
+ UnistylesRuntime.updateTheme('light', (currentTheme) => {
52
+ const extensions = computeExtensionsForTheme(currentTheme);
53
+ return {
54
+ ...currentTheme,
55
+ __extensions: extensions,
56
+ };
57
+ });
58
+
59
+ UnistylesRuntime.updateTheme('dark', (currentTheme) => {
60
+ const extensions = computeExtensionsForTheme(currentTheme);
61
+ return {
62
+ ...currentTheme,
63
+ __extensions: extensions,
64
+ };
65
+ });
66
+ } catch (error) {
67
+ // UnistylesRuntime may not be available in all contexts (e.g., SSR)
68
+ // Silently ignore errors - extensions will still work via getExtension
69
+ console.warn('Unable to sync extensions to theme:', error);
70
+ }
71
+ }
72
+
21
73
  /**
22
74
  * Completely replace the styles of a component.
23
75
  *
@@ -249,6 +301,9 @@ export function extendComponent<K extends ComponentName>(
249
301
  const existing = extensionRegistry.get(component) ?? [];
250
302
  existing.push(extension);
251
303
  extensionRegistry.set(component, existing);
304
+
305
+ // Sync extensions to theme for Unistyles reactivity
306
+ syncExtensionsToThemes();
252
307
  }
253
308
 
254
309
  /**
@@ -298,6 +353,9 @@ export function getExtension<K extends ComponentName>(
298
353
  */
299
354
  export function clearExtension<K extends ComponentName>(component: K): void {
300
355
  extensionRegistry.delete(component);
356
+
357
+ // Sync extensions to theme for Unistyles reactivity
358
+ syncExtensionsToThemes();
301
359
  }
302
360
 
303
361
  /**
@@ -313,6 +371,9 @@ export function clearExtension<K extends ComponentName>(component: K): void {
313
371
  */
314
372
  export function clearAllExtensions(): void {
315
373
  extensionRegistry.clear();
374
+
375
+ // Sync extensions to theme for Unistyles reactivity
376
+ syncExtensionsToThemes();
316
377
  }
317
378
 
318
379
  /**
package/src/index.ts CHANGED
@@ -40,7 +40,7 @@ export * from './Avatar/types';
40
40
  export { default as Screen } from './Screen';
41
41
  export * from './Screen/types';
42
42
 
43
- export { default as Icon } from './Icon';
43
+ export { default as Icon, IconRegistry } from './Icon';
44
44
  export * from './Icon/types';
45
45
 
46
46
  export { default as SVGImage } from './SVGImage';