@fluentui-react-native/menu 0.13.1 → 0.14.2
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/CHANGELOG.json +58 -1
- package/CHANGELOG.md +28 -2
- package/SPEC.md +345 -0
- package/jest.config.js +2 -0
- package/lib/Menu/useMenu.js +1 -1
- package/lib/Menu/useMenu.js.map +1 -1
- package/lib/MenuList/MenuList.types.d.ts.map +1 -1
- package/lib/MenuPopover/useMenuPopover.d.ts.map +1 -1
- package/lib/MenuPopover/useMenuPopover.js +2 -1
- package/lib/MenuPopover/useMenuPopover.js.map +1 -1
- package/lib/MenuTrigger/MenuTrigger.d.ts +2 -2
- package/lib/MenuTrigger/MenuTrigger.d.ts.map +1 -1
- package/lib/MenuTrigger/MenuTrigger.js +9 -9
- package/lib/MenuTrigger/MenuTrigger.js.map +1 -1
- package/lib/MenuTrigger/MenuTrigger.types.d.ts +2 -2
- package/lib/MenuTrigger/MenuTrigger.types.d.ts.map +1 -1
- package/lib/MenuTrigger/useMenuTrigger.d.ts +2 -2
- package/lib/MenuTrigger/useMenuTrigger.d.ts.map +1 -1
- package/lib/MenuTrigger/useMenuTrigger.js +4 -2
- package/lib/MenuTrigger/useMenuTrigger.js.map +1 -1
- package/lib/__tests__/Menu.test.d.ts +2 -0
- package/lib/__tests__/Menu.test.d.ts.map +1 -0
- package/lib/__tests__/Menu.test.js +145 -0
- package/lib/__tests__/Menu.test.js.map +1 -0
- package/lib-commonjs/Menu/useMenu.js +1 -1
- package/lib-commonjs/Menu/useMenu.js.map +1 -1
- package/lib-commonjs/MenuList/MenuList.types.d.ts.map +1 -1
- package/lib-commonjs/MenuPopover/useMenuPopover.d.ts.map +1 -1
- package/lib-commonjs/MenuPopover/useMenuPopover.js +2 -1
- package/lib-commonjs/MenuPopover/useMenuPopover.js.map +1 -1
- package/lib-commonjs/MenuTrigger/MenuTrigger.d.ts +2 -2
- package/lib-commonjs/MenuTrigger/MenuTrigger.d.ts.map +1 -1
- package/lib-commonjs/MenuTrigger/MenuTrigger.js +9 -9
- package/lib-commonjs/MenuTrigger/MenuTrigger.js.map +1 -1
- package/lib-commonjs/MenuTrigger/MenuTrigger.types.d.ts +2 -2
- package/lib-commonjs/MenuTrigger/MenuTrigger.types.d.ts.map +1 -1
- package/lib-commonjs/MenuTrigger/useMenuTrigger.d.ts +2 -2
- package/lib-commonjs/MenuTrigger/useMenuTrigger.d.ts.map +1 -1
- package/lib-commonjs/MenuTrigger/useMenuTrigger.js +4 -2
- package/lib-commonjs/MenuTrigger/useMenuTrigger.js.map +1 -1
- package/lib-commonjs/__tests__/Menu.test.d.ts +2 -0
- package/lib-commonjs/__tests__/Menu.test.d.ts.map +1 -0
- package/lib-commonjs/__tests__/Menu.test.js +148 -0
- package/lib-commonjs/__tests__/Menu.test.js.map +1 -0
- package/package.json +5 -3
- package/src/Menu/useMenu.ts +1 -1
- package/src/MenuList/MenuList.types.ts +1 -0
- package/src/MenuPopover/useMenuPopover.ts +3 -1
- package/src/MenuTrigger/MenuTrigger.tsx +11 -11
- package/src/MenuTrigger/MenuTrigger.types.ts +2 -2
- package/src/MenuTrigger/useMenuTrigger.ts +5 -3
- package/src/__tests__/Menu.test.tsx +235 -0
- package/src/__tests__/__snapshots__/Menu.test.tsx.snap +2098 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { memoize, stagedComponent } from '@fluentui-react-native/framework';
|
|
3
|
-
import { menuTriggerName,
|
|
3
|
+
import { menuTriggerName, MenuTriggerChildProps, MenuTriggerState } from './MenuTrigger.types';
|
|
4
4
|
import { useMenuTrigger } from './useMenuTrigger';
|
|
5
5
|
import { AccessibilityActionEvent } from 'react-native';
|
|
6
6
|
import { MenuTriggerProvider } from '../context/menuTriggerContext';
|
|
7
7
|
|
|
8
|
-
export const MenuTrigger = stagedComponent((
|
|
9
|
-
const menuTrigger = useMenuTrigger(
|
|
8
|
+
export const MenuTrigger = stagedComponent((_props: React.PropsWithChildren<Record<never, any>>) => {
|
|
9
|
+
const menuTrigger = useMenuTrigger();
|
|
10
10
|
|
|
11
|
-
return (_rest:
|
|
11
|
+
return (_rest: React.PropsWithChildren<Record<never, any>>, children: React.ReactNode) => {
|
|
12
12
|
const childrenArray = React.Children.toArray(children) as React.ReactElement[];
|
|
13
13
|
|
|
14
14
|
if (__DEV__) {
|
|
@@ -21,7 +21,7 @@ export const MenuTrigger = stagedComponent((props: MenuTriggerProps) => {
|
|
|
21
21
|
// child component which may affect accessibility, we need to modify the
|
|
22
22
|
// state in the inner render so we can access the child component and its props.
|
|
23
23
|
const child = childrenArray[0];
|
|
24
|
-
const revisedProps =
|
|
24
|
+
const revisedProps = getRevisedProps(menuTrigger, child.props);
|
|
25
25
|
const revised = React.cloneElement(child, revisedProps);
|
|
26
26
|
|
|
27
27
|
return <MenuTriggerProvider value={menuTrigger.hasSubmenu}>{revised}</MenuTriggerProvider>;
|
|
@@ -29,20 +29,20 @@ export const MenuTrigger = stagedComponent((props: MenuTriggerProps) => {
|
|
|
29
29
|
});
|
|
30
30
|
MenuTrigger.displayName = menuTriggerName;
|
|
31
31
|
|
|
32
|
-
const
|
|
33
|
-
function
|
|
34
|
-
const revisedProps =
|
|
32
|
+
const getRevisedProps = memoize(getRevisedPropsWorker);
|
|
33
|
+
function getRevisedPropsWorker(state: MenuTriggerState, props: any): MenuTriggerChildProps {
|
|
34
|
+
const revisedProps = state.props;
|
|
35
35
|
if (props.accessibilityState) {
|
|
36
|
-
revisedProps.accessibilityState = { ...
|
|
36
|
+
revisedProps.accessibilityState = { ...revisedProps.accessibilityState, ...props.accessibilityState };
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
if (props.accessibilityActions) {
|
|
40
|
-
revisedProps.accessibilityActions = { ...
|
|
40
|
+
revisedProps.accessibilityActions = { ...revisedProps.accessibilityActions, ...props.accessibilityActions };
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
if (props.onAccessibilityAction) {
|
|
44
44
|
revisedProps.onAccessibilityAction = (e: AccessibilityActionEvent) => {
|
|
45
|
-
|
|
45
|
+
revisedProps.onAccessibilityAction(e);
|
|
46
46
|
props.onAccessibilityAction(e);
|
|
47
47
|
};
|
|
48
48
|
}
|
|
@@ -3,7 +3,7 @@ import { ViewProps } from 'react-native';
|
|
|
3
3
|
|
|
4
4
|
export const menuTriggerName = 'MenuTrigger';
|
|
5
5
|
|
|
6
|
-
export interface
|
|
6
|
+
export interface MenuTriggerChildProps extends Omit<IWithPressableOptions<ViewProps>, 'onPress'> {
|
|
7
7
|
/**
|
|
8
8
|
* A RefObject to refer to the trigger component.
|
|
9
9
|
*/
|
|
@@ -16,6 +16,6 @@ export interface MenuTriggerProps extends Omit<IWithPressableOptions<ViewProps>,
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export interface MenuTriggerState {
|
|
19
|
-
props:
|
|
19
|
+
props: MenuTriggerChildProps;
|
|
20
20
|
hasSubmenu: boolean;
|
|
21
21
|
}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { useMenuContext } from '../context/menuContext';
|
|
2
2
|
import { InteractionEvent } from '@fluentui-react-native/interactive-hooks';
|
|
3
|
-
import {
|
|
3
|
+
import { MenuTriggerState } from './MenuTrigger.types';
|
|
4
4
|
import { AccessibilityActionEvent, AccessibilityActionName, Platform } from 'react-native';
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import { delayHover, isCloseOnHoverOutEnabled } from '../consts';
|
|
7
7
|
|
|
8
8
|
const accessibilityActions =
|
|
9
9
|
Platform.OS === ('win32' as any) ? [{ name: 'Expand' as AccessibilityActionName }, { name: 'Collapse' as AccessibilityActionName }] : [];
|
|
10
|
+
const expandedState = { expanded: true };
|
|
11
|
+
const collapsedState = { expanded: false };
|
|
10
12
|
|
|
11
|
-
export const useMenuTrigger = (
|
|
13
|
+
export const useMenuTrigger = (): MenuTriggerState => {
|
|
12
14
|
const context = useMenuContext();
|
|
13
15
|
const { open, openOnHover, popoverHoverOutTimer, setOpen, setTriggerHoverOutTimer, triggerHoverOutTimer, triggerRef } = context;
|
|
14
16
|
|
|
15
|
-
const accessibilityState = open ?
|
|
17
|
+
const accessibilityState = open ? expandedState : collapsedState;
|
|
16
18
|
|
|
17
19
|
const onAccessibilityAction = React.useCallback(
|
|
18
20
|
(e: AccessibilityActionEvent) => {
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { AccessibilityActionName } from 'react-native';
|
|
3
|
+
import * as renderer from 'react-test-renderer';
|
|
4
|
+
import { Menu } from '../Menu/Menu';
|
|
5
|
+
import { checkReRender } from '@fluentui-react-native/test-tools';
|
|
6
|
+
import MenuTrigger from '../MenuTrigger/MenuTrigger';
|
|
7
|
+
import { ButtonV1 as Button } from '@fluentui-react-native/button';
|
|
8
|
+
import MenuPopover from '../MenuPopover/MenuPopover';
|
|
9
|
+
import { MenuList } from '../MenuList/MenuList';
|
|
10
|
+
import { MenuItem } from '../MenuItem/MenuItem';
|
|
11
|
+
import { MenuItemCheckbox } from '../MenuItemCheckbox/MenuItemCheckbox';
|
|
12
|
+
import { MenuDivider } from '../MenuDivider/MenuDivider';
|
|
13
|
+
import { MenuItemRadio } from '../MenuItemRadio/MenuItemRadio';
|
|
14
|
+
|
|
15
|
+
describe('Checkbox component tests', () => {
|
|
16
|
+
it('Menu default', () => {
|
|
17
|
+
const tree = renderer
|
|
18
|
+
.create(
|
|
19
|
+
<Menu>
|
|
20
|
+
<MenuTrigger>
|
|
21
|
+
<Button>Default</Button>
|
|
22
|
+
</MenuTrigger>
|
|
23
|
+
<MenuPopover>
|
|
24
|
+
<MenuList>
|
|
25
|
+
<MenuItem content="Option 1" />
|
|
26
|
+
</MenuList>
|
|
27
|
+
</MenuPopover>
|
|
28
|
+
</Menu>,
|
|
29
|
+
)
|
|
30
|
+
.toJSON();
|
|
31
|
+
expect(tree).toMatchSnapshot();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('Menu open', () => {
|
|
35
|
+
const tree = renderer
|
|
36
|
+
.create(
|
|
37
|
+
<Menu open>
|
|
38
|
+
<MenuTrigger>
|
|
39
|
+
<Button>Open</Button>
|
|
40
|
+
</MenuTrigger>
|
|
41
|
+
<MenuPopover>
|
|
42
|
+
<MenuList>
|
|
43
|
+
<MenuItem content="Option 1" />
|
|
44
|
+
</MenuList>
|
|
45
|
+
</MenuPopover>
|
|
46
|
+
</Menu>,
|
|
47
|
+
)
|
|
48
|
+
.toJSON();
|
|
49
|
+
expect(tree).toMatchSnapshot();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('Menu defaultOpen', () => {
|
|
53
|
+
const tree = renderer
|
|
54
|
+
.create(
|
|
55
|
+
<Menu defaultOpen>
|
|
56
|
+
<MenuTrigger>
|
|
57
|
+
<Button>Open</Button>
|
|
58
|
+
</MenuTrigger>
|
|
59
|
+
<MenuPopover>
|
|
60
|
+
<MenuList>
|
|
61
|
+
<MenuItem content="Option 1" />
|
|
62
|
+
<MenuItem disabled content="Option 2" />
|
|
63
|
+
</MenuList>
|
|
64
|
+
</MenuPopover>
|
|
65
|
+
</Menu>,
|
|
66
|
+
)
|
|
67
|
+
.toJSON();
|
|
68
|
+
expect(tree).toMatchSnapshot();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('Menu open checkbox and divider', () => {
|
|
72
|
+
const tree = renderer
|
|
73
|
+
.create(
|
|
74
|
+
<Menu open>
|
|
75
|
+
<MenuTrigger>
|
|
76
|
+
<Button>Open</Button>
|
|
77
|
+
</MenuTrigger>
|
|
78
|
+
<MenuPopover>
|
|
79
|
+
<MenuList>
|
|
80
|
+
<MenuItemCheckbox content="Option 1" name="Option 1" />
|
|
81
|
+
<MenuDivider />
|
|
82
|
+
<MenuItemCheckbox disabled content="Option 2" name="Option 2" />
|
|
83
|
+
</MenuList>
|
|
84
|
+
</MenuPopover>
|
|
85
|
+
</Menu>,
|
|
86
|
+
)
|
|
87
|
+
.toJSON();
|
|
88
|
+
expect(tree).toMatchSnapshot();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('Menu open radio', () => {
|
|
92
|
+
const tree = renderer
|
|
93
|
+
.create(
|
|
94
|
+
<Menu open>
|
|
95
|
+
<MenuTrigger>
|
|
96
|
+
<Button>Open</Button>
|
|
97
|
+
</MenuTrigger>
|
|
98
|
+
<MenuPopover>
|
|
99
|
+
<MenuList>
|
|
100
|
+
<MenuItemRadio content="Option 1" name="Option 1" />
|
|
101
|
+
<MenuItemRadio content="Option 2" name="Option 2" />
|
|
102
|
+
</MenuList>
|
|
103
|
+
</MenuPopover>
|
|
104
|
+
</Menu>,
|
|
105
|
+
)
|
|
106
|
+
.toJSON();
|
|
107
|
+
expect(tree).toMatchSnapshot();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('Menu open checkbox defaultChecked', () => {
|
|
111
|
+
const tree = renderer
|
|
112
|
+
.create(
|
|
113
|
+
<Menu open defaultChecked={{ 'Option 1': true }}>
|
|
114
|
+
<MenuTrigger>
|
|
115
|
+
<Button>Open</Button>
|
|
116
|
+
</MenuTrigger>
|
|
117
|
+
<MenuPopover>
|
|
118
|
+
<MenuList>
|
|
119
|
+
<MenuItemCheckbox content="Option 1" name="Option 1" />
|
|
120
|
+
<MenuDivider />
|
|
121
|
+
<MenuItemCheckbox content="Option 2" name="Option 2" />
|
|
122
|
+
</MenuList>
|
|
123
|
+
</MenuPopover>
|
|
124
|
+
</Menu>,
|
|
125
|
+
)
|
|
126
|
+
.toJSON();
|
|
127
|
+
expect(tree).toMatchSnapshot();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('Menu open checkbox checked', () => {
|
|
131
|
+
const tree = renderer
|
|
132
|
+
.create(
|
|
133
|
+
<Menu open checked={{ 'Option 1': true }}>
|
|
134
|
+
<MenuTrigger>
|
|
135
|
+
<Button>Open</Button>
|
|
136
|
+
</MenuTrigger>
|
|
137
|
+
<MenuPopover>
|
|
138
|
+
<MenuList>
|
|
139
|
+
<MenuItemCheckbox content="Option 1" name="Option 1" />
|
|
140
|
+
<MenuDivider />
|
|
141
|
+
<MenuItemCheckbox content="Option 2" name="Option 2" />
|
|
142
|
+
</MenuList>
|
|
143
|
+
</MenuPopover>
|
|
144
|
+
</Menu>,
|
|
145
|
+
)
|
|
146
|
+
.toJSON();
|
|
147
|
+
expect(tree).toMatchSnapshot();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('Menu submenu', () => {
|
|
151
|
+
const tree = renderer
|
|
152
|
+
.create(
|
|
153
|
+
<Menu open>
|
|
154
|
+
<MenuTrigger>
|
|
155
|
+
<Button>Default</Button>
|
|
156
|
+
</MenuTrigger>
|
|
157
|
+
<MenuPopover>
|
|
158
|
+
<MenuList>
|
|
159
|
+
<MenuItem content="Option 1" />
|
|
160
|
+
<Menu>
|
|
161
|
+
<MenuTrigger>
|
|
162
|
+
<MenuItem content="Option 2" />
|
|
163
|
+
</MenuTrigger>
|
|
164
|
+
<MenuPopover>
|
|
165
|
+
<MenuList>
|
|
166
|
+
<MenuItem content="Option 1" />
|
|
167
|
+
</MenuList>
|
|
168
|
+
</MenuPopover>
|
|
169
|
+
</Menu>
|
|
170
|
+
</MenuList>
|
|
171
|
+
</MenuPopover>
|
|
172
|
+
</Menu>,
|
|
173
|
+
)
|
|
174
|
+
.toJSON();
|
|
175
|
+
expect(tree).toMatchSnapshot();
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe('Menu rerender tests', () => {
|
|
180
|
+
it('Menu re-renders correctly', () => {
|
|
181
|
+
checkReRender(
|
|
182
|
+
() => (
|
|
183
|
+
<Menu open>
|
|
184
|
+
<MenuTrigger>
|
|
185
|
+
<Button>Rerender twice</Button>
|
|
186
|
+
</MenuTrigger>
|
|
187
|
+
<MenuPopover>
|
|
188
|
+
<MenuList>
|
|
189
|
+
<MenuItem content="Option 1" />
|
|
190
|
+
</MenuList>
|
|
191
|
+
</MenuPopover>
|
|
192
|
+
</Menu>
|
|
193
|
+
),
|
|
194
|
+
3,
|
|
195
|
+
);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('Menu re-renders correctly with style', () => {
|
|
199
|
+
const style = { backgroundColor: 'black' };
|
|
200
|
+
checkReRender(
|
|
201
|
+
() => (
|
|
202
|
+
<Menu>
|
|
203
|
+
<MenuTrigger>
|
|
204
|
+
<Button style={style}>Rerender twice</Button>
|
|
205
|
+
</MenuTrigger>
|
|
206
|
+
<MenuPopover>
|
|
207
|
+
<MenuList>
|
|
208
|
+
<MenuItem content="Option 1" />
|
|
209
|
+
</MenuList>
|
|
210
|
+
</MenuPopover>
|
|
211
|
+
</Menu>
|
|
212
|
+
),
|
|
213
|
+
3,
|
|
214
|
+
);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('Menu re-renders correctly with accessibilityAction', () => {
|
|
218
|
+
const action = [{ name: 'Expand' as AccessibilityActionName }];
|
|
219
|
+
checkReRender(
|
|
220
|
+
() => (
|
|
221
|
+
<Menu>
|
|
222
|
+
<MenuTrigger>
|
|
223
|
+
<Button>Rerender twice</Button>
|
|
224
|
+
</MenuTrigger>
|
|
225
|
+
<MenuPopover>
|
|
226
|
+
<MenuList>
|
|
227
|
+
<MenuItem accessibilityActions={action} content="Option 1" />
|
|
228
|
+
</MenuList>
|
|
229
|
+
</MenuPopover>
|
|
230
|
+
</Menu>
|
|
231
|
+
),
|
|
232
|
+
3,
|
|
233
|
+
);
|
|
234
|
+
});
|
|
235
|
+
});
|