mirror of
https://github.com/NetEase/tango.git
synced 2026-08-31 09:30:28 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 308db9cac8 | |||
| a1dbf785a5 | |||
| 813eb83ebb |
@@ -232,6 +232,7 @@ export const sampleFiles = [
|
||||
{ filename: '/src/stores/app.js', code: storeApp },
|
||||
{ filename: '/src/stores/counter.js', code: storeCounter },
|
||||
{ filename: '/src/services/index.js', code: serviceCode },
|
||||
{ filename: '/src/utils/index.js', code: `export function foo() {}` },
|
||||
];
|
||||
|
||||
export const genDefaultPage = (index: number) => ({
|
||||
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 297 KiB After Width: | Height: | Size: 279 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 254 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
@@ -6,7 +6,7 @@ tags: [netease, tango, open-source]
|
||||
|
||||
## 📝 Introduction
|
||||
|
||||
Tango is a low-code designer framework for quickly building low-code platforms. With Tango, you only need a few lines of code to build a basic low-code platform frontend system. The Tango low-code designer directly reads the source code of the frontend project, executes and renders the frontend view based on the source code, and provides users with low-code visual building capabilities. User's building operations will be translated into modifications to the source code. With low-code tools or platforms built using Tango, it is possible to achieve the effect of "source code in, source code out" and seamlessly integrate with the existing R&D system within the enterprise.
|
||||
Tango is a low-code builder framework for quickly building low-code platforms or tools. With Tango, you only need a few lines of code to build a basic low-code builder. The Tango low-code builder reads the source code of the frontend project directly, executes and renders the frontend view based on the source code, and provides users with low-code visual building capabilities. User's building operations will be translated into modifications to the source code. With low-code tools or platforms built using Tango, it is possible to achieve the effect of "source code in, source code out" and seamlessly integrate with the existing development flow within the enterprise.
|
||||
|
||||
### ✨ Features
|
||||
|
||||
@@ -20,11 +20,11 @@ Tango is a low-code designer framework for quickly building low-code platforms.
|
||||
|
||||
Due to the fact that the engine kernel is completely based on the source code-driven implementation, Tango low-code engine can achieve the visualization building capability of source code input and source code output, without providing any private intermediate products. If the company already has a complete R&D system (code hosting, building, deployment, CDN), Tango low-code engine can be directly used to integrate with existing services to build a low-code development platform.
|
||||
|
||||
<img src="https://p5.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/13140534982/ee2e/f42c/cc9a/184e2918a011b57d46e6c64a2722fa44.png" />
|
||||

|
||||
|
||||
### 📄 Code in, Code out
|
||||
|
||||
由于引擎内核完全基于源代码驱动实现,Tango 低代码引擎能够实现源代码进,源代码出的可视化搭建能力,不提供任何私有的中间产物。如果公司内部已经有了一套完善的研发体系(代码托管、构建、部署、CDN),那么可以直接使用 Tango 低代码引擎与现有的服务集成构建低代码开发平台。
|
||||
Due to the engine kernel being completely driven by source code, the Tango low-code engine can achieve the visual construction capability of source code in and source code out, without providing any private intermediate products. If the company already has a complete development system (code hosting, building, deployment, CDN), then it can directly use the Tango low-code engine to integrate with existing services to build a low-code development platform.
|
||||
|
||||

|
||||
|
||||
@@ -32,23 +32,24 @@ Due to the fact that the engine kernel is completely based on the source code-dr
|
||||
|
||||
Compared to the low-code building solution based on private schema, Tango low-code engine has the following advantages:
|
||||
|
||||
| Comparison Items | Schema-base low-code solution | Tango (Code-based) |
|
||||
| ---------------- | ----------------------------------------- | ------------------------------------------- |
|
||||
| Applicable Scenarios | Targeted vertical building scenarios, such as forms, marketing pages, etc. | 🔥 Applicable to application building scenarios centered on source code |
|
||||
| Language Capabilities | Relies on private protocols for extension, inflexible, and difficult to align with programming language capabilities | 🔥 Based directly on JavaScript language, can use all language features, no extensibility issues |
|
||||
| Development Capability | LowCode | 🔥 LowCode + ProCode |
|
||||
| Source Code Export | Centered on schema, one-way code output, irreversible | 🔥 Source code-centered, two-way transcoding |
|
||||
| Custom Dependencies | Need to be encapsulated according to private protocol extension, high customization cost | 🔥 Existing components can be seamlessly and low-cost integrated |
|
||||
| Integrated R&D Facilities | High customization cost, additional customization required | 🔥 Low-cost integration, can directly reuse existing deployment and publishing capabilities |
|
||||
| Comparison Items | Schema-base low-code solution | Tango (Code-based) |
|
||||
| ------------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
||||
| Applicable Scenarios | Targeted vertical building scenarios, such as forms, marketing pages, etc. | 🔥 Applicable to application building scenarios centered on source code |
|
||||
| Language Capabilities | Relies on private protocols for extension, inflexible, and difficult to align with programming language capabilities | 🔥 Based directly on JavaScript language, can use all language features, no extensibility issues |
|
||||
| Development Capability | LowCode | 🔥 LowCode + ProCode |
|
||||
| Source Code Export | Centered on schema, one-way code output, irreversible | 🔥 Source code-centered, two-way transcoding |
|
||||
| Custom Dependencies | Need to be encapsulated according to private protocol extension, high customization cost | 🔥 Existing components can be seamlessly and low-cost integrated |
|
||||
| Integrated R&D Facilities | High customization cost, additional customization required | 🔥 Low-cost integration, can directly reuse existing deployment and publishing capabilities |
|
||||
|
||||
The specific technical architecture is shown in the following figure:
|
||||
|
||||
## 📐 Architecture
|
||||
|
||||
The Tango low-code engine has been layered and decoupled in implementation, enabling independent development and maintenance of the upper-level low-code platform and the lower-level low-code engine, allowing for fast integration and deployment. In addition, Tango's low-code engine defines an open material ecosystem, allowing developers to freely contribute to extension components and configure property setters that enhance low-code materials.
|
||||
|
||||
The specific technical architecture is shown in the following diagram.
|
||||
|
||||

|
||||

|
||||
|
||||
## ⏰ Milestones
|
||||
|
||||
@@ -58,6 +59,7 @@ Tango low-code engine is the core component of NetEase Cloud Music's internal lo
|
||||
2. We plan to release the 1.0 Beta version of the low-code engine on September 30th this year. This version will refactor the core implementation for community scenarios, remove some compatibility code we have internally in Cloud Music, and optimize the implementation of the core.
|
||||
3. We plan to release the 1.0 RC version of the low-code engine on October 30th this year. This version will ensure that the core API is basically stable and no longer has BREAKING CHANGE. At the same time, we will provide comprehensive and detailed development guides, deployment documents, and demonstration applications.
|
||||
4. The official version will be released before the end of Q4 2023, and we will further improve our open source community operation mechanism.
|
||||
|
||||

|
||||
|
||||
## 🤝 Community
|
||||
@@ -74,3 +76,5 @@ Welcome everyone to join our community and participate in the open source constr
|
||||
Thanks to the Netease Cloud Music Public Technical Team, the Front-End Team, the Live Broadcasting Technical Team, and all the colleagues who participated in the Tango project.
|
||||
|
||||
Thanks to the Sandpack project provided by CodeSandbox, which provides powerful browser-based code building and execution capabilities for Tango.
|
||||
|
||||
Tanks to the Babel project, which provides powerful javascript ast parsing and traversing capabilities for Tango.
|
||||
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 259 KiB |
@@ -25,8 +25,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.4.1",
|
||||
"@tsconfig/docusaurus": "^1.0.5",
|
||||
"typescript": "^4.7.4"
|
||||
"@tsconfig/docusaurus": "^1.0.5"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [0.1.4](https://github.com/netease/tango/compare/@music163/tango-context@0.1.3...@music163/tango-context@0.1.4) (2023-09-18)
|
||||
|
||||
**Note:** Version bump only for package @music163/tango-context
|
||||
|
||||
## [0.1.3](https://github.com/netease/tango/compare/@music163/tango-context@0.1.2...@music163/tango-context@0.1.3) (2023-09-13)
|
||||
|
||||
**Note:** Version bump only for package @music163/tango-context
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@music163/tango-context",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.4",
|
||||
"description": "react context for tango-apps",
|
||||
"keywords": [
|
||||
"react",
|
||||
@@ -28,11 +28,11 @@
|
||||
"prepublishOnly": "yarn build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.8.0"
|
||||
"react": ">= 16.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"@music163/tango-core": "^0.1.3",
|
||||
"@music163/tango-helpers": "^0.1.2",
|
||||
"@music163/tango-core": "^0.1.4",
|
||||
"@music163/tango-helpers": "^0.1.3",
|
||||
"mobx-react-lite": "4.0.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [0.1.4](https://github.com/netease/tango/compare/@music163/tango-core@0.1.3...@music163/tango-core@0.1.4) (2023-09-18)
|
||||
|
||||
**Note:** Version bump only for package @music163/tango-core
|
||||
|
||||
## [0.1.3](https://github.com/netease/tango/compare/@music163/tango-core@0.1.2...@music163/tango-core@0.1.3) (2023-09-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@music163/tango-core",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.4",
|
||||
"description": "tango core",
|
||||
"author": "wwsun <ww.sun@outlook.com>",
|
||||
"homepage": "",
|
||||
@@ -28,12 +28,15 @@
|
||||
"@babel/parser": "^7.22.15",
|
||||
"@babel/traverse": "^7.22.15",
|
||||
"@babel/types": "^7.22.15",
|
||||
"@music163/tango-helpers": "^0.1.2",
|
||||
"@music163/tango-helpers": "^0.1.3",
|
||||
"@types/babel__generator": "^7.6.4",
|
||||
"@types/babel__traverse": "^7.18.3",
|
||||
"mobx": "6.9.0",
|
||||
"path-browserify": "^1.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"mobx": "6.9.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
|
||||
@@ -17,8 +17,6 @@ import {
|
||||
keyNode2value,
|
||||
jsxAttributeValueNode2value,
|
||||
node2value,
|
||||
ast2code,
|
||||
expression2code,
|
||||
node2code,
|
||||
} from './generate';
|
||||
import {
|
||||
@@ -1134,9 +1132,6 @@ export function cloneJSXElementWithoutTrackingData(node: t.JSXElement) {
|
||||
|
||||
export function traverseViewFile(ast: t.File, idGenerator: IdGenerator) {
|
||||
const importedModules: Dict<IImportDeclarationPayload | IImportDeclarationPayload[]> = {};
|
||||
const classProperties: Dict<IClassPropertyNodeData> = {};
|
||||
let stateProperties: string[] = [];
|
||||
let stateCode = '';
|
||||
const nodes: Array<ITangoViewNodeData<t.JSXElement>> = [];
|
||||
const cloneAst = t.cloneNode(ast, true, true);
|
||||
const cleanAst = removeTrackingDataFromViewAst(cloneAst);
|
||||
@@ -1166,30 +1161,6 @@ export function traverseViewFile(ast: t.File, idGenerator: IdGenerator) {
|
||||
}
|
||||
},
|
||||
|
||||
ClassProperty(path) {
|
||||
const propName = keyNode2value(path.node.key) as string;
|
||||
if (!propName) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reference = `this.${propName}`;
|
||||
if (['defaultProps', 'propTypes', 'constructor'].includes(propName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (propName === 'state') {
|
||||
stateProperties = Object.keys(node2value(path.node.value));
|
||||
stateCode = ast2code(path.node);
|
||||
} else {
|
||||
// TODO: 这里需要完善下,并不是所有的都是 arrowFunction
|
||||
classProperties[reference] = {
|
||||
reference,
|
||||
propertyName: propName,
|
||||
propertyBody: expression2code(path.node.value),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
JSXElement(path) {
|
||||
const attributes = getJSXElementAttributes(path.node);
|
||||
|
||||
@@ -1236,9 +1207,6 @@ export function traverseViewFile(ast: t.File, idGenerator: IdGenerator) {
|
||||
ast,
|
||||
cleanAst,
|
||||
nodes,
|
||||
stateCode,
|
||||
classProperties,
|
||||
stateProperties,
|
||||
importedModules,
|
||||
variables,
|
||||
};
|
||||
|
||||
@@ -170,6 +170,7 @@ export interface IWorkspace {
|
||||
updateFile: (filename: string, code: string, shouldFormatCode?: boolean) => void;
|
||||
removeFile: (filename: string) => void;
|
||||
renameFile: (oldFilename: string, newFilename: string) => void;
|
||||
renameFolder: (oldFoldername: string, newFoldername: string) => void;
|
||||
getFile: (filename: string) => TangoFile;
|
||||
listFiles: () => Record<string, string>;
|
||||
|
||||
|
||||
@@ -283,31 +283,12 @@ export class TangoViewModule extends TangoModule implements IViewFile {
|
||||
* 导入的模块
|
||||
*/
|
||||
private _importedModules: Dict<IImportDeclarationPayload | IImportDeclarationPayload[]>;
|
||||
/**
|
||||
* 类属性
|
||||
* @deprecated
|
||||
*/
|
||||
private _classProperties: Dict<IClassPropertyNodeData>;
|
||||
/**
|
||||
* 状态属性
|
||||
*/
|
||||
private _stateProperties: string[];
|
||||
/**
|
||||
* 状态代码
|
||||
*/
|
||||
private _stateCode: string;
|
||||
|
||||
/**
|
||||
* ID 生成器
|
||||
*/
|
||||
private _idGenerator: IdGenerator;
|
||||
|
||||
get classProperties() {
|
||||
return this._classProperties;
|
||||
}
|
||||
|
||||
get stateProperties() {
|
||||
return this._stateProperties;
|
||||
}
|
||||
|
||||
get nodes() {
|
||||
return this._nodes;
|
||||
@@ -317,10 +298,6 @@ export class TangoViewModule extends TangoModule implements IViewFile {
|
||||
return toJS(this._nodesTree);
|
||||
}
|
||||
|
||||
get stateCode() {
|
||||
return this._stateCode;
|
||||
}
|
||||
|
||||
get tree() {
|
||||
return this.ast;
|
||||
}
|
||||
@@ -352,9 +329,6 @@ export class TangoViewModule extends TangoModule implements IViewFile {
|
||||
ast: newAst,
|
||||
cleanAst,
|
||||
nodes,
|
||||
stateCode,
|
||||
stateProperties,
|
||||
classProperties,
|
||||
importedModules,
|
||||
variables,
|
||||
} = traverseViewFile(this.ast, this._idGenerator);
|
||||
@@ -363,10 +337,6 @@ export class TangoViewModule extends TangoModule implements IViewFile {
|
||||
this._code = ast2code(newAst);
|
||||
this._cleanCode = ast2code(cleanAst);
|
||||
|
||||
this._stateCode = stateCode;
|
||||
|
||||
this._stateProperties = stateProperties;
|
||||
this._classProperties = classProperties;
|
||||
this._importedModules = importedModules;
|
||||
this.importMap = this.buildImportMap(importedModules);
|
||||
this.variables = variables;
|
||||
|
||||
@@ -483,8 +483,24 @@ export class Workspace extends EventTarget implements IWorkspace {
|
||||
*/
|
||||
renameFile(oldFilename: string, newFilename: string) {
|
||||
const file = this.files.get(oldFilename);
|
||||
this.removeFile(oldFilename);
|
||||
this.addFile(newFilename, file.code);
|
||||
if (file) {
|
||||
this.removeFile(oldFilename);
|
||||
this.addFile(newFilename, file.code);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重命名文件夹
|
||||
* @param oldFoldername 旧文件夹名
|
||||
* @param newFoldername 新文件夹名
|
||||
*/
|
||||
renameFolder(oldFoldername: string, newFoldername: string) {
|
||||
Array.from(this.files.keys()).forEach((key) => {
|
||||
if (key.startsWith(`${oldFoldername}/`)) {
|
||||
const newKey = key.replace(oldFoldername, newFoldername);
|
||||
this.renameFile(key, newKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [0.2.1](https://github.com/netease/tango/compare/@music163/tango-designer@0.2.0...@music163/tango-designer@0.2.1) (2023-09-18)
|
||||
|
||||
**Note:** Version bump only for package @music163/tango-designer
|
||||
|
||||
# [0.2.0](https://github.com/netease/tango/compare/@music163/tango-designer@0.1.3...@music163/tango-designer@0.2.0) (2023-09-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@music163/tango-designer",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"description": "lowcode designer",
|
||||
"keywords": [
|
||||
"react"
|
||||
@@ -27,18 +27,18 @@
|
||||
"prepublishOnly": "yarn build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.8.0",
|
||||
"styled-components": "5"
|
||||
"react": ">= 16.8",
|
||||
"styled-components": ">= 4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^4.8.0",
|
||||
"@music163/request": "^0.1.0",
|
||||
"@music163/tango-context": "^0.1.3",
|
||||
"@music163/tango-core": "^0.1.3",
|
||||
"@music163/tango-helpers": "^0.1.2",
|
||||
"@music163/tango-sandbox": "^0.1.3",
|
||||
"@music163/tango-setting-form": "^0.2.0",
|
||||
"@music163/tango-ui": "^0.1.3",
|
||||
"@music163/tango-context": "^0.1.4",
|
||||
"@music163/tango-core": "^0.1.4",
|
||||
"@music163/tango-helpers": "^0.1.3",
|
||||
"@music163/tango-sandbox": "^0.1.4",
|
||||
"@music163/tango-setting-form": "^0.2.1",
|
||||
"@music163/tango-ui": "^0.1.4",
|
||||
"antd": "^4.24.2",
|
||||
"cash-dom": "^8.1.2",
|
||||
"classnames": "^2.3.2",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useState, useRef, useEffect, memo } from 'react';
|
||||
import { Input } from 'antd';
|
||||
import { css } from 'styled-components';
|
||||
import { Box } from 'coral-system';
|
||||
import { css, Box } from 'coral-system';
|
||||
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
|
||||
const rowCss = css`
|
||||
|
||||
@@ -69,14 +69,6 @@ export const CodeEditor = observer(
|
||||
[workspace, autoRemoveUnusedImports, activeFile, files],
|
||||
);
|
||||
|
||||
const handleRenameFile = useCallback(
|
||||
(oldFilename: string, newFilename: string) => {
|
||||
workspace.renameFile(oldFilename, newFilename);
|
||||
workspace.setActiveFile(newFilename);
|
||||
},
|
||||
[workspace],
|
||||
);
|
||||
|
||||
const handleFileChange = useCallback(
|
||||
(type: string, info: any) => {
|
||||
switch (type) {
|
||||
@@ -88,7 +80,12 @@ export const CodeEditor = observer(
|
||||
workspace.removeFile(info.path);
|
||||
break;
|
||||
case 'renameFile':
|
||||
workspace.renameFile(info.path, info.newpath);
|
||||
workspace.setActiveFile(info.newpath);
|
||||
break;
|
||||
case 'renameFolder':
|
||||
workspace.renameFolder(info.path, info.newpath);
|
||||
break;
|
||||
case 'addFolder':
|
||||
default:
|
||||
break;
|
||||
@@ -114,7 +111,6 @@ export const CodeEditor = observer(
|
||||
}}
|
||||
ideConfig={ideConfig}
|
||||
onFileSave={fileSave}
|
||||
onRenameFile={handleRenameFile}
|
||||
onPathChange={handlePathChange}
|
||||
onFileChange={handleFileChange}
|
||||
defaultPath={activeFile}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Switch } from 'antd';
|
||||
import { FormItemComponentProps } from '../form-item';
|
||||
import { FormItemComponentProps } from '@music163/tango-setting-form/src/form-item';
|
||||
|
||||
export function BoolSetter({ value, onChange, ...props }: FormItemComponentProps<boolean>) {
|
||||
return <Switch checked={value} onChange={(val) => onChange?.(val)} {...props} />;
|
||||
+1
-1
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { Radio, RadioProps, Tooltip } from 'antd';
|
||||
import { IconFont } from '@music163/tango-ui';
|
||||
import type { OptionType } from '@music163/tango-helpers';
|
||||
import { FormItemComponentProps } from '../form-item';
|
||||
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
||||
|
||||
interface ChoiceSetterProps {
|
||||
mode?: 'text' | 'icon';
|
||||
@@ -3,7 +3,8 @@ import { Box } from 'coral-system';
|
||||
// @ts-ignore
|
||||
import { toJSON } from 'cssjson';
|
||||
import { InputNumber, Space } from 'antd';
|
||||
import { FormItemComponentProps, SliderSetter } from '@music163/tango-setting-form';
|
||||
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
||||
import { SliderSetter } from './number-setter';
|
||||
import {
|
||||
BgSetter,
|
||||
BorderSetter,
|
||||
|
||||
@@ -25,8 +25,38 @@ import {
|
||||
FlexAlignItemsSetter,
|
||||
FlexDirectionSetter,
|
||||
} from './style-setter';
|
||||
import { BoolSetter } from './bool-setter';
|
||||
import { ChoiceSetter } from './choice-setter';
|
||||
import { NumberSetter, SliderSetter } from './number-setter';
|
||||
import { TextAreaSetter, TextSetter } from './text-setter';
|
||||
|
||||
const setters: IFormItemCreateOptions[] = [
|
||||
{
|
||||
name: 'boolSetter',
|
||||
component: BoolSetter,
|
||||
},
|
||||
{
|
||||
name: 'choiceSetter',
|
||||
component: ChoiceSetter,
|
||||
},
|
||||
{
|
||||
name: 'expSetter',
|
||||
alias: ['expressionSetter'],
|
||||
component: ExpressionSetter,
|
||||
},
|
||||
{
|
||||
name: 'numberSetter',
|
||||
component: NumberSetter,
|
||||
},
|
||||
{
|
||||
name: 'textSetter',
|
||||
component: TextSetter,
|
||||
},
|
||||
{ name: 'textAreaSetter', component: TextAreaSetter },
|
||||
{
|
||||
name: 'sliderSetter',
|
||||
component: SliderSetter,
|
||||
},
|
||||
{
|
||||
name: 'actionListSetter',
|
||||
component: ActionListSetter,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { InputNumber, InputNumberProps, Slider } from 'antd';
|
||||
import { FormItemComponentProps } from '../form-item';
|
||||
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
||||
|
||||
const style = {
|
||||
width: '100%',
|
||||
@@ -5,7 +5,9 @@ import { SketchPicker } from 'react-color';
|
||||
import Color from 'color';
|
||||
import { BgColorsOutlined, FileImageOutlined } from '@ant-design/icons';
|
||||
import { SingleMonacoEditor, IconFont } from '@music163/tango-ui';
|
||||
import { FormItemComponentProps, ChoiceSetter, TextSetter } from '@music163/tango-setting-form';
|
||||
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
||||
import { ChoiceSetter } from './choice-setter';
|
||||
import { TextSetter } from './text-setter';
|
||||
// import { ImageSetter } from './image-setter';
|
||||
|
||||
function getRawCssValue(value: string) {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Input, InputProps } from 'antd';
|
||||
import { FormItemComponentProps } from '../form-item';
|
||||
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Box, HTMLCoralProps } from 'coral-system';
|
||||
import { css } from 'styled-components';
|
||||
import { css, Box, HTMLCoralProps } from 'coral-system';
|
||||
import { observer, useDesigner } from '@music163/tango-context';
|
||||
|
||||
export interface SimulatorProps {
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [0.1.3](https://github.com/netease/tango/compare/@music163/tango-helpers@0.1.2...@music163/tango-helpers@0.1.3) (2023-09-18)
|
||||
|
||||
**Note:** Version bump only for package @music163/tango-helpers
|
||||
|
||||
## 0.1.2 (2023-09-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@music163/tango-helpers",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.3",
|
||||
"description": "Shared types, helpers, and hooks of tango-apps",
|
||||
"keywords": [
|
||||
"shared",
|
||||
@@ -31,7 +31,7 @@
|
||||
"prepublishOnly": "yarn build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.8.0"
|
||||
"react": ">= 16.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [0.1.4](https://github.com/netease/tango/compare/@music163/tango-sandbox@0.1.3...@music163/tango-sandbox@0.1.4) (2023-09-18)
|
||||
|
||||
**Note:** Version bump only for package @music163/tango-sandbox
|
||||
|
||||
## [0.1.3](https://github.com/netease/tango/compare/@music163/tango-sandbox@0.1.2...@music163/tango-sandbox@0.1.3) (2023-09-13)
|
||||
|
||||
**Note:** Version bump only for package @music163/tango-sandbox
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@music163/tango-sandbox",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.4",
|
||||
"description": "sandbox of tango apps",
|
||||
"author": "wwsun <ww.sun@outlook.com>",
|
||||
"homepage": "",
|
||||
@@ -24,13 +24,13 @@
|
||||
"prepublishOnly": "yarn build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.8.0",
|
||||
"react-dom": ">= 16.8.0"
|
||||
"react": ">= 16.8",
|
||||
"styled-components": ">= 4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^4.8.0",
|
||||
"@music163/tango-core": "^0.1.3",
|
||||
"@music163/tango-helpers": "^0.1.2",
|
||||
"@music163/tango-core": "^0.1.4",
|
||||
"@music163/tango-helpers": "^0.1.3",
|
||||
"crypto-js": "^4.1.1",
|
||||
"lodash.isequal": "4.5.0",
|
||||
"react-frame-component": "^5.2.4"
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [0.2.1](https://github.com/netease/tango/compare/@music163/tango-setting-form@0.2.0...@music163/tango-setting-form@0.2.1) (2023-09-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- remove useless codes ([813eb83](https://github.com/netease/tango/commit/813eb83ebb9ced891636f2653f25b6281386c18d))
|
||||
|
||||
# [0.2.0](https://github.com/netease/tango/compare/@music163/tango-setting-form@0.1.3...@music163/tango-setting-form@0.2.0) (2023-09-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@music163/tango-setting-form",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"description": "setting form of tango-apps",
|
||||
"author": "wwsun <ww.sun@outlook.com>",
|
||||
"homepage": "",
|
||||
@@ -24,13 +24,13 @@
|
||||
"prepublishOnly": "yarn build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.8.0"
|
||||
"react": ">= 16.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^4.8.0",
|
||||
"@music163/tango-core": "^0.1.3",
|
||||
"@music163/tango-helpers": "^0.1.2",
|
||||
"@music163/tango-ui": "^0.1.3",
|
||||
"@music163/tango-core": "^0.1.4",
|
||||
"@music163/tango-helpers": "^0.1.3",
|
||||
"@music163/tango-ui": "^0.1.4",
|
||||
"antd": "^4.24.2",
|
||||
"coral-system": "^1.0.5",
|
||||
"mobx": "6.9.0",
|
||||
|
||||
@@ -10,48 +10,11 @@ export const useFormModel = () => {
|
||||
return useContext(FormModelContext);
|
||||
};
|
||||
|
||||
// TODO: 删掉不需要的
|
||||
export interface FormVariableContextType {
|
||||
/**
|
||||
* 是否允许表单项切换到表达式设置器
|
||||
*/
|
||||
disableSwitchExpressionSetter?: boolean;
|
||||
// /**
|
||||
// * 探测输入上下文的对象
|
||||
// */
|
||||
// evaluateContext?: object;
|
||||
// /**
|
||||
// * 表单动作发生时的回调
|
||||
// */
|
||||
// onAction?: (fn: string, args: unknown[]) => void;
|
||||
// /**
|
||||
// * 状态变量列表
|
||||
// */
|
||||
// modelVariables?: any[];
|
||||
// /**
|
||||
// * 动作变量列表
|
||||
// */
|
||||
// actionVariables?: any[];
|
||||
// /**
|
||||
// * 表达式变量列表(含状态变量和动作变量)
|
||||
// */
|
||||
// expressionVariables?: any[];
|
||||
// /**
|
||||
// * 路由选项
|
||||
// */
|
||||
// routeOptions?: any[];
|
||||
// /**
|
||||
// * 可选弹窗列表
|
||||
// */
|
||||
// modalOptions?: any[];
|
||||
// /**
|
||||
// * 关联的表单域列表
|
||||
// */
|
||||
// formFieldsOptions?: any[];
|
||||
// /**
|
||||
// * 远程服务
|
||||
// */
|
||||
// remoteServices?: TangoRemoteServicesType;
|
||||
}
|
||||
|
||||
const FormVariableContext = createContext<FormVariableContextType>(null);
|
||||
|
||||
@@ -5,14 +5,12 @@ import {
|
||||
clone,
|
||||
ComponentPropType,
|
||||
isVariableString,
|
||||
logger,
|
||||
SetterOnChangeDetailType,
|
||||
useBoolean,
|
||||
} from '@music163/tango-helpers';
|
||||
import { IconFont, ToggleButton } from '@music163/tango-ui';
|
||||
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||
import { InputProps, Tooltip } from 'antd';
|
||||
import { INTERNAL_SETTERS } from './setters';
|
||||
import { useFormModel, useFormVariable } from './context';
|
||||
import { FormControl } from './form-ui';
|
||||
|
||||
@@ -50,10 +48,6 @@ export interface IFormItemCreateOptions {
|
||||
* 是否禁用变量设置器
|
||||
*/
|
||||
disableVariableSetter?: boolean;
|
||||
/**
|
||||
* 子表单是否默认折叠
|
||||
*/
|
||||
defaultCollapsed?: boolean;
|
||||
/**
|
||||
* 默认的表单值校验逻辑
|
||||
*/
|
||||
@@ -141,7 +135,6 @@ export function createFormItem(options: IFormItemCreateOptions) {
|
||||
return (
|
||||
<FormControl
|
||||
visible={getVisible(model)}
|
||||
defaultCollapsed={options.defaultCollapsed}
|
||||
label={title}
|
||||
note={name}
|
||||
tip={tip}
|
||||
@@ -194,8 +187,6 @@ export function register(config: IFormItemCreateOptions) {
|
||||
});
|
||||
}
|
||||
|
||||
INTERNAL_SETTERS.forEach(register);
|
||||
|
||||
const iconStyle = {
|
||||
color: 'red',
|
||||
};
|
||||
|
||||
@@ -1,73 +1,40 @@
|
||||
import React, { useState } from 'react';
|
||||
import { css } from 'styled-components';
|
||||
import { css, Box, HTMLCoralProps, Text } from 'coral-system';
|
||||
import { Checkbox, Tooltip } from 'antd';
|
||||
import { Box, HTMLCoralProps, Text } from 'coral-system';
|
||||
import { CollapsePanel } from '@music163/tango-ui';
|
||||
import { isNil, isString } from '@music163/tango-helpers';
|
||||
|
||||
export interface FormControlProps extends Omit<FormLabelProps, 'type'> {
|
||||
/**
|
||||
* @deprecated 废弃 subForm 使用 FormObject 代替
|
||||
*/
|
||||
type?: 'formItem' | 'subForm';
|
||||
/**
|
||||
* 默认是否折叠,仅适用于 subForm 类型
|
||||
*/
|
||||
defaultCollapsed?: boolean;
|
||||
visible: boolean;
|
||||
extra?: React.ReactNode;
|
||||
error?: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export function FormControl(props: FormControlProps) {
|
||||
const {
|
||||
type,
|
||||
defaultCollapsed = true,
|
||||
visible,
|
||||
label,
|
||||
note,
|
||||
tip,
|
||||
docs,
|
||||
extra,
|
||||
error,
|
||||
children,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
if (type === 'formItem') {
|
||||
return (
|
||||
<Box className="FormControl" display={visible ? 'block' : 'none'} {...rest}>
|
||||
<Box display="flex" justifyContent="space-between" alignItems="center" mb="s">
|
||||
<FormLabel label={label} note={note} tip={tip} docs={docs} />
|
||||
{extra}
|
||||
</Box>
|
||||
<Box>{children}</Box>
|
||||
{!!error && (
|
||||
<Box mt="m" color="red">
|
||||
{error}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
// else type === 'subForm'
|
||||
export function FormControl({
|
||||
visible,
|
||||
label,
|
||||
note,
|
||||
tip,
|
||||
docs,
|
||||
extra,
|
||||
error,
|
||||
children,
|
||||
...rest
|
||||
}: FormControlProps) {
|
||||
return (
|
||||
<CollapsePanel
|
||||
title={<FormLabel label={label} note={note} tip={tip} docs={docs} />}
|
||||
extra={
|
||||
<Box flex="1" textAlign="right">
|
||||
{extra}
|
||||
<Box className="FormControl" display={visible ? 'block' : 'none'} {...rest}>
|
||||
<Box display="flex" justifyContent="space-between" alignItems="center" mb="s">
|
||||
<FormLabel label={label} note={note} tip={tip} docs={docs} />
|
||||
{extra}
|
||||
</Box>
|
||||
<Box>{children}</Box>
|
||||
{!!error && (
|
||||
<Box mt="m" color="red">
|
||||
{error}
|
||||
</Box>
|
||||
}
|
||||
defaultCollapsed={defaultCollapsed}
|
||||
borderTop="solid"
|
||||
borderTopColor="line.normal"
|
||||
>
|
||||
<Box bg="#f9f9f9">{children}</Box>
|
||||
<Box color="red">{error}</Box>
|
||||
</CollapsePanel>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { register } from './form-item';
|
||||
import { ExpressionSetter } from './setter';
|
||||
|
||||
// 预注册基础 Setter
|
||||
register({
|
||||
name: 'expressionSetter',
|
||||
component: ExpressionSetter,
|
||||
});
|
||||
|
||||
export * from './form';
|
||||
export * from './form-item';
|
||||
export * from './form-object';
|
||||
export * from './form-model';
|
||||
export * from './context';
|
||||
export * from './setters';
|
||||
@@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
import { FormItemComponentProps } from './form-item';
|
||||
|
||||
// FIXME: 内置 ExpressionSetter,默认全部 fallback 到此 setter
|
||||
export function ExpressionSetter(props: FormItemComponentProps<string>) {
|
||||
return <div>exp setter</div>;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import { TextAreaSetter, TextSetter } from './text-setter';
|
||||
import { ChoiceSetter } from './choice-setter';
|
||||
import { NumberSetter, SliderSetter } from './number-setter';
|
||||
import { BoolSetter } from './bool-setter';
|
||||
import { IFormItemCreateOptions } from '../form-item';
|
||||
import { ExpressionSetter } from './exp-setter';
|
||||
|
||||
export const INTERNAL_SETTERS: IFormItemCreateOptions[] = [
|
||||
{
|
||||
name: 'boolSetter',
|
||||
component: BoolSetter,
|
||||
},
|
||||
{
|
||||
name: 'choiceSetter',
|
||||
component: ChoiceSetter,
|
||||
},
|
||||
{
|
||||
name: 'expSetter',
|
||||
alias: ['expressionSetter'],
|
||||
component: ExpressionSetter,
|
||||
},
|
||||
{
|
||||
name: 'numberSetter',
|
||||
component: NumberSetter,
|
||||
},
|
||||
{
|
||||
name: 'textSetter',
|
||||
component: TextSetter,
|
||||
},
|
||||
{ name: 'textAreaSetter', component: TextAreaSetter },
|
||||
{
|
||||
name: 'sliderSetter',
|
||||
component: SliderSetter,
|
||||
},
|
||||
];
|
||||
|
||||
export * from './bool-setter';
|
||||
export * from './choice-setter';
|
||||
export * from './number-setter';
|
||||
export * from './text-setter';
|
||||
@@ -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.
|
||||
|
||||
## [0.1.4](https://github.com/netease/tango/compare/@music163/tango-ui@0.1.3...@music163/tango-ui@0.1.4) (2023-09-18)
|
||||
|
||||
**Note:** Version bump only for package @music163/tango-ui
|
||||
|
||||
## [0.1.3](https://github.com/netease/tango/compare/@music163/tango-ui@0.1.2...@music163/tango-ui@0.1.3) (2023-09-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@music163/tango-ui",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.4",
|
||||
"description": "ui widgets of tango",
|
||||
"keywords": [
|
||||
"react",
|
||||
@@ -29,20 +29,21 @@
|
||||
"prepublishOnly": "yarn build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.8.0"
|
||||
"react": ">= 16.8",
|
||||
"styled-components": ">= 4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^4.8.0",
|
||||
"@codemirror/autocomplete": "^6.7.1",
|
||||
"@codemirror/lang-javascript": "^6.1.2",
|
||||
"@codemirror/search": "^6.2.3",
|
||||
"@music163/tango-helpers": "^0.1.2",
|
||||
"@music163/tango-helpers": "^0.1.3",
|
||||
"@uiw/react-codemirror": "^4.19.3",
|
||||
"antd": "^4.24.2",
|
||||
"antd-easy-form": "^1.1.3",
|
||||
"coral-system": "^1.0.5",
|
||||
"react-json-view": "^1.21.3",
|
||||
"react-monaco-editor-lite": "^1.2.0"
|
||||
"react-monaco-editor-lite": "^1.2.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import { css } from 'styled-components';
|
||||
import { Box } from 'coral-system';
|
||||
import { css, Box } from 'coral-system';
|
||||
import { FolderOpenOutlined, FolderOutlined, FileOutlined } from '@ant-design/icons';
|
||||
|
||||
export interface Props {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import cx from 'classnames';
|
||||
import { Box, coral, Text } from 'coral-system';
|
||||
import { css } from 'styled-components';
|
||||
import { css, Box, coral, Text } from 'coral-system';
|
||||
import { EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import { noop } from '@music163/tango-helpers';
|
||||
import { Popconfirm } from 'antd';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import cx from 'classnames';
|
||||
import { css } from 'styled-components';
|
||||
import { Box, Text, HTMLCoralProps } from 'coral-system';
|
||||
import { css, Box, Text, HTMLCoralProps } from 'coral-system';
|
||||
import { merge } from '@music163/tango-helpers';
|
||||
|
||||
export interface PanelProps extends Omit<HTMLCoralProps<'div'>, 'title'> {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import { css } from 'styled-components';
|
||||
import cx from 'classnames';
|
||||
import { Button, HTMLCoralProps } from 'coral-system';
|
||||
import { css, Button, HTMLCoralProps } from 'coral-system';
|
||||
import { DropDownProps, Dropdown, MenuProps, Tooltip, TooltipProps } from 'antd';
|
||||
import { DownOutlined } from '@ant-design/icons';
|
||||
|
||||
|
||||
@@ -16989,10 +16989,10 @@ react-loadable-ssr-addon-v5-slorber@^1.0.1:
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.10.3"
|
||||
|
||||
react-monaco-editor-lite@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmmirror.com/react-monaco-editor-lite/-/react-monaco-editor-lite-1.2.0.tgz"
|
||||
integrity sha512-XIYNPrtPjJL5ICmRqIt24+mYFvvIGdX/72Sq95kV6OpFw6NdUYAoxqrKHagZqDtXe5yDO/oiXCpYDlnn+izYnw==
|
||||
react-monaco-editor-lite@^1.2.3:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.npmmirror.com/react-monaco-editor-lite/-/react-monaco-editor-lite-1.2.3.tgz#a5da8813d45973bf9014624a65c2e07106d5205c"
|
||||
integrity sha512-/rH3YDN5orsv55FY2zkvLnBBvISEHvAPGRflqtseMzPgQY0Dd1Mc+x8XMHXt9WRUnZbkJGgGfLAA1LDMEY8zLw==
|
||||
dependencies:
|
||||
monaco-editor "^0.38.0"
|
||||
monaco-editor-textmate "^4.0.0"
|
||||
@@ -19502,7 +19502,7 @@ typedoc@^0.25.0:
|
||||
minimatch "^9.0.3"
|
||||
shiki "^0.14.1"
|
||||
|
||||
"typescript@^3 || ^4", typescript@^4.7.4:
|
||||
"typescript@^3 || ^4":
|
||||
version "4.9.5"
|
||||
resolved "https://registry.npmmirror.com/typescript/-/typescript-4.9.5.tgz"
|
||||
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
|
||||
|
||||
Reference in New Issue
Block a user