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"
|
import "./index.less"
|
||||||
|
|
||||||
export default class Sidedrawer extends React.Component {
|
export const Sidedrawer = (props) => {
|
||||||
constructor(props) {
|
const sidedrawerId = props.id ?? props.key
|
||||||
super(props)
|
|
||||||
this.state = {
|
|
||||||
render: null
|
|
||||||
}
|
|
||||||
|
|
||||||
this.SidedrawerController = {
|
return <div
|
||||||
render: this._render,
|
key={sidedrawerId}
|
||||||
close: this._close
|
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 = () => {
|
componentWillUnmount = () => {
|
||||||
this.unlistenEscape()
|
this.unlistenEscape()
|
||||||
}
|
}
|
||||||
|
|
||||||
_render = (component) => {
|
drawerIsLocked = (id) => {
|
||||||
this.listenEscape()
|
return this.state.lockedIds.includes(id)
|
||||||
this.setState({ render: component })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close = () => {
|
lockDrawerId = (id) => {
|
||||||
this.unlistenEscape()
|
this.setState({
|
||||||
this.setState({ render: null })
|
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 = () => {
|
listenEscape = () => {
|
||||||
document.addEventListener("keydown", this.handleKeyPress)
|
document.addEventListener("keydown", this.handleEscKeyPress)
|
||||||
}
|
}
|
||||||
|
|
||||||
unlistenEscape = () => {
|
unlistenEscape = () => {
|
||||||
document.removeEventListener("keydown", this.handleKeyPress)
|
document.removeEventListener("keydown", this.handleEscKeyPress)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKeyPress = (event) => {
|
handleEscKeyPress = (event) => {
|
||||||
// avoid handle keypress when is nothing to render
|
// avoid handle keypress when is nothing to render
|
||||||
if (!this.state.render) {
|
if (this.state.drawers.length === 0) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,27 +211,16 @@ export default class Sidedrawer extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isEscape) {
|
if (isEscape) {
|
||||||
|
// close the last opened drawer
|
||||||
this.close()
|
this.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderComponent = (component) => {
|
|
||||||
if (!component) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (React.isValidElement(component)) {
|
|
||||||
return React.cloneElement(component)
|
|
||||||
}
|
|
||||||
|
|
||||||
return React.createElement(component)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return <div
|
||||||
<div ref={this.containerRef} className={classnames("sidedrawer", { hided: !this.state.render })}>
|
className="sidedrawers-wrapper"
|
||||||
<React.Fragment>{this.renderComponent(this.state.render)}</React.Fragment>
|
>
|
||||||
</div>
|
{this.state.drawers}
|
||||||
)
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,21 +1,37 @@
|
|||||||
@import "theme/vars.less";
|
@import "theme/vars.less";
|
||||||
|
|
||||||
.sidedrawer {
|
.sidedrawers-wrapper {
|
||||||
width: 30vw; // by default
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
background-color: var(--sidedrawer-background-color);
|
.sidedrawer {
|
||||||
border-radius: @app_sidebar_borderRadius 0 0 @app_sidebar_borderRadius;
|
position: relative;
|
||||||
|
|
||||||
word-break: break-all;
|
width: 30vw; // by default
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
transition: all 150ms ease-out;
|
min-width: 700px;
|
||||||
|
|
||||||
padding: 20px;
|
z-index: 20;
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: overlay;
|
|
||||||
|
|
||||||
&.hided {
|
background-color: var(--sidedrawer-background-color);
|
||||||
width: 0;
|
border-radius: 0 @app_sidebar_borderRadius @app_sidebar_borderRadius 0;
|
||||||
padding: 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