@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
@@ -1,263 +1,182 @@
1
- import { StyleSheet } from 'react-native-unistyles';
2
- import { Theme, Size, Styles} from '@idealyst/theme';
3
- import { buildSizeVariants } from '../utils/buildSizeVariants';
4
- import {
5
- buildMarginVariants,
6
- buildMarginVerticalVariants,
7
- buildMarginHorizontalVariants,
8
- } from '../utils/buildViewStyleVariants';
9
- import { SliderIntentVariant } from './types';
10
- import { applyExtensions } from '../extensions/applyExtension';
11
-
12
- /**
13
- * Create size variants for track
14
- */
15
- function createTrackSizeVariants(theme: Theme) {
16
- const variants = {} as Record<Size, Styles>;
17
- for (const sizeKey in theme.sizes.slider) {
18
- const size = sizeKey as Size;
19
- variants[size] = {
20
- height: theme.sizes.slider[size].trackHeight,
21
- };
22
- }
23
- return variants;
24
- }
25
-
26
1
  /**
27
- * Get filled track color based on intent
2
+ * Slider styles using defineStyle with dynamic props.
28
3
  */
29
- function getFilledTrackColor(theme: Theme, intent: SliderIntentVariant) {
30
- return theme.intents[intent].primary;
31
- }
4
+ import { StyleSheet } from 'react-native-unistyles';
5
+ import { defineStyle, ThemeStyleWrapper } from '@idealyst/theme';
6
+ import type { Theme as BaseTheme, Intent, Size } from '@idealyst/theme';
7
+ import { ViewStyleSize } from '../utils/viewStyleProps';
32
8
 
33
- /**
34
- * Create size variants for thumb
35
- */
36
- function createThumbSizeVariants(theme: Theme) {
37
- return buildSizeVariants(theme, 'slider', (size) => ({
38
- width: size.thumbSize,
39
- height: size.thumbSize,
40
- }));
41
- }
9
+ // Required: Unistyles must see StyleSheet usage in original source to process this file
10
+ void StyleSheet;
42
11
 
43
- /**
44
- * Get thumb border color based on intent
45
- */
46
- function getThumbBorderColor(theme: Theme, intent: SliderIntentVariant) {
47
- return theme.intents[intent].primary;
48
- }
12
+ // Wrap theme for $iterator support
13
+ type Theme = ThemeStyleWrapper<BaseTheme>;
49
14
 
50
- /**
51
- * Create size variants for thumb icon
52
- */
53
- function createThumbIconSizeVariants(theme: Theme) {
54
- return buildSizeVariants(theme, 'slider', (size) => ({
55
- width: size.thumbIconSize,
56
- height: size.thumbIconSize,
57
- minWidth: size.thumbIconSize,
58
- maxWidth: size.thumbIconSize,
59
- minHeight: size.thumbIconSize,
60
- maxHeight: size.thumbIconSize,
61
- }));
62
- }
15
+ export type SliderDynamicProps = {
16
+ size?: Size;
17
+ intent?: Intent;
18
+ disabled?: boolean;
19
+ margin?: ViewStyleSize;
20
+ marginVertical?: ViewStyleSize;
21
+ marginHorizontal?: ViewStyleSize;
22
+ };
63
23
 
64
24
  /**
65
- * Get thumb icon color based on intent
25
+ * Slider styles with intent/disabled handling.
66
26
  */
