@idealyst/components 1.2.13 → 1.2.15

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 (95) hide show
  1. package/package.json +3 -3
  2. package/src/Accordion/Accordion.web.tsx +1 -1
  3. package/src/ActivityIndicator/ActivityIndicator.native.tsx +3 -3
  4. package/src/ActivityIndicator/ActivityIndicator.web.tsx +3 -3
  5. package/src/Alert/Alert.native.tsx +1 -1
  6. package/src/Alert/Alert.web.tsx +1 -1
  7. package/src/Avatar/Avatar.native.tsx +1 -1
  8. package/src/Badge/Badge.web.tsx +6 -2
  9. package/src/Badge/types.ts +5 -0
  10. package/src/Breadcrumb/Breadcrumb.native.tsx +20 -21
  11. package/src/Button/Button.native.tsx +3 -3
  12. package/src/Button/Button.web.tsx +5 -1
  13. package/src/Button/types.ts +5 -0
  14. package/src/Card/Card.web.tsx +4 -1
  15. package/src/Card/types.ts +5 -0
  16. package/src/Dialog/Dialog.native.tsx +3 -3
  17. package/src/Divider/Divider.web.tsx +2 -2
  18. package/src/Icon/Icon.web.tsx +2 -2
  19. package/src/Icon/types.ts +3 -0
  20. package/src/Image/Image.styles.tsx +5 -5
  21. package/src/Image/Image.web.tsx +3 -3
  22. package/src/List/List.native.tsx +1 -2
  23. package/src/List/List.web.tsx +1 -2
  24. package/src/List/ListSection.web.tsx +3 -3
  25. package/src/Menu/Menu.web.tsx +8 -10
  26. package/src/Menu/MenuItem.web.tsx +1 -1
  27. package/src/Popover/Popover.web.tsx +1 -1
  28. package/src/Pressable/Pressable.web.tsx +1 -1
  29. package/src/Progress/Progress.styles.tsx +76 -30
  30. package/src/Progress/Progress.web.tsx +13 -15
  31. package/src/SVGImage/SVGImage.web.tsx +1 -1
  32. package/src/Select/Select.web.tsx +2 -2
  33. package/src/Skeleton/Skeleton.native.tsx +3 -3
  34. package/src/Skeleton/Skeleton.web.tsx +3 -3
  35. package/src/Slider/Slider.native.tsx +2 -2
  36. package/src/Slider/Slider.styles.tsx +131 -44
  37. package/src/Slider/Slider.web.tsx +22 -22
  38. package/src/TabBar/TabBar.native.tsx +2 -2
  39. package/src/Text/Text.web.tsx +29 -3
  40. package/src/Text/types.ts +14 -1
  41. package/src/TextArea/TextArea.styles.tsx +96 -57
  42. package/src/TextArea/TextArea.web.tsx +19 -28
  43. package/src/Tooltip/Tooltip.web.tsx +3 -3
  44. package/src/Video/Video.styles.tsx +3 -3
  45. package/src/Video/Video.web.tsx +1 -1
  46. package/src/View/View.styles.tsx +2 -2
  47. package/src/View/View.web.tsx +93 -9
  48. package/src/View/types.ts +5 -1
  49. package/src/examples/ViewExamples.tsx +34 -0
  50. package/src/extensions/index.ts +0 -7
  51. package/src/hooks/useMergeRefs.ts +12 -6
  52. package/src/index.native.ts +1 -1
  53. package/src/index.ts +1 -1
  54. package/src/utils/accessibility/keyboardPatterns.ts +4 -0
  55. package/src/utils/accessibility/types.ts +5 -1
  56. package/src/utils/accessibility/useAnnounce.ts +1 -1
  57. package/src/utils/accessibility/useKeyboardNavigation.ts +1 -1
  58. package/src/utils/index.ts +0 -3
  59. package/src/utils/viewStyleProps.ts +2 -0
  60. package/src/Accordion/Accordion.styles.old.tsx +0 -298
  61. package/src/ActivityIndicator/ActivityIndicator.styles.old.tsx +0 -94
  62. package/src/Alert/Alert.styles.old.tsx +0 -209
  63. package/src/Avatar/Avatar.styles.old.tsx +0 -99
  64. package/src/Badge/Badge.styles.old.tsx +0 -157
  65. package/src/Breadcrumb/Breadcrumb.styles.old.tsx +0 -231
  66. package/src/Card/Card.styles.old.tsx +0 -160
  67. package/src/Checkbox/Checkbox.styles.old.tsx +0 -271
  68. package/src/Chip/Chip.styles.old.tsx +0 -184
  69. package/src/Dialog/Dialog.styles.old.tsx +0 -202
  70. package/src/Divider/Divider.styles.old.tsx +0 -172
  71. package/src/Icon/Icon.styles.old.tsx +0 -81
  72. package/src/Image/Image.styles.old.tsx +0 -69
  73. package/src/Input/Input.styles.old.tsx +0 -289
  74. package/src/List/List.styles.old.tsx +0 -242
  75. package/src/Menu/Menu.styles.old.tsx +0 -197
  76. package/src/Menu/MenuItem.styles.old.tsx +0 -114
  77. package/src/Popover/Popover.styles.old.tsx +0 -135
  78. package/src/Pressable/Pressable.styles.old.tsx +0 -27
  79. package/src/Progress/Progress.styles.old.tsx +0 -200
  80. package/src/RadioButton/RadioButton.styles.old.tsx +0 -175
  81. package/src/SVGImage/SVGImage.styles.old.tsx +0 -86
  82. package/src/Screen/Screen.styles.old.tsx +0 -87
  83. package/src/Select/Select.styles.old.tsx +0 -353
  84. package/src/Skeleton/Skeleton.styles.old.tsx +0 -67
  85. package/src/Slider/Slider.styles.old.tsx +0 -259
  86. package/src/Switch/Switch.styles.old.tsx +0 -203
  87. package/src/TabBar/TabBar.styles.old.tsx +0 -343
  88. package/src/Table/Table.styles.old.tsx +0 -311
  89. package/src/Text/Text.styles.old.tsx +0 -219
  90. package/src/TextArea/TextArea.styles.old.tsx +0 -213
  91. package/src/Tooltip/Tooltip.styles.old.tsx +0 -82
  92. package/src/Video/Video.styles.old.tsx +0 -51
  93. package/src/View/View.styles.old.tsx +0 -125
  94. package/src/extensions/applyExtension.ts +0 -210
  95. package/src/utils/buildSizeVariants.ts +0 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idealyst/components",
