amis 1.5.6-beta.4 → 1.5.6-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Schema.d.ts +1 -1
- package/lib/Schema.js.map +1 -1
- package/lib/components/AsideNav.d.ts +1 -1
- package/lib/components/AsideNav.js.map +1 -1
- package/lib/components/CodeMirror.d.ts +26 -0
- package/lib/components/CodeMirror.js +104 -0
- package/lib/components/CodeMirror.js.map +13 -0
- package/lib/components/Collapse.d.ts +22 -21
- package/lib/components/Collapse.js.map +2 -2
- package/lib/components/ColorPicker.d.ts +85 -84
- package/lib/components/ColorPicker.js +15 -3
- package/lib/components/ColorPicker.js.map +2 -2
- package/lib/components/DatePicker.js +7 -3
- package/lib/components/DatePicker.js.map +2 -2
- package/lib/components/DateRangePicker.d.ts +85 -84
- package/lib/components/DateRangePicker.js +5 -3
- package/lib/components/DateRangePicker.js.map +2 -2
- package/lib/components/MonthRangePicker.d.ts +85 -84
- package/lib/components/MonthRangePicker.js +5 -3
- package/lib/components/MonthRangePicker.js.map +2 -2
- package/lib/components/PickerContainer.d.ts +2 -1
- package/lib/components/PickerContainer.js +3 -3
- package/lib/components/PickerContainer.js.map +2 -2
- package/lib/components/PopUp.d.ts +93 -0
- package/lib/components/PopUp.js +58 -0
- package/lib/components/PopUp.js.map +13 -0
- package/lib/components/Steps.d.ts +1 -0
- package/lib/components/Steps.js +5 -3
- package/lib/components/Steps.js.map +2 -2
- package/lib/components/TabsTransferPicker.js +1 -1
- package/lib/components/TabsTransferPicker.js.map +2 -2
- package/lib/components/TransferPicker.d.ts +0 -1
- package/lib/components/TransferPicker.js +2 -15
- package/lib/components/TransferPicker.js.map +2 -2
- package/lib/components/formula/Editor.d.ts +560 -0
- package/lib/components/formula/Editor.js +186 -0
- package/lib/components/formula/Editor.js.map +13 -0
- package/lib/components/formula/FuncList.d.ts +67 -0
- package/lib/components/formula/FuncList.js +35 -0
- package/lib/components/formula/FuncList.js.map +13 -0
- package/lib/components/formula/Picker.d.ts +493 -0
- package/lib/components/formula/Picker.js +48 -0
- package/lib/components/formula/Picker.js.map +13 -0
- package/lib/components/formula/VariableList.d.ts +9 -0
- package/lib/components/formula/VariableList.js +15 -0
- package/lib/components/formula/VariableList.js.map +13 -0
- package/lib/components/formula/plugin.d.ts +18 -0
- package/lib/components/formula/plugin.js +136 -0
- package/lib/components/formula/plugin.js.map +13 -0
- package/lib/helper.css +57 -57
- package/lib/helper.css.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +2 -1
- package/lib/index.js.map +2 -2
- package/lib/renderers/Form/InputColor.d.ts +84 -84
- package/lib/renderers/Form/InputColor.js +2 -2
- package/lib/renderers/Form/InputColor.js.map +2 -2
- package/lib/renderers/Form/InputDate.js +2 -2
- package/lib/renderers/Form/InputDate.js.map +2 -2
- package/lib/renderers/Form/InputDateRange.js +2 -2
- package/lib/renderers/Form/InputDateRange.js.map +2 -2
- package/lib/renderers/Form/InputFormula.d.ts +35 -0
- package/lib/renderers/Form/InputFormula.js +25 -0
- package/lib/renderers/Form/InputFormula.js.map +13 -0
- package/lib/renderers/Form/InputMonthRange.js +2 -2
- package/lib/renderers/Form/InputMonthRange.js.map +2 -2
- package/lib/renderers/Form/InputQuarterRange.js +2 -2
- package/lib/renderers/Form/InputQuarterRange.js.map +2 -2
- package/lib/renderers/Form/InputYearRange.js +2 -2
- package/lib/renderers/Form/InputYearRange.js.map +2 -2
- package/lib/renderers/Form/TreeSelect.d.ts +1 -0
- package/lib/renderers/Form/TreeSelect.js +11 -8
- package/lib/renderers/Form/TreeSelect.js.map +2 -2
- package/lib/renderers/Steps.js +2 -2
- package/lib/renderers/Steps.js.map +2 -2
- package/lib/themes/ang-ie11.css +261 -0
- package/lib/themes/ang.css +261 -0
- package/lib/themes/ang.css.map +1 -1
- package/lib/themes/antd-ie11.css +261 -0
- package/lib/themes/antd.css +261 -0
- package/lib/themes/antd.css.map +1 -1
- package/lib/themes/cxd-ie11.css +261 -0
- package/lib/themes/cxd.css +261 -0
- package/lib/themes/cxd.css.map +1 -1
- package/lib/themes/dark-ie11.css +261 -0
- package/lib/themes/dark.css +261 -0
- package/lib/themes/dark.css.map +1 -1
- package/lib/themes/default.css +261 -0
- package/lib/themes/default.css.map +1 -1
- package/lib/utils/api.js +2 -2
- package/lib/utils/api.js.map +2 -2
- package/package.json +4 -2
- package/scss/_variables.scss +1 -1
- package/scss/components/_formula.scss +122 -0
- package/scss/components/_popup.scss +123 -0
- package/scss/components/_steps.scss +60 -0
- package/scss/components/form/_color.scss +4 -0
- package/scss/components/form/_date-range.scss +4 -0
- package/scss/components/form/_date.scss +3 -0
- package/scss/components/form/_tree-select.scss +4 -0
- package/scss/helper/background/_background-color.scss +1 -1
- package/scss/helper/border/_border-color.scss +1 -1
- package/scss/helper/typography/_text-color.scss +1 -1
- package/scss/themes/_common.scss +2 -0
- package/sdk/ang-ie11.css +875 -0
- package/sdk/ang.css +875 -0
- package/sdk/antd-ie11.css +875 -0
- package/sdk/antd.css +875 -0
- package/sdk/charts.js +15 -15
- package/sdk/codemirror.js +14 -0
- package/sdk/color-picker.js +65 -65
- package/sdk/cropperjs.js +2 -2
- package/sdk/cxd-ie11.css +875 -0
- package/sdk/cxd.css +875 -0
- package/sdk/dark-ie11.css +875 -0
- package/sdk/dark.css +875 -0
- package/sdk/exceljs.js +1 -1
- package/sdk/helper.css +57 -57
- package/sdk/helper.css.map +1 -1
- package/sdk/markdown.js +69 -69
- package/sdk/papaparse.js +1 -1
- package/sdk/renderers/Form/CityDB.js +1 -1
- package/sdk/rest.js +18 -18
- package/sdk/rich-text.js +62 -62
- package/sdk/sdk-ie11.css +875 -0
- package/sdk/sdk.css +875 -0
- package/sdk/sdk.js +1219 -1201
- package/sdk/thirds/hls.js/hls.js +1 -1
- package/sdk/thirds/mpegts.js/mpegts.js +1 -1
- package/sdk/tinymce.js +57 -57
- package/src/Schema.ts +1 -0
- package/src/components/AsideNav.tsx +1 -1
- package/src/components/CodeMirror.tsx +99 -0
- package/src/components/Collapse.tsx +2 -1
- package/src/components/ColorPicker.tsx +45 -3
- package/src/components/DatePicker.tsx +33 -3
- package/src/components/DateRangePicker.tsx +17 -3
- package/src/components/MonthRangePicker.tsx +18 -4
- package/src/components/PickerContainer.tsx +10 -6
- package/src/components/PopUp.tsx +133 -0
- package/src/components/Steps.tsx +8 -3
- package/src/components/TabsTransferPicker.tsx +1 -1
- package/src/components/TransferPicker.tsx +1 -11
- package/src/components/formula/Editor.tsx +261 -0
- package/src/components/formula/FuncList.tsx +82 -0
- package/src/components/formula/Picker.tsx +86 -0
- package/src/components/formula/VariableList.tsx +49 -0
- package/src/components/formula/plugin.ts +177 -0
- package/src/index.tsx +1 -0
- package/src/renderers/Form/InputColor.tsx +2 -3
- package/src/renderers/Form/InputDate.tsx +2 -0
- package/src/renderers/Form/InputDateRange.tsx +2 -0
- package/src/renderers/Form/InputFormula.tsx +75 -0
- package/src/renderers/Form/InputMonthRange.tsx +2 -0
- package/src/renderers/Form/InputQuarterRange.tsx +2 -0
- package/src/renderers/Form/InputYearRange.tsx +2 -0
- package/src/renderers/Form/TreeSelect.tsx +82 -63
- package/src/renderers/Steps.tsx +4 -2
- package/src/utils/api.ts +5 -2
@@ -0,0 +1,261 @@
|
|
1
|
+
/**
|
2
|
+
* @file 公式编辑器
|
3
|
+
*/
|
4
|
+
import React from 'react';
|
5
|
+
import {uncontrollable} from 'uncontrollable';
|
6
|
+
import {FormulaPlugin, editorFactory} from './plugin';
|
7
|
+
import {doc} from 'amis-formula/dist/doc';
|
8
|
+
import FuncList from './FuncList';
|
9
|
+
import {VariableList} from './VariableList';
|
10
|
+
import {parse} from 'amis-formula';
|
11
|
+
import {autobind} from '../../utils/helper';
|
12
|
+
import CodeMirrorEditor from '../CodeMirror';
|
13
|
+
import {themeable, ThemeProps} from '../../theme';
|
14
|
+
import {localeable, LocaleProps} from '../../locale';
|
15
|
+
|
16
|
+
export interface VariableItem {
|
17
|
+
label: string;
|
18
|
+
value?: string;
|
19
|
+
children?: Array<VariableItem>;
|
20
|
+
selectMode?: 'tree' | 'tabs';
|
21
|
+
}
|
22
|
+
|
23
|
+
export interface FuncGroup {
|
24
|
+
groupName: string;
|
25
|
+
items: Array<FuncItem>;
|
26
|
+
}
|
27
|
+
|
28
|
+
export interface FuncItem {
|
29
|
+
name: string;
|
30
|
+
[propName: string]: any;
|
31
|
+
}
|
32
|
+
|
33
|
+
export interface FormulaEditorProps extends ThemeProps, LocaleProps {
|
34
|
+
onChange?: (value: string) => void;
|
35
|
+
value: string;
|
36
|
+
/**
|
37
|
+
* evalMode 即直接就是表达式,否则
|
38
|
+
* 需要 ${这里面才是表达式}
|
39
|
+
* 默认为 true
|
40
|
+
*/
|
41
|
+
evalMode?: boolean;
|
42
|
+
|
43
|
+
/**
|
44
|
+
* 用于提示的变量集合,默认为空
|
45
|
+
*/
|
46
|
+
variables: Array<VariableItem>;
|
47
|
+
|
48
|
+
variableMode?: 'tabs' | 'tree';
|
49
|
+
|
50
|
+
/**
|
51
|
+
* 函数集合,默认不需要传,即 amis-formula 里面那个函数
|
52
|
+
* 如果有扩充,则需要传。
|
53
|
+
*/
|
54
|
+
functions: Array<FuncGroup>;
|
55
|
+
|
56
|
+
/**
|
57
|
+
* 顶部标题,默认为表达式
|
58
|
+
*/
|
59
|
+
header: string;
|
60
|
+
}
|
61
|
+
|
62
|
+
export interface FunctionsProps {
|
63
|
+
name: string;
|
64
|
+
items: FunctionProps[];
|
65
|
+
}
|
66
|
+
|
67
|
+
export interface FunctionProps {
|
68
|
+
name: string;
|
69
|
+
intro: string;
|
70
|
+
usage: string;
|
71
|
+
example: string;
|
72
|
+
}
|
73
|
+
|
74
|
+
export interface FormulaState {
|
75
|
+
focused: boolean;
|
76
|
+
}
|
77
|
+
|
78
|
+
export class FormulaEditor extends React.Component<
|
79
|
+
FormulaEditorProps,
|
80
|
+
FormulaState
|
81
|
+
> {
|
82
|
+
state: FormulaState = {
|
83
|
+
focused: false
|
84
|
+
};
|
85
|
+
editorPlugin?: FormulaPlugin;
|
86
|
+
|
87
|
+
static buildDefaultFunctions(
|
88
|
+
doc: Array<{
|
89
|
+
namespace: string;
|
90
|
+
name: string;
|
91
|
+
[propName: string]: any;
|
92
|
+
}>
|
93
|
+
) {
|
94
|
+
const funcs: Array<FuncGroup> = [];
|
95
|
+
|
96
|
+
doc.forEach(item => {
|
97
|
+
const namespace = item.namespace || 'Others';
|
98
|
+
let exists = funcs.find(item => item.groupName === namespace);
|
99
|
+
if (!exists) {
|
100
|
+
exists = {
|
101
|
+
groupName: namespace,
|
102
|
+
items: []
|
103
|
+
};
|
104
|
+
funcs.push(exists);
|
105
|
+
}
|
106
|
+
exists.items.push(item);
|
107
|
+
});
|
108
|
+
|
109
|
+
return funcs;
|
110
|
+
}
|
111
|
+
|
112
|
+
static defaultProps: Pick<
|
113
|
+
FormulaEditorProps,
|
114
|
+
'functions' | 'variables' | 'evalMode'
|
115
|
+
> = {
|
116
|
+
functions: this.buildDefaultFunctions(doc),
|
117
|
+
variables: [],
|
118
|
+
evalMode: true
|
119
|
+
};
|
120
|
+
|
121
|
+
static highlightValue(
|
122
|
+
value: string,
|
123
|
+
variables: Array<VariableItem>,
|
124
|
+
functions: Array<FuncGroup>
|
125
|
+
) {
|
126
|
+
// todo 高亮原始文本
|
127
|
+
return value;
|
128
|
+
}
|
129
|
+
|
130
|
+
componentWillUnmount() {
|
131
|
+
this.editorPlugin?.dispose();
|
132
|
+
}
|
133
|
+
|
134
|
+
@autobind
|
135
|
+
handleFocus() {
|
136
|
+
this.setState({
|
137
|
+
focused: true
|
138
|
+
});
|
139
|
+
}
|
140
|
+
|
141
|
+
@autobind
|
142
|
+
handleBlur() {
|
143
|
+
this.setState({
|
144
|
+
focused: false
|
145
|
+
});
|
146
|
+
}
|
147
|
+
|
148
|
+
@autobind
|
149
|
+
insertValue(value: any, type: 'variable' | 'func') {
|
150
|
+
this.editorPlugin?.insertContent(value, type);
|
151
|
+
}
|
152
|
+
|
153
|
+
@autobind
|
154
|
+
handleEditorMounted(cm: any, editor: any) {
|
155
|
+
this.editorPlugin = new FormulaPlugin(editor, cm, () => this.props);
|
156
|
+
}
|
157
|
+
|
158
|
+
@autobind
|
159
|
+
validate() {
|
160
|
+
const value = this.props.value;
|
161
|
+
|
162
|
+
try {
|
163
|
+
value
|
164
|
+
? parse(value, {
|
165
|
+
evalMode: this.props.evalMode
|
166
|
+
})
|
167
|
+
: null;
|
168
|
+
} catch (e) {
|
169
|
+
return e.message;
|
170
|
+
}
|
171
|
+
|
172
|
+
return;
|
173
|
+
}
|
174
|
+
|
175
|
+
@autobind
|
176
|
+
handleFunctionSelect(item: FuncItem) {
|
177
|
+
this.editorPlugin?.insertContent(`${item.name}`, 'func');
|
178
|
+
}
|
179
|
+
|
180
|
+
@autobind
|
181
|
+
handleVariableSelect(item: VariableItem) {
|
182
|
+
this.editorPlugin?.insertContent(
|
183
|
+
{
|
184
|
+
key: item.value,
|
185
|
+
name: item.label
|
186
|
+
},
|
187
|
+
'variable'
|
188
|
+
);
|
189
|
+
}
|
190
|
+
|
191
|
+
@autobind
|
192
|
+
handleOnChange(value: any) {
|
193
|
+
const onChange = this.props.onChange;
|
194
|
+
onChange?.(value);
|
195
|
+
}
|
196
|
+
|
197
|
+
@autobind
|
198
|
+
editorFactory(dom: HTMLElement, cm: any) {
|
199
|
+
return editorFactory(dom, cm, this.props);
|
200
|
+
}
|
201
|
+
|
202
|
+
render() {
|
203
|
+
const {
|
204
|
+
variables,
|
205
|
+
header,
|
206
|
+
value,
|
207
|
+
functions,
|
208
|
+
variableMode,
|
209
|
+
classnames: cx
|
210
|
+
} = this.props;
|
211
|
+
const {focused} = this.state;
|
212
|
+
|
213
|
+
return (
|
214
|
+
<div
|
215
|
+
className={cx(`FormulaEditor`, {
|
216
|
+
'is-focused': focused
|
217
|
+
})}
|
218
|
+
>
|
219
|
+
<div className={cx(`FormulaEditor-header`)}>{header ?? '表达式'}</div>
|
220
|
+
|
221
|
+
<CodeMirrorEditor
|
222
|
+
className={cx('FormulaEditor-editor')}
|
223
|
+
value={value}
|
224
|
+
onChange={this.handleOnChange}
|
225
|
+
editorFactory={this.editorFactory}
|
226
|
+
editorDidMount={this.handleEditorMounted}
|
227
|
+
onFocus={this.handleFocus}
|
228
|
+
onBlur={this.handleBlur}
|
229
|
+
></CodeMirrorEditor>
|
230
|
+
|
231
|
+
<div className={cx('FormulaEditor-settings')}>
|
232
|
+
{Array.isArray(functions) && functions.length ? (
|
233
|
+
<div>
|
234
|
+
<h3>变量</h3>
|
235
|
+
<VariableList
|
236
|
+
className={cx('VariableList')}
|
237
|
+
selectMode={variableMode}
|
238
|
+
data={variables}
|
239
|
+
onSelect={this.handleVariableSelect}
|
240
|
+
/>
|
241
|
+
</div>
|
242
|
+
) : null}
|
243
|
+
{Array.isArray(variables) && variables.length ? (
|
244
|
+
<div>
|
245
|
+
<h3>函数</h3>
|
246
|
+
<FuncList data={functions} onSelect={this.handleFunctionSelect} />
|
247
|
+
</div>
|
248
|
+
) : null}
|
249
|
+
</div>
|
250
|
+
</div>
|
251
|
+
);
|
252
|
+
}
|
253
|
+
}
|
254
|
+
|
255
|
+
export default uncontrollable(
|
256
|
+
themeable(localeable(FormulaEditor)),
|
257
|
+
{
|
258
|
+
value: 'onChange'
|
259
|
+
},
|
260
|
+
['validate']
|
261
|
+
);
|
@@ -0,0 +1,82 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import {themeable, ThemeProps} from '../../theme';
|
3
|
+
import Collapse from '../Collapse';
|
4
|
+
import CollapseGroup from '../CollapseGroup';
|
5
|
+
import SearchBox from '../SearchBox';
|
6
|
+
import type {FuncGroup, FuncItem} from './Editor';
|
7
|
+
|
8
|
+
export interface FuncListProps extends ThemeProps {
|
9
|
+
data: Array<FuncGroup>;
|
10
|
+
onSelect?: (item: FuncItem) => void;
|
11
|
+
}
|
12
|
+
|
13
|
+
export function FuncList(props: FuncListProps) {
|
14
|
+
const cx = props.classnames;
|
15
|
+
const [filteredFuncs, setFiteredFuncs] = React.useState(props.data);
|
16
|
+
const [activeFunc, setActiveFunc] = React.useState<any>(null);
|
17
|
+
function onSearch(term: string) {
|
18
|
+
const filtered = props.data
|
19
|
+
.map(item => {
|
20
|
+
return {
|
21
|
+
...item,
|
22
|
+
items: term
|
23
|
+
? item.items.filter(item => ~item.name.indexOf(term.toUpperCase()))
|
24
|
+
: item.items
|
25
|
+
};
|
26
|
+
})
|
27
|
+
.filter(item => item.items.length);
|
28
|
+
setFiteredFuncs(filtered);
|
29
|
+
}
|
30
|
+
|
31
|
+
return (
|
32
|
+
<div className={cx('FormulaFuncList')}>
|
33
|
+
<SearchBox
|
34
|
+
className="FormulaFuncList-searchBox"
|
35
|
+
mini={false}
|
36
|
+
onSearch={onSearch}
|
37
|
+
/>
|
38
|
+
<div className={cx('FormulaFuncList-columns')}>
|
39
|
+
<CollapseGroup
|
40
|
+
className="FormulaFuncList-group"
|
41
|
+
defaultActiveKey={filteredFuncs[0]?.groupName}
|
42
|
+
accordion
|
43
|
+
>
|
44
|
+
{filteredFuncs.map(item => (
|
45
|
+
<Collapse
|
46
|
+
headingClassName="FormulaFuncList-groupTitle"
|
47
|
+
bodyClassName="FormulaFuncList-groupBody"
|
48
|
+
propKey={item.groupName}
|
49
|
+
header={item.groupName}
|
50
|
+
key={item.groupName}
|
51
|
+
>
|
52
|
+
{item.items.map(item => (
|
53
|
+
<div
|
54
|
+
className={cx(
|
55
|
+
`FormulaFuncList-funcItem ${
|
56
|
+
item.name === activeFunc?.name ? 'is-active' : ''
|
57
|
+
}`
|
58
|
+
)}
|
59
|
+
onMouseEnter={() => setActiveFunc(item)}
|
60
|
+
onClick={() => props.onSelect?.(item)}
|
61
|
+
key={item.name}
|
62
|
+
>
|
63
|
+
{item.name}
|
64
|
+
</div>
|
65
|
+
))}
|
66
|
+
</Collapse>
|
67
|
+
))}
|
68
|
+
</CollapseGroup>
|
69
|
+
<div className={cx('FormulaFuncList-column')}>
|
70
|
+
{activeFunc ? (
|
71
|
+
<div className={cx('FormulaFuncList-funcDetail')}>
|
72
|
+
<p>{activeFunc.example}</p>
|
73
|
+
<div>{activeFunc.description}</div>
|
74
|
+
</div>
|
75
|
+
) : null}
|
76
|
+
</div>
|
77
|
+
</div>
|
78
|
+
</div>
|
79
|
+
);
|
80
|
+
}
|
81
|
+
|
82
|
+
export default themeable(FuncList);
|
@@ -0,0 +1,86 @@
|
|
1
|
+
import {uncontrollable} from 'uncontrollable';
|
2
|
+
import React from 'react';
|
3
|
+
import {FormulaEditor, FormulaEditorProps} from './Editor';
|
4
|
+
import {autobind} from '../../utils/helper';
|
5
|
+
import PickerContainer from '../PickerContainer';
|
6
|
+
import Editor from './Editor';
|
7
|
+
import ResultBox from '../ResultBox';
|
8
|
+
import {Icon} from '../icons';
|
9
|
+
import {themeable} from '../../theme';
|
10
|
+
import {localeable} from '../../locale';
|
11
|
+
|
12
|
+
export interface FormulaPickerProps extends FormulaEditorProps {
|
13
|
+
// 新的属性?
|
14
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
15
|
+
|
16
|
+
/**
|
17
|
+
* 边框模式,全边框,还是半边框,或者没边框。
|
18
|
+
*/
|
19
|
+
borderMode?: 'full' | 'half' | 'none';
|
20
|
+
|
21
|
+
disabled?: boolean;
|
22
|
+
}
|
23
|
+
|
24
|
+
export class FormulaPicker extends React.Component<FormulaPickerProps> {
|
25
|
+
@autobind
|
26
|
+
handleConfirm(value: any) {
|
27
|
+
this.props.onChange?.(value);
|
28
|
+
}
|
29
|
+
|
30
|
+
render() {
|
31
|
+
const {
|
32
|
+
classnames: cx,
|
33
|
+
value,
|
34
|
+
translate: __,
|
35
|
+
disabled,
|
36
|
+
className,
|
37
|
+
onChange,
|
38
|
+
size,
|
39
|
+
borderMode,
|
40
|
+
...rest
|
41
|
+
} = this.props;
|
42
|
+
|
43
|
+
return (
|
44
|
+
<PickerContainer
|
45
|
+
showTitle={false}
|
46
|
+
bodyRender={({onClose, value, onChange}) => {
|
47
|
+
return <Editor {...rest} value={value} onChange={onChange} />;
|
48
|
+
}}
|
49
|
+
value={value}
|
50
|
+
onConfirm={this.handleConfirm}
|
51
|
+
size={'md'}
|
52
|
+
>
|
53
|
+
{({onClick, isOpened}) => (
|
54
|
+
<ResultBox
|
55
|
+
className={cx(
|
56
|
+
'FormulaPicker',
|
57
|
+
className,
|
58
|
+
isOpened ? 'is-active' : ''
|
59
|
+
)}
|
60
|
+
allowInput={false}
|
61
|
+
result={FormulaEditor.highlightValue(
|
62
|
+
value,
|
63
|
+
rest.variables,
|
64
|
+
rest.functions
|
65
|
+
)}
|
66
|
+
onResultClick={onClick}
|
67
|
+
disabled={disabled}
|
68
|
+
borderMode={borderMode}
|
69
|
+
>
|
70
|
+
<span className={cx('FormulaPicker-icon')}>
|
71
|
+
<Icon icon="pencil" className="icon" />
|
72
|
+
</span>
|
73
|
+
</ResultBox>
|
74
|
+
)}
|
75
|
+
</PickerContainer>
|
76
|
+
);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
export default themeable(
|
81
|
+
localeable(
|
82
|
+
uncontrollable(FormulaPicker, {
|
83
|
+
value: 'onChange'
|
84
|
+
})
|
85
|
+
)
|
86
|
+
);
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import GroupedSelection from '../GroupedSelection';
|
3
|
+
import Tabs, {Tab} from '../Tabs';
|
4
|
+
import TreeSelection from '../TreeSelection';
|
5
|
+
import type {VariableItem} from './Editor';
|
6
|
+
|
7
|
+
export interface VariableListProps {
|
8
|
+
className?: string;
|
9
|
+
data: Array<VariableItem>;
|
10
|
+
selectMode?: 'list' | 'tree' | 'tabs';
|
11
|
+
onSelect?: (item: VariableItem) => void;
|
12
|
+
}
|
13
|
+
|
14
|
+
export function VariableList({
|
15
|
+
data: list,
|
16
|
+
className,
|
17
|
+
selectMode,
|
18
|
+
onSelect
|
19
|
+
}: VariableListProps) {
|
20
|
+
return (
|
21
|
+
<div className={className}>
|
22
|
+
{selectMode === 'tabs' ? (
|
23
|
+
<Tabs tabsMode="radio">
|
24
|
+
{list.map((item, index) => (
|
25
|
+
<Tab eventKey={index} key={index} title={item.label}>
|
26
|
+
<VariableList
|
27
|
+
selectMode={item.selectMode}
|
28
|
+
data={item.children!}
|
29
|
+
onSelect={onSelect}
|
30
|
+
/>
|
31
|
+
</Tab>
|
32
|
+
))}
|
33
|
+
</Tabs>
|
34
|
+
) : selectMode === 'tree' ? (
|
35
|
+
<TreeSelection
|
36
|
+
multiple={false}
|
37
|
+
options={list}
|
38
|
+
onChange={(item: any) => onSelect?.(item)}
|
39
|
+
/>
|
40
|
+
) : (
|
41
|
+
<GroupedSelection
|
42
|
+
multiple={false}
|
43
|
+
options={list}
|
44
|
+
onChange={(item: any) => onSelect?.(item)}
|
45
|
+
/>
|
46
|
+
)}
|
47
|
+
</div>
|
48
|
+
);
|
49
|
+
}
|
@@ -0,0 +1,177 @@
|
|
1
|
+
/**
|
2
|
+
* @file 扩展 codemirror
|
3
|
+
*/
|
4
|
+
|
5
|
+
import type CodeMirror from 'codemirror';
|
6
|
+
import {eachTree} from '../../utils/helper';
|
7
|
+
import type {FormulaEditorProps, VariableItem} from './Editor';
|
8
|
+
|
9
|
+
export function editorFactory(
|
10
|
+
dom: HTMLElement,
|
11
|
+
cm: typeof CodeMirror,
|
12
|
+
props: any
|
13
|
+
) {
|
14
|
+
registerLaunguageMode(cm);
|
15
|
+
|
16
|
+
console.log('here', props.evalMode);
|
17
|
+
|
18
|
+
return cm(dom, {
|
19
|
+
value: props.value || '',
|
20
|
+
autofocus: true,
|
21
|
+
mode: props.evalMode ? 'text/formula' : 'text/formula-template'
|
22
|
+
});
|
23
|
+
}
|
24
|
+
|
25
|
+
export class FormulaPlugin {
|
26
|
+
constructor(
|
27
|
+
readonly editor: CodeMirror.Editor,
|
28
|
+
readonly cm: typeof CodeMirror,
|
29
|
+
readonly getProps: () => FormulaEditorProps
|
30
|
+
) {
|
31
|
+
// editor.on('change', this.autoMarkText);
|
32
|
+
this.autoMarkText();
|
33
|
+
}
|
34
|
+
|
35
|
+
autoMarkText() {
|
36
|
+
const {functions, variables, value} = this.getProps();
|
37
|
+
if (value) {
|
38
|
+
// todo functions 也需要自动替换
|
39
|
+
this.autoMark(variables);
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
insertContent(value: any, type: 'variable' | 'func') {
|
44
|
+
const from = this.editor.getCursor();
|
45
|
+
if (type === 'variable') {
|
46
|
+
this.editor.replaceSelection(value.key);
|
47
|
+
var to = this.editor.getCursor();
|
48
|
+
|
49
|
+
this.markText(from, to, value.name, 'cm-field');
|
50
|
+
} else if (type === 'func') {
|
51
|
+
// todo 支持 snippet,目前是不支持的
|
52
|
+
|
53
|
+
this.editor.replaceSelection(`${value}()`);
|
54
|
+
var to = this.editor.getCursor();
|
55
|
+
this.markText(
|
56
|
+
from,
|
57
|
+
{
|
58
|
+
line: to.line,
|
59
|
+
ch: to.ch - 2
|
60
|
+
},
|
61
|
+
value,
|
62
|
+
'cm-func'
|
63
|
+
);
|
64
|
+
|
65
|
+
this.editor.setCursor({
|
66
|
+
line: to.line,
|
67
|
+
ch: to.ch - 1
|
68
|
+
});
|
69
|
+
} else if (typeof value === 'string') {
|
70
|
+
this.editor.replaceSelection(value);
|
71
|
+
}
|
72
|
+
|
73
|
+
this.editor.focus();
|
74
|
+
}
|
75
|
+
|
76
|
+
markText(
|
77
|
+
from: CodeMirror.Position,
|
78
|
+
to: CodeMirror.Position,
|
79
|
+
label: string,
|
80
|
+
className = 'cm-func'
|
81
|
+
) {
|
82
|
+
const text = document.createElement('span');
|
83
|
+
text.className = className;
|
84
|
+
text.innerText = label;
|
85
|
+
this.editor.markText(from, to, {
|
86
|
+
atomic: true,
|
87
|
+
replacedWith: text
|
88
|
+
});
|
89
|
+
}
|
90
|
+
|
91
|
+
autoMark(variables: Array<VariableItem>) {
|
92
|
+
if (!Array.isArray(variables) || !variables.length) {
|
93
|
+
return;
|
94
|
+
}
|
95
|
+
|
96
|
+
const varMap: {
|
97
|
+
[propname: string]: string;
|
98
|
+
} = {};
|
99
|
+
|
100
|
+
eachTree(
|
101
|
+
variables,
|
102
|
+
item => item.value && (varMap[item.value] = item.label)
|
103
|
+
);
|
104
|
+
const vars = Object.keys(varMap).sort((a, b) => b.length - a.length);
|
105
|
+
|
106
|
+
const editor = this.editor;
|
107
|
+
const lines = editor.lineCount();
|
108
|
+
for (let line = 0; line < lines; line++) {
|
109
|
+
const content = editor.getLine(line);
|
110
|
+
|
111
|
+
// 标记方法调用
|
112
|
+
content.replace(/([A-Z]+)\s*\(/g, (_, func, pos) => {
|
113
|
+
this.markText(
|
114
|
+
{
|
115
|
+
line: line,
|
116
|
+
ch: pos
|
117
|
+
},
|
118
|
+
{
|
119
|
+
line: line,
|
120
|
+
ch: pos + func.length
|
121
|
+
},
|
122
|
+
func,
|
123
|
+
'cm-func'
|
124
|
+
);
|
125
|
+
return _;
|
126
|
+
});
|
127
|
+
|
128
|
+
// 标记变量
|
129
|
+
vars.forEach(v => {
|
130
|
+
let from = 0;
|
131
|
+
let idx = -1;
|
132
|
+
while (~(idx = content.indexOf(v, from))) {
|
133
|
+
this.markText(
|
134
|
+
{
|
135
|
+
line: line,
|
136
|
+
ch: idx
|
137
|
+
},
|
138
|
+
{
|
139
|
+
line: line,
|
140
|
+
ch: idx + v.length
|
141
|
+
},
|
142
|
+
varMap[v],
|
143
|
+
'cm-field'
|
144
|
+
);
|
145
|
+
from = idx + v.length;
|
146
|
+
}
|
147
|
+
});
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
dispose() {}
|
152
|
+
|
153
|
+
validate() {}
|
154
|
+
}
|
155
|
+
|
156
|
+
let modeRegisted = false;
|
157
|
+
function registerLaunguageMode(cm: typeof CodeMirror) {
|
158
|
+
if (modeRegisted) {
|
159
|
+
return;
|
160
|
+
}
|
161
|
+
modeRegisted = true;
|
162
|
+
|
163
|
+
// 对应 evalMode
|
164
|
+
cm.defineMode('formula', (config: any, parserConfig: any) => {
|
165
|
+
var formula = cm.getMode(config, 'javascript');
|
166
|
+
if (!parserConfig || !parserConfig.base) return formula;
|
167
|
+
|
168
|
+
return cm.multiplexingMode(cm.getMode(config, parserConfig.base), {
|
169
|
+
open: '${',
|
170
|
+
close: '}',
|
171
|
+
mode: formula
|
172
|
+
});
|
173
|
+
});
|
174
|
+
|
175
|
+
cm.defineMIME('text/formula', {name: 'formula'});
|
176
|
+
cm.defineMIME('text/formula-template', {name: 'formula', base: 'htmlmixed'});
|
177
|
+
}
|
package/src/index.tsx
CHANGED
@@ -89,6 +89,7 @@ import './renderers/Form/Select';
|
|
89
89
|
import './renderers/Form/Static';
|
90
90
|
import './renderers/Form/InputDate';
|
91
91
|
import './renderers/Form/InputDateRange';
|
92
|
+
import './renderers/Form/InputFormula';
|
92
93
|
import './renderers/Form/InputRepeat';
|
93
94
|
import './renderers/Form/InputTree';
|
94
95
|
import './renderers/Form/TreeSelect';
|
@@ -68,12 +68,11 @@ export default class ColorControl extends React.PureComponent<
|
|
68
68
|
};
|
69
69
|
|
70
70
|
render() {
|
71
|
-
const {className, classPrefix: ns, value, ...rest} = this.props;
|
72
|
-
|
71
|
+
const {className, classPrefix: ns, value, env, ...rest} = this.props;
|
73
72
|
return (
|
74
73
|
<div className={cx(`${ns}ColorControl`, className)}>
|
75
74
|
<Suspense fallback={<div>...</div>}>
|
76
|
-
<ColorPicker classPrefix={ns} {...rest} value={value || ''} />
|
75
|
+
<ColorPicker classPrefix={ns} {...rest} value={value || ''} useMobileUI={env.useMobileUI}/>
|
77
76
|
</Suspense>
|
78
77
|
</div>
|
79
78
|
);
|
@@ -424,6 +424,7 @@ export default class DateControl extends React.PureComponent<
|
|
424
424
|
format,
|
425
425
|
timeFormat,
|
426
426
|
valueFormat,
|
427
|
+
env,
|
427
428
|
largeMode,
|
428
429
|
render,
|
429
430
|
...rest
|
@@ -441,6 +442,7 @@ export default class DateControl extends React.PureComponent<
|
|
441
442
|
format={valueFormat || format}
|
442
443
|
{...this.state}
|
443
444
|
classnames={cx}
|
445
|
+
useMobileUI={env.useMobileUI}
|
444
446
|
schedules={this.state.schedules}
|
445
447
|
largeMode={largeMode}
|
446
448
|
onScheduleClick={this.onScheduleClick.bind(this)}
|
@@ -172,6 +172,7 @@ export default class DateRangeControl extends React.Component<DateRangeProps> {
|
|
172
172
|
maxDuration,
|
173
173
|
data,
|
174
174
|
format,
|
175
|
+
env,
|
175
176
|
...rest
|
176
177
|
} = this.props;
|
177
178
|
|
@@ -186,6 +187,7 @@ export default class DateRangeControl extends React.Component<DateRangeProps> {
|
|
186
187
|
maxDate={maxDate ? filterDate(maxDate, data, format) : undefined}
|
187
188
|
minDuration={minDuration ? parseDuration(minDuration) : undefined}
|
188
189
|
maxDuration={maxDuration ? parseDuration(maxDuration) : undefined}
|
190
|
+
useMobileUI={env.useMobileUI}
|
189
191
|
/>
|
190
192
|
</div>
|
191
193
|
);
|