diff --git a/packages/app/src/layout/sidedrawer/index.jsx b/packages/app/src/layout/sidedrawer/index.jsx
index 6de1e851..5e2a0732 100644
--- a/packages/app/src/layout/sidedrawer/index.jsx
+++ b/packages/app/src/layout/sidedrawer/index.jsx
@@ -3,48 +3,202 @@ import classnames from "classnames"
import "./index.less"
-export default class Sidedrawer extends React.Component {
- constructor(props) {
- super(props)
- this.state = {
- render: null
- }
+export const Sidedrawer = (props) => {
+ const sidedrawerId = props.id ?? props.key
- this.SidedrawerController = {
- render: this._render,
- close: this._close
+ return
+ {
+ React.createElement(props.children, {
+ ...props.props,
+ close: props.close,
+ })
+ }
+
+}
- window.app["SidedrawerController"] = this.SidedrawerController
+export default class SidedrawerController extends React.Component {
+ state = {
+ drawers: [],
+ lockedIds: [],
}
- containerRef = React.createRef()
+ constructor(props) {
+ super(props)
+
+ this.controller = window.app["SidedrawerController"] = {
+ open: this.open,
+ close: this.close,
+ closeAll: this.closeAll,
+ hasDrawers: this.state.drawers.length > 0,
+ }
+ }
+
+ componentDidMount = () => {
+ this.listenEscape()
+ }
+
+ componentDidUpdate() {
+ this.controller.hasDrawers = this.state.drawers.length > 0
+
+ if (this.controller.hasDrawers) {
+ window.app.eventBus.emit("sidedrawer.hasDrawers")
+ } else {
+ window.app.eventBus.emit("sidedrawer.noDrawers")
+ }
+ }
componentWillUnmount = () => {
this.unlistenEscape()
}
- _render = (component) => {
- this.listenEscape()
- this.setState({ render: component })
+ drawerIsLocked = (id) => {
+ return this.state.lockedIds.includes(id)
}
- close = () => {
- this.unlistenEscape()
- this.setState({ render: null })
+ lockDrawerId = (id) => {
+ this.setState({
+ lockedIds: [...this.state.lockedIds, id],
+ })
+ }
+
+ unlockDrawer = (id) => {
+ this.setState({
+ lockedIds: this.state.lockedIds.filter(lockedId => lockedId !== id),
+ })
+ }
+
+ open = async (id, component, options = {}) => {
+ if (typeof id !== "string") {
+ options = component
+ component = id
+ id = component.key ?? component.id ?? Math.random().toString(36).substr(2, 9)
+ }
+
+ let drawers = this.state.drawers
+
+ // check if id is already in use
+ // but only if its allowed to be used multiple times
+ const existentDrawer = drawers.find((drawer) => drawer.props.id === id)
+
+ if (existentDrawer) {
+ if (!existentDrawer.props.allowMultiples) {
+ console.warn(`Sidedrawer with id "${id}" already exists.`)
+ return false
+ }
+
+ // fix id appending the corresponding array index at the end of the id
+ // ex ["A", "B", "C"] => ["A", "B", "C", "A-1"]
+ // to prevent id collisions
+
+ let index = 0
+ let newId = id
+
+ while (drawers.find(drawer => drawer.props.id === newId)) {
+ index++
+ newId = id + "-" + index
+ }
+
+ id = newId
+ }
+
+ drawers.push(React.createElement(
+ Sidedrawer,
+ {
+ key: id,
+ id: id,
+ allowMultiples: options.allowMultiples ?? false,
+ ...options.props,
+ close: this.close,
+ escClosable: options.escClosable ?? true,
+ defaultVisible: false,
+ selfLock: () => {
+ this.lockDrawerId(id)
+ },
+ selfUnlock: () => {
+ this.unlockDrawer(id)
+ }
+ },
+ component
+ ))
+
+ if (options.lock) {
+ this.lockDrawerId(id)
+ }
+
+ await this.setState({ drawers })
+
+ setTimeout(() => {
+ this.toggleDrawerVisibility(id, true)
+ }, 10)
+
+ window.app.eventBus.emit("sidedrawer.open")
+ }
+
+ toggleDrawerVisibility = (id, to) => {
+ const drawer = document.getElementById(id)
+ const drawerClasses = drawer.classList
+
+ if (to) {
+ drawerClasses.remove("hided")
+ } else {
+ drawerClasses.add("hided")
+ }
+ }
+
+ close = (id) => {
+ // if an id is provided filter by key
+ // else close the last opened drawer
+ let drawers = this.state.drawers
+ let drawerId = id ?? drawers[drawers.length - 1].props.id
+
+ // check if id is locked
+ if (this.drawerIsLocked(id)) {
+ console.warn(`Sidedrawer with id "${id}" is locked.`)
+ return false
+ }
+
+ // check if id exists
+ const drawer = drawers.find(drawer => drawer.props.id === drawerId)
+
+ if (!drawer) {
+ console.warn(`Sidedrawer with id "${id}" does not exist.`)
+ return false
+ }
+
+ // emit event
+ window.app.eventBus.emit("sidedrawer.close")
+
+ // toogleVisibility off
+ this.toggleDrawerVisibility(drawerId, false)
+
+ // await drawer transition
+ setTimeout(() => {
+ // remove drawer
+ drawers = drawers.filter(drawer => drawer.props.id !== drawerId)
+
+ this.setState({ drawers })
+ }, 500)
}
listenEscape = () => {
- document.addEventListener("keydown", this.handleKeyPress)
+ document.addEventListener("keydown", this.handleEscKeyPress)
}
unlistenEscape = () => {
- document.removeEventListener("keydown", this.handleKeyPress)
+ document.removeEventListener("keydown", this.handleEscKeyPress)
}
- handleKeyPress = (event) => {
+ handleEscKeyPress = (event) => {
// avoid handle keypress when is nothing to render
- if (!this.state.render) {
+ if (this.state.drawers.length === 0) {
return false
}
@@ -57,27 +211,16 @@ export default class Sidedrawer extends React.Component {
}
if (isEscape) {
+ // close the last opened drawer
this.close()
}
}
- renderComponent = (component) => {
- if (!component) {
- return null
- }
-
- if (React.isValidElement(component)) {
- return React.cloneElement(component)
- }
-
- return React.createElement(component)
- }
-
render() {
- return (
-
- {this.renderComponent(this.state.render)}
-
- )
+ return
+ {this.state.drawers}
+
}
-}
+}
\ No newline at end of file
diff --git a/packages/app/src/layout/sidedrawer/index.less b/packages/app/src/layout/sidedrawer/index.less
index 7d7aec2a..bc0e70a4 100644
--- a/packages/app/src/layout/sidedrawer/index.less
+++ b/packages/app/src/layout/sidedrawer/index.less
@@ -1,21 +1,37 @@
@import "theme/vars.less";
-.sidedrawer {
- width: 30vw; // by default
+.sidedrawers-wrapper {
+ display: flex;
+ flex-direction: row;
- background-color: var(--sidedrawer-background-color);
- border-radius: @app_sidebar_borderRadius 0 0 @app_sidebar_borderRadius;
+ .sidedrawer {
+ position: relative;
- word-break: break-all;
+ width: 30vw; // by default
+ height: 100vh;
- transition: all 150ms ease-out;
+ min-width: 700px;
- padding: 20px;
- overflow-x: hidden;
- overflow-y: overlay;
+ z-index: 20;
- &.hided {
- width: 0;
- padding: 0;
+ background-color: var(--sidedrawer-background-color);
+ border-radius: 0 @app_sidebar_borderRadius @app_sidebar_borderRadius 0;
+
+ padding: 20px;
+ padding-left: 70px;
+
+ transform: translate(-50px, 0);
+
+ overflow-x: hidden;
+ overflow-y: overlay;
+
+ word-break: break-all;
+ transition: all 250ms ease-in-out;
+
+ &.hided {
+ width: 0;
+ min-width: 0;
+ padding: 0;
+ }
}
}
\ No newline at end of file