Merge pull request #10917 from 2betop/feat-async-renderer

feat: amis 渲染器支持异步,并且全部调整为异步
This commit is contained in:
hsm-lv 2024-09-18 10:52:38 +08:00 committed by GitHub
commit e382c8e805
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
63 changed files with 1361 additions and 356 deletions

View File

@ -7,15 +7,11 @@ import copy from 'copy-to-clipboard';
import {normalizeLink, supportsMjs} from 'amis-core';
import qs from 'qs';
import {
toast,
alert,
confirm,
ToastComponent,
AlertComponent,
render as renderAmis,
makeTranslator
} from 'amis';
import {alert, confirm} from 'amis-ui/lib/components/Alert';
import {toast, default as ToastComponent} from 'amis-ui/lib/components/Toast';
import AlertComponent from 'amis-ui/lib/components/Alert';
import {render as renderAmis, makeTranslator} from 'amis-core';
import 'amis/lib/minimal';
import 'amis-ui/lib/locale/en-US';
import 'history';

View File

@ -139,6 +139,7 @@
"\\.(svg)$": "<rootDir>/__mocks__/svgMock.js",
"\\.svg\\.js$": "<rootDir>/__mocks__/svgJsMock.js",
"^amis\\-ui$": "<rootDir>/packages/amis-ui/src/index.tsx",
"^amis\\-ui/lib/(.*)$": "<rootDir>/packages/amis-ui/src/$1",
"^amis\\-core$": "<rootDir>/packages/amis-core/src/index.tsx",
"^amis\\-formula$": "<rootDir>/packages/amis-formula/src/index.ts",
"^office\\-viewer$": "<rootDir>/packages/office-viewer/src/index.ts",

View File

