Skip to content

Commit

Permalink
fix: refactor toggle setter logic
Browse files Browse the repository at this point in the history
  • Loading branch information
wwsun committed May 14, 2024
1 parent da42d17 commit 23122bd
Show file tree
Hide file tree
Showing 11 changed files with 333 additions and 83 deletions.
12 changes: 12 additions & 0 deletions apps/playground/src/helpers/mock-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ import {
Input,
FormilyForm,
FormilyFormItem,
Table,
} from "@music163/antd";
import { Space } from "@music163/antd";
import { LocalButton } from "../components";
Expand All @@ -161,6 +162,14 @@ class App extends React.Component {
<Section tid="section1" title="Section Title">
your input: <Input tid="input1" defaultValue="hello" />
copy input: <Input value={tango.page.input1?.value} />
<Table
columns={[
{ title: "姓名", dataIndex: "name", key: "name" },
{ title: "年龄", dataIndex: "age", key: "age" },
{ title: "住址", dataIndex: "address", key: "address" },
]}
tid="table1"
/>
</Section>
<Section tid="section2">
<Space tid="space1">
Expand All @@ -175,6 +184,9 @@ class App extends React.Component {
</FormilyForm>
</Section>
<Section title="原生 DOM" tid="section4">
<h1 style={{ ...{ color: "red" }, fontSize: 64 }}>
hello world
</h1>
<div
style={{
border: "1px solid #ccc",
Expand Down
8 changes: 2 additions & 6 deletions apps/playground/src/layouts/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import React, { StrictMode } from 'react';
import React from 'react';
import { Outlet } from 'umi';
import './index.less';

export default function Layout() {
return (
<StrictMode>
<Outlet />
</StrictMode>
);
return <Outlet />;
}
141 changes: 125 additions & 16 deletions apps/storybook/src/setting-form.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { BorderSetter, DisplaySetter } from '@music163/tango-designer/src/setter
import { JsxSetter } from '@music163/tango-designer/src/setters/jsx-setter';
import { RenderSetter, TableCellSetter } from '@music163/tango-designer/src/setters/render-setter';
import { NumberSetter } from '@music163/tango-designer/src/setters/number-setter';
import { ActionListSetter } from '@music163/tango-designer/src/setters/action-list-setter';
import { ListSetter } from '@music163/tango-designer/src/setters/list-setter';
import { EnumSetter } from '@music163/tango-designer/src/setters/enum-setter';
import { Box } from 'coral-system';
import { JsonView } from '@music163/tango-ui';
import { toJS } from 'mobx';
Expand All @@ -23,6 +26,21 @@ register({
component: DisplaySetter,
});

register({
name: 'listSetter',
component: ListSetter as any,
});

register({
name: 'actionListSetter',
component: ActionListSetter,
});

register({
name: 'enumSetter',
component: EnumSetter,
});

register({
name: 'jsxSetter',
component: JsxSetter,
Expand Down Expand Up @@ -51,7 +69,7 @@ export default {
title: 'SettingForm',
};

const prototype: IComponentPrototype = {
const prototypeTest: IComponentPrototype = {
name: 'Test',
exportType: 'namedExport',
title: '测试',
Expand All @@ -69,6 +87,16 @@ const prototype: IComponentPrototype = {
docs: 'https://music-one.fn.netease.com/docs/button',
deprecated: '使用 text2 替代',
},
{
name: 'list',
title: 'listSetter',
setter: 'listSetter',
},
{
name: 'actionList',
title: 'actionListSetter',
setter: 'actionListSetter',
},
{
name: 'display',
title: 'displaySetter',
Expand Down Expand Up @@ -307,20 +335,13 @@ const FormValuePreview = observer(({ model }: { model: FormModel }) => {
return <JsonView src={data} />;
});

export function Basic() {
const model = new FormModel(
{
router: 'www.163.com',
expression: `{ foo: 'foo' }`,
object: {
name: 'Alice',
},
image:
'https://p6.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/13270238619/2cc5/0782/1d6e/009b96bf90c557b9bbde09b1687a2c80.png',
},
{ onChange: console.log },
);
interface SettingFormDemoProps {
initValues?: object;
prototype?: IComponentPrototype;
}

function SettingFormDemo({ initValues, prototype }: SettingFormDemoProps) {
const model = new FormModel(initValues, { onChange: console.log });
return (
<Box display="flex">
<Box flex="0 0 400px" overflow="hidden">
Expand All @@ -341,14 +362,102 @@ export function Basic() {
);
}

export function Basic() {
return (
<SettingFormDemo
initValues={{
bool: true,
enum: {
aaa: 'aaa',
bbb: 'bbb',
ccc: 'ccc',
},
list: [{ key: 1 }, { key: 2 }],
}}
prototype={{
name: 'Sample',
package: 'sample-pkg',
type: 'element',
props: [
{
name: 'bool',
title: 'boolSetter',
setter: 'boolSetter',
},
{
name: 'enum',
title: 'enumSetter',
setter: 'enumSetter',
},
{
name: 'list',
title: 'listSetter',
setter: 'listSetter',
},
],
}}
/>
);
}

export function InitValues() {
return (
<SettingFormDemo
initValues={{
bool: true,
bool1: '{{true}}',
}}
prototype={{
name: 'Sample',
package: 'sample-pkg',
type: 'element',
props: [
{
name: 'bool',
title: 'value初始化',
setter: 'boolSetter',
},
{
name: 'bool1',
title: 'value初始化',
setter: 'boolSetter',
},
{
name: 'bool2',
title: '无初值',
setter: 'boolSetter',
},
],
}}
/>
);
}

export function SetterList() {
return (
<SettingFormDemo
initValues={{
router: 'www.163.com',
expression: `{ foo: 'foo' }`,
object: {
name: 'Alice',
},
image:
'https://p6.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/13270238619/2cc5/0782/1d6e/009b96bf90c557b9bbde09b1687a2c80.png',
}}
prototype={prototypeTest}
/>
);
}

export function Lite() {
return (
<Box width={320} border="solid">
<SettingForm
showSearch={false}
showGroups={false}
showItemSubtitle={false}
prototype={prototype}
prototype={prototypeTest}
disableSwitchExpressionSetter
/>
</Box>
Expand All @@ -359,7 +468,7 @@ export function NoExpressionSwitch() {
const model = new FormModel({});
return (
<Box>
<SettingForm model={model} prototype={prototype} disableSwitchExpressionSetter />
<SettingForm model={model} prototype={prototypeTest} disableSwitchExpressionSetter />
</Box>
);
}
64 changes: 47 additions & 17 deletions packages/core/src/helpers/ast/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export function node2code(node: t.Node) {
}

/**
* 将 t.Node 生成为 js 值
* 将 t.Node 生成为 js 值(不适用于jsx value node)
* @param node ast node
* @param hasExpressionWrapper 是否包裹表达式
* @returns a plain javascript value
Expand All @@ -171,25 +171,26 @@ export function node2value(node: t.Node, hasExpressionWrapper = true): any {
case 'NullLiteral':
ret = null;
break;
case 'Identifier': // {data}
case 'MemberExpression': // {this.props.data}
case 'OptionalMemberExpression': // {a?.b}
case 'UnaryExpression': // {!false}
case 'ArrowFunctionExpression': // {() => {}}
case 'TemplateLiteral': // {`hello ${text}`}
case 'ConditionalExpression': // {a ? 'foo' : 'bar'}
case 'LogicalExpression': // { a || b}
case 'BinaryExpression': // { a + b}
case 'TaggedTemplateExpression': // {css``}
case 'CallExpression': // {[1,2,3].map(fn)}
case 'JSXElement': // {<Box>hello</Box>}
case 'JSXFragment': // <><Box /></>
case 'Identifier': // {{data}}
case 'MemberExpression': // {{this.props.data}}
case 'OptionalMemberExpression': // {{a?.b}}
case 'UnaryExpression': // {{!false}}
case 'ArrowFunctionExpression': // {{() => {}}}
case 'TemplateLiteral': // {{`hello ${text}`}}
case 'ConditionalExpression': // {{a ? 'foo' : 'bar'}}
case 'LogicalExpression': // {{ a || b}}
case 'BinaryExpression': // {{ a + b}}
case 'TaggedTemplateExpression': // {{css``}}
case 'CallExpression': // {{[1,2,3].map(fn)}}
case 'JSXElement': // {{<Box>hello</Box>}}
case 'JSXFragment': // {{<><Box /></>}}
ret = expression2code(node);
if (hasExpressionWrapper) {
ret = wrapCode(ret);
}
break;
case 'ObjectExpression': {
// FIXME: object, array 统一按照 code 进行处理,不解析为对象
ret = node.properties.reduce((prev, propertyNode) => {
if (propertyNode.type === 'ObjectProperty') {
const key = keyNode2value(propertyNode.key);
Expand All @@ -203,6 +204,7 @@ export function node2value(node: t.Node, hasExpressionWrapper = true): any {
break;
}
case 'ArrayExpression': {
// FIXME: array 统一按照 code 进行处理
ret = node.elements.map((elementNode) => node2value(elementNode, hasExpressionWrapper));
break;
}
Expand All @@ -214,7 +216,7 @@ export function node2value(node: t.Node, hasExpressionWrapper = true): any {
}

/**
* jsx 属性值节点转为 js value
* jsx prop value 节点转为 js value
*/
export function jsxAttributeValueNode2value(node: t.Node): any {
// e.g. <Checkbox checked /> 此时没有 value node
Expand All @@ -232,9 +234,37 @@ export function jsxAttributeValueNode2value(node: t.Node): any {
// <Foo bar={[]}>
ret = jsxAttributeValueNode2value(node.expression);
break;
default:
ret = node2value(node);
case 'StringLiteral':
case 'NumericLiteral':
case 'BooleanLiteral': {
ret = node.value;
break;
}
case 'NullLiteral':
ret = null;
break;
case 'ObjectExpression': // { key }
case 'ArrayExpression': // [{ key }]
case 'Identifier': // tango
case 'MemberExpression': // this.props.data
case 'OptionalMemberExpression': // a?.b
case 'UnaryExpression': // !false
case 'ArrowFunctionExpression': // () => {}
case 'TemplateLiteral': // `hello ${text}`
case 'ConditionalExpression': // a ? 'foo' : 'bar'
case 'LogicalExpression': // a || b
case 'BinaryExpression': // a + b
case 'TaggedTemplateExpression': // css``
case 'CallExpression': // [1,2,3].map(fn)
case 'JSXElement': // <Box>hello</Box>
case 'JSXFragment': // <><Box /></>
ret = expression2code(node);
ret = wrapCode(ret);
break;
default: {
logger.error('unknown ast node:', node);
break;
}
}

return ret;
Expand Down
1 change: 1 addition & 0 deletions packages/designer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * from './selection-menu';
export * from './widgets';
export * from './themes';
export * from './components';
export * from './setters';

export { register as registerSetter } from '@music163/tango-setting-form';

Expand Down
15 changes: 11 additions & 4 deletions packages/designer/src/setters/expression-setter.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import React, { useState, useEffect, useCallback } from 'react';
import { Box, Text, css } from 'coral-system';
import { Dropdown, Modal } from 'antd';
import { isValidExpressionCode, value2expressionCode } from '@music163/tango-core';
import { noop, useBoolean, getValue, IVariableTreeNode, wrapCode } from '@music163/tango-helpers';
import { isValidExpressionCode } from '@music163/tango-core';
import {
noop,
useBoolean,
getValue,
IVariableTreeNode,
wrapCode,
getCodeOfWrappedCode,
} from '@music163/tango-helpers';
import { CloseCircleFilled, ExpandAltOutlined, MenuOutlined } from '@ant-design/icons';
import { Panel, InputCode, Action } from '@music163/tango-ui';
import { FormItemComponentProps } from '@music163/tango-setting-form';
Expand Down Expand Up @@ -58,13 +65,13 @@ export function ExpressionSetter(props: ExpressionSetterProps) {
newStoreTemplate,
showOptionsDropDown = true,
} = props;
const codeValue = value2expressionCode(valueProp);
const codeValue = getCodeOfWrappedCode(valueProp);
const [inputValue, setInputValue] = useState(codeValue);
const [visible, { on, off }] = useBoolean();

// when receive new value, sync state
useEffect(() => {
const nextCodeValue = value2expressionCode(valueProp);
const nextCodeValue = getCodeOfWrappedCode(valueProp);
setInputValue(nextCodeValue);
}, [valueProp]);

Expand Down
Loading

0 comments on commit 23122bd

Please sign in to comment.