@idealyst/components 1.1.7 → 1.1.8

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 (105) hide show
  1. package/package.json +3 -3
  2. package/src/Accordion/Accordion.native.tsx +8 -6
  3. package/src/Accordion/Accordion.styles.old.tsx +298 -0
  4. package/src/Accordion/Accordion.styles.tsx +102 -236
  5. package/src/ActivityIndicator/ActivityIndicator.styles.old.tsx +94 -0
  6. package/src/ActivityIndicator/ActivityIndicator.styles.tsx +44 -74
  7. package/src/Alert/Alert.native.tsx +16 -6
  8. package/src/Alert/Alert.styles.old.tsx +209 -0
  9. package/src/Alert/Alert.styles.tsx +67 -149
  10. package/src/Avatar/Avatar.styles.old.tsx +99 -0
  11. package/src/Avatar/Avatar.styles.tsx +35 -80
  12. package/src/Badge/Badge.styles.old.tsx +157 -0
  13. package/src/Badge/Badge.styles.tsx +61 -121
  14. package/src/Breadcrumb/Breadcrumb.styles.old.tsx +231 -0
  15. package/src/Breadcrumb/Breadcrumb.styles.tsx +83 -200
  16. package/src/Breadcrumb/Breadcrumb.web.tsx +28 -23
  17. package/src/Button/Button.styles.tsx +89 -141
  18. package/src/Card/Card.native.tsx +7 -11
  19. package/src/Card/Card.styles.old.tsx +160 -0
  20. package/src/Card/Card.styles.tsx +105 -142
  21. package/src/Card/Card.web.tsx +5 -4
  22. package/src/Checkbox/Checkbox.native.tsx +9 -5
  23. package/src/Checkbox/Checkbox.styles.old.tsx +271 -0
  24. package/src/Checkbox/Checkbox.styles.tsx +104 -216
  25. package/src/Checkbox/Checkbox.web.tsx +6 -6
  26. package/src/Chip/Chip.styles.old.tsx +184 -0
  27. package/src/Chip/Chip.styles.tsx +34 -72
  28. package/src/Dialog/Dialog.native.tsx +7 -4
  29. package/src/Dialog/Dialog.styles.old.tsx +202 -0
  30. package/src/Dialog/Dialog.styles.tsx +69 -133
  31. package/src/Divider/Divider.styles.old.tsx +172 -0
  32. package/src/Divider/Divider.styles.tsx +62 -84
  33. package/src/Icon/Icon.native.tsx +8 -8
  34. package/src/Icon/Icon.styles.old.tsx +81 -0
  35. package/src/Icon/Icon.styles.tsx +52 -66
  36. package/src/Icon/Icon.web.tsx +43 -7
  37. package/src/Icon/IconSvg/IconSvg.web.tsx +2 -0
  38. package/src/Image/Image.styles.old.tsx +69 -0
  39. package/src/Image/Image.styles.tsx +46 -60
  40. package/src/Input/Input.native.tsx +138 -53
  41. package/src/Input/Input.styles.old.tsx +289 -0
  42. package/src/Input/Input.styles.tsx +127 -198
  43. package/src/List/List.native.tsx +5 -2
  44. package/src/List/List.styles.old.tsx +242 -0
  45. package/src/List/List.styles.tsx +179 -215
  46. package/src/List/ListItem.native.tsx +12 -6
  47. package/src/List/ListItem.web.tsx +23 -13
  48. package/src/Menu/Menu.styles.old.tsx +197 -0
  49. package/src/Menu/Menu.styles.tsx +68 -150
  50. package/src/Menu/MenuItem.native.tsx +5 -3
  51. package/src/Menu/MenuItem.styles.old.tsx +114 -0
  52. package/src/Menu/MenuItem.styles.tsx +57 -89
  53. package/src/Menu/MenuItem.web.tsx +8 -3
  54. package/src/Popover/Popover.native.tsx +10 -4
  55. package/src/Popover/Popover.styles.old.tsx +135 -0
  56. package/src/Popover/Popover.styles.tsx +51 -112
  57. package/src/Pressable/Pressable.styles.old.tsx +27 -0
  58. package/src/Pressable/Pressable.styles.tsx +35 -27
  59. package/src/Progress/Progress.styles.old.tsx +200 -0
  60. package/src/Progress/Progress.styles.tsx +75 -164
  61. package/src/RadioButton/RadioButton.native.tsx +4 -3
  62. package/src/RadioButton/RadioButton.styles.old.tsx +175 -0
  63. package/src/RadioButton/RadioButton.styles.tsx +83 -154
  64. package/src/RadioButton/RadioButton.web.tsx +2 -2
  65. package/src/SVGImage/SVGImage.styles.old.tsx +86 -0
  66. package/src/SVGImage/SVGImage.styles.tsx +35 -78
  67. package/src/Screen/Screen.native.tsx +18 -25
  68. package/src/Screen/Screen.styles.old.tsx +87 -0
  69. package/src/Screen/Screen.styles.tsx +105 -67
  70. package/src/Screen/Screen.web.tsx +1 -1
  71. package/src/Select/Select.native.tsx +42 -33
  72. package/src/Select/Select.styles.old.tsx +353 -0
  73. package/src/Select/Select.styles.tsx +223 -292
  74. package/src/Skeleton/Skeleton.styles.old.tsx +67 -0
  75. package/src/Skeleton/Skeleton.styles.tsx +29 -53
  76. package/src/Slider/Slider.styles.old.tsx +259 -0
  77. package/src/Slider/Slider.styles.tsx +153 -234
  78. package/src/Switch/Switch.native.tsx +7 -5
  79. package/src/Switch/Switch.styles.old.tsx +203 -0
  80. package/src/Switch/Switch.styles.tsx +101 -174
  81. package/src/Switch/Switch.web.tsx +5 -5
  82. package/src/TabBar/TabBar.native.tsx +3 -2
  83. package/src/TabBar/TabBar.styles.old.tsx +343 -0
  84. package/src/TabBar/TabBar.styles.tsx +145 -279
  85. package/src/Table/Table.native.tsx +18 -9
  86. package/src/Table/Table.styles.old.tsx +311 -0
  87. package/src/Table/Table.styles.tsx +152 -286
  88. package/src/Text/Text.native.tsx +1 -3
  89. package/src/Text/Text.style.demo.tsx +16 -0
  90. package/src/Text/Text.styles.old.tsx +219 -0
  91. package/src/Text/Text.styles.tsx +94 -84
  92. package/src/Text/Text.web.tsx +2 -2
  93. package/src/Text/index.ts +1 -0
  94. package/src/TextArea/TextArea.styles.old.tsx +213 -0
  95. package/src/TextArea/TextArea.styles.tsx +93 -181
  96. package/src/Tooltip/Tooltip.styles.old.tsx +82 -0
  97. package/src/Tooltip/Tooltip.styles.tsx +32 -56
  98. package/src/Video/Video.styles.old.tsx +51 -0
  99. package/src/Video/Video.styles.tsx +32 -44
  100. package/src/View/View.native.tsx +12 -14
  101. package/src/View/View.styles.old.tsx +125 -0
  102. package/src/View/View.styles.tsx +76 -106
  103. package/src/View/View.web.tsx +1 -0
  104. package/src/examples/CardExamples.tsx +0 -6
  105. package/src/extensions/extendComponent.ts +61 -0
