@idealyst/components 1.1.6 → 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 (144) hide show
  1. package/package.json +8 -3
  2. package/src/Accordion/Accordion.native.tsx +22 -14
  3. package/src/Accordion/Accordion.styles.old.tsx +298 -0
  4. package/src/Accordion/Accordion.styles.tsx +139 -248
  5. package/src/Accordion/Accordion.web.tsx +12 -7
  6. package/src/ActivityIndicator/ActivityIndicator.native.tsx +3 -2
  7. package/src/ActivityIndicator/ActivityIndicator.styles.old.tsx +94 -0
  8. package/src/ActivityIndicator/ActivityIndicator.styles.tsx +43 -62
  9. package/src/ActivityIndicator/ActivityIndicator.web.tsx +2 -2
  10. package/src/Alert/Alert.native.tsx +26 -15
  11. package/src/Alert/Alert.styles.old.tsx +209 -0
  12. package/src/Alert/Alert.styles.tsx +108 -281
  13. package/src/Alert/Alert.web.tsx +6 -10
  14. package/src/Avatar/Avatar.native.tsx +5 -2
  15. package/src/Avatar/Avatar.styles.old.tsx +99 -0
  16. package/src/Avatar/Avatar.styles.tsx +47 -62
  17. package/src/Avatar/Avatar.web.tsx +2 -2
  18. package/src/Badge/Badge.native.tsx +2 -2
  19. package/src/Badge/Badge.styles.old.tsx +157 -0
  20. package/src/Badge/Badge.styles.tsx +69 -108
  21. package/src/Badge/Badge.web.tsx +6 -6
  22. package/src/Breadcrumb/Breadcrumb.native.tsx +12 -5
  23. package/src/Breadcrumb/Breadcrumb.styles.old.tsx +231 -0
  24. package/src/Breadcrumb/Breadcrumb.styles.tsx +93 -209
  25. package/src/Breadcrumb/Breadcrumb.web.tsx +39 -27
  26. package/src/Button/Button.native.tsx +39 -14
  27. package/src/Button/Button.styles.tsx +99 -253
  28. package/src/Button/Button.web.tsx +10 -8
  29. package/src/Card/Card.native.tsx +8 -4
  30. package/src/Card/Card.styles.old.tsx +160 -0
  31. package/src/Card/Card.styles.tsx +107 -142
  32. package/src/Card/Card.web.tsx +6 -4
  33. package/src/Checkbox/Checkbox.native.tsx +14 -6
  34. package/src/Checkbox/Checkbox.styles.old.tsx +271 -0
  35. package/src/Checkbox/Checkbox.styles.tsx +109 -197
  36. package/src/Checkbox/Checkbox.web.tsx +7 -7
  37. package/src/Chip/Chip.native.tsx +5 -5
  38. package/src/Chip/Chip.styles.old.tsx +184 -0
  39. package/src/Chip/Chip.styles.tsx +34 -22
  40. package/src/Chip/Chip.web.tsx +5 -5
  41. package/src/Dialog/Dialog.native.tsx +16 -7
  42. package/src/Dialog/Dialog.styles.old.tsx +202 -0
  43. package/src/Dialog/Dialog.styles.tsx +108 -132
  44. package/src/Dialog/Dialog.web.tsx +4 -4
  45. package/src/Divider/Divider.native.tsx +29 -42
  46. package/src/Divider/Divider.styles.old.tsx +172 -0
  47. package/src/Divider/Divider.styles.tsx +116 -242
  48. package/src/Divider/Divider.web.tsx +17 -14
  49. package/src/Icon/Icon.native.tsx +12 -4
  50. package/src/Icon/Icon.styles.old.tsx +81 -0
  51. package/src/Icon/Icon.styles.tsx +52 -60
  52. package/src/Icon/Icon.web.tsx +43 -7
  53. package/src/Icon/IconSvg/IconSvg.web.tsx +2 -0
  54. package/src/Image/Image.styles.old.tsx +69 -0
  55. package/src/Image/Image.styles.tsx +45 -43
  56. package/src/Input/Input.native.tsx +140 -56
  57. package/src/Input/Input.styles.old.tsx +289 -0
  58. package/src/Input/Input.styles.tsx +177 -228
  59. package/src/Input/Input.web.tsx +5 -8
  60. package/src/Link/Link.native.tsx +4 -1
  61. package/src/List/List.native.tsx +5 -2
  62. package/src/List/List.styles.old.tsx +242 -0
  63. package/src/List/List.styles.tsx +178 -240
  64. package/src/List/ListItem.native.tsx +16 -8
  65. package/src/List/ListItem.web.tsx +26 -15
  66. package/src/Menu/Menu.native.tsx +1 -1
  67. package/src/Menu/Menu.styles.old.tsx +197 -0
  68. package/src/Menu/Menu.styles.tsx +90 -156
  69. package/src/Menu/Menu.web.tsx +2 -2
  70. package/src/Menu/MenuItem.native.tsx +9 -5
  71. package/src/Menu/MenuItem.styles.old.tsx +114 -0
  72. package/src/Menu/MenuItem.styles.tsx +71 -104
  73. package/src/Menu/MenuItem.web.tsx +23 -5
  74. package/src/Popover/Popover.native.tsx +10 -4
  75. package/src/Popover/Popover.styles.old.tsx +135 -0
  76. package/src/Popover/Popover.styles.tsx +46 -96
  77. package/src/Popover/Popover.web.tsx +1 -1
  78. package/src/Pressable/Pressable.native.tsx +3 -1
  79. package/src/Pressable/Pressable.styles.old.tsx +27 -0
  80. package/src/Pressable/Pressable.styles.tsx +35 -20
  81. package/src/Pressable/Pressable.web.tsx +1 -1
  82. package/src/Progress/Progress.native.tsx +15 -6
  83. package/src/Progress/Progress.styles.old.tsx +200 -0
  84. package/src/Progress/Progress.styles.tsx +69 -118
  85. package/src/Progress/Progress.web.tsx +10 -9
  86. package/src/RadioButton/RadioButton.native.tsx +10 -4
  87. package/src/RadioButton/RadioButton.styles.old.tsx +175 -0
  88. package/src/RadioButton/RadioButton.styles.tsx +81 -145
  89. package/src/RadioButton/RadioButton.web.tsx +4 -4
  90. package/src/SVGImage/SVGImage.styles.old.tsx +86 -0
  91. package/src/SVGImage/SVGImage.styles.tsx +35 -66
  92. package/src/Screen/Screen.native.tsx +30 -27
  93. package/src/Screen/Screen.styles.old.tsx +87 -0
  94. package/src/Screen/Screen.styles.tsx +120 -71
  95. package/src/Screen/Screen.web.tsx +2 -2
  96. package/src/Select/Select.native.tsx +44 -29
  97. package/src/Select/Select.styles.old.tsx +353 -0
  98. package/src/Select/Select.styles.tsx +244 -293
  99. package/src/Select/Select.web.tsx +5 -5
  100. package/src/Skeleton/Skeleton.styles.old.tsx +67 -0
  101. package/src/Skeleton/Skeleton.styles.tsx +31 -43
  102. package/src/Slider/Slider.native.tsx +9 -5
  103. package/src/Slider/Slider.styles.old.tsx +259 -0
  104. package/src/Slider/Slider.styles.tsx +157 -227
  105. package/src/Slider/Slider.web.tsx +5 -5
  106. package/src/Switch/Switch.native.tsx +11 -5
  107. package/src/Switch/Switch.styles.old.tsx +203 -0
  108. package/src/Switch/Switch.styles.tsx +103 -149
  109. package/src/Switch/Switch.web.tsx +8 -8
  110. package/src/TabBar/TabBar.native.tsx +24 -31
  111. package/src/TabBar/TabBar.styles.old.tsx +343 -0
  112. package/src/TabBar/TabBar.styles.tsx +204 -494
  113. package/src/TabBar/TabBar.web.tsx +21 -33
  114. package/src/Table/Table.native.tsx +18 -9
  115. package/src/Table/Table.styles.old.tsx +311 -0
  116. package/src/Table/Table.styles.tsx +151 -278
  117. package/src/Table/Table.web.tsx +1 -1
  118. package/src/Text/Text.native.tsx +1 -4
  119. package/src/Text/Text.style.demo.tsx +16 -0
  120. package/src/Text/Text.styles.old.tsx +219 -0
  121. package/src/Text/Text.styles.tsx +94 -78
  122. package/src/Text/Text.web.tsx +2 -2
  123. package/src/Text/index.ts +1 -0
  124. package/src/TextArea/TextArea.styles.old.tsx +213 -0
  125. package/src/TextArea/TextArea.styles.tsx +101 -157
  126. package/src/Tooltip/Tooltip.native.tsx +2 -2
  127. package/src/Tooltip/Tooltip.styles.old.tsx +82 -0
  128. package/src/Tooltip/Tooltip.styles.tsx +38 -53
  129. package/src/Tooltip/Tooltip.web.tsx +2 -2
  130. package/src/Video/Video.styles.old.tsx +51 -0
  131. package/src/Video/Video.styles.tsx +32 -28
  132. package/src/View/View.native.tsx +12 -12
  133. package/src/View/View.styles.old.tsx +125 -0
  134. package/src/View/View.styles.tsx +84 -103
  135. package/src/View/View.web.tsx +14 -2
  136. package/src/examples/CardExamples.tsx +0 -6
  137. package/src/extensions/applyExtension.ts +210 -0
  138. package/src/extensions/extendComponent.ts +438 -0
  139. package/src/extensions/index.ts +102 -0
  140. package/src/extensions/types.ts +497 -0
  141. package/src/globals.ts +16 -0
  142. package/src/index.native.ts +4 -0
  143. package/src/index.ts +28 -0
  144. package/src/utils/deepMerge.ts +54 -2