@ -6,6 +6,7 @@ const originalDebug = console.warn.bind(console.debug);
const originalError = console.error.bind(console.error);
require('@testing-library/jest-dom');
require('moment-timezone');
const loadAllAsyncRenderers = require('amis-core').loadAllAsyncRenderers;
const moment = require('moment');
moment.tz.setDefault('Asia/Shanghai');
const cleanup = require('@testing-library/react').cleanup;
@ -13,16 +14,18 @@ const cleanup = require('@testing-library/react').cleanup;
// https://github.com/nrwl/nx/issues/1178
// 解决jest 运行的时候报:
// ReferenceError: DragEvent is not defined
Object.defineProperty(window, 'DragEvent', {
value: class DragEvent {}
});
if (!window.DragEvent) {
Object.defineProperty(window, 'DragEvent', {
value: class DragEvent {}
});
}
// Mock ResizeObserver in jest env
global.ResizeObserver = require('resize-observer-polyfill');
global.__buildVersion = '';
global.beforeAll(() => {
global.beforeAll(async () => {
console.warn =
console.groupCollapsed =
console.group =
@ -40,6 +43,8 @@ global.beforeAll(() => {
// }
// originalWarn(msg);
};
await loadAllAsyncRenderers();
});
global.afterAll(() => {
console.warn = originalWarn;

View File

@ -113,7 +113,8 @@ function transpileDynamicImportForCJS(options) {
return {
left: 'Promise.resolve().then(function() {return new Promise(function(fullfill) {require([',
right: '], function(mod) {fullfill(tslib.__importStar(mod))})})})'
right:
', "tslib"], function(mod, tslib) {fullfill(tslib.__importStar(mod))})})})'
};
// return {

View File

@ -4,7 +4,7 @@ import type {RootProps} from './Root';
import {IScopedContext, ScopedContext, filterTarget} from './Scoped';
import {IRootStore, RootStore} from './store/root';
import {ActionObject} from './types';
import {bulkBindFunctions, guid, isVisible} from './utils/helper';
import {bulkBindFunctions, guid, isVisible, JSONTraverse} from './utils/helper';
import {filter} from './utils/tpl';
import qs from 'qs';
import pick from 'lodash/pick';
@ -12,6 +12,8 @@ import mapValues from 'lodash/mapValues';
import {saveAs} from 'file-saver';
import {normalizeApi} from './utils/api';
import {findDOMNode} from 'react-dom';
import LazyComponent from './components/LazyComponent';
import {hasAsyncRenderers, loadAsyncRenderersByType} from './factory';
export interface RootRendererProps extends RootProps {
location?: any;
@ -46,6 +48,25 @@ export class RootRenderer extends React.Component<RootRendererProps> {
'handleDrawerClose',
'handlePageVisibilityChange'
]);
this.store.init(() => {
if (!hasAsyncRenderers()) {
return;
}
const schema = props.schema;
const types: Array<string> = ['tpl', 'dialog', 'drawer'];
JSONTraverse(schema, (value: any, key: string) => {
if (key === 'type') {
types.push(value);
// form 依赖 panel
if (value === 'form') {
types.push('panel');
}
}
});
return loadAsyncRenderersByType(types);
});
}
componentDidMount() {
@ -499,6 +520,8 @@ export class RootRenderer extends React.Component<RootRendererProps> {
if (store.runtimeError) {
return this.renderRuntimeError();
} else if (!store.ready) {
return <LazyComponent className="RootLoader" />;
}
return (

View File

@ -5,7 +5,9 @@ import {isValidElementType} from 'react-is';
import LazyComponent from './components/LazyComponent';
import {
filterSchema,
loadRenderer,
loadRendererError,
loadAsyncRenderer,
registerRenderer,
RendererConfig,
RendererEnv,
RendererProps,
@ -268,7 +270,7 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
const omitList = RENDERER_TRANSMISSION_OMIT_PROPS.concat();
if (this.renderer) {
const Component = this.renderer.component;
Component.propsList &&
Component?.propsList &&
omitList.push.apply(omitList, Component.propsList as Array<string>);
}
@ -402,8 +404,7 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
} else if (!this.renderer) {
return rest.invisible ? null : (
<LazyComponent
{...rest}
{...exprProps}
defaultVisible={true}
getComponent={async () => {
const result = await rest.env.loadRenderer(
schema,
@ -417,14 +418,20 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
}
this.reRender();
return () => loadRenderer(schema, $path);
return () => loadRendererError(schema, $path);
}}
/>
);
} else if (this.renderer.getComponent && !this.renderer.component) {
// 处理异步渲染器
return rest.invisible ? null : (
<LazyComponent
defaultVisible={true}
getComponent={async () => {
await loadAsyncRenderer(this.renderer as RendererConfig);
this.reRender();
return () => null;
}}
$path={$path}
$schema={schema}
retry={this.reRender}
rootStore={rootStore}
statusStore={statusStore}
dispatchEvent={this.dispatchEvent}
/>
);
}
@ -437,7 +444,7 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
activeKey: defaultActiveKey,
...restSchema
} = schema;
const Component = renderer.component;
const Component = renderer.component!;
// 原来表单项的 visible: false 和 hidden: true 表单项的值和验证是有效的
// 而 visibleOn 和 hiddenOn 是无效的,
@ -463,6 +470,7 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
Component.prototype?.isReactComponent ||
(Component as any).$$typeof === Symbol.for('react.forward_ref');
let props: any = {
...renderer.defaultProps?.(schema.type, schema),
...theme.getRendererConfig(renderer.name),
...restSchema,
...chainEvents(rest, restSchema),

View File

@ -6,13 +6,16 @@
import React from 'react';
import {InView} from 'react-intersection-observer';
import {themeable, ThemeProps} from '../theme';
export interface LazyComponentProps {
export interface LazyComponentProps extends ThemeProps {
component?: React.ElementType;
getComponent?: () => Promise<React.ElementType>;
placeholder?: React.ReactNode;
unMountOnHidden?: boolean;
childProps?: object;
defaultVisible?: boolean;
className?: string;
[propName: string]: any;
}
@ -21,7 +24,7 @@ export interface LazyComponentState {
component?: React.ElementType;
}
export default class LazyComponent extends React.Component<
export class LazyComponent extends React.Component<
LazyComponentProps,
LazyComponentState
> {
@ -39,14 +42,14 @@ export default class LazyComponent extends React.Component<
this.mounted = true;
this.state = {
visible: false,
visible: props.defaultVisible ?? false,
component: props.component as React.ElementType
};
}
componentDidMount() {
// jest 里面有点异常,先手动让它总是可见
if (typeof jest !== 'undefined') {
if (typeof jest !== 'undefined' || this.state.visible) {
this.handleVisibleChange(true);
}
}
@ -92,8 +95,10 @@ export default class LazyComponent extends React.Component<
childProps,
partialVisibility,
children,
className,
...rest
} = this.props;
const cx = this.props.classnames;
const {visible, component: Component} = this.state;
@ -144,6 +149,10 @@ export default class LazyComponent extends React.Component<
return children;
}
return <div>{placeholder}</div>;
return <div className={cx('LazyComponent', className)}>{placeholder}</div>;
}
}
const themedLazyComponent = themeable(LazyComponent);
(themedLazyComponent as any).defaultProps = LazyComponent.defaultProps;
export default themedLazyComponent;

View File

@ -45,8 +45,10 @@ export interface TestFunc {
export interface RendererBasicConfig {
test?: RegExp | TestFunc;
type?: string;
alias?: Array<string>; // 别名, 可以绑定多个类型,命中其中一个即可。
name?: string;
storeType?: string;
defaultProps?: (type: string, schema: any) => any;
shouldSyncSuperStore?: (
store: any,
props: any,
@ -99,8 +101,16 @@ export type RendererComponent = React.ComponentType<RendererProps> & {
};
export interface RendererConfig extends RendererBasicConfig {
component: RendererComponent;
Renderer?: RendererComponent; // 原始组件
// 渲染器组件,与 Renderer 的区别是,这个可能是包裹了 store 的。
component?: RendererComponent;
// 异步渲染器
getComponent?: () => Promise<{default: RendererComponent} | any>;
// 如果要替换系统渲染器,则需要设置这个为 true
override?: boolean;
// 原始组件
Renderer?: RendererComponent;
}
export interface RenderSchemaFilter {
@ -128,6 +138,10 @@ export interface RenderOptions
}
const renderers: Array<RendererConfig> = [];
// type 与 RendererConfig 的映射关系
const renderersTypeMap: {
[propName: string]: RendererConfig;
} = {};
export const renderersMap: {
[propName: string]: boolean;
} = {};
@ -159,65 +173,111 @@ export function Renderer(config: RendererBasicConfig) {
};
}
// 将 renderer 转成组件
function rendererToComponent(
component: RendererComponent,
config: RendererConfig
): RendererComponent {
if (config.storeType && config.component) {
component = HocStoreFactory({
storeType: config.storeType,
extendsData: config.storeExtendsData,
shouldSyncSuperStore: config.shouldSyncSuperStore
})(observer(component));
}
if (config.isolateScope) {
component = Scoped(component, config.type);
}
return component;
}
export function registerRenderer(config: RendererConfig): RendererConfig {
if (!config.test && !config.type) {
throw new TypeError('please set config.test or config.type');
} else if (!config.component) {
throw new TypeError('config.component is required');
throw new TypeError('please set config.type or config.test');
} else if (!config.type) {
console.warn(
`config.type is recommended for register renderer(${config.test})`
);
}
if (typeof config.type === 'string' && config.type) {
config.type = config.type.toLowerCase();
config.test =
config.test || new RegExp(`(^|\/)${string2regExp(config.type)}$`, 'i');
config.test ||
new RegExp(
`(^|\/)(?:${(config.alias || [])
.concat(config.type)
.map(type => string2regExp(type))
.join('|')})$`,
'i'
);
}
config.weight = config.weight || 0;
config.Renderer = config.component;
config.name = config.name || config.type || `anonymous-${anonymousIndex++}`;
if (renderersMap[config.name]) {
const exists = renderersTypeMap[config.type || ''];
let renderer = {...config};
if (
exists &&
exists.component &&
exists.component !== Placeholder &&
config.component &&
!config.override
) {
throw new Error(
`The renderer with name "${config.name}" has already exists, please try another name!`
`The renderer with type "${config.type}" has already exists, please try another type!`
);
} else if (renderersMap.hasOwnProperty(config.name)) {
// 面补充
const idx = findIndex(renderers, item => item.name === config.name);
~idx && renderers.splice(idx, 0, config);
} else if (exists) {
// 如果已经存在,合并配置,并用合并后的配置
Object.assign(exists, config);
renderer = exists;
}
if (config.storeType && config.component) {
config.component = HocStoreFactory({
storeType: config.storeType,
extendsData: config.storeExtendsData,
shouldSyncSuperStore: config.shouldSyncSuperStore
})(observer(config.component));
renderer.weight = renderer.weight || 0;
renderer.name =
renderer.name || renderer.type || `anonymous-${anonymousIndex++}`;
if (config.component) {
renderer.Renderer = config.component;
renderer.component = rendererToComponent(config.component, renderer);
}
if (config.isolateScope) {
config.component = Scoped(config.component, config.type);
if (!exists) {
const idx = findIndex(
renderers,
item => (config.weight as number) < item.weight
);
~idx ? renderers.splice(idx, 0, renderer) : renderers.push(renderer);
}
const idx = findIndex(
renderers,
item => (config.weight as number) < item.weight
renderersMap[renderer.name] = !!(
renderer.component && renderer.component !== Placeholder
);
~idx ? renderers.splice(idx, 0, config) : renderers.push(config);
renderersMap[config.name] = config.component !== Placeholder;
return config;
renderer.type && (renderersTypeMap[renderer.type] = renderer);
(renderer.alias || []).forEach(alias => (renderersTypeMap[alias] = renderer));
return renderer;
}
export function unRegisterRenderer(config: RendererConfig | string) {
const name = (typeof config === 'string' ? config : config.name)!;
const idx = renderers.findIndex(item => item.name === name);
~idx && renderers.splice(idx, 1);
delete renderersMap[name];
if (~idx) {
const renderer = renderers[idx];
renderers.splice(idx, 1);
// 清空渲染器定位缓存
cache = {};
delete renderersMap[name];
delete renderersTypeMap[renderer.type || ''];
renderer.alias?.forEach(alias => delete renderersTypeMap[alias]);
// 清空渲染器定位缓存
Object.keys(cache).forEach(key => {
const value = cache[key];
if (value === renderer) {
delete cache[key];
}
});
}
}
export function loadRenderer(schema: Schema, path: string) {
export function loadRendererError(schema: Schema, path: string) {
return (
<div className="RuntimeError">
<p>Error: </p>
@ -229,6 +289,65 @@ export function loadRenderer(schema: Schema, path: string) {
);
}
export async function loadAsyncRenderer(renderer: RendererConfig) {
if (!isAsyncRenderer(renderer)) {
// already loaded
return;
}
const result = await renderer.getComponent!();
// 如果异步加载的组件没有注册渲染器
// 同时默认导出了一个组件,则自动注册
if (!renderer.component && result.default) {
registerRenderer({
...renderer,
component: result.default
});
}
}
export function isAsyncRenderer(item: RendererConfig) {
return (
(!item.component || item.component === Placeholder) && item.getComponent
);
}
export function hasAsyncRenderers() {
return renderers.some(isAsyncRenderer);
}
export async function loadAsyncRenderersByType(
type: string | Array<string>,
ignore = false
) {
const types = Array.isArray(type) ? type : [type];
const asyncRenderers = types
.map(type => {
const renderer = renderersTypeMap[type];
if (!renderer && !ignore) {
throw new Error(`Can not find the renderer by type: ${type}`);
}
return renderer;
})
.filter(isAsyncRenderer);
if (asyncRenderers.length) {
await Promise.all(asyncRenderers.map(item => loadAsyncRenderer(item)));
}
}
export async function loadAllAsyncRenderers() {
const asyncRenderers = renderers.filter(isAsyncRenderer);
if (asyncRenderers.length) {
await Promise.all(
renderers.map(async renderer => {
await loadAsyncRenderer(renderer);
})
);
}
}
export const defaultOptions: RenderOptions = {
session: 'global',
richTextToken: '',
@ -237,7 +356,7 @@ export const defaultOptions: RenderOptions = {
(window as any).enableAMISDebug ??
location.search.indexOf('amisDebug=1') !== -1 ??
false,
loadRenderer,
loadRenderer: loadRendererError,
fetcher() {
return Promise.reject('fetcher is required');
},
@ -435,8 +554,9 @@ export function resolveRenderer(
): null | RendererConfig {
const type = typeof schema?.type == 'string' ? schema.type.toLowerCase() : '';
if (type && cache[type]) {
return cache[type];
// 直接匹配类型,后续注册渲染都应该用这个方式而不是之前的判断路径。
if (type && renderersTypeMap[type]) {
return renderersTypeMap[type];
} else if (cache[path]) {
return cache[path];
} else if (path && path.length > 3072) {
@ -448,15 +568,7 @@ export function resolveRenderer(
renderers.some(item => {
let matched = false;
// 直接匹配类型,后续注册渲染都应该用这个方式而不是之前的判断路径。
if (item.type && type) {
matched = item.type === type;
// 如果是type来命中的那么cache的key直接用 type 即可。
if (matched) {
cache[type] = item;
}
} else if (typeof item.test === 'function') {
if (typeof item.test === 'function') {
// 不应该搞得这么复杂的,让每个渲染器唯一 id自己不晕别人用起来也不晕。
matched = item.test(path, schema, resolveRenderer);
} else if (item.test instanceof RegExp) {

View File

@ -10,6 +10,9 @@ import {
Renderer,
getRendererByName,
getRenderers,
loadAllAsyncRenderers,
loadAsyncRenderersByType,
loadAsyncRenderer,
registerRenderer,
unRegisterRenderer,
resolveRenderer,
@ -21,7 +24,12 @@ import {
addSchemaFilter,
extendDefaultEnv
} from './factory';
import type {RenderOptions, RendererConfig, RendererProps} from './factory';
import type {
RenderOptions,
RendererConfig,
RendererProps,
hasAsyncRenderers
} from './factory';
import './polyfills';
import './renderers/builtin';
import './renderers/register';
@ -137,6 +145,10 @@ export {
registerRenderer,
unRegisterRenderer,
getRenderers,
loadAllAsyncRenderers,
loadAsyncRenderersByType,
loadAsyncRenderer,
hasAsyncRenderers,
registerFormItem,
getFormItemByName,
registerOptionsControl,

View File

@ -1,4 +1,4 @@
import {Instance, types} from 'mobx-state-tree';
import {flow, Instance, types} from 'mobx-state-tree';
import {parseQuery} from '../utils/helper';
import {ServiceStore} from './service';
import {
@ -11,7 +11,8 @@ export const RootStore = ServiceStore.named('RootStore')
.props({
runtimeError: types.frozen(),
runtimeErrorStack: types.frozen(),
query: types.frozen()
query: types.frozen(),
ready: false
})
.volatile(self => {
return {
@ -37,22 +38,37 @@ export const RootStore = ServiceStore.named('RootStore')
return result;
}
}))
.actions(self => ({
updateContext(context: any) {
// 因为 context 不是受控属性,直接共用引用好了
// 否则还会触发孩子节点的重新渲染
Object.assign(self.context, context);
},
setRuntimeError(error: any, errorStack: any) {
self.runtimeError = error;
self.runtimeErrorStack = errorStack;
},
updateLocation(location?: any, parseFn?: Function) {
const query = parseFn ? parseFn(location) : parseQuery(location);
if (isObjectShallowModified(query, self.query, false)) {
self.query = query;
.actions(self => {
const init: (schema: any) => Promise<any> = flow(function* init(
fn: () => Promise<any>
) {
try {
const ret: any = fn();
if (ret?.then) {
yield ret;
}
} finally {
self.ready = true;
}
}
}));
});
return {
updateContext(context: any) {
// 因为 context 不是受控属性,直接共用引用好了
// 否则还会触发孩子节点的重新渲染
Object.assign(self.context, context);
},
setRuntimeError(error: any, errorStack: any) {
self.runtimeError = error;
self.runtimeErrorStack = errorStack;
},
updateLocation(location?: any, parseFn?: Function) {
const query = parseFn ? parseFn(location) : parseQuery(location);
if (isObjectShallowModified(query, self.query, false)) {
self.query = query;
}
},
init: init
};
});
export type IRootStore = Instance<typeof RootStore>;

View File

@ -99,7 +99,7 @@ function transpileDynamicImportForCJS(options) {
return {
left: 'Promise.resolve().then(function() {return new Promise(function(fullfill) {require([',
right:
'], function(mod) {fullfill(require("tslib").__importStar(mod))})})})'
', "tslib"], function(mod, tslib) {fullfill(tslib.__importStar(mod))})})})'
};
// return {

View File

@ -63,9 +63,10 @@ export class CommonConfigWrapper extends NodeWrapper {
$$editor
);
}
const Component = renderer.component!;
return (
<renderer.component
<Component
{...rest}
store={store}
$schema={$schema}

View File

@ -63,9 +63,10 @@ export class FormConfigWrapper extends NodeWrapper {
$$editor
);
}
const Component = renderer.component!;
return (
<renderer.component
<Component
{...rest}
store={store}
$schema={$schema}

View File

@ -103,13 +103,14 @@ export class NodeWrapper extends React.Component<NodeWrapperProps> {
$$editor
);
}
const Component = renderer.component!;
const supportRef =
renderer.component.prototype?.isReactComponent ||
(renderer.component as any).$$typeof === Symbol.for('react.forward_ref');
Component.prototype?.isReactComponent ||
(Component as any).$$typeof === Symbol.for('react.forward_ref');
return (
<renderer.component
<Component
{...rest}
store={store}
{...$$node?.state}

View File

@ -1,4 +1,12 @@
import {render, toast, resolveRenderer, Modal, Icon, resizeSensor} from 'amis';
import {
render,
toast,
resolveRenderer,
Modal,
Icon,
resizeSensor,
Spinner
} from 'amis';
import React, {Component} from 'react';
import cx from 'classnames';
import {autobind, guid, noop, reactionWithOldValue} from '../util';
@ -553,7 +561,11 @@ export default class Preview extends Component<PreviewProps> {
ref={this.contentsRef}
>
<div className="ae-Preview-inner">
{isMobile ? (
{!store.ready ? (
<div className="ae-Preview-loading">
<Spinner overlay size="lg" />
</div>
) : isMobile ? (
<IFramePreview
{...rest}
key="mobile"

View File

@ -33,7 +33,7 @@ export function makeWrapper(
$$id: string;
};
const store = manager.store;
const renderer = rendererConfig.component;
const renderer = rendererConfig.component!;
@observer
class Wrapper extends React.Component<Props> {

View File

@ -70,6 +70,7 @@ import {VariableManager} from './variable';
import type {IScopedContext} from 'amis';
import type {SchemaObject, SchemaCollection} from 'amis';
import type {RendererConfig} from 'amis-core';
import {loadAsyncRenderer} from 'amis-core';
export interface EditorManagerConfig
extends Omit<EditorProps, 'value' | 'onChange'> {}
@ -1902,12 +1903,15 @@ export class EditorManager {
/**
* region hack
*/
hackRenderers(renderers = getRenderers()) {
async hackRenderers(renderers = getRenderers()) {
const toHackList: Array<{
renderer: RendererConfig;
regions?: Array<RegionConfig>;
overrides?: any;
}> = [];
await Promise.all(renderers.map(renderer => loadAsyncRenderer(renderer)));
renderers.forEach(renderer => {
const plugins = this.plugins.filter(
plugin =>
@ -1950,6 +1954,8 @@ export class EditorManager {
toHackList.forEach(({regions, renderer, overrides}) =>
this.hackIn(renderer, regions, overrides)
);
this.store.markReady();
}
/**

View File

@ -147,6 +147,7 @@ export type EditorModalBody = (DialogSchema | DrawerSchema) & {
export const MainStore = types
.model('EditorRoot', {
ready: false, // 异步组件加载前不可用
isMobile: false,
isSubEditor: false,
// 用于自定义爱速搭中的 amis 文档路径
@ -1100,6 +1101,9 @@ export const MainStore = types
});
return {
markReady() {
self.ready = true;
},
setLayer(value: any) {
layer = value;
},

View File

@ -24,7 +24,9 @@ const i18nConfig = require('./i18nConfig');
const settings = {
globals: {},
commonConfig: {
footer: `window.amisEditorVersionInfo={version:'${version}',buildTime:'${moment().format("YYYY-MM-DD")}'};`,
footer: `window.amisEditorVersionInfo={version:'${version}',buildTime:'${moment().format(
'YYYY-MM-DD'
)}'};`
}
};
@ -87,7 +89,7 @@ function transpileDynamicImportForCJS(options) {
return {
left: 'Promise.resolve().then(function() {return new Promise(function(fullfill) {require([',
right:
'], function(mod) {fullfill(require("tslib").__importStar(mod))})})})'
', "tslib"], function(mod, tslib) {fullfill(tslib.__importStar(mod))})})})'
};
// return {

View File

@ -82,7 +82,7 @@ function transpileDynamicImportForCJS(options) {
return {
left: 'Promise.resolve().then(function() {return new Promise(function(fullfill) {require([',
right:
'], function(mod) {fullfill(require("tslib").__importStar(mod))})})})'
', "tslib"], function(mod, tslib) {fullfill(tslib.__importStar(mod))})})})'
};
// return {

View File

@ -133,7 +133,8 @@ function transpileDynamicImportForCJS(options) {
return {
left: 'Promise.resolve().then(function() {return new Promise(function(fullfill) {require([',
right: '], function(mod) {fullfill(tslib.__importStar(mod))})})})'
right:
', "tslib"], function(mod, tslib) {fullfill(tslib.__importStar(mod))})})})'
};
// return {

View File

@ -200,3 +200,15 @@
z-index: -999;
opacity: 0;
}
.#{$ns}RootLoader {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.#{$ns}Spinner-icon {
width: var(--Spinner-width);
height: var(--Spinner-height);
}
}

View File

@ -0,0 +1,3 @@
import {AnchorNavSection} from './AnchorNav';
export default AnchorNavSection;

View File

@ -0,0 +1,2 @@
import {AutoSizer} from './virtual-list';
export default AutoSizer;

View File

@ -279,6 +279,8 @@ export class Badge extends React.Component<BadgeProps, object> {
}
}
export default Badge;
export function withBadge<P extends object>(Component: React.ComponentType<P>) {
return hoistNonReactStatic(
class WithBadge extends React.Component<P & BadgeProps> {

View File

@ -0,0 +1,3 @@
import ConditionBuilder from './condition-builder/index';
export default ConditionBuilder;

View File

@ -0,0 +1,2 @@
import FormulaPicker from './formula/Picker';
export default FormulaPicker;

View File

@ -0,0 +1,3 @@
import {GridNavItem} from './GridNav';
export default GridNavItem;

View File

@ -0,0 +1,2 @@
import HeadCellDropDown from './table/HeadCellDropDown';
export default HeadCellDropDown;

View File

@ -0,0 +1,3 @@
import Icon from './icons';
export default Icon;

View File

@ -0,0 +1,3 @@
import InputJSONSchema from './json-schema';
export default InputJSONSchema;

View File

@ -0,0 +1,3 @@
import JSONSchemaEditor from './schema-editor';
export default JSONSchemaEditor;

View File

@ -0,0 +1,3 @@
import {Tab} from './Tabs';
export default Tab;

View File

@ -0,0 +1,3 @@
import VirtualList from './virtual-list';
export default VirtualList;

View File

@ -71,3 +71,5 @@ export function withStore<K extends IAnyStateTreeNode>(
};
};
}
export default withStore;

View File

@ -467,6 +467,8 @@ export function Icon({
return <span className="text-danger"> icon {icon}</span>;
}
export default Icon;
export {
InputClearIcon,
CloseIcon,

View File

@ -27,7 +27,8 @@ import CollapseGroup from './CollapseGroup';
import DatePicker from './DatePicker';
import DateRangePicker from './DateRangePicker';
import Drawer from './Drawer';
import {default as Tabs, Tab} from './Tabs';
import Tabs from './Tabs';
import Tab from './Tab';
import Editor from './Editor';
import Html from './Html';
export * from './icons';
@ -60,7 +61,8 @@ import ListGroup from './ListGroup';
import NumberInput from './NumberInput';
import ArrayInput from './ArrayInput';
import SearchBox from './SearchBox';
import AnchorNav, {AnchorNavSection} from './AnchorNav';
import AnchorNav from './AnchorNav';
import AnchorNavSection from './AnchorNavSection';
import Selection from './Selection';
import GroupedSelection from './GroupedSelection';
import ChainedSelection from './ChainedSelection';
@ -72,18 +74,20 @@ import Table from './table';
import SchemaVariableListPicker from './schema-editor/SchemaVariableListPicker';
import SchemaVariableList from './schema-editor/SchemaVariableList';
import VariableList from './formula/VariableList';
import FormulaPicker from './formula/Picker';
import FormulaPicker from './FormulaPicker';
import {FormulaEditor} from './formula/Editor';
import FormulaCodeEditor from './formula/CodeEditor';
import type {VariableItem, FuncGroup} from './formula/CodeEditor';
import PickerContainer from './PickerContainer';
import InputJSONSchema from './json-schema';
import {Badge, withBadge} from './Badge';
import InputJSONSchema from './InputJSONSchema';
import Badge from './Badge';
import withBadge from './withBadge';
import type {BadgeObject} from './Badge';
import {getIcon, getIconNames, Icon, registerIcon} from './icons';
import {getIcon, getIconNames, registerIcon} from './icons';
import Icon from './Icon';
import {withRemoteConfig} from './WithRemoteConfig';
import type {RemoteOptionsProps} from './WithRemoteConfig';
import ConditionBuilder from './condition-builder';
import ConditionBuilder from './ConditionBuilder';
import type {
ConditionBuilderFields,
ConditionBuilderFuncs
@ -93,7 +97,7 @@ import CityArea from './CityArea';
import type {PresetColor} from './ColorPicker';
import ListMenu from './ListMenu';
import Input from './Input';
import JSONSchemaEditor from './schema-editor';
import JSONSchemaEditor from './JSONSchemaEditor';
import LocationPicker from './LocationPicker';
import PopUp from './PopUp';
import Cascader from './Cascader';
@ -103,13 +107,15 @@ import ResultList from './ResultList';
import TransferPicker from './TransferPicker';
import UserSelect from './UserSelect';
import UserTabSelect from './UserTabSelect';
import HeadCellDropDown from './table/HeadCellDropDown';
import HeadCellDropDown from './HeadCellDropDown';
import Card from './Card';
import GridNav, {GridNavItem} from './GridNav';
import GridNav from './GridNav';
import GridNavItem from './GridNavItem';
import type {GridNavDirection} from './GridNav';
import Link from './Link';
import VirtualList, {AutoSizer} from './virtual-list';
import {withStore} from './WithStore';
import VirtualList from './VirtualList';
import AutoSizer from './AutoSizer';
import withStore from './WithStore';
import PopOverContainer from './PopOverContainer';
import Pagination from './Pagination';
import Progress from './Progress';
@ -179,6 +185,7 @@ export {
Textarea,
TitleBar,
ToastComponent,
ToastComponent as Toast,
toast,
Tooltip,
TooltipWrapper,

View File

@ -0,0 +1,3 @@
import {withBadge} from './Badge';
export default withBadge;

View File

@ -11,5 +11,6 @@ import './themes/dark';
import './themes/default';
import type {SchemaEditorItemPlaceholder} from './components/schema-editor/Common';
import {schemaEditorItemPlaceholder} from './components/schema-editor/Common';
import withStore from './withStore';
export {schemaEditorItemPlaceholder, SchemaEditorItemPlaceholder};
export {schemaEditorItemPlaceholder, SchemaEditorItemPlaceholder, withStore};

View File

@ -0,0 +1,2 @@
import withStore from './components/WithStore';
export default withStore;

View File

@ -3,6 +3,7 @@
"compilerOptions": {
"rootDir": "./",
"outDir": "./lib",
"sourceRoot": "./",
"typeRoots": [
"../../types",
"./node_modules/@types",

View File

@ -1,5 +1,6 @@
import {waitFor} from '@testing-library/react';
import {RenderOptions} from '../src';
import '../src';
// jest.useFakeTimers 会修改 global 的 setTimeout 所以需要把原始的记录下来。
const timerFn = (global as any).originSetTimeout || setTimeout;

View File

@ -37,8 +37,8 @@
}
],
"dependencies": {
"amis-core": "^6.8.0",
"amis-ui": "^6.8.0",
"amis-core": "*",
"amis-ui": "*",
"attr-accept": "2.2.2",
"blueimp-canvastoblob": "2.1.0",
"classnames": "2.3.2",
@ -62,7 +62,7 @@
"moment": "^2.19.4",
"moment-timezone": "^0.5.34",
"mpegts.js": "^1.6.10",
"office-viewer": "^0.3.14",
"office-viewer": "*",
"prop-types": "^15.6.1",
"qrcode.react": "^3.1.0",
"react-cropper": "^2.1.8",
@ -110,6 +110,7 @@
"@types/sortablejs": "^1.3.32",
"@types/tinymce": "^4.5.24",
"axios": "0.25.0",
"babel-plugin-import": "^1.13.8",
"bce-sdk-js": "^0.2.9",
"concurrently": "^7.3.0",
"copy-to-clipboard": "3.3.1",
@ -140,6 +141,7 @@
"rimraf": "^3.0.2",
"rollup": "^2.79.1",
"rollup-plugin-auto-external": "^2.0.0",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-license": "^2.7.0",
"ts-jest": "^29.0.2",
"ts-json-schema-generator": "0.96.0",
@ -222,7 +224,9 @@
"\\.(css|less|sass|scss)$": "<rootDir>/../../__mocks__/styleMock.js",
"\\.(svg)$": "<rootDir>/../../__mocks__/svgMock.js",
"\\.svg\\.js$": "<rootDir>/../../__mocks__/svgJsMock.js",
"^amis\\-ui$": "<rootDir>/../amis-ui/src/index.tsx"
"^amis\\-core$": "<rootDir>/../amis-core/src/index.tsx",
"^amis\\-ui$": "<rootDir>/../amis-ui/src/index.tsx",
"^amis\\-ui/lib/(.*)$": "<rootDir>/../amis-ui/src/$1"
},
"setupFilesAfterEnv": [
"<rootDir>/../amis-core/__tests__/jest.setup.js"

View File

@ -16,11 +16,14 @@ import {
import path from 'path';
import svgr from '@svgr/rollup';
import moment from 'moment';
import babel from 'rollup-plugin-babel';
const settings = {
globals: {},
commonConfig: {
footer: `window.amisVersionInfo={version:'${version}',buildTime:'${moment().format("YYYY-MM-DD")}'};`,
footer: `window.amisVersionInfo={version:'${version}',buildTime:'${moment().format(
'YYYY-MM-DD'
)}'};`
}
};
@ -106,7 +109,8 @@ function transpileDynamicImportForCJS(options) {
return {
left: 'Promise.resolve().then(function() {return new Promise(function(fullfill) {require([',
right: '], function(mod) {fullfill(tslib.__importStar(mod))})})})'
right:
', "tslib"], function(mod, tslib) {fullfill(tslib.__importStar(mod))})})})'
};
// return {
@ -202,6 +206,39 @@ function getPlugins(format = 'esm') {
jsnext: true,
main: true
}),
format === 'esm'
? null
: babel({
exclude: 'node_modules/**',
extensions: ['.jsx', '.tsx', '.js', '.ts'],
plugins: [
[
'import',
{
libraryName: 'amis-ui',
libraryDirectory: 'lib',
camel2DashComponentName: false,
customName: (name, file) => {
if (
['alert', 'confirm', 'setRenderSchemaFn'].includes(name)
) {
return `amis-ui/lib/components/Alert`;
} else if (['toast'].includes(name)) {
return `amis-ui/lib/components/Toast`;
} else if ('NotFound' === name) {
return `amis-ui/lib/components/404`;
} else if ('withStore' === name) {
return `amis-ui/lib/${name}`;
} /* else if (name[0].toUpperCase() === name[0]) {
return `amis-ui/lib/components/${name}`;
}*/
return `amis-ui/lib/components/${name}`;
}
},
'amis-ui'
]
]
}),
typescript(typeScriptOptions),
commonjs({
sourceMap: false

View File

@ -7,159 +7,8 @@
*/
export * from 'amis-core';
export * from 'amis-ui';
import './minimal';
import './preset';
// 注册渲染器
import './renderers/Action';
import './renderers/Alert';
import './renderers/App';
import './renderers/Avatar';
import './renderers/Remark';
import './renderers/ButtonGroup';
import './renderers/Form/ButtonToolbar';
import './renderers/Breadcrumb';
import './renderers/DropDownButton';
import './renderers/Calendar';
import './renderers/Collapse';
import './renderers/CollapseGroup';
import './renderers/Color';
import './renderers/CRUD';
import './renderers/CRUD2';
import './renderers/Pagination';
import './renderers/Cards';
import './renderers/Card';
import './renderers/Card2';
import './renderers/Custom';
import './renderers/Date';
import './renderers/Dialog';
import './renderers/Divider';
import './renderers/Each';
import './renderers/Flex';
import './renderers/Form/Control';
import './renderers/Form/Hidden';
import './renderers/Form/InputText';
import './renderers/Form/InputTag';
import './renderers/Form/InputNumber';
import './renderers/Form/Textarea';
import './renderers/Form/Checkboxes';
import './renderers/Form/Checkbox';
import './renderers/Form/InputCity';
import './renderers/Form/ChartRadios';
import './renderers/Form/InputRating';
import './renderers/Form/Switch';
import './renderers/Form/Radios';
import './renderers/Form/Radio';
import './renderers/Form/JSONSchema';
import './renderers/Form/JSONSchemaEditor';
import './renderers/Form/ListSelect';
import './renderers/Form/LocationPicker';
import './renderers/Form/Select';
import './renderers/Form/Static';
import './renderers/Form/InputDate';
import './renderers/Form/InputDateRange';
import './renderers/Form/InputFormula';
import './renderers/Form/InputRepeat';
import './renderers/Form/InputTree';
import './renderers/Form/TreeSelect';
import './renderers/Form/InputImage';
import './renderers/Form/InputFile';
import './renderers/Form/UUID';
import './renderers/Form/MatrixCheckboxes';
import './renderers/Form/InputMonthRange';
import './renderers/Form/InputQuarterRange';
import './renderers/Form/InputYearRange';
import './renderers/Form/InputRange';
import './renderers/Form/InputArray';
import './renderers/Form/Combo';
import './renderers/Form/ConditionBuilder';
import './renderers/Form/InputSubForm';
import './renderers/Form/InputExcel';
import './renderers/Form/InputRichText';
import './renderers/Form/Editor';
import './renderers/Form/DiffEditor';
import './renderers/Form/InputColor';
import './renderers/Form/ChainedSelect';
import './renderers/Form/NestedSelect';
import './renderers/Form/Transfer';
import './renderers/Form/TransferPicker';
import './renderers/Form/InputTable';
import './renderers/Form/Picker';
import './renderers/Form/IconPicker';
import './renderers/Form/IconSelect';
import './renderers/Form/Formula';
import './renderers/Form/FieldSet';
import './renderers/Form/TabsTransfer';
import './renderers/Form/TabsTransferPicker';
import './renderers/Form/Group';
import './renderers/Form/InputGroup';
import './renderers/Form/UserSelect';
import './renderers/Form/InputSignature';
import './renderers/Form/InputVerificationCode';
import './renderers/Grid';
import './renderers/Grid2D';
import './renderers/HBox';
import './renderers/VBox';
import './renderers/Image';
import './renderers/Images';
import './renderers/List';
import './renderers/Log';
import './renderers/Operation';
import './renderers/Page';
import './renderers/PaginationWrapper';
import './renderers/Panel';
import './renderers/Plain';
import './renderers/Property';
import './renderers/Portlet';
import './renderers/Spinner';
import './renderers/Table/index';
import './renderers/Tabs';
import './renderers/Tpl';
import './renderers/Mapping';
import './renderers/Progress';
import './renderers/Status';
import './renderers/Json';
import './renderers/Link';
import './renderers/Wizard';
import './renderers/Chart';
import './renderers/Container';
import './renderers/SwitchContainer';
import './renderers/SearchBox';
import './renderers/Service';
import './renderers/SparkLine';
import './renderers/Video';
import './renderers/Audio';
import './renderers/Nav';
import './renderers/Number';
import './renderers/Tasks';
import './renderers/Drawer';
import './renderers/Wrapper';
import './renderers/IFrame';
import './renderers/BarCode';
import './renderers/QRCode';
import './renderers/Icon';
import './renderers/Carousel';
import './renderers/AnchorNav';
import './renderers/Steps';
import './renderers/Timeline';
import './renderers/Markdown';
import './renderers/TableView';
import './renderers/Code';
import './renderers/WebComponent';
import './renderers/GridNav';
import './renderers/TooltipWrapper';
import './renderers/Tag';
import './renderers/Table2/index';
import './renderers/Words';
import './renderers/Password';
import './renderers/DateRange';
import './renderers/MultilineText';
import './renderers/OfficeViewer';
import './renderers/PdfViewer';
import './renderers/AMIS';
import './compat';
import './schemaExtend';
import type {
BaseSchema,
FormSchema,

View File

@ -0,0 +1,822 @@
/**
* amis
*/
import {registerRenderer} from 'amis-core';
import './preset';
// 注册渲染器
// import './renderers/Action';
registerRenderer({
type: 'action',
alias: ['button', 'submit', 'reset'],
getComponent: () => import('./renderers/Action')
});
// import './renderers/Alert';
registerRenderer({
type: 'alert',
getComponent: () => import('./renderers/Alert')
});
// import './renderers/App';
registerRenderer({
type: 'app',
getComponent: () => import('./renderers/App')
});
// import './renderers/Avatar';
registerRenderer({
type: 'avatar',
getComponent: () => import('./renderers/Avatar')
});
// import './renderers/Remark';
registerRenderer({
type: 'remark',
getComponent: () => import('./renderers/Remark')
});
// import './renderers/ButtonGroup';
registerRenderer({
type: 'button-group',
getComponent: () => import('./renderers/ButtonGroup')
});
// import './renderers/Form/ButtonToolbar';
registerRenderer({
type: 'button-toolbar',
getComponent: () => import('./renderers/Form/ButtonToolbar')
});
// import './renderers/Breadcrumb';
registerRenderer({
type: 'breadcrumb',
getComponent: () => import('./renderers/Breadcrumb')
});
// import './renderers/DropDownButton';
registerRenderer({
type: 'dropdown-button',
getComponent: () => import('./renderers/DropDownButton')
});
// import './renderers/Calendar';
registerRenderer({
type: 'calendar',
getComponent: () => import('./renderers/Calendar')
});
// import './renderers/Collapse';
registerRenderer({
type: 'collapse',
getComponent: () => import('./renderers/Collapse')
});
// import './renderers/CollapseGroup';
registerRenderer({
type: 'collapse-group',
getComponent: () => import('./renderers/CollapseGroup')
});
// import './renderers/Color';
registerRenderer({
type: 'color',
getComponent: () => import('./renderers/Color')
});
// import './renderers/CRUD';
registerRenderer({
type: 'crud',
getComponent: () => import('./renderers/CRUD')
});
// import './renderers/CRUD2';
registerRenderer({
type: 'crud2',
getComponent: () => import('./renderers/CRUD2')
});
// import './renderers/Pagination';
registerRenderer({
type: 'pagination',
alias: ['pager'],
getComponent: () => import('./renderers/Pagination')
});
// import './renderers/Cards';
registerRenderer({
type: 'cards',
getComponent: () => import('./renderers/Cards')
});
// import './renderers/Card';
registerRenderer({
type: 'card',
getComponent: () => import('./renderers/Card')
});
// import './renderers/Card2';
registerRenderer({
type: 'card2',
getComponent: () => import('./renderers/Card2')
});
// import './renderers/Custom';
registerRenderer({
type: 'custom',
getComponent: () => import('./renderers/Custom')
});
// import './renderers/Date';
registerRenderer({
type: 'date',
getComponent: () => import('./renderers/Date')
});
registerRenderer({
type: 'datetime',
getComponent: () => import('./renderers/Date')
});
registerRenderer({
type: 'time',
getComponent: () => import('./renderers/Date')
});
registerRenderer({
type: 'month',
getComponent: () => import('./renderers/Date')
});
// import './renderers/Dialog';
registerRenderer({
type: 'dialog',
getComponent: () => import('./renderers/Dialog')
});
// import './renderers/Divider';
registerRenderer({
type: 'divider',
getComponent: () => import('./renderers/Divider')
});
// import './renderers/Each';
registerRenderer({
type: 'each',
getComponent: () => import('./renderers/Each')
});
// import './renderers/Flex';
registerRenderer({
type: 'flex',
getComponent: () => import('./renderers/Flex')
});
// import './renderers/Form/ButtonGroupSelect';
registerRenderer({
type: 'button-group-select',
getComponent: () => import('./renderers/Form/ButtonGroupSelect')
});
// import './renderers/Form/Control';
registerRenderer({
type: 'control',
getComponent: () => import('./renderers/Form/Control')
});
// import './renderers/Form/Hidden';
registerRenderer({
type: 'hidden',
getComponent: () => import('./renderers/Form/Hidden')
});
// import './renderers/Form/InputText';
registerRenderer({
type: 'input-text',
alias: ['input-password', 'native-date', 'native-time', 'native-number'],
getComponent: () => import('./renderers/Form/InputText')
});
registerRenderer({
type: 'input-email',
getComponent: () => import('./renderers/Form/InputText')
});
registerRenderer({
type: 'input-url',
getComponent: () => import('./renderers/Form/InputText')
});
// import './renderers/Form/InputTag';
registerRenderer({
type: 'input-tag',
getComponent: () => import('./renderers/Form/InputTag')
});
// import './renderers/Form/InputNumber';
registerRenderer({
type: 'input-number',
getComponent: () => import('./renderers/Form/InputNumber')
});
// import './renderers/Form/Textarea';
registerRenderer({
type: 'textarea',
getComponent: () => import('./renderers/Form/Textarea')
});
// import './renderers/Form/Checkboxes';
registerRenderer({
type: 'checkboxes',
getComponent: () => import('./renderers/Form/Checkboxes')
});
// import './renderers/Form/Checkbox';
registerRenderer({
type: 'checkbox',
getComponent: () => import('./renderers/Form/Checkbox')
});
// import './renderers/Form/InputCity';
registerRenderer({
type: 'input-city',
getComponent: () => import('./renderers/Form/InputCity')
});
// import './renderers/Form/ChartRadios';
registerRenderer({
type: 'chart-radios',
getComponent: () => import('./renderers/Form/ChartRadios')
});
// import './renderers/Form/InputRating';
registerRenderer({
type: 'input-rating',
getComponent: () => import('./renderers/Form/InputRating')
});
// import './renderers/Form/Switch';
registerRenderer({
type: 'switch',
getComponent: () => import('./renderers/Form/Switch')
});
// import './renderers/Form/Radios';
registerRenderer({
type: 'radios',
getComponent: () => import('./renderers/Form/Radios')
});
// import './renderers/Form/Radio';
registerRenderer({
type: 'radio',
getComponent: () => import('./renderers/Form/Radio')
});
// import './renderers/Form/JSONSchema';
registerRenderer({
type: 'json-schema',
getComponent: () => import('./renderers/Form/JSONSchema')
});
// import './renderers/Form/JSONSchemaEditor';
registerRenderer({
type: 'json-schema-editor',
getComponent: () => import('./renderers/Form/JSONSchemaEditor')
});
// import './renderers/Form/ListSelect';
registerRenderer({
type: 'list-select',
getComponent: () => import('./renderers/Form/ListSelect')
});
// import './renderers/Form/LocationPicker';
registerRenderer({
type: 'location-picker',
getComponent: () => import('./renderers/Form/LocationPicker')
});
// import './renderers/Form/Select';
registerRenderer({
type: 'select',
getComponent: () => import('./renderers/Form/Select')
});
registerRenderer({
type: 'multi-select',
getComponent: () => import('./renderers/Form/Select')
});
import './renderers/Form/Static';
// import './renderers/Form/InputDate';
registerRenderer({
type: 'input-date',
getComponent: () => import('./renderers/Form/InputDate')
});
registerRenderer({
type: 'input-datetime',
getComponent: () => import('./renderers/Form/InputDate')
});
registerRenderer({
type: 'input-time',
getComponent: () => import('./renderers/Form/InputDate')
});
registerRenderer({
type: 'input-month',
getComponent: () => import('./renderers/Form/InputDate')
});
registerRenderer({
type: 'input-quarter',
getComponent: () => import('./renderers/Form/InputDate')
});
registerRenderer({
type: 'input-year',
getComponent: () => import('./renderers/Form/InputDate')
});
// import './renderers/Form/InputDateRange';
registerRenderer({
type: 'input-date-range',
getComponent: () => import('./renderers/Form/InputDateRange')
});
registerRenderer({
type: 'input-datetime-range',
getComponent: () => import('./renderers/Form/InputDateRange')
});
registerRenderer({
type: 'input-time-range',
getComponent: () => import('./renderers/Form/InputDateRange')
});
// import './renderers/Form/InputFormula';
registerRenderer({
type: 'input-formula',
getComponent: () => import('./renderers/Form/InputFormula')
});
// import './renderers/Form/InputRepeat';
registerRenderer({
type: 'input-repeat',
getComponent: () => import('./renderers/Form/InputRepeat')
});
// import './renderers/Form/InputTree';
registerRenderer({
type: 'input-tree',
getComponent: () => import('./renderers/Form/InputTree')
});
// import './renderers/Form/TreeSelect';
registerRenderer({
type: 'tree-select',
getComponent: () => import('./renderers/Form/TreeSelect')
});
// import './renderers/Form/InputImage';
registerRenderer({
type: 'input-image',
getComponent: () => import('./renderers/Form/InputImage')
});
// import './renderers/Form/InputFile';
registerRenderer({
type: 'input-file',
getComponent: () => import('./renderers/Form/InputFile')
});
// import './renderers/Form/UUID';
registerRenderer({
type: 'uuid',
getComponent: () => import('./renderers/Form/UUID')
});
// import './renderers/Form/MatrixCheckboxes';
registerRenderer({
type: 'matrix-checkboxes',
getComponent: () => import('./renderers/Form/MatrixCheckboxes')
});
// import './renderers/Form/InputMonthRange';
registerRenderer({
type: 'input-month-range',
getComponent: () => import('./renderers/Form/InputMonthRange')
});
// import './renderers/Form/InputQuarterRange';
registerRenderer({
type: 'input-quarter-range',
getComponent: () => import('./renderers/Form/InputQuarterRange')
});
// import './renderers/Form/InputYearRange';
registerRenderer({
type: 'input-year-range',
getComponent: () => import('./renderers/Form/InputYearRange')
});
// import './renderers/Form/InputRange';
registerRenderer({
type: 'input-range',
getComponent: () => import('./renderers/Form/InputRange')
});
// import './renderers/Form/InputArray';
registerRenderer({
type: 'input-array',
getComponent: () => import('./renderers/Form/InputArray')
});
// import './renderers/Form/Combo';
registerRenderer({
type: 'combo',
getComponent: () => import('./renderers/Form/Combo')
});
registerRenderer({
type: 'input-kv',
getComponent: () => import('./renderers/Form/Combo')
});
registerRenderer({
type: 'input-kvs',
getComponent: () => import('./renderers/Form/Combo')
});
// import './renderers/Form/ConditionBuilder';
registerRenderer({
type: 'condition-builder',
getComponent: () => import('./renderers/Form/ConditionBuilder')
});
// import './renderers/Form/InputSubForm';
registerRenderer({
type: 'input-sub-form',
getComponent: () => import('./renderers/Form/InputSubForm')
});
// import './renderers/Form/InputExcel';
registerRenderer({
type: 'input-excel',
getComponent: () => import('./renderers/Form/InputExcel')
});
// import './renderers/Form/InputRichText';
registerRenderer({
type: 'input-rich-text',
getComponent: () => import('./renderers/Form/InputRichText')
});
import './renderers/Form/Editor';
// registerRenderer({
// type: 'input-rich-text',
// getComponent: () => import('./renderers/Form/Editor')
// });
// import './renderers/Form/DiffEditor';
registerRenderer({
type: 'diff-editor',
getComponent: () => import('./renderers/Form/DiffEditor')
});
// import './renderers/Form/InputColor';
registerRenderer({
type: 'input-color',
getComponent: () => import('./renderers/Form/InputColor')
});
// import './renderers/Form/ChainedSelect';
registerRenderer({
type: 'chained-select',
getComponent: () => import('./renderers/Form/ChainedSelect')
});
// import './renderers/Form/NestedSelect';
registerRenderer({
type: 'nested-select',
getComponent: () => import('./renderers/Form/NestedSelect')
});
// import './renderers/Form/Transfer';
registerRenderer({
type: 'transfer',
getComponent: () => import('./renderers/Form/Transfer')
});
// import './renderers/Form/TransferPicker';
registerRenderer({
type: 'transfer-picker',
getComponent: () => import('./renderers/Form/TransferPicker')
});
// import './renderers/Form/InputTable';
registerRenderer({
type: 'input-table',
getComponent: () => import('./renderers/Form/InputTable')
});
// import './renderers/Form/Picker';
registerRenderer({
type: 'picker',
getComponent: () => import('./renderers/Form/Picker')
});
// import './renderers/Form/IconPicker';
registerRenderer({
type: 'icon-picker',
getComponent: () => import('./renderers/Form/IconPicker')
});
// import './renderers/Form/IconSelect';
registerRenderer({
type: 'icon-select',
getComponent: () => import('./renderers/Form/IconSelect')
});
// import './renderers/Form/Formula';
registerRenderer({
type: 'formula',
getComponent: () => import('./renderers/Form/Formula')
});
// import './renderers/Form/FieldSet';
registerRenderer({
type: 'fieldset',
getComponent: () => import('./renderers/Form/FieldSet')
});
// import './renderers/Form/TabsTransfer';
registerRenderer({
type: 'tabs-transfer',
getComponent: () => import('./renderers/Form/TabsTransfer')
});
// import './renderers/Form/TabsTransferPicker';
registerRenderer({
type: 'tabs-transfer-picker',
getComponent: () => import('./renderers/Form/TabsTransferPicker')
});
// import './renderers/Form/Group';
registerRenderer({
type: 'group',
getComponent: () => import('./renderers/Form/Group')
});
// import './renderers/Form/InputGroup';
registerRenderer({
type: 'input-group',
getComponent: () => import('./renderers/Form/InputGroup')
});
// import './renderers/Form/UserSelect';
registerRenderer({
type: 'users-select',
getComponent: () => import('./renderers/Form/UserSelect')
});
// import './renderers/Form/InputSignature';
registerRenderer({
type: 'input-signature',
getComponent: () => import('./renderers/Form/InputSignature')
});
// import './renderers/Form/InputVerificationCode';
registerRenderer({
type: 'input-verification-code',
getComponent: () => import('./renderers/Form/InputVerificationCode')
});
import './renderers/Grid';
// import './renderers/Grid2D';
registerRenderer({
type: 'grid-2d',
getComponent: () => import('./renderers/Grid2D')
});
// import './renderers/HBox';
registerRenderer({
type: 'hbox',
getComponent: () => import('./renderers/HBox')
});
// import './renderers/VBox';
registerRenderer({
type: 'vbox',
getComponent: () => import('./renderers/VBox')
});
// import './renderers/Image';
registerRenderer({
type: 'image',
getComponent: () => import('./renderers/Image')
});
// import './renderers/Images';
registerRenderer({
type: 'images',
getComponent: () => import('./renderers/Images')
});
// import './renderers/List';
registerRenderer({
type: 'list',
getComponent: () => import('./renderers/List')
});
// import './renderers/Log';
registerRenderer({
type: 'log',
getComponent: () => import('./renderers/Log')
});
// import './renderers/Operation';
registerRenderer({
type: 'operation',
getComponent: () => import('./renderers/Operation')
});
// import './renderers/Page';
registerRenderer({
type: 'page',
getComponent: () => import('./renderers/Page')
});
// import './renderers/PaginationWrapper';
registerRenderer({
type: 'pagination-wrapper',
getComponent: () => import('./renderers/PaginationWrapper')
});
// import './renderers/Panel';
registerRenderer({
type: 'panel',
getComponent: () => import('./renderers/Panel')
});
// import './renderers/Plain';
registerRenderer({
type: 'plain',
alias: ['text'],
getComponent: () => import('./renderers/Plain')
});
// import './renderers/Property';
registerRenderer({
type: 'property',
getComponent: () => import('./renderers/Property')
});
// import './renderers/Portlet';
registerRenderer({
type: 'portlet',
getComponent: () => import('./renderers/Portlet')
});
// import './renderers/Spinner';
registerRenderer({
type: 'spinner',
getComponent: () => import('./renderers/Spinner')
});
// import './renderers/Table/index';
registerRenderer({
type: 'table',
getComponent: () => import('./renderers/Table/index')
});
// import './renderers/Tabs';
registerRenderer({
type: 'tabs',
getComponent: () => import('./renderers/Tabs')
});
// import './renderers/Tpl';
registerRenderer({
type: 'tpl',
alias: ['html'],
getComponent: () => import('./renderers/Tpl')
});
// import './renderers/Mapping';
registerRenderer({
type: 'mapping',
alias: ['map'],
getComponent: () => import('./renderers/Mapping')
});
// import './renderers/Progress';
registerRenderer({
type: 'progress',
getComponent: () => import('./renderers/Progress')
});
// import './renderers/Status';
registerRenderer({
type: 'status',
getComponent: () => import('./renderers/Status')
});
// import './renderers/Json';
registerRenderer({
type: 'json',
getComponent: () => import('./renderers/Json')
});
// import './renderers/Link';
registerRenderer({
type: 'link',
getComponent: () => import('./renderers/Link')
});
// import './renderers/Wizard';
registerRenderer({
type: 'wizard',
getComponent: () => import('./renderers/Wizard')
});
// import './renderers/Chart';
registerRenderer({
type: 'chart',
getComponent: () => import('./renderers/Chart')
});
// import './renderers/Container';
registerRenderer({
type: 'container',
getComponent: () => import('./renderers/Container')
});
// import './renderers/SwitchContainer';
registerRenderer({
type: 'switch-container',
getComponent: () => import('./renderers/SwitchContainer')
});
// import './renderers/SearchBox';
registerRenderer({
type: 'search-box',
getComponent: () => import('./renderers/SearchBox')
});
// import './renderers/Service';
registerRenderer({
type: 'service',
getComponent: () => import('./renderers/Service')
});
// import './renderers/SparkLine';
registerRenderer({
type: 'sparkline',
getComponent: () => import('./renderers/SparkLine')
});
// import './renderers/Video';
registerRenderer({
type: 'video',
getComponent: () => import('./renderers/Video')
});
// import './renderers/Audio';
registerRenderer({
type: 'audio',
getComponent: () => import('./renderers/Audio')
});
// import './renderers/Nav';
registerRenderer({
type: 'nav',
alias: ['navigation'],
getComponent: () => import('./renderers/Nav')
});
// import './renderers/Number';
registerRenderer({
type: 'number',
getComponent: () => import('./renderers/Number')
});
// import './renderers/Tasks';
registerRenderer({
type: 'tasks',
getComponent: () => import('./renderers/Tasks')
});
// import './renderers/Drawer';
registerRenderer({
type: 'drawer',
getComponent: () => import('./renderers/Drawer')
});
// import './renderers/Wrapper';
registerRenderer({
type: 'wrapper',
getComponent: () => import('./renderers/Wrapper')
});
// import './renderers/IFrame';
registerRenderer({
type: 'iframe',
getComponent: () => import('./renderers/IFrame')
});
// import './renderers/BarCode';
registerRenderer({
type: 'barcode',
getComponent: () => import('./renderers/BarCode')
});
// import './renderers/QRCode';
registerRenderer({
type: 'qrcode',
alias: ['qr-code'],
getComponent: () => import('./renderers/QRCode')
});
// import './renderers/Icon';
registerRenderer({
type: 'icon',
getComponent: () => import('./renderers/Icon')
});
// import './renderers/Carousel';
registerRenderer({
type: 'carousel',
getComponent: () => import('./renderers/Carousel')
});
// import './renderers/AnchorNav';
registerRenderer({
type: 'anchor-nav',
getComponent: () => import('./renderers/AnchorNav')
});
// import './renderers/Steps';
registerRenderer({
type: 'steps',
getComponent: () => import('./renderers/Steps')
});
// import './renderers/Timeline';
registerRenderer({
type: 'timeline',
getComponent: () => import('./renderers/Timeline')
});
// import './renderers/Markdown';
registerRenderer({
type: 'markdown',
getComponent: () => import('./renderers/Markdown')
});
// import './renderers/TableView';
registerRenderer({
type: 'table-view',
getComponent: () => import('./renderers/TableView')
});
// import './renderers/Code';
registerRenderer({
type: 'code',
getComponent: () => import('./renderers/Code')
});
// import './renderers/WebComponent';
registerRenderer({
type: 'web-component',
getComponent: () => import('./renderers/WebComponent')
});
// import './renderers/GridNav';
registerRenderer({
type: 'grid-nav',
getComponent: () => import('./renderers/GridNav')
});
// import './renderers/TooltipWrapper';
registerRenderer({
type: 'tooltip-wrapper',
getComponent: () => import('./renderers/TooltipWrapper')
});
// import './renderers/Tag';
registerRenderer({
type: 'tag',
getComponent: () => import('./renderers/Tag')
});
// import './renderers/Table2/index';
registerRenderer({
type: 'table2',
getComponent: () => import('./renderers/Table2/index')
});
// import './renderers/Words';
registerRenderer({
type: 'words',
getComponent: () => import('./renderers/Words')
});
registerRenderer({
type: 'tags',
getComponent: () => import('./renderers/Words')
});
// import './renderers/Password';
registerRenderer({
type: 'password',
getComponent: () => import('./renderers/Password')
});
// import './renderers/DateRange';
registerRenderer({
type: 'date-range',
getComponent: () => import('./renderers/DateRange')
});
// import './renderers/MultilineText';
registerRenderer({
type: 'multiline-text',
getComponent: () => import('./renderers/MultilineText')
});
// import './renderers/OfficeViewer';
registerRenderer({
type: 'office-viewer',
getComponent: () => import('./renderers/OfficeViewer')
});
// import './renderers/PdfViewer';
registerRenderer({
type: 'pdf-viewer',
getComponent: () => import('./renderers/PdfViewer')
});
// import './renderers/AMIS';
registerRenderer({
type: 'amis',
getComponent: () => import('./renderers/AMIS')
});
import './compat';
import './schemaExtend';

View File

@ -6,8 +6,10 @@ import {
themeable,
ThemeProps
} from 'amis-core';
import {alert, confirm, setRenderSchemaFn, toast, ImageGallery} from 'amis-ui';
import {ImageGallery} from 'amis-ui';
import {setRenderSchemaFn} from 'amis-ui/lib/components/Alert';
import {alert, confirm} from 'amis-ui/lib/components/Alert';
import {toast} from 'amis-ui/lib/components/Toast';
import React from 'react';
extendDefaultEnv({
@ -68,6 +70,7 @@ const SimpleSpinner = themeable(
className={cx(
`Spinner-icon`,
'Spinner-icon--default',
'Spinner-icon--sm',
props.spinnerClassName
)}
></div>
@ -76,4 +79,4 @@ const SimpleSpinner = themeable(
}
);
LazyComponent.defaultProps.placeholder = <SimpleSpinner />;
(LazyComponent as any).defaultProps.placeholder = <SimpleSpinner />;

View File

@ -935,7 +935,8 @@ export type ActionRendererProps = RendererProps &
};
@Renderer({
type: 'action'
type: 'action',
alias: ['button', 'submit', 'reset']
})
// @ts-ignore 类型没搞定
@withBadge
@ -1089,18 +1090,3 @@ export class ActionRenderer extends React.Component<ActionRendererProps> {
);
}
}
@Renderer({
type: 'button'
})
export class ButtonRenderer extends ActionRenderer {}
@Renderer({
type: 'submit'
})
export class SubmitRenderer extends ActionRenderer {}
@Renderer({
type: 'reset'
})
export class ResetRenderer extends ActionRenderer {}

View File

@ -163,7 +163,7 @@ export interface AppProps
store: IAppStore;
}
export default class App extends React.Component<AppProps, object> {
export class App extends React.Component<AppProps, object> {
static propsList: Array<string> = [
'brandName',
'logo',
@ -549,7 +549,7 @@ export default class App extends React.Component<AppProps, object> {
type: 'app',
storeType: AppStore.name
})
export class AppRenderer extends App {
export default class AppRenderer extends App {
static contextType = ScopedContext;
constructor(props: AppProps, context: IScopedContext) {
super(props);

View File

@ -1083,8 +1083,8 @@ export default class Cards extends React.Component<GridProps, object> {
}
@Renderer({
test: /(^|\/)(?:crud\/body\/grid|cards)$/,
name: 'cards',
type: 'cards',
storeType: ListStore.name,
weight: -100 // 默认的 grid 不是这样,这个只识别 crud 下面的 grid
})

View File

@ -8,7 +8,7 @@ import {isPureVariable, resolveVariableAndFilter} from 'amis-core';
import type {
FuncGroup,
VariableItem
} from 'amis-ui/src/components/formula/CodeEditor';
} from 'amis-ui/lib/components/formula/CodeEditor';
import type {FormulaPickerInputSettings} from 'amis-ui/lib/components/formula/Picker';
/**

View File

@ -210,8 +210,14 @@ export default class TextControl extends React.PureComponent<
};
componentDidMount() {
const {formItem, autoComplete, addHook, formInited, data, name} =
this.props;
const {
formItem,
autoComplete,
addHook,
formInited,
data,
name
} = this.props;
if (isEffectiveApi(autoComplete, data) && formItem) {
if (formInited) {
@ -302,8 +308,14 @@ export default class TextControl extends React.PureComponent<
}
async resetValue() {
const {onChange, dispatchEvent, resetValue, formStore, store, name} =
this.props;
const {
onChange,
dispatchEvent,
resetValue,
formStore,
store,
name
} = this.props;
const pristineVal =
getVariable(formStore?.pristine ?? store?.pristine, name) ?? resetValue;
@ -484,8 +496,13 @@ export default class TextControl extends React.PureComponent<
}
async handleKeyDown(evt: React.KeyboardEvent<HTMLInputElement>) {
const {selectedOptions, onChange, multiple, creatable, dispatchEvent} =
this.props;
const {
selectedOptions,
onChange,
multiple,
creatable,
dispatchEvent
} = this.props;
const valueField = this.props?.valueField || 'value';
if (selectedOptions.length && !this.state.inputValue && evt.keyCode === 8) {
@ -627,8 +644,12 @@ export default class TextControl extends React.PureComponent<
@autobind
async handleNormalInputChange(e: React.ChangeEvent<HTMLInputElement>) {
const {onChange, dispatchEvent, trimContents, clearValueOnEmpty} =
this.props;
const {
onChange,
dispatchEvent,
trimContents,
clearValueOnEmpty
} = this.props;
let value: string | undefined = this.transformValue(e.currentTarget.value);
if (typeof value === 'string') {
if (trimContents) {
@ -653,8 +674,13 @@ export default class TextControl extends React.PureComponent<
}
normalizeValue(value: Option[] | Option | undefined | null) {
const {multiple, delimiter, joinValues, extractValue, valueField} =
this.props;
const {
multiple,
delimiter,
joinValues,
extractValue,
valueField
} = this.props;
const selectedOptions = Array.isArray(value) ? value : value ? [value] : [];
if (joinValues) {
@ -837,8 +863,9 @@ export default class TextControl extends React.PureComponent<
{
'is-opened': isOpen,
'TextControl-input--multiple': multiple,
[`TextControl-input--border${ucFirst(borderMode)}`]:
[`TextControl-input--border${ucFirst(
borderMode
)}`]: borderMode
}
)}
onClick={this.handleClick}
@ -1326,15 +1353,11 @@ export function mapItemIndex(
}
@OptionsControl({
type: 'input-text'
type: 'input-text',
alias: ['input-password', 'native-date', 'native-time', 'native-number']
})
export class TextControlRenderer extends TextControl {}
@OptionsControl({
type: 'input-password'
})
export class PasswordControlRenderer extends TextControl {}
@OptionsControl({
type: 'input-email',
validations: 'isEmail'
@ -1346,18 +1369,3 @@ export class EmailControlRenderer extends TextControl {}
validations: 'isUrl'
})
export class UrlControlRenderer extends TextControl {}
@OptionsControl({
type: 'native-date'
})
export class NativeDateControlRenderer extends TextControl {}
@OptionsControl({
type: 'native-time'
})
export class NativeTimeControlRenderer extends TextControl {}
@OptionsControl({
type: 'native-number'
})
export class NativeNumberControlRenderer extends TextControl {}

View File

@ -3,7 +3,8 @@ import omit from 'lodash/omit';
import debounce from 'lodash/debounce';
import cx from 'classnames';
import {matchSorter} from 'match-sorter';
import {SpinnerExtraProps, Tree as TreeSelector, value2array} from 'amis-ui';
import {SpinnerExtraProps, Tree as TreeSelector} from 'amis-ui';
import {value2array} from 'amis-ui/lib/components/Select';
import {
Option,
OptionsControl,

View File

@ -5,7 +5,7 @@ import {JSONSchemaEditor} from 'amis-ui';
import {autobind, isObject} from 'amis-core';
import {FormBaseControlSchema} from '../../Schema';
import {schemaEditorItemPlaceholder} from 'amis-ui';
import {schemaEditorItemPlaceholder} from 'amis-ui/lib/components/schema-editor/Common';
import type {SchemaEditorItemPlaceholder} from 'amis-ui';
import {isMobile} from 'amis-core';
@ -99,7 +99,9 @@ export interface JSONSchemaEditorProps
'type' | 'className' | 'descriptionClassName' | 'inputClassName'
> {}
export default class JSONSchemaEditorControl extends React.PureComponent<JSONSchemaEditorProps> {
export default class JSONSchemaEditorControl extends React.PureComponent<
JSONSchemaEditorProps
> {
static defaultProps = {
enableAdvancedSetting: false,
placeholder: schemaEditorItemPlaceholder

View File

@ -1552,8 +1552,7 @@ export class ListItem extends React.Component<ListItemProps> {
}
@Renderer({
test: /(^|\/)(?:list|list-group)\/(?:.*\/)?list-item$/,
name: 'list-item'
type: 'list-item'
})
export class ListItemRenderer extends ListItem {
static propsList = ['multiple', ...ListItem.propsList];

View File

@ -324,7 +324,8 @@ export const MappingField = withStore(props =>
);
@Renderer({
test: /(^|\/)(?:map|mapping)$/,
type: 'mapping',
alias: ['map'],
name: 'mapping'
})
export class MappingFieldRenderer extends React.Component<RendererProps> {

View File

@ -1415,8 +1415,15 @@ const ConditionBuilderWithRemoteOptions = withRemoteConfig({
}
async handleSelect(link: Link, depth: number) {
const {onSelect, env, data, level, dispatchEvent, updateConfig, config} =
this.props;
const {
onSelect,
env,
data,
level,
dispatchEvent,
updateConfig,
config
} = this.props;
const rendererEvent = await dispatchEvent(
'click',
@ -1459,8 +1466,14 @@ const ConditionBuilderWithRemoteOptions = withRemoteConfig({
}
render() {
const {disabled, loading, config, deferLoad, updateConfig, ...rest} =
this.props;
const {
disabled,
loading,
config,
deferLoad,
updateConfig,
...rest
} = this.props;
const currentLink = this.getCurrentLink(this.state.currentKey);
return (
@ -1482,7 +1495,8 @@ const ConditionBuilderWithRemoteOptions = withRemoteConfig({
export default ThemedNavigation;
@Renderer({
test: /(^|\/)(?:nav|navigation)$/,
type: 'nav',
alias: ['navigation'],
name: 'nav'
})
export class NavigationRenderer extends React.Component<RendererProps> {

View File

@ -141,7 +141,8 @@ export default class Pagination extends React.Component<PaginationProps> {
}
@Renderer({
test: /(^|\/)(?:pagination|pager)$/,
type: 'pagination',
alias: ['pager'],
name: 'pagination'
})
export class PaginationRenderer extends Pagination {}

View File

@ -114,7 +114,8 @@ export class Plain extends React.Component<PlainProps, object> {
}
@Renderer({
test: /(^|\/)(?:plain|text)$/,
type: 'plain',
alias: ['text'],
name: 'plain'
})
export class PlainRenderer extends Plain {}

View File

@ -244,7 +244,8 @@ export default class QRCode extends React.Component<QRCodeProps, any> {
}
@Renderer({
test: /(^|\/)qr\-?code$/,
type: 'qrcode',
alias: ['qr-code'],
name: 'qrcode'
})
export class QRCodeRenderer extends QRCode {

View File

@ -8,7 +8,8 @@ import {
filter,
getPropValue
} from 'amis-core';
import {Steps, StepStatus, RemoteOptionsProps, withRemoteConfig} from 'amis-ui';
import {Steps, RemoteOptionsProps, withRemoteConfig} from 'amis-ui';
import {StepStatus} from 'amis-ui/lib/components/Steps';
import {BaseSchema, SchemaCollection} from '../Schema';
import isPlainObject from 'lodash/isPlainObject';
import type {SchemaExpression} from 'amis-core';

View File

@ -196,7 +196,7 @@ export class TableCell extends React.Component<TableCellProps> {
}
@Renderer({
test: /(^|\/)table\/(?:.*\/)?cell$/,
type: 'cell',
name: 'table-cell'
})
@QuickEdit()

View File

@ -266,7 +266,8 @@ export class Tpl extends React.Component<TplProps, TplState> {
}
@Renderer({
test: /(^|\/)(?:tpl|html)$/,
type: 'tpl',
alias: ['html'],
name: 'tpl'
})
// @ts-ignore 类型没搞定