react-native-ui-lib 7.36.0-snapshot.6096 → 7.36.0-snapshot.6098
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 +1 -1
- package/src/components/hint/index.d.ts +186 -17
- package/src/components/hint/index.js +403 -150
- package/src/components/tabController/TabBar.js +2 -1
- package/src/components/tabController/TabBarContext.d.ts +1 -0
- package/src/components/tabController/TabBarItem.js +5 -2
- package/src/components/tabController/index.js +4 -1
- package/src/components/view/View.driver.new.js +1 -2
- package/src/components/hint/Hint.driver.new.d.ts +0 -19
- package/src/components/hint/Hint.driver.new.js +0 -19
- package/src/components/hint/HintAnchor.d.ts +0 -13
- package/src/components/hint/HintAnchor.js +0 -47
- package/src/components/hint/HintBubble.d.ts +0 -12
- package/src/components/hint/HintBubble.js +0 -64
- package/src/components/hint/HintMockChildren.d.ts +0 -8
- package/src/components/hint/HintMockChildren.js +0 -49
- package/src/components/hint/HintOld.d.ts +0 -196
- package/src/components/hint/HintOld.js +0 -549
- package/src/components/hint/hooks/useHintAccessibility.d.ts +0 -10
- package/src/components/hint/hooks/useHintAccessibility.js +0 -26
- package/src/components/hint/hooks/useHintLayout.d.ts +0 -13
- package/src/components/hint/hooks/useHintLayout.js +0 -66
- package/src/components/hint/hooks/useHintPosition.d.ts +0 -29
- package/src/components/hint/hooks/useHintPosition.js +0 -119
- package/src/components/hint/hooks/useHintVisibility.d.ts +0 -6
- package/src/components/hint/hooks/useHintVisibility.js +0 -26
- package/src/components/hint/types.d.ts +0 -106
- package/src/components/hint/types.js +0 -11
|
@@ -1,133 +1,324 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import _isUndefined from "lodash/isUndefined";
|
|
2
|
+
import _isEqual from "lodash/isEqual";
|
|
3
|
+
import _isString from "lodash/isString";
|
|
4
|
+
import React, { Component, isValidElement } from 'react';
|
|
5
|
+
import { Animated, StyleSheet, AccessibilityInfo, findNodeHandle, TouchableWithoutFeedback } from 'react-native';
|
|
3
6
|
import { Typography, Spacings, Colors, BorderRadiuses, Shadows } from "../../style";
|
|
4
7
|
import { Constants, asBaseComponent } from "../../commons/new";
|
|
5
8
|
import View from "../view";
|
|
9
|
+
import Text from "../text";
|
|
6
10
|
import Image from "../image";
|
|
7
11
|
import Modal from "../modal";
|
|
8
12
|
import TouchableOpacity from "../touchableOpacity";
|
|
9
|
-
import { HintPositions, HintProps, TargetAlignments } from "./types";
|
|
10
|
-
import useHintVisibility from "./hooks/useHintVisibility";
|
|
11
|
-
import useHintLayout from "./hooks/useHintLayout";
|
|
12
|
-
import useHintAccessibility from "./hooks/useHintAccessibility";
|
|
13
|
-
import useHintPosition from "./hooks/useHintPosition";
|
|
14
|
-
import HintMockChildren from "./HintMockChildren";
|
|
15
|
-
import HintAnchor from "./HintAnchor";
|
|
16
|
-
import HintBubble from "./HintBubble";
|
|
17
13
|
const sideTip = require("./assets/hintTipSide.png");
|
|
18
14
|
const middleTip = require("./assets/hintTipMiddle.png");
|
|
19
15
|
const DEFAULT_COLOR = Colors.$backgroundPrimaryHeavy;
|
|
20
16
|
const DEFAULT_HINT_OFFSET = Spacings.s4;
|
|
21
17
|
const DEFAULT_EDGE_MARGINS = Spacings.s5;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
18
|
+
var TARGET_POSITIONS = /*#__PURE__*/function (TARGET_POSITIONS) {
|
|
19
|
+
TARGET_POSITIONS["LEFT"] = "left";
|
|
20
|
+
TARGET_POSITIONS["RIGHT"] = "right";
|
|
21
|
+
TARGET_POSITIONS["CENTER"] = "center";
|
|
22
|
+
return TARGET_POSITIONS;
|
|
23
|
+
}(TARGET_POSITIONS || {});
|
|
24
|
+
var HintPositions = /*#__PURE__*/function (HintPositions) {
|
|
25
|
+
HintPositions["TOP"] = "top";
|
|
26
|
+
HintPositions["BOTTOM"] = "bottom";
|
|
27
|
+
return HintPositions;
|
|
28
|
+
}(HintPositions || {}); // TODO: unify with FeatureHighlightFrame
|
|
29
|
+
/**
|
|
30
|
+
* @description: Hint component for displaying a tooltip over wrapped component
|
|
31
|
+
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/HintsScreen.tsx
|
|
32
|
+
* @notes: You can either wrap a component or pass a specific targetFrame
|
|
33
|
+
* @gif: https://github.com/wix/react-native-ui-lib/blob/master/demo/showcase/Hint/Hint.gif?raw=true
|
|
34
|
+
*/
|
|
35
|
+
class Hint extends Component {
|
|
36
|
+
static displayName = 'Hint';
|
|
37
|
+
static defaultProps = {
|
|
38
|
+
position: HintPositions.BOTTOM,
|
|
39
|
+
useModal: true
|
|
40
|
+
};
|
|
41
|
+
static positions = HintPositions;
|
|
42
|
+
targetRef = null;
|
|
43
|
+
hintRef = React.createRef();
|
|
44
|
+
animationDuration = 170;
|
|
45
|
+
state = {
|
|
46
|
+
targetLayoutInWindow: undefined,
|
|
47
|
+
targetLayout: this.props.targetFrame,
|
|
48
|
+
hintUnmounted: !this.props.visible
|
|
49
|
+
};
|
|
50
|
+
visibleAnimated = new Animated.Value(Number(!!this.props.visible));
|
|
51
|
+
componentDidMount() {
|
|
52
|
+
this.focusAccessibilityOnHint();
|
|
53
|
+
}
|
|
54
|
+
componentDidUpdate(prevProps) {
|
|
55
|
+
if (prevProps.visible !== this.props.visible) {
|
|
56
|
+
this.animateHint();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
animateHint = () => {
|
|
60
|
+
Animated.timing(this.visibleAnimated, {
|
|
61
|
+
toValue: Number(!!this.props.visible),
|
|
62
|
+
duration: this.animationDuration,
|
|
63
|
+
useNativeDriver: true
|
|
64
|
+
}).start(this.toggleAnimationEndedToRemoveHint);
|
|
65
|
+
};
|
|
66
|
+
toggleAnimationEndedToRemoveHint = () => {
|
|
67
|
+
this.setState({
|
|
68
|
+
hintUnmounted: !this.props.visible
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
focusAccessibilityOnHint = () => {
|
|
72
|
+
const {
|
|
73
|
+
message
|
|
74
|
+
} = this.props;
|
|
75
|
+
const targetRefTag = findNodeHandle(this.targetRef);
|
|
76
|
+
const hintRefTag = findNodeHandle(this.hintRef.current);
|
|
77
|
+
if (targetRefTag && _isString(message)) {
|
|
78
|
+
AccessibilityInfo.setAccessibilityFocus(targetRefTag);
|
|
79
|
+
} else if (hintRefTag) {
|
|
80
|
+
AccessibilityInfo.setAccessibilityFocus(hintRefTag);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
setTargetRef = ref => {
|
|
84
|
+
this.targetRef = ref;
|
|
85
|
+
this.focusAccessibilityOnHint();
|
|
86
|
+
};
|
|
87
|
+
onTargetLayout = ({
|
|
88
|
+
nativeEvent: {
|
|
89
|
+
layout
|
|
90
|
+
}
|
|
91
|
+
}) => {
|
|
92
|
+
if (!_isEqual(this.state.targetLayout, layout)) {
|
|
93
|
+
this.setState({
|
|
94
|
+
targetLayout: layout
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (!this.state.targetLayoutInWindow || this.props.onBackgroundPress) {
|
|
98
|
+
setTimeout(() => {
|
|
99
|
+
this.targetRef?.measureInWindow?.((x, y, width, height) => {
|
|
100
|
+
const targetLayoutInWindow = {
|
|
101
|
+
x,
|
|
102
|
+
y,
|
|
103
|
+
width,
|
|
104
|
+
height
|
|
105
|
+
};
|
|
106
|
+
this.setState({
|
|
107
|
+
targetLayoutInWindow
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
getAccessibilityInfo() {
|
|
114
|
+
const {
|
|
115
|
+
visible,
|
|
116
|
+
message
|
|
117
|
+
} = this.props;
|
|
118
|
+
if (visible && _isString(message)) {
|
|
119
|
+
return {
|
|
120
|
+
accessible: true,
|
|
121
|
+
accessibilityLabel: `hint: ${message}`
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
get containerWidth() {
|
|
126
|
+
const {
|
|
127
|
+
containerWidth = Constants.windowWidth
|
|
128
|
+
} = this.props;
|
|
129
|
+
return containerWidth;
|
|
130
|
+
}
|
|
131
|
+
get targetLayout() {
|
|
132
|
+
const {
|
|
133
|
+
onBackgroundPress,
|
|
134
|
+
useModal,
|
|
135
|
+
targetFrame
|
|
136
|
+
} = this.props;
|
|
137
|
+
const {
|
|
138
|
+
targetLayout,
|
|
139
|
+
targetLayoutInWindow
|
|
140
|
+
} = this.state;
|
|
141
|
+
if (targetFrame) {
|
|
142
|
+
return targetFrame;
|
|
143
|
+
}
|
|
144
|
+
return onBackgroundPress && useModal ? targetLayoutInWindow : targetLayout;
|
|
145
|
+
}
|
|
146
|
+
get showHint() {
|
|
147
|
+
return !!this.targetLayout;
|
|
148
|
+
}
|
|
149
|
+
get tipSize() {
|
|
150
|
+
return this.useSideTip ? {
|
|
151
|
+
width: 14,
|
|
152
|
+
height: 7
|
|
153
|
+
} : {
|
|
154
|
+
width: 20,
|
|
155
|
+
height: 7
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
get hintOffset() {
|
|
159
|
+
const {
|
|
160
|
+
offset = DEFAULT_HINT_OFFSET
|
|
161
|
+
} = this.props;
|
|
162
|
+
return offset;
|
|
163
|
+
}
|
|
164
|
+
get edgeMargins() {
|
|
165
|
+
const {
|
|
166
|
+
edgeMargins = DEFAULT_EDGE_MARGINS
|
|
167
|
+
} = this.props;
|
|
168
|
+
return edgeMargins;
|
|
169
|
+
}
|
|
170
|
+
get useSideTip() {
|
|
171
|
+
const {
|
|
172
|
+
useSideTip
|
|
173
|
+
} = this.props;
|
|
174
|
+
if (!_isUndefined(useSideTip)) {
|
|
175
|
+
return useSideTip;
|
|
176
|
+
}
|
|
177
|
+
return this.getTargetPositionOnScreen() !== TARGET_POSITIONS.CENTER;
|
|
178
|
+
}
|
|
179
|
+
getTargetPositionOnScreen() {
|
|
180
|
+
if (this.targetLayout?.x !== undefined && this.targetLayout?.width) {
|
|
181
|
+
const targetMidPosition = this.targetLayout.x + this.targetLayout.width / 2;
|
|
182
|
+
if (targetMidPosition > this.containerWidth * (2 / 3)) {
|
|
183
|
+
return TARGET_POSITIONS.RIGHT;
|
|
184
|
+
} else if (targetMidPosition < this.containerWidth * (1 / 3)) {
|
|
185
|
+
return TARGET_POSITIONS.LEFT;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return TARGET_POSITIONS.CENTER;
|
|
189
|
+
}
|
|
190
|
+
getContainerPosition() {
|
|
191
|
+
if (this.targetLayout) {
|
|
192
|
+
return {
|
|
193
|
+
top: this.targetLayout.y,
|
|
194
|
+
left: this.targetLayout.x
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
getHintPosition() {
|
|
199
|
+
const {
|
|
200
|
+
position
|
|
201
|
+
} = this.props;
|
|
202
|
+
const hintPositionStyle = {
|
|
203
|
+
alignItems: 'center'
|
|
204
|
+
};
|
|
205
|
+
if (this.targetLayout?.x !== undefined) {
|
|
206
|
+
hintPositionStyle.left = -this.targetLayout.x;
|
|
207
|
+
}
|
|
208
|
+
if (position === HintPositions.TOP) {
|
|
209
|
+
hintPositionStyle.bottom = 0;
|
|
210
|
+
} else if (this.targetLayout?.height) {
|
|
211
|
+
hintPositionStyle.top = this.targetLayout.height;
|
|
212
|
+
}
|
|
213
|
+
const targetPositionOnScreen = this.getTargetPositionOnScreen();
|
|
214
|
+
if (targetPositionOnScreen === TARGET_POSITIONS.RIGHT) {
|
|
215
|
+
hintPositionStyle.alignItems = Constants.isRTL ? 'flex-start' : 'flex-end';
|
|
216
|
+
} else if (targetPositionOnScreen === TARGET_POSITIONS.LEFT) {
|
|
217
|
+
hintPositionStyle.alignItems = Constants.isRTL ? 'flex-end' : 'flex-start';
|
|
218
|
+
}
|
|
219
|
+
return hintPositionStyle;
|
|
220
|
+
}
|
|
221
|
+
getHintPadding() {
|
|
222
|
+
const paddings = {
|
|
223
|
+
paddingVertical: this.hintOffset,
|
|
224
|
+
paddingHorizontal: this.edgeMargins
|
|
225
|
+
};
|
|
226
|
+
if (this.useSideTip && this.targetLayout?.x !== undefined) {
|
|
227
|
+
const targetPositionOnScreen = this.getTargetPositionOnScreen();
|
|
228
|
+
if (targetPositionOnScreen === TARGET_POSITIONS.LEFT) {
|
|
229
|
+
paddings.paddingLeft = this.targetLayout.x;
|
|
230
|
+
} else if (targetPositionOnScreen === TARGET_POSITIONS.RIGHT && this.targetLayout?.width) {
|
|
231
|
+
paddings.paddingRight = this.containerWidth - this.targetLayout.x - this.targetLayout.width;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return paddings;
|
|
235
|
+
}
|
|
236
|
+
getHintAnimatedStyle = () => {
|
|
237
|
+
const {
|
|
238
|
+
position
|
|
239
|
+
} = this.props;
|
|
103
240
|
const translateY = position === HintPositions.TOP ? -10 : 10;
|
|
104
241
|
return {
|
|
105
|
-
opacity:
|
|
242
|
+
opacity: this.visibleAnimated,
|
|
106
243
|
transform: [{
|
|
107
|
-
translateY:
|
|
244
|
+
translateY: this.visibleAnimated.interpolate({
|
|
108
245
|
inputRange: [0, 1],
|
|
109
246
|
outputRange: [translateY, 0]
|
|
110
247
|
})
|
|
111
248
|
}]
|
|
112
249
|
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
250
|
+
};
|
|
251
|
+
getTipPosition() {
|
|
252
|
+
const {
|
|
253
|
+
position
|
|
254
|
+
} = this.props;
|
|
255
|
+
const tipPositionStyle = {};
|
|
256
|
+
if (position === HintPositions.TOP) {
|
|
257
|
+
tipPositionStyle.bottom = this.hintOffset - this.tipSize.height;
|
|
258
|
+
!this.useSideTip ? tipPositionStyle.bottom += 1 : undefined;
|
|
259
|
+
} else {
|
|
260
|
+
tipPositionStyle.top = this.hintOffset - this.tipSize.height;
|
|
261
|
+
}
|
|
262
|
+
const layoutWidth = this.targetLayout?.width || 0;
|
|
263
|
+
if (this.targetLayout?.x !== undefined) {
|
|
264
|
+
const targetMidWidth = layoutWidth / 2;
|
|
265
|
+
const tipMidWidth = this.tipSize.width / 2;
|
|
266
|
+
const leftPosition = this.useSideTip ? this.targetLayout.x : this.targetLayout.x + targetMidWidth - tipMidWidth;
|
|
267
|
+
const rightPosition = this.useSideTip ? this.containerWidth - this.targetLayout.x - layoutWidth : this.containerWidth - this.targetLayout.x - targetMidWidth - tipMidWidth;
|
|
268
|
+
const targetPositionOnScreen = this.getTargetPositionOnScreen();
|
|
269
|
+
switch (targetPositionOnScreen) {
|
|
270
|
+
case TARGET_POSITIONS.LEFT:
|
|
271
|
+
tipPositionStyle.left = Constants.isRTL ? rightPosition : leftPosition;
|
|
272
|
+
break;
|
|
273
|
+
case TARGET_POSITIONS.RIGHT:
|
|
274
|
+
tipPositionStyle.right = Constants.isRTL ? leftPosition : rightPosition;
|
|
275
|
+
break;
|
|
276
|
+
case TARGET_POSITIONS.CENTER:
|
|
277
|
+
default:
|
|
278
|
+
tipPositionStyle.left = this.targetLayout.x + targetMidWidth - tipMidWidth;
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return tipPositionStyle;
|
|
283
|
+
}
|
|
284
|
+
isUsingModal = () => {
|
|
285
|
+
const {
|
|
286
|
+
onBackgroundPress,
|
|
287
|
+
useModal
|
|
288
|
+
} = this.props;
|
|
289
|
+
return onBackgroundPress && useModal;
|
|
290
|
+
};
|
|
291
|
+
renderOverlay() {
|
|
292
|
+
const {
|
|
293
|
+
targetLayoutInWindow
|
|
294
|
+
} = this.state;
|
|
295
|
+
const {
|
|
296
|
+
onBackgroundPress,
|
|
297
|
+
backdropColor,
|
|
298
|
+
testID
|
|
299
|
+
} = this.props;
|
|
300
|
+
if (targetLayoutInWindow) {
|
|
301
|
+
const containerPosition = this.getContainerPosition();
|
|
116
302
|
return <Animated.View style={[styles.overlay, {
|
|
117
|
-
|
|
303
|
+
top: containerPosition.top - targetLayoutInWindow.y,
|
|
304
|
+
left: containerPosition.left - targetLayoutInWindow.x,
|
|
118
305
|
backgroundColor: backdropColor,
|
|
119
|
-
opacity:
|
|
306
|
+
opacity: this.visibleAnimated
|
|
120
307
|
}]} pointerEvents="box-none" testID={`${testID}.overlay`}>
|
|
121
308
|
{onBackgroundPress && <TouchableWithoutFeedback style={StyleSheet.absoluteFillObject} onPress={onBackgroundPress}>
|
|
122
309
|
<View flex />
|
|
123
310
|
</TouchableWithoutFeedback>}
|
|
124
311
|
</Animated.View>;
|
|
125
312
|
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const
|
|
313
|
+
}
|
|
314
|
+
renderHintTip() {
|
|
315
|
+
const {
|
|
316
|
+
position,
|
|
317
|
+
color = DEFAULT_COLOR
|
|
318
|
+
} = this.props;
|
|
319
|
+
const source = this.useSideTip ? sideTip : middleTip;
|
|
129
320
|
const flipVertically = position === HintPositions.TOP;
|
|
130
|
-
const flipHorizontally =
|
|
321
|
+
const flipHorizontally = this.getTargetPositionOnScreen() === TARGET_POSITIONS.RIGHT;
|
|
131
322
|
const flipStyle = {
|
|
132
323
|
transform: [{
|
|
133
324
|
scaleY: flipVertically ? -1 : 1
|
|
@@ -135,49 +326,121 @@ const Hint = props => {
|
|
|
135
326
|
scaleX: flipHorizontally ? -1 : 1
|
|
136
327
|
}]
|
|
137
328
|
};
|
|
138
|
-
return <Image tintColor={color} source={source} style={[styles.hintTip,
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
329
|
+
return <Image tintColor={color} source={source} style={[styles.hintTip, this.getTipPosition(), flipStyle]} />;
|
|
330
|
+
}
|
|
331
|
+
renderContent() {
|
|
332
|
+
const {
|
|
333
|
+
message,
|
|
334
|
+
messageStyle,
|
|
335
|
+
icon,
|
|
336
|
+
iconStyle,
|
|
337
|
+
borderRadius,
|
|
338
|
+
color = DEFAULT_COLOR,
|
|
339
|
+
customContent,
|
|
340
|
+
removePaddings,
|
|
341
|
+
enableShadow,
|
|
342
|
+
visible,
|
|
343
|
+
testID
|
|
344
|
+
} = this.props;
|
|
345
|
+
return <View testID={`${testID}.message`} row centerV style={[styles.hint, !removePaddings && styles.hintPaddings, visible && enableShadow && styles.containerShadow, {
|
|
346
|
+
backgroundColor: color
|
|
347
|
+
}, !_isUndefined(borderRadius) && {
|
|
348
|
+
borderRadius
|
|
349
|
+
}]} ref={this.hintRef}>
|
|
350
|
+
{customContent}
|
|
351
|
+
{!customContent && icon && <Image source={icon} style={[styles.icon, iconStyle]} />}
|
|
352
|
+
{!customContent && <Text recorderTag={'unmask'} style={[styles.hintMessage, messageStyle]} testID={`${testID}.message.text`}>
|
|
353
|
+
{message}
|
|
354
|
+
</Text>}
|
|
355
|
+
</View>;
|
|
356
|
+
}
|
|
357
|
+
renderHint() {
|
|
358
|
+
const {
|
|
359
|
+
onPress,
|
|
360
|
+
testID
|
|
361
|
+
} = this.props;
|
|
144
362
|
const opacity = onPress ? 0.9 : 1.0;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
363
|
+
if (this.showHint) {
|
|
364
|
+
return <View animated style={[{
|
|
365
|
+
width: this.containerWidth
|
|
366
|
+
}, styles.animatedContainer, this.getHintPosition(), this.getHintPadding(), this.getHintAnimatedStyle()]} pointerEvents="box-none" testID={testID}>
|
|
367
|
+
<TouchableOpacity activeOpacity={opacity} onPress={onPress}>
|
|
368
|
+
{this.renderContent()}
|
|
369
|
+
</TouchableOpacity>
|
|
370
|
+
{this.renderHintTip()}
|
|
371
|
+
</View>;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
renderHintContainer() {
|
|
375
|
+
const {
|
|
376
|
+
style,
|
|
377
|
+
...others
|
|
378
|
+
} = this.props;
|
|
379
|
+
return <View {...others}
|
|
380
|
+
// this view must be collapsable, don't pass testID or backgroundColor etc'.
|
|
381
|
+
collapsable testID={undefined} style={[styles.container, style, this.getContainerPosition(), !this.isUsingModal() && styles.overlayContainer]}>
|
|
382
|
+
{this.renderHint()}
|
|
383
|
+
</View>;
|
|
384
|
+
}
|
|
385
|
+
renderMockChildren() {
|
|
386
|
+
const {
|
|
387
|
+
children,
|
|
388
|
+
backdropColor
|
|
389
|
+
} = this.props;
|
|
390
|
+
const isBackdropColorPassed = backdropColor !== undefined;
|
|
391
|
+
if (children && React.isValidElement(children)) {
|
|
392
|
+
const layout = {
|
|
393
|
+
...this.getContainerPosition(),
|
|
394
|
+
width: this.targetLayout?.width,
|
|
395
|
+
height: this.targetLayout?.height,
|
|
396
|
+
right: Constants.isRTL ? this.targetLayout?.x : undefined,
|
|
397
|
+
left: Constants.isRTL ? undefined : this.targetLayout?.x
|
|
398
|
+
};
|
|
399
|
+
return <View style={[styles.mockChildrenContainer, layout, !isBackdropColorPassed && styles.hidden]}>
|
|
400
|
+
{React.cloneElement(children, {
|
|
401
|
+
collapsable: false,
|
|
402
|
+
key: 'mock',
|
|
403
|
+
style: [children.props.style, styles.mockChildren]
|
|
404
|
+
})}
|
|
405
|
+
</View>;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
renderChildren() {
|
|
409
|
+
const {
|
|
410
|
+
targetFrame
|
|
411
|
+
} = this.props;
|
|
412
|
+
if (!targetFrame && isValidElement(this.props.children)) {
|
|
413
|
+
return React.cloneElement(this.props.children, {
|
|
158
414
|
key: 'clone',
|
|
159
415
|
collapsable: false,
|
|
160
|
-
onLayout: onTargetLayout,
|
|
161
|
-
ref: setTargetRef,
|
|
162
|
-
...
|
|
416
|
+
onLayout: this.onTargetLayout,
|
|
417
|
+
ref: this.setTargetRef,
|
|
418
|
+
...this.getAccessibilityInfo()
|
|
163
419
|
});
|
|
164
420
|
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
421
|
+
}
|
|
422
|
+
render() {
|
|
423
|
+
const {
|
|
424
|
+
onBackgroundPress,
|
|
425
|
+
backdropColor,
|
|
426
|
+
testID
|
|
427
|
+
} = this.props;
|
|
428
|
+
if (!this.props.visible && this.state.hintUnmounted) {
|
|
429
|
+
return this.props.children || null;
|
|
430
|
+
}
|
|
431
|
+
return <>
|
|
432
|
+
{this.renderChildren()}
|
|
433
|
+
{this.isUsingModal() ? <Modal visible={this.showHint} animationType={backdropColor ? 'fade' : 'none'} overlayBackgroundColor={backdropColor} transparent onBackgroundPress={onBackgroundPress} onRequestClose={onBackgroundPress} testID={`${testID}.modal`}>
|
|
434
|
+
{this.renderMockChildren()}
|
|
435
|
+
{this.renderHintContainer()}
|
|
436
|
+
</Modal> : <>
|
|
437
|
+
{this.renderOverlay()}
|
|
438
|
+
{this.renderMockChildren()}
|
|
439
|
+
{this.renderHintContainer()}
|
|
440
|
+
</>}
|
|
441
|
+
</>;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
181
444
|
const styles = StyleSheet.create({
|
|
182
445
|
container: {
|
|
183
446
|
position: 'absolute'
|
|
@@ -217,7 +480,6 @@ const styles = StyleSheet.create({
|
|
|
217
480
|
position: 'absolute'
|
|
218
481
|
},
|
|
219
482
|
hint: {
|
|
220
|
-
minWidth: HINT_MIN_WIDTH,
|
|
221
483
|
maxWidth: Math.min(Constants.windowWidth - 2 * Spacings.s4, 400),
|
|
222
484
|
borderRadius: BorderRadiuses.br60,
|
|
223
485
|
backgroundColor: DEFAULT_COLOR
|
|
@@ -240,13 +502,4 @@ const styles = StyleSheet.create({
|
|
|
240
502
|
tintColor: Colors.white
|
|
241
503
|
}
|
|
242
504
|
});
|
|
243
|
-
Hint.displayName = 'Hint';
|
|
244
|
-
Hint.defaultProps = {
|
|
245
|
-
position: HintPositions.BOTTOM,
|
|
246
|
-
useModal: true
|
|
247
|
-
};
|
|
248
|
-
Hint.positions = HintPositions;
|
|
249
|
-
export { HintProps, Hint };
|
|
250
|
-
|
|
251
|
-
// @ts-expect-error
|
|
252
505
|
export default asBaseComponent(Hint);
|
|
@@ -149,7 +149,8 @@ const TabBar = props => {
|
|
|
149
149
|
}, [labelColor, selectedLabelColor]);
|
|
150
150
|
return <View style={_containerStyle} key={key} bg-$backgroundElevated>
|
|
151
151
|
<FadedScrollView ref={tabBar} horizontal showsHorizontalScrollIndicator={false} showStartFader startFaderProps={faderProps} showEndFader endFaderProps={faderProps} contentContainerStyle={scrollViewContainerStyle} testID={testID} onContentSizeChange={onContentSizeChange} onLayout={onLayout}>
|
|
152
|
-
|
|
152
|
+
{/* TODO: Might need to change role to tablist, when upgrading rn77. It didn't work now (rn73) */}
|
|
153
|
+
<View style={tabBarContainerStyle} accessibilityRole="tabbar">{tabBarItems}</View>
|
|
153
154
|
{itemsCount > 1 && <Reanimated.View style={[styles.selectedIndicator, indicatorStyle, _indicatorTransitionStyle]} />}
|
|
154
155
|
</FadedScrollView>
|
|
155
156
|
</View>;
|
|
@@ -13,6 +13,7 @@ interface TabControllerContext {
|
|
|
13
13
|
/** transition page index (can be a fraction when transitioning between pages) */
|
|
14
14
|
targetPage: Reanimated.SharedValue<number>;
|
|
15
15
|
setCurrentIndex: (index: number) => void;
|
|
16
|
+
selectedIndex: number;
|
|
16
17
|
}
|
|
17
18
|
declare const TabBarContext: React.Context<TabControllerContext>;
|
|
18
19
|
export default TabBarContext;
|
|
@@ -44,7 +44,8 @@ export default function TabBarItem({
|
|
|
44
44
|
}) {
|
|
45
45
|
const {
|
|
46
46
|
currentPage,
|
|
47
|
-
setCurrentIndex
|
|
47
|
+
setCurrentIndex,
|
|
48
|
+
selectedIndex
|
|
48
49
|
} = useContext(TabBarContext);
|
|
49
50
|
const itemRef = useRef();
|
|
50
51
|
const itemWidth = useRef(props.width);
|
|
@@ -133,7 +134,9 @@ export default function TabBarItem({
|
|
|
133
134
|
return <GestureDetector gesture={gesture}>
|
|
134
135
|
<View reanimated
|
|
135
136
|
// @ts-expect-error
|
|
136
|
-
ref={itemRef} style={_style} onLayout={onLayout} testID={testID}
|
|
137
|
+
ref={itemRef} style={_style} onLayout={onLayout} testID={testID} accessible accessibilityRole="tab" accessibilityState={{
|
|
138
|
+
selected: selectedIndex === index
|
|
139
|
+
}}>
|
|
137
140
|
{leadingAccessory}
|
|
138
141
|
{icon && <Reanimated.Image source={icon} style={[!_isUndefined(label) && styles.tabItemIconWithLabel, animatedIconStyle]} />}
|
|
139
142
|
{!_isEmpty(label) && <Reanimated.Text {...labelProps} fsTagName={'unmask'} style={[styles.tabItemLabel, labelStyle, animatedLabelStyle, animatedLabelColorStyle]}>
|
|
@@ -38,6 +38,7 @@ const TabController = React.forwardRef((props, ref) => {
|
|
|
38
38
|
children
|
|
39
39
|
} = themeProps;
|
|
40
40
|
const [screenWidth, setScreenWidth] = useState(getScreenWidth(useSafeArea));
|
|
41
|
+
const [selectedIndex, setSelectedIndex] = useState(initialIndex);
|
|
41
42
|
if (items?.length < 2) {
|
|
42
43
|
console.warn('TabController component expect a minimum of 2 items');
|
|
43
44
|
}
|
|
@@ -61,6 +62,7 @@ const TabController = React.forwardRef((props, ref) => {
|
|
|
61
62
|
'worklet';
|
|
62
63
|
|
|
63
64
|
currentPage.value = index;
|
|
65
|
+
runOnJS(setSelectedIndex)(index);
|
|
64
66
|
}, []);
|
|
65
67
|
useEffect(() => {
|
|
66
68
|
setCurrentIndex(initialIndex);
|
|
@@ -88,12 +90,13 @@ const TabController = React.forwardRef((props, ref) => {
|
|
|
88
90
|
/* Animated Values */
|
|
89
91
|
targetPage,
|
|
90
92
|
currentPage,
|
|
93
|
+
selectedIndex,
|
|
91
94
|
containerWidth: screenWidth,
|
|
92
95
|
/* Callbacks */
|
|
93
96
|
onChangeIndex,
|
|
94
97
|
setCurrentIndex
|
|
95
98
|
};
|
|
96
|
-
}, [initialIndex, asCarousel, items, onChangeIndex, screenWidth, nestedInScrollView]);
|
|
99
|
+
}, [initialIndex, asCarousel, items, onChangeIndex, screenWidth, nestedInScrollView, selectedIndex]);
|
|
97
100
|
return <TabBarContext.Provider value={context}>{children}</TabBarContext.Provider>;
|
|
98
101
|
});
|
|
99
102
|
|