-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(react-formio): migrate FormBuilder to react hooks
- Loading branch information
Showing
12 changed files
with
2,379 additions
and
3,869 deletions.
There are no files selected for viewing
2,042 changes: 2,042 additions & 0 deletions
2,042
packages/react-formio/src/components/__fixtures__/form-wizard.fixture.json
Large diffs are not rendered by default.
Oops, something went wrong.
196 changes: 22 additions & 174 deletions
196
packages/react-formio/src/components/form-builder/formBuilder.component.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,177 +1,25 @@ | ||
import AllComponents from "formiojs/components"; | ||
import Components from "formiojs/components/Components"; | ||
import FormioFormBuilder from "formiojs/FormBuilder"; | ||
import cloneDeep from "lodash/cloneDeep"; | ||
import noop from "lodash/noop"; | ||
import { Component } from "react"; | ||
|
||
import { ComponentType } from "../../interfaces"; | ||
import { callLast } from "../../utils/callLast"; | ||
|
||
Components.setComponents(AllComponents); | ||
|
||
const EVENTS = [ | ||
"addComponent", | ||
"updateComponent", | ||
"removeComponent", | ||
"saveComponent", | ||
"cancelComponent", | ||
"moveComponent", | ||
"editComponent", | ||
"editJson", | ||
"copyComponent", | ||
"pasteComponent" | ||
]; | ||
|
||
const EVENTS_CHANGE = ["addComponent", "saveComponent", "updateComponent", "removeComponent"]; | ||
|
||
async function createBuilder(el: Element, { components = [], display, options, onChange, events = {} }: any): Promise<void> { | ||
const form = { | ||
display, | ||
components: [...components] | ||
}; | ||
|
||
try { | ||
const builder = await new FormioFormBuilder(el, form, { ...options }).ready; | ||
|
||
const handleEvent = (event: string) => { | ||
return (...args: any[]) => { | ||
events[event] && events[event](...args); | ||
|
||
if (EVENTS_CHANGE.includes(event)) { | ||
onChange(builder.form.components); | ||
} | ||
}; | ||
}; | ||
|
||
EVENTS.forEach((event) => builder.on(event, callLast(handleEvent(event), 200))); | ||
|
||
return builder; | ||
} catch (er) { | ||
console.error(er); | ||
} | ||
} | ||
|
||
export interface FormBuilderProps { | ||
components: ComponentType[]; | ||
display?: string; | ||
options?: any; | ||
builder?: any; | ||
onChange?: (components: ComponentType[]) => void; | ||
onAddComponent?: Function; | ||
onUpdateComponent?: Function; | ||
onRemoveComponent?: Function; | ||
onSaveComponent?: Function; | ||
onCancelComponent?: Function; | ||
onMoveComponent?: Function; | ||
onEditComponent?: Function; | ||
onEditJson?: Function; | ||
onCopyComponent?: Function; | ||
onPasteComponent?: Function; | ||
} | ||
|
||
export class FormBuilder extends Component<FormBuilderProps, any> { | ||
static defaultProps = { | ||
options: {}, | ||
onChange: noop, | ||
onReady: noop, | ||
onDestroy: noop | ||
}; | ||
|
||
private elRef: any; | ||
private builderRef: any; | ||
|
||
constructor(props: FormBuilderProps) { | ||
super(props); | ||
|
||
this.state = { | ||
display: props.display, | ||
components: cloneDeep(props.components) | ||
}; | ||
this.elRef = null; | ||
this.builderRef = null; | ||
} | ||
|
||
async componentDidMount(): Promise<void> { | ||
await this.create(this.props); | ||
} | ||
|
||
async create(props: FormBuilderProps) { | ||
const { | ||
options, | ||
display, | ||
components, | ||
onAddComponent, | ||
onUpdateComponent, | ||
onRemoveComponent, | ||
onSaveComponent, | ||
onCancelComponent, | ||
onMoveComponent, | ||
onEditComponent, | ||
onEditJson, | ||
onCopyComponent, | ||
onPasteComponent | ||
} = props; | ||
|
||
this.builderRef = await createBuilder(this.elRef.firstChild, { | ||
display, | ||
options: { ...options }, | ||
components: cloneDeep(components), | ||
onChange: this.whenComponentsChange.bind(this), | ||
events: { | ||
onAddComponent, | ||
onUpdateComponent, | ||
onRemoveComponent, | ||
onSaveComponent, | ||
onCancelComponent, | ||
onMoveComponent, | ||
onEditComponent, | ||
onEditJson, | ||
onCopyComponent, | ||
onPasteComponent | ||
} | ||
}); | ||
} | ||
|
||
componentWillUnmount(): void { | ||
this.builderRef?.destroy(); | ||
} | ||
|
||
// eslint-disable-next-line react/no-deprecated | ||
async componentWillReceiveProps(nextProps: FormBuilderProps) { | ||
if (this.builderRef) { | ||
if (nextProps.display !== this.state.display) { | ||
await this.create({ | ||
...this.props, | ||
display: nextProps.display | ||
}); | ||
} else if (nextProps.components !== this.state.components) { | ||
this.builderRef.form = { | ||
display: this.state.display, | ||
components: nextProps.components | ||
}; | ||
} | ||
} | ||
} | ||
|
||
whenComponentsChange(components: ComponentType[]) { | ||
this.setState({ components }, () => { | ||
this.props?.onChange && this.props.onChange(components); | ||
}); | ||
} | ||
|
||
/* eslint-disable jsx-a11y/no-static-element-interactions */ | ||
/* eslint-disable jsx-a11y/click-events-have-key-events */ | ||
render() { | ||
return ( | ||
<div | ||
ref={(ref) => { | ||
this.elRef = ref; | ||
}} | ||
onClick={(e) => e.stopPropagation()} | ||
> | ||
import type { CSSProperties } from "react"; | ||
|
||
import { useFormBuilder, UseFormBuilderProps } from "./useFormBuilder.hook"; | ||
|
||
export function FormBuilder({ | ||
className = "", | ||
style = {}, | ||
["data-testid"]: dataTestId = "formio-builder-container", | ||
...props | ||
}: UseFormBuilderProps & { | ||
className?: string; | ||
style?: CSSProperties; | ||
["data-testid"]?: string; | ||
}) { | ||
const renderElement = useFormBuilder(props); | ||
|
||
return ( | ||
<div style={style} className={className} data-testid={dataTestId}> | ||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */} | ||
<div ref={renderElement} onClick={(e) => e.stopPropagation()}> | ||
<div /> | ||
</div> | ||
); | ||
} | ||
</div> | ||
); | ||
} |
Oops, something went wrong.