diff --git a/src/App.js b/src/App.js
index 584a5c2..8b4b232 100644
--- a/src/App.js
+++ b/src/App.js
@@ -19,6 +19,9 @@ function App() {
* @type {Canvas | null>}
*/
const canvasRef = useRef()
+ const widgetOverlayRef = useRef()
+ const [initialPosition, setInitialPosition] = useState({ x: 0, y: 0 })
+
const [uploadedAssets, setUploadedAssets] = useState([]) // a global storage for assets, since redux can't store files(serialize files)
@@ -56,9 +59,23 @@ function App() {
console.log("Drag start: ", event)
const draggedItem = sidebarWidgets.find((item) => item.name === event.active.id)
setActiveSidebarWidget(draggedItem)
+
+ const activeItemElement = widgetOverlayRef.current
+
+ if (activeItemElement) {
+ const rect = activeItemElement.getBoundingClientRect()
+
+ // Store the initial position of the dragged element
+ setInitialPosition({
+ x: rect.left,
+ y: rect.top,
+ })
+ }
}
const handleDragMove = (event) => {
+
+ // console.log("drag move: ", event)
}
const handleDragEnd = (event) => {
@@ -67,10 +84,11 @@ function App() {
const {active, over, delta, activatorEvent} = event
const widgetItem = active.data.current?.title
- const activeItemElement = document.getElementById(`${active.id}`)
+ const activeItemElement = widgetOverlayRef.current
- // console.log("ended: ", activatorEvent, "delta", delta, "drag ended: ", event, "active: ", active, "over: ", over)
- console.log("over: ", active, over, activeItemElement)
+
+ console.log("ended: ", activatorEvent.clientX, activatorEvent.clientY)
+ // console.log("over: ", active, over, activeItemElement)
if (over?.id !== "canvas-droppable" || !widgetItem) {
setDropAnimation({ duration: 250, easing: "ease" })
return
@@ -79,34 +97,40 @@ function App() {
// FIXME: drop offset is not correct
// Calculate the dragged item's bounding rectangle
- // const itemRect = activeItemElement.getBoundingClientRect();
- // const itemCenterX = itemRect.left + itemRect.width / 2
- // const itemCenterY = itemRect.top + itemRect.height / 2
+ const itemRect = activeItemElement.getBoundingClientRect();
+ const itemCenterX = itemRect.left + itemRect.width / 2
+ const itemCenterY = itemRect.top + itemRect.height / 2
+
+ console.log("widget overlay: ", delta, itemRect)
+
- // // Calculate cursor position relative to the canvas
- // const cursorX = activatorEvent.clientX
- // const cursorY = activatorEvent.clientY
-
- // // Calculate the offset from the center of the item to the cursor
- // const offsetX = cursorX - itemCenterX
- // const offsetY = cursorY - itemCenterY
+ // Get widget dimensions (assuming you have a way to get these)
+ const widgetWidth = activeItemElement.offsetWidth; // Adjust this based on how you get widget size
+ const widgetHeight = activeItemElement.offsetHeight; // Adjust this based on how you get widget size
+
const canvasContainerRect = canvasRef.current.getCanvasContainerBoundingRect()
const canvasTranslate = canvasRef.current.getCanvasTranslation()
const zoom = canvasRef.current.getZoom()
+ // let finalPosition = {
+ // x: (delta.x - canvasContainerRect.x - canvasTranslate.x) / zoom,
+ // y: (delta.y - canvasContainerRect.y - canvasTranslate.y) / zoom,
+ // }
+
let finalPosition = {
- x: (delta.x - canvasContainerRect.x - canvasTranslate.x) / zoom,
- y: (delta.y - canvasContainerRect.y - canvasTranslate.y) / zoom,
+ x: (initialPosition.x + delta.x - canvasContainerRect.x - canvasTranslate.x) / zoom - (widgetWidth / 2),
+ y: (initialPosition.y + delta.y - canvasContainerRect.y - canvasTranslate.y) / zoom - (widgetHeight / 2),
}
+
// find the center of the active widget then set the final position
// finalPosition = {
// finalPosition
// }
- // console.log("drop position: ", "delta: ", delta, "activator", canvasContainerRect, canvasTranslate,)
+ console.log("drop position: ", "delta: ", delta, "activator", finalPosition, canvasTranslate,)
canvasRef.current.addWidget(Widget, ({id, widgetRef}) => {
widgetRef.current.setPos(finalPosition.x, finalPosition.y)
@@ -126,7 +150,7 @@ function App() {
-
{/* dragOverlay (dnd-kit) helps move items from one container to another */}
-
+
{activeSidebarWidget ? (
):
null}
diff --git a/src/canvas/canvas.js b/src/canvas/canvas.js
index 3537dee..76cb632 100644
--- a/src/canvas/canvas.js
+++ b/src/canvas/canvas.js
@@ -2,13 +2,14 @@ import React from "react"
import {DndContext} from '@dnd-kit/core'
-import { CloseOutlined, FullscreenOutlined, ReloadOutlined } from "@ant-design/icons"
+import { CloseOutlined, DeleteOutlined, EditOutlined, FullscreenOutlined, ReloadOutlined } from "@ant-design/icons"
import { Button, Tooltip, Dropdown } from "antd"
import Droppable from "../components/utils/droppable"
import Widget from "./widgets/base"
import Cursor from "./constants/cursor"
import { UID } from "../utils/uid"
+import { removeDuplicateObjects } from "../utils/common"
const CanvasModes = {
@@ -71,6 +72,8 @@ class Canvas extends React.Component {
this.fitCanvasToBoundingBox = this.fitCanvasToBoundingBox.bind(this)
this.getCanvasBoundingRect = this.getCanvasContainerBoundingRect.bind(this)
+ this.deleteSelectedWidgets = this.deleteSelectedWidgets.bind(this)
+ this.removeWidget = this.removeWidget.bind(this)
this.clearSelections = this.clearSelections.bind(this)
this.clearCanvas = this.clearCanvas.bind(this)
@@ -159,19 +162,23 @@ class Canvas extends React.Component {
if (selectedWidget){
// if the widget is selected don't pan, instead move the widget
if (!selectedWidget._disableSelection){
- selectedWidget.select()
- if (this.selectedWidgets.length >= 1){ // allow only one selection for now
- this.clearSelections()
+ const selectedLength = this.selectedWidgets.length
+
+ if (selectedLength === 0 || (selectedLength === 1 && selectedWidget.__id !== this.selectedWidgets[0].__id)){
+ this.selectedWidgets[0]?.deSelect() // deselect the previous widget before adding the new one
+ this.selectedWidgets[0]?.setZIndex(0)
+
+ selectedWidget.setZIndex(1000)
+ selectedWidget.select()
+ this.selectedWidgets[0] = selectedWidget
}
-
- this.selectedWidgets.push(selectedWidget)
this.currentMode = CanvasModes.MOVE_WIDGET
}
this.currentMode = CanvasModes.PAN
- }else if (this.state?.widgets?.length > 0){
+ }else if (!selectedWidget){
// get the canvas ready to pan, if there are widgets on the canvas
this.clearSelections()
this.currentMode = CanvasModes.PAN
@@ -187,24 +194,36 @@ class Canvas extends React.Component {
// })
}else if (event.button === 2){
//right click
- if (selectedWidget)
- this.setState({
- contextMenuItems: [{
- key: "delete",
- label: "Delete"
- }]
- })
+
+ if (this.selectedWidgets.length > 0 && this.selectedWidgets[0].__id !== selectedWidget.__id){
+ this.clearSelections()
+ }
- // this.setState({
- // showContextMenu: true
- // })
- console.log("button: ", selectedWidget)
+ if (selectedWidget)
+ this.selectedWidgets[0] = selectedWidget
+ console.log("renaming: ", selectedWidget)
+ this.setState({
+ contextMenuItems: [
+ {
+ key: "rename",
+ label: ( selectedWidget.openRenaming()}> Rename
),
+ icons: ,
+ },
+ {
+ key: "delete",
+ label: ( this.deleteSelectedWidgets([selectedWidget])}> Delete
),
+ icons: ,
+ danger: true
+ }
+ ]
+ })
}
}
mouseMoveEvent(event){
+
// console.log("mode: ", this.currentMode, this.getActiveObjects())
if (this.mousePressed && [CanvasModes.PAN, CanvasModes.MOVE_WIDGET].includes(this.currentMode)) {
const deltaX = event.clientX - this.mousePos.x
@@ -401,16 +420,38 @@ class Canvas extends React.Component {
return {id, widgetRef}
}
+ deleteSelectedWidgets(widgets){
+
+
+ let activeWidgets = removeDuplicateObjects([...widgets, ...this.selectedWidgets], "__id")
+ console.log("active widget: ", widgets, activeWidgets)
+ const widgetIds = activeWidgets.map(widget => widget.__id)
+
+ for (let widgetId of widgetIds){
+ console.log("removed: ", widgetId)
+
+ // this.widgetRefs[widgetId]?.current.remove()
+ delete this.widgetRefs[widgetId]
+
+ this.setState((prevState) => ({
+ widgets: prevState.widgets.filter(widget => widget.id !== widgetId)
+ }))
+ // value.current?.remove()
+ }
+
+ }
+
/**
* removes all the widgets from the canvas
*/
clearCanvas(){
- for (let [key, value] of Object.entries(this.widgetRefs)){
- console.log("removed: ", value, value.current?.getElement())
+ // NOTE: Don't remove from it using remove() function since, it already removed from the DOM tree when its removed from widgets
+ // for (let [key, value] of Object.entries(this.widgetRefs)){
+ // console.log("removed: ", value, value.current?.getElement())
- value.current?.remove()
- }
+ // value.current?.remove()
+ // }
this.widgetRefs = {}
this.setState(() => ({
@@ -422,7 +463,7 @@ class Canvas extends React.Component {
removeWidget(widgetId){
- this.widgetRefs[widgetId]?.current.remove()
+ // this.widgetRefs[widgetId]?.current.remove()
delete this.widgetRefs[widgetId]
this.setState((prevState) => ({
@@ -454,7 +495,7 @@ class Canvas extends React.Component {
-
+
0 ? value : prev.widgetName
}))
}
-
+ // console.log("selected: ", this.state.selected)
return (
diff --git a/src/components/cards.js b/src/components/cards.js
index 6595281..8ee0b01 100644
--- a/src/components/cards.js
+++ b/src/components/cards.js
@@ -6,7 +6,7 @@ import { FileImageOutlined, GithubOutlined, GitlabOutlined, LinkOutlined,
FileTextOutlined} from "@ant-design/icons"
-export function DraggableWidgetCard({ name, img, url}){
+export function DraggableWidgetCard({ name, img, url, innerRef}){
const urlIcon = useMemo(() => {
if (url){
@@ -29,7 +29,7 @@ export function DraggableWidgetCard({ name, img, url}){
return (
-

diff --git a/src/components/editableDiv.js b/src/components/editableDiv.js
index 3230510..da88e6b 100644
--- a/src/components/editableDiv.js
+++ b/src/components/editableDiv.js
@@ -1,8 +1,8 @@
import React, { useState, useRef, useEffect } from 'react'
-function EditableDiv({value, onChange, maxLength=Infinity, className='', inputClassName}) {
- const [isEditable, setIsEditable] = useState(false)
+function EditableDiv({value, onChange, openEdit=false, maxLength=Infinity, className='', inputClassName}) {
+ const [isEditable, setIsEditable] = useState(openEdit)
const [content, setContent] = useState(value)
const inputRef = useRef(null)
@@ -12,6 +12,17 @@ function EditableDiv({value, onChange, maxLength=Infinity, className='', inputCl
}, [value])
+ useEffect(() => {
+ setIsEditable(openEdit)
+
+ if (openEdit){
+ setTimeout(() => {
+ inputRef.current.focus()
+ }, 15)
+ }
+
+ }, [openEdit])
+
const handleInput = (event) => {
console.log("Event key: ", event.key)
diff --git a/src/components/utils/draggable.js b/src/components/utils/draggable.js
index 1639494..7cca531 100644
--- a/src/components/utils/draggable.js
+++ b/src/components/utils/draggable.js
@@ -14,10 +14,10 @@ function Draggable(props) {
return (
)
diff --git a/src/utils/common.js b/src/utils/common.js
new file mode 100644
index 0000000..b9b302d
--- /dev/null
+++ b/src/utils/common.js
@@ -0,0 +1,14 @@
+// contains commonly used functions to manipulate objects, array etc.
+
+
+export function removeDuplicateObjects(array, key) {
+ const seen = new Set()
+
+ return array.filter(item => {
+ if (!seen.has(item[key])) {
+ seen.add(item[key])
+ return true
+ }
+ return false
+ })
+}
\ No newline at end of file