@idealyst/components 1.3.3 → 1.3.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idealyst/components",
3
- "version": "1.3.3",
3
+ "version": "1.3.4",
4
4
  "description": "Shared component library for React and React Native",
5
5
  "documentation": "https://github.com/IdealystIO/idealyst-framework/tree/main/packages/components#readme",
6
6
  "readme": "README.md",
@@ -56,7 +56,7 @@
56
56
  "publish:npm": "npm publish"
57
57
  },
58
58
  "peerDependencies": {
59
- "@idealyst/theme": "^1.3.3",
59
+ "@idealyst/theme": "^1.3.4",
60
60
  "@mdi/js": ">=7.0.0",
61
61
  "@mdi/react": ">=1.0.0",
62
62
  "@react-native-vector-icons/common": ">=12.0.0",
@@ -111,8 +111,8 @@
111
111
  },
112
112
  "devDependencies": {
113
113
  "@idealyst/blur": "^1.2.40",
114
- "@idealyst/theme": "^1.3.3",
115
- "@idealyst/tooling": "^1.3.3",
114
+ "@idealyst/theme": "^1.3.4",
115
+ "@idealyst/tooling": "^1.3.4",
116
116
  "@mdi/react": "^1.6.1",
117
117
  "@types/react": "^19.1.0",
118
118
  "react": "^19.1.0",
@@ -17,34 +17,26 @@ interface BreadcrumbItemProps {
17
17
  }
18
18
 
19
19
  const BreadcrumbItem: React.FC<BreadcrumbItemProps> = ({ item, isLast, size, intent, itemStyle }) => {
20
- const isClickable = !!item.onPress && !item.disabled;
21
20
  const isDisabled = item.disabled || false;
22
21
 
23
- // Apply size variant
24
22
  breadcrumbStyles.useVariants({
25
23
  size,
26
- });
27
-
28
- // Get dynamic item text style
29
- const itemTextStyle = (breadcrumbStyles.itemText as any)({
30
24
  intent,
31
- isLast,
25
+ active: isLast,
32
26
  disabled: isDisabled,
33
- clickable: isClickable,
34
27
  });
35
28
 
36
- const iconStyle = (breadcrumbStyles.icon as any)({});
29
+ const iconSize = (breadcrumbStyles.icon as any).width || 16;
37
30
 
38
31
  const renderIcon = () => {
39
32
  if (!item.icon) return null;
40
33
 
41
34
  if (typeof item.icon === 'string') {
42
- const iconSize = iconStyle.width || 16;
43
35
  return (
44
36
  <Icon
45
37
  name={item.icon as IconName}
46
38
  size={iconSize}
47
- style={iconStyle}
39
+ style={breadcrumbStyles.icon}
48
40
  />
49
41
  );
50
42
  } else if (isValidElement(item.icon)) {
@@ -54,16 +46,14 @@ const BreadcrumbItem: React.FC<BreadcrumbItemProps> = ({ item, isLast, size, int
54
46
  return null;
55
47
  };
56
48
 
57
- const itemContainerStyle = (breadcrumbStyles.item as any)({});
58
-
59
49
  const content = (
60
- <View style={[itemContainerStyle, itemStyle]}>
61
- {item.icon && <View style={iconStyle}>{renderIcon()}</View>}
62
- <Text style={itemTextStyle}>{item.label}</Text>
50
+ <View style={[breadcrumbStyles.item, itemStyle]}>
51
+ {item.icon && <View style={breadcrumbStyles.icon}>{renderIcon()}</View>}
52
+ <Text style={breadcrumbStyles.itemText}>{item.label}</Text>
63
53
  </View>
64
54
  );
65
55
 
66
- if (isClickable) {
56
+ if (!!item.onPress && !item.disabled) {
67
57
  return (
68
58
  <Pressable
69
59
  onPress={item.onPress}
@@ -91,12 +81,10 @@ const BreadcrumbSeparator: React.FC<BreadcrumbSeparatorProps> = ({ separator, si
91
81
  breadcrumbStyles.useVariants({ size });
92
82
 
93
83
  if (typeof separator === 'string') {
94
- const sepStyle = (breadcrumbStyles.separator as any)({});
95
- return <Text style={[sepStyle, separatorStyle]}>{separator}</Text>;
84
+ return <Text style={[breadcrumbStyles.separator, separatorStyle]}>{separator}</Text>;
96
85
  }
97
86
 
98
- const sepIconStyle = (breadcrumbStyles.separatorIcon as any)({});
99
- return <View style={[sepIconStyle, separatorStyle]}>{separator}</View>;
87
+ return <View style={[breadcrumbStyles.separatorIcon, separatorStyle]}>{separator}</View>;
100
88
  };
101
89
 
102
90
  interface BreadcrumbEllipsisProps {
@@ -105,13 +93,11 @@ interface BreadcrumbEllipsisProps {
105
93
  }
106
94
 
107
95
  const BreadcrumbEllipsis: React.FC<BreadcrumbEllipsisProps> = ({ size, intent }) => {
108
- breadcrumbStyles.useVariants({ size });
109
- const ellipsisStyle = (breadcrumbStyles.ellipsis as any)({});
110
- const iconStyle = (breadcrumbStyles.ellipsisIcon as any)({ intent });
96
+ breadcrumbStyles.useVariants({ size, intent });
111
97
 
112
98
  return (
113
- <View style={ellipsisStyle}>
114
- <Icon name="dots-horizontal" style={iconStyle} />
99
+ <View style={breadcrumbStyles.ellipsis}>
100
+ <Icon name="dots-horizontal" style={breadcrumbStyles.ellipsisIcon} />
115
101
  </View>
116
102
  );
117
103
  };
@@ -132,11 +118,7 @@ const Breadcrumb = forwardRef<IdealystElement, BreadcrumbProps>(({
132
118
  }, ref) => {
133
119
  const [menuOpen, setMenuOpen] = useState(false);
134
120
 
135
- // Apply variants
136
- breadcrumbStyles.useVariants({ size });
137
- const containerStyle = (breadcrumbStyles.container as any)({});
138
- const menuButtonStyle = (breadcrumbStyles.menuButton as any)({});
139
- const menuIconStyle = (breadcrumbStyles.menuButtonIcon as any)({ intent });
121
+ breadcrumbStyles.useVariants({ size, intent });
140
122
 
141
123
  // Handle responsive collapsing
142
124
  let displayItems = items;
@@ -174,7 +156,7 @@ const Breadcrumb = forwardRef<IdealystElement, BreadcrumbProps>(({
174
156
  <View
175
157
  ref={ref as any}
176
158
  nativeID={id}
177
- style={[containerStyle, style]}
159
+ style={[breadcrumbStyles.container, style]}
178
160
  testID={testID}
179
161
  accessibilityLabel="Breadcrumb"
180
162
  >
@@ -202,11 +184,11 @@ const Breadcrumb = forwardRef<IdealystElement, BreadcrumbProps>(({
202
184
  size={size}
203
185
  >
204
186
  <Pressable
205
- style={menuButtonStyle}
187
+ style={breadcrumbStyles.menuButton}
206
188
  accessibilityRole="button"
207
189
  accessibilityLabel="Show more breadcrumb items"
208
190
  >
209
- <Icon name="dots-horizontal" style={menuIconStyle} />
191
+ <Icon name="dots-horizontal" style={breadcrumbStyles.menuButtonIcon} />
210
192
  </Pressable>
211
193
  </Menu>
212
194
  <BreadcrumbSeparator separator={separator} size={size} separatorStyle={separatorStyle} />
@@ -1,9 +1,10 @@
1
1
  /**
2
- * Breadcrumb styles using defineStyle with $iterator expansion.
2
+ * Breadcrumb styles using defineStyle with static variants.
3
3
  */
4
4
  import { StyleSheet } from 'react-native-unistyles';
5
5
  import { defineStyle, ThemeStyleWrapper } from '@idealyst/theme';
6
- import type { Theme as BaseTheme, Size } from '@idealyst/theme';
6
+ import type { Theme as BaseTheme } from '@idealyst/theme';
7
+ import { ViewStyleSize } from '../utils/viewStyleProps';
7
8
 
8
9
  // Required: Unistyles must see StyleSheet usage in original source to process this file
9
10
  void StyleSheet;
@@ -11,65 +12,61 @@ void StyleSheet;
11
12
  // Wrap theme for $iterator support
12
13
  type Theme = ThemeStyleWrapper<BaseTheme>;
13
14
 
14
- type BreadcrumbIntent = 'primary' | 'neutral';
15
-
16
- export type BreadcrumbDynamicProps = {
17
- size?: Size;
18
- intent?: BreadcrumbIntent;
15
+ export type BreadcrumbVariants = {
16
+ size?: ViewStyleSize;
17
+ intent?: 'primary' | 'neutral';
18
+ active?: boolean;
19
19
  disabled?: boolean;
20
- isLast?: boolean;
21
- clickable?: boolean;
22
20
  };
23
21
 
24
22
  /**
25
- * Breadcrumb styles with intent and state handling.
23
+ * Breadcrumb styles with static variants.
26
24
  */
27
25
  export const breadcrumbStyles = defineStyle('Breadcrumb', (theme: Theme) => ({
28
- container: (_props: BreadcrumbDynamicProps) => ({
26
+ container: {
29
27
  display: 'flex' as const,
30
28
  flexDirection: 'row' as const,
31
29
  alignItems: 'center' as const,
32
30
  flexWrap: 'wrap' as const,
33
31
  gap: 4,
34
- }),
32
+ },
35
33
 
36
- item: (_props: BreadcrumbDynamicProps) => ({
34
+ item: {
37
35
  display: 'flex' as const,
38
36
  flexDirection: 'row' as const,
39
37
  alignItems: 'center' as const,
40
38
  gap: 4,
41
- }),
42
-
43
- itemText: ({ intent = 'primary', isLast = false, disabled = false, clickable = true }: BreadcrumbDynamicProps) => {
44
- // Get color based on state - inline for Unistyles to trace
45
- const color = disabled
46
- ? theme.colors.text.secondary
47
- : isLast
48
- ? theme.colors.text.primary
49
- : clickable
50
- ? (intent === 'primary' ? theme.intents.primary.primary : theme.colors.text.secondary)
51
- : theme.colors.text.secondary;
39
+ opacity: 0.7,
40
+ variants: {
41
+ active: {
42
+ true: { opacity: 1 },
43
+ false: { _web: { _hover: { opacity: 1 } } },
44
+ },
45
+ disabled: {
46
+ true: { opacity: 0.5 },
47
+ false: {},
48
+ },
49
+ },
50
+ _web: {
51
+ transition: 'opacity 0.2s ease',
52
+ },
53
+ },
52
54
 
53
- return {
54
- color,
55
- opacity: disabled ? 0.5 : 1,
56
- variants: {
57
- // $iterator expands for each breadcrumb size
58
- size: {
59
- fontSize: theme.sizes.$breadcrumb.fontSize,
60
- lineHeight: theme.sizes.$breadcrumb.lineHeight,
61
- },
55
+ itemText: {
56
+ color: theme.colors.text.primary,
57
+ variants: {
58
+ size: {
59
+ fontSize: theme.sizes.$breadcrumb.fontSize,
60
+ lineHeight: theme.sizes.$breadcrumb.lineHeight,
61
+ },
62
+ disabled: {
63
+ true: { color: theme.colors.text.secondary },
64
+ false: {},
62
65
  },
63
- _web: clickable && !isLast && !disabled ? {
64
- _hover: {
65
- textDecoration: 'underline',
66
- opacity: 0.8,
67
- },
68
- } : {},
69
- } as const;
66
+ },
70
67
  },
71
68
 
72
- icon: (_props: BreadcrumbDynamicProps) => ({
69
+ icon: {
73
70
  variants: {
74
71
  size: {
75
72
  width: theme.sizes.$breadcrumb.iconSize,
@@ -77,23 +74,25 @@ export const breadcrumbStyles = defineStyle('Breadcrumb', (theme: Theme) => ({
77
74
  fontSize: theme.sizes.$breadcrumb.iconSize,
78
75
  },
79
76
  },
80
- }),
77
+ },
81
78
 
82
- separator: (_props: BreadcrumbDynamicProps) => ({
79
+ separator: {
83
80
  color: theme.colors.text.tertiary,
81
+ opacity: 0.9,
84
82
  variants: {
85
83
  size: {
86
84
  fontSize: theme.sizes.$breadcrumb.fontSize,
87
85
  lineHeight: theme.sizes.$breadcrumb.lineHeight,
88
86
  },
89
87
  },
90
- }),
88
+ },
91
89
 
92
- separatorIcon: (_props: BreadcrumbDynamicProps) => ({
90
+ separatorIcon: {
93
91
  display: 'flex' as const,
94
92
  alignItems: 'center' as const,
95
93
  justifyContent: 'center' as const,
96
94
  color: theme.colors.text.tertiary,
95
+ opacity: 0.9,
97
96
  variants: {
98
97
  size: {
99
98
  width: theme.sizes.$breadcrumb.iconSize,
@@ -101,38 +100,46 @@ export const breadcrumbStyles = defineStyle('Breadcrumb', (theme: Theme) => ({
101
100
  fontSize: theme.sizes.$breadcrumb.iconSize,
102
101
  },
103
102
  },
104
- }),
103
+ },
105
104
 
106
- ellipsis: (_props: BreadcrumbDynamicProps) => ({
105
+ ellipsis: {
107
106
  display: 'flex' as const,
108
107
  alignItems: 'center' as const,
109
108
  justifyContent: 'center' as const,
110
- }),
109
+ },
111
110
 
112
- ellipsisIcon: ({ intent = 'primary' }: BreadcrumbDynamicProps) => ({
113
- color: intent === 'primary' ? theme.intents.primary.primary : theme.colors.text.secondary,
111
+ ellipsisIcon: {
112
+ color: theme.colors.text.secondary,
114
113
  variants: {
115
114
  size: {
116
115
  width: theme.sizes.$breadcrumb.iconSize,
117
116
  height: theme.sizes.$breadcrumb.iconSize,
118
117
  fontSize: theme.sizes.$breadcrumb.iconSize,
119
118
  },
119
+ intent: {
120
+ primary: { color: theme.intents.primary.primary },
121
+ neutral: { color: theme.colors.text.secondary },
122
+ },
120
123
  },
121
- }),
124
+ },
122
125
 
123
- menuButton: (_props: BreadcrumbDynamicProps) => ({
126
+ menuButton: {
124
127
  paddingVertical: 4,
125
128
  paddingHorizontal: 8,
126
- }),
129
+ },
127
130
 
128
- menuButtonIcon: ({ intent = 'primary' }: BreadcrumbDynamicProps) => ({
129
- color: intent === 'primary' ? theme.intents.primary.primary : theme.colors.text.secondary,
131
+ menuButtonIcon: {
132
+ color: theme.colors.text.secondary,
130
133
  variants: {
131
134
  size: {
132
135
  width: theme.sizes.$breadcrumb.iconSize,
133
136
  height: theme.sizes.$breadcrumb.iconSize,
134
137
  fontSize: theme.sizes.$breadcrumb.iconSize,
135
138
  },
139
+ intent: {
140
+ primary: { color: theme.intents.primary.primary },
141
+ neutral: { color: theme.colors.text.secondary },
142
+ },
136
143
  },
137
- }),
144
+ },
138
145
  }));
@@ -19,24 +19,16 @@ const BreadcrumbItem: React.FC<BreadcrumbItemProps> = ({ item, isLast, size, int
19
19
  const isClickable = !!item.onPress && !item.disabled;
20
20
  const isDisabled = item.disabled || false;
21
21
 
22
- // Apply size variant
23
22
  breadcrumbStyles.useVariants({
24
23
  size,
25
- });
26
-
27
- // Get dynamic styles - call as functions for theme reactivity
28
- const itemStyle_ = (breadcrumbStyles.item as any)({});
29
- const itemTextStyle = (breadcrumbStyles.itemText as any)({
30
24
  intent,
31
- isLast,
25
+ active: isLast,
32
26
  disabled: isDisabled,
33
- clickable: isClickable,
34
27
  });
35
- const iconStyle = (breadcrumbStyles.icon as any)({});
36
28
 
37
- const itemProps = getWebProps([itemStyle_]);
38
- const itemTextProps = getWebProps([itemTextStyle, itemStyle]);
39
- const iconProps = getWebProps([iconStyle]);
29
+ const itemProps = getWebProps([breadcrumbStyles.item]);
30
+ const itemTextProps = getWebProps([breadcrumbStyles.itemText, itemStyle]);
31
+ const iconProps = getWebProps([breadcrumbStyles.icon]);
40
32
 
41
33
  const handleClick = () => {
42
34
  if (!item.disabled && item.onPress) {
@@ -61,30 +53,13 @@ const BreadcrumbItem: React.FC<BreadcrumbItemProps> = ({ item, isLast, size, int
61
53
  return null;
62
54
  };
63
55
 
64
- const content = (
65
- <div {...itemProps}>
66
- {item.icon && (
67
- <span
68
- {...iconProps}
69
- style={{
70
- display: 'inline-flex',
71
- alignItems: 'center',
72
- justifyContent: 'center',
73
- }}
74
- >
75
- {renderIcon()}
76
- </span>
77
- )}
78
- <span {...itemTextProps}>
79
- {item.label}
80
- </span>
81
- </div>
82
- );
83
-
84
56
  if (isClickable) {
85
57
  return (
86
58
  <button
59
+ {...itemProps}
87
60
  onClick={handleClick}
61
+ disabled={isDisabled}
62
+ aria-current={isLast ? 'page' : undefined}
88
63
  style={{
89
64
  background: 'none',
90
65
  border: 'none',
@@ -95,17 +70,43 @@ const BreadcrumbItem: React.FC<BreadcrumbItemProps> = ({ item, isLast, size, int
95
70
  font: 'inherit',
96
71
  color: 'inherit',
97
72
  }}
98
- disabled={isDisabled}
99
- aria-current={isLast ? 'page' : undefined}
100
73
  >
101
- {content}
74
+ {item.icon && (
75
+ <span
76
+ {...iconProps}
77
+ style={{
78
+ display: 'inline-flex',
79
+ alignItems: 'center',
80
+ justifyContent: 'center',
81
+ }}
82
+ >
83
+ {renderIcon()}
84
+ </span>
85
+ )}
86
+ <span {...itemTextProps}>
87
+ {item.label}
88
+ </span>
102
89
  </button>
103
90
  );
104
91
  }
105
92
 
106
93
  return (
107
- <div aria-current={isLast ? 'page' : undefined}>
108
- {content}
94
+ <div {...itemProps} aria-current={isLast ? 'page' : undefined}>
95
+ {item.icon && (
96
+ <span
97
+ {...iconProps}
98
+ style={{
99
+ display: 'inline-flex',
100
+ alignItems: 'center',
101
+ justifyContent: 'center',
102
+ }}
103
+ >
104
+ {renderIcon()}
105
+ </span>
106
+ )}
107
+ <span {...itemTextProps}>
108
+ {item.label}
109
+ </span>
109
110
  </div>
110
111
  );
111
112
  };
@@ -121,8 +122,7 @@ const BreadcrumbSeparator: React.FC<BreadcrumbSeparatorProps> = ({ separator, si
121
122
  const isTextSeparator = typeof separator === 'string';
122
123
 
123
124
  if (isTextSeparator) {
124
- const separatorStyle_ = (breadcrumbStyles.separator as any)({});
125
- const separatorProps = getWebProps([separatorStyle_, separatorStyle]);
125
+ const separatorProps = getWebProps([breadcrumbStyles.separator, separatorStyle]);
126
126
  return (
127
127
  <span {...separatorProps} aria-hidden="true">
128
128
  {separator}
@@ -130,8 +130,7 @@ const BreadcrumbSeparator: React.FC<BreadcrumbSeparatorProps> = ({ separator, si
130
130
  );
131
131
  }
132
132
 
133
- const separatorIconStyle = (breadcrumbStyles.separatorIcon as any)({});
134
- const separatorIconProps = getWebProps([separatorIconStyle, separatorStyle]);
133
+ const separatorIconProps = getWebProps([breadcrumbStyles.separatorIcon, separatorStyle]);
135
134
  return (
136
135
  <span {...separatorIconProps} aria-hidden="true">
137
136
  {separator}
@@ -145,11 +144,9 @@ interface BreadcrumbEllipsisProps {
145
144
  }
146
145
 
147
146
  const BreadcrumbEllipsis: React.FC<BreadcrumbEllipsisProps> = ({ size, intent }) => {
148
- breadcrumbStyles.useVariants({ size });
149
- const ellipsisStyle = (breadcrumbStyles.ellipsis as any)({});
150
- const ellipsisIconStyle = (breadcrumbStyles.ellipsisIcon as any)({ intent });
151
- const ellipsisProps = getWebProps([ellipsisStyle]);
152
- const iconProps = getWebProps([ellipsisIconStyle]);
147
+ breadcrumbStyles.useVariants({ size, intent });
148
+ const ellipsisProps = getWebProps([breadcrumbStyles.ellipsis]);
149
+ const iconProps = getWebProps([breadcrumbStyles.ellipsisIcon]);
153
150
 
154
151
  return (
155
152
  <span {...ellipsisProps}>
@@ -182,17 +179,10 @@ const Breadcrumb: React.FC<BreadcrumbProps> = ({
182
179
  }) => {
183
180
  const [menuOpen, setMenuOpen] = useState(false);
184
181
 
185
- // Get dynamic styles - call as functions for theme reactivity
186
- const containerStyle = (breadcrumbStyles.container as any)({});
187
- const menuButtonStyle = (breadcrumbStyles.menuButton as any)({});
188
- const menuButtonIconStyle = (breadcrumbStyles.menuButtonIcon as any)({ intent });
189
-
190
- const containerProps = getWebProps([containerStyle, style as any]);
191
-
192
- // Apply variants for menu button
193
- breadcrumbStyles.useVariants({ size });
194
- const menuButtonProps = getWebProps([menuButtonStyle]);
195
- const menuIconProps = getWebProps([menuButtonIconStyle]);
182
+ breadcrumbStyles.useVariants({ size, intent });
183
+ const containerProps = getWebProps([breadcrumbStyles.container, style as any]);
184
+ const menuButtonProps = getWebProps([breadcrumbStyles.menuButton]);
185
+ const menuIconProps = getWebProps([breadcrumbStyles.menuButtonIcon]);
196
186
 
197
187
  // Handle responsive collapsing
198
188
  let displayItems = items;