@idealyst/components 1.2.133 → 1.2.134
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 +4 -4
- package/src/Button/Button.native.tsx +7 -3
- package/src/IconButton/IconButton.native.tsx +8 -3
- package/src/IconButton/IconButton.web.tsx +2 -1
- package/src/IconButton/types.ts +3 -2
- package/src/Pressable/Pressable.native.tsx +10 -6
- package/src/Pressable/Pressable.web.tsx +5 -3
- package/src/utils/events/events.native.ts +7 -2
- package/src/utils/events/events.web.ts +1 -0
- package/src/utils/events/types.ts +21 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idealyst/components",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.134",
|
|
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.
|
|
59
|
+
"@idealyst/theme": "^1.2.134",
|
|
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.2.
|
|
115
|
-
"@idealyst/tooling": "^1.2.
|
|
114
|
+
"@idealyst/theme": "^1.2.134",
|
|
115
|
+
"@idealyst/tooling": "^1.2.134",
|
|
116
116
|
"@mdi/react": "^1.6.1",
|
|
117
117
|
"@types/react": "^19.1.0",
|
|
118
118
|
"react": "^19.1.0",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { forwardRef, useMemo } from 'react';
|
|
1
|
+
import { forwardRef, useRef, useMemo } from 'react';
|
|
2
2
|
import { ActivityIndicator, StyleSheet as RNStyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
|
3
3
|
import MaterialDesignIcons from '@react-native-vector-icons/material-design-icons';
|
|
4
4
|
import Svg, { Defs, LinearGradient, Stop, Rect } from 'react-native-svg';
|
|
@@ -6,6 +6,7 @@ import { buttonStyles } from './Button.styles';
|
|
|
6
6
|
import { ButtonProps } from './types';
|
|
7
7
|
import { createPressEvent } from '../utils/events';
|
|
8
8
|
import { getNativeInteractiveAccessibilityProps } from '../utils/accessibility';
|
|
9
|
+
import useMergeRefs from '../hooks/useMergeRefs';
|
|
9
10
|
import type { IdealystElement } from '../utils/refTypes';
|
|
10
11
|
|
|
11
12
|
const Button = forwardRef<IdealystElement, ButtonProps>((props, ref) => {
|
|
@@ -37,6 +38,9 @@ const Button = forwardRef<IdealystElement, ButtonProps>((props, ref) => {
|
|
|
37
38
|
accessibilityPressed,
|
|
38
39
|
} = props;
|
|
39
40
|
|
|
41
|
+
const internalRef = useRef<IdealystElement>(null);
|
|
42
|
+
const mergedRef = useMergeRefs(ref, internalRef);
|
|
43
|
+
|
|
40
44
|
// Button is effectively disabled when loading
|
|
41
45
|
const isDisabled = disabled || loading;
|
|
42
46
|
|
|
@@ -169,8 +173,8 @@ const Button = forwardRef<IdealystElement, ButtonProps>((props, ref) => {
|
|
|
169
173
|
|
|
170
174
|
// TouchableOpacity types don't include nativeID but it's a valid RN prop
|
|
171
175
|
const touchableProps = {
|
|
172
|
-
ref,
|
|
173
|
-
onPress: pressHandler ? (e: any) => pressHandler(createPressEvent(e)) : undefined,
|
|
176
|
+
ref: mergedRef,
|
|
177
|
+
onPress: pressHandler ? (e: any) => pressHandler(createPressEvent(e, 'press', internalRef)) : undefined,
|
|
174
178
|
disabled: isDisabled,
|
|
175
179
|
testID,
|
|
176
180
|
nativeID: id,
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { forwardRef, useMemo } from 'react';
|
|
1
|
+
import { forwardRef, useRef, useMemo } from 'react';
|
|
2
2
|
import { ActivityIndicator, StyleSheet as RNStyleSheet, TouchableOpacity, View } from 'react-native';
|
|
3
3
|
import MaterialDesignIcons from '@react-native-vector-icons/material-design-icons';
|
|
4
4
|
import Svg, { Defs, LinearGradient, Stop, Rect } from 'react-native-svg';
|
|
5
5
|
import { useUnistyles } from 'react-native-unistyles';
|
|
6
6
|
import { iconButtonStyles } from './IconButton.styles';
|
|
7
7
|
import { IconButtonProps } from './types';
|
|
8
|
+
import { createPressEvent } from '../utils/events';
|
|
8
9
|
import { getNativeInteractiveAccessibilityProps } from '../utils/accessibility';
|
|
10
|
+
import useMergeRefs from '../hooks/useMergeRefs';
|
|
9
11
|
import type { IdealystElement } from '../utils/refTypes';
|
|
10
12
|
import type { Theme } from '@idealyst/theme';
|
|
11
13
|
|
|
@@ -36,6 +38,9 @@ const IconButton = forwardRef<IdealystElement, IconButtonProps>((props, ref) =>
|
|
|
36
38
|
accessibilityPressed,
|
|
37
39
|
} = props;
|
|
38
40
|
|
|
41
|
+
const internalRef = useRef<IdealystElement>(null);
|
|
42
|
+
const mergedRef = useMergeRefs(ref, internalRef);
|
|
43
|
+
|
|
39
44
|
// Get theme for icon size
|
|
40
45
|
const { theme } = useUnistyles() as { theme: Theme };
|
|
41
46
|
|
|
@@ -153,8 +158,8 @@ const IconButton = forwardRef<IdealystElement, IconButtonProps>((props, ref) =>
|
|
|
153
158
|
|
|
154
159
|
// TouchableOpacity types don't include nativeID but it's a valid RN prop
|
|
155
160
|
const touchableProps = {
|
|
156
|
-
ref,
|
|
157
|
-
onPress: pressHandler,
|
|
161
|
+
ref: mergedRef,
|
|
162
|
+
onPress: pressHandler ? (e: any) => pressHandler(createPressEvent(e, 'press', internalRef)) : undefined,
|
|
158
163
|
disabled: isDisabled,
|
|
159
164
|
testID,
|
|
160
165
|
nativeID: id,
|
|
@@ -4,6 +4,7 @@ import { useUnistyles } from 'react-native-unistyles';
|
|
|
4
4
|
import { IconButtonProps } from './types';
|
|
5
5
|
import { iconButtonStyles } from './IconButton.styles';
|
|
6
6
|
import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
|
|
7
|
+
import { createPressEvent } from '../utils/events';
|
|
7
8
|
import useMergeRefs from '../hooks/useMergeRefs';
|
|
8
9
|
import { getWebInteractiveAriaProps, generateAccessibilityId } from '../utils/accessibility';
|
|
9
10
|
import type { IdealystElement } from '../utils/refTypes';
|
|
@@ -72,7 +73,7 @@ const IconButton = forwardRef<IdealystElement, IconButtonProps>((props, ref) =>
|
|
|
72
73
|
e.preventDefault();
|
|
73
74
|
e.stopPropagation();
|
|
74
75
|
if (!isDisabled && pressHandler) {
|
|
75
|
-
pressHandler();
|
|
76
|
+
pressHandler(createPressEvent(e));
|
|
76
77
|
}
|
|
77
78
|
};
|
|
78
79
|
|
package/src/IconButton/types.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { IconName } from '../Icon/icon-types';
|
|
|
4
4
|
import { Intent, Size } from '@idealyst/theme';
|
|
5
5
|
import { BaseProps } from '../utils/viewStyleProps';
|
|
6
6
|
import { InteractiveAccessibilityProps } from '../utils/accessibility';
|
|
7
|
+
import type { PressEvent } from '../utils/events';
|
|
7
8
|
|
|
8
9
|
// Component-specific type aliases for future extensibility
|
|
9
10
|
export type IconButtonType = 'contained' | 'outlined' | 'text';
|
|
@@ -31,13 +32,13 @@ export interface IconButtonProps extends BaseProps, InteractiveAccessibilityProp
|
|
|
31
32
|
/**
|
|
32
33
|
* Called when the button is pressed
|
|
33
34
|
*/
|
|
34
|
-
onPress?: () => void;
|
|
35
|
+
onPress?: (event: PressEvent) => void;
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
38
|
* @deprecated Use `onPress` instead. This prop exists for web compatibility only.
|
|
38
39
|
* Using onClick will log a deprecation warning in development.
|
|
39
40
|
*/
|
|
40
|
-
onClick?: () => void;
|
|
41
|
+
onClick?: (event: PressEvent) => void;
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
44
|
* Whether the button is disabled
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { forwardRef } from 'react';
|
|
1
|
+
import { forwardRef, useRef } from 'react';
|
|
2
2
|
import { TouchableWithoutFeedback, View } from 'react-native';
|
|
3
3
|
import { PressableProps } from './types';
|
|
4
4
|
import { pressableStyles } from './Pressable.styles';
|
|
5
5
|
import { createPressEvent } from '../utils/events';
|
|
6
|
+
import useMergeRefs from '../hooks/useMergeRefs';
|
|
6
7
|
import type { IdealystElement } from '../utils/refTypes';
|
|
7
8
|
|
|
8
9
|
const Pressable = forwardRef<IdealystElement, PressableProps>(({
|
|
@@ -21,6 +22,9 @@ const Pressable = forwardRef<IdealystElement, PressableProps>(({
|
|
|
21
22
|
accessibilityRole: _accessibilityRole,
|
|
22
23
|
id,
|
|
23
24
|
}, ref) => {
|
|
25
|
+
const internalRef = useRef<IdealystElement>(null);
|
|
26
|
+
const mergedRef = useMergeRefs(ref, internalRef);
|
|
27
|
+
|
|
24
28
|
// Apply spacing variants
|
|
25
29
|
pressableStyles.useVariants({
|
|
26
30
|
padding,
|
|
@@ -32,14 +36,14 @@ const Pressable = forwardRef<IdealystElement, PressableProps>(({
|
|
|
32
36
|
|
|
33
37
|
return (
|
|
34
38
|
<TouchableWithoutFeedback
|
|
35
|
-
onPress={disabled ? undefined : (e) => onPress?.(createPressEvent(e))}
|
|
36
|
-
onPressIn={disabled ? undefined : (e) => onPressIn?.(createPressEvent(e, 'pressIn'))}
|
|
37
|
-
onPressOut={disabled ? undefined : (e) => onPressOut?.(createPressEvent(e, 'pressOut'))}
|
|
39
|
+
onPress={disabled ? undefined : (e) => onPress?.(createPressEvent(e, 'press', internalRef))}
|
|
40
|
+
onPressIn={disabled ? undefined : (e) => onPressIn?.(createPressEvent(e, 'pressIn', internalRef))}
|
|
41
|
+
onPressOut={disabled ? undefined : (e) => onPressOut?.(createPressEvent(e, 'pressOut', internalRef))}
|
|
38
42
|
disabled={disabled}
|
|
39
43
|
testID={testID}
|
|
40
44
|
accessibilityLabel={accessibilityLabel}
|
|
41
45
|
>
|
|
42
|
-
<View ref={
|
|
46
|
+
<View ref={mergedRef as any} nativeID={id} style={[pressableStyle, style]}>
|
|
43
47
|
{children}
|
|
44
48
|
</View>
|
|
45
49
|
</TouchableWithoutFeedback>
|
|
@@ -48,4 +52,4 @@ const Pressable = forwardRef<IdealystElement, PressableProps>(({
|
|
|
48
52
|
|
|
49
53
|
Pressable.displayName = 'Pressable';
|
|
50
54
|
|
|
51
|
-
export default Pressable;
|
|
55
|
+
export default Pressable;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useState, forwardRef } from 'react';
|
|
1
|
+
import React, { useCallback, useRef, useState, forwardRef } from 'react';
|
|
2
2
|
import { getWebProps } from 'react-native-unistyles/web';
|
|
3
3
|
import { PressableProps } from './types';
|
|
4
4
|
import { pressableStyles } from './Pressable.styles';
|
|
@@ -24,6 +24,7 @@ const Pressable = forwardRef<IdealystElement, PressableProps>(({
|
|
|
24
24
|
accessibilityRole = 'button',
|
|
25
25
|
id,
|
|
26
26
|
}, ref) => {
|
|
27
|
+
const internalRef = useRef<IdealystElement>(null);
|
|
27
28
|
const [_isPressed, setIsPressed] = useState(false);
|
|
28
29
|
|
|
29
30
|
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
|
@@ -57,6 +58,7 @@ const Pressable = forwardRef<IdealystElement, PressableProps>(({
|
|
|
57
58
|
const pressEvent: PressEvent = {
|
|
58
59
|
...createBaseSyntheticEvent(event.nativeEvent),
|
|
59
60
|
type: 'press',
|
|
61
|
+
targetRef: internalRef,
|
|
60
62
|
};
|
|
61
63
|
onPress?.(pressEvent);
|
|
62
64
|
}
|
|
@@ -71,8 +73,8 @@ const Pressable = forwardRef<IdealystElement, PressableProps>(({
|
|
|
71
73
|
|
|
72
74
|
const webProps = getWebProps([(pressableStyles.pressable as any)({ disabled }), flattenStyle(style)]);
|
|
73
75
|
|
|
74
|
-
// Merge ref from getWebProps with forwarded ref
|
|
75
|
-
const mergedRef = useMergeRefs(ref as any, webProps.ref as any);
|
|
76
|
+
// Merge ref from getWebProps with forwarded ref and internal ref
|
|
77
|
+
const mergedRef = useMergeRefs(ref as any, webProps.ref as any, internalRef);
|
|
76
78
|
|
|
77
79
|
return (
|
|
78
80
|
<div
|
|
@@ -24,16 +24,20 @@ import type {
|
|
|
24
24
|
ScrollEvent,
|
|
25
25
|
SubmitEvent,
|
|
26
26
|
} from './types';
|
|
27
|
+
import type { RefObject } from 'react';
|
|
28
|
+
import type { IdealystElement } from '../refTypes';
|
|
27
29
|
|
|
28
30
|
// No-op functions for native (these concepts don't apply)
|
|
29
31
|
const noop = () => {};
|
|
30
32
|
|
|
31
33
|
/**
|
|
32
|
-
* Wraps a React Native GestureResponderEvent into a standardized PressEvent
|
|
34
|
+
* Wraps a React Native GestureResponderEvent into a standardized PressEvent.
|
|
35
|
+
* Pass the component's ref object as `targetRef` so consumers can use it for anchoring.
|
|
33
36
|
*/
|
|
34
37
|
export function createPressEvent(
|
|
35
38
|
event: GestureResponderEvent,
|
|
36
|
-
type: PressEvent['type'] = 'press'
|
|
39
|
+
type: PressEvent['type'] = 'press',
|
|
40
|
+
targetRef?: RefObject<IdealystElement>
|
|
37
41
|
): PressEvent {
|
|
38
42
|
return {
|
|
39
43
|
nativeEvent: event.nativeEvent,
|
|
@@ -41,6 +45,7 @@ export function createPressEvent(
|
|
|
41
45
|
defaultPrevented: false,
|
|
42
46
|
propagationStopped: false,
|
|
43
47
|
type,
|
|
48
|
+
targetRef: targetRef ?? { current: event.target },
|
|
44
49
|
preventDefault: noop,
|
|
45
50
|
stopPropagation: noop,
|
|
46
51
|
};
|
|
@@ -35,6 +35,7 @@ export function createPressEvent(
|
|
|
35
35
|
defaultPrevented: event.defaultPrevented,
|
|
36
36
|
propagationStopped: false,
|
|
37
37
|
type,
|
|
38
|
+
targetRef: { current: event.currentTarget },
|
|
38
39
|
preventDefault: () => event.preventDefault(),
|
|
39
40
|
stopPropagation: () => event.stopPropagation(),
|
|
40
41
|
};
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
* React Native's event system doesn't have these concepts in the same way.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import type { RefObject } from 'react';
|
|
10
|
+
import type { IdealystElement } from '../refTypes';
|
|
11
|
+
|
|
9
12
|
/**
|
|
10
13
|
* Base synthetic event interface that normalizes web and native events
|
|
11
14
|
*/
|
|
@@ -53,6 +56,24 @@ export interface PressEvent extends SyntheticEvent {
|
|
|
53
56
|
* The type of press event
|
|
54
57
|
*/
|
|
55
58
|
type: 'press' | 'pressIn' | 'pressOut' | 'longPress';
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* A ref pointing to the element that fired the event.
|
|
62
|
+
* Can be passed directly as an anchor to Menu, Popover, etc.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```tsx
|
|
66
|
+
* const [open, setOpen] = useState(false);
|
|
67
|
+
* const [anchor, setAnchor] = useState<RefObject<IdealystElement> | null>(null);
|
|
68
|
+
*
|
|
69
|
+
* <Button onPress={(e) => {
|
|
70
|
+
* setAnchor(e.targetRef);
|
|
71
|
+
* setOpen(true);
|
|
72
|
+
* }}>Actions</Button>
|
|
73
|
+
* <Menu anchor={anchor} open={open} onOpenChange={setOpen} items={items} />
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
targetRef: RefObject<IdealystElement>;
|
|
56
77
|
}
|
|
57
78
|
|
|
58
79
|
/**
|