@fluentui-react-native/tester 0.59.38 → 0.60.0

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 (24) hide show
  1. package/CHANGELOG.json +76 -1
  2. package/CHANGELOG.md +31 -2
  3. package/lib/FluentTester/TestComponents/Avatar/BasicAvatar.d.ts.map +1 -1
  4. package/lib/FluentTester/TestComponents/Avatar/BasicAvatar.js +3 -2
  5. package/lib/FluentTester/TestComponents/Avatar/BasicAvatar.js.map +1 -1
  6. package/lib/FluentTester/TestComponents/Avatar/CustomizedAvatar.d.ts.map +1 -1
  7. package/lib/FluentTester/TestComponents/Avatar/CustomizedAvatar.js +9 -14
  8. package/lib/FluentTester/TestComponents/Avatar/CustomizedAvatar.js.map +1 -1
  9. package/lib/FluentTester/TestComponents/Callout/CalloutTest.d.ts.map +1 -1
  10. package/lib/FluentTester/TestComponents/Callout/CalloutTest.js +98 -37
  11. package/lib/FluentTester/TestComponents/Callout/CalloutTest.js.map +1 -1
  12. package/lib-commonjs/FluentTester/TestComponents/Avatar/BasicAvatar.d.ts.map +1 -1
  13. package/lib-commonjs/FluentTester/TestComponents/Avatar/BasicAvatar.js +3 -2
  14. package/lib-commonjs/FluentTester/TestComponents/Avatar/BasicAvatar.js.map +1 -1
  15. package/lib-commonjs/FluentTester/TestComponents/Avatar/CustomizedAvatar.d.ts.map +1 -1
  16. package/lib-commonjs/FluentTester/TestComponents/Avatar/CustomizedAvatar.js +9 -14
  17. package/lib-commonjs/FluentTester/TestComponents/Avatar/CustomizedAvatar.js.map +1 -1
  18. package/lib-commonjs/FluentTester/TestComponents/Callout/CalloutTest.d.ts.map +1 -1
  19. package/lib-commonjs/FluentTester/TestComponents/Callout/CalloutTest.js +97 -36
  20. package/lib-commonjs/FluentTester/TestComponents/Callout/CalloutTest.js.map +1 -1
  21. package/package.json +5 -5
  22. package/src/FluentTester/TestComponents/Avatar/BasicAvatar.tsx +3 -2
  23. package/src/FluentTester/TestComponents/Avatar/CustomizedAvatar.tsx +10 -15
  24. package/src/FluentTester/TestComponents/Callout/CalloutTest.tsx +138 -32
@@ -1,6 +1,15 @@
1
1
  import * as React from 'react';
2
2
  import { ScreenRect, Text, View, Switch, Picker, ScrollView } from 'react-native';
3
- import { Button, Callout, Separator, IFocusable, RestoreFocusEvent, DismissBehaviors, StealthButton } from '@fluentui/react-native';
3
+ import {
4
+ Button,
5
+ Callout,
6
+ Separator,
7
+ IFocusable,
8
+ Pressable,
9
+ RestoreFocusEvent,
10
+ DismissBehaviors,
11
+ StealthButton,
12
+ } from '@fluentui/react-native';
4
13
  import { CALLOUT_TESTPAGE } from './consts';
5
14
  import { Test, TestSection, PlatformStatus } from '../Test';
6
15
  import { E2ECalloutTest } from './CalloutE2ETest';
