-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathWidgetWrapper.tsx
120 lines (109 loc) · 4.09 KB
/
WidgetWrapper.tsx
1
2
3
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
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import React, { useRef, useState } from 'react';
import { ButtonToolbar, Form, Modal } from 'react-bootstrap';
import { ExportButton } from './CombinedExport/ExportButton';
import { ExportManager, ExportManagerContext } from './CombinedExport/ExportManager';
import { NamedCard, TabConfig } from './NamedCard';
// InternalProps are passed by Widget
export interface InternalProps {
getShareUrl: () => Promise<string>;
children: React.ReactNode | React.ReactNode[];
componentLabels?: string[];
}
// LayoutProps as passed by WidgetWrapper to the component responsible for Layout
export interface LayoutProps {
title: string;
toolbar?: React.ReactNode | React.ReactNode[];
children: React.ReactNode | React.ReactNode[];
tabs?: TabConfig;
}
// ExternalProps are passed by users of Widget.ShareableComponent
export interface ExternalProps {
title: string;
toolbarChildren?: React.ReactNode | React.ReactNode[];
showExport?: boolean;
height?: number;
widgetLayout?: React.ComponentType<LayoutProps>;
}
// IMPORTANT externalPropsKeys must be kept in sync with ExternalProps
const externalPropsKeys: (keyof ExternalProps)[] = [
'title',
'toolbarChildren',
'showExport',
'height',
'widgetLayout',
];
export function pickExternalProps<T extends { [K in keyof ExternalProps]?: never }>(
allProps: T
): { external: ExternalProps; remaining: T } {
const external: { [key: string]: unknown } = {};
const remaining: { [key: string]: unknown } = {};
for (const [k, v] of Object.entries(allProps)) {
if ((externalPropsKeys as string[]).includes(k)) {
external[k] = v;
} else {
remaining[k] = v;
}
}
return { external: external as any as ExternalProps, remaining: remaining as any };
}
type Props = InternalProps & ExternalProps;
export function WidgetWrapper({
children,
title,
toolbarChildren,
showExport = true,
height,
widgetLayout: WidgetLayout = NamedCard,
componentLabels,
}: Props) {
const exportManagerRef = useRef(new ExportManager());
const [activeTabIndex, setActiveTabIndex] = useState(0);
const childrenAsArray: React.ReactNode[] = React.Children.toArray(children);
const tabs: TabConfig | undefined = componentLabels
? {
activeTabIndex,
labels: componentLabels,
onNewTabSelect: setActiveTabIndex,
}
: undefined;
const [shownEmbeddingCode, setShownEmbeddingCode] = useState<string>();
// HACK(by Chaoran): The embed widget feature was used a few times but has not been as useful as I originally
// anticipated. It also has not been well-maintained for a while, and we don't have any tests for them. Thus, I'd like
// to avoid having new people using this feature. The only case where the feature will be useful for the foreseeable
// future is for the wastewater plots.
// useEffect(() => {
// const handle = exportManagerRef.current.register('Embed widget', async () => {
// const embeddingCode = `<iframe src="${host}/embed/${await getShareUrl()}" width="800" height="500" frameborder="0"></iframe>`;
// setShownEmbeddingCode(embeddingCode);
// });
//
// return handle.deregister;
// }, [getShareUrl]);
return (
<>
<ExportManagerContext.Provider value={exportManagerRef.current}>
<WidgetLayout
title={title}
toolbar={
<ButtonToolbar className='mb-1'>
{showExport && <ExportButton key={title} className='mt-1 ml-1' />}
{toolbarChildren}
</ButtonToolbar>
}
tabs={tabs}
>
<div style={height ? { height } : undefined}>{childrenAsArray[activeTabIndex]}</div>
</WidgetLayout>
</ExportManagerContext.Provider>
<Modal size='lg' show={!!shownEmbeddingCode} onHide={() => setShownEmbeddingCode(undefined)}>
<Modal.Header closeButton>
<Modal.Title>Embed widget on your website</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>Copy the following code into your website to embed the widget.</p>
<Form.Control as='textarea' value={shownEmbeddingCode} rows={7} readOnly />
</Modal.Body>
</Modal>
</>
);
}