Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pterodactyl
GitHub Repository: pterodactyl/panel
Path: blob/1.0-develop/resources/scripts/hoc/asModal.tsx
7458 views
1
import React from 'react';
2
import PortaledModal, { ModalProps } from '@/components/elements/Modal';
3
import ModalContext, { ModalContextValues } from '@/context/ModalContext';
4
import isEqual from 'react-fast-compare';
5
6
export interface AsModalProps {
7
visible: boolean;
8
onModalDismissed?: () => void;
9
}
10
11
export type SettableModalProps = Omit<ModalProps, 'appear' | 'visible' | 'onDismissed'>;
12
13
interface State {
14
render: boolean;
15
visible: boolean;
16
propOverrides: Partial<SettableModalProps>;
17
}
18
19
type ExtendedComponentType<T> = (C: React.ComponentType<T>) => React.ComponentType<T & AsModalProps>;
20
21
// eslint-disable-next-line @typescript-eslint/ban-types
22
function asModal<P extends {}>(
23
modalProps?: SettableModalProps | ((props: P) => SettableModalProps)
24
): ExtendedComponentType<P> {
25
return function (Component) {
26
return class extends React.PureComponent<P & AsModalProps, State> {
27
static displayName = `asModal(${Component.displayName})`;
28
29
constructor(props: P & AsModalProps) {
30
super(props);
31
32
this.state = {
33
render: props.visible,
34
visible: props.visible,
35
propOverrides: {},
36
};
37
}
38
39
get computedModalProps(): Readonly<SettableModalProps & { visible: boolean }> {
40
return {
41
...(typeof modalProps === 'function' ? modalProps(this.props) : modalProps),
42
...this.state.propOverrides,
43
visible: this.state.visible,
44
};
45
}
46
47
/**
48
* @this {React.PureComponent<P & AsModalProps, State>}
49
*/
50
componentDidUpdate(prevProps: Readonly<P & AsModalProps>, prevState: Readonly<State>) {
51
if (prevProps.visible && !this.props.visible) {
52
this.setState({ visible: false, propOverrides: {} });
53
} else if (!prevProps.visible && this.props.visible) {
54
this.setState({ render: true, visible: true });
55
}
56
if (!this.state.render && !isEqual(prevState.propOverrides, this.state.propOverrides)) {
57
this.setState({ propOverrides: {} });
58
}
59
}
60
61
dismiss = () => this.setState({ visible: false });
62
63
setPropOverrides: ModalContextValues['setPropOverrides'] = (value) =>
64
this.setState((state) => ({
65
propOverrides: !value ? {} : typeof value === 'function' ? value(state.propOverrides) : value,
66
}));
67
68
/**
69
* @this {React.PureComponent<P & AsModalProps, State>}
70
*/
71
render() {
72
if (!this.state.render) return null;
73
74
return (
75
<PortaledModal
76
appear
77
onDismissed={() =>
78
this.setState({ render: false }, () => {
79
if (typeof this.props.onModalDismissed === 'function') {
80
this.props.onModalDismissed();
81
}
82
})
83
}
84
{...this.computedModalProps}
85
>
86
<ModalContext.Provider
87
value={{
88
dismiss: this.dismiss.bind(this),
89
setPropOverrides: this.setPropOverrides.bind(this),
90
}}
91
>
92
<Component {...this.props} />
93
</ModalContext.Provider>
94
</PortaledModal>
95
);
96
}
97
};
98
};
99
}
100
101
export default asModal;
102
103