3
- "version": "1.2.13",
3
+ "version": "1.2.15",
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.2.13",
59
+ "@idealyst/theme": "^1.2.15",
60
60
  "@mdi/js": ">=7.0.0",
61
61
  "@mdi/react": ">=1.0.0",
62
62
  "@react-native-vector-icons/common": ">=12.0.0",
@@ -106,7 +106,7 @@
106
106
  }
107
107
  },
108
108
  "devDependencies": {
109
- "@idealyst/theme": "^1.2.13",
109
+ "@idealyst/theme": "^1.2.15",
110
110
  "@idealyst/tooling": "^1.2.4",
111
111
  "@mdi/react": "^1.6.1",
112
112
  "@types/react": "^19.1.0",
@@ -47,7 +47,7 @@ const AccordionItem: React.FC<AccordionItemProps> = ({
47
47
  const itemStyle = (accordionStyles.item as any)({ type, isLast });
48
48
  const itemProps = getWebProps([itemStyle]);
49
49
  const headerProps = getWebProps([(accordionStyles.header as any)({})]);
50
- const titleProps = getWebProps([accordionStyles.title]);
50
+ const titleProps = getWebProps([accordionStyles.title as any]);
51
51
  const iconProps = getWebProps([(accordionStyles.icon as any)({})]);
52
52
  // Pass expanded state to get correct maxHeight from styles
53
53
  const contentProps = getWebProps([(accordionStyles.content as any)({ expanded: isExpanded })]);
@@ -15,17 +15,17 @@ const ActivityIndicator = forwardRef<View, ActivityIndicatorProps>(({
15
15
  id,
16
16
  // Accessibility props
17
17
  accessibilityLabel,
18
- accessibilityLiveRegion,
18
+ accessibilityLive,
19
19
  accessibilityBusy,
20
20
  }, ref) => {
21
21
  // Generate native accessibility props
22
22
  const nativeA11yProps = useMemo(() => {
23
23
  return getNativeLiveRegionAccessibilityProps({
24
24
  accessibilityLabel: accessibilityLabel ?? 'Loading',
25
- accessibilityLiveRegion: accessibilityLiveRegion ?? 'polite',
25
+ accessibilityLive: accessibilityLive ?? 'polite',
26
26
  accessibilityBusy: accessibilityBusy ?? animating,
27
27
  });
28
- }, [accessibilityLabel, accessibilityLiveRegion, accessibilityBusy, animating]);
28
+ }, [accessibilityLabel, accessibilityLive, accessibilityBusy, animating]);
29
29
  // Handle numeric size
30
30
  const sizeVariant = typeof size === 'number' ? 'md' : size;
31
31
  const customSize = typeof size === 'number' ? size : undefined;
@@ -20,7 +20,7 @@ const ActivityIndicator = forwardRef<HTMLDivElement, ActivityIndicatorProps>(({
20
20
  id,
21
21
  // Accessibility props
22
22
  accessibilityLabel,
23
- accessibilityLiveRegion,
23
+ accessibilityLive,
24
24
  accessibilityBusy,
25
25
  accessibilityAtomic,
26
26
  accessibilityRelevant,
@@ -29,12 +29,12 @@ const ActivityIndicator = forwardRef<HTMLDivElement, ActivityIndicatorProps>(({
29
29
  const ariaProps = useMemo(() => {
30
30
  return getWebLiveRegionAriaProps({
31
31
  accessibilityLabel: accessibilityLabel ?? 'Loading',
32
- accessibilityLiveRegion: accessibilityLiveRegion ?? 'polite',
32
+ accessibilityLive: accessibilityLive ?? 'polite',
33
33
  accessibilityBusy: accessibilityBusy ?? animating,
34
34
  accessibilityAtomic,
35
35
  accessibilityRelevant,
36
36
  });
37
- }, [accessibilityLabel, accessibilityLiveRegion, accessibilityBusy, animating, accessibilityAtomic, accessibilityRelevant]);
37
+ }, [accessibilityLabel, accessibilityLive, accessibilityBusy, animating, accessibilityAtomic, accessibilityRelevant]);
38
38
  // Handle numeric size
39
39
  const sizeVariant = typeof size === 'number' ? 'md' : size;
40
40
  const customSize = typeof size === 'number' ? size : undefined;
@@ -6,7 +6,7 @@ import { isIconName } from '../Icon/icon-resolver';
6
6
  import type { AlertProps } from './types';
7
7
 
8
8
  // Default icon names for each intent
9
- const defaultIcons = {
9
+ const defaultIcons: Record<string, string> = {
10
10
  primary: 'information',
11
11
  success: 'check-circle',
12
12
  error: 'alert-circle',
@@ -7,7 +7,7 @@ import { isIconName } from '../Icon/icon-resolver';
7
7
  import useMergeRefs from '../hooks/useMergeRefs';
8
8
 
9
9
  // Default icons for each intent
10
- const defaultIcons = {
10
+ const defaultIcons: Record<string, string> = {
11
11
  primary: 'information',
12
12
  success: 'check-circle',
13
13
  error: 'alert-circle',
@@ -27,7 +27,7 @@ const Avatar = forwardRef<View, AvatarProps>(({
27
27
  accessibilityHint,
28
28
  accessibilityDisabled,
29
29
  accessibilityHidden,
30
- accessibilityRole: accessibilityRole ?? 'image',
30
+ accessibilityRole: accessibilityRole ?? 'img',
31
31
  });
32
32
  }, [accessibilityLabel, alt, accessibilityHint, accessibilityDisabled, accessibilityHidden, accessibilityRole]);
33
33
  const [hasError, setHasError] = useState(false);
@@ -13,7 +13,8 @@ const Badge = forwardRef<HTMLSpanElement, BadgeProps>((props, ref) => {
13
13
  const {
14
14
  children,
15
15
  size = 'md',
16
- type = 'filled',
16
+ type: typeProp,
17
+ variant,
17
18
  color = 'blue',
18
19
  icon,
19
20
  style,
@@ -21,13 +22,16 @@ const Badge = forwardRef<HTMLSpanElement, BadgeProps>((props, ref) => {
21
22
  id,
22
23
  } = props;
23
24
 
25
+ // variant is an alias for type - variant takes precedence if both are set
26
+ const type = variant ?? typeProp ?? 'filled';
27
+
24
28
  badgeStyles.useVariants({
25
29
  size,
26
30
  type,
27
31
  });
28
32
 
29
33
  const badgeStyle = (badgeStyles.badge as any)({ color });
30
- const contentStyle = badgeStyles.content;
34
+ const contentStyle = badgeStyles.content as any;
31
35
  const textStyle = (badgeStyles.text as any)({ color });
32
36
 
33
37
  const badgeProps = getWebProps([badgeStyle]);
@@ -29,6 +29,11 @@ export interface BadgeProps extends BaseProps {
29
29
  */
30
30
  type?: BadgeType;
31
31
 
32
+ /**
33
+ * Alias for type - the visual style variant of the badge
34
+ */
35
+ variant?: BadgeType;
36
+
32
37
  /**
33
38
  * The color scheme of the badge
34
39
  */
@@ -1,12 +1,6 @@
1
1
  import React, { forwardRef, isValidElement, useState } from 'react';
2
2
  import { Pressable, Text, View } from 'react-native';
3
- import {
4
- breadcrumbContainerStyles,
5
- breadcrumbItemStyles,
6
- breadcrumbSeparatorStyles,
7
- breadcrumbEllipsisStyles,
8
- breadcrumbMenuButtonStyles
9
- } from './Breadcrumb.styles';
3
+ import { breadcrumbStyles } from './Breadcrumb.styles';
10
4
  import type { BreadcrumbProps, BreadcrumbItem as BreadcrumbItemType } from './types';
11
5
  import Icon from '../Icon';
12
6
  import type { IconName } from '../Icon/icon-types';
@@ -26,19 +20,19 @@ const BreadcrumbItem: React.FC<BreadcrumbItemProps> = ({ item, isLast, size, int
26
20
  const isDisabled = item.disabled || false;
27
21
 
28
22
  // Apply size variant
29
- breadcrumbItemStyles.useVariants({
23
+ breadcrumbStyles.useVariants({
30
24
  size,
31
25
  });
32
26
 
33
27
  // Get dynamic item text style
34
- const itemTextStyle = (breadcrumbItemStyles.itemText as any)({
28
+ const itemTextStyle = (breadcrumbStyles.itemText as any)({
35
29
  intent,
36
30
  isLast,
37
31
  disabled: isDisabled,
38
32
  clickable: isClickable,
39
33
  });
40
34
 
41
- const iconStyle = breadcrumbItemStyles.icon;
35
+ const iconStyle = (breadcrumbStyles.icon as any)({});
42
36
 
43
37
  const renderIcon = () => {
44
38
  if (!item.icon) return null;
@@ -59,8 +53,10 @@ const BreadcrumbItem: React.FC<BreadcrumbItemProps> = ({ item, isLast, size, int
59
53
  return null;
60
54
  };
61
55
 
56
+ const itemContainerStyle = (breadcrumbStyles.item as any)({});
57
+
62
58
  const content = (
63
- <View style={[breadcrumbItemStyles.item, itemStyle]}>
59
+ <View style={[itemContainerStyle, itemStyle]}>
64
60
  {item.icon && <View style={iconStyle}>{renderIcon()}</View>}
65
61
  <Text style={itemTextStyle}>{item.label}</Text>
66
62
  </View>
@@ -91,8 +87,8 @@ interface BreadcrumbSeparatorProps {
91
87
  }
92
88
 
93
89
  const BreadcrumbSeparator: React.FC<BreadcrumbSeparatorProps> = ({ separator, size, separatorStyle }) => {
94
- breadcrumbSeparatorStyles.useVariants({ size });
95
- const sepStyle = breadcrumbSeparatorStyles.separator;
90
+ breadcrumbStyles.useVariants({ size });
91
+ const sepStyle = (breadcrumbStyles.separator as any)({});
96
92
 
97
93
  if (typeof separator === 'string') {
98
94
  return <Text style={[sepStyle, separatorStyle]}>{separator}</Text>;
@@ -106,11 +102,12 @@ interface BreadcrumbEllipsisProps {
106
102
  }
107
103
 
108
104
  const BreadcrumbEllipsis: React.FC<BreadcrumbEllipsisProps> = ({ size, intent }) => {
109
- breadcrumbEllipsisStyles.useVariants({ size });
110
- const iconStyle = breadcrumbEllipsisStyles.icon({ intent });
105
+ breadcrumbStyles.useVariants({ size });
106
+ const ellipsisStyle = (breadcrumbStyles.ellipsis as any)({});
107
+ const iconStyle = (breadcrumbStyles.ellipsisIcon as any)({ intent });
111
108
 
112
109
  return (
113
- <View style={breadcrumbEllipsisStyles.ellipsis}>
110
+ <View style={ellipsisStyle}>
114
111
  <Icon name="dots-horizontal" style={iconStyle} />
115
112
  </View>
116
113
  );
@@ -132,9 +129,11 @@ const Breadcrumb = forwardRef<View, BreadcrumbProps>(({
132
129
  }, ref) => {
133
130
  const [menuOpen, setMenuOpen] = useState(false);
134
131
 
135
- // Apply variants for menu button
136
- breadcrumbMenuButtonStyles.useVariants({ size });
137
- const menuIconStyle = breadcrumbMenuButtonStyles.icon({ intent });
132
+ // Apply variants
133
+ breadcrumbStyles.useVariants({ size });
134
+ const containerStyle = (breadcrumbStyles.container as any)({});
135
+ const menuButtonStyle = (breadcrumbStyles.menuButton as any)({});
136
+ const menuIconStyle = (breadcrumbStyles.menuButtonIcon as any)({ intent });
138
137
 
139
138
  // Handle responsive collapsing
140
139
  let displayItems = items;
@@ -172,7 +171,7 @@ const Breadcrumb = forwardRef<View, BreadcrumbProps>(({
172
171
  <View
173
172
  ref={ref}
174
173
  nativeID={id}
175
- style={[breadcrumbContainerStyles.container, style]}
174
+ style={[containerStyle, style]}
176
175
  testID={testID}
177
176
  accessibilityLabel="Breadcrumb"
178
177
  >
@@ -200,7 +199,7 @@ const Breadcrumb = forwardRef<View, BreadcrumbProps>(({
200
199
  size={size}
201
200
  >
202
201
  <Pressable
203
- style={breadcrumbMenuButtonStyles.button}
202
+ style={menuButtonStyle}
204
203
  accessibilityRole="button"
205
204
  accessibilityLabel="Show more breadcrumb items"
206
205
  >
@@ -68,14 +68,14 @@ const Button = forwardRef<ComponentRef<typeof TouchableOpacity>, ButtonProps>((p
68
68
  };
69
69
 
70
70
  // Map button size to icon size
71
- const iconSizeMap = {
71
+ const iconSizeMap: Record<string, number> = {
72
72
  xs: 12,
73
73
  sm: 14,
74
74
  md: 16,
75
75
  lg: 18,
76
76
  xl: 20,
77
- } as const;
78
- const iconSize = iconSizeMap[size];
77
+ };
78
+ const iconSize = iconSizeMap[size] ?? 16;
79
79
 
80
80
 
81
81
  // Use children if available, otherwise use title
@@ -17,7 +17,8 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
17
17
  onPress,
18
18
  disabled = false,
19
19
  loading = false,
20
- type = 'contained',
20
+ type: typeProp,
21
+ variant,
21
22
  intent = 'primary',
22
23
  size = 'md',
23
24
  gradient,
@@ -41,6 +42,9 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
41
42
  accessibilityHasPopup,
42
43
  } = props;
43
44
 
45
+ // variant is an alias for type - variant takes precedence if both are set
46
+ const type = variant ?? typeProp ?? 'contained';
47
+
44
48
  // Button is effectively disabled when loading
45
49
  const isDisabled = disabled || loading;
46
50
 
@@ -48,6 +48,11 @@ export interface ButtonProps extends BaseProps, InteractiveAccessibilityProps {
48
48
  */
49
49
  type?: ButtonType;
50
50
 
51
+ /**
52
+ * Alias for type - the visual style variant of the button
53
+ */
54
+ variant?: ButtonType;
55
+
51
56
  /**
52
57
  * The intent/color scheme of the button
53
58
  */
@@ -11,7 +11,8 @@ import { getWebInteractiveAriaProps } from '../utils/accessibility';
11
11
  */
12
12
  const Card = forwardRef<HTMLDivElement | HTMLButtonElement, CardProps>(({
13
13
  children,
14
- type = 'elevated',
14
+ type: typeProp,
15
+ variant,
15
16
  radius = 'md',
16
17
  intent,
17
18
  clickable = false,
@@ -36,6 +37,8 @@ const Card = forwardRef<HTMLDivElement | HTMLButtonElement, CardProps>(({
36
37
  accessibilityRole,
37
38
  accessibilityPressed,
38
39
  }, ref) => {
40
+ // variant is an alias for type - variant takes precedence if both are set
41
+ const type = variant ?? typeProp ?? 'elevated';
39
42
  // Generate ARIA props
40
43
  const ariaProps = useMemo(() => {
41
44
  return getWebInteractiveAriaProps({
package/src/Card/types.ts CHANGED
@@ -24,6 +24,11 @@ export interface CardProps extends ContainerStyleProps, InteractiveAccessibility
24
24
  */
25
25
  type?: CardType;
26
26
 
27
+ /**
28
+ * Alias for type - the visual style variant of the card
29
+ */
30
+ variant?: CardType;
31
+
27
32
  /**
28
33
  * The border radius of the card
29
34
  */
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, forwardRef, useMemo } from 'react';
2
- import { Modal, View, Text, TouchableOpacity, TouchableWithoutFeedback, BackHandler } from 'react-native';
2
+ import { Modal, View, Text, TouchableOpacity, TouchableWithoutFeedback, BackHandler, GestureResponderEvent } from 'react-native';
3
3
  import Animated, { useSharedValue, useAnimatedStyle, withTiming, Easing } from 'react-native-reanimated';
4
4
  import { DialogProps } from './types';
5
5
  import { dialogStyles } from './Dialog.styles';
@@ -11,7 +11,7 @@ const Dialog = forwardRef<View, DialogProps>(({
11
11
  title,
12
12
  children,
13
13
  size = 'md',
14
- type = 'standard',
14
+ type = 'default',
15
15
  showCloseButton = true,
16
16
  closeOnBackdropClick = true,
17
17
  animationType = 'fade',
@@ -135,7 +135,7 @@ const Dialog = forwardRef<View, DialogProps>(({
135
135
  >
136
136
  <TouchableWithoutFeedback onPress={handleBackdropPress}>
137
137
  <Animated.View style={[backdropStyle, backdropAnimatedStyle]}>
138
- <TouchableWithoutFeedback onPress={(e) => e.stopPropagation()}>
138
+ <TouchableWithoutFeedback onPress={(e: GestureResponderEvent) => e.stopPropagation()}>
139
139
  <Animated.View ref={ref as any} style={[containerStyle, style, containerAnimatedStyle]} nativeID={id} {...nativeA11yProps}>
140
140
  {(title || showCloseButton) && (
141
141
  <View style={headerStyle}>
@@ -45,8 +45,8 @@ const Divider = forwardRef<HTMLDivElement, DividerProps>(({
45
45
 
46
46
  // Generate web props
47
47
  const dividerProps = getWebProps([dividerStyle, style as any]);
48
- const containerProps = getWebProps([dividerStyles.container]);
49
- const contentProps = getWebProps([dividerStyles.content]);
48
+ const containerProps = getWebProps([dividerStyles.container as any]);
49
+ const contentProps = getWebProps([dividerStyles.content as any]);
50
50
  const lineProps = getWebProps([lineStyle]);
51
51
 
52
52
  const mergedDividerRef = useMergeRefs(ref, dividerProps.ref);
@@ -45,7 +45,8 @@ const Icon = forwardRef<HTMLSpanElement, IconProps>((props, ref) => {
45
45
  iconSize = size;
46
46
  } else {
47
47
  const themeSize = theme.sizes.icon[size as keyof typeof theme.sizes.icon];
48
- iconSize = typeof themeSize === 'number' ? themeSize : (themeSize?.width ?? 24);
48
+ const rawSize = typeof themeSize === 'number' ? themeSize : themeSize?.width;
49
+ iconSize = typeof rawSize === 'number' ? rawSize : 24;
49
50
  }
50
51
 
51
52
  // Compute color - priority: intent > color > textColor > default
@@ -70,7 +71,6 @@ const Icon = forwardRef<HTMLSpanElement, IconProps>((props, ref) => {
70
71
  ref={mergedRef}
71
72
  id={id}
72
73
  style={{
73
- ...iconProps.style,
74
74
  fontSize: iconSize,
75
75
  width: '1em',
76
76
  height: '1em',
package/src/Icon/types.ts CHANGED
@@ -4,6 +4,9 @@ import type { Size, Text } from '@idealyst/theme';
4
4
  import { Color, Intent } from '@idealyst/theme';
5
5
  import { BaseProps } from '../utils/viewStyleProps';
6
6
 
7
+ // Re-export IconName for external consumers
8
+ export type { IconName } from './icon-types';
9
+
7
10
  export type IconSizeVariant = Size | number;
8
11
 
9
12
  /**
@@ -20,7 +20,7 @@ export const imageStyles = defineStyle('Image', (theme: Theme) => ({
20
20
  container: (_props: ImageDynamicProps) => ({
21
21
  position: 'relative' as const,
22
22
  overflow: 'hidden' as const,
23
- backgroundColor: theme.colors['gray.200'],
23
+ backgroundColor: theme.colors.pallet.gray?.['200'] ?? theme.colors.surface.secondary,
24
24
  }),
25
25
 
26
26
  image: (_props: ImageDynamicProps) => ({
@@ -37,7 +37,7 @@ export const imageStyles = defineStyle('Image', (theme: Theme) => ({
37
37
  display: 'flex' as const,
38
38
  alignItems: 'center' as const,
39
39
  justifyContent: 'center' as const,
40
- backgroundColor: theme.colors['gray.200'],
40
+ backgroundColor: theme.colors.pallet.gray?.['200'] ?? theme.colors.surface.secondary,
41
41
  }),
42
42
 
43
43
  fallback: (_props: ImageDynamicProps) => ({
@@ -49,11 +49,11 @@ export const imageStyles = defineStyle('Image', (theme: Theme) => ({
49
49
  display: 'flex' as const,
50
50
  alignItems: 'center' as const,
51
51
  justifyContent: 'center' as const,
52
- backgroundColor: theme.colors['gray.300'],
53
- color: theme.colors['gray.600'],
52
+ backgroundColor: theme.colors.pallet.gray?.['300'] ?? theme.colors.surface.tertiary,
53
+ color: theme.colors.pallet.gray?.['600'] ?? theme.colors.text.secondary,
54
54
  }),
55
55
 
56
56
  loadingIndicator: (_props: ImageDynamicProps) => ({
57
- color: theme.colors['gray.600'],
57
+ color: theme.colors.pallet.gray?.['600'] ?? theme.colors.text.secondary,
58
58
  }),
59
59
  }));
@@ -50,15 +50,15 @@ const Image: React.FC<ImageProps> = ({
50
50
  ]);
51
51
 
52
52
  const imageProps = getWebProps([
53
- imageStyles.image,
53
+ imageStyles.image as any,
54
54
  {
55
55
  objectFit: objectFit,
56
56
  borderRadius: borderRadius ? `${borderRadius}px` : undefined,
57
57
  }
58
58
  ]);
59
59
 
60
- const placeholderProps = getWebProps([imageStyles.placeholder]);
61
- const fallbackProps = getWebProps([imageStyles.fallback]);
60
+ const placeholderProps = getWebProps([imageStyles.placeholder as any]);
61
+ const fallbackProps = getWebProps([imageStyles.fallback as any]);
62
62
 
63
63
  return (
64
64
  <div
@@ -64,9 +64,8 @@ const List = forwardRef<View, ListProps>(({
64
64
  const processedChildren = childArray.map((child, index) => {
65
65
  if (isValidElement(child)) {
66
66
  return cloneElement(child, {
67
- ...child.props,
68
67
  isLast: index === childArray.length - 1,
69
- });
68
+ } as Record<string, unknown>);
70
69
  }
71
70
  return child;
72
71
  });
@@ -52,9 +52,8 @@ const List: React.FC<ListProps> = ({
52
52
  const processedChildren = childArray.map((child, index) => {
53
53
  if (isValidElement(child)) {
54
54
  return cloneElement(child, {
55
- ...child.props,
56
55
  isLast: index === childArray.length - 1,
57
- });
56
+ } as Record<string, unknown>);
58
57
  }
59
58
  return child;
60
59
  });
@@ -10,9 +10,9 @@ const ListSection: React.FC<ListSectionProps> = ({
10
10
  style,
11
11
  testID,
12
12
  }) => {
13
- const sectionProps = getWebProps([listStyles.section, style as any]);
14
- const titleProps = getWebProps([listStyles.sectionTitle]);
15
- const contentProps = getWebProps([listStyles.sectionContent]);
13
+ const sectionProps = getWebProps([listStyles.section as any, style as any]);
14
+ const titleProps = getWebProps([listStyles.sectionTitle as any]);
15
+ const contentProps = getWebProps([listStyles.sectionContent as any]);
16
16
 
17
17
  return (
18
18
  <div {...sectionProps} data-testid={testID}>
@@ -5,7 +5,7 @@ import type { MenuProps } from './types';
5
5
  import MenuItem from './MenuItem.web';
6
6
  import useMergeRefs from '../hooks/useMergeRefs';
7
7
  import { PositionedPortal } from '../internal/PositionedPortal';
8
- import { getWebInteractiveAriaProps, generateAccessibilityId, MENU_KEYS } from '../utils/accessibility';
8
+ import { getWebInteractiveAriaProps, generateAccessibilityId, MENU_KEYS, matchesKey } from '../utils/accessibility';
9
9
 
10
10
  /**
11
11
  * Dropdown menu for actions and navigation triggered by a button or element.
@@ -64,9 +64,7 @@ const Menu = forwardRef<HTMLDivElement, MenuProps>(({
64
64
 
65
65
  // Keyboard navigation handler
66
66
  const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
67
- const key = e.key;
68
-
69
- if (MENU_KEYS.close.includes(key)) {
67
+ if (matchesKey(e, MENU_KEYS.close)) {
70
68
  e.preventDefault();
71
69
  onOpenChange?.(false);
72
70
  // Return focus to trigger
@@ -78,16 +76,16 @@ const Menu = forwardRef<HTMLDivElement, MenuProps>(({
78
76
 
79
77
  let nextIndex = focusedIndex.current;
80
78
 
81
- if (MENU_KEYS.next.includes(key)) {
79
+ if (matchesKey(e, MENU_KEYS.next)) {
82
80
  e.preventDefault();
83
81
  nextIndex = focusedIndex.current < enabledItems.length - 1 ? focusedIndex.current + 1 : 0;
84
- } else if (MENU_KEYS.prev.includes(key)) {
82
+ } else if (matchesKey(e, MENU_KEYS.prev)) {
85
83
  e.preventDefault();
86
84
  nextIndex = focusedIndex.current > 0 ? focusedIndex.current - 1 : enabledItems.length - 1;
87
- } else if (MENU_KEYS.first.includes(key)) {
85
+ } else if (matchesKey(e, MENU_KEYS.first)) {
88
86
  e.preventDefault();
89
87
  nextIndex = 0;
90
- } else if (MENU_KEYS.last.includes(key)) {
88
+ } else if (matchesKey(e, MENU_KEYS.last)) {
91
89
  e.preventDefault();
92
90
  nextIndex = enabledItems.length - 1;
93
91
  }
@@ -119,7 +117,7 @@ const Menu = forwardRef<HTMLDivElement, MenuProps>(({
119
117
 
120
118
  const overlayProps = getWebProps([(menuStyles.overlay as any)({})]);
121
119
  const menuProps = getWebProps([(menuStyles.menu as any)({}), style as any]);
122
- const separatorProps = getWebProps([menuStyles.separator]);
120
+ const separatorProps = getWebProps([menuStyles.separator as any]);
123
121
 
124
122
  const handleTriggerClick = () => {
125
123
  onOpenChange?.(!open);
@@ -161,7 +159,7 @@ const Menu = forwardRef<HTMLDivElement, MenuProps>(({
161
159
 
162
160
  <PositionedPortal
163
161
  open={open}
164
- anchor={triggerRef}
162
+ anchor={triggerRef as React.RefObject<HTMLElement>}
165
163
  placement={placement}
166
164
  offset={4}
167
165
  onClickOutside={() => onOpenChange?.(false)}
@@ -67,7 +67,7 @@ const MenuItem = forwardRef<HTMLButtonElement, MenuItemProps>(({ item, onPress,
67
67
  <button
68
68
  {...itemProps}
69
69
  ref={mergedRef}
70
- style={{ ...buttonResetStyles, ...itemProps.style }}
70
+ style={buttonResetStyles}
71
71
  onClick={() => onPress(item)}
72
72
  disabled={item.disabled}
73
73
  role="menuitem"
@@ -49,7 +49,7 @@ const Popover = forwardRef<HTMLDivElement, PopoverProps>(({
49
49
  popoverStyles.useVariants({});
50
50
 
51
51
  const containerProps = getWebProps([(popoverStyles.container as any)({})]);
52
- const contentProps = getWebProps([popoverStyles.content]);
52
+ const contentProps = getWebProps([popoverStyles.content as any]);
53
53
 
54
54
  const mergedPopoverRef = useMergeRefs(ref, popoverRef);
55
55
 
@@ -78,7 +78,7 @@ const Pressable = forwardRef<HTMLDivElement, PressableProps>(({
78
78
  id={id}
79
79
  role={accessibilityRole}
80
80
  tabIndex={disabled ? -1 : 0}
81
- style={{ ...baseStyle, ...webProps.style }}
81
+ style={baseStyle}
82
82
  onMouseDown={handleMouseDown}
83
83
  onMouseUp={handleMouseUp}
84
84
  onMouseLeave={handleMouseUp} // Handle mouse leave as press out