@@ -0,0 +1,172 @@
1
+ import { StyleSheet } from 'react-native-unistyles';
2
+ import { Theme, Intent } from '@idealyst/theme';
3
+ import { applyExtensions } from '../extensions/applyExtension';
4
+
5
+ type DividerOrientation = 'horizontal' | 'vertical';
6
+ type DividerThickness = 'thin' | 'md' | 'thick';
7
+ type DividerType = 'solid' | 'dashed' | 'dotted';
8
+ type DividerIntent = Intent | 'secondary' | 'neutral' | 'info';
9
+ type DividerLength = 'full' | 'auto';
10
+ type DividerSpacing = 'none' | 'sm' | 'md' | 'lg';
11
+
12
+ type DividerDynamicProps = {
13
+ orientation?: DividerOrientation;
14
+ thickness?: DividerThickness;
15
+ type?: DividerType;
16
+ intent?: DividerIntent;
17
+ spacing?: DividerSpacing;
18
+ };
19
+
20
+ type LineDynamicProps = {
21
+ orientation?: DividerOrientation;
22
+ thickness?: DividerThickness;
23
+ };
24
+
25
+ function getIntentColor(theme: Theme, intent: DividerIntent): string {
26
+ if (intent === 'secondary') return theme.colors.border.primary;
27
+ if (intent === 'neutral') return theme.colors.border.secondary;
28
+ if (intent === 'info') return theme.intents.primary.primary;
29
+ return theme.intents[intent as Intent].primary;
30
+ }
31
+
32
+ function getThicknessValue(thickness: DividerThickness): number {
33
+ switch (thickness) {
34
+ case 'thin': return 1;
35
+ case 'md': return 2;
36
+ case 'thick': return 4;
37
+ default: return 1;
38
+ }
39
+ }
40
+
41
+ function getSpacingValue(spacing: DividerSpacing): number {
42
+ switch (spacing) {
43
+ case 'none': return 0;
44
+ case 'sm': return 8;
45
+ case 'md': return 16;
46
+ case 'lg': return 24;
47
+ default: return 0;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Create dynamic divider styles
53
+ */
54
+ function createDividerStyles(theme: Theme) {
55
+ return ({
56
+ orientation = 'horizontal',
57
+ thickness = 'thin',
58
+ type = 'solid',
59
+ intent = 'neutral',
60
+ spacing = 'md'
61
+ }: DividerDynamicProps) => {
62
+ const color = getIntentColor(theme, intent);
63
+ const thicknessValue = getThicknessValue(thickness);
64
+ const spacingValue = getSpacingValue(spacing);
65
+
66
+ const isHorizontal = orientation === 'horizontal';
67
+ const isDashedOrDotted = type === 'dashed' || type === 'dotted';
68
+
69
+ // Base dimension styles based on orientation and thickness
70
+ const dimensionStyles = isHorizontal
71
+ ? { width: '100%', height: thicknessValue, flexDirection: 'row' as const }
72
+ : { width: thicknessValue, height: '100%', flexDirection: 'column' as const };
73
+
74
+ // Spacing styles based on orientation
75
+ const spacingStyles = isHorizontal
76
+ ? { marginVertical: spacingValue }
77
+ : { marginHorizontal: spacingValue };
78
+
79
+ // Web-specific border styles for dashed/dotted
80
+ const webBorderStyles = isDashedOrDotted ? {
81
+ border: 'none',
82
+ backgroundColor: 'transparent',
83
+ ...(isHorizontal
84
+ ? { borderTop: `${thicknessValue}px ${type} ${color}` }
85
+ : { borderLeft: `${thicknessValue}px ${type} ${color}` }
86
+ ),
87
+ } : {};
88
+
89
+ return {
90
+ backgroundColor: isDashedOrDotted ? 'transparent' : color,
91
+ ...dimensionStyles,
92
+ ...spacingStyles,
93
+ variants: {
94
+ length: {
95
+ full: {},
96
+ auto: {},
97
+ },
98
+ },
99
+ _web: webBorderStyles,
100
+ } as const;
101
+ };
102
+ }
103
+
104
+ /**
105
+ * Create dynamic line styles (for dividers with content)
106
+ */
107
+ function createLineStyles(theme: Theme) {
108
+ return ({ orientation = 'horizontal', thickness = 'thin' }: LineDynamicProps) => {
109
+ const thicknessValue = getThicknessValue(thickness);
110
+ const isHorizontal = orientation === 'horizontal';
111
+
112
+ return {
113
+ backgroundColor: theme.colors.border.secondary,
114
+ flex: 1,
115
+ ...(isHorizontal
116
+ ? { height: thicknessValue }
117
+ : { width: thicknessValue }
118
+ ),
119
+ } as const;
120
+ };
121
+ }
122
+
123
+ // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
124
+ // transform on native cannot resolve function calls to extract variant structures.
125
+ export const dividerStyles = StyleSheet.create((theme: Theme) => {
126
+ // Apply extensions to main visual elements
127
+
128
+ return applyExtensions('Divider', theme, {divider: createDividerStyles(theme),
129
+ // Additional styles (merged from return)
130
+ // Minor utility styles (not extended)
131
+ container: {
132
+ alignItems: 'center',
133
+ justifyContent: 'center',
134
+ display: 'flex',
135
+ variants: {
136
+ orientation: {
137
+ horizontal: {
138
+ flexDirection: 'row',
139
+ width: '100%',
140
+ },
141
+ vertical: {
142
+ flexDirection: 'column',
143
+ height: '100%',
144
+ },
145
+ },
146
+ spacing: {
147
+ none: { gap: 0 },
148
+ xs: { gap: 4 },
149
+ sm: { gap: 8 },
150
+ md: { gap: 16 },
151
+ lg: { gap: 24 },
152
+ xl: { gap: 32 },
153
+ },
154
+ },
155
+ },
156
+ content: {
157
+ backgroundColor: theme.colors.surface.primary,
158
+ color: theme.colors.text.secondary,
159
+ fontSize: 14,
160
+ variants: {
161
+ orientation: {
162
+ horizontal: {
163
+ paddingHorizontal: 8,
164
+ },
165
+ vertical: {
166
+ paddingVertical: 8,
167
+ },
168
+ },
169
+ },
170
+ },
171
+ line: createLineStyles(theme)});
172
+ });
@@ -1,15 +1,24 @@
1
+ /**
2
+ * Divider styles using defineStyle with dynamic functions.
3
+ */
1
4
  import { StyleSheet } from 'react-native-unistyles';
2
- import { Theme, Intent } from '@idealyst/theme';
3
- import { applyExtensions } from '../extensions/applyExtension';
5
+ import { defineStyle, ThemeStyleWrapper } from '@idealyst/theme';
6
+ import type { Theme as BaseTheme, Intent } from '@idealyst/theme';
7
+
8
+ // Required: Unistyles must see StyleSheet usage in original source to process this file
9
+ void StyleSheet;
10
+
11
+ // Wrap theme for $iterator support
12
+ type Theme = ThemeStyleWrapper<BaseTheme>;
4
13
 
5
14
  type DividerOrientation = 'horizontal' | 'vertical';
6
15
  type DividerThickness = 'thin' | 'md' | 'thick';
7
16
  type DividerType = 'solid' | 'dashed' | 'dotted';
8
17
  type DividerIntent = Intent | 'secondary' | 'neutral' | 'info';
9
- type DividerLength = 'full' | 'auto';
10
18
  type DividerSpacing = 'none' | 'sm' | 'md' | 'lg';
19
+ type DividerLength = 'full' | 'auto';
11
20
 
12
- type DividerDynamicProps = {
21
+ export type DividerDynamicProps = {
13
22
  orientation?: DividerOrientation;
14
23
  thickness?: DividerThickness;
15
24
  type?: DividerType;
@@ -17,18 +26,11 @@ type DividerDynamicProps = {
17
26
  spacing?: DividerSpacing;
18
27
  };
19
28
 
20
- type LineDynamicProps = {
29
+ export type LineDynamicProps = {
21
30
  orientation?: DividerOrientation;
22
31
  thickness?: DividerThickness;
23
32
  };
24
33
 
25
- function getIntentColor(theme: Theme, intent: DividerIntent): string {
26
- if (intent === 'secondary') return theme.colors.border.primary;
27
- if (intent === 'neutral') return theme.colors.border.secondary;
28
- if (intent === 'info') return theme.intents.primary.primary;
29
- return theme.intents[intent as Intent].primary;
30
- }
31
-
32
34
  function getThicknessValue(thickness: DividerThickness): number {
33
35
  switch (thickness) {
34
36
  case 'thin': return 1;
@@ -49,34 +51,38 @@ function getSpacingValue(spacing: DividerSpacing): number {
49
51
  }
50
52
 
51
53
  /**
52
- * Create dynamic divider styles
54
+ * Divider styles with dynamic functions for orientation/thickness/intent combinations.
53
55
  */
54
- function createDividerStyles(theme: Theme) {
55
- return ({
56
+ export const dividerStyles = defineStyle('Divider', (theme: Theme) => ({
57
+ divider: ({
56
58
  orientation = 'horizontal',
57
59
  thickness = 'thin',
58
60
  type = 'solid',
59
61
  intent = 'neutral',
60
62
  spacing = 'md'
61
63
  }: DividerDynamicProps) => {
62
- const color = getIntentColor(theme, intent);
63
64
  const thicknessValue = getThicknessValue(thickness);
64
65
  const spacingValue = getSpacingValue(spacing);
65
-
66
66
  const isHorizontal = orientation === 'horizontal';
67
67
  const isDashedOrDotted = type === 'dashed' || type === 'dotted';
68
68
 
69
- // Base dimension styles based on orientation and thickness
69
+ // Get color based on intent - inline for Unistyles to trace
70
+ const color = intent === 'secondary'
71
+ ? theme.colors.border.primary
72
+ : intent === 'neutral'
73
+ ? theme.colors.border.secondary
74
+ : intent === 'info'
75
+ ? theme.intents.primary.primary
76
+ : theme.intents[intent as Intent].primary;
77
+
70
78
  const dimensionStyles = isHorizontal
71
79
  ? { width: '100%', height: thicknessValue, flexDirection: 'row' as const }
72
80
  : { width: thicknessValue, height: '100%', flexDirection: 'column' as const };
73
81
 
74
- // Spacing styles based on orientation
75
82
  const spacingStyles = isHorizontal
76
83
  ? { marginVertical: spacingValue }
77
84
  : { marginHorizontal: spacingValue };
78
85
 
79
- // Web-specific border styles for dashed/dotted
80
86
  const webBorderStyles = isDashedOrDotted ? {
81
87
  border: 'none',
82
88
  backgroundColor: 'transparent',
@@ -98,14 +104,41 @@ function createDividerStyles(theme: Theme) {
98
104
  },
99
105
  _web: webBorderStyles,
100
106
  } as const;
101
- };
102
- }
107
+ },
108
+
109
+ container: (_props: { orientation?: DividerOrientation; spacing?: DividerSpacing }) => ({
110
+ alignItems: 'center',
111
+ justifyContent: 'center',
112
+ display: 'flex',
113
+ variants: {
114
+ orientation: {
115
+ horizontal: { flexDirection: 'row', width: '100%' },
116
+ vertical: { flexDirection: 'column', height: '100%' },
117
+ },
118
+ spacing: {
119
+ none: { gap: 0 },
120
+ xs: { gap: 4 },
121
+ sm: { gap: 8 },
122
+ md: { gap: 16 },
123
+ lg: { gap: 24 },
124
+ xl: { gap: 32 },
125
+ },
126
+ },
127
+ }),
128
+
129
+ content: (_props: { orientation?: DividerOrientation }) => ({
130
+ backgroundColor: theme.colors.surface.primary,
131
+ color: theme.colors.text.secondary,
132
+ fontSize: 14,
133
+ variants: {
134
+ orientation: {
135
+ horizontal: { paddingHorizontal: 8 },
136
+ vertical: { paddingVertical: 8 },
137
+ },
138
+ },
139
+ }),
103
140
 
104
- /**
105
- * Create dynamic line styles (for dividers with content)
106
- */
107
- function createLineStyles(theme: Theme) {
108
- return ({ orientation = 'horizontal', thickness = 'thin' }: LineDynamicProps) => {
141
+ line: ({ orientation = 'horizontal', thickness = 'thin' }: LineDynamicProps) => {
109
142
  const thicknessValue = getThicknessValue(thickness);
110
143
  const isHorizontal = orientation === 'horizontal';
111
144
 
@@ -117,60 +150,5 @@ function createLineStyles(theme: Theme) {
117
150
  : { width: thicknessValue }
118
151
  ),
119
152
  } as const;
120
- };
121
- }
122
-
123
- // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
124
- // transform on native cannot resolve function calls to extract variant structures.
125
- export const dividerStyles = StyleSheet.create((theme: Theme) => {
126
- // Apply extensions to main visual elements
127
- const extended = applyExtensions('Divider', theme, {
128
- divider: createDividerStyles(theme),
129
- });
130
-
131
- return {
132
- ...extended,
133
- // Minor utility styles (not extended)
134
- container: {
135
- alignItems: 'center',
136
- justifyContent: 'center',
137
- display: 'flex',
138
- variants: {
139
- orientation: {
140
- horizontal: {
141
- flexDirection: 'row',
142
- width: '100%',
143
- },
144
- vertical: {
145
- flexDirection: 'column',
146
- height: '100%',
147
- },
148
- },
149
- spacing: {
150
- none: { gap: 0 },
151
- xs: { gap: 4 },
152
- sm: { gap: 8 },
153
- md: { gap: 16 },
154
- lg: { gap: 24 },
155
- xl: { gap: 32 },
156
- },
157
- },
158
- },
159
- content: {
160
- backgroundColor: theme.colors.surface.primary,
161
- color: theme.colors.text.secondary,
162
- fontSize: 14,
163
- variants: {
164
- orientation: {
165
- horizontal: {
166
- paddingHorizontal: 8,
167
- },
168
- vertical: {
169
- paddingVertical: 8,
170
- },
171
- },
172
- },
173
- },
174
- line: createLineStyles(theme),
175
- };
176
- });
153
+ },
154
+ }));
@@ -1,7 +1,7 @@
1
1
  import { forwardRef, useMemo } from 'react';
2
2
  import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
3
3
  import { IconProps } from './types';
4
- import { iconStyles, buildIconSize } from './Icon.styles';
4
+ import { iconStyles } from './Icon.styles';
5
5
  import { useUnistyles } from 'react-native-unistyles';
6
6
 
7
7
  const Icon = forwardRef<any, IconProps>(({
@@ -14,18 +14,17 @@ const Icon = forwardRef<any, IconProps>(({
14
14
  accessibilityLabel,
15
15
  id,
16
16
  }: IconProps, ref) => {
17
+ const { theme } = useUnistyles();
17
18
 
18
-
19
- // Call dynamic style with variants
19
+ // Call dynamic style with variants - includes theme-reactive color
20
20
  const iconStyle = (iconStyles.icon as any)({ color, intent, size });
21
21
 
22
- const { theme } = useUnistyles();
23
-
24
22
  const iconSize = useMemo(() => {
25
- return buildIconSize(theme, size).width;
26
- }, [theme, size]);
23
+ return iconStyle.width;
24
+ }, [iconStyle]);
27
25
 
28
- // Get fontSize from styles for numeric size prop
26
+ // Extract color from iconStyle for explicit color prop (RN vector icons need this)
27
+ const iconColor = iconStyle.color;
29
28
 
30
29
  return (
31
30
  <MaterialCommunityIcons
@@ -33,6 +32,7 @@ const Icon = forwardRef<any, IconProps>(({
33
32
  nativeID={id}
34
33
  size={iconSize}
35
34
  name={name}
35
+ color={iconColor}
36
36
  style={[iconStyle, style]}
37
37
  testID={testID}
38
38
  accessibilityLabel={accessibilityLabel}
@@ -0,0 +1,81 @@
1
+ import { StyleSheet } from 'react-native-unistyles';
2
+ import { Theme, StylesheetStyles, Intent, Color, getColorFromString } from '@idealyst/theme';
3
+ import { buildSizeVariants } from '../utils/buildSizeVariants';
4
+ import { IconSizeVariant } from './types';
5
+ import { applyExtensions } from '../extensions/applyExtension';
6
+
7
+ type IconVariants = {
8
+ size: IconSizeVariant;
9
+ intent?: Intent;
10
+ color?: Color;
11
+ }
12
+
13
+ export type ExpandedIconStyles = StylesheetStyles<keyof IconVariants>;
14
+
15
+ export type IconStylesheet = {
16
+ icon: ExpandedIconStyles;
17
+ }
18
+
19
+ /**
20
+ * Create color variants for icon
21
+ */
22
+ function getIconColor(theme: Theme, color?: Color, intent?: Intent): string {
23
+ if (intent) {
24
+ return theme.intents[intent]?.primary
25
+ } else if (color) {
26
+ return getColorFromString(theme, color);
27
+ }
28
+ return theme.colors.text.primary;
29
+ }
30
+
31
+ export function buildIconSize(theme: Theme, size?: IconSizeVariant) {
32
+ // Handle direct numeric sizes
33
+ if (typeof size === 'number') {
34
+ return {
35
+ width: size,
36
+ height: size,
37
+ };
38
+ }
39
+
40
+ // Default to 'md' if size is undefined
41
+ const sizeKey = size || 'md';
42
+ const iconSize = theme.sizes.icon[sizeKey];
43
+
44
+ if (typeof iconSize === 'number') {
45
+ return {
46
+ width: iconSize,
47
+ height: iconSize,
48
+ };
49
+ }
50
+
51
+ return buildSizeVariants(theme, 'icon', (size) => ({
52
+ width: size.width,
53
+ height: size.height,
54
+ }))[sizeKey];
55
+ }
56
+
57
+ function createIconStyles(theme: Theme) {
58
+ return ({ color, intent, size }: Partial<IconVariants>) => {
59
+ const iconSize = buildIconSize(theme, size);
60
+ return {
61
+ width: iconSize.width,
62
+ height: iconSize.height,
63
+ color: getIconColor(theme, color, intent),
64
+ _web: {
65
+ display: 'inline-block',
66
+ verticalAlign: 'middle',
67
+ flexShrink: 0,
68
+ lineHeight: 0,
69
+ },
70
+ } as const;
71
+ }
72
+ }
73
+
74
+ // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
75
+ // transform on native cannot resolve function calls to extract variant structures.
76
+ export const iconStyles = StyleSheet.create((theme: Theme) => {
77
+ // Apply extensions to main visual elements
78
+ return applyExtensions('Icon', theme, {
79
+ icon: createIconStyles(theme),
80
+ });
81
+ });
@@ -1,85 +1,71 @@
1
+ /**
2
+ * Icon styles using defineStyle with dynamic functions.
3
+ */
1
4
  import { StyleSheet } from 'react-native-unistyles';
2
- import { Theme, StylesheetStyles, Intent, Color, getColorFromString } from '@idealyst/theme';
3
- import { buildSizeVariants } from '../utils/buildSizeVariants';
5
+ import { defineStyle, ThemeStyleWrapper, getColorFromString } from '@idealyst/theme';
6
+ import type { Theme as BaseTheme, Intent, Color } from '@idealyst/theme';
4
7
  import { IconSizeVariant } from './types';
5
- import { applyExtensions } from '../extensions/applyExtension';
6
8
 
7
- type IconVariants = {
9
+ // Required: Unistyles must see StyleSheet usage in original source to process this file
10
+ void StyleSheet;
11
+
12
+ // Wrap theme for $iterator support
13
+ type Theme = ThemeStyleWrapper<BaseTheme>;
14
+
15
+ export type IconVariants = {
8
16
  size: IconSizeVariant;
9
17
  intent?: Intent;
10
18
  color?: Color;
11
- }
12
-
13
- export type ExpandedIconStyles = StylesheetStyles<keyof IconVariants>;
19
+ };
14
20
 
15
- export type IconStylesheet = {
16
- icon: ExpandedIconStyles;
17
- }
21
+ export type IconDynamicProps = Partial<IconVariants>;
18
22
 
19
23
  /**
20
- * Create color variants for icon
24
+ * Icon styles with dynamic color/size handling.
21
25
  */
22
- function getIconColor(theme: Theme, color?: Color, intent?: Intent): string {
23
- if (intent) {
24
- return theme.intents[intent]?.primary
25
- } else if (color) {
26
- return getColorFromString(theme, color);
27
- }
28
- return theme.colors.text.primary;
29
- }
26
+ export const iconStyles = defineStyle('Icon', (theme: Theme) => ({
27
+ icon: ({ color, intent, size = 'md' }: IconDynamicProps) => {
28
+ // Handle size - can be a named size or number
29
+ let iconWidth: number;
30
+ let iconHeight: number;
30
31
 
31
- export function buildIconSize(theme: Theme, size?: IconSizeVariant) {
32
- // Handle direct numeric sizes
33
- if (typeof size === 'number') {
34
- return {
35
- width: size,
36
- height: size,
37
- };
38
- }
32
+ if (typeof size === 'number') {
33
+ iconWidth = size;
34
+ iconHeight = size;
35
+ } else {
36
+ const sizeKey = size || 'md';
37
+ const iconSize = theme.sizes.icon[sizeKey];
38
+ if (typeof iconSize === 'number') {
39
+ iconWidth = iconSize;
40
+ iconHeight = iconSize;
41
+ } else {
42
+ iconWidth = (iconSize?.width as number) ?? 24;
43
+ iconHeight = (iconSize?.height as number) ?? 24;
44
+ }
45
+ }
39
46
 
40
- // Default to 'md' if size is undefined
41
- const sizeKey = size || 'md';
42
- const iconSize = theme.sizes.icon[sizeKey];
47
+ // Get color - intent takes priority, then color prop, then default
48
+ const iconColor = intent
49
+ ? theme.intents[intent]?.primary
50
+ : color
51
+ ? getColorFromString(theme as unknown as BaseTheme, color)
52
+ : theme.colors.text.primary;
43
53
 
44
- if (typeof iconSize === 'number') {
45
54
  return {
46
- width: iconSize,
47
- height: iconSize,
48
- };
49
- }
50
-
51
- return buildSizeVariants(theme, 'icon', (size) => ({
52
- width: size.width,
53
- height: size.height,
54
- }))[sizeKey];
55
- }
56
-
57
- function createIconStyles(theme: Theme) {
58
- return ({ color, intent, size }: Partial<IconVariants>) => {
59
- const iconSize = buildIconSize(theme, size);
60
- return {
61
- width: iconSize.width,
62
- height: iconSize.height,
63
- color: getIconColor(theme, color, intent),
55
+ width: iconWidth,
56
+ height: iconHeight,
57
+ color: iconColor,
64
58
  _web: {
65
- display: 'inline-block',
59
+ fontSize: iconWidth,
60
+ width: '1em',
61
+ height: '1em',
62
+ display: 'inline-flex',
63
+ alignItems: 'center',
64
+ justifyContent: 'center',
66
65
  verticalAlign: 'middle',
67
66
  flexShrink: 0,
68
- lineHeight: 0,
67
+ lineHeight: 1,
69
68
  },
70
69
  } as const;
71
- }
72
- }
73
-
74
- // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
75
- // transform on native cannot resolve function calls to extract variant structures.
76
- export const iconStyles = StyleSheet.create((theme: Theme) => {
77
- // Apply extensions to main visual elements
78
- const extended = applyExtensions('Icon', theme, {
79
- icon: createIconStyles(theme),
80
- });
81
-
82
- return {
83
- ...extended,
84
- };
85
- });
70
+ },
71
+ }));