Compare commits

...

16 Commits

Author SHA1 Message Date
Wells
897fe0a5a1 chore(release): publish
- @music163/tango-context@1.0.2
 - @music163/tango-core@1.0.2
 - @music163/tango-designer@1.0.3
 - @music163/tango-helpers@1.0.0
 - @music163/tango-sandbox@1.0.2
 - @music163/tango-setting-form@1.1.0
 - @music163/tango-ui@1.0.3
2024-05-09 10:54:49 +08:00
Wells
b52bbad547 fix: disable toggle variable for expSetter & add isValid to workspace (#146)
* fix: add isValid to test if valid project

* fix: disable toggle variable for expSetter
2024-05-08 20:11:22 +08:00
864907600cc
f7c837a8a9 feat: support validate on formItem (#145)
Co-authored-by: ccloli <8115912+ccloli@users.noreply.github.com>
2024-05-08 19:57:32 +08:00
Wells
f64d178ab8 chore: up 2024-05-06 15:32:10 +08:00
maxwls
f2dcc942ed chore: support start playground in different os (#139)
Co-authored-by: 王龙生 <wanglongsheng@pansoft.com>
2024-05-06 15:31:09 +08:00
Wells
ac48a8880e fix: update setting form styles & sort deprecated props to the bottom (#142)
* fix: sort the deprecated props to the bottom

* fix: merge undefined props

* fix: update form label color
2024-05-06 15:30:29 +08:00
Wells
0f1711868d chore(release): publish
- @music163/tango-context@1.0.1
 - @music163/tango-core@1.0.1
 - @music163/tango-designer@1.0.2
 - @music163/tango-helpers@1.0.0-alpha.7
 - @music163/tango-sandbox@1.0.1
 - @music163/tango-setting-form@1.0.2
 - @music163/tango-ui@1.0.2
2024-04-22 11:36:47 +08:00
Wells
06cd3b3a18 chore: generate setting-form docs 2024-04-22 11:34:20 +08:00
Wells
2664613ab2 fix: allow reload state tree & display pageStore in variable tree (#135)
* fix: update state tree display

* fix: allow reload state tree

* fix: update action props

* fix: display pageStore in variable tree
2024-04-19 19:55:40 +08:00
Wells
e39a913a87 chore(release): publish
- @music163/tango-designer@1.0.1
 - @music163/tango-setting-form@1.0.1
 - @music163/tango-ui@1.0.1
2024-04-16 15:29:34 +08:00
Wells
52864b5400 fix: variable tree remove button event handling (#134)
* docs: add StrictMode

* fix: variable tree remove button event handling
2024-04-16 15:25:09 +08:00
BoBoooooo
27166ec949 fix: render-setter expression value bug (#133)
* Create sync.yml

* Update sync.yml

* fix: render-setter expression value bug

* ci: remove sync.yml
2024-04-16 10:33:54 +08:00
Wells
1a8d15c9da chore: up 2024-04-15 14:47:52 +08:00
Wells
43b99de01c chore(release): publish
- @music163/tango-context@1.0.0
 - @music163/tango-core@1.0.0
 - @music163/tango-designer@1.0.0
 - @music163/tango-sandbox@1.0.0
 - @music163/tango-setting-form@1.0.0
 - @music163/tango-ui@1.0.0
2024-04-15 14:41:25 +08:00
BoBoooooo
1c1ad9e5eb feat: support traverse native dom (#132)
* Create sync.yml

* Update sync.yml

* feat: support nativeDom

* ci: remove sync.yml

* fix: update test case

* fix: update isValidComponentName logic
2024-04-15 14:22:34 +08:00
BoBoooooo
776837079a feat: update ui & add dual screen mode (#131)
* fix: change view source icon

* fix: setting-form collapsed panel default collapsed

* fix: selectAction font size larger

* feat: add dual screen mode

* fix: trigger bug
2024-04-11 10:20:07 +08:00
52 changed files with 2786 additions and 23726 deletions

View File

@@ -4,7 +4,7 @@
"private": true,
"author": "Wells <ww.sun@outlook.com>",
"scripts": {
"dev": "HOST=local.netease.com PORT=8001 umi dev",
"dev": "cross-env HOST=local.netease.com PORT=8001 umi dev",
"build": "umi build",
"postinstall": "umi setup",
"setup": "umi setup",

View File

@@ -173,6 +173,60 @@ class App extends React.Component {
<FormilyFormItem name="select1" component="Select" label="表单项" />
</FormilyForm>
</Section>
<Section title="原生 DOM" tid="section4">
<div
style={{
border: "1px solid #ccc",
borderRadius: "5px",
backgroundColor: "#f4f4f4",
}}
>
<form onSubmit={tango.stores.app.submitForm} style={{
padding: "10px",
}}>
<div>
<label>Username:</label>
<input
type="text"
id="username"
name="username"
style={{ margin: "5px" }}
/>
</div>
<div>
<label>Password:</label>
<input
type="password"
id="password"
name="password"
style={{ margin: "5px" }}
/>
</div>
<div>
<label>Role:</label>
<select id="role" name="role" style={{ margin: "5px" }}>
<option value="admin">Admin</option>
<option value="user">User</option>
</select>
</div>
<div>
<button
type="submit"
style={{
marginTop: '5px',
padding: "3px 10px",
backgroundColor: "#007bff",
color: "#fff",
border: "none",
borderRadius: "5px",
}}
>
Submit
</button>
</div>
</form>
</div>
</Section>
</Page>
);
}
@@ -227,38 +281,21 @@ const storeApp = `
import { defineStore } from '@music163/tango-boot';
export default defineStore({
title: 'Page Title',
array: [1, 2, 3],
test: function() {
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
console.log('test');
},
submitForm: function(event) {
event.preventDefault();
const formData = new FormData(event.target);
const username = formData.get("username");
const password = formData.get("password");
const role = formData.get("role");
console.log("Submitted Data:", { username, password, role });
}
}, 'app');
`;

View File

@@ -85,8 +85,82 @@ basePrototypes['Section'].siblingNames = [
'Section',
];
export const nativeDomPrototypes = () => {
const doms = [
'div',
'span',
'h1',
'h2',
'p',
'a',
'img',
'ul',
'ol',
'li',
'input',
'button',
'form',
'table',
'tr',
'td',
'header',
'footer',
'nav',
'section',
'article',
'aside',
'main',
'video',
'audio',
'label',
'select',
'option',
'textarea',
'iframe',
];
const componentPrototypes: Dict<IComponentPrototype> = doms.reduce(
(acc: Dict<IComponentPrototype>, tag) => {
acc[tag] = {
name: tag,
title: tag,
hasChildren: true,
package: '',
type: 'element',
props: [
{
name: 'style',
title: '样式',
group: 'style',
setter: 'expressionSetter',
},
{
name: 'className',
title: '类名',
setter: 'textSetter',
},
{
name: 'id',
title: 'ID',
setter: 'textSetter',
},
{
name: 'onClick',
title: '点击事件',
setter: 'actionSetter',
group: 'event',
},
],
};
return acc;
},
{},
);
return componentPrototypes;
};
// iconfont: https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=2891794
const prototypes: Dict<IComponentPrototype> = {
...nativeDomPrototypes(),
...(basePrototypes as any),
SnippetSuccessResult,
Snippet2ColumnLayout,
@@ -100,6 +174,30 @@ const prototypes: Dict<IComponentPrototype> = {
package: '@music163/antd',
hasChildren: true,
siblingNames: ['Box'],
props: [
{
name: 'aaa',
title: 'aaa',
setter: 'textSetter',
},
{
name: 'bbb',
title: 'bbb',
setter: 'textSetter',
deprecated: true,
},
{
name: 'ccc',
title: 'ccc',
setter: 'textSetter',
deprecated: true,
},
{
name: 'd',
title: 'd',
setter: 'textSetter',
},
],
},
Columns: {
name: 'Columns',

View File

@@ -1,11 +1,11 @@
import React from 'react';
import React, { StrictMode } from 'react';
import { Outlet } from 'umi';
import './index.less';
export default function Layout() {
return (
<div>
<StrictMode>
<Outlet />
</div>
</StrictMode>
);
}

View File

@@ -63,6 +63,7 @@ const menuData = {
'Columns',
'Column',
'Box',
'Text',
'Space',
'Typography',
'Title',

View File

@@ -4,6 +4,7 @@ import { IComponentPrototype } from '@music163/tango-helpers';
import { BorderSetter, DisplaySetter } from '@music163/tango-designer/src/setters/style-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 { Box } from 'coral-system';
import { JsonView } from '@music163/tango-ui';
import { toJS } from 'mobx';
@@ -37,6 +38,11 @@ register({
component: TableCellSetter,
});
register({
name: 'numberSetter',
component: NumberSetter,
});
createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/c/font_2891794_cou9i7556tl.js',
});
@@ -274,6 +280,22 @@ const prototype: IComponentPrototype = {
title: 'invalidSetter',
setter: 'invalidSetter',
},
{
name: 'validate',
title: 'validate',
setter: 'numberSetter',
validate: (value) => {
if (!value && value !== 0) {
return '必填';
}
if (value < 0) {
return '必须大于 0';
}
if (value > 10) {
return '必须小于等于 10';
}
},
},
],
};

View File

@@ -40,6 +40,7 @@
"@typescript-eslint/parser": "^6.13.2",
"conventional-changelog-cli": "^4.1.0",
"copyfiles": "^2.4.1",
"cross-env": "^7.0.3",
"eslint": "^8.55.0",
"eslint-config-ali": "^14.0.2",
"eslint-config-prettier": "^9.1.0",

View File

@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.1](https://github.com/netease/tango/compare/@music163/tango-context@1.0.0...@music163/tango-context@1.0.1) (2024-04-22)
### Bug Fixes
- allow reload state tree & display pageStore in variable tree ([#135](https://github.com/netease/tango/issues/135)) ([2664613](https://github.com/netease/tango/commit/2664613ab263aead2a5239fa012454fc7fd5ff99))
# [1.0.0-alpha.10](https://github.com/netease/tango/compare/@music163/tango-context@1.0.0-alpha.9...@music163/tango-context@1.0.0-alpha.10) (2024-04-09)
**Note:** Version bump only for package @music163/tango-context

View File

@@ -1,6 +1,6 @@
{
"name": "@music163/tango-context",
"version": "1.0.0-alpha.10",
"version": "1.0.2",
"description": "react context for tango-apps",
"keywords": [
"react",
@@ -31,8 +31,8 @@
"react": ">= 16.8"
},
"dependencies": {
"@music163/tango-core": "^1.0.0-alpha.10",
"@music163/tango-helpers": "^1.0.0-alpha.6",
"@music163/tango-core": "^1.0.2",
"@music163/tango-helpers": "^1.0.0",
"mobx-react-lite": "4.0.5"
},
"publishConfig": {

View File

@@ -35,8 +35,14 @@ export const useWorkspaceData = () => {
const modelVariables: IVariableTreeNode[] = []; // 绑定变量列表
const storeActionVariables: IVariableTreeNode[] = []; // 模型中的所有 actions
const storeVariables: IVariableTreeNode[] = []; // 模型中的所有变量
const pageStoreVariables: IVariableTreeNode[] = []; // 页面中的组件实例变量
const serviceVariables: IVariableTreeNode[] = []; // 服务中的所有变量
pageStoreVariables.push({
title: 'pageStore',
key: 'pageStore',
});
Object.values(workspace.storeModules).forEach((file) => {
const prefix = `stores.${file.name}`;
const states: IVariableTreeNode[] = file.states.map((item) => ({
@@ -109,6 +115,7 @@ export const useWorkspaceData = () => {
}
let expressionVariables: IVariableTreeNode[] = [
buildVariableOptions('当前页面组件实例', '$pageStore', pageStoreVariables),
buildVariableOptions('数据模型', '$stores', storeVariables),
buildVariableOptions('服务函数', '$services', serviceVariables),
];

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.1](https://github.com/netease/tango/compare/@music163/tango-core@1.0.0...@music163/tango-core@1.0.1) (2024-04-22)
**Note:** Version bump only for package @music163/tango-core
# [1.0.0-alpha.10](https://github.com/netease/tango/compare/@music163/tango-core@1.0.0-alpha.9...@music163/tango-core@1.0.0-alpha.10) (2024-04-09)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@music163/tango-core",
"version": "1.0.0-alpha.10",
"version": "1.0.2",
"description": "tango core",
"author": "wwsun <ww.sun@outlook.com>",
"homepage": "",
@@ -28,7 +28,7 @@
"@babel/parser": "^7.23.5",
"@babel/traverse": "^7.23.5",
"@babel/types": "^7.23.5",
"@music163/tango-helpers": "^1.0.0-alpha.6",
"@music163/tango-helpers": "^1.0.0",
"@types/babel__generator": "^7.6.7",
"@types/babel__traverse": "^7.20.4",
"mobx": "6.12.0",

View File

@@ -155,7 +155,7 @@ export function prototype2code(prototype: IComponentPrototype, extraProps?: Dict
}))
: [];
// merge extraProps to props
const props = [...prototype.props, ...propList];
const props = [...(prototype.props || []), ...propList];
const keys =
props.reduce((acc, item) => {

View File

@@ -75,15 +75,20 @@ export function inferFileType(filename: string): FileType {
/**
* 判断组件名是否合法
* @example Button -> valid
* @example div -> invalid
* @example isStrict ? div -> invalid : div -> valid
* @param name
* @param isStrict 是否严格模式(严格模式不匹配原生标签)
* @returns
*/
export function isValidComponentName(name: string) {
export function isValidComponentName(name: string, isStrict = false) {
if (!name) {
return false;
}
if (!isStrict) {
return true;
}
const firstChar = name.charAt(0);
return firstChar === firstChar.toUpperCase();
}

View File

@@ -3,7 +3,7 @@ import { IWorkspace } from './interfaces';
export type SimulatorNameType = 'desktop' | 'phone';
export type DesignerViewType = 'design' | 'code';
export type DesignerViewType = 'design' | 'code' | 'dual';
interface ISimulatorType {
name: SimulatorNameType;

View File

@@ -285,9 +285,16 @@ export interface IWorkspace {
* 解析后的项目配置信息
*/
get projectConfig(): ITangoConfigJson;
/**
* 当前活动的视图文件
*/
get activeViewModule(): IViewFile;
get pages(): any[];
get bizComps(): string[];
get baseComps(): string[];
get localComps(): string[];
/**
* 是否是合法的项目
*/
get isValid(): boolean;
}

View File

@@ -144,6 +144,13 @@ export class Workspace extends EventTarget implements IWorkspace {
*/
private copyTempNodes: TangoNode[];
/**
* 是否是合法的项目
*/
get isValid() {
return !!this.tangoConfigJson && !!this.activeViewModule;
}
/**
* 项目配置,返回解析后的 tango.config.json 文件
*/

View File

@@ -161,6 +161,10 @@ describe('string helpers', () => {
it('isValidComponentName', () => {
expect(isValidComponentName('Button')).toBeTruthy();
expect(isValidComponentName('Button.Group')).toBeTruthy();
expect(isValidComponentName('div')).toBeTruthy();
expect(isValidComponentName('')).toBeFalsy();
expect(isValidComponentName(null)).toBeFalsy();
expect(isValidComponentName(undefined)).toBeFalsy();
});
it('inferFileType', () => {

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,19 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.2](https://github.com/netease/tango/compare/@music163/tango-designer@1.0.1...@music163/tango-designer@1.0.2) (2024-04-22)
### Bug Fixes
- allow reload state tree & display pageStore in variable tree ([#135](https://github.com/netease/tango/issues/135)) ([2664613](https://github.com/netease/tango/commit/2664613ab263aead2a5239fa012454fc7fd5ff99))
## [1.0.1](https://github.com/netease/tango/compare/@music163/tango-designer@1.0.0...@music163/tango-designer@1.0.1) (2024-04-16)
### Bug Fixes
- render-setter expression value bug ([#133](https://github.com/netease/tango/issues/133)) ([27166ec](https://github.com/netease/tango/commit/27166ec94976979cb59130788399d90977cf0aec))
- variable tree remove button event handling ([#134](https://github.com/netease/tango/issues/134)) ([52864b5](https://github.com/netease/tango/commit/52864b540095025232ae237134d6be5701d20549))
# [1.0.0-alpha.18](https://github.com/netease/tango/compare/@music163/tango-designer@1.0.0-alpha.17...@music163/tango-designer@1.0.0-alpha.18) (2024-04-09)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@music163/tango-designer",
"version": "1.0.0-alpha.18",
"version": "1.0.3",
"description": "lowcode designer",
"keywords": [
"react"
@@ -33,12 +33,12 @@
"dependencies": {
"@ant-design/icons": "^4.8.0",
"@music163/request": "^0.1.2",
"@music163/tango-context": "^1.0.0-alpha.10",
"@music163/tango-core": "^1.0.0-alpha.10",
"@music163/tango-helpers": "^1.0.0-alpha.6",
"@music163/tango-sandbox": "^1.0.0-alpha.10",
"@music163/tango-setting-form": "^1.0.0-alpha.14",
"@music163/tango-ui": "^1.0.0-alpha.12",
"@music163/tango-context": "^1.0.2",
"@music163/tango-core": "^1.0.2",
"@music163/tango-helpers": "^1.0.0",
"@music163/tango-sandbox": "^1.0.2",
"@music163/tango-setting-form": "^1.1.0",
"@music163/tango-ui": "^1.0.3",
"antd": "^4.24.2",
"cash-dom": "^8.1.2",
"classnames": "^2.3.2",

View File

@@ -204,7 +204,8 @@ export function VariableTree(props: VariableTreeProps) {
{node.showRemoveButton && (
<Popconfirm
title={`确认删除吗 ${node.title}?该操作会导致引用此模型的代码报错,请谨慎操作!`}
onConfirm={() => {
onConfirm={(e) => {
e.stopPropagation();
if (isStoreVariablePath(node.key)) {
onRemoveStoreVariable(node.key);
} else {

View File

@@ -1,7 +1,6 @@
import React from 'react';
import { observer, useDesigner } from '@music163/tango-context';
import { SelectAction } from '@music163/tango-ui';
import { AimOutlined } from '@ant-design/icons';
import { SelectAction, CodeOutlined } from '@music163/tango-ui';
export const ViewSourceAction = observer(() => {
const designer = useDesigner();
@@ -12,7 +11,7 @@ export const ViewSourceAction = observer(() => {
designer.setActiveView('code');
}}
>
<AimOutlined />
<CodeOutlined />
</SelectAction>
);
});

View File

@@ -43,6 +43,7 @@ const setters: IFormItemCreateOptions[] = [
name: 'expSetter',
alias: ['expressionSetter'],
component: ExpressionSetter,
disableVariableSetter: true,
},
{
name: 'numberSetter',

View File

@@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { ActionSelect, InputCode } from '@music163/tango-ui';
import { FormItemComponentProps } from '@music163/tango-setting-form';
import { Box } from 'coral-system';
import { value2expressionCode } from '@music163/tango-core';
interface IRenderOption {
label: string;
@@ -26,10 +27,11 @@ export function RenderSetter({
options = [],
fallbackOption,
}: FormItemComponentProps & RenderSetterProps) {
const [inputValue, setInputValue] = useState(value);
const [inputValue, setInputValue] = useState(() => {
return value2expressionCode(value);
});
useEffect(() => {
setInputValue(value);
setInputValue(value2expressionCode(value));
}, [value]);
const optionsMap = useMemo(() => {
@@ -53,9 +55,9 @@ export function RenderSetter({
return (
<Box>
<ActionSelect text={text} options={options} onSelect={onSelect} />
{value && (
{inputValue && (
<InputCode
value={value}
value={inputValue}
onChange={(val) => setInputValue(val)}
onBlur={() => onChange(inputValue)}
/>

View File

@@ -23,11 +23,7 @@ export function OutlinePanel({ showStateView = true, ...treeProps }: OutlineView
>
<ComponentsTree {...treeProps} />
</CollapsePanel>
{showStateView && (
<CollapsePanel title="页面状态" stickyHeader maxHeight="90%" overflowY="auto">
<StateTree />
</CollapsePanel>
)}
{showStateView && <StateTree />}
</Box>
);
}

View File

@@ -1,7 +1,8 @@
import React, { useEffect, useReducer } from 'react';
import { observer } from '@music163/tango-context';
import { isFunction, isObject, pick } from '@music163/tango-helpers';
import { JsonView } from '@music163/tango-ui';
import { CollapsePanel, IconButton, JsonView } from '@music163/tango-ui';
import { ReloadOutlined } from '@ant-design/icons';
import { useSandboxQuery } from '../../context';
function processTango(obj: any = {}, index = 0) {
@@ -26,7 +27,7 @@ export const StateTree = observer(() => {
const [, forceUpdate] = useReducer((x) => x + 1, 0);
const tangoContext = pick(sandboxQuery.window['tango'] || {}, [
'stores',
'page',
'pageStore',
'services',
'config',
]);
@@ -34,6 +35,7 @@ export const StateTree = observer(() => {
forceUpdate();
};
useEffect(() => {
// FIXME: 优化这段代码,应该监听 tangoContext 的变化,来刷新
const settingForm = document.querySelector('.SettingPanel');
const ob = new MutationObserver(callback);
if (settingForm) {
@@ -48,13 +50,31 @@ export const StateTree = observer(() => {
};
}, []);
return (
<JsonView
src={processTango(tangoContext)}
collapsed={1}
name="tango"
displayObjectSize={false}
indentWidth={2}
enableCopy
/>
<CollapsePanel
title="页面状态"
stickyHeader
maxHeight="90%"
overflowY="auto"
extra={
<IconButton
tooltip="同步状态"
size="small"
icon={<ReloadOutlined />}
onClick={(e) => {
e.stopPropagation();
forceUpdate();
}}
/>
}
>
<JsonView
src={processTango(tangoContext)}
collapsed={1}
name="tango"
displayObjectSize={false}
indentWidth={2}
enableCopy
/>
</CollapsePanel>
);
});

View File

@@ -1,13 +1,25 @@
import React from 'react';
import React, { useCallback } from 'react';
import { Group } from 'coral-system';
import { Modal } from 'antd';
import { ToggleButton, CodeOutlined } from '@music163/tango-ui';
import { ToggleButton, CodeOutlined, DualOutlined } from '@music163/tango-ui';
import { observer, useDesigner, useWorkspace } from '@music163/tango-context';
import { BorderOutlined } from '@ant-design/icons';
export const ModeSwitchTool = observer(() => {
const workspace = useWorkspace();
const designer = useDesigner();
const activeFileCheck = useCallback(() => {
if (workspace.activeFile !== workspace.activeViewFile) {
Modal.confirm({
title: '当前打开的文件与视图不匹配,是否切换到当前视图对应的文件?',
onOk: () => {
workspace.setActiveFile(workspace.activeViewFile);
},
});
}
}, [workspace]);
return (
<Group attached>
<ToggleButton
@@ -26,19 +38,24 @@ export const ModeSwitchTool = observer(() => {
onClick={() => {
designer.setActiveView('code'); // 切换到源码视图
designer.setActiveSidebarPanel(''); // 关闭左侧面板
if (workspace.activeFile !== workspace.activeViewFile) {
Modal.confirm({
title: '当前打开的文件与视图不匹配,是否切换到当前视图对应的文件?',
onOk: () => {
workspace.setActiveFile(workspace.activeViewFile);
},
});
}
activeFileCheck();
}}
tooltip="源码视图"
>
<CodeOutlined />
</ToggleButton>
<ToggleButton
shape="ghost"
selected={designer.activeView === 'dual'}
onClick={() => {
designer.setActiveView('dual'); // 切换到双屏视图
designer.setActiveSidebarPanel(''); // 关闭左侧面板
activeFileCheck();
}}
tooltip="双屏视图"
>
<DualOutlined />
</ToggleButton>
</Group>
);
});

View File

@@ -13,7 +13,7 @@ export const PreviewTool = observer(() => {
onClick={() => {
const nextIsPreview = !designer.isPreview;
designer.toggleIsPreview(nextIsPreview);
if (nextIsPreview) {
if (nextIsPreview && designer.activeView === 'code') {
designer.setActiveView('design');
}
}}

View File

@@ -9,7 +9,6 @@ export function WorkspacePanel({ children }: WorkspacePanelProps) {
<Box
flex="1"
display="flex"
flexDirection="column"
overflow="hidden"
bg="colors.custom.viewportBg"
position="relative"

View File

@@ -21,7 +21,7 @@ export const WorkspaceView = observer((props: WorkspaceViewProps) => {
return (
<Box
className={`ViewPanel ${mode}`}
display={display}
display={designer.activeView === 'dual' ? 'block' : display}
flex="1"
overflow={overflow}
position="relative"

View File

@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.0.0-alpha.7](https://github.com/netease/tango/compare/@music163/tango-helpers@1.0.0-alpha.6...@music163/tango-helpers@1.0.0-alpha.7) (2024-04-22)
### Bug Fixes
- allow reload state tree & display pageStore in variable tree ([#135](https://github.com/netease/tango/issues/135)) ([2664613](https://github.com/netease/tango/commit/2664613ab263aead2a5239fa012454fc7fd5ff99))
# [1.0.0-alpha.6](https://github.com/netease/tango/compare/@music163/tango-helpers@1.0.0-alpha.5...@music163/tango-helpers@1.0.0-alpha.6) (2024-04-09)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@music163/tango-helpers",
"version": "1.0.0-alpha.6",
"version": "1.0.0",
"description": "Shared types, helpers, and hooks of tango-apps",
"keywords": [
"shared",

View File

@@ -50,7 +50,7 @@ export function isNil(val: any) {
* @returns
*/
export function isStoreVariablePath(key: string) {
return /^stores\.[a-zA-Z0-9]+\.\w+$/.test(key);
return key === 'pageStore' || /^stores\.[a-zA-Z0-9]+\.\w+$/.test(key);
}
/**

View File

@@ -19,6 +19,15 @@ export type ComponentDndRulesType = IComponentDndRules;
*/
export type ComponentPrototypeType = IComponentPrototype;
/**
* 组件校验规则
*/
export type ComponentPropValidate = (
value: any,
field: any,
trigger: string,
) => string | Promise<string>;
/**
* 组件属性类型
*/
@@ -107,6 +116,10 @@ export interface IComponentProp<T = any> {
* 动态设置表单项是否展示
*/
getVisible?: (form: any) => boolean;
/**
* 表单值校验逻辑
*/
validate?: ComponentPropValidate;
/**
* 标记属性是否已废弃
*/

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.1](https://github.com/netease/tango/compare/@music163/tango-sandbox@1.0.0...@music163/tango-sandbox@1.0.1) (2024-04-22)
**Note:** Version bump only for package @music163/tango-sandbox
# [1.0.0-alpha.10](https://github.com/netease/tango/compare/@music163/tango-sandbox@1.0.0-alpha.9...@music163/tango-sandbox@1.0.0-alpha.10) (2024-04-09)
**Note:** Version bump only for package @music163/tango-sandbox

View File

@@ -1,6 +1,6 @@
{
"name": "@music163/tango-sandbox",
"version": "1.0.0-alpha.10",
"version": "1.0.2",
"description": "sandbox of tango apps",
"author": "wwsun <ww.sun@outlook.com>",
"homepage": "",
@@ -29,8 +29,8 @@
},
"dependencies": {
"@ant-design/icons": "^4.8.0",
"@music163/tango-core": "^1.0.0-alpha.10",
"@music163/tango-helpers": "^1.0.0-alpha.6",
"@music163/tango-core": "^1.0.2",
"@music163/tango-helpers": "^1.0.0",
"crypto-js": "^4.1.1",
"lodash.isequal": "4.5.0",
"react-frame-component": "^5.2.4"

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.2](https://github.com/netease/tango/compare/@music163/tango-setting-form@1.0.1...@music163/tango-setting-form@1.0.2) (2024-04-22)
**Note:** Version bump only for package @music163/tango-setting-form
## [1.0.1](https://github.com/netease/tango/compare/@music163/tango-setting-form@1.0.0...@music163/tango-setting-form@1.0.1) (2024-04-16)
**Note:** Version bump only for package @music163/tango-setting-form
# [1.0.0-alpha.14](https://github.com/netease/tango/compare/@music163/tango-setting-form@1.0.0-alpha.13...@music163/tango-setting-form@1.0.0-alpha.14) (2024-04-09)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@music163/tango-setting-form",
"version": "1.0.0-alpha.14",
"version": "1.1.0",
"description": "setting form of tango-apps",
"author": "wwsun <ww.sun@outlook.com>",
"homepage": "",
@@ -28,9 +28,9 @@
},
"dependencies": {
"@ant-design/icons": "^4.8.0",
"@music163/tango-core": "^1.0.0-alpha.10",
"@music163/tango-helpers": "^1.0.0-alpha.6",
"@music163/tango-ui": "^1.0.0-alpha.12",
"@music163/tango-core": "^1.0.2",
"@music163/tango-helpers": "^1.0.0",
"@music163/tango-ui": "^1.0.3",
"antd": "^4.24.2",
"coral-system": "^1.0.5",
"mobx": "6.12.0",

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { toJS } from 'mobx';
import { observer } from 'mobx-react-lite';
import { clone, IComponentProp, useBoolean } from '@music163/tango-helpers';
import { clone, ComponentPropValidate, IComponentProp, useBoolean } from '@music163/tango-helpers';
import { isWrappedByExpressionContainer } from '@music163/tango-core';
import { ToggleButton, CodeOutlined } from '@music163/tango-ui';
import { InputProps } from 'antd';
@@ -58,7 +58,7 @@ export interface IFormItemCreateOptions {
/**
* 默认的表单值校验逻辑
*/
validate?: (value: string) => string | Promise<any>;
validate?: ComponentPropValidate;
}
const defaultGetSetterProps = () => ({});
@@ -86,6 +86,7 @@ export function createFormItem(options: IFormItemCreateOptions) {
extra,
footer,
noStyle,
validate,
}: FormItemProps) {
const { disableSwitchExpressionSetter, showItemSubtitle } = useFormVariable();
const model = useFormModel();
@@ -99,7 +100,7 @@ export function createFormItem(options: IFormItemCreateOptions) {
const setterName = isVariable ? 'expressionSetter' : setter;
field.setConfig({
validate: options.validate,
validate: validate || options.validate,
});
const baseComponentProps = clone(

View File

@@ -234,11 +234,11 @@ export class Field {
this.state.validating = false;
this.state.error = error;
// 校验错误,不触发 onChange
if (error) {
return error;
}
// 校验错误,不触发 onChange
this.parent?.onChange?.(this.name, this.value, this);
}),
);

View File

@@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { css, Box, HTMLCoralProps, Link } from 'coral-system';
import { Checkbox, Tooltip } from 'antd';
import { CollapsePanel } from '@music163/tango-ui';
import { isNil, isString } from '@music163/tango-helpers';
import { isString } from '@music163/tango-helpers';
import { WarningOutlined } from '@ant-design/icons';
export interface FormControlProps extends Omit<FormLabelProps, 'type'> {
@@ -62,10 +62,6 @@ export interface FormControlGroupProps extends FormLabelProps {
* 是否勾选
*/
checked?: boolean;
/**
* checkbox 默认是否勾选
*/
defaultChecked?: boolean;
}
export function FormControlGroup({
@@ -78,9 +74,9 @@ export function FormControlGroup({
children,
onCheck,
checked,
defaultChecked = false,
}: FormControlGroupProps) {
const [collapsed, setCollapsed] = useState(isNil(checked) ? !defaultChecked : !checked);
// 默认折叠
const [collapsed, setCollapsed] = useState(true);
return (
<CollapsePanel
collapsed={collapsed}
@@ -98,7 +94,7 @@ export function FormControlGroup({
onCheck?.(nextChecked);
}}
/>
<FormLabel type="secondary" label={label} note={note} tip={tip} docs={docs} />
<FormLabel label={label} note={note} tip={tip} docs={docs} />
</Box>
}
extra={
@@ -152,11 +148,6 @@ const tipStyle = css`
`;
interface FormLabelProps extends HTMLCoralProps<'div'> {
/**
* 类型
*/
// eslint-disable-next-line react/no-unused-prop-types
type?: 'normal' | 'secondary';
/**
* 标签
*/
@@ -180,15 +171,7 @@ interface FormLabelProps extends HTMLCoralProps<'div'> {
deprecated?: boolean | string;
}
function FormLabel({
type = 'normal',
label,
note,
tip,
docs,
deprecated,
...rest
}: FormLabelProps) {
function FormLabel({ label, note, tip, docs, deprecated, ...rest }: FormLabelProps) {
let help: React.ReactNode;
if (deprecated || docs) {
help = (
@@ -213,16 +196,11 @@ function FormLabel({
help = tip;
}
const labelColor = {
normal: 'text.body',
secondary: 'text.note',
}[type];
let labelNode = (
<Box
as="span"
display="inline-block"
color={labelColor}
color="text2"
className={help ? 'hasHelp' : ''}
css={labelStyle}
title={isString(label) ? label : undefined}
@@ -240,7 +218,7 @@ function FormLabel({
<Box fontSize="14px" {...rest}>
{labelNode}
{note && (
<Box as="i" display="inline-block" fontSize="12px" color="text.note" ml="m">
<Box as="i" display="inline-block" fontSize="12px" color="text3" ml="m">
{note}
</Box>
)}

View File

@@ -165,7 +165,15 @@ export function SettingForm({
// 没有进行搜索的情况
if (!keyword) {
if (showGroups) {
return componentPropGroups[tabKey] || [];
return (
componentPropGroups[tabKey].sort((a, b) => {
// TIP: 将废弃属性往后移
if (!a.deprecated && b.deprecated) {
return -1;
}
return 1;
}) || []
);
} else {
return computedProps;
}

View File

@@ -76,6 +76,7 @@ export function registerBuiltinSetters() {
register({
name: 'expressionSetter',
component: ExpressionSetter,
disableVariableSetter: true,
});
register({

View File

@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.2](https://github.com/netease/tango/compare/@music163/tango-ui@1.0.1...@music163/tango-ui@1.0.2) (2024-04-22)
### Bug Fixes
- allow reload state tree & display pageStore in variable tree ([#135](https://github.com/netease/tango/issues/135)) ([2664613](https://github.com/netease/tango/commit/2664613ab263aead2a5239fa012454fc7fd5ff99))
## [1.0.1](https://github.com/netease/tango/compare/@music163/tango-ui@1.0.0...@music163/tango-ui@1.0.1) (2024-04-16)
**Note:** Version bump only for package @music163/tango-ui
# [1.0.0-alpha.12](https://github.com/netease/tango/compare/@music163/tango-ui@1.0.0-alpha.11...@music163/tango-ui@1.0.0-alpha.12) (2024-04-09)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@music163/tango-ui",
"version": "1.0.0-alpha.12",
"version": "1.0.3",
"description": "ui widgets of tango",
"keywords": [
"react",
@@ -38,14 +38,14 @@
"@codemirror/lang-javascript": "^6.2.1",
"@codemirror/lint": "^6.4.2",
"@codemirror/search": "^6.5.5",
"@music163/tango-helpers": "^1.0.0-alpha.6",
"@music163/tango-helpers": "^1.0.0",
"@uiw/react-codemirror": "^4.21.21",
"antd": "^4.24.2",
"classnames": "^2.5.1",
"coral-system": "^1.0.5",
"eslint-linter-browserify": "^8.51.0",
"react-json-view": "^1.21.3",
"react-monaco-editor-lite": "^1.2.4"
"react-monaco-editor-lite": "^1.3.2"
},
"publishConfig": {
"access": "public",

View File

@@ -68,6 +68,7 @@ export interface ActionProps extends HTMLCoralProps<any> {
*/
className?: string;
children?: React.ReactNode;
onClick?: React.MouseEventHandler;
}
export function Action({

View File

@@ -0,0 +1,17 @@
import React from 'react';
import { createIcon } from './create-icon';
const DualOutlinedSvg = () => (
<svg
viewBox="0 0 1025 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
fill="currentColor"
>
<path d="M912 64H112c-26.5 0-48 21.5-48 48v800c0 26.5 21.5 48 48 48h800c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM136 193h340v695H136V193z m412 695V193h340v695H548z" />
</svg>
);
export const DualOutlined = createIcon(DualOutlinedSvg, 'DualOutlined');

View File

@@ -8,3 +8,4 @@ export * from './open-panel-left-outlined';
export * from './open-panel-right-outlined';
export * from './undo-outlined';
export * from './redo-outlined';
export * from './dual-outlined';

View File

@@ -21,7 +21,7 @@ export function SelectAction({ tooltip, children, ...rest }: SelectActionProps)
bg="brand"
color="white"
px="s"
fontSize="body"
fontSize="subtitle"
css={selectionActionStyle}
{...rest}
>

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://typedoc.org/schema.json",
"name": "Tango LowCode Builder",
"entryPoints": ["packages/core", "packages/designer", "packages/helpers"],
"entryPoints": ["packages/core", "packages/designer","packages/setting-form", "packages/helpers"],
"entryPointStrategy": "packages",
"exclude": ["packages/**/tests/**/*"],
"out": "docs",

5019
yarn.lock

File diff suppressed because it is too large Load Diff