fix: fixed issue with pack manager
This commit is contained in:
@@ -135,7 +135,6 @@ class Canvas extends React.Component {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
console.log("unmounted")
|
||||
|
||||
this.canvasContainerRef.current.removeEventListener("mousedown", this.mouseDownEvent)
|
||||
this.canvasContainerRef.current.removeEventListener("mouseup", this.mouseUpEvent)
|
||||
@@ -1210,6 +1209,53 @@ class Canvas extends React.Component {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the widget's initial data, else when there is a remount, you'll loose all the state
|
||||
*
|
||||
* TODO: Find a efficient way to call this function
|
||||
*
|
||||
* NOTE: this would cause entire widgetList to remount
|
||||
* NOTE: this would cause the toolbar to loose active widget
|
||||
*/
|
||||
updateWidgetData = (widgetId, latestData) => {
|
||||
|
||||
const widgetObj = this.getWidgetById(widgetId)?.current
|
||||
// console.log("Data unmount: ", this.widgets, this.widgetRefs, widgetObj, widgetId, widgetObj?.serialize(), latestData)
|
||||
|
||||
if (!widgetObj){
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
this.setWidgets(prevWidgets => {
|
||||
const updateWidget = (widgets) => {
|
||||
return widgets.map(widget => {
|
||||
if (widget.id === widgetId) {
|
||||
return {
|
||||
...widget,
|
||||
initialData: {
|
||||
...widget.initialData,
|
||||
...widgetObj.serialize()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (widget.children && widget.children.length > 0) {
|
||||
return {
|
||||
...widget,
|
||||
children: updateWidget(widget.children) // Always return new children
|
||||
};
|
||||
}
|
||||
|
||||
return widget; // Return unchanged widget
|
||||
});
|
||||
};
|
||||
|
||||
return updateWidget(prevWidgets);
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
renderWidget = (widget) => {
|
||||
|
||||
@@ -1252,19 +1298,25 @@ class Canvas extends React.Component {
|
||||
pan: this.state.currentTranslate
|
||||
}}
|
||||
|
||||
|
||||
onSelect={handleWidgetSelect}
|
||||
|
||||
onWidgetDeleteRequest={this.removeWidget}
|
||||
|
||||
onPanToWidget={this.panToWidget}
|
||||
|
||||
requestWidgetDataUpdate={this.updateWidgetData}
|
||||
// onWidgetUpdate={this.onActiveWidgetUpdate}
|
||||
// onWidgetUpdate={this.updateWidgetDataOnUnmount}
|
||||
// onUnmount={this.updateWidgetDataOnUnmount}
|
||||
|
||||
onWidgetUpdate={this.onActiveWidgetUpdate}
|
||||
onAddChildWidget={this.handleAddWidgetChild}
|
||||
onCreateWidgetRequest={this.createWidget} // create widget when dropped from sidebar
|
||||
onWidgetResizing={(resizeSide) => this.setState({ widgetResizing: resizeSide })}
|
||||
// onWidgetDragStart={() => this.setState({isWidgetDragging: true})}
|
||||
// onWidgetDragEnd={() => this.setState({isWidgetDragging: false})}
|
||||
onLayoutUpdate={this.updateChildLayouts}
|
||||
|
||||
>
|
||||
{/* Render children inside the parent with layout applied */}
|
||||
{renderChildren(children)}
|
||||
|
||||
@@ -15,7 +15,7 @@ import { AudioOutlined, FileImageOutlined, FileTextOutlined, VideoCameraOutlined
|
||||
import { useWidgetContext } from "./context/widgetContext.js"
|
||||
|
||||
|
||||
// FIXME: Maximum recursion error
|
||||
// FIXME: input cursors problem
|
||||
// FIXME: Every time the parent attrs are changed a remount happens, which causes input cursor to go to the end
|
||||
/**
|
||||
*
|
||||
@@ -340,10 +340,12 @@ const CanvasToolBar = memo(({ isOpen, widgetType, }) => {
|
||||
|
||||
|
||||
const renderToolbar = (obj, parentKey = "", toolCount=0) => {
|
||||
// console.log("obj: ", obj)
|
||||
const keys = []
|
||||
|
||||
return Object.entries(obj).map(([key, val], i) => {
|
||||
const keyName = parentKey ? `${parentKey}.${key}` : key
|
||||
// console.log("obj2: ", key, val)
|
||||
|
||||
// Highlight outer labels in blue for first-level keys
|
||||
const isFirstLevel = parentKey === ""
|
||||
@@ -352,6 +354,10 @@ const CanvasToolBar = memo(({ isOpen, widgetType, }) => {
|
||||
? "tw-text-sm tw-text-black tw-font-medium"
|
||||
: "tw-text-sm"
|
||||
|
||||
if (!val?.label){
|
||||
return null
|
||||
}
|
||||
|
||||
// Render tool widgets
|
||||
if (typeof val === "object" && val.tool) {
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import React from "react"
|
||||
import { NotImplementedError } from "../../utils/errors"
|
||||
|
||||
@@ -25,7 +27,7 @@ import { Layout, message } from "antd"
|
||||
|
||||
const ATTRS_KEYS = ['value', 'label', 'tool', 'onChange', 'options', 'toolProps'] // these are attrs keywords, don't use these keywords as keys while defining the attrs property or serializing
|
||||
|
||||
|
||||
// FIXME: the initial data in canvas should be updated so when it remounts the widget doesn't change state
|
||||
/**
|
||||
* Base class to be extended
|
||||
*/
|
||||
@@ -78,6 +80,8 @@ class Widget extends React.Component {
|
||||
selected: false,
|
||||
isWidgetVisible: true,
|
||||
|
||||
forceRerenderId: "",
|
||||
|
||||
widgetName: widgetName || 'widget', // this will later be converted to variable name
|
||||
enableRename: false, // will open the widgets editable div for renaming
|
||||
|
||||
@@ -202,13 +206,13 @@ class Widget extends React.Component {
|
||||
this.getRenderSize = this.getRenderSize.bind(this)
|
||||
this.getInnerRenderStyling = this.getInnerRenderStyling.bind(this)
|
||||
|
||||
this.updateState = this.updateState.bind(this)
|
||||
|
||||
this.stateUpdateCallback = null // allowing other components such as toolbar to subscribe to changes in this widget
|
||||
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
console.log("state layout: ")
|
||||
this.setLayout({layout: Layouts.FLEX, gap: 10})
|
||||
|
||||
// if (this.state.attrs.layout){
|
||||
@@ -226,8 +230,16 @@ class Widget extends React.Component {
|
||||
if (prevProps !== this.props) {
|
||||
this.canvasMetaData = this.props.canvasMetaData
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// componentWillUnmount(){
|
||||
// // TODO: serialize and store the widget data in setWidgets under widget context especially initialData
|
||||
// console.log("unmounting widget: ", this.state.attrs, this.serialize())
|
||||
|
||||
// // this.props.onUnmount(this.__id, this.serialize())
|
||||
// }
|
||||
|
||||
|
||||
stateChangeSubscriberCallback = (callback) => {
|
||||
// NOTE: don't subscribe to multiple callbacks, only the last one will work
|
||||
@@ -241,25 +253,25 @@ class Widget extends React.Component {
|
||||
* @param {} newState - this can either be a callback or a new State like (prevState) => ({key: value})
|
||||
* @param {*} callback - callback to run after setState
|
||||
*/
|
||||
updateState = (newState, callback) => {
|
||||
|
||||
updateState(newState, callback){
|
||||
// console.trace("Callback trace");
|
||||
// debugger;
|
||||
|
||||
// FIXME: maximum recursion error when updating size, color etc
|
||||
this.setState(newState, () => {
|
||||
console.log("updatinhg./..: ", this.state)
|
||||
// console.log("updatinhg./..: ", this.state, newState)
|
||||
|
||||
const { onWidgetUpdate } = this.props
|
||||
|
||||
|
||||
if (this.stateUpdateCallback)
|
||||
this.stateUpdateCallback()
|
||||
|
||||
// FIXME: super inefficient
|
||||
// if (onWidgetUpdate) {
|
||||
// onWidgetUpdate(this.__id)
|
||||
// }
|
||||
|
||||
// const { activeWidgetId, updateToolAttrs } = this.context
|
||||
|
||||
// if (activeWidgetId === this.__id)
|
||||
// updateToolAttrs(this.getToolbarAttrs())
|
||||
|
||||
if (callback) callback()
|
||||
|
||||
})
|
||||
@@ -326,10 +338,13 @@ class Widget extends React.Component {
|
||||
...this.state.attrs,
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
forceRerender = () => {
|
||||
this.forceUpdate()
|
||||
// this.forceUpdate() // Don't use forceUpdate widgets will loose their states
|
||||
this.setState({forceRerenderId: `${uuidv4()}`})
|
||||
console.log("rerender")
|
||||
}
|
||||
|
||||
// TODO: add context menu items such as delete, add etc
|
||||
@@ -501,7 +516,6 @@ class Widget extends React.Component {
|
||||
setAttrValue(path, value, callback) {
|
||||
|
||||
this.updateState((prevState) => { // since the setState is Async only the prevState contains the latest state
|
||||
|
||||
const keys = path.split('.')
|
||||
const lastKey = keys.pop()
|
||||
|
||||
@@ -806,6 +820,7 @@ class Widget extends React.Component {
|
||||
// NOTE: when serializing make sure, you are only passing serializable objects not functions or other
|
||||
return ({
|
||||
zIndex: this.state.zIndex,
|
||||
selected: this.state.selected,
|
||||
widgetName: this.state.widgetName,
|
||||
pos: this.state.pos,
|
||||
size: this.state.size,
|
||||
@@ -814,7 +829,7 @@ class Widget extends React.Component {
|
||||
widgetOuterStyling: this.state.widgetOuterStyling,
|
||||
parentLayout: this.state.parentLayout,
|
||||
positionType: this.state.positionType,
|
||||
attrs: this.serializeAttrsValues() // makes sure that functions are not serialized
|
||||
attrs: this.serializeAttrsValues(), // makes sure that functions are not serialized
|
||||
})
|
||||
|
||||
}
|
||||
@@ -830,9 +845,9 @@ class Widget extends React.Component {
|
||||
|
||||
data = {...data} // create a shallow copy
|
||||
|
||||
const {attrs={}, pos={x: 0, y: 0}, parentLayout=null, ...restData} = data
|
||||
|
||||
const {attrs={}, selected, pos={x: 0, y: 0}, parentLayout=null, ...restData} = data
|
||||
|
||||
|
||||
let layoutUpdates = {
|
||||
parentLayout: parentLayout.layout || null
|
||||
}
|
||||
@@ -887,6 +902,10 @@ class Widget extends React.Component {
|
||||
|
||||
this.updateState({ attrs: newAttrs }, callback)
|
||||
|
||||
if (selected){
|
||||
this.select()
|
||||
console.log("selected again")
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
@@ -1090,12 +1109,14 @@ class Widget extends React.Component {
|
||||
// console.log("Dropped on Sidebar: ", this.__id)
|
||||
|
||||
|
||||
const parentRect = this.getBoundingRect()
|
||||
// const parentRect = this.getBoundingRect()
|
||||
const canvasRect = this.props.canvasInnerContainerRef.current.getBoundingClientRect()
|
||||
|
||||
const {zoom, pan} = this.props.canvasMetaData
|
||||
|
||||
let initialPos = {
|
||||
x: (e.clientX - parentRect.left) / zoom,
|
||||
y: (e.clientY - parentRect.top) / zoom,
|
||||
x: (e.clientX - canvasRect.left) / zoom,
|
||||
y: (e.clientY - canvasRect.top) / zoom,
|
||||
}
|
||||
|
||||
this.props.onCreateWidgetRequest(widgetClass, {x: initialPos.x, y: initialPos.y},({ id, widgetRef }) => {
|
||||
|
||||
@@ -52,7 +52,7 @@ function Header({projectName, onProjectNameChange, framework, onFrameworkChange,
|
||||
tw-border-gray-400 tw-rounded-md tw-no-underline tw-border-solid hover:tw-bg-[#9333EA]
|
||||
hover:tw-text-white tw-duration-200
|
||||
tw-text-black tw-text-center tw-px-4 tw-text-sm tw-cursor-pointer">
|
||||
Join Waitlist
|
||||
Get Updates
|
||||
</button>
|
||||
<Premium className="tw-text-2xl tw-bg-purple-600 tw-text-center
|
||||
tw-w-[40px] tw-min-w-[40px] tw-h-[35px] tw-rounded-md
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Layouts, PosType } from "../../../canvas/constants/layouts"
|
||||
import Tools from "../../../canvas/constants/tools"
|
||||
import Widget from "../../../canvas/widgets/base"
|
||||
import { convertObjectToKeyValueString, isNumeric, removeKeyFromObject } from "../../../utils/common"
|
||||
import { randomArrayChoice } from "../../../utils/random"
|
||||
import { Tkinter_TO_WEB_CURSOR_MAPPING } from "../constants/cursor"
|
||||
import { Tkinter_To_GFonts } from "../constants/fontFamily"
|
||||
import { JUSTIFY, RELIEF } from "../constants/styling"
|
||||
@@ -16,13 +17,23 @@ export class TkinterBase extends Widget {
|
||||
super(props)
|
||||
|
||||
this.getLayoutCode = this.getLayoutCode.bind(this)
|
||||
|
||||
console.log("constructor 1: ", this.__id, this.state)
|
||||
|
||||
this.state = {
|
||||
...this.state,
|
||||
flexSide: "left"
|
||||
}
|
||||
|
||||
this.getPackSide = this.getPackSide.bind(this)
|
||||
this.renderTkinterLayout = this.renderTkinterLayout.bind(this)
|
||||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
console.log("unmounting from child: ", this.state.attrs, this.serialize(), this.__id)
|
||||
super.componentWillUnmount()
|
||||
}
|
||||
|
||||
getLayoutCode(){
|
||||
const {layout: parentLayout, direction, gap, align="start"} = this.getParentLayout()
|
||||
|
||||
@@ -102,10 +113,14 @@ export class TkinterBase extends Widget {
|
||||
}
|
||||
|
||||
getPackAttrs = () => {
|
||||
|
||||
return {
|
||||
// NOTE: tis returns (creates) a new object everytime causing unncessary renders
|
||||
return ({
|
||||
side: this.state.flexSide,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getPackSide(){
|
||||
return this.state.flexSide
|
||||
}
|
||||
|
||||
setParentLayout(layout){
|
||||
@@ -215,16 +230,23 @@ export class TkinterBase extends Widget {
|
||||
label: "Align Side",
|
||||
tool: Tools.SELECT_DROPDOWN,
|
||||
options: ["left", "right", "top", "bottom", ""].map(val => ({value: val, label: val})),
|
||||
value: "left",
|
||||
value: this.state.flexSide,
|
||||
onChange: (value) => {
|
||||
|
||||
console.log("call 0: ", value)
|
||||
// FIXME: force parent rerender because, here only child get rerendered, if only parent get rerendered the widget would move
|
||||
this.setAttrValue("flexManager.side", value)
|
||||
|
||||
this.setState({flexSide: value}, () => {
|
||||
console.log("updated side: ", this.state.attrs)
|
||||
setTimeout(this.props.parentWidgetRef.current.forceRerender, 1)
|
||||
this.setAttrValue("flexManager.side", value, () => {
|
||||
this.updateState({flexSide: value}, () => {
|
||||
console.log("call")
|
||||
this.props.requestWidgetDataUpdate(this.__id)
|
||||
this.stateChangeSubscriberCallback()
|
||||
// console.log("force rendering: ", this.state.flexSide)
|
||||
// this.props.parentWidgetRef.current.forceRerender()
|
||||
// setTimeout(, 1)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
// this.props.parentWidgetRef.current.forceRerender()
|
||||
// console.log("updateing state: ", value, this.props.parentWidgetRef.current)
|
||||
}
|
||||
@@ -345,29 +367,38 @@ export class TkinterBase extends Widget {
|
||||
// console.log("updated atters: ", this.state)
|
||||
// })
|
||||
|
||||
this.updateState((prevState) => ({...prevState, ...updates}))
|
||||
console.log('setting paret layiout')
|
||||
this.updateState((prevState) => ({...prevState, ...updates}), () => {
|
||||
console.log("updated layout state: ", this.state.attrs)
|
||||
})
|
||||
|
||||
|
||||
return updates
|
||||
}
|
||||
|
||||
renderTkinterLayout = () => {
|
||||
renderTkinterLayout(){
|
||||
const {layout, direction, gap} = this.getLayout()
|
||||
console.log("rendering: ", layout, this.state)
|
||||
if (layout === Layouts.FLEX){
|
||||
return (
|
||||
<>
|
||||
{["top", "bottom", "left", "right", "center"].map((pos) => (
|
||||
<div key={pos} style={this.getFlexLayoutStyle(pos)}>
|
||||
{this.props.children.filter(item => {
|
||||
const packAttrs = item.ref?.current?.getPackAttrs()
|
||||
console.log("side: ", packAttrs, item, item.ref?.current?.getPackAttrs())
|
||||
// const widgetSide = item.ref.current?.getAttrValue("flexManager.side") || "left"
|
||||
// console.log("widget side: ", item.ref.current?.__id, item.ref.current, item.ref.current.getAttrValue("flexManager.side"))
|
||||
return ((packAttrs?.side ) === pos)
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
{(this.props.children.length > 0) && ["top", "bottom", "left", "right", "center"].map((pos) => {
|
||||
|
||||
const filteredChildren = this.props.children.filter((item) => {
|
||||
const widgetRef = item.ref?.current
|
||||
if (!widgetRef) return false // Ensure ref exists before accessing
|
||||
|
||||
const packAttrs = widgetRef.getPackSide()// Cache value
|
||||
console.log("pack attrs: ", widgetRef.getPackSide())
|
||||
return packAttrs === pos
|
||||
})
|
||||
console.log("filtered children:", filteredChildren, pos)
|
||||
return (
|
||||
<div key={pos} style={this.getFlexLayoutStyle(pos)}>
|
||||
{filteredChildren}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -407,10 +438,6 @@ export class TkinterBase extends Widget {
|
||||
setLayout(value) {
|
||||
const { layout, direction, grid = { rows: 1, cols: 1 }, gap = 10, align } = value
|
||||
|
||||
console.log("setting layout: ", layout)
|
||||
|
||||
// FIXME the display grid is still flex
|
||||
// FIXME: this should be grid only when the widget accepts children else flex or something tp center
|
||||
// console.log("layout value: ", value)
|
||||
// FIXME: In grid layout the layout doesn't adapt to the size of the child if resized
|
||||
|
||||
@@ -505,8 +532,10 @@ export class TkinterBase extends Widget {
|
||||
|
||||
|
||||
serialize(){
|
||||
console.log("serialzied item: ", this.state.attrs, super.serialize(), this.__id, this.serializeAttrsValues())
|
||||
return ({
|
||||
...super.serialize(),
|
||||
attrs: this.serializeAttrsValues(), // makes sure that functions are not serialized
|
||||
flexSide: this.state.flexSide
|
||||
})
|
||||
}
|
||||
@@ -523,7 +552,10 @@ export class TkinterBase extends Widget {
|
||||
|
||||
data = {...data} // create a shallow copy
|
||||
|
||||
const {attrs={}, pos={x: 0, y: 0}, parentLayout=null, ...restData} = data
|
||||
console.log("data reloaded: ", data)
|
||||
|
||||
|
||||
const {attrs={}, selected, pos={x: 0, y: 0}, parentLayout=null, ...restData} = data
|
||||
|
||||
let layoutUpdates = {
|
||||
parentLayout: parentLayout
|
||||
@@ -551,14 +583,12 @@ export class TkinterBase extends Widget {
|
||||
pos
|
||||
}
|
||||
|
||||
console.log("data: ", newData)
|
||||
|
||||
this.setState(newData, () => {
|
||||
let layoutAttrs = this.setParentLayout(parentLayout).attrs || {}
|
||||
|
||||
// UPdates attrs
|
||||
let newAttrs = { ...this.state.attrs, ...layoutAttrs }
|
||||
console.log("new attrs: ", newAttrs, attrs)
|
||||
// Iterate over each path in the updates object
|
||||
Object.entries(attrs).forEach(([path, value]) => {
|
||||
const keys = path.split('.')
|
||||
@@ -582,9 +612,12 @@ export class TkinterBase extends Widget {
|
||||
// TODO: find a better way to apply innerStyles
|
||||
this.setWidgetInnerStyle("backgroundColor", newAttrs.styling.backgroundColor.value)
|
||||
}
|
||||
console.log("new arttrs: ", newData)
|
||||
this.updateState({ attrs: newAttrs }, callback)
|
||||
|
||||
if (selected){
|
||||
this.select()
|
||||
console.log("selected again")
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -51,10 +51,7 @@ function Premium({ children, className = "" }) {
|
||||
>
|
||||
more.
|
||||
</a>
|
||||
<div className="tw-text-sm tw-mt-2">
|
||||
Or you could support development by sharing this tool on your socials and you'll be eligible for a
|
||||
<a href="https://tally.so/r/mJM22X" target="_blank" rel="noreferrer noopener">free license</a>.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<section className="tw-mt-1 tw-flex tw-w-full tw-flex-col tw-place-items-center tw-p-[2%] max-lg:tw-p-2" id="pricing">
|
||||
@@ -300,6 +297,11 @@ function Premium({ children, className = "" }) {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="tw-text-sm tw-mt-4">
|
||||
Or you could support development by sharing this tool on your socials and you'll be eligible for a
|
||||
<a href="https://tally.so/r/mJM22X" target="_blank" rel="noreferrer noopener">free license</a>.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
5
src/utils/random.js
Normal file
5
src/utils/random.js
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
export function randomArrayChoice(arr){
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
}
|
||||
Reference in New Issue
Block a user