@@ -9,6 +18,8 @@ import { fluentTesterStyles } from '../Common/styles';
9
18
  const StandardCallout: React.FunctionComponent = () => {
10
19
  const [showStandardCallout, setShowStandardCallout] = React.useState(false);
11
20
  const [isStandardCalloutVisible, setIsStandardCalloutVisible] = React.useState(false);
21
+ const [openCalloutOnHoverAnchor, setOpenCalloutOnHoverAnchor] = React.useState(true);
22
+ const [calloutHovered, setCalloutHovered] = React.useState(false);
12
23
 
13
24
  const [shouldSetInitialFocus, setShouldSetInitialFocus] = React.useState(true);
14
25
  const onInitialFocusChange = React.useCallback((value) => setShouldSetInitialFocus(value), []);
@@ -59,32 +70,94 @@ const StandardCallout: React.FunctionComponent = () => {
59
70
  const decoyBtn1Ref = React.useRef<IFocusable>(null);
60
71
  const decoyBtn2Ref = React.useRef<IFocusable>(null);
61
72
  const [anchorRef, setAnchorRef] = React.useState(redTargetRef);
73
+ const [hoveredTargetsCount, setHoveredTargetsCount] = React.useState(0);
74
+ const [displayCountHoveredTargets, setDisplayCountHoveredTargets] = React.useState(0);
75
+
76
+ const anchorRefsInfo: { hoverCount: number; isCurrentAnchor: boolean[] } = React.useMemo(() => {
77
+ return {
78
+ hoverCount: displayCountHoveredTargets,
79
+ isCurrentAnchor: [
80
+ openCalloutOnHoverAnchor && isStandardCalloutVisible && anchorRef == redTargetRef,
81
+ openCalloutOnHoverAnchor && isStandardCalloutVisible && anchorRef == greenTargetRef,
82
+ openCalloutOnHoverAnchor && isStandardCalloutVisible && anchorRef == blueTargetRef,
83
+ ],
84
+ };
85
+ }, [anchorRef, displayCountHoveredTargets, isStandardCalloutVisible, openCalloutOnHoverAnchor]);
86
+
87
+ // Use a timer to update the targets count and avoid jittery updates of counts on-screen
88
+ React.useLayoutEffect(() => {
89
+ const timer = setTimeout(() => {
90
+ setDisplayCountHoveredTargets(hoveredTargetsCount);
91
+ }, 50);
92
+
93
+ return () => clearTimeout(timer);
94
+ }, [hoveredTargetsCount]);
95
+
96
+ React.useLayoutEffect(() => {
97
+ // The callout may be dismissed by multiple mechanisms, depending on its active invocation
98
+ // mechanisms. In each of those dismissal routes, we use this function to reset the callout's
99
+ // state universally.
100
+ if (!showStandardCallout) {
101
+ setIsStandardCalloutVisible(false);
102
+ setCalloutHovered(false);
103
+ }
104
+ }, [showStandardCallout]);
62
105
 
63
106
  const toggleShowStandardCallout = React.useCallback(() => {
64
107
  setShowStandardCallout(!showStandardCallout);
108
+ }, [showStandardCallout]);
109
+
110
+ // Set up a LayoutEffect for hover callout mechanics including:
111
+ // the toggle switch for hover callout behavior
112
+ // multiple hover targets (i.e. the callout and its anchor)
113
+ // a dismissal timer for closing the callout with no targets hovered
114
+ React.useLayoutEffect(() => {
115
+ if (!openCalloutOnHoverAnchor) {
116
+ setShowStandardCallout(false);
117
+ } else if (openCalloutOnHoverAnchor && hoveredTargetsCount > 0) {
118
+ setShowStandardCallout(true);
119
+ } else {
120
+ const timer = setTimeout(() => {
121
+ setShowStandardCallout(false);
122
+ }, 2000);
123
+ return () => clearTimeout(timer);
124
+ }
125
+ return undefined;
126
+ }, [openCalloutOnHoverAnchor, hoveredTargetsCount]);
127
+
128
+ const updateCalloutTargetsHoverState = React.useCallback(
129
+ (show: boolean, hoverAnchorRef: React.MutableRefObject<View>) => {
130
+ if (hoverAnchorRef !== undefined && hoverAnchorRef !== anchorRef) {
131
+ return;
132
+ }
65
133
 
66
- // Unmounting a callout does not invoke onDismiss; onDismiss is only invoked
67
- // for dismissals generated by the native app. When toggling to 'show',
68
- // the isVisible state will be corrected to 'true' by the onShow callback.
69
- setIsStandardCalloutVisible(false);
70
- }, [showStandardCallout, setIsStandardCalloutVisible, setShowStandardCallout]);
134
+ setHoveredTargetsCount(hoveredTargetsCount + (show ? 1 : -1));
135
+ },
136
+ [anchorRef, hoveredTargetsCount, setHoveredTargetsCount],
137
+ );
138
+
139
+ const calloutHoveredCallback = React.useCallback(
140
+ (isHovered: boolean) => {
141
+ updateCalloutTargetsHoverState(isHovered, undefined);
142
+ setCalloutHovered(isHovered);
143
+ },
144
+ [updateCalloutTargetsHoverState],
145
+ );
71
146
 
