@idealyst/components 1.2.32 → 1.2.33

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.2.32",
3
+ "version": "1.2.33",
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.32",
59
+ "@idealyst/theme": "^1.2.33",
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.32",
109
+ "@idealyst/theme": "^1.2.33",
110
110
  "@idealyst/tooling": "^1.2.30",
111
111
  "@mdi/react": "^1.6.1",
112
112
  "@types/react": "^19.1.0",
@@ -61,7 +61,11 @@ const AccordionItem: React.FC<AccordionItemProps> = ({
61
61
  <button
62
62
  {...headerProps}
63
63
  id={headerId}
64
- onClick={onToggle}
64
+ onClick={(e: React.MouseEvent) => {
65
+ e.preventDefault();
66
+ e.stopPropagation();
67
+ onToggle();
68
+ }}
65
69
  onKeyDown={(e) => onKeyDown(e, item.id)}
66
70
  disabled={item.disabled}
67
71
  aria-expanded={isExpanded}
@@ -146,16 +150,20 @@ const Accordion: React.FC<AccordionProps> = ({
146
150
  // ArrowDown moves to next item
147
151
  if (key === 'ArrowDown') {
148
152
  e.preventDefault();
153
+ e.stopPropagation();
149
154
  nextIndex = currentIndex < enabledItems.length - 1 ? currentIndex + 1 : 0;
150
155
  // ArrowUp moves to previous item
151
156
  } else if (key === 'ArrowUp') {
152
157
  e.preventDefault();
158
+ e.stopPropagation();
153
159
  nextIndex = currentIndex > 0 ? currentIndex - 1 : enabledItems.length - 1;
154
160
  } else if (ACCORDION_KEYS.first.includes(key as 'Home')) {
155
161
  e.preventDefault();
162
+ e.stopPropagation();
156
163
  nextIndex = 0;
157
164
  } else if (ACCORDION_KEYS.last.includes(key as 'End')) {
158
165
  e.preventDefault();
166
+ e.stopPropagation();
159
167
  nextIndex = enabledItems.length - 1;
160
168
  }
161
169
 
@@ -64,10 +64,8 @@ const Button = forwardRef<IdealystElement, ButtonProps>((props, ref) => {
64
64
 
65
65
  const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
66
66
  e.preventDefault();
67
- // Only stop propagation if we have a handler
68
- // Otherwise, let clicks bubble up to parent handlers (e.g., Menu triggers)
67
+ e.stopPropagation();
69
68
  if (!isDisabled && pressHandler) {
70
- e.stopPropagation();
71
69
  pressHandler();
72
70
  }
73
71
  };
@@ -72,7 +72,9 @@ const Card = forwardRef<IdealystElement, CardProps>(({
72
72
  });
73
73
  }, [accessibilityLabel, accessibilityHint, accessibilityDisabled, disabled, accessibilityHidden, accessibilityRole, clickable, accessibilityPressed]);
74
74
 
75
- const handleClick = () => {
75
+ const handleClick = (e: React.MouseEvent) => {
76
+ e.preventDefault();
77
+ e.stopPropagation();
76
78
  if (!disabled && clickable) {
77
79
  // Prefer onPress, fall back to deprecated onClick
78
80
  const handler = onPress ?? onClick;
@@ -53,6 +53,8 @@ const Checkbox = forwardRef<IdealystElement, CheckboxProps>(({
53
53
  }, [checked]);
54
54
 
55
55
  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
56
+ event.preventDefault();
57
+ event.stopPropagation();
56
58
  if (disabled) return;
57
59
 
58
60
  const newChecked = event.target.checked;
@@ -61,7 +61,9 @@ const Chip = forwardRef<IdealystElement, ChipProps>(({
61
61
  const deleteButtonProps = getWebProps([(chipStyles.deleteButton as any)({ size })]);
62
62
  const deleteIconProps = getWebProps([(chipStyles.deleteIcon as any)({ size, intent, type, selected: isSelected })]);
63
63
 
64
- const handleClick = () => {
64
+ const handleClick = (e: React.MouseEvent) => {
65
+ e.preventDefault();
66
+ e.stopPropagation();
65
67
  if (disabled) return;
66
68
  // Prefer onPress, fall back to deprecated onClick
67
69
  const handler = onPress ?? onClick;
@@ -71,6 +73,7 @@ const Chip = forwardRef<IdealystElement, ChipProps>(({
71
73
  };
72
74
 
73
75
  const handleDelete = (e: React.MouseEvent) => {
76
+ e.preventDefault();
74
77
  e.stopPropagation();
75
78
  if (disabled) return;
76
79
  if (onDelete) {
@@ -62,8 +62,8 @@ const IconButton = forwardRef<IdealystElement, IconButtonProps>((props, ref) =>
62
62
 
63
63
  const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
64
64
  e.preventDefault();
65
+ e.stopPropagation();
65
66
  if (!isDisabled && pressHandler) {
66
- e.stopPropagation();
67
67
  pressHandler();
68
68
  }
69
69
  };
@@ -53,7 +53,9 @@ const ListItem: React.FC<ListItemProps & { isLast?: boolean }> = ({
53
53
  const leadingProps = getWebProps([leadingStyle]);
54
54
  const trailingProps = getWebProps([trailingStyle]);
55
55
 
56
- const handleClick = () => {
56
+ const handleClick = (e: React.MouseEvent) => {
57
+ e.preventDefault();
58
+ e.stopPropagation();
57
59
  if (!disabled && onPress) {
58
60
  onPress();
59
61
  }
@@ -69,7 +69,11 @@ const MenuItem = forwardRef<IdealystElement, MenuItemProps>(({ item, onPress, si
69
69
  {...itemProps}
70
70
  ref={mergedRef}
71
71
  style={buttonResetStyles}
72
- onClick={() => onPress(item)}
72
+ onClick={(e: React.MouseEvent) => {
73
+ e.preventDefault();
74
+ e.stopPropagation();
75
+ onPress(item);
76
+ }}
73
77
  disabled={item.disabled}
74
78
  role="menuitem"
75
79
  aria-disabled={item.disabled}
@@ -23,19 +23,25 @@ const Pressable = forwardRef<IdealystElement, PressableProps>(({
23
23
  }, ref) => {
24
24
  const [_isPressed, setIsPressed] = useState(false);
25
25
 
26
- const handleMouseDown = useCallback(() => {
26
+ const handleMouseDown = useCallback((e: React.MouseEvent) => {
27
+ e.preventDefault();
28
+ e.stopPropagation();
27
29
  if (disabled) return;
28
30
  setIsPressed(true);
29
31
  onPressIn?.();
30
32
  }, [disabled, onPressIn]);
31
33
 
32
- const handleMouseUp = useCallback(() => {
34
+ const handleMouseUp = useCallback((e: React.MouseEvent) => {
35
+ e.preventDefault();
36
+ e.stopPropagation();
33
37
  if (disabled) return;
34
38
  setIsPressed(false);
35
39
  onPressOut?.();
36
40
  }, [disabled, onPressOut]);
37
41
 
38
- const handleClick = useCallback(() => {
42
+ const handleClick = useCallback((e: React.MouseEvent) => {
43
+ e.preventDefault();
44
+ e.stopPropagation();
39
45
  if (disabled) return;
40
46
  onPress?.();
41
47
  }, [disabled, onPress]);
@@ -44,6 +50,7 @@ const Pressable = forwardRef<IdealystElement, PressableProps>(({
44
50
  if (disabled) return;
45
51
  if (event.key === 'Enter' || event.key === ' ') {
46
52
  event.preventDefault();
53
+ event.stopPropagation();
47
54
  onPress?.();
48
55
  }
49
56
  }, [disabled, onPress]);
@@ -39,7 +39,9 @@ const RadioButton: React.FC<RadioButtonProps> = ({
39
39
  const checked = group.value !== undefined ? group.value === value : checkedProp;
40
40
  const disabled = group.disabled || disabledProp;
41
41
 
42
- const handleClick = () => {
42
+ const handleClick = (e: React.MouseEvent) => {
43
+ e.preventDefault();
44
+ e.stopPropagation();
43
45
  if (!disabled) {
44
46
  if (group.onValueChange) {
45
47
  group.onValueChange(value);
@@ -56,39 +56,43 @@ export const selectStyles = defineStyle('Select', (theme: Theme) => ({
56
56
  marginBottom: 4,
57
57
  }),
58
58
 
59
- trigger: ({ type: _type = 'outlined', intent: _intent = 'neutral', disabled = false, error: _error = false, focused: _focused = false }: SelectDynamicProps) => ({
60
- position: 'relative' as const,
61
- flexDirection: 'row' as const,
62
- alignItems: 'center' as const,
63
- justifyContent: 'space-between' as const,
64
- borderWidth: 1,
65
- borderStyle: 'solid' as const,
66
- opacity: disabled ? 0.6 : 1,
67
- variants: {
68
- type: {
69
- filled: {
70
- backgroundColor: theme.colors.surface.secondary,
71
- borderColor: 'transparent',
72
- },
73
- outlined: {
74
- backgroundColor: theme.colors.surface.primary,
75
- borderWidth: 1,
76
- borderColor: theme.colors.border.primary,
77
- }
59
+ trigger: ({ type = 'outlined', intent = 'neutral', disabled = false, error = false, focused = false }: SelectDynamicProps) => {
60
+ // Determine border color based on state priority: error > focused > default
61
+ const getBorderColor = () => {
62
+ if (error) return theme.intents.danger.primary;
63
+ if (focused) return theme.intents[intent]?.primary ?? theme.intents.primary.primary;
64
+ return type === 'filled' ? 'transparent' : theme.colors.border.primary;
65
+ };
66
+
67
+ const borderColor = getBorderColor();
68
+
69
+ return {
70
+ position: 'relative' as const,
71
+ flexDirection: 'row' as const,
72
+ alignItems: 'center' as const,
73
+ justifyContent: 'space-between' as const,
74
+ borderWidth: 1,
75
+ borderStyle: 'solid' as const,
76
+ borderColor,
77
+ borderRadius: 8,
78
+ opacity: disabled ? 0.6 : 1,
79
+ backgroundColor: type === 'filled' ? theme.colors.surface.secondary : theme.colors.surface.primary,
80
+ variants: {
81
+ size: theme.sizes.$select,
78
82
  },
79
- size: theme.sizes.$select,
80
- },
81
- _web: {
82
- display: 'flex',
83
- boxSizing: 'border-box',
84
- cursor: disabled ? 'not-allowed' : 'pointer',
85
- border: `1px solid`,
86
- transition: 'border-color 0.2s ease, box-shadow 0.2s ease',
87
- _hover: disabled ? {} : { opacity: 0.9 },
88
- _active: disabled ? {} : { opacity: 0.8 },
89
- _focus: { outline: 'none' },
90
- },
91
- }),
83
+ _web: {
84
+ display: 'flex',
85
+ boxSizing: 'border-box',
86
+ cursor: disabled ? 'not-allowed' : 'pointer',
87
+ border: `1px solid ${borderColor}`,
88
+ boxShadow: focused && !error ? `0 0 0 2px ${theme.intents[intent]?.primary ?? theme.intents.primary.primary}33` : 'none',
89
+ transition: 'border-color 0.2s ease, box-shadow 0.2s ease',
90
+ _hover: disabled ? {} : { borderColor: focused || error ? borderColor : theme.colors.border.secondary },
91
+ _active: disabled ? {} : { opacity: 0.9 },
92
+ _focus: { outline: 'none' },
93
+ },
94
+ };
95
+ },
92
96
 
93
97
  triggerContent: (_props: SelectDynamicProps) => ({
94
98
  flex: 1,
@@ -101,6 +101,7 @@ const Slider = forwardRef<IdealystElement, SliderProps>(({
101
101
  if (disabled) return;
102
102
 
103
103
  e.preventDefault();
104
+ e.stopPropagation();
104
105
 
105
106
  // Check if click is on the thumb
106
107
  const isThumbClick = thumbRef.current && thumbRef.current.contains(e.target as Node);
@@ -145,21 +146,27 @@ const Slider = forwardRef<IdealystElement, SliderProps>(({
145
146
 
146
147
  if (matchesKey(e, SLIDER_KEYS.increase)) {
147
148
  e.preventDefault();
149
+ e.stopPropagation();
148
150
  newValue = clampValue(value + step);
149
151
  } else if (matchesKey(e, SLIDER_KEYS.decrease)) {
150
152
  e.preventDefault();
153
+ e.stopPropagation();
151
154
  newValue = clampValue(value - step);
152
155
  } else if (matchesKey(e, SLIDER_KEYS.min)) {
153
156
  e.preventDefault();
157
+ e.stopPropagation();
154
158
  newValue = min;
155
159
  } else if (matchesKey(e, SLIDER_KEYS.max)) {
156
160
  e.preventDefault();
161
+ e.stopPropagation();
157
162
  newValue = max;
158
163
  } else if (matchesKey(e, SLIDER_KEYS.increaseLarge)) {
159
164
  e.preventDefault();
165
+ e.stopPropagation();
160
166
  newValue = clampValue(value + largeStep);
161
167
  } else if (matchesKey(e, SLIDER_KEYS.decreaseLarge)) {
162
168
  e.preventDefault();
169
+ e.stopPropagation();
163
170
  newValue = clampValue(value - largeStep);
164
171
  }
165
172
 
@@ -39,7 +39,9 @@ const Switch = forwardRef<IdealystElement, SwitchProps>(({
39
39
  accessibilityDescribedBy,
40
40
  accessibilityChecked,
41
41
  }, ref) => {
42
- const handleClick = () => {
42
+ const handleClick = (e: React.MouseEvent) => {
43
+ e.preventDefault();
44
+ e.stopPropagation();
43
45
  if (!disabled && onChange) {
44
46
  onChange(!checked);
45
47
  }
@@ -36,7 +36,7 @@ function renderIcon(
36
36
  interface TabProps {
37
37
  item: TabBarItem;
38
38
  isActive: boolean;
39
- onClick: () => void;
39
+ onClick: (e: React.MouseEvent) => void;
40
40
  onKeyDown: (e: React.KeyboardEvent) => void;
41
41
  size: TabBarProps['size'];
42
42
  type: TabBarProps['type'];
@@ -168,15 +168,19 @@ const TabBar: React.FC<TabBarProps> = ({
168
168
 
169
169
  if (key === 'ArrowRight') {
170
170
  e.preventDefault();
171
+ e.stopPropagation();
171
172
  nextIndex = currentIndex < enabledItems.length - 1 ? currentIndex + 1 : 0;
172
173
  } else if (key === 'ArrowLeft') {
173
174
  e.preventDefault();
175
+ e.stopPropagation();
174
176
  nextIndex = currentIndex > 0 ? currentIndex - 1 : enabledItems.length - 1;
175
177
  } else if (key === 'Home') {
176
178
  e.preventDefault();
179
+ e.stopPropagation();
177
180
  nextIndex = 0;
178
181
  } else if (key === 'End') {
179
182
  e.preventDefault();
183
+ e.stopPropagation();
180
184
  nextIndex = enabledItems.length - 1;
181
185
  }
182
186
 
@@ -237,7 +241,9 @@ const TabBar: React.FC<TabBarProps> = ({
237
241
  updateIndicator();
238
242
  }, [items]);
239
243
 
240
- const handleTabClick = (itemValue: string, disabled?: boolean) => {
244
+ const handleTabClick = (e: React.MouseEvent, itemValue: string, disabled?: boolean) => {
245
+ e.preventDefault();
246
+ e.stopPropagation();
241
247
  if (disabled) return;
242
248
 
243
249
  if (controlledValue === undefined) {
@@ -306,7 +312,7 @@ const TabBar: React.FC<TabBarProps> = ({
306
312
  key={item.value}
307
313
  item={item}
308
314
  isActive={isActive}
309
- onClick={() => handleTabClick(item.value, item.disabled)}
315
+ onClick={(e) => handleTabClick(e, item.value, item.disabled)}
310
316
  onKeyDown={(e) => handleKeyDown(e, item.value)}
311
317
  size={size}
312
318
  type={type}
@@ -168,6 +168,7 @@ const TextArea = forwardRef<IdealystElement, TextAreaProps>(({
168
168
  }, [value, autoGrow, minHeight, maxHeight]);
169
169
 
170
170
  const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
171
+ e.stopPropagation();
171
172
  const newValue = e.target.value;
172
173
 
173
174
  if (maxLength && newValue.length > maxLength) {
@@ -88,6 +88,7 @@ const TextInput = React.forwardRef<IdealystElement, TextInputProps>(({
88
88
  };
89
89
 
90
90
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
91
+ e.stopPropagation();
91
92
  if (onChangeText) {
92
93
  onChangeText(e.target.value);
93
94
  }