@@ -38,11 +38,11 @@ const Avatar = forwardRef<HTMLDivElement, AvatarProps>(({
38
38
  shape,
39
39
  });
40
40
 
41
- const avatarStyleArray = [avatarStyles.avatar, style];
41
+ const avatarStyleArray = [(avatarStyles.avatar as any)({}), style];
42
42
  const avatarProps = getWebProps(avatarStyleArray);
43
43
 
44
44
  // Generate fallback text styles with proper theming and size
45
- const fallbackStyleArray = [avatarStyles.fallback];
45
+ const fallbackStyleArray = [(avatarStyles.fallback as any)({})];
46
46
  const fallbackProps = getWebProps(fallbackStyleArray);
47
47
 
48
48
  const handleImageError = () => {
@@ -21,8 +21,8 @@ const Badge = forwardRef<View, BadgeProps>(({
21
21
  });
22
22
 
23
23
  // Call dynamic styles with color variant
24
- const badgeStyle = badgeStyles.badge({ color });
25
- const textStyle = badgeStyles.text({ color });
24
+ const badgeStyle = (badgeStyles.badge as any)({ color });
25
+ const textStyle = (badgeStyles.text as any)({ color });
26
26
 
27
27
  // Map badge size to icon size
28
28
  const iconSize = size === 'sm' ? 12 : size === 'md' ? 14 : 16;
@@ -0,0 +1,157 @@
1
+ import { StyleSheet } from 'react-native-unistyles';
2
+ import { Theme, StylesheetStyles, getColorFromString, Size, Color } from '@idealyst/theme';
3
+ import { buildSizeVariants } from '../utils/buildSizeVariants';
4
+ import { applyExtensions } from '../extensions/applyExtension';
5
+
6
+ type BadgeType = 'filled' | 'outlined' | 'dot';
7
+
8
+ type BadgeVariants = {
9
+ size: Size;
10
+ type: BadgeType;
11
+ color: Color;
12
+ }
13
+
14
+ export type ExpandedBadgeStyles = StylesheetStyles<keyof BadgeVariants>;
15
+
16
+ export type BadgeStylesheet = {
17
+ badge: ExpandedBadgeStyles;
18
+ content: ExpandedBadgeStyles;
19
+ icon: ExpandedBadgeStyles;
20
+ text: ExpandedBadgeStyles;
21
+ }
22
+
23
+ /**
24
+ * Create type variants for badge
25
+ */
26
+ function createBadgeTypeVariants(theme: Theme, color: Color) {
27
+ const colorValue = getColorFromString(theme, color);
28
+ return {
29
+ filled: {
30
+ borderWidth: 0,
31
+ backgroundColor: colorValue,
32
+ },
33
+ outlined: {
34
+ backgroundColor: 'transparent',
35
+ borderWidth: 2,
36
+ borderStyle: 'solid',
37
+ borderColor: colorValue,
38
+ },
39
+ dot: {
40
+ minWidth: 8,
41
+ width: 8,
42
+ height: 8,
43
+ paddingHorizontal: 0,
44
+ paddingVertical: 0,
45
+ backgroundColor: colorValue,
46
+ },
47
+ } as const;
48
+ }
49
+
50
+ /**
51
+ * Create type variants for badge text
52
+ */
53
+ function createTextTypeVariants(theme: Theme, color: Color){
54
+ const colorValue = getColorFromString(theme, color);
55
+ return {
56
+ filled: {
57
+ color: theme.colors.text.inverse,
58
+ },
59
+ outlined: {
60
+ color: colorValue,
61
+ },
62
+ dot: {
63
+ display: 'none',
64
+ },
65
+ } as const;
66
+ }
67
+
68
+ /**
69
+ * Generate badge container styles
70
+ */
71
+ function createBadgeStyles(theme: Theme) {
72
+ return ({ color }: Partial<BadgeVariants>) => {
73
+ return {
74
+ alignItems: 'center',
75
+ justifyContent: 'center',
76
+ borderRadius: 9999,
77
+ variants: {
78
+ size: buildSizeVariants(theme, 'badge', (size) => ({
79
+ minWidth: size.minWidth,
80
+ height: size.height,
81
+ paddingHorizontal: size.paddingHorizontal,
82
+ })),
83
+ type: createBadgeTypeVariants(theme, color),
84
+ },
85
+ _web: {
86
+ display: 'flex',
87
+ alignItems: 'center',
88
+ justifyContent: 'center',
89
+ boxSizing: 'border-box',
90
+ fontWeight: '600',
91
+ lineHeight: 1,
92
+ },
93
+ } as const;
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Generate badge text styles
99
+ */
100
+ function createTextStyles(theme: Theme) {
101
+ return ({ color }: Partial<BadgeVariants>) => {
102
+ return {
103
+ fontWeight: '600',
104
+ textAlign: 'center',
105
+ variants: {
106
+ size: buildSizeVariants(theme, 'badge', (size) => ({
107
+ fontSize: size.fontSize,
108
+ lineHeight: size.lineHeight,
109
+ })),
110
+ type: createTextTypeVariants(theme, color),
111
+ },
112
+ } as const;
113
+ };
114
+ }
115
+
116
+ /**
117
+ * Create content styles
118
+ */
119
+ function createContentStyles() {
120
+ return () => ({
121
+ display: 'flex' as const,
122
+ flexDirection: 'row' as const,
123
+ alignItems: 'center' as const,
124
+ justifyContent: 'center' as const,
125
+ gap: 4,
126
+ });
127
+ }
128
+
129
+ /**
130
+ * Create icon styles
131
+ */
132
+ function createIconStyles(theme: Theme) {
133
+ return () => ({
134
+ display: 'flex' as const,
135
+ alignItems: 'center' as const,
136
+ justifyContent: 'center' as const,
137
+ variants: {
138
+ size: buildSizeVariants(theme, 'badge', (size) => ({
139
+ width: size.iconSize,
140
+ height: size.iconSize,
141
+ })),
142
+ },
143
+ });
144
+ }
145
+
146
+ // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
147
+ // transform on native cannot resolve function calls to extract variant structures.
148
+ export const badgeStyles = StyleSheet.create((theme: Theme) => {
149
+ // Apply extensions to main visual elements
150
+
151
+ return applyExtensions('Badge', theme, {badge: createBadgeStyles(theme),
152
+ text: createTextStyles(theme),
153
+ // Additional styles (merged from return)
154
+ // Minor utility styles (not extended)
155
+ content: createContentStyles()(),
156
+ icon: createIconStyles(theme)()});
157
+ });
@@ -1,85 +1,49 @@
1
+ /**
2
+ * Badge styles using defineStyle with $iterator expansion.
3
+ */
1
4
  import { StyleSheet } from 'react-native-unistyles';
2
- import { Theme, StylesheetStyles, getColorFromString, Size, Color } from '@idealyst/theme';
3
- import { buildSizeVariants } from '../utils/buildSizeVariants';
5
+ import { defineStyle, ThemeStyleWrapper, getColorFromString } from '@idealyst/theme';
6
+ import type { Theme as BaseTheme, Size, Color } from '@idealyst/theme';
4
7
 
5
- type BadgeType = 'filled' | 'outlined' | 'dot';
8
+ // Required: Unistyles must see StyleSheet usage in original source to process this file
9
+ void StyleSheet;
6
10
 
7
- type BadgeVariants = {
8
- size: Size;
9
- type: BadgeType;
10
- color: Color;
11
- }
11
+ // Wrap theme for $iterator support
12
+ type Theme = ThemeStyleWrapper<BaseTheme>;
12
13
 
13
- export type ExpandedBadgeStyles = StylesheetStyles<keyof BadgeVariants>;
14
+ type BadgeType = 'filled' | 'outlined' | 'dot';
14
15
 
15
- export type BadgeStylesheet = {
16
- badge: ExpandedBadgeStyles;
17
- content: ExpandedBadgeStyles;
18
- icon: ExpandedBadgeStyles;
19
- text: ExpandedBadgeStyles;
20
- }
16
+ export type BadgeDynamicProps = {
17
+ size?: Size;
18
+ type?: BadgeType;
19
+ color?: Color;
20
+ };
21
21
 
22
22
  /**
23
- * Create type variants for badge
23
+ * Badge styles with color-based type variants.
24
24
  */
25
- function createBadgeTypeVariants(theme: Theme, color: Color) {
26
- const colorValue = getColorFromString(theme, color);
27
- return {
28
- filled: {
29
- borderWidth: 0,
30
- backgroundColor: colorValue,
31
- },
32
- outlined: {
33
- backgroundColor: 'transparent',
34
- borderWidth: 2,
35
- borderStyle: 'solid',
36
- borderColor: colorValue,
37
- },
38
- dot: {
39
- minWidth: 8,
40
- width: 8,
41
- height: 8,
42
- paddingHorizontal: 0,
43
- paddingVertical: 0,
44
- backgroundColor: colorValue,
45
- },
46
- } as const;
47
- }
25
+ export const badgeStyles = defineStyle('Badge', (theme: Theme) => ({
26
+ badge: ({ color = 'primary', type = 'filled' }: BadgeDynamicProps) => {
27
+ const colorValue = getColorFromString(theme as unknown as BaseTheme, color);
48
28
 
49
- /**
50
- * Create type variants for badge text
51
- */
52
- function createTextTypeVariants(theme: Theme, color: Color){
53
- const colorValue = getColorFromString(theme, color);
54
- return {
55
- filled: {
56
- color: theme.colors.text.inverse,
57
- },
58
- outlined: {
59
- color: colorValue,
60
- },
61
- dot: {
62
- display: 'none',
63
- },
64
- } as const;
65
- }
29
+ const typeStyles = type === 'filled'
30
+ ? { borderWidth: 0, backgroundColor: colorValue }
31
+ : type === 'outlined'
32
+ ? { backgroundColor: 'transparent', borderWidth: 2, borderStyle: 'solid' as const, borderColor: colorValue }
33
+ : { minWidth: 8, width: 8, height: 8, paddingHorizontal: 0, paddingVertical: 0, backgroundColor: colorValue };
66
34
 
67
- /**
68
- * Generate badge container styles
69
- */
70
- function createBadgeStyles(theme: Theme) {
71
- return ({ color }: Partial<BadgeVariants>) => {
72
35
  return {
73
- alignItems: 'center',
74
- justifyContent: 'center',
36
+ alignItems: 'center' as const,
37
+ justifyContent: 'center' as const,
75
38
  borderRadius: 9999,
39
+ ...typeStyles,
76
40
  variants: {
77
- size: buildSizeVariants(theme, 'badge', (size) => ({
78
- minWidth: size.minWidth,
79
- height: size.height,
80
- paddingHorizontal: size.paddingHorizontal,
81
- })),
82
- type: createBadgeTypeVariants(theme, color),
41
+ // $iterator expands for each badge size
42
+ size: {
43
+ minWidth: theme.sizes.$badge.minWidth,
44
+ height: theme.sizes.$badge.height,
45
+ paddingHorizontal: theme.sizes.$badge.paddingHorizontal,
46
+ },
83
47
  },
84
48
  _web: {
85
49
  display: 'flex',
@@ -90,51 +54,48 @@ function createBadgeStyles(theme: Theme) {
90
54
  lineHeight: 1,
91
55
  },
92
56
  } as const;
93
- }
94
- }
57
+ },
58
+
59
+ text: ({ color = 'primary', type = 'filled' }: BadgeDynamicProps) => {
60
+ const colorValue = getColorFromString(theme as unknown as BaseTheme, color);
61
+
62
+ const textColor = type === 'filled'
63
+ ? theme.colors.text.inverse
64
+ : type === 'outlined'
65
+ ? colorValue
66
+ : 'transparent'; // dot type hides text
95
67
 
96
- /**
97
- * Generate badge text styles
98
- */
99
- function createTextStyles(theme: Theme) {
100
- return ({ color }: Partial<BadgeVariants>) => {
101
68
  return {
102
- fontWeight: '600',
103
- textAlign: 'center',
69
+ fontWeight: '600' as const,
70
+ textAlign: 'center' as const,
71
+ color: textColor,
72
+ ...(type === 'dot' ? { display: 'none' as const } : {}),
104
73
  variants: {
105
- size: buildSizeVariants(theme, 'badge', (size) => ({
106
- fontSize: size.fontSize,
107
- lineHeight: size.lineHeight,
108
- })),
109
- type: createTextTypeVariants(theme, color),
74
+ size: {
75
+ fontSize: theme.sizes.$badge.fontSize,
76
+ lineHeight: theme.sizes.$badge.lineHeight,
77
+ },
110
78
  },
111
79
  } as const;
112
- };
113
- }
80
+ },
114
81
 
115
- // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
116
- // transform on native cannot resolve function calls to extract variant structures.
117
- export const badgeStyles = StyleSheet.create((theme: Theme) => {
118
- return {
119
- badge: createBadgeStyles(theme),
120
- content: {
121
- display: 'flex',
122
- flexDirection: 'row',
123
- alignItems: 'center',
124
- justifyContent: 'center',
82
+ content: (_props: BadgeDynamicProps) => ({
83
+ display: 'flex' as const,
84
+ flexDirection: 'row' as const,
85
+ alignItems: 'center' as const,
86
+ justifyContent: 'center' as const,
125
87
  gap: 4,
126
- },
127
- icon: {
128
- display: 'flex',
129
- alignItems: 'center',
130
- justifyContent: 'center',
88
+ }),
89
+
90
+ icon: (_props: BadgeDynamicProps) => ({
91
+ display: 'flex' as const,
92
+ alignItems: 'center' as const,
93
+ justifyContent: 'center' as const,
131
94
  variants: {
132
- size: buildSizeVariants(theme, 'badge', (size) => ({
133
- width: size.iconSize,
134
- height: size.iconSize,
135
- })),
95
+ size: {
96
+ width: theme.sizes.$badge.iconSize,
97
+ height: theme.sizes.$badge.iconSize,
98
+ },
136
99
  },
137
- },
138
- text: createTextStyles(theme),
139
- };
140
- });
100
+ }),
101
+ }));
@@ -28,13 +28,13 @@ const Badge = forwardRef<HTMLSpanElement, BadgeProps>((props: InternalBadgeProps
28
28
  type,
29
29
  });
30
30
 
31
- const badgeStyle = badgeStyles.badge({ color });
31
+ const badgeStyle = (badgeStyles.badge as any)({ color });
32
32
  const contentStyle = badgeStyles.content;
33
- const textStyle = badgeStyles.text({ color });
34
-
35
- const badgeProps = getWebProps(badgeStyle);
36
- const contentProps = getWebProps(contentStyle);
37
- const textProps = getWebProps(textStyle);
33
+ const textStyle = (badgeStyles.text as any)({ color });
34
+
35
+ const badgeProps = getWebProps([badgeStyle]);
36
+ const contentProps = getWebProps([contentStyle]);
37
+ const textProps = getWebProps([textStyle]);
38
38
  const iconProps = getWebProps([badgeStyles.icon, textStyle]);
39
39
 
40
40
  // Helper to render icon
@@ -22,13 +22,20 @@ interface BreadcrumbItemProps {
22
22
  }
23
23
 
24
24
  const BreadcrumbItem: React.FC<BreadcrumbItemProps> = ({ item, isLast, size, intent, itemStyle }) => {
25
- // Apply variants for this item only
25
+ const isClickable = !!item.onPress && !item.disabled;
26
+ const isDisabled = item.disabled || false;
27
+
28
+ // Apply size variant
26
29
  breadcrumbItemStyles.useVariants({
27
30
  size,
31
+ });
32
+
33
+ // Get dynamic item text style
34
+ const itemTextStyle = (breadcrumbItemStyles.itemText as any)({
28
35
  intent,
29
- disabled: item.disabled || false,
30
36
  isLast,
31
- clickable: !!item.onPress && !item.disabled,
37
+ disabled: isDisabled,
38
+ clickable: isClickable,
32
39
  });
33
40
 
34
41
  const iconStyle = breadcrumbItemStyles.icon;
@@ -55,11 +62,11 @@ const BreadcrumbItem: React.FC<BreadcrumbItemProps> = ({ item, isLast, size, int
55
62
  const content = (
56
63
  <View style={[breadcrumbItemStyles.item, itemStyle]}>
57
64
  {item.icon && <View style={iconStyle}>{renderIcon()}</View>}
58
- <Text style={breadcrumbItemStyles.itemText}>{item.label}</Text>
65
+ <Text style={itemTextStyle}>{item.label}</Text>
59
66
  </View>
60
67
  );
61
68
 
62
- if (item.onPress && !item.disabled) {
69
+ if (isClickable) {
63
70
  return (
64
71
  <Pressable
65
72
  onPress={item.onPress}
@@ -0,0 +1,231 @@
1
+ import { StyleSheet } from 'react-native-unistyles';
2
+ import { Theme, StylesheetStyles, Size } from '@idealyst/theme';
3
+ import { buildSizeVariants } from '../utils/buildSizeVariants';
4
+ import { applyExtensions } from '../extensions/applyExtension';
5
+
6
+ type BreadcrumbSize = Size;
7
+ type BreadcrumbIntent = 'primary' | 'neutral';
8
+
9
+ type BreadcrumbVariants = {
10
+ size: BreadcrumbSize;
11
+ intent: BreadcrumbIntent;
12
+ disabled: boolean;
13
+ isLast: boolean;
14
+ clickable: boolean;
15
+ }
16
+
17
+ export type ExpandedBreadcrumbStyles = StylesheetStyles<keyof BreadcrumbVariants>;
18
+
19
+ export type BreadcrumbStylesheet = {
20
+ container: ExpandedBreadcrumbStyles;
21
+ item: ExpandedBreadcrumbStyles;
22
+ itemText: ExpandedBreadcrumbStyles;
23
+ icon: ExpandedBreadcrumbStyles;
24
+ separator: ExpandedBreadcrumbStyles;
25
+ ellipsis: ExpandedBreadcrumbStyles;
26
+ ellipsisIcon: ExpandedBreadcrumbStyles;
27
+ menuButton: ExpandedBreadcrumbStyles;
28
+ menuButtonIcon: ExpandedBreadcrumbStyles;
29
+ }
30
+
31
+ type ItemTextDynamicProps = {
32
+ intent?: BreadcrumbIntent;
33
+ isLast?: boolean;
34
+ disabled?: boolean;
35
+ clickable?: boolean;
36
+ };
37
+
38
+ /**
39
+ * Create size variants for item text
40
+ */
41
+ function createItemTextSizeVariants(theme: Theme) {
42
+ return buildSizeVariants(theme, 'breadcrumb', (size) => ({
43
+ fontSize: size.fontSize,
44
+ lineHeight: size.lineHeight,
45
+ }));
46
+ }
47
+
48
+ /**
49
+ * Get item text color based on state
50
+ */
51
+ function getItemTextColor(theme: Theme, intent: BreadcrumbIntent, isLast: boolean, disabled: boolean, clickable: boolean): string {
52
+ if (disabled) {
53
+ return theme.colors.text.secondary;
54
+ }
55
+ if (isLast) {
56
+ return theme.colors.text.primary;
57
+ }
58
+ if (clickable) {
59
+ return intent === 'primary' ? theme.intents.primary.primary : theme.colors.text.secondary;
60
+ }
61
+ return theme.colors.text.secondary;
62
+ }
63
+
64
+ /**
65
+ * Create size variants for icons
66
+ */
67
+ function createIconSizeVariants(theme: Theme) {
68
+ return buildSizeVariants(theme, 'breadcrumb', (size) => ({
69
+ width: size.iconSize,
70
+ height: size.iconSize,
71
+ }));
72
+ }
73
+
74
+ /**
75
+ * Get icon color based on intent
76
+ */
77
+ function getIconColor(theme: Theme, intent: BreadcrumbIntent) {
78
+ if (intent === 'primary') {
79
+ return theme.intents.primary.primary;
80
+ }
81
+ return theme.colors.text.secondary;
82
+ }
83
+
84
+ const createItemTextStyles = (theme: Theme) => {
85
+ return ({ intent = 'primary', isLast = false, disabled = false, clickable = true }: ItemTextDynamicProps) => {
86
+ const color = getItemTextColor(theme, intent, isLast, disabled, clickable);
87
+ return {
88
+ color,
89
+ opacity: disabled ? 0.5 : 1,
90
+ variants: {
91
+ size: createItemTextSizeVariants(theme),
92
+ },
93
+ } as const;
94
+ };
95
+ }
96
+
97
+ const createIconStyles = (theme: Theme) => {
98
+ return {
99
+ variants: {
100
+ size: createIconSizeVariants(theme),
101
+ },
102
+ } as const;
103
+ }
104
+
105
+ const createSeparatorStyles = (theme: Theme) => {
106
+ return {
107
+ color: theme.colors.text.tertiary,
108
+ variants: {
109
+ size: createItemTextSizeVariants(theme),
110
+ },
111
+ } as const;
112
+ }
113
+
114
+ const createEllipsisIconStyles = (theme: Theme) => {
115
+ return ({ intent }: Partial<BreadcrumbVariants>) => {
116
+ return {
117
+ color: getIconColor(theme, intent),
118
+ variants: {
119
+ size: createIconSizeVariants(theme),
120
+ },
121
+ } as const;
122
+ }
123
+ }
124
+
125
+ const createMenuButtonIconStyles = (theme: Theme) => {
126
+ return ({ intent }: Partial<BreadcrumbVariants>) => {
127
+ return {
128
+ color: getIconColor(theme, intent),
129
+ variants: {
130
+ size: createIconSizeVariants(theme),
131
+ },
132
+ } as const;
133
+ }
134
+ }
135
+
136
+ // Style creators for extension support
137
+ function createContainerStyles() {
138
+ return () => ({
139
+ display: 'flex' as const,
140
+ flexDirection: 'row' as const,
141
+ alignItems: 'center' as const,
142
+ flexWrap: 'wrap' as const,
143
+ gap: 8,
144
+ });
145
+ }
146
+
147
+ function createItemStyles() {
148
+ return () => ({
149
+ display: 'flex' as const,
150
+ flexDirection: 'row' as const,
151
+ alignItems: 'center' as const,
152
+ gap: 4,
153
+ });
154
+ }
155
+
156
+ // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel transform on native cannot resolve function calls to extract variant structures.
157
+ export const breadcrumbStyles = StyleSheet.create((theme: Theme) => {
158
+ // Apply extensions to main visual elements
159
+
160
+ return applyExtensions('Breadcrumb', theme, {container: createContainerStyles(),
161
+ item: createItemStyles(),
162
+ itemText: createItemTextStyles(theme),
163
+ // Additional styles (merged from return)
164
+ // Minor utility styles (not extended)
165
+ icon: createIconStyles(theme),
166
+ separator: createSeparatorStyles(theme),
167
+ ellipsis: {
168
+ display: 'flex',
169
+ alignItems: 'center',
170
+ justifyContent: 'center',
171
+ },
172
+ ellipsisIcon: createEllipsisIconStyles(theme),
173
+ menuButton: {
174
+ paddingVertical: 4,
175
+ paddingHorizontal: 8,
176
+ },
177
+ menuButtonIcon: createMenuButtonIconStyles(theme)});
178
+ });
179
+
180
+ // Export individual style sheets for backwards compatibility
181
+ export const breadcrumbContainerStyles = StyleSheet.create((theme: Theme) => {
182
+ return {
183
+ container: {
184
+ display: 'flex',
185
+ flexDirection: 'row',
186
+ alignItems: 'center',
187
+ flexWrap: 'wrap',
188
+ gap: 8,
189
+ },
190
+ };
191
+ });
192
+
193
+ export const breadcrumbItemStyles = StyleSheet.create((theme: Theme) => {
194
+ return {
195
+ item: {
196
+ display: 'flex',
197
+ flexDirection: 'row',
198
+ alignItems: 'center',
199
+ gap: 4,
200
+ },
201
+ itemText: createItemTextStyles(theme),
202
+ icon: createIconStyles(theme),
203
+ } as const;
204
+ });
205
+
206
+ export const breadcrumbSeparatorStyles = StyleSheet.create((theme: Theme) => {
207
+ return {
208
+ separator: createSeparatorStyles(theme),
209
+ } as const;
210
+ });
211
+
212
+ export const breadcrumbEllipsisStyles = StyleSheet.create((theme: Theme) => {
213
+ return {
214
+ ellipsis: {
215
+ display: 'flex',
216
+ alignItems: 'center',
217
+ justifyContent: 'center',
218
+ },
219
+ icon: createEllipsisIconStyles(theme),
220
+ } as const;
221
+ });
222
+
223
+ export const breadcrumbMenuButtonStyles = StyleSheet.create((theme: Theme) => {
224
+ return {
225
+ button: {
226
+ paddingVertical: 4,
227
+ paddingHorizontal: 8,
228
+ },
229
+ icon: createMenuButtonIconStyles(theme),
230
+ } as const;
231
+ });