mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-10 02:54:15 +00:00
rewrite new Sidedrawer
controller
This commit is contained in:
parent
5ba73d13eb
commit
954d231da4
@ -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 <div
|
||||
key={sidedrawerId}
|
||||
id={sidedrawerId}
|
||||
className={
|
||||
classnames("sidedrawer", {
|
||||
"hided": !props.defaultVisible,
|
||||
})
|
||||
}
|
||||
>
|
||||
{
|
||||
React.createElement(props.children, {
|
||||
...props.props,
|
||||
close: props.close,
|
||||
})
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
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 (
|
||||
<div ref={this.containerRef} className={classnames("sidedrawer", { hided: !this.state.render })}>
|
||||
<React.Fragment>{this.renderComponent(this.state.render)}</React.Fragment>
|
||||
</div>
|
||||
)
|
||||
return <div
|
||||
className="sidedrawers-wrapper"
|
||||
>
|
||||
{this.state.drawers}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user