2024-08-08 16:21:19 +05:30
import React from "react"
import { NotImplementedError } from "../../utils/errors"
import Tools from "../constants/tools"
2024-09-19 19:26:10 +05:30
import { Layouts , PosType } from "../constants/layouts"
2024-08-08 16:21:19 +05:30
import Cursor from "../constants/cursor"
2024-09-09 19:06:03 +05:30
import { toSnakeCase } from "../utils/utils"
import EditableDiv from "../../components/editableDiv"
2024-09-16 22:04:24 +05:30
import DraggableWrapper from "../../components/draggable/draggable"
import DroppableWrapper from "../../components/draggable/droppable"
import { ActiveWidgetContext } from "../activeWidgetContext"
2024-09-17 11:55:21 +05:30
import { DragWidgetProvider } from "./draggableWidgetContext"
import WidgetDraggable from "./widgetDragDrop"
2024-09-19 19:26:10 +05:30
import WidgetContainer from "../constants/containers"
const ATTRS _KEYS = [ 'value' , 'label' , 'tool' , 'onChange' , 'toolProps' ] // these are attrs keywords, don't use these keywords as keys while defining the attrs property
2024-08-08 16:21:19 +05:30
/ * *
* Base class to be extended
* /
2024-09-15 12:08:29 +05:30
class Widget extends React . Component {
2024-08-08 16:21:19 +05:30
2024-08-08 22:49:14 +05:30
static widgetType = "widget"
2024-08-08 16:21:19 +05:30
2024-09-16 22:04:24 +05:30
// static contextType = ActiveWidgetContext
2024-09-15 12:08:29 +05:30
constructor ( props ) {
2024-08-08 16:21:19 +05:30
super ( props )
2024-08-08 22:49:14 +05:30
2024-09-15 12:08:29 +05:30
const { id , widgetName , canvasRef } = props
2024-09-12 19:20:46 +05:30
// console.log("Id: ", id)
2024-08-08 16:21:19 +05:30
// this id has to be unique inside the canvas, it will be set automatically and should never be changed
2024-08-08 22:49:14 +05:30
this . _ _id = id
2024-09-13 22:05:38 +05:30
this . canvas = canvasRef ? . current || null // canvasContainerRef, because some events work properly only if attached to the container
2024-09-09 19:06:03 +05:30
// this._selected = false
2024-08-08 16:21:19 +05:30
this . _disableResize = false
this . _disableSelection = false
2024-09-15 12:08:29 +05:30
this . minSize = { width : 50 , height : 50 } // disable resizing below this number
this . maxSize = { width : 500 , height : 500 } // disable resizing above this number
2024-09-10 21:34:05 +05:30
2024-08-08 16:21:19 +05:30
this . cursor = Cursor . POINTER
this . icon = "" // antd icon name representing this widget
2024-09-15 12:08:29 +05:30
this . elementRef = React . createRef ( )
2024-08-08 16:21:19 +05:30
this . functions = {
2024-09-15 12:08:29 +05:30
"load" : { "args1" : "number" , "args2" : "string" }
2024-08-08 16:21:19 +05:30
}
2024-09-18 22:16:34 +05:30
this . layout = Layouts . FLEX
2024-08-08 16:21:19 +05:30
this . boundingRect = {
x : 0 ,
y : 0 ,
height : 100 ,
width : 100
2024-09-15 12:08:29 +05:30
}
2024-08-08 16:21:19 +05:30
2024-08-08 22:49:14 +05:30
this . state = {
2024-09-09 19:06:03 +05:30
zIndex : 0 ,
selected : false ,
2024-09-15 12:08:29 +05:30
widgetName : widgetName || 'widget' , // this will later be converted to variable name
2024-09-13 12:28:32 +05:30
enableRename : false , // will open the widgets editable div for renaming
2024-09-17 18:32:33 +05:30
dragEnabled : true ,
2024-09-19 19:26:10 +05:30
widgetContainer : WidgetContainer . CANVAS , // what is the parent of the widget
2024-09-17 18:32:33 +05:30
showDroppableStyle : { // shows the droppable indicator
allow : false ,
show : false ,
} ,
2024-09-13 19:24:03 +05:30
2024-09-15 12:08:29 +05:30
pos : { x : 0 , y : 0 } ,
size : { width : 100 , height : 100 } ,
2024-09-19 19:26:10 +05:30
positionType : PosType . ABSOLUTE ,
2024-09-14 16:03:26 +05:30
2024-09-13 22:05:38 +05:30
widgetStyling : {
2024-09-14 16:03:26 +05:30
// use for widget's inner styling
2024-09-20 19:17:29 +05:30
backgroundColor : "#fff" ,
display : "flex" ,
flexDirection : "row" ,
gap : 10 ,
flexWrap : "wrap"
2024-09-13 22:05:38 +05:30
} ,
2024-09-15 12:08:29 +05:30
attrs : {
2024-09-13 19:24:03 +05:30
styling : {
backgroundColor : {
2024-09-14 16:03:26 +05:30
label : "Background Color" ,
2024-09-13 19:24:03 +05:30
tool : Tools . COLOR _PICKER , // the tool to display, can be either HTML ELement or a constant string
2024-09-20 15:12:43 +05:30
value : "#fff" ,
2024-09-16 22:04:24 +05:30
onChange : ( value ) => {
this . setWidgetStyling ( "backgroundColor" , value )
this . setAttrValue ( "styling.backgroundColor" , value )
}
2024-09-13 19:24:03 +05:30
} ,
foregroundColor : {
2024-09-14 16:03:26 +05:30
label : "Foreground Color" ,
2024-09-13 19:24:03 +05:30
tool : Tools . COLOR _PICKER ,
2024-09-19 19:26:10 +05:30
value : "#000" ,
2024-09-14 16:03:26 +05:30
} ,
2024-09-15 12:08:29 +05:30
label : "Styling"
2024-09-14 16:03:26 +05:30
} ,
layout : {
label : "Layout" ,
2024-09-18 22:16:34 +05:30
tool : Tools . LAYOUT _MANAGER , // the tool to display, can be either HTML ELement or a constant string
value : {
layout : "flex" ,
2024-09-20 15:12:43 +05:30
direction : "row" ,
2024-09-18 22:16:34 +05:30
grid : {
rows : 1 ,
cols : 1
2024-09-20 15:12:43 +05:30
} ,
gap : 10 ,
2024-09-18 22:16:34 +05:30
} ,
2024-09-19 19:26:10 +05:30
toolProps : {
options : [
{ value : "flex" , label : "Flex" } ,
{ value : "grid" , label : "Grid" } ,
{ value : "place" , label : "Place" } ,
] ,
} ,
2024-09-20 15:12:43 +05:30
onChange : ( value ) => {
// this.setAttrValue("layout", value)
this . setLayout ( value )
}
2024-09-13 19:24:03 +05:30
} ,
events : {
event1 : {
tool : Tools . EVENT _HANDLER ,
value : ""
}
}
} ,
2024-08-08 22:49:14 +05:30
}
2024-09-09 19:06:03 +05:30
this . mousePress = this . mousePress . bind ( this )
this . getElement = this . getElement . bind ( this )
2024-09-20 15:12:43 +05:30
this . getId = this . getId . bind ( this )
2024-09-15 12:08:29 +05:30
this . getPos = this . getPos . bind ( this )
this . getSize = this . getSize . bind ( this )
2024-09-13 16:03:58 +05:30
this . getWidgetName = this . getWidgetName . bind ( this )
this . getWidgetType = this . getWidgetType . bind ( this )
2024-09-15 12:08:29 +05:30
this . getBoundingRect = this . getBoundingRect . bind ( this )
this . getToolbarAttrs = this . getToolbarAttrs . bind ( this )
2024-09-13 12:28:32 +05:30
// this.openRenaming = this.openRenaming.bind(this)
2024-09-09 19:06:03 +05:30
this . isSelected = this . isSelected . bind ( this )
this . setPos = this . setPos . bind ( this )
2024-09-15 12:08:29 +05:30
this . setAttrValue = this . setAttrValue . bind ( this )
this . setWidgetName = this . setWidgetName . bind ( this )
2024-09-13 22:05:38 +05:30
this . setWidgetStyling = this . setWidgetStyling . bind ( this )
2024-09-19 19:26:10 +05:30
this . setPosType = this . setPosType . bind ( this )
2024-09-13 22:05:38 +05:30
2024-09-15 12:08:29 +05:30
}
2024-08-08 16:21:19 +05:30
2024-09-15 12:08:29 +05:30
componentDidMount ( ) {
2024-08-08 22:49:14 +05:30
this . elementRef . current ? . addEventListener ( "click" , this . mousePress )
2024-09-19 19:26:10 +05:30
2024-09-20 19:17:29 +05:30
// FIXME: initial layout is not set properly
console . log ( "prior layout: " , this . state . attrs . layout . value )
2024-09-20 15:12:43 +05:30
this . setLayout ( this . state . attrs . layout . value )
this . setWidgetStyling ( 'backgroundColor' , this . state . attrs . styling ? . backgroundColor . value || "#fff" )
this . load ( this . props . initialData || { } ) // load the initial data
2024-09-19 19:26:10 +05:30
2024-08-08 16:21:19 +05:30
}
2024-09-15 12:08:29 +05:30
componentWillUnmount ( ) {
2024-08-08 22:49:14 +05:30
this . elementRef . current ? . removeEventListener ( "click" , this . mousePress )
2024-08-08 16:21:19 +05:30
}
2024-09-16 22:04:24 +05:30
componentDidUpdate ( prevProps , prevState ) {
// if (prevState !== this.state) {
// // State has changed
// console.log('State has been updated')
// } else {
// // State has not changed
// console.log('State has not changed')
// }
}
2024-09-15 12:08:29 +05:30
updateState = ( newState , callback ) => {
2024-09-16 22:04:24 +05:30
// FIXME: maximum recursion error when updating size
2024-09-15 12:08:29 +05:30
this . setState ( newState , ( ) => {
2024-09-16 22:04:24 +05:30
2024-09-15 12:08:29 +05:30
const { onWidgetUpdate } = this . props
if ( onWidgetUpdate ) {
onWidgetUpdate ( this . _ _id )
}
2024-09-16 22:04:24 +05:30
// const { activeWidgetId, updateToolAttrs } = this.context
// if (activeWidgetId === this.__id)
// updateToolAttrs(this.getToolbarAttrs())
2024-09-15 12:08:29 +05:30
if ( callback ) callback ( )
2024-09-16 22:04:24 +05:30
2024-09-15 12:08:29 +05:30
} )
}
_getWidgetMethods = ( ) => {
return {
rename : this . setWidgetName ,
resize : this . setWidgetSize ,
setWidgetAttrs : this . setAttrValue ,
}
}
getToolbarAttrs ( ) {
return ( {
2024-09-20 15:12:43 +05:30
id : this . _ _id ,
2024-09-15 12:08:29 +05:30
widgetName : {
label : "Widget Name" ,
tool : Tools . INPUT , // the tool to display, can be either HTML ELement or a constant string
toolProps : { placeholder : "Widget name" , maxLength : 40 } ,
value : this . state . widgetName ,
onChange : ( value ) => this . setWidgetName ( value )
} ,
size : {
2024-09-16 22:04:24 +05:30
label : "Size" ,
2024-09-15 12:08:29 +05:30
display : "horizontal" ,
width : {
label : "Width" ,
tool : Tools . NUMBER _INPUT , // the tool to display, can be either HTML ELement or a constant string
toolProps : { placeholder : "width" , max : this . maxSize . width , min : this . minSize . width } ,
value : this . state . size . width || 100 ,
onChange : ( value ) => this . setWidgetSize ( value , null )
} ,
height : {
label : "Height" ,
tool : Tools . NUMBER _INPUT ,
2024-09-15 15:31:04 +05:30
toolProps : { placeholder : "height" , max : this . maxSize . height , min : this . minSize . height } ,
2024-09-15 12:08:29 +05:30
value : this . state . size . height || 100 ,
onChange : ( value ) => this . setWidgetSize ( null , value )
} ,
} ,
... this . state . attrs ,
} )
}
2024-09-09 19:06:03 +05:30
// TODO: add context menu items such as delete, add etc
2024-09-15 12:08:29 +05:30
contextMenu ( ) {
2024-09-09 19:06:03 +05:30
}
2024-09-15 12:08:29 +05:30
getVariableName ( ) {
2024-09-09 19:06:03 +05:30
return toSnakeCase ( this . state . widgetName )
}
2024-09-15 12:08:29 +05:30
getWidgetName ( ) {
2024-09-13 16:03:58 +05:30
return this . state . widgetName
}
2024-09-15 12:08:29 +05:30
getWidgetType ( ) {
2024-09-13 16:03:58 +05:30
return this . constructor . widgetType
}
2024-09-15 12:08:29 +05:30
getAttributes ( ) {
2024-09-13 19:24:03 +05:30
return this . state . attrs
}
2024-09-20 15:12:43 +05:30
getId ( ) {
return this . _ _id
}
2024-09-15 12:08:29 +05:30
mousePress ( event ) {
2024-09-09 19:06:03 +05:30
// event.preventDefault()
2024-09-15 12:08:29 +05:30
if ( ! this . _disableSelection ) {
2024-08-08 16:21:19 +05:30
}
}
2024-09-15 12:08:29 +05:30
select ( ) {
2024-09-09 19:24:43 +05:30
this . setState ( {
2024-09-09 19:06:03 +05:30
selected : true
2024-09-09 19:24:43 +05:30
} )
2024-09-15 12:08:29 +05:30
2024-08-08 16:21:19 +05:30
}
2024-09-15 12:08:29 +05:30
deSelect ( ) {
2024-09-09 19:24:43 +05:30
this . setState ( {
2024-09-09 19:06:03 +05:30
selected : false
2024-09-09 19:24:43 +05:30
} )
2024-09-09 19:06:03 +05:30
}
2024-09-15 12:08:29 +05:30
isSelected ( ) {
2024-09-09 19:06:03 +05:30
return this . state . selected
}
2024-09-19 19:26:10 +05:30
setPosType ( positionType ) {
if ( ! Object . values ( PosType ) . includes ( positionType ) ) {
throw Error ( ` The Position type can only be among: ${ Object . values ( PosType ) . join ( ", " ) } ` )
}
this . setState ( {
positionType : positionType
} )
}
2024-09-15 12:08:29 +05:30
setPos ( x , y ) {
2024-09-10 21:34:05 +05:30
2024-09-16 22:04:24 +05:30
this . setState ( {
2024-09-15 12:08:29 +05:30
pos : { x , y }
} )
2024-09-16 22:04:24 +05:30
// this.updateState({
// pos: { x, y }
// })
2024-09-12 22:09:13 +05:30
}
2024-09-09 19:06:03 +05:30
2024-09-15 12:08:29 +05:30
getPos ( ) {
2024-09-14 16:03:26 +05:30
return this . state . pos
2024-08-08 16:21:19 +05:30
}
2024-09-15 12:08:29 +05:30
getProps ( ) {
2024-09-09 19:06:03 +05:30
return this . attrs
2024-08-08 16:21:19 +05:30
}
2024-09-15 12:08:29 +05:30
getBoundingRect ( ) {
2024-09-10 21:34:05 +05:30
return this . elementRef . current ? . getBoundingClientRect ( )
}
2024-09-15 12:08:29 +05:30
getSize ( ) {
return this . state . size
2024-09-10 21:34:05 +05:30
}
2024-09-15 12:08:29 +05:30
getWidgetFunctions ( ) {
2024-08-08 16:21:19 +05:30
return this . functions
}
2024-09-15 12:08:29 +05:30
getId ( ) {
2024-08-08 16:21:19 +05:30
return this . _ _id
}
2024-09-15 12:08:29 +05:30
getElement ( ) {
2024-09-09 19:06:03 +05:30
return this . elementRef . current
}
2024-09-19 19:26:10 +05:30
getLayoutStyleForWidget = ( ) => {
switch ( this . state . attrs . layout ) {
case 'grid' :
return { display : 'grid' , gridTemplateColumns : 'repeat(2, 1fr)' , gap : '10px' }
case 'flex' :
return { display : 'flex' , flexDirection : 'row' , justifyContent : 'space-around' }
case 'absolute' :
return { position : 'absolute' , left : "0" , top : "0" } // Custom positioning
default :
return { }
}
}
2024-09-14 16:03:26 +05:30
/ * *
* Given the key as a path , sets the value for the widget attribute
* @ param { string } path - path to the key , eg : styling . backgroundColor
* @ param { any } value
* /
2024-09-15 12:08:29 +05:30
setAttrValue ( path , value ) {
2024-09-14 16:03:26 +05:30
this . setState ( ( prevState ) => {
// Split the path to access the nested property (e.g., "styling.backgroundColor")
const keys = path . split ( '.' )
const lastKey = keys . pop ( )
2024-09-15 12:08:29 +05:30
2024-09-14 16:03:26 +05:30
// Traverse the state and update the nested value immutably
let newAttrs = { ... prevState . attrs }
let nestedObject = newAttrs
2024-09-15 12:08:29 +05:30
2024-09-14 16:03:26 +05:30
keys . forEach ( key => {
nestedObject [ key ] = { ... nestedObject [ key ] } // Ensure immutability
nestedObject = nestedObject [ key ]
} )
nestedObject [ lastKey ] . value = value
2024-09-15 12:08:29 +05:30
2024-09-14 16:03:26 +05:30
return { attrs : newAttrs }
} )
}
2024-09-19 19:26:10 +05:30
/ * *
* returns the path from the serialized attrs values ,
* this is a helper function to remove any non - serializable data associated with attrs
* eg : { "styling.backgroundColor" : "#ffff" , "layout" : { layout : "flex" , direction : "" , grid : } }
* /
serializeAttrsValues = ( ) => {
const serializeValues = ( obj , currentPath = "" ) => {
const result = { }
for ( let key in obj ) {
if ( ATTRS _KEYS . includes ( key ) ) continue // don't serialize these as separate keys
if ( typeof obj [ key ] === 'object' && obj [ key ] !== null ) {
// If the key contains a value property
if ( obj [ key ] . hasOwnProperty ( 'value' ) ) {
const path = currentPath ? ` ${ currentPath } . ${ key } ` : key ;
// If the value is an object, retain the entire value object
if ( typeof obj [ key ] . value === 'object' && obj [ key ] . value !== null ) {
result [ path ] = obj [ key ] . value
} else {
result [ ` ${ path } ` ] = obj [ key ] . value
}
}
// Continue recursion for nested objects
Object . assign ( result , serializeValues ( obj [ key ] , currentPath ? ` ${ currentPath } . ${ key } ` : key ) )
}
}
return result
}
return serializeValues ( this . state . attrs )
}
2024-09-15 12:08:29 +05:30
setZIndex ( zIndex ) {
2024-09-13 12:28:32 +05:30
this . setState ( {
zIndex : zIndex
} )
}
2024-09-15 12:08:29 +05:30
setWidgetName ( name ) {
2024-09-14 16:03:26 +05:30
2024-09-15 12:08:29 +05:30
this . updateState ( {
widgetName : name . length > 0 ? name : this . state . widgetName
} )
2024-09-14 16:03:26 +05:30
}
2024-09-20 15:12:43 +05:30
setLayout ( value ) {
const { layout , direction , grid = { rows : 1 , cols : 1 } , gap = 10 } = value
const widgetStyle = {
... this . state . widgetStyling ,
display : layout ,
flexDirection : direction ,
gap : ` ${ gap } px ` ,
flexWrap : "wrap"
// TODO: add grid rows and cols
}
this . setAttrValue ( "layout" , value )
this . updateState ( {
widgetStyling : widgetStyle
} )
}
2024-09-15 12:08:29 +05:30
/ * *
*
* @ param { string } key - The string in react Style format
* @ param { string } value - Value of the style
* /
2024-09-16 22:04:24 +05:30
setWidgetStyling ( key , value ) {
2024-09-15 12:08:29 +05:30
const widgetStyle = {
... this . state . widgetStyling ,
[ key ] : value
}
this . setState ( {
widgetStyling : widgetStyle
} )
}
/ * *
*
* @ param { number | null } width
* @ param { number | null } height
* /
2024-09-16 22:04:24 +05:30
setWidgetSize ( width , height ) {
2024-09-15 12:08:29 +05:30
const newSize = {
width : Math . max ( this . minSize . width , Math . min ( width || this . state . size . width , this . maxSize . width ) ) ,
height : Math . max ( this . minSize . height , Math . min ( height || this . state . size . height , this . maxSize . height ) ) ,
}
this . updateState ( {
size : newSize
} )
2024-09-14 16:03:26 +05:30
}
2024-09-18 11:39:07 +05:30
setResize ( pos , size ) {
// useful when resizing the widget relative to the canvas, sets all pos, and size
2024-09-15 12:08:29 +05:30
this . updateState ( {
2024-09-18 11:39:07 +05:30
size : size ,
pos : pos
2024-09-15 12:08:29 +05:30
} )
2024-09-10 21:34:05 +05:30
}
2024-09-15 12:08:29 +05:30
openRenaming ( ) {
2024-09-13 12:28:32 +05:30
this . setState ( {
selected : true ,
enableRename : true
} )
}
2024-09-15 12:08:29 +05:30
closeRenaming ( ) {
2024-09-13 12:28:32 +05:30
this . setState ( {
enableRename : false
} )
}
2024-09-20 22:07:22 +05:30
enableDrag = ( ) => {
this . setState ( {
dragEnabled : true
} )
}
disableDrag = ( ) => {
this . setState ( {
dragEnabled : false
} )
}
2024-09-17 18:32:33 +05:30
handleDrop = ( event , dragElement ) => {
console . log ( "dragging event: " , event , dragElement )
const container = dragElement . getAttribute ( "data-container" )
2024-09-18 22:16:34 +05:30
// TODO: check if the drop is allowed
2024-09-17 18:32:33 +05:30
if ( container === "canvas" ) {
2024-09-18 22:16:34 +05:30
this . props . onAddChildWidget ( this . _ _id , dragElement . getAttribute ( "data-widget-id" ) )
} else if ( container === "sidebar" ) {
this . props . onAddChildWidget ( this . _ _id , null , true ) // if dragged from the sidebar create the widget first
2024-09-17 18:32:33 +05:30
}
2024-09-15 15:31:04 +05:30
}
2024-09-19 19:26:10 +05:30
/ * *
*
* serialize data for saving
* /
serialize = ( ) => {
// NOTE: when serializing make sure, you are only passing serializable objects not functions or other
return ( {
zIndex : this . state . zIndex ,
widgetName : this . state . widgetName ,
pos : this . state . pos ,
size : this . state . size ,
widgetContainer : this . state . widgetContainer ,
widgetStyling : this . state . widgetStyling ,
positionType : this . state . positionType ,
attrs : this . serializeAttrsValues ( ) // makes sure that functions are not serialized
} )
}
/ * *
* loads the data
* @ param { object } data
* /
load = ( data ) => {
2024-09-20 19:17:29 +05:30
if ( Object . keys ( data ) . length === 0 ) return // no data to load
2024-09-19 19:26:10 +05:30
for ( let [ key , value ] of Object . entries ( data . attrs | { } ) )
this . setAttrValue ( key , value )
2024-09-20 19:17:29 +05:30
delete data . attrs
2024-09-19 19:26:10 +05:30
/ * *
* const obj = { a : 1 , b : 2 , c : 3 }
* const { b , ... newObj } = obj
* console . log ( newObj ) // { a: 1, c: 3 }
* /
this . setState ( data )
}
// FIXME: children outside the bounding box
2024-09-15 12:08:29 +05:30
renderContent ( ) {
2024-08-08 16:21:19 +05:30
// throw new NotImplementedError("render method has to be implemented")
return (
2024-09-20 19:17:29 +05:30
< div className = "tw-w-full tw-h-full tw-p-2 tw-content-start tw-rounded-md" style = { this . state . widgetStyling } >
2024-09-19 19:26:10 +05:30
{ this . props . children }
2024-08-08 16:21:19 +05:30
< / d i v >
)
}
2024-09-15 15:31:04 +05:30
2024-08-08 16:21:19 +05:30
/ * *
* This is an internal methods don ' t override
* @ returns { HTMLElement }
* /
2024-09-15 12:08:29 +05:30
render ( ) {
2024-09-14 16:03:26 +05:30
let outerStyle = {
2024-08-08 16:21:19 +05:30
cursor : this . cursor ,
2024-09-13 12:28:32 +05:30
zIndex : this . state . zIndex ,
2024-09-19 19:26:10 +05:30
position : this . state . positionType , // don't change this if it has to be movable on the canvas
2024-09-15 12:08:29 +05:30
top : ` ${ this . state . pos . y } px ` ,
left : ` ${ this . state . pos . x } px ` ,
2024-09-14 16:03:26 +05:30
width : ` ${ this . state . size . width } px ` ,
height : ` ${ this . state . size . height } px ` ,
2024-08-08 16:21:19 +05:30
}
2024-09-20 22:07:22 +05:30
// console.log("selected: ", this.state.dragEnabled)
2024-08-08 16:21:19 +05:30
return (
2024-09-17 18:32:33 +05:30
< WidgetDraggable widgetRef = { this . elementRef }
enableDrag = { this . state . dragEnabled }
onDrop = { this . handleDrop }
onDragEnter = { ( { dragElement , showDrop } ) => {
this . setState ( {
showDroppableStyle : showDrop
} )
}
}
onDragLeave = { ( ) => {
this . setState ( {
showDroppableStyle : {
allow : false ,
show : false
}
} )
}
}
>
2024-09-17 11:55:21 +05:30
< div data - widget - id = { this . _ _id }
ref = { this . elementRef }
className = "tw-absolute tw-shadow-xl tw-w-fit tw-h-fit"
2024-09-16 22:04:24 +05:30
style = { outerStyle }
2024-09-17 11:55:21 +05:30
data - draggable - type = { this . getWidgetType ( ) } // helps with droppable
2024-09-19 19:26:10 +05:30
data - container = { this . state . widgetContainer } // indicates how the canvas should handle dragging, one is sidebar other is canvas
2024-09-16 22:04:24 +05:30
>
2024-09-20 22:07:22 +05:30
< div className = "tw-relative tw-w-full tw-h-full tw-top-0 tw-left-0"
>
2024-09-20 19:17:29 +05:30
{ this . renderContent ( ) }
2024-09-19 19:26:10 +05:30
{
// show drop style on drag hover
this . state . showDroppableStyle . show &&
< div className = { ` ${ this . state . showDroppableStyle . allow ? "tw-border-blue-600" : "tw-border-red-600" }
tw - absolute tw - top - [ - 5 px ] tw - left - [ - 5 px ] tw - w - full tw - h - full tw - z - [ 2 ]
tw - border - 2 tw - border - dashed tw - rounded - lg tw - pointer - events - none
` }
style = {
{
width : "calc(100% + 10px)" ,
height : "calc(100% + 10px)" ,
}
2024-09-17 18:32:33 +05:30
}
2024-09-20 19:17:29 +05:30
>
2024-09-19 19:26:10 +05:30
< / d i v >
}
< div className = { ` tw-absolute tw-bg-transparent tw-scale-[1.1] tw-opacity-100
tw - w - full tw - h - full tw - top - 0
$ { this . state . selected ? 'tw-border-2 tw-border-solid tw-border-blue-500' : 'tw-hidden' } ` }>
< div className = "tw-relative tw-w-full tw-h-full" >
< EditableDiv value = { this . state . widgetName } onChange = { this . setWidgetName }
maxLength = { 40 }
openEdit = { this . state . enableRename }
className = " tw - text - sm tw - w - fit tw - max - w - [ 160 px ] tw - text - clip tw - min - w - [ 150 px ]
tw - overflow - hidden tw - absolute tw -- top - 6 tw - h - 6 "
/ >
< div
className = "tw-w-2 tw-h-2 tw-absolute tw--left-1 tw--top-1 tw-bg-blue-500"
style = { { cursor : Cursor . NW _RESIZE } }
onMouseDown = { ( e ) => {
2024-09-20 19:17:29 +05:30
e . stopPropagation ( )
e . preventDefault ( )
2024-09-19 19:26:10 +05:30
this . props . onWidgetResizing ( "nw" )
this . setState ( { dragEnabled : false } )
} }
2024-09-20 19:17:29 +05:30
onMouseUp = { ( ) => this . setState ( { dragEnabled : true } ) }
2024-09-19 19:26:10 +05:30
/ >
< div
className = "tw-w-2 tw-h-2 tw-absolute tw--right-1 tw--top-1 tw-bg-blue-500"
style = { { cursor : Cursor . SW _RESIZE } }
onMouseDown = { ( e ) => {
2024-09-20 19:17:29 +05:30
e . stopPropagation ( )
e . preventDefault ( )
2024-09-19 19:26:10 +05:30
this . props . onWidgetResizing ( "ne" )
this . setState ( { dragEnabled : false } )
} }
2024-09-20 19:17:29 +05:30
onMouseUp = { ( ) => this . setState ( { dragEnabled : true } ) }
2024-09-19 19:26:10 +05:30
/ >
< div
className = "tw-w-2 tw-h-2 tw-absolute tw--left-1 tw--bottom-1 tw-bg-blue-500"
style = { { cursor : Cursor . SW _RESIZE } }
onMouseDown = { ( e ) => {
2024-09-20 19:17:29 +05:30
e . stopPropagation ( )
e . preventDefault ( )
2024-09-19 19:26:10 +05:30
this . props . onWidgetResizing ( "sw" )
this . setState ( { dragEnabled : false } )
} }
2024-09-20 19:17:29 +05:30
onMouseUp = { ( ) => this . setState ( { dragEnabled : true } ) }
2024-09-19 19:26:10 +05:30
/ >
< div
className = "tw-w-2 tw-h-2 tw-absolute tw--right-1 tw--bottom-1 tw-bg-blue-500"
style = { { cursor : Cursor . SE _RESIZE } }
onMouseDown = { ( e ) => {
2024-09-20 19:17:29 +05:30
e . stopPropagation ( )
e . preventDefault ( )
2024-09-19 19:26:10 +05:30
this . props . onWidgetResizing ( "se" )
this . setState ( { dragEnabled : false } )
} }
2024-09-20 19:17:29 +05:30
onMouseUp = { ( ) => this . setState ( { dragEnabled : true } ) }
2024-09-19 19:26:10 +05:30
/ >
2024-09-17 18:32:33 +05:30
< / d i v >
2024-09-16 22:04:24 +05:30
< / d i v >
2024-08-08 16:21:19 +05:30
2024-09-09 19:06:03 +05:30
2024-09-16 22:04:24 +05:30
< / d i v >
2024-08-08 16:21:19 +05:30
< / d i v >
2024-09-17 11:55:21 +05:30
< / W i d g e t D r a g g a b l e >
2024-08-08 16:21:19 +05:30
)
}
2024-09-15 12:08:29 +05:30
}
2024-08-08 16:21:19 +05:30
export default Widget