2022-09-07 13:17:17 +02:00

172 lines
3.7 KiB
JavaScript

import React from "react"
import { DraggableDrawer } from "components"
import EventEmitter from "@foxify/events"
import "./index.less"
export default class DrawerController extends React.Component {
constructor(props) {
super(props)
this.state = {
addresses: {},
refs: {},
drawers: [],
}
this.DrawerController = {
open: this.open,
close: this.close,
closeAll: this.closeAll,
}
window.app["DrawerController"] = this.DrawerController
}
sendEvent = (id, ...context) => {
const ref = this.state.refs[id]?.current
return ref.events.emit(...context)
}
open = (id, component, options) => {
const refs = this.state.refs ?? {}
const drawers = this.state.drawers ?? []
const addresses = this.state.addresses ?? {}
const instance = {
id,
key: id,
ref: React.createRef(),
children: component,
options,
controller: this,
}
if (typeof addresses[id] === "undefined") {
drawers.push(<Drawer {...instance} />)
addresses[id] = drawers.length - 1
refs[id] = instance.ref
} else {
const ref = refs[id].current
const isLocked = ref.state.locked
if (!isLocked) {
drawers[addresses[id]] = <Drawer {...instance} />
refs[id] = instance.ref
} else {
console.warn("Cannot update an locked drawer.")
}
}
this.setState({ refs, addresses, drawers })
}
destroy = (id) => {
let { addresses, drawers, refs } = this.state
const index = addresses[id]
if (typeof drawers[index] !== "undefined") {
drawers = drawers.filter((value, i) => i !== index)
}
delete addresses[id]
delete refs[id]
this.setState({ addresses, drawers })
}
close = (id) => {
const ref = this.state.refs[id]?.current
if (typeof ref !== "undefined") {
if (ref.state.locked && ref.state.visible) {
return console.warn("This drawer is locked and cannot be closed")
} else {
return ref.close()
}
} else {
return console.warn("This drawer not exists")
}
}
closeAll = () => {
this.state.drawers.forEach((drawer) => {
drawer.ref.current.close()
})
}
render() {
return this.state.drawers
}
}
export class Drawer extends React.Component {
options = this.props.options ?? {}
events = new EventEmitter()
state = {
visible: true,
}
componentDidMount = async () => {
if (typeof this.props.controller === "undefined") {
throw new Error(`Cannot mount an drawer without an controller`)
}
if (typeof this.props.children === "undefined") {
throw new Error(`Empty component`)
}
}
toogleVisibility = (to) => {
this.setState({ visible: to ?? !this.state.visible })
}
close = () => {
this.toogleVisibility(false)
this.events.emit("beforeClose")
setTimeout(() => {
if (typeof this.options.onClose === "function") {
this.options.onClose()
}
this.props.controller.destroy(this.props.id)
}, 500)
}
sendEvent = (...context) => {
return this.props.controller.sendEvent(this.props.id, ...context)
}
handleDone = (...context) => {
if (typeof this.options.onDone === "function") {
this.options.onDone(this, ...context)
}
}
handleFail = (...context) => {
if (typeof this.options.onFail === "function") {
this.options.onFail(this, ...context)
}
}
render() {
const drawerProps = {
...this.options.props,
ref: this.props.ref,
key: this.props.id,
onRequestClose: this.close,
open: this.state.visible,
containerElementClass: "drawer",
modalElementClass: "body",
}
const componentProps = {
...this.options.componentProps,
events: this.events,
close: this.close,
handleDone: this.handleDone,
handleFail: this.handleFail,
}
return <DraggableDrawer {...drawerProps}>
{React.createElement(this.props.children, componentProps)}
</DraggableDrawer>
}
}