72
147
  const toggleCalloutRef = React.useCallback(() => {
73
148
  // Cycle the target ref between the RGB target views
74
149
  setAnchorRef(anchorRef === redTargetRef ? greenTargetRef : anchorRef === greenTargetRef ? blueTargetRef : redTargetRef);
75
- }, [anchorRef, setAnchorRef]);
150
+ }, [anchorRef]);
76
151
 
77
152
  const onShowStandardCallout = React.useCallback(() => {
78
153
  setIsStandardCalloutVisible(true);
79
- }, [setIsStandardCalloutVisible]);
154
+ }, []);
80
155
 
81
156
  const onDismissStandardCallout = React.useCallback(() => {
82
- setIsStandardCalloutVisible(false);
83
-
84
157
  // setting the internal state to false will instigate unmounting the
85
158
  // zombie Callout control.
86
159
  setShowStandardCallout(false);
87
- }, [setIsStandardCalloutVisible, setShowStandardCallout]);
160
+ }, []);
88
161
 
89
162
  const onRestoreFocusStandardCallout = React.useCallback(
90
163
  (restoreFocusEvent: RestoreFocusEvent) => {
@@ -125,6 +198,11 @@ const StandardCallout: React.FunctionComponent = () => {
125
198
  <View>
126
199
  <View style={{ flexDirection: 'row', paddingVertical: 5 }}>
127
200
  <View style={{ flexDirection: 'column', paddingHorizontal: 5 }}>
201
+ <View style={{ flexDirection: 'row' }}>
202
+ <Switch value={openCalloutOnHoverAnchor} onValueChange={setOpenCalloutOnHoverAnchor} />
203
+ <Text>Show Callout On Hover Anchor</Text>
204
+ </View>
205
+
128
206
  <View style={{ flexDirection: 'row' }}>
129
207
  <Switch value={shouldSetInitialFocus} onValueChange={onInitialFocusChange} />
130
208
  <Text>Set Initial Focus</Text>
@@ -189,7 +267,11 @@ const StandardCallout: React.FunctionComponent = () => {
189
267
  <Separator vertical />
190
268
 
191
269
  <View style={{ flexDirection: 'column', paddingHorizontal: 5 }}>
192
- <Button content="Press for Callout" onClick={toggleShowStandardCallout} />
270
+ <Button
271
+ content={(openCalloutOnHoverAnchor ? 'Hover Color Anchor ' : 'Press Here ') + 'for Callout'}
272
+ onClick={toggleShowStandardCallout}
273
+ disabled={openCalloutOnHoverAnchor}
274
+ />
193
275
  <Text>
194
276
  <Text>Visibility: </Text>
195
277
  {isStandardCalloutVisible ? <Text style={{ color: 'green' }}>Visible</Text> : <Text style={{ color: 'red' }}>Not Visible</Text>}
@@ -199,9 +281,30 @@ const StandardCallout: React.FunctionComponent = () => {
199
281
  <Separator vertical />
200
282
 
201
283
  <View style={{ flexDirection: 'column', paddingHorizontal: 5 }}>
202
- <View ref={redTargetRef} style={{ height: 20, width: 20, backgroundColor: 'red', padding: 5 }} />
203
- <View ref={greenTargetRef} style={{ height: 20, width: 20, backgroundColor: 'green', padding: 5 }} />
204
- <View ref={blueTargetRef} style={{ height: 20, width: 20, backgroundColor: 'blue', padding: 5 }} />
284
+ <Pressable
285
+ onHoverIn={() => updateCalloutTargetsHoverState(true, redTargetRef)}
286
+ onHoverOut={() => updateCalloutTargetsHoverState(false, redTargetRef)}
287
+ >
288
+ <View ref={redTargetRef} style={{ height: 40, width: 40, backgroundColor: 'red', padding: 5 }}>
289
+ {anchorRefsInfo.isCurrentAnchor[0] && <Text>{anchorRefsInfo.hoverCount}</Text>}
290
+ </View>
291
+ </Pressable>
292
+ <Pressable
293
+ onHoverIn={() => updateCalloutTargetsHoverState(true, greenTargetRef)}
294
+ onHoverOut={() => updateCalloutTargetsHoverState(false, greenTargetRef)}
295
+ >
296
+ <View ref={greenTargetRef} style={{ height: 40, width: 40, backgroundColor: 'green', padding: 5 }}>
297
+ {anchorRefsInfo.isCurrentAnchor[1] && <Text>{anchorRefsInfo.hoverCount}</Text>}
298
+ </View>
299
+ </Pressable>
300
+ <Pressable
301
+ onHoverIn={() => updateCalloutTargetsHoverState(true, blueTargetRef)}
302
+ onHoverOut={() => updateCalloutTargetsHoverState(false, blueTargetRef)}
303
+ >
304
+ <View ref={blueTargetRef} style={{ height: 40, width: 40, backgroundColor: 'blue', padding: 5 }}>
305
+ {anchorRefsInfo.isCurrentAnchor[2] && <Text style={{ color: 'white' }}>{anchorRefsInfo.hoverCount}</Text>}
306
+ </View>
307
+ </Pressable>
205
308
  </View>
206
309
  </View>
207
310
 
@@ -215,6 +318,7 @@ const StandardCallout: React.FunctionComponent = () => {
215
318
  {showStandardCallout && (
216
319
  <Callout
217
320
  {...{
321
+ doNotTakePointerCapture: openCalloutOnHoverAnchor ?? undefined,
218
322
  target: anchorRef,
219
323
  onDismiss: onDismissStandardCallout,
220
324
  onShow: onShowStandardCallout,
@@ -228,23 +332,25 @@ const StandardCallout: React.FunctionComponent = () => {
228
332
  ...(calloutDismissBehaviors && { dismissBehaviors: calloutDismissBehaviors }),
229
333
  }}
230
334
  >
231
- {showScrollViewCallout ? (
232
- <View style={fluentTesterStyles.scrollViewContainer}>
233
- <ScrollView contentContainerStyle={fluentTesterStyles.scrollViewStyle} showsVerticalScrollIndicator={true}>
234
- <StealthButton content="click to change anchor" onClick={toggleCalloutRef} />
235
- <StealthButton content="Click to add a button" style={fluentTesterStyles.testListItem} onClick={addButton} />
236
- <StealthButton content="Click to remove a button" style={fluentTesterStyles.testListItem} onClick={removeButton} />
237
- {scrollviewContents.map((value) => {
238
- return <StealthButton key={value} content="Button" style={fluentTesterStyles.testListItem} />;
239
- })}
240
- </ScrollView>
241
- </View>
242
- ) : (
243
- //else
244
- <View style={{ padding: 20 }}>
245
- <Button content="click to change anchor" onClick={toggleCalloutRef} />
246
- </View>
247
- )}
335
+ <Pressable onHoverIn={() => calloutHoveredCallback(true)} onHoverOut={() => calloutHoveredCallback(false)}>
336
+ {showScrollViewCallout ? (
337
+ <View style={fluentTesterStyles.scrollViewContainer}>
338
+ <ScrollView contentContainerStyle={fluentTesterStyles.scrollViewStyle} showsVerticalScrollIndicator={true}>
339
+ <StealthButton content="click to change anchor" onClick={toggleCalloutRef} />
340
+ <StealthButton content="Click to add a button" style={fluentTesterStyles.testListItem} onClick={addButton} />
341
+ <StealthButton content="Click to remove a button" style={fluentTesterStyles.testListItem} onClick={removeButton} />
342
+ {scrollviewContents.map((value) => {
343
+ return <StealthButton key={value} content="Button" style={fluentTesterStyles.testListItem} />;
344
+ })}
345
+ </ScrollView>
346
+ </View>
347
+ ) : (
348
+ //else
349
+ <View style={[{ padding: 20 }, { backgroundColor: calloutHovered ? 'lightgreen' : 'pink' }]}>
350
+ <Button content="click to change anchor" onClick={toggleCalloutRef} />
351
+ </View>
352
+ )}
353
+ </Pressable>
248
354
  </Callout>
249
355
  )}
250
356
  </View>