@idealyst/components 1.2.29 → 1.2.31

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 (143) hide show
  1. package/README.md +3 -3
  2. package/package.json +4 -4
  3. package/plugin/__tests__/web.test.ts +2 -2
  4. package/plugin/web.js +2 -0
  5. package/src/Accordion/Accordion.native.tsx +3 -2
  6. package/src/ActivityIndicator/ActivityIndicator.native.tsx +4 -2
  7. package/src/ActivityIndicator/ActivityIndicator.styles.tsx +22 -27
  8. package/src/ActivityIndicator/ActivityIndicator.web.tsx +17 -29
  9. package/src/Alert/Alert.native.tsx +20 -10
  10. package/src/Alert/Alert.styles.tsx +173 -86
  11. package/src/Alert/Alert.web.tsx +34 -30
  12. package/src/Alert/types.ts +53 -3
  13. package/src/Avatar/Avatar.native.tsx +3 -2
  14. package/src/Avatar/Avatar.web.tsx +2 -1
  15. package/src/Avatar/types.ts +1 -1
  16. package/src/Badge/Badge.native.tsx +18 -6
  17. package/src/Badge/Badge.styles.tsx +22 -5
  18. package/src/Badge/Badge.web.tsx +12 -4
  19. package/src/Badge/types.ts +14 -2
  20. package/src/Breadcrumb/Breadcrumb.native.tsx +3 -2
  21. package/src/Button/Button.native.tsx +16 -6
  22. package/src/Button/Button.styles.tsx +2 -2
  23. package/src/Button/Button.web.tsx +19 -15
  24. package/src/Button/types.ts +6 -10
  25. package/src/Card/Card.native.tsx +27 -3
  26. package/src/Card/Card.web.tsx +30 -4
  27. package/src/Card/types.ts +15 -0
  28. package/src/Checkbox/Checkbox.native.tsx +5 -4
  29. package/src/Checkbox/Checkbox.styles.tsx +62 -52
  30. package/src/Checkbox/Checkbox.web.tsx +4 -3
  31. package/src/Checkbox/types.ts +1 -1
  32. package/src/Chip/Chip.native.tsx +30 -7
  33. package/src/Chip/Chip.web.tsx +28 -5
  34. package/src/Chip/types.ts +15 -0
  35. package/src/Dialog/Dialog.native.tsx +6 -6
  36. package/src/Dialog/Dialog.web.tsx +5 -5
  37. package/src/Dialog/types.ts +2 -2
  38. package/src/Divider/Divider.native.tsx +20 -17
  39. package/src/Divider/Divider.styles.tsx +51 -29
  40. package/src/Divider/Divider.web.tsx +5 -4
  41. package/src/Divider/types.ts +3 -3
  42. package/src/Icon/Icon.native.tsx +3 -2
  43. package/src/Icon/Icon.web.tsx +2 -1
  44. package/src/Icon/IconSvg/IconSvg.native.tsx +3 -2
  45. package/src/IconButton/IconButton.native.tsx +219 -0
  46. package/src/IconButton/IconButton.styles.tsx +127 -0
  47. package/src/IconButton/IconButton.web.tsx +198 -0
  48. package/src/IconButton/index.native.ts +5 -0
  49. package/src/IconButton/index.ts +5 -0
  50. package/src/IconButton/index.web.ts +5 -0
  51. package/src/IconButton/types.ts +84 -0
  52. package/src/Image/Image.native.tsx +3 -2
  53. package/src/Input/Input.native.tsx +42 -290
  54. package/src/Input/Input.styles.tsx +1 -1
  55. package/src/Input/Input.web.tsx +37 -288
  56. package/src/Input/index.native.ts +9 -2
  57. package/src/Input/index.ts +8 -1
  58. package/src/Input/index.web.ts +8 -1
  59. package/src/Input/types.ts +1 -1
  60. package/src/List/List.native.tsx +3 -2
  61. package/src/List/ListItem.native.tsx +3 -2
  62. package/src/List/ListSection.native.tsx +3 -2
  63. package/src/Menu/Menu.native.tsx +2 -1
  64. package/src/Menu/Menu.styles.tsx +79 -29
  65. package/src/Menu/Menu.web.tsx +2 -1
  66. package/src/Menu/MenuItem.native.tsx +4 -3
  67. package/src/Menu/MenuItem.styles.tsx +81 -32
  68. package/src/Menu/MenuItem.web.tsx +2 -1
  69. package/src/Menu/docs.ts +1 -1
  70. package/src/Popover/Popover.native.tsx +2 -1
  71. package/src/Popover/Popover.web.tsx +2 -1
  72. package/src/Popover/types.ts +15 -4
  73. package/src/Pressable/Pressable.native.tsx +3 -2
  74. package/src/Pressable/Pressable.web.tsx +3 -5
  75. package/src/Progress/Progress.native.tsx +5 -4
  76. package/src/Progress/Progress.web.tsx +3 -3
  77. package/src/Progress/types.ts +3 -3
  78. package/src/RadioButton/RadioButton.native.tsx +4 -3
  79. package/src/RadioButton/RadioButton.styles.tsx +53 -33
  80. package/src/RadioButton/RadioGroup.native.tsx +3 -2
  81. package/src/SVGImage/SVGImage.native.tsx +5 -4
  82. package/src/SVGImage/SVGImage.styles.tsx +44 -10
  83. package/src/SVGImage/SVGImage.web.tsx +2 -1
  84. package/src/Screen/Screen.native.tsx +2 -1
  85. package/src/Screen/Screen.web.tsx +2 -1
  86. package/src/Select/Select.native.tsx +6 -5
  87. package/src/Select/Select.styles.tsx +1 -1
  88. package/src/Select/Select.web.tsx +4 -3
  89. package/src/Select/types.ts +1 -1
  90. package/src/Skeleton/Skeleton.native.tsx +2 -1
  91. package/src/Skeleton/Skeleton.web.tsx +1 -1
  92. package/src/Slider/Slider.native.tsx +9 -8
  93. package/src/Slider/Slider.web.tsx +10 -9
  94. package/src/Slider/types.ts +9 -2
  95. package/src/Switch/Switch.native.tsx +7 -6
  96. package/src/Switch/Switch.styles.tsx +52 -17
  97. package/src/Switch/Switch.web.tsx +15 -16
  98. package/src/Switch/types.ts +44 -4
  99. package/src/TabBar/TabBar.native.tsx +3 -2
  100. package/src/Text/Text.native.tsx +3 -2
  101. package/src/Text/Text.web.tsx +2 -1
  102. package/src/TextArea/TextArea.native.tsx +3 -2
  103. package/src/TextArea/TextArea.styles.tsx +2 -2
  104. package/src/TextArea/TextArea.web.tsx +2 -1
  105. package/src/TextInput/TextInput.native.tsx +300 -0
  106. package/src/TextInput/TextInput.styles.tsx +207 -0
  107. package/src/TextInput/TextInput.web.tsx +301 -0
  108. package/src/TextInput/index.native.ts +3 -0
  109. package/src/TextInput/index.ts +5 -0
  110. package/src/TextInput/index.web.ts +5 -0
  111. package/src/TextInput/types.ts +163 -0
  112. package/src/Tooltip/Tooltip.native.tsx +3 -2
  113. package/src/Video/Video.native.tsx +4 -3
  114. package/src/View/View.native.tsx +2 -1
  115. package/src/View/View.styles.tsx +1 -0
  116. package/src/View/View.web.tsx +9 -2
  117. package/src/examples/ActivityIndicatorExamples.tsx +177 -0
  118. package/src/examples/AlertExamples.tsx +5 -5
  119. package/src/examples/ButtonExamples.tsx +12 -12
  120. package/src/examples/CardExamples.tsx +1 -1
  121. package/src/examples/CheckboxExamples.tsx +2 -2
  122. package/src/examples/ChipExamples.tsx +6 -6
  123. package/src/examples/DialogExamples.tsx +1 -1
  124. package/src/examples/DividerExamples.tsx +1 -1
  125. package/src/examples/InputExamples.tsx +1 -1
  126. package/src/examples/LinkExamples.tsx +1 -1
  127. package/src/examples/ListExamples.tsx +1 -1
  128. package/src/examples/MenuExamples.tsx +2 -2
  129. package/src/examples/ProgressExamples.tsx +1 -1
  130. package/src/examples/RadioButtonExamples.tsx +5 -5
  131. package/src/examples/SVGImageExamples.tsx +1 -1
  132. package/src/examples/SelectExamples.tsx +1 -1
  133. package/src/examples/SliderExamples.tsx +5 -5
  134. package/src/examples/SwitchExamples.tsx +26 -26
  135. package/src/examples/TableExamples.tsx +1 -1
  136. package/src/examples/TooltipExamples.tsx +2 -2
  137. package/src/examples/index.ts +1 -0
  138. package/src/extensions/index.ts +1 -0
  139. package/src/extensions/types.ts +22 -3
  140. package/src/index.native.ts +4 -0
  141. package/src/index.ts +27 -2
  142. package/src/utils/index.ts +12 -0
  143. package/src/utils/refTypes.ts +50 -0
