Skip to content

Commit 14f4cf6

Browse files
committed
improve ModalContext example
1 parent bced125 commit 14f4cf6

2 files changed

Lines changed: 166 additions & 150 deletions

File tree

Lines changed: 12 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,11 @@
11
import React from "react";
2-
import { Classes, OverlaysProvider } from "@blueprintjs/core";
2+
import { OverlaysProvider } from "@blueprintjs/core";
33
import { Meta, StoryFn } from "@storybook/react";
44
import { fn } from "@storybook/test";
55

66
import { SimpleCard } from "../../Card/stories/Card.stories";
77

8-
import {
9-
Button,
10-
Card,
11-
CardContent,
12-
Modal,
13-
ModalContext,
14-
ModalSize,
15-
Spacing,
16-
useModalContext,
17-
} from "./../../../../index";
8+
import { Card, Modal } from "./../../../../index";
189

1910
export default {
2011
title: "Components/Dialog/Modal",
@@ -24,15 +15,18 @@ export default {
2415
control: false,
2516
},
2617
},
18+
decorators: [
19+
(Story) => (
20+
<OverlaysProvider>
21+
<div style={{ height: "400px" }}>
22+
<Story />
23+
</div>
24+
</OverlaysProvider>
25+
),
26+
],
2727
} as Meta<typeof Modal>;
2828

29-
const Template: StoryFn<typeof Modal> = (args) => (
30-
<OverlaysProvider>
31-
<div style={{ height: "400px" }}>
32-
<Modal {...args} />
33-
</div>
34-
</OverlaysProvider>
35-
);
29+
const Template: StoryFn<typeof Modal> = (args) => <Modal {...args} />;
3630

