Skip to content

Commit

Permalink
refactor: Update FormBuilder component to use LayoutToColumns functio…
Browse files Browse the repository at this point in the history
…n for converting layout to columns
  • Loading branch information
trheyi committed Jun 3, 2024
1 parent b6108a8 commit 7ccb88b
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 63 deletions.
150 changes: 105 additions & 45 deletions packages/xgen/components/edit/FormBuilder/components/Canvas/index.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { Panel, Icon } from '@/widgets'
import { Panel, Icon, PanelPresets as Presets, PanelFilter as Filter } from '@/widgets'
import GridLayout from 'react-grid-layout'
import { Field, Layout, Presets, Setting, Type, Remote, Data } from '../../types'
import { Field, Layout, Setting, Type, Data } from '../../types'
import { useEffect, useState } from 'react'
import { GenerateID, LayoutToColumns, TypeMappping, UpdatePosition, ValueToLayout } from '../../utils'
import clsx from 'clsx'
import Preset from '../Preset'
import type { Component } from '@/types'
import { IconName, IconSize } from '@/components/edit/FlowBuilder/utils'
import { getLocale } from '@umijs/max'
import { Tooltip } from 'antd'
import { Background } from 'reactflow'
import Ruler from '../Ruler'
import { CodeSandboxCircleFilled } from '@ant-design/icons'

