fix: added fit-content for width and height.
fixed button and label centering for tkinter widgets
This commit is contained in:
@@ -774,7 +774,6 @@ class Canvas extends React.Component {
|
||||
|
||||
const parentWidget = this.widgetRefs[parentWidgetId].current
|
||||
const parentRect = parentWidget.getBoundingRect()
|
||||
const canvasRect = this.canvasRef.current.getBoundingClientRect()
|
||||
const { clientX, clientY } = event
|
||||
|
||||
|
||||
@@ -782,7 +781,7 @@ class Canvas extends React.Component {
|
||||
x: (clientX - parentRect.left) / this.state.zoom,
|
||||
y: (clientY - parentRect.top) / this.state.zoom,
|
||||
}
|
||||
|
||||
// TODO: fix swapping for grid layouts
|
||||
if (swap) {
|
||||
// If swapping, we need to find the common parent
|
||||
const grandParentWidgetObj = this.findWidgetFromListById(dropWidgetObj.parent)
|
||||
|
||||
@@ -12,10 +12,11 @@ import { DragWidgetProvider } from "./draggableWidgetContext"
|
||||
import WidgetDraggable from "./widgetDragDrop"
|
||||
import WidgetContainer from "../constants/containers"
|
||||
import { DragContext } from "../../components/draggable/draggableContext"
|
||||
import { removeKeyFromObject } from "../../utils/common"
|
||||
import { isNumeric, removeKeyFromObject } from "../../utils/common"
|
||||
|
||||
// FIXME: make it possible to have fit-width and height
|
||||
// FIXME: widget styling not being applied if directly added to child instead of the canvas
|
||||
|
||||
// TODO: make it possible to apply widgetInnerStyle on load
|
||||
|
||||
const ATTRS_KEYS = ['value', 'label', 'tool', 'onChange', 'toolProps'] // these are attrs keywords, don't use these keywords as keys while defining the attrs property
|
||||
|
||||
@@ -63,12 +64,12 @@ class Widget extends React.Component {
|
||||
// This indicates if the draggable can be dropped on this widget, set this to null to disable drops
|
||||
this.droppableTags = {}
|
||||
|
||||
this.boundingRect = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
height: 100,
|
||||
width: 100
|
||||
}
|
||||
// this.boundingRect = {
|
||||
// x: 0,
|
||||
// y: 0,
|
||||
// height: 100,
|
||||
// width: 100
|
||||
// }
|
||||
|
||||
this.state = {
|
||||
zIndex: 0,
|
||||
@@ -178,6 +179,10 @@ class Widget extends React.Component {
|
||||
|
||||
this.setPosType = this.setPosType.bind(this)
|
||||
this.setParentLayout = this.setParentLayout.bind(this)
|
||||
|
||||
this.load = this.load.bind(this)
|
||||
this.serialize = this.serialize.bind(this)
|
||||
this.serializeAttrsValues = this.serializeAttrsValues.bind(this)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -186,7 +191,7 @@ class Widget extends React.Component {
|
||||
|
||||
if (this.state.attrs.layout){
|
||||
this.setLayout(this.state.attrs.layout.value)
|
||||
console.log("prior layout: ", this.state.attrs.layout.value)
|
||||
// console.log("prior layout: ", this.state.attrs.layout.value)
|
||||
}
|
||||
|
||||
if (this.state.attrs.styling.backgroundColor)
|
||||
@@ -230,8 +235,6 @@ class Widget extends React.Component {
|
||||
|
||||
getToolbarAttrs() {
|
||||
|
||||
console.log("Current attributes: ", this.state.attrs)
|
||||
|
||||
return ({
|
||||
id: this.__id,
|
||||
widgetName: {
|
||||
@@ -258,6 +261,50 @@ class Widget extends React.Component {
|
||||
value: this.state.size.height || 100,
|
||||
onChange: (value) => this.setWidgetSize(null, value)
|
||||
},
|
||||
fitWidth: {
|
||||
label: "Fit width",
|
||||
tool: Tools.CHECK_BUTTON,
|
||||
value: this.state.size?.width === 'fit-content' || false,
|
||||
onChange: (value) => {
|
||||
if (value === true){
|
||||
this.updateState({
|
||||
size: {
|
||||
...this.state.size,
|
||||
width: 'fit-content'
|
||||
}
|
||||
})
|
||||
}else{
|
||||
this.updateState({
|
||||
size: {
|
||||
...this.state.size,
|
||||
width: Math.floor(this.getBoundingRect().width)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
fitHeight: {
|
||||
label: "Fit height",
|
||||
tool: Tools.CHECK_BUTTON,
|
||||
value: this.state.size?.height === 'fit-content' || false,
|
||||
onChange: (value) => {
|
||||
if (value === true){
|
||||
this.updateState({
|
||||
size: {
|
||||
...this.state.size,
|
||||
height: 'fit-content'
|
||||
}
|
||||
})
|
||||
}else{
|
||||
this.updateState({
|
||||
size: {
|
||||
...this.state.size,
|
||||
height: Math.floor(this.getBoundingRect().height)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
...this.state.attrs,
|
||||
@@ -440,7 +487,7 @@ class Widget extends React.Component {
|
||||
* this is a helper function to remove any non-serializable data associated with attrs
|
||||
* eg: {"styling.backgroundColor": "#ffff", "layout": {layout: "flex", direction: "", grid: }}
|
||||
*/
|
||||
serializeAttrsValues = () => {
|
||||
serializeAttrsValues(){
|
||||
|
||||
const serializeValues = (obj, currentPath = "") => {
|
||||
const result = {}
|
||||
@@ -524,11 +571,10 @@ class Widget extends React.Component {
|
||||
}
|
||||
|
||||
setLayout(value) {
|
||||
// FIXME: when the parent layout is place, the child widgets should have position absolute
|
||||
const { layout, direction, grid = { rows: 1, cols: 1 }, gap = 10 } = value
|
||||
|
||||
console.log("layout value: ", value)
|
||||
|
||||
// console.log("layout value: ", value)
|
||||
// FIXME: In grid layout the layout doesn't adapt to the size of the child if resized
|
||||
let widgetStyle = {
|
||||
...this.state.widgetInnerStyling,
|
||||
display: layout !== Layouts.PLACE ? layout : "block",
|
||||
@@ -537,7 +583,8 @@ class Widget extends React.Component {
|
||||
flexWrap: "wrap",
|
||||
gridTemplateColumns: "repeat(auto-fill, minmax(100px, 1fr))",
|
||||
gridTemplateRows: "repeat(auto-fill, minmax(100px, 1fr))",
|
||||
// gridAutoRows: "auto"
|
||||
// gridAutoRows: 'minmax(100px, auto)', // Rows with minimum height of 100px, and grow to fit content
|
||||
// gridAutoCols: 'minmax(100px, auto)', // Cols with minimum height of 100px, and grow to fit content
|
||||
}
|
||||
|
||||
this.updateState({
|
||||
@@ -647,7 +694,7 @@ class Widget extends React.Component {
|
||||
*
|
||||
* serialize data for saving
|
||||
*/
|
||||
serialize = () => {
|
||||
serialize(){
|
||||
// NOTE: when serializing make sure, you are only passing serializable objects not functions or other
|
||||
return ({
|
||||
zIndex: this.state.zIndex,
|
||||
@@ -667,8 +714,9 @@ class Widget extends React.Component {
|
||||
/**
|
||||
* loads the data
|
||||
* @param {object} data
|
||||
* @param {() => void | undefined} callback - optional callback that will be called after load
|
||||
*/
|
||||
load = (data) => {
|
||||
load(data, callback){
|
||||
|
||||
if (Object.keys(data).length === 0) return // no data to load
|
||||
|
||||
@@ -699,10 +747,9 @@ class Widget extends React.Component {
|
||||
...restData,
|
||||
...layoutUpdates
|
||||
}
|
||||
console.log("loaded layout2: ", newData)
|
||||
|
||||
this.setState(newData, () => {
|
||||
// UPdates attrs
|
||||
// Updates attrs
|
||||
let newAttrs = { ...this.state.attrs }
|
||||
|
||||
// Iterate over each path in the updates object
|
||||
@@ -723,7 +770,12 @@ class Widget extends React.Component {
|
||||
nestedObject[lastKey].value = value
|
||||
})
|
||||
|
||||
this.updateState({ attrs: newAttrs })
|
||||
if (newAttrs?.styling?.backgroundColor){
|
||||
// some widgets don't have background color
|
||||
this.setWidgetInnerStyle("backgroundColor", newAttrs.styling.backgroundColor)
|
||||
}
|
||||
|
||||
this.updateState({ attrs: newAttrs }, callback)
|
||||
|
||||
})
|
||||
|
||||
@@ -785,7 +837,7 @@ class Widget extends React.Component {
|
||||
return
|
||||
}
|
||||
|
||||
setOverElement(e.currentTarget) // provide context to the provider
|
||||
setOverElement(this.elementRef.current) // provide context to the provider
|
||||
|
||||
let showDrop = {
|
||||
allow: true,
|
||||
@@ -858,8 +910,6 @@ class Widget extends React.Component {
|
||||
allow: false,
|
||||
show: false
|
||||
}
|
||||
}, () => {
|
||||
console.log("droppable cleared: ", this.elementRef.current, this.state.showDroppableStyle)
|
||||
})
|
||||
|
||||
|
||||
@@ -923,16 +973,29 @@ class Widget extends React.Component {
|
||||
}
|
||||
|
||||
|
||||
handleDragLeave = (e, draggedElement) => {
|
||||
handleDragLeave = (e, draggedElement, overElement) => {
|
||||
|
||||
// console.log("Left: ", e.currentTarget, e.relatedTarget, draggedElement)
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
if (!e.currentTarget.contains(draggedElement)) {
|
||||
const rect = this.getBoundingRect()
|
||||
|
||||
const {clientX, clientY} = e
|
||||
|
||||
const isInBoundingBox = (clientX >= rect.left && clientX <= rect.right &&
|
||||
clientY >= rect.top && clientY <= rect.bottom)
|
||||
|
||||
// if (!e.currentTarget.contains(draggedElement)) {
|
||||
if (!isInBoundingBox) {
|
||||
// FIXME: if the mouse pointer is over this widget's child, then droppable from here
|
||||
// only if the dragging element is not within the rect of this element remove the dragging rect
|
||||
this.setState({
|
||||
showDroppableStyle: {
|
||||
allow: false,
|
||||
show: false
|
||||
}
|
||||
}, () => {
|
||||
// console.log("Drag left", this.state.showDroppableStyle)
|
||||
})
|
||||
|
||||
}
|
||||
@@ -977,6 +1040,9 @@ class Widget extends React.Component {
|
||||
*/
|
||||
render() {
|
||||
|
||||
const width = isNumeric(this.state.size.width) ? `${this.state.size.width}px` : this.state.size.width
|
||||
const height = isNumeric(this.state.size.height) ? `${this.state.size.height}px` : this.state.size.height
|
||||
|
||||
let outerStyle = {
|
||||
...this.state.widgetOuterStyling,
|
||||
cursor: this.cursor,
|
||||
@@ -984,8 +1050,8 @@ class Widget extends React.Component {
|
||||
position: this.state.positionType, // don't change this if it has to be movable on the canvas
|
||||
top: `${this.state.pos.y}px`,
|
||||
left: `${this.state.pos.x}px`,
|
||||
width: `${this.state.size.width}px`,
|
||||
height: `${this.state.size.height}px`,
|
||||
width: width,
|
||||
height: height,
|
||||
opacity: this.state.isDragging ? 0.3 : 1,
|
||||
}
|
||||
|
||||
@@ -996,7 +1062,7 @@ class Widget extends React.Component {
|
||||
|
||||
<DragContext.Consumer>
|
||||
{
|
||||
({ draggedElement, widgetClass, onDragStart, onDragEnd, setOverElement }) => (
|
||||
({ draggedElement, widgetClass, onDragStart, onDragEnd, overElement, setOverElement }) => (
|
||||
|
||||
<div data-widget-id={this.__id}
|
||||
ref={this.elementRef}
|
||||
@@ -1013,7 +1079,7 @@ class Widget extends React.Component {
|
||||
onDrop={(e) => this.handleDropEvent(e, draggedElement, widgetClass)}
|
||||
|
||||
onDragEnter={(e) => this.handleDragEnter(e, draggedElement, setOverElement)}
|
||||
onDragLeave={(e) => this.handleDragLeave(e, draggedElement)}
|
||||
onDragLeave={(e) => this.handleDragLeave(e, draggedElement, overElement)}
|
||||
|
||||
onDragStart={(e) => this.handleDragStart(e, onDragStart)}
|
||||
onDragEnd={(e) => this.handleDragEnd(onDragEnd)}
|
||||
|
||||
@@ -132,7 +132,7 @@ class TkinterBase extends Widget {
|
||||
* loads the data
|
||||
* @param {object} data
|
||||
*/
|
||||
load = (data) => {
|
||||
load(data, callback=null){
|
||||
|
||||
if (Object.keys(data).length === 0) return // no data to load
|
||||
|
||||
@@ -188,7 +188,13 @@ class TkinterBase extends Widget {
|
||||
nestedObject[lastKey].value = value
|
||||
})
|
||||
|
||||
this.updateState({ attrs: newAttrs })
|
||||
|
||||
if (newAttrs?.styling?.backgroundColor){
|
||||
// TODO: find a better way to apply innerStyles
|
||||
this.setWidgetInnerStyle("backgroundColor", newAttrs.styling.backgroundColor.value)
|
||||
}
|
||||
|
||||
this.updateState({ attrs: newAttrs }, callback)
|
||||
|
||||
})
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ class Button extends TkinterBase{
|
||||
return (
|
||||
<div className="tw-w-flex tw-flex-col tw-w-full tw-h-full tw-rounded-md
|
||||
tw-border tw-border-solid tw-border-gray-400 tw-overflow-hidden">
|
||||
<div className="tw-p-2 tw-w-full tw-h-full tw-content-start " style={this.state.widgetInnerStyling}>
|
||||
<div className="tw-p-2 tw-w-full tw-flex tw-place-content-center tw-place-items-center tw-h-full tw-text-center" style={this.state.widgetInnerStyling}>
|
||||
{/* {this.props.children} */}
|
||||
<div className="tw-text-sm" style={{color: this.getAttrValue("styling.foregroundColor")}}>
|
||||
{this.getAttrValue("buttonLabel")}
|
||||
|
||||
@@ -10,7 +10,7 @@ class Frame extends TkinterBase{
|
||||
super(props)
|
||||
|
||||
this.droppableTags = {
|
||||
exclude: ["image", "video", "media"]
|
||||
exclude: ["image", "video", "media", "toplevel"]
|
||||
}
|
||||
|
||||
this.state = {
|
||||
|
||||
@@ -47,7 +47,7 @@ class Label extends TkinterBase{
|
||||
|
||||
componentDidMount(){
|
||||
super.componentDidMount()
|
||||
this.setAttrValue("styling.backgroundColor", "#fff")
|
||||
this.setAttrValue("styling.backgroundColor", "#fff0")
|
||||
this.setWidgetInnerStyle("backgroundColor", "#fff0")
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ class Label extends TkinterBase{
|
||||
renderContent(){
|
||||
return (
|
||||
<div className="tw-w-flex tw-flex-col tw-w-full tw-h-full tw-rounded-md tw-overflow-hidden">
|
||||
<div className="tw-p-2 tw-w-full tw-h-full tw-content-start " style={this.state.widgetInnerStyling}>
|
||||
<div className="tw-p-2 tw-w-full tw-h-full tw-flex tw-place-content-center tw-place-items-center " style={this.state.widgetInnerStyling}>
|
||||
{/* {this.props.children} */}
|
||||
<div className="tw-text-sm" style={{color: this.getAttrValue("styling.foregroundColor")}}>
|
||||
{this.getAttrValue("labelWidget")}
|
||||
|
||||
@@ -50,4 +50,12 @@ export function removeKeyFromObject(path, _object) {
|
||||
delete nestedObject[lastKey]
|
||||
|
||||
return newAttrs
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function isNumeric(str) {
|
||||
if (typeof str != "string") return false // we only process strings!
|
||||
return !isNaN(str) && // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
|
||||
!isNaN(parseFloat(str)) // ...and ensure strings of whitespace fail
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user