3731
export const Default = Template.bind({});
3832
Default.args = {
@@ -42,135 +36,3 @@ Default.args = {
4236
onOpening: fn(),
4337
onClosing: fn(),
4438
};
45-
46-
const ContextTemplate = ({ children }: React.HTMLAttributes<HTMLDivElement>) => {
47-
const { setModalOpen, openModalStack } = useModalContext();
48-
49-
return (
50-
<OverlaysProvider>
51-
<div style={{ height: "70vh", position: "relative" }} id={"modalPortal"}>
52-
<ModalContext.Provider value={{ setModalOpen, openModalStack }}>{children}</ModalContext.Provider>
53-
</div>
54-
</OverlaysProvider>
55-
);
56-
};
57-
58-
const ModalContent = ({ children }: React.HTMLAttributes<HTMLDivElement>) => {
59-
return (
60-
<Card style={{ height: "100%" }}>
61-
<CardContent>{children}</CardContent>
62-
</Card>
63-
);
64-
};
65-
66-
/** Component for nested modals. */
67-
const ExampleModal = ({
68-
id,
69-
size,
70-
children,
71-
}: {
72-
id?: string;
73-
size: ModalSize;
74-
children?: React.HTMLAttributes<HTMLDivElement>["children"];
75-
}) => {
76-
const [isOpen, setIsOpen] = React.useState(true);
77-
const [portalElement, setPortalElement] = React.useState<HTMLElement | undefined>();
78-
79-
React.useEffect(() => {
80-
setPortalElement(document.getElementById("modalPortal")!);
81-
}, []);
82-
83-
return (
84-
<Modal
85-
modalId={id}
86-
size={size}
87-
isOpen={isOpen}
88-
usePortal={true}
89-
portalContainer={portalElement}
90-
hasBackdrop={true}
91-
onOpened={() => {
92-
// workaround, Blueprint attach a class to body tht prevents scrolling, probably it is attached to the wrong portal
93-
document.body.classList.remove(Classes.OVERLAY_OPEN);
94-
}}
95-
>
96-
<ModalContent>
97-
Modal with constant modal ID "{id}".
98-
<Spacing />
99-
<TrackingContent />
100-
<Spacing />
101-
{children}
102-
<Spacing />
103-
<Button key={"close"} onClick={() => setIsOpen(false)}>
104-
Close
105-
</Button>
106-
</ModalContent>
107-
</Modal>
108-
);
109-
};
110-
111-
const InnerModal = () => {
112-
return <ExampleModal id="innerModal" size="small" />;
113-
};
114-
115-
const MiddleModal = () => {
116-
return (
117-
<ExampleModal id="middleModal" size="regular">
118-
<InnerModal />
119-
</ExampleModal>
120-
);
121-
};
122-
123-
/** Shows the current stack of open modals. */
124-
const TrackingContent = () => {
125-
const modalContext = React.useContext(ModalContext);
126-
127-
return (
128-
<ul>
129-
{(modalContext.openModalStack() ?? []).map((modalId, idx) => (
130-
<li key={modalId}>
131-
{idx + 1}. {modalId}
132-
</li>
133-
))}
134-
</ul>
135-
);
136-
};
137-
138-
/**
139-
* `ModalContext` can be used as provider to track a stack of modals.
140-
*
141-
* ```(Javascript)
142-
* const ContextTemplate = () => {
143-
* const { setModalOpen, openModalStack } = useModalContext();
144-
* return (
145-
* <ModalContext.Provider value={{ setModalOpen, openModalStack }}>
146-
* <SimpleDialog size="large" isOpen>
147-
* <OtherModal />
148-
* </SimpleDialog>
149-
* </ModalContext.Provider>
150-
* );
151-
* };
152-
*
153-
* const OtherModal = () => {
154-
* const modalContext = React.useContext(ModalContext);
155-
* return (
156-
* <SimpleDialog size="small">
157-
* <ul>
158-
* {(modalContext.openModalStack ?? []).map((modalId, idx) => (
159-
* <li key={modalId}>
160-
* {idx + 1}. {modalId}
161-
* </li>
162-
* ))}
163-
* </ul>
164-
* </SimpleDialog>
165-
* );
166-
* };
167-
* ```
168-
*/
169-
export const NestedModalWithContext = ContextTemplate.bind({});
170-
NestedModalWithContext.args = {
171-
children: [
172-
<ExampleModal id="rootModal" size="large">
173-
<MiddleModal />
174-
</ExampleModal>,
175-
],
176-
};
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import React from "react";
2+
import { Classes, OverlaysProvider } from "@blueprintjs/core";
3+
import { Meta } from "@storybook/react";
4+
5+
import {
6+
Button,
7+
Card,
8+
CardContent,
9+
Modal,
10+
ModalContext,
11+
ModalContextProps,
12+
ModalSize,
13+
Spacing,
14+
useModalContext,
15+
} from "./../../../../index";
16+
17+
/**
18+
* `ModalContext` can be used as provider to track a stack of modals.
19+
*
20+
* ```(Javascript)
21+
* import { ModalContext, SimpleDialog } from "@eccenca/gui-elements";
22+
*
23+
* const ContextTemplate = () => {
24+
* const { setModalOpen, openModalStack } = useModalContext();
25+
* return (
26+
* <ModalContext.Provider value={{ setModalOpen, openModalStack }}>
27+
* <SimpleDialog size="large" isOpen>
28+
* <OtherModal />
29+
* </SimpleDialog>
30+
* </ModalContext.Provider>
31+
* );
32+
* };
33+
*
34+
* const OtherModal = () => {
35+
* const modalContext = React.useContext(ModalContext);
36+
* return (
37+
* <SimpleDialog size="small">
38+
* <ul>
39+
* {(modalContext.openModalStack ?? []).map((modalId, idx) => (
40+
* <li key={modalId}>
41+
* {idx + 1}. {modalId}
42+
* </li>
43+
* ))}
44+
* </ul>
45+
* </SimpleDialog>
46+
* );
47+
* };
48+
* ```
49+
*/
50+
export default {
51+
title: "Components/Dialog/ModalContext",
52+
decorators: [
53+
(Story) => (
54+
<OverlaysProvider>
55+
<div style={{ height: "70vh", position: "relative" }} id={"modalPortal"}>
56+
<Story />
57+
</div>
58+
</OverlaysProvider>
59+
),
60+
],
61+
} as Meta<ModalContextProps>;
62+
63+
export const Usage = () => {
64+
const { setModalOpen, openModalStack } = useModalContext();
65+
66+
return (
67+
<ModalContext.Provider value={{ setModalOpen, openModalStack }}>
68+
<ExampleModal id="rootModal" size="large">
69+
<MiddleModal />
70+
</ExampleModal>
71+
,
72+
</ModalContext.Provider>
73+
);
74+
};
75+
76+
const ModalContent = ({ children }: React.HTMLAttributes<HTMLDivElement>) => {
77+
return (
78+
<Card style={{ height: "100%" }}>
79+
<CardContent>{children}</CardContent>
80+
</Card>
81+
);
82+
};
83+
84+
/** Component for nested modals. */
85+
const ExampleModal = ({
86+
id,
87+
size,
88+
children,
89+
}: {
90+
id?: string;
91+
size: ModalSize;
92+
children?: React.HTMLAttributes<HTMLDivElement>["children"];
93+
}) => {
94+
const [isOpen, setIsOpen] = React.useState(true);
95+
const [portalElement, setPortalElement] = React.useState<HTMLElement | undefined>();
96+
97+
React.useEffect(() => {
98+
setPortalElement(document.getElementById("modalPortal")!);
99+
}, []);
100+
101+
return (
102+
<Modal
103+
modalId={id}
104+
size={size}
105+
isOpen={isOpen}
106+
usePortal={true}
107+
portalContainer={portalElement}
108+
hasBackdrop={true}
109+
onOpened={() => {
110+
// workaround, Blueprint attach a class to body tht prevents scrolling, probably it is attached to the wrong portal
111+
document.body.classList.remove(Classes.OVERLAY_OPEN);
112+
}}
113+
>
114+
<ModalContent>
115+
Modal with constant modal ID "{id}".
116+
<Spacing />
117+
<TrackingContent />
118+
<Spacing />
119+
{children}
120+
<Spacing />
121+
<Button key={"close"} onClick={() => setIsOpen(false)}>
122+
Close
123+
</Button>
124+
</ModalContent>
125+
</Modal>
126+
);
127+
};
128+
129+
const InnerModal = () => {
130+
return <ExampleModal id="innerModal" size="small" />;
131+
};
132+
133+
const MiddleModal = () => {
134+
return (
135+
<ExampleModal id="middleModal" size="regular">
136+
<InnerModal />
137+
</ExampleModal>
138+
);
139+
};
140+
141+
/** Shows the current stack of open modals. */
142+
const TrackingContent = () => {
143+
const modalContext = React.useContext(ModalContext);
144+
145+
return (
146+
<ul>
147+
{(modalContext.openModalStack() ?? []).map((modalId, idx) => (
148+
<li key={modalId}>
149+
{idx + 1}. {modalId}
150+
</li>
151+
))}
152+
</ul>
153+
);
154+
};

0 commit comments

Comments
 (0)