fix: refactor setting formItem

This commit is contained in:
wwsun
2023-09-13 11:04:05 +08:00
parent 8d396ff134
commit b786de2f1a
9 changed files with 42 additions and 73 deletions
+2 -2
View File
@@ -11,7 +11,7 @@ const packageJson = {
},
};
const tangoJson = {
const tangoConfigJson = {
packages: {
react: {
version: '17.0.2',
@@ -221,7 +221,7 @@ p {
export const sampleFiles = [
{ filename: '/package.json', code: JSON.stringify(packageJson) },
{ filename: '/appJson.json', code: JSON.stringify(appJson) },
{ filename: '/tango.config.json', code: JSON.stringify(tangoJson) },
{ filename: '/tango.config.json', code: JSON.stringify(tangoConfigJson) },
{ filename: '/README.md', code: '# readme' },
{ filename: '/src/index.less', code: lessCode },
{ filename: '/src/style.css', code: cssCode },
+2 -2
View File
@@ -43,7 +43,7 @@ import { IWorkspace } from './interfaces';
import { SelectSource } from './select-source';
import { DragSource } from './drag-source';
export type WorkspaceOptionsType = {
export interface IWorkspaceOptions {
/**
* 入口文件
*/
@@ -225,7 +225,7 @@ export class Workspace extends EventTarget implements IWorkspace {
return Object.keys(this.localBlocks);
}
constructor(options?: WorkspaceOptionsType) {
constructor(options?: IWorkspaceOptions) {
super();
this.history = new TangoHistory(this);
this.selectSource = new SelectSource(this);
+3 -1
View File
@@ -12,4 +12,6 @@ export * from './sidebar';
export * from './toolbar';
export * from './selection-menu';
export { register as registerSetter, FormItemComponentProps, FormItemCreateOptionsType } from '@music163/tango-setting-form';
export { register as registerSetter } from '@music163/tango-setting-form';
export type { FormItemComponentProps, IFormItemCreateOptions } from '@music163/tango-setting-form';
+4 -2
View File
@@ -1,7 +1,7 @@
import React, { useImperativeHandle, ForwardedRef, useRef, useState, useEffect } from 'react';
import { Box } from 'coral-system';
import { CodeSandbox, CodeSandboxProps } from '@music163/tango-sandbox';
import { getValue, logger, pick, setValue } from '@music163/tango-helpers';
import { getValue, isFunction, logger, pick, setValue } from '@music163/tango-helpers';
import { observer, useWorkspace, useDesigner } from '@music163/tango-context';
import { Simulator, Viewport } from '../simulator';
import { useSandboxQuery } from '../context';
@@ -491,7 +491,9 @@ function mergeTangoConfigJson(
setValue(json, 'sandbox.externals', externals);
setValue(json, 'sandbox.externalResources', [...new Set(externalResources)]);
json = formatter?.(json);
if (isFunction(formatter)) {
json = formatter?.(json);
}
return JSON.stringify(json);
}
@@ -4,8 +4,7 @@ import { SingleMonacoEditor } from '@music163/tango-ui';
import { FormItemComponentProps } from '@music163/tango-setting-form';
/**
* 废弃掉,直接使用 ExpressionSetter 代替
* @deprecated
* JSON Setter
*/
export function JSONSetter({ value, onChange }: FormItemComponentProps) {
return (
+1
View File
@@ -4,6 +4,7 @@ import { SettingForm, FormModel, SettingFormProps } from '@music163/tango-settin
import { Panel } from '@music163/tango-ui';
import { clone } from '@music163/tango-helpers';
import { observer, useDesigner, useWorkspace } from '@music163/tango-context';
import './setters';
export interface SettingPanelProps extends SettingFormProps {
title?: React.ReactNode;
@@ -1,10 +1,10 @@
import React from 'react';
import { Button, Space } from 'antd';
import { EditableVariableTree, EditableVariableTreeProps } from '@music163/tango-setting-form';
import { useBoolean } from '@music163/tango-helpers';
import { Panel, Form, IconButton } from '@music163/tango-ui';
import { FileAddOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import { observer, useWorkspace, useWorkspaceData } from '@music163/tango-context';
import { EditableVariableTree, EditableVariableTreeProps } from '../components';
export interface VariablePanelProps extends EditableVariableTreeProps {
wrapperHeight?: number | string;
+26 -56
View File
@@ -14,7 +14,7 @@ import { QuestionCircleOutlined } from '@ant-design/icons';
import { InputProps, Tooltip } from 'antd';
import { INTERNAL_SETTERS } from './setters';
import { useFormModel, useFormVariable } from './context';
import { FormControl, FormControlProps } from './form-ui';
import { FormControl } from './form-ui';
export interface FormItemProps extends ComponentPropType {
extra?: React.ReactNode;
@@ -50,10 +50,6 @@ export interface IFormItemCreateOptions {
* 是否禁用变量设置器
*/
disableVariableSetter?: boolean;
/**
* 表单项类型
*/
type?: FormControlProps['type'];
/**
* 子表单是否默认折叠
*/
@@ -64,25 +60,12 @@ export interface IFormItemCreateOptions {
validate?: (value: string) => string | Promise<any>;
}
function normalizeCreateOptions(
options: IFormItemCreateOptions,
): Required<Omit<IFormItemCreateOptions, 'component' | 'alias'>> {
const render = options.render ?? ((props: any) => React.createElement(options.component, props));
return {
name: options.name,
render,
disableVariableSetter: options.disableVariableSetter ?? false,
type: options.type || 'formItem',
defaultCollapsed: options.defaultCollapsed ?? true,
validate: options.validate,
};
}
const defaultGetSetterProps = () => ({});
const defaultGetVisible = () => true;
export function createFormItem(options: IFormItemCreateOptions) {
const _options = normalizeCreateOptions(options);
const renderSetter =
options.render ?? ((props: any) => React.createElement(options.component, props));
function FormItem({
name,
@@ -95,7 +78,7 @@ export function createFormItem(options: IFormItemCreateOptions) {
setterProps,
defaultValue,
options: setterOptions,
disableVariableSetter: disableVariableSetterProp,
disableVariableSetter: disableVariableSetterProp = options.disableVariableSetter,
getVisible: getVisibleProp,
getSetterProps: getSetterPropsProp,
extra,
@@ -104,16 +87,15 @@ export function createFormItem(options: IFormItemCreateOptions) {
const model = useFormModel();
const field = model.getField(name);
const value = toJS(field.value ?? defaultValue);
const disableVariableSetter =
disableSwitchExpressionSetter || disableVariableSetterProp || _options.disableVariableSetter;
const disableVariableSetter = disableSwitchExpressionSetter ?? disableVariableSetterProp;
const [isVariable, { toggle: toggleIsVariable }] = useBoolean(
() => !disableVariableSetter && isVariableString(value),
);
const setterName = isVariable ? 'expressionSetter' : setter;
const validate = SETTERS_VALIDATE_DICT[setterName];
field.setConfig({
validate,
validate: options.validate,
});
const baseComponentProps = clone(
@@ -140,12 +122,13 @@ export function createFormItem(options: IFormItemCreateOptions) {
}
const getSetterProps = getSetterPropsProp || defaultGetSetterProps;
const ExpressionSetter = SETTERS_DICT['expressionSetter'];
// 从注册表中获取 expSetter
const ExpressionSetter = REGISTERED_FORM_ITEM_MAP['expressionSetter']?.config?.component;
const setterNode = isVariable ? (
<ExpressionSetter {...expProps} {...baseComponentProps} />
) : (
_options.render({
renderSetter({
...expProps,
...baseComponentProps,
...setterProps, // setterProps 优先级大于快捷属性
@@ -158,8 +141,7 @@ export function createFormItem(options: IFormItemCreateOptions) {
return (
<FormControl
visible={getVisible(model)}
type={_options.type}
defaultCollapsed={_options.defaultCollapsed}
defaultCollapsed={options.defaultCollapsed}
label={title}
note={name}
tip={tip}
@@ -192,28 +174,27 @@ export function createFormItem(options: IFormItemCreateOptions) {
);
}
FormItem.displayName = `FormItem_${_options.name}`;
FormItem.displayName = `FormItem_${options.name}`;
FormItem.config = options;
return observer(FormItem);
}
// setter 查找表
const SETTERS_DICT: Record<string, React.FunctionComponent<any>> = {};
// setter 校验函数查找表
const SETTERS_VALIDATE_DICT: Record<string, IFormItemCreateOptions['validate']> = {};
// 已注册的 setter 查找表
const REGISTERED_FORM_ITEM_MAP: Record<string, ReturnType<typeof createFormItem>> = {};
INTERNAL_SETTERS.forEach((config) => {
const ret = createFormItem(config);
/**
* Setter 注册
* @param config 注册选项
*/
export function register(config: IFormItemCreateOptions) {
const names = [config.name, ...(config.alias ?? [])];
names.forEach((name) => {
SETTERS_DICT[name] = ret;
REGISTERED_FORM_ITEM_MAP[name] = createFormItem(config);
});
if (config.validate) {
names.forEach((name) => {
SETTERS_VALIDATE_DICT[name] = config.validate;
});
}
});
}
INTERNAL_SETTERS.forEach(register);
const iconStyle = {
color: 'red',
@@ -221,9 +202,9 @@ const iconStyle = {
export function SettingFormItem(props: FormItemProps) {
const { setter } = props;
const Comp = SETTERS_DICT[setter];
const Comp = REGISTERED_FORM_ITEM_MAP[setter];
if (Comp == null) {
const Fallback = SETTERS_DICT.expressionSetter;
const Fallback = REGISTERED_FORM_ITEM_MAP.expressionSetter;
return (
<Fallback
{...props}
@@ -237,14 +218,3 @@ export function SettingFormItem(props: FormItemProps) {
}
return React.createElement(Comp, props);
}
/**
* Setter 注册
* @param options
*/
export function register(options: IFormItemCreateOptions) {
if (SETTERS_DICT[options.name]) {
logger.log(`Internal setter override: <${options.name}>`);
}
SETTERS_DICT[options.name] = createFormItem(options);
}
+2 -7
View File
@@ -5539,7 +5539,7 @@
resolved "https://registry.npmmirror.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz"
integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
"@yarnpkg/parsers@^3.0.0-rc.18":
"@yarnpkg/parsers@3.0.0-rc.48.1", "@yarnpkg/parsers@^3.0.0-rc.18":
version "3.0.0-rc.48.1"
resolved "https://registry.npmmirror.com/@yarnpkg/parsers/-/parsers-3.0.0-rc.48.1.tgz#8636c24c02c888f2602a464edfd7fb113d75e937"
integrity sha512-qEewJouhRvaecGjbkjz9kMKn96UASbDodNrE5MYy2TrXkHcisIkbMxZdGBYfAq+s1dFtCSx/5H4k5bEkfakM+A==
@@ -13946,12 +13946,7 @@ modify-values@^1.0.0:
resolved "https://registry.npmmirror.com/modify-values/-/modify-values-1.0.1.tgz"
integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==
moment@^2.24.0, moment@^2.29.2:
version "2.29.4"
resolved "https://registry.npmmirror.com/moment/-/moment-2.29.4.tgz"
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
moment@^2.29.4:
moment@^2.24.0, moment@^2.29.2, moment@^2.29.4:
version "2.29.4"
resolved "https://registry.npmmirror.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==