mirror of
https://github.com/NetEase/tango.git
synced 2026-09-01 15:03:03 +08:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a3ab3c093 | |||
| 55602fc961 | |||
| a3c0e463ca | |||
| 79f9a8c179 | |||
| ea96872261 | |||
| a86e0e049c | |||
| c4e1ed67f5 | |||
| 179de0cc52 | |||
| 6de54884b5 | |||
| 55bf417ddf | |||
| ca56edd9ae | |||
| 65149f1326 | |||
| 939466648d |
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Box, Group } from 'coral-system';
|
import { Box, Group, Text } from 'coral-system';
|
||||||
import { Avatar, Space, Switch } from 'antd';
|
import { Avatar, Space, Switch } from 'antd';
|
||||||
import { BranchesOutlined, MenuOutlined, QuestionCircleOutlined } from '@ant-design/icons';
|
import { BranchesOutlined, MenuOutlined, QuestionCircleOutlined } from '@ant-design/icons';
|
||||||
import { registerSetter } from '@music163/tango-designer';
|
import { registerSetter } from '@music163/tango-designer';
|
||||||
@@ -66,12 +66,12 @@ export function Logo() {
|
|||||||
export function ProjectDetail() {
|
export function ProjectDetail() {
|
||||||
return (
|
return (
|
||||||
<Box display="flex" alignItems="center" columnGap="l">
|
<Box display="flex" alignItems="center" columnGap="l">
|
||||||
<Box className="ProjectName" fontSize="18px" fontWeight="bold">
|
<Text className="ProjectName" fontSize="18px" fontWeight="bold" truncated>
|
||||||
community-test
|
community-test
|
||||||
</Box>
|
</Text>
|
||||||
<Box className="BranchName" as="code" fontSize="14px">
|
<Text className="BranchName" as="code" fontSize="14px" truncated>
|
||||||
<BranchesOutlined /> feature/list
|
<BranchesOutlined /> feature/list
|
||||||
</Box>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ import { definePage } from "@music163/tango-boot";
|
|||||||
import {
|
import {
|
||||||
Page,
|
Page,
|
||||||
Section,
|
Section,
|
||||||
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Input,
|
Input,
|
||||||
FormilyForm,
|
FormilyForm,
|
||||||
@@ -167,7 +168,9 @@ class App extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Page title={tango.stores.app.title} subTitle={<><Button>hello</Button></>}>
|
<Page title={tango.stores.app.title} subTitle={<><Button>hello</Button></>}>
|
||||||
<Section tid="section0" />
|
<Section tid="section0">
|
||||||
|
<Box></Box>
|
||||||
|
</Section>
|
||||||
<Section tid="section1" title="Section Title">
|
<Section tid="section1" title="Section Title">
|
||||||
your input: <Input tid="input1" defaultValue="hello" />
|
your input: <Input tid="input1" defaultValue="hello" />
|
||||||
copy input: <Input value={tango.page.input1?.value} />
|
copy input: <Input value={tango.page.input1?.value} />
|
||||||
@@ -374,13 +377,16 @@ export default defineServices({
|
|||||||
add: {
|
add: {
|
||||||
url: 'https://nei.hz.netease.com/api/apimock-v2/c45109399a1d33d83e32a59984b25b00/api/users',
|
url: 'https://nei.hz.netease.com/api/apimock-v2/c45109399a1d33d83e32a59984b25b00/api/users',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
description: '新增用户'
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
url: 'https://nei.hz.netease.com/api/apimock-v2/c45109399a1d33d83e32a59984b25b00/api/users',
|
url: 'https://nei.hz.netease.com/api/apimock-v2/c45109399a1d33d83e32a59984b25b00/api/users',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
description: '更新用户'
|
||||||
},
|
},
|
||||||
delete: {
|
delete: {
|
||||||
url: 'https://nei.hz.netease.com/api/apimock-v2/c45109399a1d33d83e32a59984b25b00/api/users?id=1',
|
url: 'https://nei.hz.netease.com/api/apimock-v2/c45109399a1d33d83e32a59984b25b00/api/users?id=1',
|
||||||
|
description: '删除用户'
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ const Snippet3ColumnLayout: IComponentPrototype = {
|
|||||||
icon: 'icon-column-3',
|
icon: 'icon-column-3',
|
||||||
type: 'snippet',
|
type: 'snippet',
|
||||||
package: '@music163/antd',
|
package: '@music163/antd',
|
||||||
// FIXME: Column 组件 需要更新为 defineComponent
|
|
||||||
initChildren: `
|
initChildren: `
|
||||||
<Columns columns={12}>
|
<Columns columns={12}>
|
||||||
<Column colSpan={4}>
|
<Column colSpan={4}>
|
||||||
@@ -132,6 +131,9 @@ export const nativeDomPrototypes = () => {
|
|||||||
title: '样式',
|
title: '样式',
|
||||||
group: 'style',
|
group: 'style',
|
||||||
setter: 'expressionSetter',
|
setter: 'expressionSetter',
|
||||||
|
setterProps: {
|
||||||
|
expressionType: 'cssObject',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'className',
|
name: 'className',
|
||||||
@@ -166,6 +168,32 @@ const prototypes: Dict<IComponentPrototype> = {
|
|||||||
Snippet2ColumnLayout,
|
Snippet2ColumnLayout,
|
||||||
Snippet3ColumnLayout,
|
Snippet3ColumnLayout,
|
||||||
SnippetButtonGroup,
|
SnippetButtonGroup,
|
||||||
|
Section: {
|
||||||
|
...basePrototypes['Section'],
|
||||||
|
props: [
|
||||||
|
// ...(basePrototypes['Section'].props as any),
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
title: '标题',
|
||||||
|
setter: 'textSetter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'extra',
|
||||||
|
title: '额外内容',
|
||||||
|
setter: 'renderSetter',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '按钮组',
|
||||||
|
value: 'ButtonGroup',
|
||||||
|
renderBody:
|
||||||
|
'<ButtonGroup><Button>button1</Button><Button>button2</Button></ButtonGroup>',
|
||||||
|
relatedImports: ['ButtonGroup', 'Button'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
template: '(v) => {\n return {{content}};\n}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
Box: {
|
Box: {
|
||||||
name: 'Box',
|
name: 'Box',
|
||||||
title: '盒子',
|
title: '盒子',
|
||||||
@@ -197,6 +225,32 @@ const prototypes: Dict<IComponentPrototype> = {
|
|||||||
title: 'd',
|
title: 'd',
|
||||||
setter: 'textSetter',
|
setter: 'textSetter',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'onClick',
|
||||||
|
title: '点击事件',
|
||||||
|
setter: 'eventSetter',
|
||||||
|
template: '(e) => {\n {{content}}\n}',
|
||||||
|
tip: '回调参数说明:e 为事件对象',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'renderFoo',
|
||||||
|
title: 'foo自定义渲染',
|
||||||
|
setter: 'renderSetter',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '占位空间',
|
||||||
|
value: 'Box',
|
||||||
|
render: '() => <Box>test</Box>',
|
||||||
|
relatedImports: ['Box'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '占位文本',
|
||||||
|
value: 'Text',
|
||||||
|
render: '() => <Text>text</Text>',
|
||||||
|
relatedImports: ['Text'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Columns: {
|
Columns: {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { SystemProvider } from 'coral-system';
|
|||||||
import 'antd/dist/antd.css';
|
import 'antd/dist/antd.css';
|
||||||
|
|
||||||
export const parameters = {
|
export const parameters = {
|
||||||
actions: { argTypesRegex: '^on[A-Z].*' },
|
actions: { argTypesRegex: '^on.*' },
|
||||||
controls: {
|
controls: {
|
||||||
matchers: {
|
matchers: {
|
||||||
color: /(background|color)$/i,
|
color: /(background|color)$/i,
|
||||||
|
|||||||
@@ -69,6 +69,14 @@ const prototypeHasBasicProps: IComponentPrototype = {
|
|||||||
title: 'codeSetter',
|
title: 'codeSetter',
|
||||||
setter: 'codeSetter',
|
setter: 'codeSetter',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'style',
|
||||||
|
title: 'codeSetter(cssObject)',
|
||||||
|
setter: 'codeSetter',
|
||||||
|
setterProps: {
|
||||||
|
expressionType: 'cssObject',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'text',
|
name: 'text',
|
||||||
title: 'textSetter',
|
title: 'textSetter',
|
||||||
@@ -268,6 +276,9 @@ export function InitValues() {
|
|||||||
name: 'style',
|
name: 'style',
|
||||||
title: 'codeSetter',
|
title: 'codeSetter',
|
||||||
setter: 'codeSetter',
|
setter: 'codeSetter',
|
||||||
|
setterProps: {
|
||||||
|
expressionType: 'cssObject',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'object',
|
name: 'object',
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ActionSelect } from '@music163/tango-ui';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'UI/ActionSelect',
|
||||||
|
component: ActionSelect,
|
||||||
|
};
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{ label: 'action1', value: 'action1' },
|
||||||
|
{ label: 'action2', value: 'action2' },
|
||||||
|
{ label: 'action3', value: 'action3' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const Basic = {
|
||||||
|
args: {
|
||||||
|
defaultText: '选择动作',
|
||||||
|
options,
|
||||||
|
onSelect: console.log,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const showInput = {
|
||||||
|
args: {
|
||||||
|
text: '选择动作',
|
||||||
|
options,
|
||||||
|
showInput: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { ClassNameInput } from '@music163/tango-ui';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'UI/ClassNameInput',
|
||||||
|
};
|
||||||
|
|
||||||
|
export function Basic() {
|
||||||
|
return <ClassNameInput defaultValue="hello world" onChange={console.log} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Controlled() {
|
||||||
|
const [value, setValue] = useState('');
|
||||||
|
return <ClassNameInput value={value} onChange={setValue} />;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Action, InputCode } from '@music163/tango-ui';
|
import { Action, InputCode, InputStyleCode } from '@music163/tango-ui';
|
||||||
import { BlockOutlined } from '@ant-design/icons';
|
import { BlockOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -28,6 +28,10 @@ export function Basic() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function CSS() {
|
||||||
|
return <InputStyleCode enableESLint suffix={<Action icon={<BlockOutlined />} size="small" />} />;
|
||||||
|
}
|
||||||
|
|
||||||
const code = `
|
const code = `
|
||||||
function foo() {
|
function foo() {
|
||||||
console.log("test");
|
console.log("test");
|
||||||
|
|||||||
@@ -3,6 +3,16 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.1.10](https://github.com/netease/tango/compare/@music163/tango-context@1.1.9...@music163/tango-context@1.1.10) (2024-09-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- service support set description field ([#206](https://github.com/netease/tango/issues/206)) ([79f9a8c](https://github.com/netease/tango/commit/79f9a8c1791424f35f194ab2a9aa7c263ef39f40))
|
||||||
|
|
||||||
|
## [1.1.9](https://github.com/netease/tango/compare/@music163/tango-context@1.1.8...@music163/tango-context@1.1.9) (2024-09-02)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @music163/tango-context
|
||||||
|
|
||||||
## [1.1.8](https://github.com/netease/tango/compare/@music163/tango-context@1.1.7...@music163/tango-context@1.1.8) (2024-08-06)
|
## [1.1.8](https://github.com/netease/tango/compare/@music163/tango-context@1.1.7...@music163/tango-context@1.1.8) (2024-08-06)
|
||||||
|
|
||||||
**Note:** Version bump only for package @music163/tango-context
|
**Note:** Version bump only for package @music163/tango-context
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@music163/tango-context",
|
"name": "@music163/tango-context",
|
||||||
"version": "1.1.8",
|
"version": "1.1.10",
|
||||||
"description": "react context for tango-apps",
|
"description": "react context for tango-apps",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
@@ -31,8 +31,8 @@
|
|||||||
"react": ">= 16.8"
|
"react": ">= 16.8"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@music163/tango-core": "^1.4.2",
|
"@music163/tango-core": "^1.4.4",
|
||||||
"@music163/tango-helpers": "^1.2.2",
|
"@music163/tango-helpers": "^1.2.4",
|
||||||
"mobx-react-lite": "4.0.7"
|
"mobx-react-lite": "4.0.7"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -90,12 +90,15 @@ export const useWorkspaceData = () => {
|
|||||||
key: prefix,
|
key: prefix,
|
||||||
selectable: false,
|
selectable: false,
|
||||||
showAddButton: true,
|
showAddButton: true,
|
||||||
children: Object.keys(file.serviceFunctions || {}).map((key) => ({
|
children: Object.entries(file.serviceFunctions || {}).map(([key, value]) => {
|
||||||
title: key,
|
const title = value.description ? `${key}(${value.description})` : key;
|
||||||
key: [prefix, key].join('.'),
|
return {
|
||||||
type: 'function',
|
title,
|
||||||
showRemoveButton: true,
|
key: [prefix, key].join('.'),
|
||||||
})),
|
type: 'function',
|
||||||
|
showRemoveButton: true,
|
||||||
|
};
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,14 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.4.4](https://github.com/netease/tango/compare/@music163/tango-core@1.4.3...@music163/tango-core@1.4.4) (2024-09-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @music163/tango-core
|
||||||
|
|
||||||
|
## [1.4.3](https://github.com/netease/tango/compare/@music163/tango-core@1.4.2...@music163/tango-core@1.4.3) (2024-09-02)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @music163/tango-core
|
||||||
|
|
||||||
## [1.4.2](https://github.com/netease/tango/compare/@music163/tango-core@1.4.1...@music163/tango-core@1.4.2) (2024-08-06)
|
## [1.4.2](https://github.com/netease/tango/compare/@music163/tango-core@1.4.1...@music163/tango-core@1.4.2) (2024-08-06)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@music163/tango-core",
|
"name": "@music163/tango-core",
|
||||||
"version": "1.4.2",
|
"version": "1.4.4",
|
||||||
"description": "tango core",
|
"description": "tango core",
|
||||||
"author": "wwsun <ww.sun@outlook.com>",
|
"author": "wwsun <ww.sun@outlook.com>",
|
||||||
"homepage": "",
|
"homepage": "",
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
"@babel/parser": "^7.23.5",
|
"@babel/parser": "^7.23.5",
|
||||||
"@babel/traverse": "^7.23.5",
|
"@babel/traverse": "^7.23.5",
|
||||||
"@babel/types": "^7.23.5",
|
"@babel/types": "^7.23.5",
|
||||||
"@music163/tango-helpers": "^1.2.2",
|
"@music163/tango-helpers": "^1.2.4",
|
||||||
"@types/babel__generator": "^7.6.7",
|
"@types/babel__generator": "^7.6.7",
|
||||||
"@types/babel__traverse": "^7.20.4",
|
"@types/babel__traverse": "^7.20.4",
|
||||||
"mobx": "6.12.3",
|
"mobx": "6.12.3",
|
||||||
|
|||||||
@@ -3,6 +3,34 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.4.6](https://github.com/netease/tango/compare/@music163/tango-designer@1.4.5...@music163/tango-designer@1.4.6) (2024-09-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- add classNameSetter and classNameInput ([#207](https://github.com/netease/tango/issues/207)) ([55602fc](https://github.com/netease/tango/commit/55602fc961b5c20d923891ce13d7a51588bd047f))
|
||||||
|
- renderSetter with template ([#202](https://github.com/netease/tango/issues/202)) ([ea96872](https://github.com/netease/tango/commit/ea9687226123c839f7a9e001b4c01aa8315a135d))
|
||||||
|
- service support set description field ([#206](https://github.com/netease/tango/issues/206)) ([79f9a8c](https://github.com/netease/tango/commit/79f9a8c1791424f35f194ab2a9aa7c263ef39f40))
|
||||||
|
|
||||||
|
## [1.4.5](https://github.com/netease/tango/compare/@music163/tango-designer@1.4.4...@music163/tango-designer@1.4.5) (2024-09-02)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- add prop value template & fix components popover ([#201](https://github.com/netease/tango/issues/201)) ([c4e1ed6](https://github.com/netease/tango/commit/c4e1ed67f55deb17dae740559602cd0adcfc8eb4))
|
||||||
|
|
||||||
|
## [1.4.4](https://github.com/netease/tango/compare/@music163/tango-designer@1.4.3...@music163/tango-designer@1.4.4) (2024-08-16)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- CodeInput 支持 jsx css 代码补全 ([#198](https://github.com/netease/tango/issues/198)) ([6de5488](https://github.com/netease/tango/commit/6de54884b50d683c74d695a8c13184dc0ce8d3c4))
|
||||||
|
|
||||||
|
## [1.4.3](https://github.com/netease/tango/compare/@music163/tango-designer@1.4.2...@music163/tango-designer@1.4.3) (2024-08-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- file errors overlay support click to error file & optimize ui ([#197](https://github.com/netease/tango/issues/197)) ([ca56edd](https://github.com/netease/tango/commit/ca56edd9ae201dbeb84b03ad390a09085433a257))
|
||||||
|
- route matching without query string & toggle button wrapping ([#195](https://github.com/netease/tango/issues/195)) ([9394666](https://github.com/netease/tango/commit/939466648d40331800f15e886256a0789b7e7623))
|
||||||
|
- update mobile simulator ui ([#196](https://github.com/netease/tango/issues/196)) ([65149f1](https://github.com/netease/tango/commit/65149f1326eaf78e8a27222993c3cacc674cd378))
|
||||||
|
|
||||||
## [1.4.2](https://github.com/netease/tango/compare/@music163/tango-designer@1.4.1...@music163/tango-designer@1.4.2) (2024-08-06)
|
## [1.4.2](https://github.com/netease/tango/compare/@music163/tango-designer@1.4.1...@music163/tango-designer@1.4.2) (2024-08-06)
|
||||||
|
|
||||||
**Note:** Version bump only for package @music163/tango-designer
|
**Note:** Version bump only for package @music163/tango-designer
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@music163/tango-designer",
|
"name": "@music163/tango-designer",
|
||||||
"version": "1.4.2",
|
"version": "1.4.6",
|
||||||
"description": "lowcode designer",
|
"description": "lowcode designer",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react"
|
"react"
|
||||||
@@ -33,12 +33,12 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^4.8.0",
|
"@ant-design/icons": "^4.8.0",
|
||||||
"@music163/request": "^0.2.0",
|
"@music163/request": "^0.2.0",
|
||||||
"@music163/tango-context": "^1.1.8",
|
"@music163/tango-context": "^1.1.10",
|
||||||
"@music163/tango-core": "^1.4.2",
|
"@music163/tango-core": "^1.4.4",
|
||||||
"@music163/tango-helpers": "^1.2.2",
|
"@music163/tango-helpers": "^1.2.4",
|
||||||
"@music163/tango-sandbox": "^1.0.11",
|
"@music163/tango-sandbox": "^1.0.13",
|
||||||
"@music163/tango-setting-form": "^1.2.11",
|
"@music163/tango-setting-form": "^1.2.15",
|
||||||
"@music163/tango-ui": "^1.4.1",
|
"@music163/tango-ui": "^1.4.5",
|
||||||
"antd": "^4.24.2",
|
"antd": "^4.24.2",
|
||||||
"cash-dom": "^8.1.2",
|
"cash-dom": "^8.1.2",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
|
|||||||
@@ -34,17 +34,17 @@ export const ComponentsPopover = observer(
|
|||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
workspace.componentPrototypes.get(selectedNode?.name) ?? ({} as IComponentPrototype);
|
workspace.componentPrototypes.get(selectedNode?.name) ?? ({} as IComponentPrototype);
|
||||||
|
|
||||||
// 推荐使用的子组件
|
const recommendedList = useMemo(() => {
|
||||||
const insertedList = useMemo(
|
if (type === 'inner') {
|
||||||
() =>
|
return prototype?.childrenName
|
||||||
Array.isArray(prototype?.childrenName)
|
? Array.isArray(prototype?.childrenName)
|
||||||
? prototype?.childrenName
|
? prototype.childrenName
|
||||||
: [prototype?.childrenName].filter(Boolean),
|
: [prototype.childrenName]
|
||||||
[prototype?.childrenName],
|
: [];
|
||||||
);
|
}
|
||||||
|
// 默认推荐使用相同类型的组件作为兄弟节点
|
||||||
// 推荐使用的代码片段
|
return prototype.siblingNames || [prototype.name];
|
||||||
const siblingList = useMemo(() => prototype?.siblingNames ?? [], [prototype.siblingNames]);
|
}, [prototype.childrenName, prototype.siblingNames, prototype.name, type]);
|
||||||
|
|
||||||
const tipsTextMap = useMemo(
|
const tipsTextMap = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@@ -82,22 +82,15 @@ export const ComponentsPopover = observer(
|
|||||||
const menuList = JSON.parse(JSON.stringify(designer.menuData));
|
const menuList = JSON.parse(JSON.stringify(designer.menuData));
|
||||||
|
|
||||||
const commonList = menuList['common'] ?? [];
|
const commonList = menuList['common'] ?? [];
|
||||||
if (commonList?.length && siblingList?.length) {
|
if (commonList?.length && recommendedList.length) {
|
||||||
commonList.unshift({
|
|
||||||
title: '代码片段',
|
|
||||||
items: siblingList,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (commonList?.length && insertedList?.length) {
|
|
||||||
commonList.unshift({
|
commonList.unshift({
|
||||||
title: '推荐使用',
|
title: '推荐使用',
|
||||||
items: insertedList,
|
items: recommendedList,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return menuList;
|
return menuList;
|
||||||
}, [insertedList, siblingList, designer.menuData]);
|
}, [recommendedList, designer.menuData]);
|
||||||
|
|
||||||
const innerTypeProps =
|
const innerTypeProps =
|
||||||
// 手动触发 适用于 点击添加组件
|
// 手动触发 适用于 点击添加组件
|
||||||
|
|||||||
@@ -1,11 +1,39 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Box, css } from 'coral-system';
|
import { Box, css, Text } from 'coral-system';
|
||||||
import { observer, useWorkspace } from '@music163/tango-context';
|
import { observer, useDesigner, useWorkspace } from '@music163/tango-context';
|
||||||
import { CloseOutlined } from '@ant-design/icons';
|
import { CloseOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
const errorMessageStyle = css`
|
const errorMessageStyle = css`
|
||||||
padding: 24px;
|
padding: 35px;
|
||||||
|
position: relative;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
|
color: #f45755;
|
||||||
|
font-weight: bold;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #171717;
|
||||||
|
border-radius: 8px;
|
||||||
|
.top-bar {
|
||||||
|
border-radius: 8px 8px 0 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 10px;
|
||||||
|
background-color: #f45755;
|
||||||
|
}
|
||||||
|
.WorkspaceErrorOverlayItem {
|
||||||
|
font-size: 18px;
|
||||||
|
padding-top: 20px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
.WorkspaceErrorOverlayItemFilename {
|
||||||
|
color: #48cacb;
|
||||||
|
text-decoration: underline;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
&:hover {
|
||||||
|
color: #51b1ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,11 +42,17 @@ const errorMessageStyle = css`
|
|||||||
export const FileErrorsOverlay = observer(() => {
|
export const FileErrorsOverlay = observer(() => {
|
||||||
const [isVisible, setIsVisible] = useState<boolean>(true);
|
const [isVisible, setIsVisible] = useState<boolean>(true);
|
||||||
const workspace = useWorkspace();
|
const workspace = useWorkspace();
|
||||||
|
const designer = useDesigner();
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setIsVisible(false);
|
setIsVisible(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleOpenErrorFile = (fileName: string) => {
|
||||||
|
workspace.setActiveFile(fileName);
|
||||||
|
designer.setActiveView('code');
|
||||||
|
};
|
||||||
|
|
||||||
if (workspace.fileErrors.length === 0) {
|
if (workspace.fileErrors.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -35,32 +69,63 @@ export const FileErrorsOverlay = observer(() => {
|
|||||||
left="0"
|
left="0"
|
||||||
right="0"
|
right="0"
|
||||||
height="100%"
|
height="100%"
|
||||||
bg="rgba(244, 244, 244, 0.9)"
|
bg="rgb(84, 84, 84)"
|
||||||
|
padding="30px"
|
||||||
color="red"
|
color="red"
|
||||||
|
overflow="auto"
|
||||||
zIndex={1999}
|
zIndex={1999}
|
||||||
>
|
>
|
||||||
<Box position="relative" p="4">
|
<Box position="relative" p="4" boxShadow="0 0 10px rgba(0, 0, 0, 0.5)">
|
||||||
<CloseOutlined
|
<CloseOutlined
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 12,
|
top: 24,
|
||||||
right: 12,
|
right: 12,
|
||||||
color: '#000',
|
color: '#fff',
|
||||||
|
zIndex: 2,
|
||||||
}}
|
}}
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
/>
|
/>
|
||||||
<Box css={errorMessageStyle}>
|
<Box css={errorMessageStyle}>
|
||||||
<Box fontSize="20px" mb="l">
|
<Box className="top-bar" />
|
||||||
代码解析错误,请回到源码模式检查并修改错误
|
<Box fontSize="18px" mb="l">
|
||||||
|
<Text letterSpacing=".5px" color="#c29ef5">
|
||||||
|
[plugin: @babel/parser]
|
||||||
|
</Text>
|
||||||
|
<Text marginLeft={'8px'} color="#f45755">
|
||||||
|
SyntaxError in {workspace.fileErrors.length} files,Click file to modify the error
|
||||||
|
code
|
||||||
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
{workspace.fileErrors.map((fileError) => (
|
<Box>
|
||||||
<Box key={fileError.filename} borderBottom="solid" borderBottomColor="line2" py="l">
|
{workspace.fileErrors.map((fileError, index) => (
|
||||||
<Box fontWeight="bold">{fileError.filename}</Box>
|
<Box
|
||||||
<Box as="code" display="block">
|
className="WorkspaceErrorOverlayItem"
|
||||||
{fileError.message}
|
key={fileError.filename}
|
||||||
|
borderBottom={index === workspace.fileErrors.length - 1 ? 'none' : 'dashed'}
|
||||||
|
borderBottomColor="line2"
|
||||||
|
py="l"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
className="WorkspaceErrorOverlayItemFilename"
|
||||||
|
fontWeight="bold"
|
||||||
|
style={{ cursor: 'pointer' }}
|
||||||
|
onClick={() => handleOpenErrorFile(fileError.filename)}
|
||||||
|
>
|
||||||
|
{fileError.filename}
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
as="code"
|
||||||
|
display="block"
|
||||||
|
color="#daa15e"
|
||||||
|
fontSize="16px"
|
||||||
|
fontWeight={'normal'}
|
||||||
|
>
|
||||||
|
{fileError.message}
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
))}
|
||||||
))}
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -88,6 +88,10 @@ export function AddServiceForm({
|
|||||||
>
|
>
|
||||||
<Input placeholder="请输入数据服务调用名称" disabled={disabled || isModifyMode} />
|
<Input placeholder="请输入数据服务调用名称" disabled={disabled || isModifyMode} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
{/* 备注 */}
|
||||||
|
<Form.Item label="备注" name="description">
|
||||||
|
<Input placeholder="请输入备注信息" />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item label="路径" name="url" rules={[{ required: true, type: 'url' }]}>
|
<Form.Item label="路径" name="url" rules={[{ required: true, type: 'url' }]}>
|
||||||
<Input placeholder="请输入数据服务调用名称" disabled={disabled || isModifyMode} />
|
<Input placeholder="请输入数据服务调用名称" disabled={disabled || isModifyMode} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { Radio, RadioProps, Tooltip } from 'antd';
|
import { Radio, RadioProps, Tooltip } from 'antd';
|
||||||
import type { OptionType } from '@music163/tango-helpers';
|
import type { IOptionItem } from '@music163/tango-helpers';
|
||||||
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
||||||
import { IconFont } from '@music163/tango-ui';
|
import { IconFont } from '@music163/tango-ui';
|
||||||
|
|
||||||
interface ChoiceSetterProps {
|
interface ChoiceSetterProps {
|
||||||
options?: OptionType[];
|
options?: IOptionItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ChoiceSetter({
|
export function ChoiceSetter({
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
||||||
|
import { ClassNameInput } from '@music163/tango-ui';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export function ClassNameSetter({ value, onChange }: FormItemComponentProps<string>) {
|
||||||
|
return <ClassNameInput value={value} onChange={onChange} />;
|
||||||
|
}
|
||||||
+64
-19
@@ -2,9 +2,17 @@ import React, { useState, useEffect, useCallback } from 'react';
|
|||||||
import { Box, Text, css } from 'coral-system';
|
import { Box, Text, css } from 'coral-system';
|
||||||
import { Dropdown, Button } from 'antd';
|
import { Dropdown, Button } from 'antd';
|
||||||
import { isValidExpressionCode } from '@music163/tango-core';
|
import { isValidExpressionCode } from '@music163/tango-core';
|
||||||
import { getValue, IVariableTreeNode, noop } from '@music163/tango-helpers';
|
import { getValue, interpolate, IVariableTreeNode, noop } from '@music163/tango-helpers';
|
||||||
import { CloseCircleFilled, MenuOutlined } from '@ant-design/icons';
|
import { CloseCircleFilled, MenuOutlined } from '@ant-design/icons';
|
||||||
import { Panel, InputCode, Action, DragPanel, PopOutOutlined } from '@music163/tango-ui';
|
import {
|
||||||
|
Panel,
|
||||||
|
InputCode,
|
||||||
|
Action,
|
||||||
|
DragPanel,
|
||||||
|
PopOutOutlined,
|
||||||
|
InputCodeProps,
|
||||||
|
InputStyleCode,
|
||||||
|
} from '@music163/tango-ui';
|
||||||
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
||||||
import { useWorkspace, useWorkspaceData } from '@music163/tango-context';
|
import { useWorkspace, useWorkspaceData } from '@music163/tango-context';
|
||||||
import { VariableTree } from '../components';
|
import { VariableTree } from '../components';
|
||||||
@@ -26,6 +34,19 @@ export const jsonValueValidate = (value: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拼装回调函数
|
||||||
|
* @param value 回调函数体
|
||||||
|
* @param template 回调函数模板
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function getCallbackValue(value: string, template?: string) {
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return template ? interpolate(template, { content: value }) : `() => {\n ${value}\n}`;
|
||||||
|
}
|
||||||
|
|
||||||
const suffixStyle = css`
|
const suffixStyle = css`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -37,26 +58,32 @@ const suffixStyle = css`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export interface ExpressionSetterProps extends FormItemComponentProps<string> {
|
export interface CodeSetterProps extends FormItemComponentProps<string> {
|
||||||
modalTitle?: string;
|
modalTitle?: string;
|
||||||
modalTip?: string;
|
modalTip?: string;
|
||||||
autoCompleteOptions?: string[];
|
autoCompleteOptions?: string[];
|
||||||
allowClear?: boolean;
|
allowClear?: boolean;
|
||||||
showOptionsDropDown?: boolean;
|
showOptionsDropDown?: boolean;
|
||||||
|
/**
|
||||||
|
* 表达式类型指定为 css object
|
||||||
|
*/
|
||||||
|
expressionType?: 'cssObject';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ExpressionSetter(props: ExpressionSetterProps) {
|
export function CodeSetter(props: CodeSetterProps) {
|
||||||
const {
|
const {
|
||||||
onChange,
|
onChange,
|
||||||
modalTitle,
|
modalTitle,
|
||||||
modalTip,
|
modalTip,
|
||||||
autoCompleteOptions,
|
autoCompleteOptions,
|
||||||
placeholder = '在这里输入JS代码',
|
template,
|
||||||
|
placeholder = '在这里输入代码',
|
||||||
value: valueProp,
|
value: valueProp,
|
||||||
status,
|
status,
|
||||||
allowClear = true,
|
allowClear = true,
|
||||||
newStoreTemplate,
|
newStoreTemplate,
|
||||||
showOptionsDropDown = true,
|
showOptionsDropDown = true,
|
||||||
|
expressionType,
|
||||||
} = props;
|
} = props;
|
||||||
// const codeValue = getCodeOfWrappedCode(valueProp);
|
// const codeValue = getCodeOfWrappedCode(valueProp);
|
||||||
const [inputValue, setInputValue] = useState(valueProp);
|
const [inputValue, setInputValue] = useState(valueProp);
|
||||||
@@ -79,10 +106,12 @@ export function ExpressionSetter(props: ExpressionSetterProps) {
|
|||||||
const sandbox = useSandboxQuery();
|
const sandbox = useSandboxQuery();
|
||||||
const evaluateContext = sandbox.window;
|
const evaluateContext = sandbox.window;
|
||||||
|
|
||||||
|
const InputCodeComponent = expressionType === 'cssObject' ? InputStyleCode : InputCode;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box className="ExpressionSetter">
|
<Box className="ExpressionSetter">
|
||||||
{/* 同时支持下拉框展示 */}
|
{/* 同时支持下拉框展示 */}
|
||||||
<InputCode
|
<InputCodeComponent
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
suffix={
|
suffix={
|
||||||
<Box css={suffixStyle}>
|
<Box css={suffixStyle}>
|
||||||
@@ -90,7 +119,7 @@ export function ExpressionSetter(props: ExpressionSetterProps) {
|
|||||||
<CloseCircleFilled
|
<CloseCircleFilled
|
||||||
title="清空"
|
title="清空"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
change('');
|
change(undefined);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -119,8 +148,10 @@ export function ExpressionSetter(props: ExpressionSetterProps) {
|
|||||||
subTitle={modalTip}
|
subTitle={modalTip}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
autoCompleteOptions={autoCompleteOptions}
|
autoCompleteOptions={autoCompleteOptions}
|
||||||
|
template={template}
|
||||||
newStoreTemplate={newStoreTemplate}
|
newStoreTemplate={newStoreTemplate}
|
||||||
value={inputValue}
|
value={inputValue}
|
||||||
|
expressionType={expressionType}
|
||||||
onOk={(value) => {
|
onOk={(value) => {
|
||||||
change(value);
|
change(value);
|
||||||
}}
|
}}
|
||||||
@@ -141,7 +172,7 @@ export function ExpressionSetter(props: ExpressionSetterProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExpressionPopoverProps {
|
export interface ExpressionPopoverProps extends InputCodeProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
subTitle?: string;
|
subTitle?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
@@ -150,10 +181,18 @@ export interface ExpressionPopoverProps {
|
|||||||
onOk?: (value: string) => void;
|
onOk?: (value: string) => void;
|
||||||
dataSource?: IVariableTreeNode[];
|
dataSource?: IVariableTreeNode[];
|
||||||
autoCompleteOptions?: string[];
|
autoCompleteOptions?: string[];
|
||||||
|
/**
|
||||||
|
* 值的模板,一般用于定义函数模板
|
||||||
|
*/
|
||||||
|
template?: string;
|
||||||
/**
|
/**
|
||||||
* 新建 store 的模板代码
|
* 新建 store 的模板代码
|
||||||
*/
|
*/
|
||||||
newStoreTemplate?: string;
|
newStoreTemplate?: string;
|
||||||
|
/**
|
||||||
|
* 表达式类型指定为 css object
|
||||||
|
*/
|
||||||
|
expressionType?: 'cssObject';
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,12 +205,15 @@ export function ExpressionPopover({
|
|||||||
value,
|
value,
|
||||||
dataSource,
|
dataSource,
|
||||||
autoCompleteOptions,
|
autoCompleteOptions,
|
||||||
|
template,
|
||||||
newStoreTemplate = CODE_TEMPLATES.newStoreTemplate,
|
newStoreTemplate = CODE_TEMPLATES.newStoreTemplate,
|
||||||
children,
|
children,
|
||||||
|
expressionType,
|
||||||
}: ExpressionPopoverProps) {
|
}: ExpressionPopoverProps) {
|
||||||
const [exp, setExp] = useState(value ?? defaultValue);
|
const [exp, setExp] = useState(value ?? defaultValue);
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
const workspace = useWorkspace();
|
const workspace = useWorkspace();
|
||||||
|
const InputCodeComponent = expressionType === 'cssObject' ? InputStyleCode : InputCode;
|
||||||
|
|
||||||
const selectNodePath = workspace.selectSource.selected[0]?.codeId;
|
const selectNodePath = workspace.selectSource.selected[0]?.codeId;
|
||||||
|
|
||||||
@@ -207,7 +249,7 @@ export function ExpressionPopover({
|
|||||||
body={
|
body={
|
||||||
<Box display="flex" flexDirection="column">
|
<Box display="flex" flexDirection="column">
|
||||||
<Box p="m">
|
<Box p="m">
|
||||||
<InputCode
|
<InputCodeComponent
|
||||||
shape="inset"
|
shape="inset"
|
||||||
minHeight="56px"
|
minHeight="56px"
|
||||||
maxHeight="160px"
|
maxHeight="160px"
|
||||||
@@ -223,19 +265,18 @@ export function ExpressionPopover({
|
|||||||
autoCompleteOptions={autoCompleteOptions}
|
autoCompleteOptions={autoCompleteOptions}
|
||||||
/>
|
/>
|
||||||
{error ? (
|
{error ? (
|
||||||
<Text color="red" fontSize="12px" as="p">
|
<Text color="red" fontSize="12px" as="div">
|
||||||
出错了!输入的表达式存在语法错误,请修改后再提交!
|
出错了!输入的表达式存在语法错误,请修改后再提交!
|
||||||
</Text>
|
</Text>
|
||||||
) : null}
|
) : null}
|
||||||
{subTitle && (
|
<Box fontSize="12px" color="text2">
|
||||||
<Text fontSize="12px" color="text3" as="p">
|
<Text display="block">说明:</Text>
|
||||||
{subTitle}
|
{subTitle && <Text display="block">{subTitle}</Text>}
|
||||||
|
<Text display="block">
|
||||||
|
你可以在上面的代码输入框里输入常规的 javascript 代码,还可以直接使用 jsx
|
||||||
|
代码,但需要符合该属性的接受值定义。
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
</Box>
|
||||||
<Text fontSize="12px" color="text3" as="p">
|
|
||||||
说明:你可以在上面的代码输入框里输入常规的 javascript 代码,还可以直接使用 jsx
|
|
||||||
代码,但需要符合该属性的接受值定义。
|
|
||||||
</Text>
|
|
||||||
</Box>
|
</Box>
|
||||||
<Panel
|
<Panel
|
||||||
title="从变量列表中选中"
|
title="从变量列表中选中"
|
||||||
@@ -274,7 +315,11 @@ export function ExpressionPopover({
|
|||||||
}
|
}
|
||||||
let str;
|
let str;
|
||||||
if (/^(stores|services)\./.test(node.key)) {
|
if (/^(stores|services)\./.test(node.key)) {
|
||||||
str = `tango.${node.key.replaceAll('.', '?.')}`;
|
// 从匹配到的第二个点开始替换为 ?.,因为第一个点是 stores 或 services
|
||||||
|
str = `tango.${node.key.replace(/(?<=\..*?)\./g, '?.')}`;
|
||||||
|
if (node.type === 'function') {
|
||||||
|
str = getCallbackValue(`${str}();`, template);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
str = `${node.key}`;
|
str = `${node.key}`;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import { css, Box, Text } from 'coral-system';
|
import { css, Box, Text } from 'coral-system';
|
||||||
import { AutoComplete } from 'antd';
|
import { AutoComplete, Input } from 'antd';
|
||||||
import { ActionSelect } from '@music163/tango-ui';
|
import { ActionSelect } from '@music163/tango-ui';
|
||||||
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
||||||
import { useWorkspace, useWorkspaceData } from '@music163/tango-context';
|
import { useWorkspace, useWorkspaceData } from '@music163/tango-context';
|
||||||
import { Dict, wrapCode } from '@music163/tango-helpers';
|
import { Dict, wrapCode } from '@music163/tango-helpers';
|
||||||
import { ExpressionPopover } from './expression-setter';
|
import { ExpressionPopover, getCallbackValue } from './code-setter';
|
||||||
import { value2code } from '@music163/tango-core';
|
import { value2code } from '@music163/tango-core';
|
||||||
|
|
||||||
enum EventAction {
|
enum EventAction {
|
||||||
@@ -31,7 +31,7 @@ export type EventSetterProps = FormItemComponentProps<string>;
|
|||||||
* 事件监听函数绑定器
|
* 事件监听函数绑定器
|
||||||
*/
|
*/
|
||||||
export function EventSetter(props: EventSetterProps) {
|
export function EventSetter(props: EventSetterProps) {
|
||||||
const { value, onChange, modalTitle } = props;
|
const { value, onChange, modalTitle, modalTip, template } = props;
|
||||||
const [type, setType] = useState<EventAction>(); // 事件类型
|
const [type, setType] = useState<EventAction>(); // 事件类型
|
||||||
const [temp, setTemp] = useState(''); // 二级暂存值
|
const [temp, setTemp] = useState(''); // 二级暂存值
|
||||||
const { actionVariables, routeOptions } = useWorkspaceData();
|
const { actionVariables, routeOptions } = useWorkspaceData();
|
||||||
@@ -59,7 +59,9 @@ export function EventSetter(props: EventSetterProps) {
|
|||||||
label: (
|
label: (
|
||||||
<ExpressionPopover
|
<ExpressionPopover
|
||||||
title={modalTitle}
|
title={modalTitle}
|
||||||
|
subTitle={modalTip}
|
||||||
value={value}
|
value={value}
|
||||||
|
template={template}
|
||||||
onOk={(nextValue) => {
|
onOk={(nextValue) => {
|
||||||
handleChange(nextValue);
|
handleChange(nextValue);
|
||||||
}}
|
}}
|
||||||
@@ -74,30 +76,34 @@ export function EventSetter(props: EventSetterProps) {
|
|||||||
{ label: '打开弹窗', value: EventAction.OpenModal },
|
{ label: '打开弹窗', value: EventAction.OpenModal },
|
||||||
{ label: '关闭弹窗', value: EventAction.CloseModal },
|
{ label: '关闭弹窗', value: EventAction.CloseModal },
|
||||||
],
|
],
|
||||||
[modalTitle, value, actionVariables, handleChange],
|
[modalTitle, value, actionVariables, template, handleChange],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onAction = (key: string) => {
|
const onAction = (key: string) => {
|
||||||
setType(key as EventAction); // 记录事件类型
|
setType(key as EventAction); // 记录事件类型
|
||||||
setTemp(''); // 重置二级选项值
|
setTemp(''); // 重置二级选项值
|
||||||
|
|
||||||
switch (key) {
|
if (key === EventAction.NoAction) {
|
||||||
case EventAction.ConsoleLog:
|
handleChange(undefined);
|
||||||
handleChange('(...args) => console.log(...args)');
|
return;
|
||||||
break;
|
|
||||||
case EventAction.NoAction:
|
|
||||||
handleChange(undefined);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const actionText = getActionText(type, temp, code);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box css={wrapperStyle}>
|
<Box css={wrapperStyle}>
|
||||||
<ActionSelect options={options} onSelect={onAction} text={actionText} />
|
<ActionSelect options={options} onSelect={onAction} defaultText="请选择动作类型" />
|
||||||
|
{type === EventAction.ConsoleLog && (
|
||||||
|
<Input
|
||||||
|
placeholder="输入 Console.log 日志内容"
|
||||||
|
value={temp}
|
||||||
|
onChange={(e) => setTemp(e.target.value)}
|
||||||
|
onBlur={() => {
|
||||||
|
if (temp) {
|
||||||
|
handleChange(getExpressionValue(type, temp));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{type === EventAction.NavigateTo && (
|
{type === EventAction.NavigateTo && (
|
||||||
<AutoComplete
|
<AutoComplete
|
||||||
placeholder="选择或输入页面路由"
|
placeholder="选择或输入页面路由"
|
||||||
@@ -142,25 +148,15 @@ export function EventSetter(props: EventSetterProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handlerMap: Dict = {
|
const handlerMap: Dict = {
|
||||||
[EventAction.OpenModal]: 'openModal',
|
[EventAction.ConsoleLog]: 'console.log',
|
||||||
[EventAction.CloseModal]: 'closeModal',
|
[EventAction.OpenModal]: 'tango.openModal',
|
||||||
[EventAction.NavigateTo]: 'navigateTo',
|
[EventAction.CloseModal]: 'tango.closeModal',
|
||||||
|
[EventAction.NavigateTo]: 'tango.navigateTo',
|
||||||
};
|
};
|
||||||
|
|
||||||
function getActionText(type: EventAction, temp: string, fallbackCode: string) {
|
|
||||||
let text;
|
|
||||||
if (handlerMap[type]) {
|
|
||||||
text = getExpressionValue(type, temp);
|
|
||||||
} else if (fallbackCode) {
|
|
||||||
text = fallbackCode;
|
|
||||||
}
|
|
||||||
text = text || '请选择';
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getExpressionValue(type: EventAction, value = '') {
|
function getExpressionValue(type: EventAction, value = '') {
|
||||||
const handler = handlerMap[type];
|
const handler = handlerMap[type];
|
||||||
if (handler) {
|
if (handler) {
|
||||||
return `() => tango.${handler}("${value}")`;
|
return getCallbackValue(`${handler}("${value}");`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import { CssSetter } from './css-setter';
|
|||||||
import { DateRangeSetter, DateSetter, TimeRangeSetter } from './date-setter';
|
import { DateRangeSetter, DateSetter, TimeRangeSetter } from './date-setter';
|
||||||
import { EnumSetter } from './enum-setter';
|
import { EnumSetter } from './enum-setter';
|
||||||
import { EventSetter } from './event-setter';
|
import { EventSetter } from './event-setter';
|
||||||
import { ExpressionSetter } from './expression-setter';
|
import { CodeSetter } from './code-setter';
|
||||||
import { JSONSetter } from './json-setter';
|
import { JSONSetter } from './json-setter';
|
||||||
import { JsxSetter } from './jsx-setter';
|
import { JsxSetter } from './jsx-setter';
|
||||||
import { ListSetter } from './list-setter';
|
import { ListSetter } from './list-setter';
|
||||||
import { ModelSetter } from './model-setter';
|
import { ModelSetter } from './model-setter';
|
||||||
import { OptionSetter } from './option-setter';
|
import { OptionSetter } from './option-setter';
|
||||||
import { PickerSetter } from './picker-setter';
|
import { PickerSetter } from './picker-setter';
|
||||||
import { RenderSetter, TableCellSetter, TableExpandableSetter } from './render-setter';
|
import { RenderSetter } from './render-setter';
|
||||||
import { RouterSetter } from './router-setter';
|
import { RouterSetter } from './router-setter';
|
||||||
import {
|
import {
|
||||||
SpacingSetter,
|
SpacingSetter,
|
||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
FlexDirectionSetter,
|
FlexDirectionSetter,
|
||||||
} from './style-setter';
|
} from './style-setter';
|
||||||
import { ChoiceSetter } from './choice-setter';
|
import { ChoiceSetter } from './choice-setter';
|
||||||
|
import { ClassNameSetter } from './classname-setter';
|
||||||
import { isValidExpressionCode } from '@music163/tango-core';
|
import { isValidExpressionCode } from '@music163/tango-core';
|
||||||
|
|
||||||
const codeValidate: IFormItemCreateOptions['validate'] = (value, field) => {
|
const codeValidate: IFormItemCreateOptions['validate'] = (value, field) => {
|
||||||
@@ -49,10 +50,14 @@ export const BUILT_IN_SETTERS: IFormItemCreateOptions[] = [
|
|||||||
{
|
{
|
||||||
name: 'codeSetter',
|
name: 'codeSetter',
|
||||||
alias: ['expSetter', 'expressionSetter'],
|
alias: ['expSetter', 'expressionSetter'],
|
||||||
component: ExpressionSetter,
|
component: CodeSetter,
|
||||||
type: 'code',
|
type: 'code',
|
||||||
validate: codeValidate,
|
validate: codeValidate,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'classNameSetter',
|
||||||
|
component: ClassNameSetter,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'radioGroupSetter',
|
name: 'radioGroupSetter',
|
||||||
alias: ['choiceSetter'],
|
alias: ['choiceSetter'],
|
||||||
@@ -126,22 +131,12 @@ export const BUILT_IN_SETTERS: IFormItemCreateOptions[] = [
|
|||||||
component: PickerSetter,
|
component: PickerSetter,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'renderPropsSetter',
|
name: 'renderSetter',
|
||||||
|
alias: ['renderPropsSetter'],
|
||||||
component: RenderSetter,
|
component: RenderSetter,
|
||||||
type: 'code',
|
type: 'code',
|
||||||
validate: codeValidate,
|
validate: codeValidate,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'tableCellSetter',
|
|
||||||
component: TableCellSetter,
|
|
||||||
type: 'code',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'tableExpandableSetter',
|
|
||||||
component: TableExpandableSetter,
|
|
||||||
type: 'code',
|
|
||||||
validate: codeValidate,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'routerSetter',
|
name: 'routerSetter',
|
||||||
component: RouterSetter,
|
component: RouterSetter,
|
||||||
|
|||||||
@@ -2,22 +2,16 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||||||
import { ActionSelect, InputCode } from '@music163/tango-ui';
|
import { ActionSelect, InputCode } from '@music163/tango-ui';
|
||||||
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
import { FormItemComponentProps } from '@music163/tango-setting-form';
|
||||||
import { Box } from 'coral-system';
|
import { Box } from 'coral-system';
|
||||||
import { Dict } from '@music163/tango-helpers';
|
import { Dict, IOptionItem } from '@music163/tango-helpers';
|
||||||
|
import { getCallbackValue } from './code-setter';
|
||||||
interface IRenderOption {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
render?: string;
|
|
||||||
relatedImports?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RenderSetterProps {
|
export interface RenderSetterProps {
|
||||||
text?: string;
|
text?: string;
|
||||||
options?: IRenderOption[];
|
options?: IOptionItem[];
|
||||||
fallbackOption?: IRenderOption;
|
fallbackOption?: IOptionItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultOptions: IRenderOption[] = [
|
const defaultOptions: IOptionItem[] = [
|
||||||
{ label: '取消自定义', value: '' },
|
{ label: '取消自定义', value: '' },
|
||||||
{ label: '自定义渲染', value: 'Box', render: '() => <Box></Box>' },
|
{ label: '自定义渲染', value: 'Box', render: '() => <Box></Box>' },
|
||||||
];
|
];
|
||||||
@@ -30,6 +24,7 @@ export function RenderSetter({
|
|||||||
onChange,
|
onChange,
|
||||||
text = '自定义渲染为',
|
text = '自定义渲染为',
|
||||||
options = defaultOptions,
|
options = defaultOptions,
|
||||||
|
template = `() => {{content}}`,
|
||||||
fallbackOption,
|
fallbackOption,
|
||||||
}: FormItemComponentProps & RenderSetterProps) {
|
}: FormItemComponentProps & RenderSetterProps) {
|
||||||
const [inputValue, setInputValue] = useState(value || '');
|
const [inputValue, setInputValue] = useState(value || '');
|
||||||
@@ -47,13 +42,14 @@ export function RenderSetter({
|
|||||||
const onSelect = useCallback(
|
const onSelect = useCallback(
|
||||||
(key: string) => {
|
(key: string) => {
|
||||||
const option = optionsMap[key] || fallbackOption;
|
const option = optionsMap[key] || fallbackOption;
|
||||||
if (option?.render) {
|
const next = option?.render || getCallbackValue(option.renderBody, template);
|
||||||
onChange(option.render, { relatedImports: option.relatedImports });
|
if (next) {
|
||||||
|
onChange(next, { relatedImports: option.relatedImports });
|
||||||
} else {
|
} else {
|
||||||
onChange(undefined);
|
onChange(undefined);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[optionsMap, fallbackOption, onChange],
|
[optionsMap, fallbackOption, onChange, template],
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
@@ -68,69 +64,3 @@ export function RenderSetter({
|
|||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRender = (content: string, type?: 'tableCell' | 'tableExpandable') => {
|
|
||||||
let code;
|
|
||||||
switch (type) {
|
|
||||||
case 'tableCell':
|
|
||||||
code = `(value, record, index) => ${content}`;
|
|
||||||
break;
|
|
||||||
case 'tableExpandable':
|
|
||||||
code = `{
|
|
||||||
expandedRowRender: (record) => ${content},
|
|
||||||
rowExpandable: (record) => true
|
|
||||||
}`;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
code = `() => ${content}`;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return code;
|
|
||||||
};
|
|
||||||
|
|
||||||
const tableCellOptions: RenderSetterProps['options'] = [
|
|
||||||
{ label: '取消自定义', value: '' },
|
|
||||||
{
|
|
||||||
label: '自定义区域',
|
|
||||||
value: 'Box',
|
|
||||||
render: getRender('<Box></Box>', 'tableCell'),
|
|
||||||
relatedImports: ['Box'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '标签',
|
|
||||||
value: 'Tag',
|
|
||||||
render: getRender('<Tag>tag</Tag>', 'tableCell'),
|
|
||||||
relatedImports: ['Tag'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '按钮',
|
|
||||||
value: 'Button',
|
|
||||||
render: getRender('<Button>button</Button>', 'tableCell'),
|
|
||||||
relatedImports: ['Button'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '图片',
|
|
||||||
value: 'Image',
|
|
||||||
render: getRender('<Image width={150} src="https://picsum.photos/100" />', 'tableCell'),
|
|
||||||
relatedImports: ['Image'],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const tableExpandableOptions: RenderSetterProps['options'] = [
|
|
||||||
{
|
|
||||||
label: '设置可展开行',
|
|
||||||
value: 'Box',
|
|
||||||
render: getRender('<Box></Box>', 'tableExpandable'),
|
|
||||||
relatedImports: ['Box'],
|
|
||||||
},
|
|
||||||
{ label: '取消可展开行', value: '' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export function TableCellSetter(props: FormItemComponentProps) {
|
|
||||||
return <RenderSetter options={tableCellOptions} {...props} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: 应该直接用 props 嵌套的模式
|
|
||||||
export function TableExpandableSetter(props: FormItemComponentProps) {
|
|
||||||
return <RenderSetter options={tableExpandableOptions} text="配置表格可展开行" {...props} />;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ function MaterialGrid({ data }: MaterialProps) {
|
|||||||
<IconFont className="material-icon" type={data.icon || 'icon-placeholder'} />
|
<IconFont className="material-icon" type={data.icon || 'icon-placeholder'} />
|
||||||
) : (
|
) : (
|
||||||
<Box className="material-icon">
|
<Box className="material-icon">
|
||||||
<img src={icon} alt={data.name} />
|
<img src={icon} alt={data.name} height="32" />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -25,22 +25,45 @@ function DesktopSimulator({ children }: HTMLCoralProps<'div'>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mobileStyle = css`
|
const mobileStyle = css`
|
||||||
--device-viewport-width: 375px;
|
--device-viewport-width: 360px;
|
||||||
--device-viewport-height: 812px;
|
--device-viewport-height: 640px;
|
||||||
--device-frame-width: 13px;
|
position: relative;
|
||||||
background-image: url(https://p5.music.126.net/obj/wonDlsKUwrLClGjCm8Kx/21897838692/b1c5/2665/56db/10558c1bb2030d55ceabbcc74431de99.png);
|
margin: auto;
|
||||||
background-repeat: no-repeat;
|
border: 16px black solid;
|
||||||
background-size: 100% 100%;
|
border-top-width: 60px;
|
||||||
box-shadow: 0 2px 8px rgb(2 8 20 / 10%), 0 8px 16px rgb(2 8 20 / 8%);
|
border-bottom-width: 60px;
|
||||||
border-radius: 62px;
|
border-radius: 36px;
|
||||||
overflow: hidden;
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 60px;
|
||||||
|
height: 5px;
|
||||||
|
position: absolute;
|
||||||
|
top: -30px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background: #333;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
bottom: -65px;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background: #333;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
.MobileSimulatorDeviceFrame {
|
.MobileSimulatorDeviceFrame {
|
||||||
border-radius: 50px;
|
|
||||||
width: var(--device-viewport-width);
|
width: var(--device-viewport-width);
|
||||||
height: var(--device-viewport-height);
|
height: var(--device-viewport-height);
|
||||||
margin: var(--device-frame-width);
|
background: white;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const ModeSwitchTool = observer(() => {
|
|||||||
const designer = useDesigner();
|
const designer = useDesigner();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Group attached>
|
<Group attached whiteSpace="nowrap">
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
shape="ghost"
|
shape="ghost"
|
||||||
selected={designer.activeView === 'design'}
|
selected={designer.activeView === 'design'}
|
||||||
|
|||||||
@@ -47,11 +47,14 @@ function PageSelect({ value, onSelect, onRemove, onUpdate, onCopy, options }: Pa
|
|||||||
setVisible(false);
|
setVisible(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const current = optionMap[value];
|
const pathname = value?.split?.('?')[0];
|
||||||
|
const current = optionMap[pathname];
|
||||||
return (
|
return (
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
shape="ghost"
|
shape="ghost"
|
||||||
minWidth={100}
|
minWidth={100}
|
||||||
|
maxWidth={200}
|
||||||
|
textAlign="left"
|
||||||
dropdownProps={{
|
dropdownProps={{
|
||||||
open: visible,
|
open: visible,
|
||||||
onOpenChange: setVisible,
|
onOpenChange: setVisible,
|
||||||
|
|||||||
@@ -3,6 +3,18 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.2.4](https://github.com/netease/tango/compare/@music163/tango-helpers@1.2.3...@music163/tango-helpers@1.2.4) (2024-09-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- renderSetter with template ([#202](https://github.com/netease/tango/issues/202)) ([ea96872](https://github.com/netease/tango/commit/ea9687226123c839f7a9e001b4c01aa8315a135d))
|
||||||
|
|
||||||
|
## [1.2.3](https://github.com/netease/tango/compare/@music163/tango-helpers@1.2.2...@music163/tango-helpers@1.2.3) (2024-09-02)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- add prop value template & fix components popover ([#201](https://github.com/netease/tango/issues/201)) ([c4e1ed6](https://github.com/netease/tango/commit/c4e1ed67f55deb17dae740559602cd0adcfc8eb4))
|
||||||
|
|
||||||
## [1.2.2](https://github.com/netease/tango/compare/@music163/tango-helpers@1.2.1...@music163/tango-helpers@1.2.2) (2024-08-05)
|
## [1.2.2](https://github.com/netease/tango/compare/@music163/tango-helpers@1.2.1...@music163/tango-helpers@1.2.2) (2024-08-05)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@music163/tango-helpers",
|
"name": "@music163/tango-helpers",
|
||||||
"version": "1.2.2",
|
"version": "1.2.4",
|
||||||
"description": "Shared types, helpers, and hooks of tango-apps",
|
"description": "Shared types, helpers, and hooks of tango-apps",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"shared",
|
"shared",
|
||||||
|
|||||||
@@ -125,3 +125,17 @@ export function parseDndId(str: string): DndIdParsedType {
|
|||||||
id: str,
|
id: str,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换模板中的变量
|
||||||
|
* @example interpolate('hello {{name}}', { name: 'world' }) -> 'hello world'
|
||||||
|
*
|
||||||
|
* @param template 带模板变量的字符串
|
||||||
|
* @param props 变量字典
|
||||||
|
* @returns 返回替换后的字符串
|
||||||
|
*/
|
||||||
|
export function interpolate(template: string, props: Record<string, any>) {
|
||||||
|
return template.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
|
||||||
|
return props[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,11 +10,19 @@ export type MousePoint = {
|
|||||||
y: number;
|
y: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type OptionType = {
|
/**
|
||||||
|
* @deprecated 使用 IOptionItem 代替
|
||||||
|
*/
|
||||||
|
export type OptionType = IOptionItem<any>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表项
|
||||||
|
*/
|
||||||
|
export interface IOptionItem<T = string> {
|
||||||
/**
|
/**
|
||||||
* 值
|
* 值
|
||||||
*/
|
*/
|
||||||
value: any;
|
value: T;
|
||||||
/**
|
/**
|
||||||
* 显示的文本
|
* 显示的文本
|
||||||
*/
|
*/
|
||||||
@@ -28,10 +36,18 @@ export type OptionType = {
|
|||||||
*/
|
*/
|
||||||
tip?: string;
|
tip?: string;
|
||||||
/**
|
/**
|
||||||
* 关联的导入
|
* 自定义渲染函数,仅用于 renderSetter
|
||||||
|
*/
|
||||||
|
render?: string;
|
||||||
|
/**
|
||||||
|
* 自定义渲染函数的 body(可以用来和 template 配合),仅用于 renderSetter
|
||||||
|
*/
|
||||||
|
renderBody?: string;
|
||||||
|
/**
|
||||||
|
* 关联的导入,仅用于 renderSetter
|
||||||
*/
|
*/
|
||||||
relatedImports?: string[];
|
relatedImports?: string[];
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 变量树节点类型
|
* 变量树节点类型
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* 物料描述类型
|
* 物料描述类型
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { OptionType } from './advanced';
|
import { IOptionItem } from './advanced';
|
||||||
import { PartialRecord } from './base';
|
import { PartialRecord } from './base';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,6 +88,11 @@ export interface IComponentProp<T = any> {
|
|||||||
* 自动补全的提示值,仅对 ExpressionSetter 有效
|
* 自动补全的提示值,仅对 ExpressionSetter 有效
|
||||||
*/
|
*/
|
||||||
autoCompleteOptions?: string[];
|
autoCompleteOptions?: string[];
|
||||||
|
/**
|
||||||
|
* value 的模板,一般用于函数类型的属性,便于 setter 用来拼装返回值
|
||||||
|
* @example "(arg1, arg2, arg3) => { {{content}}}"
|
||||||
|
*/
|
||||||
|
template?: string;
|
||||||
/**
|
/**
|
||||||
* 设置器
|
* 设置器
|
||||||
*/
|
*/
|
||||||
@@ -108,7 +113,7 @@ export interface IComponentProp<T = any> {
|
|||||||
/**
|
/**
|
||||||
* 配置项的可选值,setterProps.options 的简写
|
* 配置项的可选值,setterProps.options 的简写
|
||||||
*/
|
*/
|
||||||
options?: OptionType[];
|
options?: IOptionItem[];
|
||||||
/**
|
/**
|
||||||
* 是否禁用变量绑定
|
* 是否禁用变量绑定
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,6 +3,14 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.0.13](https://github.com/netease/tango/compare/@music163/tango-sandbox@1.0.12...@music163/tango-sandbox@1.0.13) (2024-09-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @music163/tango-sandbox
|
||||||
|
|
||||||
|
## [1.0.12](https://github.com/netease/tango/compare/@music163/tango-sandbox@1.0.11...@music163/tango-sandbox@1.0.12) (2024-09-02)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @music163/tango-sandbox
|
||||||
|
|
||||||
## [1.0.11](https://github.com/netease/tango/compare/@music163/tango-sandbox@1.0.10...@music163/tango-sandbox@1.0.11) (2024-08-06)
|
## [1.0.11](https://github.com/netease/tango/compare/@music163/tango-sandbox@1.0.10...@music163/tango-sandbox@1.0.11) (2024-08-06)
|
||||||
|
|
||||||
**Note:** Version bump only for package @music163/tango-sandbox
|
**Note:** Version bump only for package @music163/tango-sandbox
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@music163/tango-sandbox",
|
"name": "@music163/tango-sandbox",
|
||||||
"version": "1.0.11",
|
"version": "1.0.13",
|
||||||
"description": "sandbox of tango apps",
|
"description": "sandbox of tango apps",
|
||||||
"author": "wwsun <ww.sun@outlook.com>",
|
"author": "wwsun <ww.sun@outlook.com>",
|
||||||
"homepage": "",
|
"homepage": "",
|
||||||
@@ -29,8 +29,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^4.8.0",
|
"@ant-design/icons": "^4.8.0",
|
||||||
"@music163/tango-core": "^1.4.2",
|
"@music163/tango-core": "^1.4.4",
|
||||||
"@music163/tango-helpers": "^1.2.2",
|
"@music163/tango-helpers": "^1.2.4",
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"lodash.isequal": "4.5.0",
|
"lodash.isequal": "4.5.0",
|
||||||
"react-frame-component": "^5.2.4"
|
"react-frame-component": "^5.2.4"
|
||||||
|
|||||||
@@ -3,6 +3,28 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.2.15](https://github.com/netease/tango/compare/@music163/tango-setting-form@1.2.14...@music163/tango-setting-form@1.2.15) (2024-09-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- renderSetter with template ([#202](https://github.com/netease/tango/issues/202)) ([ea96872](https://github.com/netease/tango/commit/ea9687226123c839f7a9e001b4c01aa8315a135d))
|
||||||
|
|
||||||
|
## [1.2.14](https://github.com/netease/tango/compare/@music163/tango-setting-form@1.2.13...@music163/tango-setting-form@1.2.14) (2024-09-02)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- add prop value template & fix components popover ([#201](https://github.com/netease/tango/issues/201)) ([c4e1ed6](https://github.com/netease/tango/commit/c4e1ed67f55deb17dae740559602cd0adcfc8eb4))
|
||||||
|
|
||||||
|
## [1.2.13](https://github.com/netease/tango/compare/@music163/tango-setting-form@1.2.12...@music163/tango-setting-form@1.2.13) (2024-08-16)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- CodeInput 支持 jsx css 代码补全 ([#198](https://github.com/netease/tango/issues/198)) ([6de5488](https://github.com/netease/tango/commit/6de54884b50d683c74d695a8c13184dc0ce8d3c4))
|
||||||
|
|
||||||
|
## [1.2.12](https://github.com/netease/tango/compare/@music163/tango-setting-form@1.2.11...@music163/tango-setting-form@1.2.12) (2024-08-09)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @music163/tango-setting-form
|
||||||
|
|
||||||
## [1.2.11](https://github.com/netease/tango/compare/@music163/tango-setting-form@1.2.10...@music163/tango-setting-form@1.2.11) (2024-08-06)
|
## [1.2.11](https://github.com/netease/tango/compare/@music163/tango-setting-form@1.2.10...@music163/tango-setting-form@1.2.11) (2024-08-06)
|
||||||
|
|
||||||
**Note:** Version bump only for package @music163/tango-setting-form
|
**Note:** Version bump only for package @music163/tango-setting-form
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@music163/tango-setting-form",
|
"name": "@music163/tango-setting-form",
|
||||||
"version": "1.2.11",
|
"version": "1.2.15",
|
||||||
"description": "setting form of tango-apps",
|
"description": "setting form of tango-apps",
|
||||||
"author": "wwsun <ww.sun@outlook.com>",
|
"author": "wwsun <ww.sun@outlook.com>",
|
||||||
"homepage": "",
|
"homepage": "",
|
||||||
@@ -28,9 +28,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^4.8.0",
|
"@ant-design/icons": "^4.8.0",
|
||||||
"@music163/tango-core": "^1.4.2",
|
"@music163/tango-core": "^1.4.4",
|
||||||
"@music163/tango-helpers": "^1.2.2",
|
"@music163/tango-helpers": "^1.2.4",
|
||||||
"@music163/tango-ui": "^1.4.1",
|
"@music163/tango-ui": "^1.4.5",
|
||||||
"antd": "^4.24.2",
|
"antd": "^4.24.2",
|
||||||
"coral-system": "^1.0.5",
|
"coral-system": "^1.0.5",
|
||||||
"mobx": "6.12.3",
|
"mobx": "6.12.3",
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ export function createFormItem(options: IFormItemCreateOptions) {
|
|||||||
placeholder,
|
placeholder,
|
||||||
docs,
|
docs,
|
||||||
autoCompleteOptions,
|
autoCompleteOptions,
|
||||||
|
template,
|
||||||
setter: setterProp,
|
setter: setterProp,
|
||||||
setterProps,
|
setterProps,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
@@ -230,14 +231,20 @@ export function createFormItem(options: IFormItemCreateOptions) {
|
|||||||
|
|
||||||
// FIXME: 重新考虑这段代码的位置,外置这个逻辑
|
// FIXME: 重新考虑这段代码的位置,外置这个逻辑
|
||||||
if (
|
if (
|
||||||
['codeSetter', 'expressionSetter', 'expSetter', 'actionSetter', 'eventSetter'].includes(
|
[
|
||||||
setter,
|
'codeSetter',
|
||||||
)
|
'expressionSetter',
|
||||||
|
'expSetter',
|
||||||
|
'actionSetter',
|
||||||
|
'eventSetter',
|
||||||
|
'renderSetter',
|
||||||
|
].includes(setter)
|
||||||
) {
|
) {
|
||||||
expProps = {
|
expProps = {
|
||||||
modalTitle: title,
|
modalTitle: title,
|
||||||
modalTip: tip,
|
modalTip: tip,
|
||||||
autoCompleteOptions,
|
autoCompleteOptions,
|
||||||
|
template,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,7 +253,7 @@ export function createFormItem(options: IFormItemCreateOptions) {
|
|||||||
const CodeSetter = REGISTERED_FORM_ITEM_MAP['codeSetter']?.config?.component;
|
const CodeSetter = REGISTERED_FORM_ITEM_MAP['codeSetter']?.config?.component;
|
||||||
|
|
||||||
const setterNode = isCodeSetter ? (
|
const setterNode = isCodeSetter ? (
|
||||||
<CodeSetter {...expProps} {...baseComponentProps} />
|
<CodeSetter {...expProps} {...baseComponentProps} {...setterProps} />
|
||||||
) : (
|
) : (
|
||||||
renderSetter({
|
renderSetter({
|
||||||
...expProps,
|
...expProps,
|
||||||
|
|||||||
@@ -3,6 +3,31 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.4.5](https://github.com/netease/tango/compare/@music163/tango-ui@1.4.4...@music163/tango-ui@1.4.5) (2024-09-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- add classNameSetter and classNameInput ([#207](https://github.com/netease/tango/issues/207)) ([55602fc](https://github.com/netease/tango/commit/55602fc961b5c20d923891ce13d7a51588bd047f))
|
||||||
|
|
||||||
|
## [1.4.4](https://github.com/netease/tango/compare/@music163/tango-ui@1.4.3...@music163/tango-ui@1.4.4) (2024-09-02)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- add prop value template & fix components popover ([#201](https://github.com/netease/tango/issues/201)) ([c4e1ed6](https://github.com/netease/tango/commit/c4e1ed67f55deb17dae740559602cd0adcfc8eb4))
|
||||||
|
|
||||||
|
## [1.4.3](https://github.com/netease/tango/compare/@music163/tango-ui@1.4.2...@music163/tango-ui@1.4.3) (2024-08-16)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- CodeInput 支持 jsx css 代码补全 ([#198](https://github.com/netease/tango/issues/198)) ([6de5488](https://github.com/netease/tango/commit/6de54884b50d683c74d695a8c13184dc0ce8d3c4))
|
||||||
|
|
||||||
|
## [1.4.2](https://github.com/netease/tango/compare/@music163/tango-ui@1.4.1...@music163/tango-ui@1.4.2) (2024-08-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- route matching without query string & toggle button wrapping ([#195](https://github.com/netease/tango/issues/195)) ([9394666](https://github.com/netease/tango/commit/939466648d40331800f15e886256a0789b7e7623))
|
||||||
|
- update mobile simulator ui ([#196](https://github.com/netease/tango/issues/196)) ([65149f1](https://github.com/netease/tango/commit/65149f1326eaf78e8a27222993c3cacc674cd378))
|
||||||
|
|
||||||
## [1.4.1](https://github.com/netease/tango/compare/@music163/tango-ui@1.4.0...@music163/tango-ui@1.4.1) (2024-08-05)
|
## [1.4.1](https://github.com/netease/tango/compare/@music163/tango-ui@1.4.0...@music163/tango-ui@1.4.1) (2024-08-05)
|
||||||
|
|
||||||
**Note:** Version bump only for package @music163/tango-ui
|
**Note:** Version bump only for package @music163/tango-ui
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@music163/tango-ui",
|
"name": "@music163/tango-ui",
|
||||||
"version": "1.4.1",
|
"version": "1.4.5",
|
||||||
"description": "ui widgets of tango",
|
"description": "ui widgets of tango",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
"@codemirror/lang-javascript": "^6.2.2",
|
"@codemirror/lang-javascript": "^6.2.2",
|
||||||
"@codemirror/lint": "^6.7.1",
|
"@codemirror/lint": "^6.7.1",
|
||||||
"@codemirror/search": "^6.5.6",
|
"@codemirror/search": "^6.5.6",
|
||||||
"@music163/tango-helpers": "^1.2.2",
|
"@music163/tango-helpers": "^1.2.4",
|
||||||
"@uiw/react-codemirror": "^4.22.0",
|
"@uiw/react-codemirror": "^4.22.0",
|
||||||
"antd": "^4.24.2",
|
"antd": "^4.24.2",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
"eslint-linter-browserify": "^8.51.0",
|
"eslint-linter-browserify": "^8.51.0",
|
||||||
"react-draggable": "^4.4.5",
|
"react-draggable": "^4.4.5",
|
||||||
"react-json-view": "^1.21.3",
|
"react-json-view": "^1.21.3",
|
||||||
"react-monaco-editor-lite": "^1.3.11"
|
"react-monaco-editor-lite": "^1.3.16"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public",
|
"access": "public",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Box, css, Text } from 'coral-system';
|
import { Box, css, Text } from 'coral-system';
|
||||||
import { Button, Dropdown, Input, Menu } from 'antd';
|
import { Button, Dropdown, Input, Menu } from 'antd';
|
||||||
import { DownOutlined, PlusSquareOutlined } from '@ant-design/icons';
|
import { DownOutlined, PlusSquareOutlined } from '@ant-design/icons';
|
||||||
@@ -23,9 +23,13 @@ interface ActionSelectProps {
|
|||||||
*/
|
*/
|
||||||
onInputChange?: (value: string) => void;
|
onInputChange?: (value: string) => void;
|
||||||
/**
|
/**
|
||||||
* 提示文本
|
* 受控的提示文本
|
||||||
*/
|
*/
|
||||||
text?: string;
|
text?: string;
|
||||||
|
/**
|
||||||
|
* 默认的提示文本
|
||||||
|
*/
|
||||||
|
defaultText?: string;
|
||||||
/**
|
/**
|
||||||
* 选择菜单时的回调
|
* 选择菜单时的回调
|
||||||
*/
|
*/
|
||||||
@@ -50,11 +54,6 @@ const actionInputStyle = css`
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
color: var(--tango-colors-text3);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--tango-colors-text2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.anticon-down {
|
.anticon-down {
|
||||||
@@ -71,15 +70,25 @@ const inputStyle = { width: 'calc(100% - 82px)' };
|
|||||||
export function ActionSelect({
|
export function ActionSelect({
|
||||||
showInput = false,
|
showInput = false,
|
||||||
defaultInputValue,
|
defaultInputValue,
|
||||||
text,
|
text: textProp,
|
||||||
|
defaultText,
|
||||||
options = [],
|
options = [],
|
||||||
onSelect,
|
onSelect,
|
||||||
onInputChange,
|
onInputChange,
|
||||||
}: ActionSelectProps) {
|
}: ActionSelectProps) {
|
||||||
|
const [text, setText] = useState<string>(defaultText);
|
||||||
const menu = (
|
const menu = (
|
||||||
<Menu onClick={({ key }) => onSelect(key)}>
|
<Menu>
|
||||||
{options.map((item) => (
|
{options.map((item) => (
|
||||||
<Menu.Item key={item.value}>
|
<Menu.Item
|
||||||
|
key={item.value}
|
||||||
|
onClick={() => {
|
||||||
|
onSelect?.(item.value);
|
||||||
|
if (!textProp) {
|
||||||
|
setText(item.label as string);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Box display="flex" alignItems="center" minWidth={200} columnGap="m">
|
<Box display="flex" alignItems="center" minWidth={200} columnGap="m">
|
||||||
<Box flex="1">{item.label}</Box>
|
<Box flex="1">{item.label}</Box>
|
||||||
<Text fontSize="12px" color="text.note">
|
<Text fontSize="12px" color="text.note">
|
||||||
@@ -122,8 +131,8 @@ export function ActionSelect({
|
|||||||
mb="m"
|
mb="m"
|
||||||
css={actionInputStyle}
|
css={actionInputStyle}
|
||||||
>
|
>
|
||||||
<Box className="action-input-text" color="text.body">
|
<Box className="action-input-text" color="text2">
|
||||||
{text}
|
{textProp ?? text}
|
||||||
</Box>
|
</Box>
|
||||||
<DownOutlined />
|
<DownOutlined />
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -0,0 +1,312 @@
|
|||||||
|
import React, { useState, useRef, KeyboardEvent, ChangeEvent, useEffect } from 'react';
|
||||||
|
import { Dropdown, Menu, Tag } from 'antd';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const InputWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4px 11px;
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
border-radius: 2px;
|
||||||
|
min-height: 32px;
|
||||||
|
&:hover {
|
||||||
|
border-color: #40a9ff;
|
||||||
|
}
|
||||||
|
&:focus-within {
|
||||||
|
border-color: #40a9ff;
|
||||||
|
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Input = styled.input`
|
||||||
|
flex: 1;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
min-width: 50px;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTag = styled(Tag)`
|
||||||
|
margin: 2px 4px 2px 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Tailwind CSS 基础类名列表
|
||||||
|
const tailwindClasses = [
|
||||||
|
// 布局
|
||||||
|
'container',
|
||||||
|
'flex',
|
||||||
|
'grid',
|
||||||
|
'block',
|
||||||
|
'inline',
|
||||||
|
'inline-block',
|
||||||
|
'hidden',
|
||||||
|
// 弹性布局
|
||||||
|
'flex-row',
|
||||||
|
'flex-col',
|
||||||
|
'flex-wrap',
|
||||||
|
'flex-nowrap',
|
||||||
|
'justify-start',
|
||||||
|
'justify-end',
|
||||||
|
'justify-center',
|
||||||
|
'justify-between',
|
||||||
|
'justify-around',
|
||||||
|
'items-start',
|
||||||
|
'items-end',
|
||||||
|
'items-center',
|
||||||
|
'items-baseline',
|
||||||
|
'items-stretch',
|
||||||
|
// 网格布局
|
||||||
|
'grid-cols-1',
|
||||||
|
'grid-cols-2',
|
||||||
|
'grid-cols-3',
|
||||||
|
'grid-cols-4',
|
||||||
|
'grid-cols-5',
|
||||||
|
'grid-cols-6',
|
||||||
|
'grid-cols-12',
|
||||||
|
// 间距
|
||||||
|
'p-0',
|
||||||
|
'p-1',
|
||||||
|
'p-2',
|
||||||
|
'p-3',
|
||||||
|
'p-4',
|
||||||
|
'p-5',
|
||||||
|
'p-6',
|
||||||
|
'p-8',
|
||||||
|
'p-10',
|
||||||
|
'p-12',
|
||||||
|
'p-16',
|
||||||
|
'p-20',
|
||||||
|
'm-0',
|
||||||
|
'm-1',
|
||||||
|
'm-2',
|
||||||
|
'm-3',
|
||||||
|
'm-4',
|
||||||
|
'm-5',
|
||||||
|
'm-6',
|
||||||
|
'm-8',
|
||||||
|
'm-10',
|
||||||
|
'm-12',
|
||||||
|
'm-16',
|
||||||
|
'm-20',
|
||||||
|
// 尺寸
|
||||||
|
'w-full',
|
||||||
|
'w-auto',
|
||||||
|
'w-1/2',
|
||||||
|
'w-1/3',
|
||||||
|
'w-2/3',
|
||||||
|
'w-1/4',
|
||||||
|
'w-3/4',
|
||||||
|
'h-full',
|
||||||
|
'h-auto',
|
||||||
|
'h-screen',
|
||||||
|
// 字体
|
||||||
|
'text-xs',
|
||||||
|
'text-sm',
|
||||||
|
'text-base',
|
||||||
|
'text-lg',
|
||||||
|
'text-xl',
|
||||||
|
'text-2xl',
|
||||||
|
'text-3xl',
|
||||||
|
'text-4xl',
|
||||||
|
'text-5xl',
|
||||||
|
'font-thin',
|
||||||
|
'font-light',
|
||||||
|
'font-normal',
|
||||||
|
'font-medium',
|
||||||
|
'font-semibold',
|
||||||
|
'font-bold',
|
||||||
|
'font-extrabold',
|
||||||
|
// 文本颜色
|
||||||
|
'text-black',
|
||||||
|
'text-white',
|
||||||
|
'text-gray-100',
|
||||||
|
'text-gray-200',
|
||||||
|
'text-gray-300',
|
||||||
|
'text-gray-400',
|
||||||
|
'text-gray-500',
|
||||||
|
'text-red-500',
|
||||||
|
'text-blue-500',
|
||||||
|
'text-green-500',
|
||||||
|
'text-yellow-500',
|
||||||
|
'text-purple-500',
|
||||||
|
'text-pink-500',
|
||||||
|
// 背景颜色
|
||||||
|
'bg-transparent',
|
||||||
|
'bg-black',
|
||||||
|
'bg-white',
|
||||||
|
'bg-gray-100',
|
||||||
|
'bg-gray-200',
|
||||||
|
'bg-gray-300',
|
||||||
|
'bg-gray-400',
|
||||||
|
'bg-gray-500',
|
||||||
|
'bg-red-500',
|
||||||
|
'bg-blue-500',
|
||||||
|
'bg-green-500',
|
||||||
|
'bg-yellow-500',
|
||||||
|
'bg-purple-500',
|
||||||
|
'bg-pink-500',
|
||||||
|
// 边框
|
||||||
|
'border',
|
||||||
|
'border-0',
|
||||||
|
'border-2',
|
||||||
|
'border-4',
|
||||||
|
'border-8',
|
||||||
|
'border-black',
|
||||||
|
'border-white',
|
||||||
|
'border-gray-300',
|
||||||
|
'border-gray-400',
|
||||||
|
'border-gray-500',
|
||||||
|
// 圆角
|
||||||
|
'rounded-none',
|
||||||
|
'rounded-sm',
|
||||||
|
'rounded',
|
||||||
|
'rounded-lg',
|
||||||
|
'rounded-full',
|
||||||
|
// 阴影
|
||||||
|
'shadow-sm',
|
||||||
|
'shadow',
|
||||||
|
'shadow-md',
|
||||||
|
'shadow-lg',
|
||||||
|
'shadow-xl',
|
||||||
|
'shadow-2xl',
|
||||||
|
'shadow-none',
|
||||||
|
// 不透明度
|
||||||
|
'opacity-0',
|
||||||
|
'opacity-25',
|
||||||
|
'opacity-50',
|
||||||
|
'opacity-75',
|
||||||
|
'opacity-100',
|
||||||
|
];
|
||||||
|
|
||||||
|
interface ClassNameInputProps {
|
||||||
|
value?: string;
|
||||||
|
defaultValue?: string;
|
||||||
|
onChange?: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ClassNameInput({ value, defaultValue, onChange }: ClassNameInputProps) {
|
||||||
|
const [inputValue, setInputValue] = useState('');
|
||||||
|
const [suggestions, setSuggestions] = useState<string[]>([]);
|
||||||
|
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
const [internalValue, setInternalValue] = useState(defaultValue || '');
|
||||||
|
const isControlled = value !== undefined;
|
||||||
|
const classNames = (isControlled ? value : internalValue).split(' ').filter(Boolean);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isControlled) {
|
||||||
|
setInternalValue(value);
|
||||||
|
}
|
||||||
|
}, [isControlled, value]);
|
||||||
|
|
||||||
|
const isValidClassName = (className: string) => {
|
||||||
|
return /^[a-zA-Z0-9_-]+(?::[a-zA-Z0-9_-]+)*$/.test(className);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateValue = (newClassNames: string[]) => {
|
||||||
|
const newValue = newClassNames.join(' ');
|
||||||
|
if (isControlled) {
|
||||||
|
onChange?.(newValue);
|
||||||
|
} else {
|
||||||
|
setInternalValue(newValue);
|
||||||
|
onChange?.(newValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
event.preventDefault();
|
||||||
|
if (highlightedIndex >= 0 && highlightedIndex < suggestions.length) {
|
||||||
|
addClassName(suggestions[highlightedIndex]);
|
||||||
|
} else {
|
||||||
|
addClassName(inputValue.trim());
|
||||||
|
}
|
||||||
|
} else if (event.key === 'ArrowDown') {
|
||||||
|
event.preventDefault();
|
||||||
|
setHighlightedIndex((prev) => (prev < suggestions.length - 1 ? prev + 1 : 0));
|
||||||
|
} else if (event.key === 'ArrowUp') {
|
||||||
|
event.preventDefault();
|
||||||
|
setHighlightedIndex((prev) => (prev > 0 ? prev - 1 : suggestions.length - 1));
|
||||||
|
} else if (event.key === 'Backspace' && inputValue === '' && classNames.length > 0) {
|
||||||
|
event.preventDefault();
|
||||||
|
const newClassNames = [...classNames];
|
||||||
|
newClassNames.pop();
|
||||||
|
updateValue(newClassNames);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const input = event.target.value;
|
||||||
|
setInputValue(input);
|
||||||
|
if (input) {
|
||||||
|
const matchedSuggestions = tailwindClasses
|
||||||
|
.filter(
|
||||||
|
(className) =>
|
||||||
|
className.toLowerCase().includes(input.toLowerCase()) &&
|
||||||
|
!classNames.includes(className),
|
||||||
|
)
|
||||||
|
.slice(0, 10);
|
||||||
|
setSuggestions(matchedSuggestions);
|
||||||
|
setHighlightedIndex(-1);
|
||||||
|
} else {
|
||||||
|
setSuggestions([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const addClassName = (className: string) => {
|
||||||
|
if (className && !classNames.includes(className) && isValidClassName(className)) {
|
||||||
|
updateValue([...classNames, className]);
|
||||||
|
setInputValue('');
|
||||||
|
setSuggestions([]);
|
||||||
|
setHighlightedIndex(-1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeClassName = (removedTag: string) => {
|
||||||
|
const newClassNames = classNames.filter((tag) => tag !== removedTag);
|
||||||
|
updateValue(newClassNames);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSuggestionClick = (suggestion: string) => {
|
||||||
|
addClassName(suggestion);
|
||||||
|
};
|
||||||
|
|
||||||
|
const menu = (
|
||||||
|
<Menu>
|
||||||
|
{suggestions.map((suggestion, index) => (
|
||||||
|
<Menu.Item
|
||||||
|
key={index}
|
||||||
|
onClick={() => handleSuggestionClick(suggestion)}
|
||||||
|
className={index === highlightedIndex ? 'ant-dropdown-menu-item-active' : ''}
|
||||||
|
>
|
||||||
|
{suggestion}
|
||||||
|
</Menu.Item>
|
||||||
|
))}
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown overlay={menu} visible={suggestions.length > 0} placement="bottomLeft">
|
||||||
|
<InputWrapper onClick={() => inputRef.current?.focus()}>
|
||||||
|
{classNames.map((className) => (
|
||||||
|
<StyledTag key={className} closable onClose={() => removeClassName(className)}>
|
||||||
|
{className}
|
||||||
|
</StyledTag>
|
||||||
|
))}
|
||||||
|
<Input
|
||||||
|
ref={inputRef}
|
||||||
|
type="text"
|
||||||
|
value={inputValue}
|
||||||
|
onKeyDown={handleInputKeyDown}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
placeholder={classNames.length === 0 ? '输入 class 名称' : ''}
|
||||||
|
/>
|
||||||
|
</InputWrapper>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import { createIcon } from './create-icon';
|
|||||||
|
|
||||||
const DualOutlinedSvg = () => (
|
const DualOutlinedSvg = () => (
|
||||||
<svg
|
<svg
|
||||||
viewBox="0 0 1025 1024"
|
viewBox="0 0 1024 1024"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="1em"
|
width="1em"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export * from './menu';
|
|||||||
export * from './panel';
|
export * from './panel';
|
||||||
export * from './toggle-button';
|
export * from './toggle-button';
|
||||||
export * from './input-code';
|
export * from './input-code';
|
||||||
|
export * from './input-style-code';
|
||||||
export * from './input-list';
|
export * from './input-list';
|
||||||
export * from './search';
|
export * from './search';
|
||||||
export * from './json-view';
|
export * from './json-view';
|
||||||
@@ -25,3 +26,4 @@ export * from './tag-select';
|
|||||||
export * from './popover';
|
export * from './popover';
|
||||||
export * from './drag-panel';
|
export * from './drag-panel';
|
||||||
export * from './context-action';
|
export * from './context-action';
|
||||||
|
export * from './classname-input';
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ export function InputCode({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function useInputCode({
|
export function useInputCode({
|
||||||
shape,
|
shape,
|
||||||
status,
|
status,
|
||||||
showLineNumbers,
|
showLineNumbers,
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Box } from 'coral-system';
|
||||||
|
import CodeMirror from '@uiw/react-codemirror';
|
||||||
|
import { javascript, javascriptLanguage, esLint } from '@codemirror/lang-javascript';
|
||||||
|
import { CompletionContext } from '@codemirror/autocomplete';
|
||||||
|
import { syntaxTree } from '@codemirror/language';
|
||||||
|
import { linter, lintGutter } from '@codemirror/lint';
|
||||||
|
import * as eslint from 'eslint-linter-browserify';
|
||||||
|
import { jsxCSSproperties, jsxCSSvalues } from './lang/css-object';
|
||||||
|
import type { Completion } from '@codemirror/autocomplete';
|
||||||
|
import { InputCodeProps, useInputCode } from './input-code';
|
||||||
|
|
||||||
|
const eslintConfig = {
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 'latest',
|
||||||
|
sourceType: 'module',
|
||||||
|
},
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
},
|
||||||
|
rules: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
function completeProperties(from: number, cssOptions: Completion[] | readonly Completion[]) {
|
||||||
|
return {
|
||||||
|
from,
|
||||||
|
options: cssOptions,
|
||||||
|
validFor: /^[\w$]*$/,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param scope 预测 CSS 的补全上下文
|
||||||
|
* @param customOptions 自定义补全选项列表
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function buildAutoComplete() {
|
||||||
|
/**
|
||||||
|
* @see context https://codemirror.net/docs/ref/#autocomplete.CompletionContext
|
||||||
|
*/
|
||||||
|
return function (context: CompletionContext) {
|
||||||
|
const nodeBefore = syntaxTree(context.state).resolveInner(context.pos, -1);
|
||||||
|
if (nodeBefore.name === 'VariableName') {
|
||||||
|
// match css property name
|
||||||
|
return completeProperties(nodeBefore.from, jsxCSSproperties());
|
||||||
|
}
|
||||||
|
// match css property value
|
||||||
|
else if (nodeBefore.name === 'String') {
|
||||||
|
return completeProperties(nodeBefore.from + 1, jsxCSSvalues);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type InputStyleCodeProps = Omit<
|
||||||
|
InputCodeProps,
|
||||||
|
'autoCompleteContext' | 'autoCompleteOptions'
|
||||||
|
>;
|
||||||
|
|
||||||
|
export function InputStyleCode({
|
||||||
|
shape = 'solid',
|
||||||
|
suffix,
|
||||||
|
status,
|
||||||
|
showLineNumbers,
|
||||||
|
showFoldGutter,
|
||||||
|
enableESLint = false,
|
||||||
|
...rest
|
||||||
|
}: InputStyleCodeProps) {
|
||||||
|
const extensions = [
|
||||||
|
javascript({ jsx: true }),
|
||||||
|
javascriptLanguage.data.of({
|
||||||
|
autocomplete: buildAutoComplete(),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
if (enableESLint) {
|
||||||
|
extensions.push(lintGutter(), linter(esLint(new eslint.Linter(), eslintConfig)));
|
||||||
|
}
|
||||||
|
const { rootStyle, codeSetup } = useInputCode({
|
||||||
|
shape,
|
||||||
|
status,
|
||||||
|
showLineNumbers,
|
||||||
|
showFoldGutter,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box className="InputCode" display="flex" alignItems="center" overflow="hidden" {...rootStyle}>
|
||||||
|
<Box flex="1" overflow="auto">
|
||||||
|
<CodeMirror
|
||||||
|
extensions={extensions}
|
||||||
|
basicSetup={codeSetup}
|
||||||
|
placeholder={'//输入 css 代码'}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
{suffix}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,602 @@
|
|||||||
|
/**
|
||||||
|
* @file: jsx css completion file
|
||||||
|
* @description: fork from https://github.com/codemirror/lang-css/blob/main/src/complete.ts
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { Completion } from '@codemirror/autocomplete';
|
||||||
|
|
||||||
|
function toCamelCase(input: string): string {
|
||||||
|
return input.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
let _properties: readonly Completion[] | null = null;
|
||||||
|
|
||||||
|
// inject global css properties
|
||||||
|
export function jsxCSSproperties() {
|
||||||
|
if (!_properties && typeof document === 'object' && document.body) {
|
||||||
|
const { style } = document.body;
|
||||||
|
const names = [];
|
||||||
|
const seen = new Set();
|
||||||
|
for (let prop in style)
|
||||||
|
if (prop !== 'cssText' && prop !== 'cssFloat') {
|
||||||
|
if (typeof style[prop] === 'string') {
|
||||||
|
if (/[A-Z]/.test(prop)) prop = prop.replace(/[A-Z]/g, (ch) => `-${ch.toLowerCase()}`);
|
||||||
|
if (!seen.has(prop)) {
|
||||||
|
names.push(prop);
|
||||||
|
seen.add(prop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_properties = names.sort().map((name) => ({ label: toCamelCase(name), type: 'variable' }));
|
||||||
|
}
|
||||||
|
return _properties || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const jsxCSSvalues = [
|
||||||
|
'above',
|
||||||
|
'absolute',
|
||||||
|
'activeborder',
|
||||||
|
'additive',
|
||||||
|
'activecaption',
|
||||||
|
'after-white-space',
|
||||||
|
'ahead',
|
||||||
|
'alias',
|
||||||
|
'all',
|
||||||
|
'all-scroll',
|
||||||
|
'alphabetic',
|
||||||
|
'alternate',
|
||||||
|
'always',
|
||||||
|
'antialiased',
|
||||||
|
'appworkspace',
|
||||||
|
'asterisks',
|
||||||
|
'attr',
|
||||||
|
'auto',
|
||||||
|
'auto-flow',
|
||||||
|
'avoid',
|
||||||
|
'avoid-column',
|
||||||
|
'avoid-page',
|
||||||
|
'avoid-region',
|
||||||
|
'axis-pan',
|
||||||
|
'background',
|
||||||
|
'backwards',
|
||||||
|
'baseline',
|
||||||
|
'below',
|
||||||
|
'bidi-override',
|
||||||
|
'blink',
|
||||||
|
'block',
|
||||||
|
'block-axis',
|
||||||
|
'bold',
|
||||||
|
'bolder',
|
||||||
|
'border',
|
||||||
|
'border-box',
|
||||||
|
'both',
|
||||||
|
'bottom',
|
||||||
|
'break',
|
||||||
|
'break-all',
|
||||||
|
'break-word',
|
||||||
|
'bullets',
|
||||||
|
'button',
|
||||||
|
'button-bevel',
|
||||||
|
'buttonface',
|
||||||
|
'buttonhighlight',
|
||||||
|
'buttonshadow',
|
||||||
|
'buttontext',
|
||||||
|
'calc',
|
||||||
|
'capitalize',
|
||||||
|
'caps-lock-indicator',
|
||||||
|
'caption',
|
||||||
|
'captiontext',
|
||||||
|
'caret',
|
||||||
|
'cell',
|
||||||
|
'center',
|
||||||
|
'checkbox',
|
||||||
|
'circle',
|
||||||
|
'cjk-decimal',
|
||||||
|
'clear',
|
||||||
|
'clip',
|
||||||
|
'close-quote',
|
||||||
|
'col-resize',
|
||||||
|
'collapse',
|
||||||
|
'color',
|
||||||
|
'color-burn',
|
||||||
|
'color-dodge',
|
||||||
|
'column',
|
||||||
|
'column-reverse',
|
||||||
|
'compact',
|
||||||
|
'condensed',
|
||||||
|
'contain',
|
||||||
|
'content',
|
||||||
|
'contents',
|
||||||
|
'content-box',
|
||||||
|
'context-menu',
|
||||||
|
'continuous',
|
||||||
|
'copy',
|
||||||
|
'counter',
|
||||||
|
'counters',
|
||||||
|
'cover',
|
||||||
|
'crop',
|
||||||
|
'cross',
|
||||||
|
'crosshair',
|
||||||
|
'currentcolor',
|
||||||
|
'cursive',
|
||||||
|
'cyclic',
|
||||||
|
'darken',
|
||||||
|
'dashed',
|
||||||
|
'decimal',
|
||||||
|
'decimal-leading-zero',
|
||||||
|
'default',
|
||||||
|
'default-button',
|
||||||
|
'dense',
|
||||||
|
'destination-atop',
|
||||||
|
'destination-in',
|
||||||
|
'destination-out',
|
||||||
|
'destination-over',
|
||||||
|
'difference',
|
||||||
|
'disc',
|
||||||
|
'discard',
|
||||||
|
'disclosure-closed',
|
||||||
|
'disclosure-open',
|
||||||
|
'document',
|
||||||
|
'dot-dash',
|
||||||
|
'dot-dot-dash',
|
||||||
|
'dotted',
|
||||||
|
'double',
|
||||||
|
'down',
|
||||||
|
'e-resize',
|
||||||
|
'ease',
|
||||||
|
'ease-in',
|
||||||
|
'ease-in-out',
|
||||||
|
'ease-out',
|
||||||
|
'element',
|
||||||
|
'ellipse',
|
||||||
|
'ellipsis',
|
||||||
|
'embed',
|
||||||
|
'end',
|
||||||
|
'ethiopic-abegede-gez',
|
||||||
|
'ethiopic-halehame-aa-er',
|
||||||
|
'ethiopic-halehame-gez',
|
||||||
|
'ew-resize',
|
||||||
|
'exclusion',
|
||||||
|
'expanded',
|
||||||
|
'extends',
|
||||||
|
'extra-condensed',
|
||||||
|
'extra-expanded',
|
||||||
|
'fantasy',
|
||||||
|
'fast',
|
||||||
|
'fill',
|
||||||
|
'fill-box',
|
||||||
|
'fixed',
|
||||||
|
'flat',
|
||||||
|
'flex',
|
||||||
|
'flex-end',
|
||||||
|
'flex-start',
|
||||||
|
'footnotes',
|
||||||
|
'forwards',
|
||||||
|
'from',
|
||||||
|
'geometricPrecision',
|
||||||
|
'graytext',
|
||||||
|
'grid',
|
||||||
|
'groove',
|
||||||
|
'hand',
|
||||||
|
'hard-light',
|
||||||
|
'help',
|
||||||
|
'hidden',
|
||||||
|
'hide',
|
||||||
|
'higher',
|
||||||
|
'highlight',
|
||||||
|
'highlighttext',
|
||||||
|
'horizontal',
|
||||||
|
'hsl',
|
||||||
|
'hsla',
|
||||||
|
'hue',
|
||||||
|
'icon',
|
||||||
|
'ignore',
|
||||||
|
'inactiveborder',
|
||||||
|
'inactivecaption',
|
||||||
|
'inactivecaptiontext',
|
||||||
|
'infinite',
|
||||||
|
'infobackground',
|
||||||
|
'infotext',
|
||||||
|
'inherit',
|
||||||
|
'initial',
|
||||||
|
'inline',
|
||||||
|
'inline-axis',
|
||||||
|
'inline-block',
|
||||||
|
'inline-flex',
|
||||||
|
'inline-grid',
|
||||||
|
'inline-table',
|
||||||
|
'inset',
|
||||||
|
'inside',
|
||||||
|
'intrinsic',
|
||||||
|
'invert',
|
||||||
|
'italic',
|
||||||
|
'justify',
|
||||||
|
'keep-all',
|
||||||
|
'landscape',
|
||||||
|
'large',
|
||||||
|
'larger',
|
||||||
|
'left',
|
||||||
|
'level',
|
||||||
|
'lighter',
|
||||||
|
'lighten',
|
||||||
|
'line-through',
|
||||||
|
'linear',
|
||||||
|
'linear-gradient',
|
||||||
|
'lines',
|
||||||
|
'list-item',
|
||||||
|
'listbox',
|
||||||
|
'listitem',
|
||||||
|
'local',
|
||||||
|
'logical',
|
||||||
|
'loud',
|
||||||
|
'lower',
|
||||||
|
'lower-hexadecimal',
|
||||||
|
'lower-latin',
|
||||||
|
'lower-norwegian',
|
||||||
|
'lowercase',
|
||||||
|
'ltr',
|
||||||
|
'luminosity',
|
||||||
|
'manipulation',
|
||||||
|
'match',
|
||||||
|
'matrix',
|
||||||
|
'matrix3d',
|
||||||
|
'medium',
|
||||||
|
'menu',
|
||||||
|
'menutext',
|
||||||
|
'message-box',
|
||||||
|
'middle',
|
||||||
|
'min-intrinsic',
|
||||||
|
'mix',
|
||||||
|
'monospace',
|
||||||
|
'move',
|
||||||
|
'multiple',
|
||||||
|
'multiple_mask_images',
|
||||||
|
'multiply',
|
||||||
|
'n-resize',
|
||||||
|
'narrower',
|
||||||
|
'ne-resize',
|
||||||
|
'nesw-resize',
|
||||||
|
'no-close-quote',
|
||||||
|
'no-drop',
|
||||||
|
'no-open-quote',
|
||||||
|
'no-repeat',
|
||||||
|
'none',
|
||||||
|
'normal',
|
||||||
|
'not-allowed',
|
||||||
|
'nowrap',
|
||||||
|
'ns-resize',
|
||||||
|
'numbers',
|
||||||
|
'numeric',
|
||||||
|
'nw-resize',
|
||||||
|
'nwse-resize',
|
||||||
|
'oblique',
|
||||||
|
'opacity',
|
||||||
|
'open-quote',
|
||||||
|
'optimizeLegibility',
|
||||||
|
'optimizeSpeed',
|
||||||
|
'outset',
|
||||||
|
'outside',
|
||||||
|
'outside-shape',
|
||||||
|
'overlay',
|
||||||
|
'overline',
|
||||||
|
'padding',
|
||||||
|
'padding-box',
|
||||||
|
'painted',
|
||||||
|
'page',
|
||||||
|
'paused',
|
||||||
|
'perspective',
|
||||||
|
'pinch-zoom',
|
||||||
|
'plus-darker',
|
||||||
|
'plus-lighter',
|
||||||
|
'pointer',
|
||||||
|
'polygon',
|
||||||
|
'portrait',
|
||||||
|
'pre',
|
||||||
|
'pre-line',
|
||||||
|
'pre-wrap',
|
||||||
|
'preserve-3d',
|
||||||
|
'progress',
|
||||||
|
'push-button',
|
||||||
|
'radial-gradient',
|
||||||
|
'radio',
|
||||||
|
'read-only',
|
||||||
|
'read-write',
|
||||||
|
'read-write-plaintext-only',
|
||||||
|
'rectangle',
|
||||||
|
'region',
|
||||||
|
'relative',
|
||||||
|
'repeat',
|
||||||
|
'repeating-linear-gradient',
|
||||||
|
'repeating-radial-gradient',
|
||||||
|
'repeat-x',
|
||||||
|
'repeat-y',
|
||||||
|
'reset',
|
||||||
|
'reverse',
|
||||||
|
'rgb',
|
||||||
|
'rgba',
|
||||||
|
'ridge',
|
||||||
|
'right',
|
||||||
|
'rotate',
|
||||||
|
'rotate3d',
|
||||||
|
'rotateX',
|
||||||
|
'rotateY',
|
||||||
|
'rotateZ',
|
||||||
|
'round',
|
||||||
|
'row',
|
||||||
|
'row-resize',
|
||||||
|
'row-reverse',
|
||||||
|
'rtl',
|
||||||
|
'run-in',
|
||||||
|
'running',
|
||||||
|
's-resize',
|
||||||
|
'sans-serif',
|
||||||
|
'saturation',
|
||||||
|
'scale',
|
||||||
|
'scale3d',
|
||||||
|
'scaleX',
|
||||||
|
'scaleY',
|
||||||
|
'scaleZ',
|
||||||
|
'screen',
|
||||||
|
'scroll',
|
||||||
|
'scrollbar',
|
||||||
|
'scroll-position',
|
||||||
|
'se-resize',
|
||||||
|
'self-start',
|
||||||
|
'self-end',
|
||||||
|
'semi-condensed',
|
||||||
|
'semi-expanded',
|
||||||
|
'separate',
|
||||||
|
'serif',
|
||||||
|
'show',
|
||||||
|
'single',
|
||||||
|
'skew',
|
||||||
|
'skewX',
|
||||||
|
'skewY',
|
||||||
|
'skip-white-space',
|
||||||
|
'slide',
|
||||||
|
'slider-horizontal',
|
||||||
|
'slider-vertical',
|
||||||
|
'sliderthumb-horizontal',
|
||||||
|
'sliderthumb-vertical',
|
||||||
|
'slow',
|
||||||
|
'small',
|
||||||
|
'small-caps',
|
||||||
|
'small-caption',
|
||||||
|
'smaller',
|
||||||
|
'soft-light',
|
||||||
|
'solid',
|
||||||
|
'source-atop',
|
||||||
|
'source-in',
|
||||||
|
'source-out',
|
||||||
|
'source-over',
|
||||||
|
'space',
|
||||||
|
'space-around',
|
||||||
|
'space-between',
|
||||||
|
'space-evenly',
|
||||||
|
'spell-out',
|
||||||
|
'square',
|
||||||
|
'start',
|
||||||
|
'static',
|
||||||
|
'status-bar',
|
||||||
|
'stretch',
|
||||||
|
'stroke',
|
||||||
|
'stroke-box',
|
||||||
|
'sub',
|
||||||
|
'subpixel-antialiased',
|
||||||
|
'svg_masks',
|
||||||
|
'super',
|
||||||
|
'sw-resize',
|
||||||
|
'symbolic',
|
||||||
|
'symbols',
|
||||||
|
'system-ui',
|
||||||
|
'table',
|
||||||
|
'table-caption',
|
||||||
|
'table-cell',
|
||||||
|
'table-column',
|
||||||
|
'table-column-group',
|
||||||
|
'table-footer-group',
|
||||||
|
'table-header-group',
|
||||||
|
'table-row',
|
||||||
|
'table-row-group',
|
||||||
|
'text',
|
||||||
|
'text-bottom',
|
||||||
|
'text-top',
|
||||||
|
'textarea',
|
||||||
|
'textfield',
|
||||||
|
'thick',
|
||||||
|
'thin',
|
||||||
|
'threeddarkshadow',
|
||||||
|
'threedface',
|
||||||
|
'threedhighlight',
|
||||||
|
'threedlightshadow',
|
||||||
|
'threedshadow',
|
||||||
|
'to',
|
||||||
|
'top',
|
||||||
|
'transform',
|
||||||
|
'translate',
|
||||||
|
'translate3d',
|
||||||
|
'translateX',
|
||||||
|
'translateY',
|
||||||
|
'translateZ',
|
||||||
|
'transparent',
|
||||||
|
'ultra-condensed',
|
||||||
|
'ultra-expanded',
|
||||||
|
'underline',
|
||||||
|
'unidirectional-pan',
|
||||||
|
'unset',
|
||||||
|
'up',
|
||||||
|
'upper-latin',
|
||||||
|
'uppercase',
|
||||||
|
'url',
|
||||||
|
'var',
|
||||||
|
'vertical',
|
||||||
|
'vertical-text',
|
||||||
|
'view-box',
|
||||||
|
'visible',
|
||||||
|
'visibleFill',
|
||||||
|
'visiblePainted',
|
||||||
|
'visibleStroke',
|
||||||
|
'visual',
|
||||||
|
'w-resize',
|
||||||
|
'wait',
|
||||||
|
'wave',
|
||||||
|
'wider',
|
||||||
|
'window',
|
||||||
|
'windowframe',
|
||||||
|
'windowtext',
|
||||||
|
'words',
|
||||||
|
'wrap',
|
||||||
|
'wrap-reverse',
|
||||||
|
'x-large',
|
||||||
|
'x-small',
|
||||||
|
'xor',
|
||||||
|
'xx-large',
|
||||||
|
'xx-small',
|
||||||
|
]
|
||||||
|
.map((name) => ({ label: name, type: 'text' }))
|
||||||
|
.concat(
|
||||||
|
[
|
||||||
|
'aliceblue',
|
||||||
|
'antiquewhite',
|
||||||
|
'aqua',
|
||||||
|
'aquamarine',
|
||||||
|
'azure',
|
||||||
|
'beige',
|
||||||
|
'bisque',
|
||||||
|
'black',
|
||||||
|
'blanchedalmond',
|
||||||
|
'blue',
|
||||||
|
'blueviolet',
|
||||||
|
'brown',
|
||||||
|
'burlywood',
|
||||||
|
'cadetblue',
|
||||||
|
'chartreuse',
|
||||||
|
'chocolate',
|
||||||
|
'coral',
|
||||||
|
'cornflowerblue',
|
||||||
|
'cornsilk',
|
||||||
|
'crimson',
|
||||||
|
'cyan',
|
||||||
|
'darkblue',
|
||||||
|
'darkcyan',
|
||||||
|
'darkgoldenrod',
|
||||||
|
'darkgray',
|
||||||
|
'darkgreen',
|
||||||
|
'darkkhaki',
|
||||||
|
'darkmagenta',
|
||||||
|
'darkolivegreen',
|
||||||
|
'darkorange',
|
||||||
|
'darkorchid',
|
||||||
|
'darkred',
|
||||||
|
'darksalmon',
|
||||||
|
'darkseagreen',
|
||||||
|
'darkslateblue',
|
||||||
|
'darkslategray',
|
||||||
|
'darkturquoise',
|
||||||
|
'darkviolet',
|
||||||
|
'deeppink',
|
||||||
|
'deepskyblue',
|
||||||
|
'dimgray',
|
||||||
|
'dodgerblue',
|
||||||
|
'firebrick',
|
||||||
|
'floralwhite',
|
||||||
|
'forestgreen',
|
||||||
|
'fuchsia',
|
||||||
|
'gainsboro',
|
||||||
|
'ghostwhite',
|
||||||
|
'gold',
|
||||||
|
'goldenrod',
|
||||||
|
'gray',
|
||||||
|
'grey',
|
||||||
|
'green',
|
||||||
|
'greenyellow',
|
||||||
|
'honeydew',
|
||||||
|
'hotpink',
|
||||||
|
'indianred',
|
||||||
|
'indigo',
|
||||||
|
'ivory',
|
||||||
|
'khaki',
|
||||||
|
'lavender',
|
||||||
|
'lavenderblush',
|
||||||
|
'lawngreen',
|
||||||
|
'lemonchiffon',
|
||||||
|
'lightblue',
|
||||||
|
'lightcoral',
|
||||||
|
'lightcyan',
|
||||||
|
'lightgoldenrodyellow',
|
||||||
|
'lightgray',
|
||||||
|
'lightgreen',
|
||||||
|
'lightpink',
|
||||||
|
'lightsalmon',
|
||||||
|
'lightseagreen',
|
||||||
|
'lightskyblue',
|
||||||
|
'lightslategray',
|
||||||
|
'lightsteelblue',
|
||||||
|
'lightyellow',
|
||||||
|
'lime',
|
||||||
|
'limegreen',
|
||||||
|
'linen',
|
||||||
|
'magenta',
|
||||||
|
'maroon',
|
||||||
|
'mediumaquamarine',
|
||||||
|
'mediumblue',
|
||||||
|
'mediumorchid',
|
||||||
|
'mediumpurple',
|
||||||
|
'mediumseagreen',
|
||||||
|
'mediumslateblue',
|
||||||
|
'mediumspringgreen',
|
||||||
|
'mediumturquoise',
|
||||||
|
'mediumvioletred',
|
||||||
|
'midnightblue',
|
||||||
|
'mintcream',
|
||||||
|
'mistyrose',
|
||||||
|
'moccasin',
|
||||||
|
'navajowhite',
|
||||||
|
'navy',
|
||||||
|
'oldlace',
|
||||||
|
'olive',
|
||||||
|
'olivedrab',
|
||||||
|
'orange',
|
||||||
|
'orangered',
|
||||||
|
'orchid',
|
||||||
|
'palegoldenrod',
|
||||||
|
'palegreen',
|
||||||
|
'paleturquoise',
|
||||||
|
'palevioletred',
|
||||||
|
'papayawhip',
|
||||||
|
'peachpuff',
|
||||||
|
'peru',
|
||||||
|
'pink',
|
||||||
|
'plum',
|
||||||
|
'powderblue',
|
||||||
|
'purple',
|
||||||
|
'rebeccapurple',
|
||||||
|
'red',
|
||||||
|
'rosybrown',
|
||||||
|
'royalblue',
|
||||||
|
'saddlebrown',
|
||||||
|
'salmon',
|
||||||
|
'sandybrown',
|
||||||
|
'seagreen',
|
||||||
|
'seashell',
|
||||||
|
'sienna',
|
||||||
|
'silver',
|
||||||
|
'skyblue',
|
||||||
|
'slateblue',
|
||||||
|
'slategray',
|
||||||
|
'snow',
|
||||||
|
'springgreen',
|
||||||
|
'steelblue',
|
||||||
|
'tan',
|
||||||
|
'teal',
|
||||||
|
'thistle',
|
||||||
|
'tomato',
|
||||||
|
'turquoise',
|
||||||
|
'violet',
|
||||||
|
'wheat',
|
||||||
|
'white',
|
||||||
|
'whitesmoke',
|
||||||
|
'yellow',
|
||||||
|
'yellowgreen',
|
||||||
|
].map((name) => ({ label: name, type: 'text' })),
|
||||||
|
);
|
||||||
@@ -12,6 +12,7 @@ const buttonStyle = css`
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--tango-colors-gray-50);
|
color: var(--tango-colors-gray-50);
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
.anticon-down {
|
.anticon-down {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
@@ -201,7 +202,8 @@ export function ToggleButton(props: ToggleButtonProps) {
|
|||||||
|
|
||||||
let btn = (
|
let btn = (
|
||||||
<Button css={buttonStyle} className={clazz} type="button" {...rest}>
|
<Button css={buttonStyle} className={clazz} type="button" {...rest}>
|
||||||
<Box as="span">
|
{/* @ts-ignore textOverflow is available */}
|
||||||
|
<Box as="span" flex="1" overflow="hidden" textOverflow="ellipsis">
|
||||||
{icon && (
|
{icon && (
|
||||||
<Box as="span" className="buttonIcon" mr="s">
|
<Box as="span" className="buttonIcon" mr="s">
|
||||||
{icon}
|
{icon}
|
||||||
|
|||||||
@@ -16195,10 +16195,10 @@ react-merge-refs@^1.1.0:
|
|||||||
resolved "https://registry.npmmirror.com/react-merge-refs/-/react-merge-refs-1.1.0.tgz"
|
resolved "https://registry.npmmirror.com/react-merge-refs/-/react-merge-refs-1.1.0.tgz"
|
||||||
integrity sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==
|
integrity sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==
|
||||||
|
|
||||||
react-monaco-editor-lite@^1.3.11:
|
react-monaco-editor-lite@^1.3.16:
|
||||||
version "1.3.11"
|
version "1.3.16"
|
||||||
resolved "https://registry.npmmirror.com/react-monaco-editor-lite/-/react-monaco-editor-lite-1.3.11.tgz#b81b681d23f3ca46f54d4e01f13781bcff6a4a03"
|
resolved "https://registry.npmmirror.com/react-monaco-editor-lite/-/react-monaco-editor-lite-1.3.16.tgz#066d744c7414df3b08b4cda65750057c2dd42f45"
|
||||||
integrity sha512-+9xlIn98Yp2hD8OFjRNpQiBx+wLFzsvvT5EgNTxReFrDhFAPPjivdLUCiex1ktzpkGTdo3fxDFUokckvO7hVvQ==
|
integrity sha512-FP3DeGZ709XEz+ZRQiQvw/yAa9fhjJm0989kv85o6f0dKcNBmb4gCADGZdZpoqbYBrT+7wIXBxvH1LQ2N2AodQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
monaco-editor "^0.38.0"
|
monaco-editor "^0.38.0"
|
||||||
monaco-editor-textmate "^4.0.0"
|
monaco-editor-textmate "^4.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user