@tomino/dynamic-form-semantic-ui
Version:
Semantic UI form renderer based on dynamic form generation
234 lines (203 loc) • 6.39 kB
text/typescript
/* eslint-disable @typescript-eslint/no-use-before-define */
import {
FormElement,
FormComponentCatalogue,
EditorComponentCatalogue,
EditorComponent,
JSONSchema
} from '@tomino/dynamic-form';
import { CellHighlighter } from './form/cell_highlighter';
import { observable, computed, action } from 'mobx';
import { toJS } from '../common';
import { buildDataSet } from '@tomino/dynamic-form';
import { debounce } from '@tomino/toolbelt';
import { ProjectManager } from './project_manager';
import { SchemaRecord } from './editor_types';
import { prepareStores } from './form_store';
import { schemaSchema } from './common_schemas';
import { schemaDatasetToJS } from '../helpers';
import { IStorage, IProject } from '../storage/common_storage';
import { Theme } from './themes/common';
import { white } from './themes/white';
import { black } from './themes/black';
type Builder = (form: FormElement, schema: JSONSchema) => DynamicForm.ProjectDataSet;
let id = 0;
export class EditorState {
static LAST = 'CORPIX_LAST_PROJECT';
__id = id++;
_dragItem: any;
get dragItem() {
return this._dragItem;
}
set dragItem(v) {
this._dragItem = v;
}
buildProject: Builder;
componentCatalogue: FormComponentCatalogue;
dataSource: any;
editorCatalogue: EditorComponentCatalogue;
form: DynamicForm.FormDataSet;
handlers: any;
highlighter: CellHighlighter;
hoverParent: FormElement;
leftPanelConfig = [true, true];
manager: ProjectManager;
schema: DynamicForm.SchemaDataSet;
state: DynamicForm.StateDataSet;
selectedDataSetTab = 'dataset';
selectedParent: DynamicForm.FormDataSet;
selectedParentSchema: DynamicForm.SchemaDataSet;
selectedSourcePath: string = null;
tabSelection: { [index: string]: any } = {};
types: SchemaRecord[];
theme: Theme;
projectHandlers: string[];
help: string = '';
dataVersion = 0;
dataPreview = '';
previewOpen = false;
.shallow project: DynamicForm.ProjectDataSet;
// standard app context
alert: any = null;
authToken: string = null;
auth = observable({ user: null });
app = {};
private _cachedProps: { [index: string]: FormElement[] } = {};
private _cachedChildProps: { [index: string]: FormElement[] } = {};
constructor(
componentCatalogue: FormComponentCatalogue = null,
editorCatalogue: EditorComponentCatalogue = null,
handlers: any = {},
types: SchemaRecord[] = [],
storage: IStorage = null,
theme: string = 'dark'
) {
this.componentCatalogue = componentCatalogue;
this.editorCatalogue = editorCatalogue;
this.handlers = handlers;
this.types = types;
this.theme = theme === 'light' ? white : black;
this.types = (types || []).concat(
{
id: 'schema',
name: 'Schema',
description: 'Schema of the schema definition',
schema: schemaSchema
}
// {
// id: 'form',
// name: 'Form',
// description: 'Schema of the form definition',
// schema: elementSchema(true)
// }
);
this.buildProject = prepareStores(this);
this.manager = new ProjectManager(storage, this.buildProject);
if (handlers) {
this.projectHandlers = Object.getOwnPropertyNames(handlers).sort();
}
}
async loadLastProject() {
if (this.manager.storage) {
this.project = await this.manager.loadLastProject();
}
return this.project;
}
get data() {
if (!this.dataSource) {
this.recomputeData();
}
// subscribe
this.dataVersion;
return this.dataSource;
}
recomputeData() {
const data = toJS(this.dataSource);
const dataSet = schemaDatasetToJS(this.schema, false);
try {
this.dataSource = this.project ? buildDataSet(dataSet, data, false) : null;
} catch (ex) {
alert('Data is no longer valid, needed to remove temporary data');
this.dataSource = this.project ? buildDataSet(dataSet, {}, false) : null;
}
this.dataVersion++;
}
recomputeDataBounce = debounce(() => this.recomputeData(), 500);
highlight(
highlighter: CellHighlighter,
row: number,
column: number,
className: string,
width: number = 1,
clear = true
) {
if (clear && this.highlighter) {
this.highlighter.clearHighlight();
}
this.highlighter = highlighter;
this.highlighter.highlight(row, column, className, width);
}
highlightMultiple(
highlighter: CellHighlighter,
cells: { row: number; column: number; className: string }[]
) {
if (this.highlighter) {
this.highlighter.clearHighlight();
}
this.highlighter = highlighter;
this.highlighter.highlightMultiple(cells);
}
changeTab(from: string, to: string) {
this.tabSelection[from] = {
schema: this.project.state.selectedSchema,
name: this.project.state.selectedSchemaName
};
if (this.tabSelection[to]) {
this.project.state.setSchema(this.tabSelection[to].schema, this.tabSelection[to].name);
}
this.selectedDataSetTab = to;
}
cachedProps(element: EditorComponent) {
if (!element.props) {
return [];
}
if (!this._cachedProps[element.control]) {
this._cachedProps[element.control] = Object.keys(element.props).map(
key => element.props[key].control
);
}
return this._cachedProps[element.control];
}
cachedChildProps(element: EditorComponent) {
if (!element.childProps) {
return [];
}
if (!this._cachedChildProps[element.control]) {
this._cachedChildProps[element.control] = Object.keys(element.childProps).map(
key => element.childProps[key].control
);
}
return this._cachedChildProps[element.control];
}
load(project: IProject, saveLast = true) {
this.project = this.manager.load(project, saveLast);
}
duplicateProject(name: string) {
this.project = this.manager.duplicateProject(this.project, name);
}
createProject(name: string) {
this.project = this.manager.createProject(name);
}
editorProps: FormElement[] = [
{
group: 'Editor',
control: 'Input',
props: { value: { source: 'editorLabel' }, label: 'Label' }
},
{
group: 'Editor',
control: 'Checkbox',
props: { checked: { source: 'locked' }, label: 'Locked' }
}
];
}