interface IProps {
width?: number
height?: number
contentHeight?: number
setting?: Setting
presets?: Presets | Remote
presets?: Component.Request
value?: Data // initial value
fixed: boolean
offsetTop: number
Expand All @@ -26,6 +26,9 @@ interface IProps {
showSidebar: boolean
fullscreen: boolean
setFullscreen: (v: boolean) => void

__namespace: string
__bind: string
}

const Index = (props: IProps) => {
Expand All @@ -47,6 +50,8 @@ const Index = (props: IProps) => {
const [isPreset, setIsPreset] = useState(false)
const [isSetting, setIsSetting] = useState(false)

const [keywords, setKeywords] = useState<string>('')

const onPanelChange = (id: string, bind: string, value: any) => {
if (isSetting) {
updateForm(bind, value)
Expand All @@ -67,22 +72,33 @@ const Index = (props: IProps) => {
}

const showPanel = (id: string, field: Field, type: Type) => {
if (isSetting) return showSettings()

setIsPreset(false)
setIsSetting(false)
setField(field)
setType(type)
setActive(id)
setMask(true)
setOpen(true)
}

const showPresets = () => {}
const showPresets = () => {
setIsPreset(true)
setIsSetting(false)
setActive(undefined)
setMask(false)
setOpen(true)
}
const showSettings = () => {
setIsSetting(true)
setMask(true)
setIsPreset(false)
setActive(undefined)
setOpen(true)
}

const hidePanel = () => {
setOpen(false)
setMask(true)
setActive(undefined)
setIsSetting(false)
setIsPreset(false)
Expand All @@ -95,6 +111,8 @@ const Index = (props: IProps) => {

const getLabel = () => {
if (isSetting) return is_cn ? '设置' : 'Settings'
if (isPreset) return is_cn ? '插入' : 'Insert'

return field?.props?.label || field?.props?.name || type?.label || (is_cn ? '未命名' : 'Untitled')
}

Expand All @@ -103,11 +121,44 @@ const Index = (props: IProps) => {
return field?.props || {}
}

const getActions = () => {
if (isPreset) {
return [<Filter key='filter' onChange={(value) => setKeywords(value)} />]
}

return undefined
}

const getType = () => {
if (isSetting) return getSetting()
if (isPreset) return undefined
return type
}

// add addColumn to the layout
const addColumn = (field: Field) => {
const maxY = Math.max(...layout.map((item) => item.y))
const copyField = { ...field }
copyField.id = GenerateID()
copyField.x = 0
copyField.y = maxY + 1

const newCloumns = [...(value?.columns || []), copyField]
setValue((value) => ({ ...value, columns: newCloumns }))
setLayout([
...layout,
{
i: copyField.id,
x: copyField.x,
y: copyField.y,
w: copyField.width || 4,
h: 1,
resizeHandles: ['w', 'e']
}
])
setFieldMap({ ...fieldMap, [copyField.id]: copyField })
}

const getSetting = () => {
if (!props.setting) return undefined
if (!props.setting.form) {
Expand Down Expand Up @@ -188,31 +239,6 @@ const Index = (props: IProps) => {
setFieldMap(mapping)
}

// add from the preset
const onAdd = (field: Field) => {
const maxY = Math.max(...layout.map((item) => item.y))
const copyField = { ...field }
copyField.id = GenerateID()
copyField.x = 0
copyField.y = maxY + 1

const newCloumns = [...(value?.columns || []), copyField]
setValue((value) => ({ ...value, columns: newCloumns }))
setLayout([
...layout,
{
i: copyField.id,
x: copyField.x,
y: copyField.y,
w: copyField.width || 4,
h: 1,
resizeHandles: ['w', 'e']
}
])
setFieldMap({ ...fieldMap, [copyField.id]: copyField })
showPanel(copyField.id, copyField, typeMap[copyField.type])
}

// Clone the item
const onClone = (key: string) => {
const layoutItem = layout.find((item) => item.i === key)
Expand Down Expand Up @@ -244,31 +270,52 @@ const Index = (props: IProps) => {

// Drop the item add the item to the layout
const onDrop = (layout: Layout[], layoutItem: GridLayout.Layout, e: any) => {
const raw = e.dataTransfer.getData('text') || ''
// Drop from preset
const payload = e.dataTransfer.getData('application/form/preset')
if (payload) {
let data: Record<string, any> = {}
try {
data = JSON.parse(payload)
} catch (e: any) {
console.error(`Error parsing JSON data: ${e.message}`)
return
}

if (!data.columns) {
console.error('Columns not found in payload')
return
}

setValue((value) => {
value = value || { columns: [], form: {} }
const newColumns = [...value.columns, ...data.columns]
const res = ValueToLayout(newColumns, [], { x: layoutItem.x, y: layoutItem.y })
setLayout(res.layout)
setFieldMap(res.mapping)
return { ...value, columns: newColumns }
})
return
}

// Drop from type
const raw = e.dataTransfer.getData('application/form/type') || ''
let data: Record<string, any> = {}
try {
data = JSON.parse(raw)
} catch (e: any) {
console.error(`Error parsing JSON data: ${e.message}`)
return
}

const field = {
addColumn({
id: GenerateID(),
type: data.type,
x: layoutItem.x,
y: layoutItem.y,
width: data.width || 4,
props: data.props || {}
}

const newCloumns = [...(value?.columns || []), field]
setValue((value) => ({ ...value, columns: newCloumns }))
setLayout([
...layout,
{ i: field.id, x: field.x, y: field.y, w: field.width, h: 1, resizeHandles: ['w', 'e'] }
])
setFieldMap({ ...fieldMap, [field.id]: field })
showPanel(field.id, field, typeMap[field.type])
})
// showPanel(field.id, field, typeMap[field.type])
}

// Remove the item
Expand Down Expand Up @@ -297,10 +344,23 @@ const Index = (props: IProps) => {
label={getLabel()}
data={getData()}
type={getType()}
actions={getActions()}
fixed={props.fixed}
mask={mask}
width={420}
offsetTop={props.offsetTop}
icon={isPreset ? 'icon-plus-circle' : undefined}
children={
isPreset ? (
<Presets
keywords={keywords}
transfer='application/form/preset'
__namespace={props.__namespace}
__bind={props.__bind}
presets={props.presets}
/>
) : undefined
}
/>
<div className='title-bar' style={{ width: props.width }}>
<div className='head'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const Index = (props: IProps) => {
unselectable='on'
onDragStart={(e) =>
e.dataTransfer.setData(
'text/plain',
'application/form/type',
JSON.stringify({ type: type.name })
)
}
Expand Down
14 changes: 7 additions & 7 deletions packages/xgen/components/edit/FormBuilder/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,23 @@ import { useEffect, useRef, useState } from 'react'
import 'react-grid-layout/css/styles.css'
import styles from './index.less'
import clsx from 'clsx'
import { Data, Presets, Remote, Setting } from './types'
import { Data, Setting } from './types'
import Sidebar from './components/Sidebar'
import Canvas from './components/Canvas'
import { Else, If, Then } from 'react-if'
import { GetSetting } from './utils'
import { useGlobal } from '@/context/app'
import Ruler from './components/Ruler'

interface IFormBuilderProps {
setting?: Remote | Setting
presets?: Remote | Presets
setting?: Component.Request
presets?: Component.Request
height?: number

value?: Data
disabled?: boolean

label?: string
bind?: string
namespace?: string
type?: string
onChange?: (v: any) => void
}
Expand Down Expand Up @@ -195,6 +193,8 @@ const FormBuilder = window.$app.memo((props: IProps) => {
setFullscreen={setFullscreen}
showSidebar={showSidebar}
toggleSidebar={toggleSidebar}
__namespace={props.__namespace}
__bind={props.__bind}
/>
</Else>
</If>
Expand All @@ -203,10 +203,10 @@ const FormBuilder = window.$app.memo((props: IProps) => {
})

const Index = (props: IProps) => {
const { __bind, __name, itemProps, ...rest_props } = props
const { __bind, __namespace, __name, itemProps, ...rest_props } = props
return (
<Item {...itemProps} {...{ __bind, __name }}>
<FormBuilder {...rest_props} {...{ __bind, __name }}></FormBuilder>
<FormBuilder {...rest_props} {...{ __bind, __namespace, __name }}></FormBuilder>
</Item>
)
}
Expand Down
22 changes: 12 additions & 10 deletions packages/xgen/components/edit/FormBuilder/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import axios from 'axios'
import { Field, Layout, Presets, Remote, Setting, Type } from './types'
import { nanoid } from 'nanoid'

export const GetSetting = async (setting?: Remote | Setting): Promise<Setting> => {
if (setting && 'api' in setting) {
Expand Down Expand Up @@ -133,14 +134,15 @@ export const LayoutToColumns = (

export const ValueToLayout = (
value?: Field[],
defaultValue?: Field[]
defaultValue?: Field[],
offsets?: { x: number; y: number }
): { layout: Layout[]; mapping: Record<string, Field> } => {
if (Array.isArray(value)) {
return _valueToLayout(value)
return _valueToLayout(value, offsets)
}

if (Array.isArray(defaultValue)) {
return _valueToLayout(defaultValue)
return _valueToLayout(defaultValue, offsets)
}

return { layout: [], mapping: {} }
Expand All @@ -162,21 +164,21 @@ export const UpdatePosition = (mapping: Record<string, Field>, layout: Layout[])
}

export const GenerateID = (): string => {
const timestamp: number = new Date().getTime()
const random: number = Math.floor(Math.random() * 10000)
const uniqueId: string = `${timestamp}${random}`
return uniqueId
return '_' + nanoid() + new Date().valueOf()
}

const _valueToLayout = (value?: Field[]): { layout: Layout[]; mapping: Record<string, Field> } => {
const _valueToLayout = (
value?: Field[],
offsets?: { x: number; y: number }
): { layout: Layout[]; mapping: Record<string, Field> } => {
if (!Array.isArray(value)) {
return { layout: [], mapping: {} }
}
const mapping: Record<string, Field> = {}
const layout: Layout[] = []

let cols = 0
let y = 0
let cols = 0 + (offsets?.x || 0)
let y = 0 + (offsets?.y || 0)
value.map((item, index) => {
if (!item) return false
const id = item.id || GenerateID()
Expand Down

0 comments on commit 7ccb88b

Please sign in to comment.