@jetshop/ui 5.12.0 → 5.12.3
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/Image/B2BImage.d.ts +2 -2
- package/Image/B2BImage.js.map +1 -1
- package/Modal/Drawer/DrawerTarget.d.ts +1 -1
- package/Modal/Drawer/DrawerTarget.js +3 -3
- package/Modal/Drawer/DrawerTarget.js.map +1 -1
- package/Modal/Drawer/DrawerTarget.test.js +25 -45
- package/Modal/Drawer/DrawerTrigger.d.ts +2 -0
- package/Modal/Drawer/DrawerTrigger.js +8 -4
- package/Modal/Drawer/DrawerTrigger.js.map +1 -1
- package/Modal/Flyout/FlyoutTarget.d.ts +1 -1
- package/Modal/Flyout/FlyoutTarget.js +5 -3
- package/Modal/Flyout/FlyoutTarget.js.map +1 -1
- package/Modal/Flyout/FlyoutTarget.test.js +15 -26
- package/Modal/Flyout/FlyoutTrigger.d.ts +2 -0
- package/Modal/Flyout/FlyoutTrigger.js +5 -4
- package/Modal/Flyout/FlyoutTrigger.js.map +1 -1
- package/Modal/ModalContext.d.ts +9 -2
- package/Modal/ModalContext.js +1 -5
- package/Modal/ModalContext.js.map +1 -1
- package/Modal/ModalProvider.d.ts +4 -10
- package/Modal/ModalProvider.js +77 -32
- package/Modal/ModalProvider.js.map +1 -1
- package/Modal/ModalProvider.test.js +0 -3
- package/Modal/ModalRoot.d.ts +2 -2
- package/Modal/ModalRoot.js +9 -4
- package/Modal/ModalRoot.js.map +1 -1
- package/Modal/ModalRoot.test.js +36 -7
- package/Modal/__test_utils__/getComponentWithModalContext.js +2 -6
- package/ScrollRestorationHandler/useScrollRestore.js +5 -0
- package/ScrollRestorationHandler/useScrollRestore.js.map +1 -1
- package/package.json +1 -1
- package/Modal/TargetWrapper.d.ts +0 -31
- package/Modal/TargetWrapper.js +0 -45
- package/Modal/TargetWrapper.js.map +0 -1
- package/Modal/TargetWrapper.test.js +0 -81
package/Image/B2BImage.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { PropsWithChildren } from 'react';
|
|
2
2
|
import { ProductImageSize } from '@jetshop/core/types';
|
|
3
3
|
export declare type ImageSrcType = string | ProductImageSize[];
|
|
4
4
|
export declare type BreakpointValues = string[];
|
|
@@ -46,5 +46,5 @@ interface ImageProps extends ImageParameters {
|
|
|
46
46
|
className?: string;
|
|
47
47
|
badges?: React.ReactElement<any>;
|
|
48
48
|
}
|
|
49
|
-
declare function B2BImage(props: ImageProps): JSX.Element;
|
|
49
|
+
declare function B2BImage(props: PropsWithChildren<ImageProps>): JSX.Element;
|
|
50
50
|
export default B2BImage;
|
package/Image/B2BImage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"B2BImage.js","sourceRoot":"","sources":["B2BImage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,aAAa,CAAC;AAChC,OAAO,
|
|
1
|
+
{"version":3,"file":"B2BImage.js","sourceRoot":"","sources":["B2BImage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,aAAa,CAAC;AAChC,OAAO,KAA4B,MAAM,OAAO,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAUxD,MAAM,CAAC,MAAM,kBAAkB,GAC7B,oHAAoH,CAAC;AA4CvH,SAAS,KAAK;IACZ,OAAO,CACL,6BACE,KAAK,EAAE;YACL,UAAU,EAAE,SAAS;YACrB,OAAO,EAAE,MAAM;YACf,cAAc,EAAE,QAAQ;YACxB,UAAU,EAAE,QAAQ;YACpB,QAAQ,EAAE,UAAU;YACpB,GAAG,EAAE,CAAC;YACN,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,MAAM;SACf,sBAGG,CACP,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,KAAoC;IACpD,MAAM,EACJ,OAAO,EACP,IAAI,EACJ,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC,EACvB,MAAM,EACN,OAAO,EACP,QAAQ,EACR,YAAY,EACb,GAAG,KAAK,CAAC;IAEV,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,GACzD,iBAAiB,CAAC;QAChB,OAAO;QACP,IAAI;QACJ,GAAG,EAAE,WAAW;QAChB,KAAK,EAAE,UAAU;QACjB,MAAM;QACN,OAAO;QACP,QAAQ;QACR,YAAY;QACZ,WAAW,EAAE;YACX,EAAE,EAAE,OAAO;YACX,EAAE,EAAE,OAAO;YACX,EAAE,EAAE,OAAO;YACX,EAAE,EAAE,OAAO;YACX,EAAE,EAAE,OAAO;SACZ;QACD,OAAO,EAAE,EAAE;KACZ,CAAC,CAAC;IAEL,OAAO,CACL,oBAAC,KAAK,oBACA,KAAK,IACT,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,KAAK,IACZ,CACH,CAAC;AACJ,CAAC;AAED,eAAe,QAAQ,CAAC"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import ModalContext from '../ModalContext';
|
|
3
|
-
import TargetWrapper from '../TargetWrapper';
|
|
4
3
|
export const DrawerTarget = ({ id, children }) => {
|
|
5
|
-
return (React.createElement(ModalContext.Consumer, null, ({
|
|
4
|
+
return (React.createElement(ModalContext.Consumer, null, ({ modals, hideTarget }) => {
|
|
5
|
+
const { modalId, isOpen } = modals.find(({ modalId }) => modalId === id) || {};
|
|
6
6
|
// For drawers, the child should always render.
|
|
7
7
|
// Drawers implement their own hide/show behaviour that relies
|
|
8
8
|
// on `isOpen` being toggled to trigger the animation
|
|
9
|
-
return (
|
|
9
|
+
return children({ hideTarget, isOpen: isOpen && modalId === id });
|
|
10
10
|
}));
|
|
11
11
|
};
|
|
12
12
|
//# sourceMappingURL=DrawerTarget.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DrawerTarget.js","sourceRoot":"","sources":["DrawerTarget.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,YAA4B,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"DrawerTarget.js","sourceRoot":"","sources":["DrawerTarget.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,YAA4B,MAAM,iBAAiB,CAAC;AAE3D,MAAM,CAAC,MAAM,YAAY,GAGpB,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;IACxB,OAAO,CACL,oBAAC,YAAY,CAAC,QAAQ,QACnB,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE;QAC1B,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GACvB,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;QACrD,+CAA+C;QAC/C,8DAA8D;QAC9D,qDAAqD;QACrD,OAAO,QAAQ,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC,CAAC;IACpE,CAAC,CACqB,CACzB,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -24,54 +24,44 @@ xdescribe('DrawerTarget', () => {
|
|
|
24
24
|
it('no matter what the context state is', () => {
|
|
25
25
|
const DrawerTarget = target({
|
|
26
26
|
...defaultContext,
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
modals: [
|
|
28
|
+
{
|
|
29
|
+
modalType: 'drawer',
|
|
30
|
+
isOpen: false
|
|
31
|
+
}
|
|
32
|
+
]
|
|
29
33
|
});
|
|
30
34
|
wrapper = mount(<DrawerTarget>{reachableChild}</DrawerTarget>);
|
|
31
35
|
});
|
|
32
36
|
|
|
33
37
|
it('with `isOpen` prop passed', () => {
|
|
34
38
|
expect(
|
|
35
|
-
wrapper
|
|
36
|
-
.children()
|
|
37
|
-
.children()
|
|
38
|
-
.props().isOpen
|
|
39
|
+
wrapper.children().children().props().modals[0].isOpen
|
|
39
40
|
).toBeDefined();
|
|
40
41
|
});
|
|
41
42
|
|
|
42
43
|
it('with `modalType` prop passed', () => {
|
|
43
|
-
expect(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
.children()
|
|
47
|
-
.props().modalType
|
|
48
|
-
).toBe('drawer');
|
|
44
|
+
expect(wrapper.children().children().props().modals[0].modalType).toBe(
|
|
45
|
+
'drawer'
|
|
46
|
+
);
|
|
49
47
|
});
|
|
50
48
|
|
|
51
49
|
it('with `hideTarget` func passed', () => {
|
|
52
|
-
expect(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
.children()
|
|
56
|
-
.props().hideTarget
|
|
57
|
-
).toBe(defaultContext.hideTarget);
|
|
50
|
+
expect(wrapper.children().children().props().hideTarget).toBe(
|
|
51
|
+
defaultContext.hideTarget
|
|
52
|
+
);
|
|
58
53
|
});
|
|
59
54
|
|
|
60
55
|
describe('with `isOpen` prop set to `true`', () => {
|
|
61
56
|
it('when `isOpen` is true and `modalId` matches `id`', () => {
|
|
62
57
|
const DrawerTarget = target({
|
|
63
58
|
...defaultContext,
|
|
64
|
-
modalType: 'drawer',
|
|
65
|
-
isOpen: true,
|
|
66
|
-
modalId: 'foo'
|
|
59
|
+
modals: [{ modalType: 'drawer', isOpen: true, modalId: 'foo' }]
|
|
67
60
|
});
|
|
68
61
|
wrapper = mount(<DrawerTarget id="foo">{reachableChild}</DrawerTarget>);
|
|
69
|
-
expect(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
.children()
|
|
73
|
-
.props().isOpen
|
|
74
|
-
).toBe(true);
|
|
62
|
+
expect(wrapper.children().children().props().modals[0].isOpen).toBe(
|
|
63
|
+
true
|
|
64
|
+
);
|
|
75
65
|
});
|
|
76
66
|
});
|
|
77
67
|
|
|
@@ -79,33 +69,23 @@ xdescribe('DrawerTarget', () => {
|
|
|
79
69
|
it('when `isOpen` is false', () => {
|
|
80
70
|
const DrawerTarget = target({
|
|
81
71
|
...defaultContext,
|
|
82
|
-
modalType: 'drawer',
|
|
83
|
-
isOpen: false,
|
|
84
|
-
modalId: 'foo'
|
|
72
|
+
modals: [{ modalType: 'drawer', isOpen: false, modalId: 'foo' }]
|
|
85
73
|
});
|
|
86
74
|
wrapper = mount(<DrawerTarget id="foo">{reachableChild}</DrawerTarget>);
|
|
87
|
-
expect(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.children()
|
|
91
|
-
.props().isOpen
|
|
92
|
-
).toBe(false);
|
|
75
|
+
expect(wrapper.children().children().props().modals[0].isOpen).toBe(
|
|
76
|
+
false
|
|
77
|
+
);
|
|
93
78
|
});
|
|
94
79
|
|
|
95
80
|
it('when received `modalId` does not match `id` prop', () => {
|
|
96
81
|
const DrawerTarget = target({
|
|
97
82
|
...defaultContext,
|
|
98
|
-
modalType: 'drawer',
|
|
99
|
-
isOpen: true,
|
|
100
|
-
modalId: 'bar'
|
|
83
|
+
modals: [{ modalType: 'drawer', isOpen: true, modalId: 'bar' }]
|
|
101
84
|
});
|
|
102
85
|
wrapper = mount(<DrawerTarget id="foo">{reachableChild}</DrawerTarget>);
|
|
103
|
-
expect(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
.children()
|
|
107
|
-
.props().isOpen
|
|
108
|
-
).toBe(false);
|
|
86
|
+
expect(wrapper.children().children().props().modals[0].isOpen).toBe(
|
|
87
|
+
false
|
|
88
|
+
);
|
|
109
89
|
});
|
|
110
90
|
});
|
|
111
91
|
});
|
|
@@ -4,6 +4,8 @@ export declare const DrawerTrigger: React.SFC<{
|
|
|
4
4
|
id: string;
|
|
5
5
|
/** Whether to show a clickable semi-opaque Cover behind the flyout */
|
|
6
6
|
showCover: boolean;
|
|
7
|
+
/** Whether to prevent the body from scrolling when flyout is open */
|
|
8
|
+
canCloseOnEsc?: boolean;
|
|
7
9
|
coverStyles?: {};
|
|
8
10
|
children: (args: Partial<ModalState>) => React.ReactNode;
|
|
9
11
|
}>;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import ModalContext from '../ModalContext';
|
|
3
|
-
export const DrawerTrigger = ({ id, children, showCover = true, coverStyles }) => {
|
|
4
|
-
return (React.createElement(ModalContext.Consumer, null, ({ showTarget,
|
|
3
|
+
export const DrawerTrigger = ({ id, children, showCover = true, canCloseOnEsc = true, coverStyles }) => {
|
|
4
|
+
return (React.createElement(ModalContext.Consumer, null, ({ showTarget, hideTarget, modals }) => {
|
|
5
5
|
return children({
|
|
6
|
-
showTarget: () => showTarget(null, 'drawer', id, {
|
|
6
|
+
showTarget: () => showTarget(null, 'drawer', id, {
|
|
7
|
+
showCover,
|
|
8
|
+
coverStyles,
|
|
9
|
+
canCloseOnEsc
|
|
10
|
+
}),
|
|
7
11
|
hideTarget,
|
|
8
|
-
isOpen: modalId === id
|
|
12
|
+
isOpen: modals.some(({ modalId }) => modalId === id)
|
|
9
13
|
});
|
|
10
14
|
}));
|
|
11
15
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DrawerTrigger.js","sourceRoot":"","sources":["DrawerTrigger.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,YAA4B,MAAM,iBAAiB,CAAC;AAE3D,MAAM,CAAC,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"DrawerTrigger.js","sourceRoot":"","sources":["DrawerTrigger.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,YAA4B,MAAM,iBAAiB,CAAC;AAE3D,MAAM,CAAC,MAAM,aAAa,GAQrB,CAAC,EACJ,EAAE,EACF,QAAQ,EACR,SAAS,GAAG,IAAI,EAChB,aAAa,GAAG,IAAI,EACpB,WAAW,EACZ,EAAE,EAAE;IACH,OAAO,CACL,oBAAC,YAAY,CAAC,QAAQ,QACnB,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE;QACtC,OAAO,QAAQ,CAAC;YACd,UAAU,EAAE,GAAG,EAAE,CACf,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;gBAC7B,SAAS;gBACT,WAAW;gBACX,aAAa;aACd,CAAC;YACJ,UAAU;YACV,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,KAAK,EAAE,CAAC;SACrD,CAAC,CAAC;IACL,CAAC,CACqB,CACzB,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import { ModalState } from '../ModalContext';
|
|
3
3
|
export interface FlyoutTargetProps {
|
|
4
4
|
id: string;
|
|
5
|
-
children: (args: Partial<ModalState>) =>
|
|
5
|
+
children: (args: Partial<ModalState>) => React.ReactNode;
|
|
6
6
|
}
|
|
7
7
|
export declare class FlyoutTarget extends React.Component<FlyoutTargetProps, any> {
|
|
8
8
|
render(): JSX.Element;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import ModalContext from '../ModalContext';
|
|
3
|
-
import TargetWrapper from '../TargetWrapper';
|
|
4
3
|
export class FlyoutTarget extends React.Component {
|
|
5
4
|
render() {
|
|
6
5
|
const { id, children } = this.props;
|
|
7
|
-
return (React.createElement(ModalContext.Consumer, null, ({
|
|
8
|
-
|
|
6
|
+
return (React.createElement(ModalContext.Consumer, null, ({ modals }) => {
|
|
7
|
+
const { modalId, isOpen, modalType, hideTarget } = modals.find(({ modalId }) => modalId === id) || {};
|
|
8
|
+
return isOpen && modalId === id && modalType === 'flyout'
|
|
9
|
+
? children({ hideTarget, isOpen })
|
|
10
|
+
: null;
|
|
9
11
|
}));
|
|
10
12
|
}
|
|
11
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FlyoutTarget.js","sourceRoot":"","sources":["FlyoutTarget.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,YAA4B,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"FlyoutTarget.js","sourceRoot":"","sources":["FlyoutTarget.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,YAA4B,MAAM,iBAAiB,CAAC;AAO3D,MAAM,OAAO,YAAa,SAAQ,KAAK,CAAC,SAAiC;IACvE,MAAM;QACJ,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QACpC,OAAO,CACL,oBAAC,YAAY,CAAC,QAAQ,QACnB,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE;YACd,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAC9C,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;YACrD,OAAO,MAAM,IAAI,OAAO,KAAK,EAAE,IAAI,SAAS,KAAK,QAAQ;gBACvD,CAAC,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;gBAClC,CAAC,CAAC,IAAI,CAAC;QACX,CAAC,CACqB,CACzB,CAAC;IACJ,CAAC;CACF;AAED,eAAe,YAAY,CAAC"}
|
|
@@ -28,8 +28,12 @@ xdescribe('FlyoutTarget', () => {
|
|
|
28
28
|
it('when isOpen is true but ID prop does not match modalId', () => {
|
|
29
29
|
const FlyoutTarget = target({
|
|
30
30
|
...defaultContext,
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
modals: [
|
|
32
|
+
{
|
|
33
|
+
isOpen: true,
|
|
34
|
+
modalId: 'bar'
|
|
35
|
+
}
|
|
36
|
+
]
|
|
33
37
|
});
|
|
34
38
|
wrapper = mount(<FlyoutTarget id="foo">{unreachableChild}</FlyoutTarget>);
|
|
35
39
|
});
|
|
@@ -37,9 +41,7 @@ xdescribe('FlyoutTarget', () => {
|
|
|
37
41
|
it('when isOpen is true and ID matches, but `modalType` is not `flyout`', () => {
|
|
38
42
|
const FlyoutTarget = target({
|
|
39
43
|
...defaultContext,
|
|
40
|
-
isOpen: true,
|
|
41
|
-
modalId: 'foo',
|
|
42
|
-
modalType: 'modal'
|
|
44
|
+
modals: [{ isOpen: true, modalId: 'foo', modalType: 'modal' }]
|
|
43
45
|
});
|
|
44
46
|
wrapper = mount(<FlyoutTarget id="foo">{unreachableChild}</FlyoutTarget>);
|
|
45
47
|
});
|
|
@@ -53,9 +55,7 @@ xdescribe('FlyoutTarget', () => {
|
|
|
53
55
|
beforeEach(() => {
|
|
54
56
|
FlyoutTarget = target({
|
|
55
57
|
...defaultContext,
|
|
56
|
-
isOpen: true,
|
|
57
|
-
modalId: 'foo',
|
|
58
|
-
modalType: 'flyout'
|
|
58
|
+
modals: [{ isOpen: true, modalId: 'foo', modalType: 'flyout' }]
|
|
59
59
|
});
|
|
60
60
|
});
|
|
61
61
|
|
|
@@ -68,28 +68,17 @@ xdescribe('FlyoutTarget', () => {
|
|
|
68
68
|
expect(wrapper.children().text()).toBe('Hello from the inside!');
|
|
69
69
|
});
|
|
70
70
|
it('with `isOpen` prop passed', () => {
|
|
71
|
-
expect(
|
|
72
|
-
wrapper
|
|
73
|
-
.children()
|
|
74
|
-
.children()
|
|
75
|
-
.props().isOpen
|
|
76
|
-
).toBe(true);
|
|
71
|
+
expect(wrapper.children().children().props().modals[0].isOpen).toBe(true);
|
|
77
72
|
});
|
|
78
73
|
it('with `modalType` prop passed', () => {
|
|
79
|
-
expect(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
.children()
|
|
83
|
-
.props().modalType
|
|
84
|
-
).toBe('flyout');
|
|
74
|
+
expect(wrapper.children().children().props().modals[0].modalType).toBe(
|
|
75
|
+
'flyout'
|
|
76
|
+
);
|
|
85
77
|
});
|
|
86
78
|
it('with `hideTarget` func passed', () => {
|
|
87
|
-
expect(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.children()
|
|
91
|
-
.props().hideTarget
|
|
92
|
-
).toBe(defaultContext.hideTarget);
|
|
79
|
+
expect(wrapper.children().children().props().hideTarget).toBe(
|
|
80
|
+
defaultContext.hideTarget
|
|
81
|
+
);
|
|
93
82
|
});
|
|
94
83
|
});
|
|
95
84
|
});
|
|
@@ -6,6 +6,8 @@ export declare const FlyoutTrigger: React.SFC<{
|
|
|
6
6
|
showCover?: boolean;
|
|
7
7
|
/** Whether to prevent the body from scrolling when flyout is open */
|
|
8
8
|
preventOverflow?: boolean;
|
|
9
|
+
/** Whether to able to close modal via Escape button */
|
|
10
|
+
canCloseOnEsc?: boolean;
|
|
9
11
|
coverStyles?: {};
|
|
10
12
|
children: (args: Pick<ModalState, 'hideTarget' | 'isOpen'> & {
|
|
11
13
|
showTarget: () => void;
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import ModalContext from '../ModalContext';
|
|
3
|
-
export const FlyoutTrigger = ({ id, children, showCover = true,
|
|
4
|
-
return (React.createElement(ModalContext.Consumer, null, ({ showTarget,
|
|
3
|
+
export const FlyoutTrigger = ({ id, children, showCover = true, preventOverflow = false, canCloseOnEsc = true, coverStyles }) => {
|
|
4
|
+
return (React.createElement(ModalContext.Consumer, null, ({ showTarget, hideTarget, modals }) => {
|
|
5
5
|
const open = () => showTarget(null, 'flyout', id, {
|
|
6
6
|
showCover,
|
|
7
7
|
coverStyles,
|
|
8
|
-
preventOverflow
|
|
8
|
+
preventOverflow,
|
|
9
|
+
canCloseOnEsc
|
|
9
10
|
});
|
|
10
11
|
return children({
|
|
11
12
|
showTarget: open,
|
|
12
13
|
hideTarget,
|
|
13
|
-
isOpen: modalId === id
|
|
14
|
+
isOpen: modals.some(({ modalId }) => modalId === id)
|
|
14
15
|
});
|
|
15
16
|
}));
|
|
16
17
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FlyoutTrigger.js","sourceRoot":"","sources":["FlyoutTrigger.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,YAA4B,MAAM,iBAAiB,CAAC;AAE3D,MAAM,CAAC,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"FlyoutTrigger.js","sourceRoot":"","sources":["FlyoutTrigger.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,YAA4B,MAAM,iBAAiB,CAAC;AAE3D,MAAM,CAAC,MAAM,aAAa,GAYrB,CAAC,EACJ,EAAE,EACF,QAAQ,EACR,SAAS,GAAG,IAAI,EAChB,eAAe,GAAG,KAAK,EACvB,aAAa,GAAG,IAAI,EACpB,WAAW,EACZ,EAAE,EAAE;IACH,OAAO,CACL,oBAAC,YAAY,CAAC,QAAQ,QACnB,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE;QACtC,MAAM,IAAI,GAAG,GAAG,EAAE,CAChB,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;YAC7B,SAAS;YACT,WAAW;YACX,eAAe;YACf,aAAa;SACd,CAAC,CAAC;QACL,OAAO,QAAQ,CAAC;YACd,UAAU,EAAE,IAAI;YAChB,UAAU;YACV,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,KAAK,EAAE,CAAC;SACrD,CAAC,CAAC;IACL,CAAC,CACqB,CACzB,CAAC;AACJ,CAAC,CAAC"}
|
package/Modal/ModalContext.d.ts
CHANGED
|
@@ -9,11 +9,18 @@ export interface ModalState {
|
|
|
9
9
|
/** Called when a modal is requested */
|
|
10
10
|
showTarget(...args: any[]): void;
|
|
11
11
|
/** Called when a modal is dismissed */
|
|
12
|
-
hideTarget(): void;
|
|
12
|
+
hideTarget(...args: any[]): void;
|
|
13
13
|
/** Whether a modal is open */
|
|
14
14
|
isOpen: boolean;
|
|
15
15
|
/** props to be passed on to the displayed modalComponent */
|
|
16
16
|
props?: any;
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
export interface ModalContextProps {
|
|
19
|
+
/** Called when a modal is requested */
|
|
20
|
+
showTarget(...args: any[]): void;
|
|
21
|
+
/** Called when a modal is dismissed */
|
|
22
|
+
hideTarget(...args: any[]): void;
|
|
23
|
+
modals: ModalState[];
|
|
24
|
+
}
|
|
25
|
+
declare const ModalContext: React.Context<ModalContextProps>;
|
|
19
26
|
export default ModalContext;
|
package/Modal/ModalContext.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { createContext } from 'react';
|
|
2
2
|
const initialModalState = {
|
|
3
|
-
modalComponent: null,
|
|
4
|
-
modalType: null,
|
|
5
|
-
modalId: null,
|
|
6
|
-
isOpen: false,
|
|
7
3
|
showTarget: null,
|
|
8
4
|
hideTarget: null,
|
|
9
|
-
|
|
5
|
+
modals: []
|
|
10
6
|
};
|
|
11
7
|
const ModalContext = createContext(initialModalState);
|
|
12
8
|
export default ModalContext;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModalContext.js","sourceRoot":"","sources":["ModalContext.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ModalContext.js","sourceRoot":"","sources":["ModalContext.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AA2B7C,MAAM,iBAAiB,GAAsB;IAC3C,UAAU,EAAE,IAAI;IAChB,UAAU,EAAE,IAAI;IAChB,MAAM,EAAE,EAAE;CACX,CAAC;AAEF,MAAM,YAAY,GAAG,aAAa,CAAC,iBAAiB,CAAC,CAAC;AAEtD,eAAe,YAAY,CAAC"}
|
package/Modal/ModalProvider.d.ts
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import React
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
showTarget: (modalComponent: React.ReactNode, modalType: 'modal' | 'flyout' | 'drawer', modalId: string, props?: {}) => void;
|
|
6
|
-
hideTarget: () => void;
|
|
7
|
-
initialState: ModalState;
|
|
8
|
-
state: ModalState;
|
|
9
|
-
render(): JSX.Element;
|
|
10
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
declare const ModalProvider: ({ children }: {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
}) => JSX.Element;
|
|
11
5
|
export default ModalProvider;
|
package/Modal/ModalProvider.js
CHANGED
|
@@ -1,38 +1,83 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useEffect, useState, useCallback } from 'react';
|
|
2
2
|
import ModalContext from './ModalContext';
|
|
3
3
|
import ReactModal from 'react-modal';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
4
|
+
import { css } from 'linaria';
|
|
5
|
+
const preventBodyScrollStyle = css `
|
|
6
|
+
overflow: hidden;
|
|
7
|
+
`;
|
|
8
|
+
const ModalProvider = ({ children }) => {
|
|
9
|
+
const [modals, setModals] = useState([]);
|
|
10
|
+
function showTarget(modalComponent, modalType, modalId, props = {}) {
|
|
11
|
+
setModals((prevModals) => {
|
|
12
|
+
const newModals = [...prevModals];
|
|
13
|
+
const modalProps = {
|
|
14
|
+
modalComponent,
|
|
15
|
+
modalId,
|
|
16
|
+
modalType,
|
|
17
|
+
isOpen: true,
|
|
18
|
+
props,
|
|
19
|
+
showTarget,
|
|
20
|
+
hideTarget: () => hideTarget(modalId)
|
|
21
|
+
};
|
|
22
|
+
// Check if modal with same id already exists
|
|
23
|
+
const matchIndex = newModals.findIndex((modal) => modal.modalId === modalId);
|
|
24
|
+
if (matchIndex >= 0)
|
|
25
|
+
newModals[matchIndex] = modalProps;
|
|
26
|
+
else
|
|
27
|
+
newModals.push(modalProps);
|
|
28
|
+
return newModals;
|
|
29
|
+
});
|
|
29
30
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
function hideTarget(modalId) {
|
|
32
|
+
setModals((prevModals) => {
|
|
33
|
+
const newModals = [...prevModals];
|
|
34
|
+
// Calling hideTarget directly from a MouseEvent passes down an event
|
|
35
|
+
// object. Therefore we have to check if the passed prop is a string.
|
|
36
|
+
if (modalId && typeof modalId === 'string') {
|
|
37
|
+
// Removing the modal based on modalId if opened
|
|
38
|
+
const matchIndex = newModals.findIndex((modal) => modal.modalId === modalId);
|
|
39
|
+
if (matchIndex >= 0)
|
|
40
|
+
newModals.splice(matchIndex, 1);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// Removing the last opened modal
|
|
44
|
+
newModals.pop();
|
|
45
|
+
}
|
|
46
|
+
return newModals;
|
|
47
|
+
});
|
|
35
48
|
}
|
|
36
|
-
|
|
49
|
+
// Handling modal close on Escape button
|
|
50
|
+
const handleKeydown = useCallback((e) => {
|
|
51
|
+
if (e.key !== 'Escape' || modals.length === 0)
|
|
52
|
+
return;
|
|
53
|
+
const lastModal = modals[modals.length - 1];
|
|
54
|
+
if (!lastModal.props.canCloseOnEsc)
|
|
55
|
+
return;
|
|
56
|
+
hideTarget();
|
|
57
|
+
}, [modals]);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
ReactModal.setAppElement('#root');
|
|
60
|
+
}, []);
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
document.addEventListener('keydown', handleKeydown);
|
|
63
|
+
return () => document.removeEventListener('keydown', handleKeydown);
|
|
64
|
+
}, [handleKeydown]);
|
|
65
|
+
// Disabling scrolling when relevant
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
const preventOverflow = modals.some((modal) => modal.props.preventOverflow ||
|
|
68
|
+
(modal.modalType === 'drawer' && modal.isOpen));
|
|
69
|
+
if (preventOverflow)
|
|
70
|
+
document.body.classList.add(preventBodyScrollStyle);
|
|
71
|
+
else
|
|
72
|
+
document.body.classList.remove(preventBodyScrollStyle);
|
|
73
|
+
return () => document.body.classList.remove(preventBodyScrollStyle);
|
|
74
|
+
}, [modals]);
|
|
75
|
+
const initialState = {
|
|
76
|
+
showTarget,
|
|
77
|
+
hideTarget,
|
|
78
|
+
modals
|
|
79
|
+
};
|
|
80
|
+
return (React.createElement(ModalContext.Provider, { value: initialState }, children));
|
|
81
|
+
};
|
|
37
82
|
export default ModalProvider;
|
|
38
83
|
//# sourceMappingURL=ModalProvider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModalProvider.js","sourceRoot":"","sources":["ModalProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ModalProvider.js","sourceRoot":"","sources":["ModalProvider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -21,9 +21,6 @@ xdescribe('ModalProvider', () => {
|
|
|
21
21
|
it('mirrors the component state', () => {
|
|
22
22
|
const wrapper = shallow(<ModalProvider />);
|
|
23
23
|
expect(wrapper.prop('value')).toEqual(wrapper.instance().initialState);
|
|
24
|
-
|
|
25
|
-
wrapper.setState({ isOpen: true });
|
|
26
|
-
expect(wrapper.prop('value').isOpen).toBe(true);
|
|
27
24
|
});
|
|
28
25
|
});
|
|
29
26
|
});
|
package/Modal/ModalRoot.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
declare const ModalRoot:
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
declare const ModalRoot: () => JSX.Element;
|
|
3
3
|
export default ModalRoot;
|
package/Modal/ModalRoot.js
CHANGED
|
@@ -12,21 +12,25 @@ const Cover = styled('div') `
|
|
|
12
12
|
background: rgba(0, 0, 0, 0.2);
|
|
13
13
|
`;
|
|
14
14
|
Cover.displayName = 'Cover';
|
|
15
|
-
const ModalRoot = () =>
|
|
15
|
+
const ModalRoot = () => {
|
|
16
|
+
const { modals } = React.useContext(ModalContext);
|
|
17
|
+
return (React.createElement(React.Fragment, null, modals.map((modalProps) => (React.createElement(Modal, Object.assign({ key: modalProps.modalId }, modalProps))))));
|
|
18
|
+
};
|
|
19
|
+
const Modal = ({ modalComponent, isOpen, modalType, hideTarget, props }) => {
|
|
16
20
|
/** Do not render anything if there is no active modal */
|
|
17
21
|
if (!isOpen)
|
|
18
22
|
return null;
|
|
19
23
|
const Component = modalComponent;
|
|
20
24
|
if (Component && isOpen && modalType === 'modal') {
|
|
21
25
|
/** A modal has been requested, from somewhere in the app */
|
|
22
|
-
return (React.createElement(ReactModal, { className: props.modalStyles,
|
|
26
|
+
return (React.createElement(ReactModal, Object.assign({ className: props.modalStyles }, props.modalProps, {
|
|
23
27
|
/** isOpen should always be true here, since this is only rendered when a modal is requested */
|
|
24
28
|
isOpen: true,
|
|
25
29
|
/**
|
|
26
30
|
* react-modal requires an onRequestClose prop that takes a func to call when the modal is closed
|
|
27
31
|
* We use this to make sure the context is updated
|
|
28
32
|
*/
|
|
29
|
-
onRequestClose: hideTarget },
|
|
33
|
+
onRequestClose: hideTarget }),
|
|
30
34
|
React.createElement(Component, Object.assign({ hideTarget: hideTarget }, props))));
|
|
31
35
|
}
|
|
32
36
|
if (isOpen && props.showCover) {
|
|
@@ -34,6 +38,7 @@ const ModalRoot = () => (React.createElement(ModalContext.Consumer, null, ({ mod
|
|
|
34
38
|
/** Inject a clickable 'cover' behind flyouts */
|
|
35
39
|
return React.createElement(Cover, { onClick: hideTarget, style: coverStyles });
|
|
36
40
|
}
|
|
37
|
-
|
|
41
|
+
return null;
|
|
42
|
+
};
|
|
38
43
|
export default ModalRoot;
|
|
39
44
|
//# sourceMappingURL=ModalRoot.js.map
|
package/Modal/ModalRoot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModalRoot.js","sourceRoot":"","sources":["ModalRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,YAA4B,MAAM,gBAAgB,CAAC;AAC1D,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;;;;;;;;CAQ1B,CAAC;AACF,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC;AAE5B,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"ModalRoot.js","sourceRoot":"","sources":["ModalRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,YAA4B,MAAM,gBAAgB,CAAC;AAC1D,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;;;;;;;;CAQ1B,CAAC;AACF,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC;AAE5B,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IAClD,OAAO,CACL,0CACG,MAAM,CAAC,GAAG,CAAC,CAAC,UAAsB,EAAE,EAAE,CAAC,CACtC,oBAAC,KAAK,kBAAC,GAAG,EAAE,UAAU,CAAC,OAAO,IAAM,UAAU,EAAI,CACnD,CAAC,CACD,CACJ,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,KAAK,GAAG,CAAC,EACb,cAAc,EACd,MAAM,EACN,SAAS,EACT,UAAU,EACV,KAAK,EACM,EAAE,EAAE;IACf,yDAAyD;IACzD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,SAAS,GAAG,cAA2B,CAAC;IAE9C,IAAI,SAAS,IAAI,MAAM,IAAI,SAAS,KAAK,OAAO,EAAE;QAChD,6DAA6D;QAC7D,OAAO,CACL,oBAAC,UAAU,kBACT,SAAS,EAAE,KAAK,CAAC,WAAW,IACxB,KAAK,CAAC,UAAU;YACpB,+FAA+F;YAC/F,MAAM;YACN;;;eAGG;YACH,cAAc,EAAE,UAAU;YAE1B,oBAAC,SAAS,kBAAC,UAAU,EAAE,UAAU,IAAM,KAAK,EAAI,CACrC,CACd,CAAC;KACH;IAED,IAAI,MAAM,IAAI,KAAK,CAAC,SAAS,EAAE;QAC7B,MAAM,WAAW,GAAG,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,WAAW,CAAC;QAEvC,gDAAgD;QAChD,OAAO,oBAAC,KAAK,IAAC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAI,CAAC;KAC3D;IAED,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
package/Modal/ModalRoot.test.js
CHANGED
|
@@ -24,9 +24,13 @@ xdescribe('ModalRoot', () => {
|
|
|
24
24
|
it('renders a `Modal` when Component, isOpen and modalType is `modal`', () => {
|
|
25
25
|
const Comp = () => <div>Component being rendered inside Modal</div>;
|
|
26
26
|
const ModalRoot = modalRoot({
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
modals: [
|
|
28
|
+
{
|
|
29
|
+
modalComponent: Comp,
|
|
30
|
+
isOpen: true,
|
|
31
|
+
modalType: 'modal'
|
|
32
|
+
}
|
|
33
|
+
]
|
|
30
34
|
});
|
|
31
35
|
const wrapper = mount(<ModalRoot>{funcAsChild}</ModalRoot>);
|
|
32
36
|
expect(wrapper.find('Modal')).toHaveLength(1);
|
|
@@ -37,10 +41,14 @@ xdescribe('ModalRoot', () => {
|
|
|
37
41
|
const hideTarget = jest.fn();
|
|
38
42
|
|
|
39
43
|
const ModalRoot = modalRoot({
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
modals: [
|
|
45
|
+
{
|
|
46
|
+
hideTarget: hideTarget,
|
|
47
|
+
isOpen: true,
|
|
48
|
+
modalType: 'flyout',
|
|
49
|
+
props: { showCover: true }
|
|
50
|
+
}
|
|
51
|
+
]
|
|
44
52
|
});
|
|
45
53
|
const wrapper = mount(<ModalRoot>{funcAsChild}</ModalRoot>);
|
|
46
54
|
const Cover = wrapper.find('Cover');
|
|
@@ -48,4 +56,25 @@ xdescribe('ModalRoot', () => {
|
|
|
48
56
|
expect(Cover).toHaveLength(1);
|
|
49
57
|
expect(Cover.prop('onClick')).toBe(hideTarget);
|
|
50
58
|
});
|
|
59
|
+
|
|
60
|
+
it('renders multiple `Modal` when Component, isOpen and modalType is `modal`', () => {
|
|
61
|
+
const Comp = () => <div>Component being rendered inside Modal</div>;
|
|
62
|
+
const ModalRoot = modalRoot({
|
|
63
|
+
modals: [
|
|
64
|
+
{
|
|
65
|
+
modalComponent: Comp,
|
|
66
|
+
isOpen: true,
|
|
67
|
+
modalType: 'modal'
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
modalComponent: Comp,
|
|
71
|
+
isOpen: true,
|
|
72
|
+
modalType: 'modal'
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
const wrapper = mount(<ModalRoot>{funcAsChild}</ModalRoot>);
|
|
77
|
+
expect(wrapper.find('Modal')).toHaveLength(2);
|
|
78
|
+
expect(wrapper.text()).toContain('Component being rendered');
|
|
79
|
+
});
|
|
51
80
|
});
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
export const defaultContext = {
|
|
2
|
-
|
|
3
|
-
modalType: 'flyout',
|
|
4
|
-
modalId: 'foo',
|
|
5
|
-
isOpen: true,
|
|
6
|
-
props: {},
|
|
2
|
+
modals: [],
|
|
7
3
|
showTarget: jest.fn(),
|
|
8
4
|
hideTarget: jest.fn()
|
|
9
5
|
};
|
|
@@ -17,7 +13,7 @@ const getComponentWithModalContext = (targetPath, moduleToExport = null) => {
|
|
|
17
13
|
// Mock out ModalContext Consumer (used by all modals)
|
|
18
14
|
jest.doMock('../ModalContext', () => {
|
|
19
15
|
return {
|
|
20
|
-
Consumer: props => props.children(context)
|
|
16
|
+
Consumer: (props) => props.children(context)
|
|
21
17
|
};
|
|
22
18
|
});
|
|
23
19
|
|
|
@@ -9,6 +9,11 @@ export function useScrollRestore({ location, ignoreForRouteTypes, prevLocation }
|
|
|
9
9
|
if (!prevLocation && location.hash !== '') {
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
|
+
if (prevLocation &&
|
|
13
|
+
prevLocation.pathname === location.pathname &&
|
|
14
|
+
prevLocation.search === location.search) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
12
17
|
window.scrollTo(0, 0);
|
|
13
18
|
}, [ignoreForRouteTypes, location, prevLocation]);
|
|
14
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useScrollRestore.js","sourceRoot":"","sources":["useScrollRestore.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,UAAU,gBAAgB,CAAC,EAC/B,QAAQ,EACR,mBAAmB,EACnB,YAAY,EAKb;IACC,SAAS,CAAC,GAAG,EAAE;QACb,IACE,mBAAmB;YACnB,qBAAqB,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,mBAAmB,EAAE,CAAC,EACpE;YACA,OAAO;SACR;QAED,IAAI,CAAC,YAAY,IAAI,QAAQ,CAAC,IAAI,KAAK,EAAE,EAAE;YACzC,OAAO;SACR;QAED,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACxB,CAAC,EAAE,CAAC,mBAAmB,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;AACpD,CAAC"}
|
|
1
|
+
{"version":3,"file":"useScrollRestore.js","sourceRoot":"","sources":["useScrollRestore.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,UAAU,gBAAgB,CAAC,EAC/B,QAAQ,EACR,mBAAmB,EACnB,YAAY,EAKb;IACC,SAAS,CAAC,GAAG,EAAE;QACb,IACE,mBAAmB;YACnB,qBAAqB,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,mBAAmB,EAAE,CAAC,EACpE;YACA,OAAO;SACR;QAED,IAAI,CAAC,YAAY,IAAI,QAAQ,CAAC,IAAI,KAAK,EAAE,EAAE;YACzC,OAAO;SACR;QAGD,IAAI,YAAY;YACd,YAAY,CAAC,QAAQ,KAAK,QAAQ,CAAC,QAAQ;YAC3C,YAAY,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE;YACzC,OAAO;SACR;QAED,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACxB,CAAC,EAAE,CAAC,mBAAmB,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;AACpD,CAAC"}
|
package/package.json
CHANGED
package/Modal/TargetWrapper.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ModalState } from '@jetshop/ui/Modal/ModalContext';
|
|
3
|
-
/** Function to hide the target modal */
|
|
4
|
-
export declare type hideTarget = () => void;
|
|
5
|
-
export declare type isOpen = boolean;
|
|
6
|
-
export declare type childProps = {
|
|
7
|
-
hideTarget: hideTarget;
|
|
8
|
-
isOpen: isOpen;
|
|
9
|
-
};
|
|
10
|
-
export interface TargetWrapperProps {
|
|
11
|
-
/** React child-as-function */
|
|
12
|
-
children: (args: Partial<ModalState>) => React.ReactNode;
|
|
13
|
-
hideTarget: hideTarget;
|
|
14
|
-
isOpen: isOpen;
|
|
15
|
-
modalType: 'modal' | 'flyout' | 'drawer';
|
|
16
|
-
/** Whether to prevent the body from scrolling when flyout is open */
|
|
17
|
-
preventOverflow: boolean;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Wraps target's children and supplies lifecycle hooks
|
|
21
|
-
* to close on esc
|
|
22
|
-
*/
|
|
23
|
-
declare class TargetWrapper extends React.Component<TargetWrapperProps> {
|
|
24
|
-
componentDidMount(): void;
|
|
25
|
-
componentDidUpdate(prevProps: TargetWrapperProps): void;
|
|
26
|
-
componentWillUnmount(): void;
|
|
27
|
-
cleanup: () => void;
|
|
28
|
-
handleKeydown: (e: any) => void;
|
|
29
|
-
render(): React.ReactNode;
|
|
30
|
-
}
|
|
31
|
-
export default TargetWrapper;
|
package/Modal/TargetWrapper.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { css } from 'linaria';
|
|
3
|
-
const preventBodyScrollStyle = css `
|
|
4
|
-
overflow: hidden;
|
|
5
|
-
`;
|
|
6
|
-
/**
|
|
7
|
-
* Wraps target's children and supplies lifecycle hooks
|
|
8
|
-
* to close on esc
|
|
9
|
-
*/
|
|
10
|
-
class TargetWrapper extends React.Component {
|
|
11
|
-
constructor() {
|
|
12
|
-
super(...arguments);
|
|
13
|
-
this.cleanup = () => {
|
|
14
|
-
document.removeEventListener('keydown', this.handleKeydown);
|
|
15
|
-
document.body.classList.remove(preventBodyScrollStyle);
|
|
16
|
-
};
|
|
17
|
-
this.handleKeydown = (e) => e.key === 'Escape' && this.props.hideTarget();
|
|
18
|
-
}
|
|
19
|
-
componentDidMount() {
|
|
20
|
-
document.addEventListener('keydown', this.handleKeydown);
|
|
21
|
-
if (this.props.preventOverflow) {
|
|
22
|
-
document.body.classList.add(preventBodyScrollStyle);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
componentDidUpdate(prevProps) {
|
|
26
|
-
// If we're opening a drawer, add event handlers and prevent body scroll
|
|
27
|
-
if (this.props.modalType === 'drawer' && this.props.isOpen) {
|
|
28
|
-
document.addEventListener('keydown', this.handleKeydown);
|
|
29
|
-
document.body.classList.add(preventBodyScrollStyle);
|
|
30
|
-
}
|
|
31
|
-
// If we have just closed a drawer, clean it up
|
|
32
|
-
if (prevProps.modalType === 'drawer' && !this.props.isOpen) {
|
|
33
|
-
this.cleanup();
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
componentWillUnmount() {
|
|
37
|
-
this.cleanup();
|
|
38
|
-
}
|
|
39
|
-
render() {
|
|
40
|
-
const { hideTarget, isOpen } = this.props;
|
|
41
|
-
return this.props.children({ hideTarget, isOpen });
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
export default TargetWrapper;
|
|
45
|
-
//# sourceMappingURL=TargetWrapper.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TargetWrapper.js","sourceRoot":"","sources":["TargetWrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAsB9B,MAAM,sBAAsB,GAAG,GAAG,CAAA;;CAEjC,CAAC;AAEF;;;GAGG;AACH,MAAM,aAAc,SAAQ,KAAK,CAAC,SAA6B;IAA/D;;QA0BE,YAAO,GAAG,GAAG,EAAE;YACb,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;YAC5D,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;QACzD,CAAC,CAAC;QAEF,kBAAa,GAAG,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;IAM5E,CAAC;IApCC,iBAAiB;QACf,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAEzD,IAAI,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE;YAC9B,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;SACrD;IACH,CAAC;IAED,kBAAkB,CAAC,SAA6B;QAC9C,wEAAwE;QACxE,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAC1D,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;YACzD,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;SACrD;QAED,+CAA+C;QAC/C,IAAI,SAAS,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAC1D,IAAI,CAAC,OAAO,EAAE,CAAC;SAChB;IACH,CAAC;IAED,oBAAoB;QAClB,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC;IASD,MAAM;QACJ,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;IACrD,CAAC;CACF;AAED,eAAe,aAAa,CAAC"}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import TargetWrapper from './TargetWrapper';
|
|
3
|
-
|
|
4
|
-
xdescribe('TargetWrapper', () => {
|
|
5
|
-
let mountedTargetWrapper;
|
|
6
|
-
let props;
|
|
7
|
-
let childFunc = () => <div>hello</div>;
|
|
8
|
-
|
|
9
|
-
/** @returns {ShallowWrapper} */
|
|
10
|
-
const targetWrapper = (child = childFunc) =>
|
|
11
|
-
(mountedTargetWrapper = !mountedTargetWrapper
|
|
12
|
-
? (mountedTargetWrapper = shallow(
|
|
13
|
-
<TargetWrapper {...props}>{child}</TargetWrapper>
|
|
14
|
-
))
|
|
15
|
-
: mountedTargetWrapper);
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
props = {
|
|
19
|
-
hideTarget: jest.fn(),
|
|
20
|
-
isOpen: false
|
|
21
|
-
};
|
|
22
|
-
mountedTargetWrapper = undefined;
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe('on mount', () => {
|
|
26
|
-
const spy = jest.spyOn(TargetWrapper.prototype, 'handleKeydown');
|
|
27
|
-
|
|
28
|
-
it('adds a keydown event listener to window', () => {
|
|
29
|
-
targetWrapper();
|
|
30
|
-
|
|
31
|
-
var event = new KeyboardEvent('keydown', { key: 'Escape' });
|
|
32
|
-
document.dispatchEvent(event);
|
|
33
|
-
|
|
34
|
-
expect(spy).toHaveBeenCalled();
|
|
35
|
-
targetWrapper().unmount();
|
|
36
|
-
});
|
|
37
|
-
it('removes keydown event listener when unmounted', () => {
|
|
38
|
-
targetWrapper().unmount();
|
|
39
|
-
|
|
40
|
-
var event = new KeyboardEvent('keydown', { key: 'Escape' });
|
|
41
|
-
document.dispatchEvent(event);
|
|
42
|
-
|
|
43
|
-
// handleKeyDown should have been called only once, in the previous test
|
|
44
|
-
expect(spy).toHaveBeenCalledTimes(1);
|
|
45
|
-
});
|
|
46
|
-
describe('if `drawer` is given for `modalType` prop', () => {
|
|
47
|
-
beforeEach(() => {
|
|
48
|
-
props.modalType = 'drawer';
|
|
49
|
-
});
|
|
50
|
-
it('adds a class to body', () => {
|
|
51
|
-
targetWrapper();
|
|
52
|
-
expect(document.body.classList.length).toBe(1);
|
|
53
|
-
});
|
|
54
|
-
it('removes the class when unmounted', () => {
|
|
55
|
-
targetWrapper().unmount();
|
|
56
|
-
expect(document.body.classList.length).toBe(0);
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
describe('if `modalType` is not `drawer`', () => {
|
|
60
|
-
it('no class is added to body', () => {
|
|
61
|
-
targetWrapper();
|
|
62
|
-
expect(document.body.classList.length).toBe(0);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
describe('it executes the child prop', () => {
|
|
67
|
-
const funcAsChild = jest.fn();
|
|
68
|
-
|
|
69
|
-
it('on mount', () => {
|
|
70
|
-
targetWrapper(funcAsChild);
|
|
71
|
-
expect(funcAsChild).toBeCalled();
|
|
72
|
-
});
|
|
73
|
-
it('with `hideTarget` and `isOpen` props passed as args', () => {
|
|
74
|
-
targetWrapper(funcAsChild);
|
|
75
|
-
expect(funcAsChild).toHaveBeenLastCalledWith({
|
|
76
|
-
hideTarget: props.hideTarget,
|
|
77
|
-
isOpen: props.isOpen
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
});
|