@@ -1,16 +1,21 @@
1
- import { forwardRef, ComponentRef, useMemo } from 'react';
1
+ import { forwardRef, useMemo, useEffect, useRef } from 'react';
2
2
  import { View, Pressable } from 'react-native';
3
3
  import { CardProps } from './types';
4
4
  import { cardStyles } from './Card.styles';
5
5
  import { getNativeInteractiveAccessibilityProps } from '../utils/accessibility';
6
+ import type { IdealystElement } from '../utils/refTypes';
6
7
 
7
- const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressable>, CardProps>(({
8
+ // Track if we've logged the onClick deprecation warning (log once per session)
9
+ let hasLoggedOnClickWarning = false;
10
+
11
+ const Card = forwardRef<IdealystElement, CardProps>(({
8
12
  children,
9
13
  type = 'elevated',
10
14
  radius = 'md',
11
15
  intent: _intent = 'neutral',
12
16
  clickable = false,
13
17
  onPress,
18
+ onClick,
14
19
  disabled = false,
15
20
  // Spacing variants from ContainerStyleProps
16
21
  gap,
@@ -31,6 +36,22 @@ const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressabl
31
36
  accessibilityRole,
32
37
  accessibilityPressed,
33
38
  }, ref) => {
39
+ const hasWarnedRef = useRef(false);
40
+
41
+ // Warn about onClick usage (deprecated)
42
+ useEffect(() => {
43
+ if (onClick && !hasWarnedRef.current && !hasLoggedOnClickWarning) {
44
+ hasWarnedRef.current = true;
45
+ hasLoggedOnClickWarning = true;
46
+ console.warn(
47
+ '[Card] onClick is deprecated. Use onPress instead.\n' +
48
+ 'Card is a cross-platform component that follows React Native conventions.\n' +
49
+ 'onClick will be removed in a future version.\n\n' +
50
+ 'Migration: Replace onClick={handler} with onPress={handler}'
51
+ );
52
+ }
53
+ }, [onClick]);
54
+
34
55
  // Generate native accessibility props
35
56
  const nativeA11yProps = useMemo(() => {
36
57
  return getNativeInteractiveAccessibilityProps({
@@ -64,6 +85,9 @@ const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressabl
64
85
  // Use appropriate component based on clickable state
65
86
  const Component = clickable ? Pressable : View;
66
87
 
88
+ // Prefer onPress, fall back to deprecated onClick
89
+ const pressHandler = onPress ?? onClick;
90
+
67
91
  const componentProps = {
68
92
  ref,
69
93
  nativeID: id,
@@ -71,7 +95,7 @@ const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressabl
71
95
  testID,
72
96
  ...nativeA11yProps,
73
97
  ...(clickable && {
74
- onPress: disabled ? undefined : onPress,
98
+ onPress: disabled ? undefined : pressHandler,
75
99
  disabled,
76
100
  android_ripple: { color: 'rgba(0, 0, 0, 0.1)' },
77
101
  }),
@@ -1,15 +1,19 @@
1
- import { forwardRef, useMemo } from 'react';
1
+ import { forwardRef, useMemo, useEffect, useRef } from 'react';
2
2
  import { getWebProps } from 'react-native-unistyles/web';
3
3
  import { CardProps } from './types';
4
4
  import { cardStyles } from './Card.styles';
5
5
  import useMergeRefs from '../hooks/useMergeRefs';
6
6
  import { getWebInteractiveAriaProps } from '../utils/accessibility';
7
+ import type { IdealystElement } from '../utils/refTypes';
8
+
9
+ // Track if we've logged the onClick deprecation warning (log once per session)
10
+ let hasLoggedOnClickWarning = false;
7
11
 
8
12
  /**
9
13
  * Container component for grouping related content with elevation and styling options.
10
14
  * Supports elevated, outlined, and filled variants with optional click interaction.
11
15
  */
12
- const Card = forwardRef<HTMLDivElement | HTMLButtonElement, CardProps>(({
16
+ const Card = forwardRef<IdealystElement, CardProps>(({
13
17
  children,
14
18
  type: typeProp,
15
19
  variant,
@@ -17,6 +21,7 @@ const Card = forwardRef<HTMLDivElement | HTMLButtonElement, CardProps>(({
17
21
  intent: _intent,
18
22
  clickable = false,
19
23
  onPress,
24
+ onClick,
20
25
  disabled = false,
21
26
  // Spacing variants from ContainerStyleProps
22
27
  gap,
@@ -37,6 +42,22 @@ const Card = forwardRef<HTMLDivElement | HTMLButtonElement, CardProps>(({
37
42
  accessibilityRole,
38
43
  accessibilityPressed,
39
44
  }, ref) => {
45
+ const hasWarnedRef = useRef(false);
46
+
47
+ // Warn about onClick usage (deprecated)
48
+ useEffect(() => {
49
+ if (onClick && !hasWarnedRef.current && !hasLoggedOnClickWarning) {
50
+ hasWarnedRef.current = true;
51
+ hasLoggedOnClickWarning = true;
52
+ console.warn(
53
+ '[Card] onClick is deprecated. Use onPress instead.\n' +
54
+ 'Card is a cross-platform component that follows React Native conventions.\n' +
55
+ 'onClick will be removed in a future version.\n\n' +
56
+ 'Migration: Replace onClick={handler} with onPress={handler}'
57
+ );
58
+ }
59
+ }, [onClick]);
60
+
40
61
  // variant is an alias for type - variant takes precedence if both are set
41
62
  const type = variant ?? typeProp ?? 'elevated';
42
63
  // Generate ARIA props
@@ -50,9 +71,14 @@ const Card = forwardRef<HTMLDivElement | HTMLButtonElement, CardProps>(({
50
71
  accessibilityPressed,
51
72
  });
52
73
  }, [accessibilityLabel, accessibilityHint, accessibilityDisabled, disabled, accessibilityHidden, accessibilityRole, clickable, accessibilityPressed]);
74
+
53
75
  const handleClick = () => {
54
- if (!disabled && clickable && onPress) {
55
- onPress();
76
+ if (!disabled && clickable) {
77
+ // Prefer onPress, fall back to deprecated onClick
78
+ const handler = onPress ?? onClick;
79
+ if (handler) {
80
+ handler();
81
+ }
56
82
  }
57
83
  };
58
84
 
package/src/Card/types.ts CHANGED
@@ -49,6 +49,21 @@ export interface CardProps extends ContainerStyleProps, InteractiveAccessibility
49
49
  */
50
50
  onPress?: () => void;
51
51
 
52
+ /**
53
+ * @deprecated Use `onPress` instead. This is a cross-platform component - use React Native conventions.
54
+ *
55
+ * Using `onClick` will trigger a console warning in development.
56
+ * This prop exists only for migration convenience and will be removed in a future version.
57
+ *
58
+ * @example
59
+ * // ❌ Don't use onClick
60
+ * <Card clickable onClick={() => {}} />
61
+ *
62
+ * // ✅ Use onPress instead
63
+ * <Card clickable onPress={() => {}} />
64
+ */
65
+ onClick?: () => void;
66
+
52
67
  /**
53
68
  * Whether the card is disabled
54
69
  */
@@ -4,12 +4,13 @@ import MaterialDesignIcons from '@react-native-vector-icons/material-design-icon
4
4
  import { CheckboxProps } from './types';
5
5
  import { checkboxStyles } from './Checkbox.styles';
6
6
  import { getNativeSelectionAccessibilityProps } from '../utils/accessibility';
7
+ import type { IdealystElement } from '../utils/refTypes';
7
8
 
8
- const Checkbox = forwardRef<View, CheckboxProps>(({
9
+ const Checkbox = forwardRef<IdealystElement, CheckboxProps>(({
9
10
  checked = false,
10
11
  indeterminate = false,
11
12
  disabled = false,
12
- onCheckedChange,
13
+ onChange,
13
14
  size = 'md',
14
15
  intent = 'primary',
15
16
  variant = 'default',
@@ -46,7 +47,7 @@ const Checkbox = forwardRef<View, CheckboxProps>(({
46
47
 
47
48
  const newChecked = !internalChecked;
48
49
  setInternalChecked(newChecked);
49
- onCheckedChange?.(newChecked);
50
+ onChange?.(newChecked);
50
51
  };
51
52
 
52
53
  // Generate native accessibility props
@@ -108,7 +109,7 @@ const Checkbox = forwardRef<View, CheckboxProps>(({
108
109
  const helperTextStyle = (checkboxStyles.helperText as any)({ error: !!error });
109
110
 
110
111
  return (
111
- <View ref={ref} nativeID={id} style={[wrapperStyle, style]}>
112
+ <View ref={ref as any} nativeID={id} style={[wrapperStyle, style]}>
112
113
  <Pressable
113
114
  onPress={handlePress}
114
115
  disabled={disabled}
@@ -67,63 +67,61 @@ export const checkboxStyles = defineStyle('Checkbox', (theme: Theme) => ({
67
67
  },
68
68
  }),
69
69
 
70
- checkbox: ({ intent = 'primary', type = 'default', checked = false, disabled = false }: CheckboxDynamicProps) => {
71
- const intentColors = theme.intents[intent];
72
-
73
- // Base border styles based on type
74
- const borderWidth = type === 'outlined' ? 2 : 1;
75
-
76
- // Checked state colors
77
- const backgroundColor = checked ? intentColors.primary : 'transparent';
78
- const borderColor = checked ? intentColors.primary : theme.colors.border.primary;
79
-
80
- return {
81
- alignItems: 'center' as const,
82
- justifyContent: 'center' as const,
83
- borderRadius: 4,
84
- position: 'relative' as const,
85
- backgroundColor,
86
- borderColor,
87
- borderWidth,
88
- borderStyle: 'solid' as const,
89
- opacity: disabled ? 0.5 : 1,
90
- variants: {
91
- size: {
92
- xs: { width: 14, height: 14 },
93
- sm: { width: 16, height: 16 },
94
- md: { width: 20, height: 20 },
95
- lg: { width: 24, height: 24 },
96
- xl: { width: 28, height: 28 },
97
- },
70
+ checkbox: (_props: CheckboxDynamicProps) => ({
71
+ alignItems: 'center' as const,
72
+ justifyContent: 'center' as const,
73
+ borderRadius: 4,
74
+ position: 'relative' as const,
75
+ borderStyle: 'solid' as const,
76
+ variants: {
77
+ size: {
78
+ xs: { width: 14, height: 14 },
79
+ sm: { width: 16, height: 16 },
80
+ md: { width: 20, height: 20 },
81
+ lg: { width: 24, height: 24 },
82
+ xl: { width: 28, height: 28 },
83
+ },
84
+ type: {
85
+ default: { borderWidth: 1 },
86
+ outlined: { borderWidth: 2 },
98
87
  },
99
- _web: {
100
- outline: 'none',
101
- display: 'flex',
102
- boxSizing: 'border-box',
103
- userSelect: 'none',
104
- WebkitAppearance: 'none',
105
- MozAppearance: 'none',
106
- appearance: 'none',
107
- transition: 'all 0.2s ease',
108
- cursor: disabled ? 'not-allowed' : 'pointer',
109
- border: `${borderWidth}px solid ${borderColor}`,
110
- _focus: {
111
- outline: `2px solid ${theme.intents.primary.primary}`,
112
- outlineOffset: '2px',
88
+ checked: {
89
+ true: {
90
+ backgroundColor: theme.$intents.primary,
91
+ borderColor: theme.$intents.primary,
113
92
  },
114
- _hover: disabled ? {} : { opacity: 0.8 },
115
- _active: disabled ? {} : { opacity: 0.6 },
93
+ false: {
94
+ backgroundColor: 'transparent',
95
+ borderColor: theme.colors.border.primary,
96
+ },
97
+ },
98
+ disabled: {
99
+ true: { opacity: 0.5 },
100
+ false: { opacity: 1 },
116
101
  },
117
- } as const;
118
- },
102
+ },
103
+ _web: {
104
+ outline: 'none',
105
+ display: 'flex',
106
+ boxSizing: 'border-box',
107
+ userSelect: 'none',
108
+ WebkitAppearance: 'none',
109
+ MozAppearance: 'none',
110
+ appearance: 'none',
111
+ transition: 'all 0.2s ease',
112
+ _focus: {
113
+ outline: `2px solid ${theme.intents.primary.primary}`,
114
+ outlineOffset: '2px',
115
+ },
116
+ },
117
+ }),
119
118
 
120
- checkmark: ({ checked = false }: CheckboxDynamicProps) => ({
119
+ checkmark: (_props: CheckboxDynamicProps) => ({
121
120
  position: 'absolute' as const,
122
121
  display: 'flex' as const,
123
122
  alignItems: 'center' as const,
124
123
  justifyContent: 'center' as const,
125
124
  color: '#ffffff',
126
- opacity: checked ? 1 : 0,
127
125
  variants: {
128
126
  size: {
129
127
  xs: { width: 10, height: 10 },
@@ -132,12 +130,15 @@ export const checkboxStyles = defineStyle('Checkbox', (theme: Theme) => ({
132
130
  lg: { width: 16, height: 16 },
133
131
  xl: { width: 20, height: 20 },
134
132
  },
133
+ checked: {
134
+ true: { opacity: 1 },
135
+ false: { opacity: 0 },
136
+ },
135
137
  },
136
138
  }),
137
139
 
138
- label: ({ disabled = false }: CheckboxDynamicProps) => ({
140
+ label: (_props: CheckboxDynamicProps) => ({
139
141
  color: theme.colors.text.primary,
140
- opacity: disabled ? 0.5 : 1,
141
142
  variants: {
142
143
  size: {
143
144
  xs: { fontSize: 12 },
@@ -146,6 +147,10 @@ export const checkboxStyles = defineStyle('Checkbox', (theme: Theme) => ({
146
147
  lg: { fontSize: 18 },
147
148
  xl: { fontSize: 20 },
148
149
  },
150
+ disabled: {
151
+ true: { opacity: 0.5 },
152
+ false: { opacity: 1 },
153
+ },
149
154
  },
150
155
  _web: {
151
156
  display: 'block',
@@ -155,9 +160,14 @@ export const checkboxStyles = defineStyle('Checkbox', (theme: Theme) => ({
155
160
  },
156
161
  }),
157
162
 
158
- helperText: ({ error = false }: CheckboxDynamicProps) => ({
163
+ helperText: (_props: CheckboxDynamicProps) => ({
159
164
  fontSize: 14,
160
- color: error ? theme.intents.error.primary : theme.colors.text.secondary,
161
165
  marginTop: 2,
166
+ variants: {
167
+ error: {
168
+ true: { color: theme.intents.danger.primary },
169
+ false: { color: theme.colors.text.secondary },
170
+ },
171
+ },
162
172
  }),
163
173
  }));
@@ -5,16 +5,17 @@ import { checkboxStyles } from './Checkbox.styles';
5
5
  import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
6
6
  import useMergeRefs from '../hooks/useMergeRefs';
7
7
  import { getWebSelectionAriaProps, generateAccessibilityId, combineIds } from '../utils/accessibility';
8
+ import type { IdealystElement } from '../utils/refTypes';
8
9
 
9
10
  /**
10
11
  * Checkbox input for boolean selection with support for indeterminate state.
11
12
  * Includes label, helper text, and error display options.
12
13
  */
13
- const Checkbox = forwardRef<HTMLDivElement, CheckboxProps>(({
14
+ const Checkbox = forwardRef<IdealystElement, CheckboxProps>(({
14
15
  checked = false,
15
16
  indeterminate = false,
16
17
  disabled = false,
17
- onCheckedChange,
18
+ onChange,
18
19
  size = 'md',
19
20
  intent = 'primary',
20
21
  variant = 'default',
@@ -56,7 +57,7 @@ const Checkbox = forwardRef<HTMLDivElement, CheckboxProps>(({
56
57
 
57
58
  const newChecked = event.target.checked;
58
59
  setInternalChecked(newChecked);
59
- onCheckedChange?.(newChecked);
60
+ onChange?.(newChecked);
60
61
  };
61
62
 
62
63
  // Generate unique IDs for accessibility
@@ -32,7 +32,7 @@ export interface CheckboxProps extends FormInputStyleProps, SelectionAccessibili
32
32
  /**
33
33
  * Called when the checkbox state changes
34
34
  */
35
- onCheckedChange?: (checked: boolean) => void;
35
+ onChange?: (checked: boolean) => void;
36
36
 
37
37
  /**
38
38
  * The size of the checkbox
@@ -1,11 +1,15 @@
1
- import { isValidElement, forwardRef, ComponentRef } from 'react';
1
+ import { isValidElement, forwardRef, useEffect, useRef } from 'react';
2
2
  import { Pressable, Text, View } from 'react-native';
3
3
  import MaterialDesignIcons from '@react-native-vector-icons/material-design-icons';
4
4
  import { chipStyles } from './Chip.styles';
5
5
  import { isIconName } from '../Icon/icon-resolver';
6
6
  import type { ChipProps } from './types';
7
+ import type { IdealystElement } from '../utils/refTypes';
7
8
 
8
- const Chip = forwardRef<ComponentRef<typeof Pressable>, ChipProps>(({
9
+ // Track if we've logged the onClick deprecation warning (log once per session)
10
+ let hasLoggedOnClickWarning = false;
11
+
12
+ const Chip = forwardRef<IdealystElement, ChipProps>(({
9
13
  label,
10
14
  type = 'filled',
11
15
  intent = 'primary',
@@ -16,6 +20,7 @@ const Chip = forwardRef<ComponentRef<typeof Pressable>, ChipProps>(({
16
20
  selectable = false,
17
21
  selected = false,
18
22
  onPress,
23
+ onClick,
19
24
  disabled = false,
20
25
  style,
21
26
  testID,
@@ -24,10 +29,28 @@ const Chip = forwardRef<ComponentRef<typeof Pressable>, ChipProps>(({
24
29
  accessibilityLabel,
25
30
  accessibilityChecked,
26
31
  }, ref) => {
32
+ const hasWarnedRef = useRef(false);
33
+
34
+ // Warn about onClick usage (deprecated)
35
+ useEffect(() => {
36
+ if (onClick && !hasWarnedRef.current && !hasLoggedOnClickWarning) {
37
+ hasWarnedRef.current = true;
38
+ hasLoggedOnClickWarning = true;
39
+ console.warn(
40
+ '[Chip] onClick is deprecated. Use onPress instead.\n' +
41
+ 'Chip is a cross-platform component that follows React Native conventions.\n' +
42
+ 'onClick will be removed in a future version.\n\n' +
43
+ 'Migration: Replace onClick={handler} with onPress={handler}'
44
+ );
45
+ }
46
+ }, [onClick]);
47
+
27
48
  const handlePress = () => {
28
49
  if (disabled) return;
29
- if (onPress) {
30
- onPress();
50
+ // Prefer onPress, fall back to deprecated onClick
51
+ const handler = onPress ?? onClick;
52
+ if (handler) {
53
+ handler();
31
54
  }
32
55
  };
33
56
 
@@ -72,7 +95,7 @@ const Chip = forwardRef<ComponentRef<typeof Pressable>, ChipProps>(({
72
95
  return null;
73
96
  };
74
97
 
75
- const isClickable = (onPress && !disabled) || (selectable && !disabled);
98
+ const isClickable = ((onPress || onClick) && !disabled) || (selectable && !disabled);
76
99
 
77
100
  const innerContent = (
78
101
  <>
@@ -102,7 +125,7 @@ const Chip = forwardRef<ComponentRef<typeof Pressable>, ChipProps>(({
102
125
  if (isClickable) {
103
126
  return (
104
127
  <Pressable
105
- ref={ref}
128
+ ref={ref as any}
106
129
  nativeID={id}
107
130
  onPress={handlePress}
108
131
  disabled={disabled}
@@ -122,7 +145,7 @@ const Chip = forwardRef<ComponentRef<typeof Pressable>, ChipProps>(({
122
145
  }
123
146
 
124
147
  return (
125
- <View ref={ref} nativeID={id} style={[containerStyle, style]} testID={testID}>
148
+ <View ref={ref as any} nativeID={id} style={[containerStyle, style]} testID={testID}>
126
149
  {innerContent}
127
150
  </View>
128
151
  );
@@ -1,16 +1,20 @@
1
- import React, { isValidElement, forwardRef } from 'react';
1
+ import React, { isValidElement, forwardRef, useEffect, useRef } from 'react';
2
2
  import { getWebProps } from 'react-native-unistyles/web';
3
3
  import { chipStyles } from './Chip.styles';
4
4
  import type { ChipProps } from './types';
5
5
  import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
6
6
  import { isIconName } from '../Icon/icon-resolver';
7
7
  import useMergeRefs from '../hooks/useMergeRefs';
8
+ import type { IdealystElement } from '../utils/refTypes';
9
+
10
+ // Track if we've logged the onClick deprecation warning (log once per session)
11
+ let hasLoggedOnClickWarning = false;
8
12
 
9
13
  /**
10
14
  * Compact interactive element for tags, filters, or selections.
11
15
  * Supports icons, selection state, and delete functionality.
12
16
  */
13
- const Chip = forwardRef<HTMLDivElement, ChipProps>(({
17
+ const Chip = forwardRef<IdealystElement, ChipProps>(({
14
18
  label,
15
19
  type = 'filled',
16
20
  intent = 'primary',
@@ -22,6 +26,7 @@ const Chip = forwardRef<HTMLDivElement, ChipProps>(({
22
26
  selectable = false,
23
27
  selected = false,
24
28
  onPress,
29
+ onClick,
25
30
  disabled = false,
26
31
  style,
27
32
  testID,
@@ -30,6 +35,22 @@ const Chip = forwardRef<HTMLDivElement, ChipProps>(({
30
35
  accessibilityLabel,
31
36
  accessibilityChecked,
32
37
  }, ref) => {
38
+ const hasWarnedRef = useRef(false);
39
+
40
+ // Warn about onClick usage (deprecated)
41
+ useEffect(() => {
42
+ if (onClick && !hasWarnedRef.current && !hasLoggedOnClickWarning) {
43
+ hasWarnedRef.current = true;
44
+ hasLoggedOnClickWarning = true;
45
+ console.warn(
46
+ '[Chip] onClick is deprecated. Use onPress instead.\n' +
47
+ 'Chip is a cross-platform component that follows React Native conventions.\n' +
48
+ 'onClick will be removed in a future version.\n\n' +
49
+ 'Migration: Replace onClick={handler} with onPress={handler}'
50
+ );
51
+ }
52
+ }, [onClick]);
53
+
33
54
  // Compute actual selected state
34
55
  const isSelected = selectable ? selected : false;
35
56
 
@@ -42,8 +63,10 @@ const Chip = forwardRef<HTMLDivElement, ChipProps>(({
42
63
 
43
64
  const handleClick = () => {
44
65
  if (disabled) return;
45
- if (onPress) {
46
- onPress();
66
+ // Prefer onPress, fall back to deprecated onClick
67
+ const handler = onPress ?? onClick;
68
+ if (handler) {
69
+ handler();
47
70
  }
48
71
  };
49
72
 
@@ -91,7 +114,7 @@ const Chip = forwardRef<HTMLDivElement, ChipProps>(({
91
114
  return null;
92
115
  };
93
116
 
94
- const isClickable = (onPress && !disabled) || (selectable && !disabled);
117
+ const isClickable = ((onPress || onClick) && !disabled) || (selectable && !disabled);
95
118
 
96
119
  const mergedRef = useMergeRefs(ref, containerProps.ref);
97
120
 
package/src/Chip/types.ts CHANGED
@@ -46,6 +46,21 @@ export interface ChipProps extends BaseProps, SelectionAccessibilityProps {
46
46
  /** Callback when chip is pressed */
47
47
  onPress?: () => void;
48
48
 
49
+ /**
50
+ * @deprecated Use `onPress` instead. This is a cross-platform component - use React Native conventions.
51
+ *
52
+ * Using `onClick` will trigger a console warning in development.
53
+ * This prop exists only for migration convenience and will be removed in a future version.
54
+ *
55
+ * @example
56
+ * // ❌ Don't use onClick
57
+ * <Chip label="Tag" onClick={() => {}} />
58
+ *
59
+ * // ✅ Use onPress instead
60
+ * <Chip label="Tag" onPress={() => {}} />
61
+ */
62
+ onClick?: () => void;
63
+
49
64
  /** Whether the chip is disabled */
50
65
  disabled?: boolean;
51
66
 
@@ -7,7 +7,7 @@ import { getNativeInteractiveAccessibilityProps } from '../utils/accessibility';
7
7
 
8
8
  const Dialog = forwardRef<View, DialogProps>(({
9
9
  open,
10
- onOpenChange,
10
+ onClose,
11
11
  title,
12
12
  children,
13
13
  size = 'md',
@@ -76,22 +76,22 @@ const Dialog = forwardRef<View, DialogProps>(({
76
76
  if (!open) return;
77
77
 
78
78
  const handleBackPress = () => {
79
- onOpenChange(false);
79
+ onClose();
80
80
  return true; // Prevent default back behavior
81
81
  };
82
82
 
83
83
  const backHandler = BackHandler.addEventListener('hardwareBackPress', handleBackPress);
84
84
  return () => backHandler.remove();
85
- }, [open, onOpenChange]);
85
+ }, [open, onClose]);
86
86
 
87
87
  const handleBackdropPress = () => {
88
88
  if (closeOnBackdropClick) {
89
- onOpenChange(false);
89
+ onClose();
90
90
  }
91
91
  };
92
92
 
93
93
  const handleClosePress = () => {
94
- onOpenChange(false);
94
+ onClose();
95
95
  };
96
96
 
97
97
  // Apply variants
@@ -129,7 +129,7 @@ const Dialog = forwardRef<View, DialogProps>(({
129
129
  visible={open}
130
130
  transparent
131
131
  animationType="none"
132
- onRequestClose={() => onOpenChange(false)}
132
+ onRequestClose={() => onClose()}
133
133
  statusBarTranslucent
134
134
  testID={testID}
135
135
  >
@@ -13,7 +13,7 @@ import { getWebInteractiveAriaProps, generateAccessibilityId } from '../utils/ac
13
13
  */
14
14
  const Dialog = forwardRef<HTMLDivElement, DialogProps>(({
15
15
  open,
16
- onOpenChange,
16
+ onClose,
17
17
  title,
18
18
  children,
19
19
  size = 'md',
@@ -81,13 +81,13 @@ const Dialog = forwardRef<HTMLDivElement, DialogProps>(({
81
81
 
82
82
  const handleEscape = (event: KeyboardEvent) => {
83
83
  if (event.key === 'Escape') {
84
- onOpenChange(false);
84
+ onClose();
85
85
  }
86
86
  };
87
87
 
88
88
  document.addEventListener('keydown', handleEscape);
89
89
  return () => document.removeEventListener('keydown', handleEscape);
90
- }, [open, closeOnEscapeKey, onOpenChange]);
90
+ }, [open, closeOnEscapeKey, onClose]);
91
91
 
92
92
  // Handle focus management
93
93
  useEffect(() => {
@@ -122,12 +122,12 @@ const Dialog = forwardRef<HTMLDivElement, DialogProps>(({
122
122
 
123
123
  const handleBackdropClick = (event: React.MouseEvent) => {
124
124
  if (closeOnBackdropClick && event.target === event.currentTarget) {
125
- onOpenChange(false);
125
+ onClose();
126
126
  }
127
127
  };
128
128
 
129
129
  const handleCloseClick = () => {
130
- onOpenChange(false);
130
+ onClose();
131
131
  };
132
132
 
133
133
  // Apply variants
@@ -19,9 +19,9 @@ export interface DialogProps extends BaseProps, InteractiveAccessibilityProps {
19
19
  open: boolean;
20
20
 
21
21
  /**
22
- * Called when the dialog should be opened or closed
22
+ * Called when the dialog should be closed
23
23
  */
24
- onOpenChange: (open: boolean) => void;
24
+ onClose: () => void;
25
25
 
26
26
  /**
27
27
  * Optional title for the dialog