67
- function getThumbIconColor(theme: Theme, intent: SliderIntentVariant){
68
- return theme.intents[intent].primary;
69
- }
70
-
71
- /**
72
- * Create size variants for mark
73
- */
74
- function createMarkSizeVariants(theme: Theme) {
75
- return buildSizeVariants(theme, 'slider', (size) => ({
76
- height: size.markHeight,
77
- }));
78
- }
79
-
80
- const createFilledTrackStyles = (theme: Theme) => {
81
- return ({ intent }: { intent: SliderIntentVariant }) => {
82
- return {
83
- position: 'absolute',
84
- height: '100%',
85
- borderRadius: 9999,
86
- top: 0,
87
- left: 0,
88
- backgroundColor: getFilledTrackColor(theme, intent),
89
- } as const;
90
- }
91
- }
92
-
93
- const createThumbStyles = (theme: Theme) => {
94
- return ({ intent, disabled }: { intent: SliderIntentVariant, disabled: boolean }) => {
95
- return {
96
- position: 'absolute',
97
- backgroundColor: theme.colors.surface.primary,
98
- borderRadius: 9999,
99
- borderWidth: 2,
100
- borderStyle: 'solid',
101
- borderColor: getThumbBorderColor(theme, intent),
102
- top: '50%',
103
- display: 'flex',
104
- alignItems: 'center',
105
- justifyContent: 'center',
106
- shadowColor: '#000',
107
- shadowOffset: { width: 0, height: 2 },
108
- shadowOpacity: 0.2,
109
- shadowRadius: 4,
110
- elevation: 2,
111
- variants: {
112
- size: createThumbSizeVariants(theme),
113
- disabled: {
114
- true: {
115
- opacity: 0.6,
116
- _web: {
117
- cursor: 'not-allowed',
118
- },
119
- },
120
- false: {
121
- opacity: 1,
122
- _web: {
123
- cursor: 'grab',
124
- _hover: {
125
- transform: 'translate(-50%, -50%) scale(1.05)',
126
- },
127
- _active: {
128
- cursor: 'grabbing',
129
- transform: 'translate(-50%, -50%) scale(1.1)',
130
- },
131
- },
132
- },
133
- },
134
- },
135
- _web: {
136
- boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)',
137
- transform: 'translate(-50%, -50%)',
138
- transition: 'transform 0.15s ease, box-shadow 0.2s ease',
139
- },
140
- } as const;
141
- }
142
- }
143
-
144
- const createThumbIconStyles = (theme: Theme) => {
145
- return ({ intent }: { intent: SliderIntentVariant }) => {
146
- return {
147
- display: 'flex',
148
- alignItems: 'center',
149
- justifyContent: 'center',
150
- flexShrink: 0,
151
- color: getThumbIconColor(theme, intent),
152
- variants: {
153
- size: createThumbIconSizeVariants(theme),
154
- },
155
- } as const;
156
- }
157
- }
158
-
159
- // Container style creator for extension support
160
- function createContainerStyles(theme: Theme) {
161
- return () => ({
27
+ export const sliderStyles = defineStyle('Slider', (theme: Theme) => ({
28
+ container: (_props: SliderDynamicProps) => ({
162
29
  gap: 4,
163
30
  paddingVertical: 8,
164
31
  variants: {
165
- margin: buildMarginVariants(theme),
166
- marginVertical: buildMarginVerticalVariants(theme),
167
- marginHorizontal: buildMarginHorizontalVariants(theme),
32
+ margin: {
33
+ margin: theme.sizes.$view.padding,
34
+ },
35
+ marginVertical: {
36
+ marginVertical: theme.sizes.$view.padding,
37
+ },
38
+ marginHorizontal: {
39
+ marginHorizontal: theme.sizes.$view.padding,
40
+ },
168
41
  },
169
- });
170
- }
42
+ }),
43
+
44
+ sliderWrapper: (_props: SliderDynamicProps) => ({
45
+ position: 'relative' as const,
46
+ paddingVertical: 4,
47
+ }),
171
48
 
172
- // Track style creator for extension support
173
- function createTrackStyles(theme: Theme) {
174
- return () => ({
49
+ track: ({ disabled = false }: SliderDynamicProps) => ({
175
50
  backgroundColor: theme.colors.surface.tertiary,
176
51
  borderRadius: 9999,
177
52
  position: 'relative' as const,
53
+ opacity: disabled ? 0.5 : 1,
178
54
  variants: {
179
- size: createTrackSizeVariants(theme),
180
- disabled: {
181
- true: {
182
- opacity: 0.5,
183
- _web: { cursor: 'not-allowed' },
184
- },
185
- false: {
186
- opacity: 1,
187
- _web: { cursor: 'pointer' },
188
- },
55
+ size: {
56
+ height: theme.sizes.$slider.trackHeight,
189
57
  },
190
- } as const,
191
- });
192
- }
58
+ },
59
+ _web: {
60
+ cursor: disabled ? 'not-allowed' : 'pointer',
61
+ },
62
+ }),
193
63
 
194
- // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel transform on native cannot resolve function calls to extract variant structures.
195
- export const sliderStyles = StyleSheet.create((theme: Theme) => {
196
- // Apply extensions to main visual elements
197
- const extended = applyExtensions('Slider', theme, {
198
- container: createContainerStyles(theme),
199
- track: createTrackStyles(theme),
200
- filledTrack: createFilledTrackStyles(theme),
201
- thumb: createThumbStyles(theme),
202
- thumbIcon: createThumbIconStyles(theme),
203
- });
64
+ filledTrack: ({ intent = 'primary' }: SliderDynamicProps) => ({
65
+ position: 'absolute' as const,
66
+ height: '100%',
67
+ borderRadius: 9999,
68
+ top: 0,
69
+ left: 0,
70
+ backgroundColor: theme.intents[intent].primary,
71
+ }),
204
72
 
205
- return {
206
- ...extended,
207
- // Minor utility styles
208
- sliderWrapper: {
209
- position: 'relative',
210
- paddingVertical: 4,
211
- },
212
- thumbActive: {
213
- _web: {
214
- transform: 'translate(-50%, -50%) scale(1.1)',
73
+ thumb: ({ intent = 'primary', disabled = false }: SliderDynamicProps) => ({
74
+ position: 'absolute' as const,
75
+ backgroundColor: theme.colors.surface.primary,
76
+ borderRadius: 9999,
77
+ borderWidth: 2,
78
+ borderStyle: 'solid' as const,
79
+ borderColor: theme.intents[intent].primary,
80
+ top: '50%',
81
+ display: 'flex' as const,
82
+ alignItems: 'center' as const,
83
+ justifyContent: 'center' as const,
84
+ shadowColor: '#000',
85
+ shadowOffset: { width: 0, height: 2 },
86
+ shadowOpacity: 0.2,
87
+ shadowRadius: 4,
88
+ elevation: 2,
89
+ opacity: disabled ? 0.6 : 1,
90
+ variants: {
91
+ size: {
92
+ width: theme.sizes.$slider.thumbSize,
93
+ height: theme.sizes.$slider.thumbSize,
215
94
  },
216
95
  },
217
- valueLabel: {
218
- fontSize: 12,
219
- fontWeight: '600',
220
- color: theme.colors.text.primary,
221
- textAlign: 'center',
222
- },
223
- minMaxLabels: {
224
- flexDirection: 'row',
225
- justifyContent: 'space-between',
226
- marginTop: 4,
96
+ _web: {
97
+ boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)',
98
+ transform: 'translate(-50%, -50%)',
99
+ transition: 'transform 0.15s ease, box-shadow 0.2s ease',
100
+ cursor: disabled ? 'not-allowed' : 'grab',
101
+ _hover: disabled ? {} : { transform: 'translate(-50%, -50%) scale(1.05)' },
102
+ _active: disabled ? {} : { cursor: 'grabbing', transform: 'translate(-50%, -50%) scale(1.1)' },
227
103
  },
228
- minMaxLabel: {
229
- fontSize: 12,
230
- color: theme.colors.text.secondary,
104
+ }),
105
+
106
+ thumbActive: (_props: SliderDynamicProps) => ({
107
+ _web: {
108
+ transform: 'translate(-50%, -50%) scale(1.1)',
231
109
  },
232
- mark: {
233
- position: 'absolute',
234
- width: 2,
235
- backgroundColor: theme.colors.border.secondary,
236
- top: '50%',
237
- variants: {
238
- size: createMarkSizeVariants(theme),
110
+ }),
111
+
112
+ thumbIcon: ({ intent = 'primary' }: SliderDynamicProps) => ({
113
+ display: 'flex' as const,
114
+ alignItems: 'center' as const,
115
+ justifyContent: 'center' as const,
116
+ flexShrink: 0,
117
+ color: theme.intents[intent].primary,
118
+ variants: {
119
+ size: {
120
+ width: theme.sizes.$slider.thumbIconSize,
121
+ height: theme.sizes.$slider.thumbIconSize,
122
+ minWidth: theme.sizes.$slider.thumbIconSize,
123
+ maxWidth: theme.sizes.$slider.thumbIconSize,
124
+ minHeight: theme.sizes.$slider.thumbIconSize,
125
+ maxHeight: theme.sizes.$slider.thumbIconSize,
239
126
  },
240
- _web: {
241
- transform: 'translate(-50%, -50%)',
127
+ },
128
+ }),
129
+
130
+ valueLabel: (_props: SliderDynamicProps) => ({
131
+ fontSize: 12,
132
+ fontWeight: '600' as const,
133
+ color: theme.colors.text.primary,
134
+ textAlign: 'center' as const,
135
+ }),
136
+
137
+ minMaxLabels: (_props: SliderDynamicProps) => ({
138
+ flexDirection: 'row' as const,
139
+ justifyContent: 'space-between' as const,
140
+ marginTop: 4,
141
+ }),
142
+
143
+ minMaxLabel: (_props: SliderDynamicProps) => ({
144
+ fontSize: 12,
145
+ color: theme.colors.text.secondary,
146
+ }),
147
+
148
+ marks: (_props: SliderDynamicProps) => ({
149
+ position: 'absolute' as const,
150
+ width: '100%',
151
+ height: '100%',
152
+ top: 0,
153
+ left: 0,
154
+ }),
155
+
156
+ mark: (_props: SliderDynamicProps) => ({
157
+ position: 'absolute' as const,
158
+ width: 2,
159
+ backgroundColor: theme.colors.border.secondary,
160
+ top: '50%',
161
+ variants: {
162
+ size: {
163
+ height: theme.sizes.$slider.markHeight,
242
164
  },
243
165
  },
244
- marks: {
245
- position: 'absolute',
246
- width: '100%',
247
- height: '100%',
248
- top: 0,
249
- left: 0,
166
+ _web: {
167
+ transform: 'translate(-50%, -50%)',
250
168
  },
251
- markLabel: {
252
- position: 'absolute',
253
- fontSize: 10,
254
- color: theme.colors.text.secondary,
255
- top: '100%',
256
- marginTop: 4,
257
- _web: {
258
- transform: 'translateX(-50%)',
259
- whiteSpace: 'nowrap',
260
- },
169
+ }),
170
+
171
+ markLabel: (_props: SliderDynamicProps) => ({
172
+ position: 'absolute' as const,
173
+ fontSize: 10,
174
+ color: theme.colors.text.secondary,
175
+ top: '100%',
176
+ marginTop: 4,
177
+ _web: {
178
+ transform: 'translateX(-50%)',
179
+ whiteSpace: 'nowrap',
261
180
  },
262
- };
263
- });
181
+ }),
182
+ }));
@@ -118,9 +118,11 @@ const Switch = forwardRef<ComponentRef<typeof Pressable>, SwitchProps>(({
118
118
  };
119
119
  });
120
120
 
121
- // Get dynamic styles
122
- const switchTrackStyle = (switchStyles.switchTrack as any)({ checked, intent });
121
+ // Get dynamic styles - call as functions for theme reactivity
122
+ const switchTrackStyle = (switchStyles.switchTrack as any)({ checked, intent, disabled });
123
123
  const containerStyle = (switchStyles.container as any)({});
124
+ const switchContainerStyle = (switchStyles.switchContainer as any)({});
125
+ const labelStyle = (switchStyles.label as any)({ disabled, labelPosition });
124
126
 
125
127
  const switchElement = (
126
128
  <Pressable
@@ -128,7 +130,7 @@ const Switch = forwardRef<ComponentRef<typeof Pressable>, SwitchProps>(({
128
130
  nativeID={!label ? id : undefined}
129
131
  onPress={handlePress}
130
132
  disabled={disabled}
131
- style={switchStyles.switchContainer}
133
+ style={switchContainerStyle}
132
134
  testID={testID}
133
135
  {...nativeA11yProps}
134
136
  >
@@ -165,11 +167,11 @@ const Switch = forwardRef<ComponentRef<typeof Pressable>, SwitchProps>(({
165
167
  style={[containerStyle, style]}
166
168
  >
167
169
  {labelPosition === 'left' && (
168
- <Text style={switchStyles.label}>{label}</Text>
170
+ <Text style={labelStyle}>{label}</Text>
169
171
  )}
170
172
  {switchElement}
171
173
  {labelPosition === 'right' && (
172
- <Text style={switchStyles.label}>{label}</Text>
174
+ <Text style={labelStyle}>{label}</Text>
173
175
  )}
174
176
  </Pressable>
175
177
  );
@@ -0,0 +1,203 @@
1
+ import { StyleSheet } from 'react-native-unistyles';
2
+ import { Theme, StylesheetStyles, Intent, Size } from '@idealyst/theme';
3
+ import { buildSizeVariants } from '../utils/buildSizeVariants';
4
+ import {
5
+ buildMarginVariants,
6
+ buildMarginVerticalVariants,
7
+ buildMarginHorizontalVariants,
8
+ } from '../utils/buildViewStyleVariants';
9
+ import { SwitchIntentVariant, SwitchSizeVariant } from './types';
10
+ import { applyExtensions } from '../extensions/applyExtension';
11
+
12
+ function createTrackSizeVariants(theme: Theme) {
13
+ return buildSizeVariants(theme, 'switch', (size) => ({
14
+ width: size.trackWidth,
15
+ height: size.trackHeight,
16
+ }));
17
+ }
18
+
19
+ function getTrackBackgroundColor(theme: Theme, checked: boolean, intent: SwitchIntentVariant) {
20
+ if (checked) {
21
+ return theme.intents[intent].primary;
22
+ }
23
+ return theme.colors.border.secondary;
24
+ }
25
+
26
+ function createThumbSizeVariants(theme: Theme) {
27
+ return buildSizeVariants(theme, 'switch', (size) => ({
28
+ width: size.thumbSize,
29
+ height: size.thumbSize,
30
+ left: 2,
31
+ }));
32
+ }
33
+
34
+ function getThumbTransform(theme: Theme, size: SwitchSizeVariant, checked: boolean) {
35
+ const sizeValue = theme.sizes.switch[size];
36
+ const translateX = checked ? sizeValue.translateX : 0;
37
+ return `translateY(-50%) translateX(${translateX}px)`;
38
+ }
39
+
40
+ function createThumbIconSizeVariants(theme: Theme) {
41
+ return buildSizeVariants(theme, 'switch', (size) => ({
42
+ width: size.thumbIconSize,
43
+ height: size.thumbIconSize,
44
+ }));
45
+ }
46
+
47
+ function getThumbIconColor(theme: Theme, checked: boolean, intent: SwitchIntentVariant) {
48
+ if (checked) {
49
+ return theme.intents[intent].primary;
50
+ }
51
+ return theme.colors.border.secondary;
52
+ }
53
+
54
+ function createSwitchTrackStyles(theme: Theme) {
55
+ return ({ checked, intent }: { checked: boolean, intent: SwitchIntentVariant }) => {
56
+ return {
57
+ borderRadius: 9999,
58
+ position: 'relative',
59
+ backgroundColor: getTrackBackgroundColor(theme, checked, intent),
60
+ variants: {
61
+ size: createTrackSizeVariants(theme),
62
+ disabled: {
63
+ true: {
64
+ opacity: 0.5,
65
+ _web: {
66
+ cursor: 'not-allowed',
67
+ },
68
+ },
69
+ false: {
70
+ opacity: 1,
71
+ _web: {
72
+ cursor: 'pointer',
73
+ _hover: {
74
+ opacity: 0.9,
75
+ },
76
+ _active: {
77
+ opacity: 0.8,
78
+ },
79
+ },
80
+ },
81
+ },
82
+ } as const,
83
+ _web: {
84
+ transition: 'background-color 0.2s ease',
85
+ },
86
+ } as const;
87
+ }
88
+ }
89
+
90
+ function createSwitchThumbStyles(theme: Theme) {
91
+ return ({ size, checked }: { size: SwitchSizeVariant, checked: boolean }) => {
92
+ return {
93
+ position: 'absolute',
94
+ backgroundColor: theme.colors.surface.primary,
95
+ borderRadius: 9999,
96
+ top: '50%',
97
+ display: 'flex',
98
+ alignItems: 'center',
99
+ justifyContent: 'center',
100
+ shadowColor: '#000',
101
+ shadowOffset: { width: 0, height: 1 },
102
+ shadowOpacity: 0.2,
103
+ shadowRadius: 3,
104
+ elevation: 2,
105
+ variants: {
106
+ size: createThumbSizeVariants(theme),
107
+ },
108
+ _web: {
109
+ boxShadow: '0 1px 3px rgba(0, 0, 0, 0.2)',
110
+ transition: 'transform 0.2s ease',
111
+ transform: getThumbTransform(theme, size, checked),
112
+ },
113
+ } as const;
114
+ }
115
+ }
116
+
117
+ function createThumbIconStyles(theme: Theme) {
118
+ return ({ checked, intent }: { checked: boolean, intent: SwitchIntentVariant }) => {
119
+ return {
120
+ display: 'flex',
121
+ alignItems: 'center',
122
+ justifyContent: 'center',
123
+ color: getThumbIconColor(theme, checked, intent),
124
+ variants: {
125
+ size: createThumbIconSizeVariants(theme),
126
+ },
127
+ } as const;
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Create container styles
133
+ */
134
+ function createContainerStyles(theme: Theme) {
135
+ return () => ({
136
+ flexDirection: 'row' as const,
137
+ alignItems: 'center' as const,
138
+ gap: 8,
139
+ variants: {
140
+ margin: buildMarginVariants(theme),
141
+ marginVertical: buildMarginVerticalVariants(theme),
142
+ marginHorizontal: buildMarginHorizontalVariants(theme),
143
+ },
144
+ });
145
+ }
146
+
147
+ /**
148
+ * Create switch container styles
149
+ */
150
+ function createSwitchContainerStyles() {
151
+ return () => ({
152
+ justifyContent: 'center' as const,
153
+ _web: {
154
+ border: 'none',
155
+ padding: 0,
156
+ backgroundColor: 'transparent',
157
+ width: 'fit-content',
158
+ },
159
+ });
160
+ }
161
+
162
+ /**
163
+ * Create label styles
164
+ */
165
+ function createLabelStyles(theme: Theme) {
166
+ return () => ({
167
+ fontSize: 14,
168
+ color: theme.colors.text.primary,
169
+ variants: {
170
+ disabled: {
171
+ true: {
172
+ opacity: 0.5,
173
+ },
174
+ false: {
175
+ opacity: 1,
176
+ },
177
+ },
178
+ position: {
179
+ left: {
180
+ marginRight: 8,
181
+ },
182
+ right: {
183
+ marginLeft: 8,
184
+ },
185
+ },
186
+ } as const,
187
+ });
188
+ }
189
+
190
+ // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
191
+ // transform on native cannot resolve function calls to extract variant structures.
192
+ export const switchStyles = StyleSheet.create((theme: Theme) => {
193
+ // Apply extensions to main visual elements
194
+
195
+ return applyExtensions('Switch', theme, {container: createContainerStyles(theme),
196
+ switchTrack: createSwitchTrackStyles(theme),
197
+ switchThumb: createSwitchThumbStyles(theme),
198
+ // Additional styles (merged from return)
199
+ // Minor utility styles (not extended)
200
+ switchContainer: createSwitchContainerStyles()(),
201
+ thumbIcon: createThumbIconStyles(theme),
202
+ label: createLabelStyles(theme)()});
203
+ });