;
suspensed?: boolean;
- componentsDescription?: ComponentMetadata[];
+ componentMetadatas?: ComponentMetadata[];
eventPipe?: EventEmitter;
+ globalComponentActions?: ComponentAction[];
onMount?: (designer: Designer) => void;
onDragstart?: (e: LocateEvent) => void;
onDrag?: (e: LocateEvent) => void;
@@ -229,8 +230,8 @@ export default class Designer {
if (props.suspensed !== this.props.suspensed && props.suspensed != null) {
this.suspensed = props.suspensed;
}
- if (props.componentsDescription !== this.props.componentsDescription && props.componentsDescription != null) {
- this.buildComponentMetasMap(props.componentsDescription);
+ if (props.componentMetadatas !== this.props.componentMetadatas && props.componentMetadatas != null) {
+ this.buildComponentMetasMap(props.componentMetadatas);
}
} else {
// init hotkeys
@@ -246,8 +247,8 @@ export default class Designer {
if (props.suspensed != null) {
this.suspensed = props.suspensed;
}
- if (props.componentsDescription != null) {
- this.buildComponentMetasMap(props.componentsDescription);
+ if (props.componentMetadatas != null) {
+ this.buildComponentMetasMap(props.componentMetadatas);
}
}
this.props = props;
@@ -307,7 +308,7 @@ export default class Designer {
meta.metadata = data;
this._lostComponentMetasMap.delete(key);
} else {
- meta = new ComponentMeta(data);
+ meta = new ComponentMeta(this, data);
}
this._componentMetasMap.set(key, meta);
@@ -315,6 +316,10 @@ export default class Designer {
});
}
+ getGlobalComponentActions(): ComponentAction[] | null {
+ return this.props?.globalComponentActions || null;
+ }
+
getComponentMeta(componentName: string, generateMetadata?: () => ComponentMetadata | null): ComponentMeta {
if (this._componentMetasMap.has(componentName)) {
return this._componentMetasMap.get(componentName)!;
@@ -324,7 +329,7 @@ export default class Designer {
return this._lostComponentMetasMap.get(componentName)!;
}
- const meta = new ComponentMeta({
+ const meta = new ComponentMeta(this, {
componentName,
...(generateMetadata ? generateMetadata() : null),
});
diff --git a/packages/designer/src/designer/helper/offset-observer.ts b/packages/designer/src/designer/helper/offset-observer.ts
index 21a8175b7..798ec43a8 100644
--- a/packages/designer/src/designer/helper/offset-observer.ts
+++ b/packages/designer/src/designer/helper/offset-observer.ts
@@ -2,6 +2,7 @@ import { obx, computed } from '@recore/obx';
import { INodeSelector, IViewport } from '../simulator';
import { uniqueId } from '../../../../utils/unique-id';
import { isRootNode } from '../document/node/root-node';
+import Node from '../document/node/node';
export default class OffsetObserver {
readonly id = uniqueId('oobx');
@@ -10,39 +11,65 @@ export default class OffsetObserver {
private lastOffsetTop?: number;
private lastOffsetHeight?: number;
private lastOffsetWidth?: number;
- @obx private height = 0;
- @obx private width = 0;
- @obx private left = 0;
- @obx private top = 0;
+ @obx private _height = 0;
+ @obx private _width = 0;
+ @obx private _left = 0;
+ @obx private _top = 0;
+ @obx private _right = 0;
+ @obx private _bottom = 0;
+
+ @computed get height() {
+ return this.isRoot ? this.viewport.height : this._height * this.scale;
+ }
+
+ @computed get width() {
+ return this.isRoot ? this.viewport.width : this._width * this.scale;
+ }
+
+ @computed get top() {
+ return this.isRoot ? 0 : this._top * this.scale;
+ }
+
+ @computed get left() {
+ return this.isRoot ? 0 : this._left * this.scale;
+ }
+
+ @computed get bottom() {
+ return this.isRoot ? this.viewport.height : this._bottom * this.scale;
+ }
+
+ @computed get right() {
+ return this.isRoot ? this.viewport.width : this._right * this.scale;
+ }
@obx hasOffset = false;
@computed get offsetLeft() {
if (this.isRoot) {
- return this.viewport.scrollX;
+ return this.viewport.scrollX * this.scale;
}
if (!this.viewport.scrolling || this.lastOffsetLeft == null) {
- this.lastOffsetLeft = (this.left + this.viewport.scrollX) * this.scale;
+ this.lastOffsetLeft = this.left + this.viewport.scrollX * this.scale;
}
return this.lastOffsetLeft;
}
@computed get offsetTop() {
if (this.isRoot) {
- return this.viewport.scrollY;
+ return this.viewport.scrollY * this.scale;
}
if (!this.viewport.scrolling || this.lastOffsetTop == null) {
- this.lastOffsetTop = (this.top + this.viewport.scrollY) * this.scale;
+ this.lastOffsetTop = this.top + this.viewport.scrollY * this.scale;
}
return this.lastOffsetTop;
}
@computed get offsetHeight() {
if (!this.viewport.scrolling || this.lastOffsetHeight == null) {
- this.lastOffsetHeight = this.isRoot ? this.viewport.height : this.height * this.scale;
+ this.lastOffsetHeight = this.isRoot ? this.viewport.height : this.height;
}
return this.lastOffsetHeight;
}
@computed get offsetWidth() {
if (!this.viewport.scrolling || this.lastOffsetWidth == null) {
- this.lastOffsetWidth = this.isRoot ? this.viewport.width : this.width * this.scale;
+ this.lastOffsetWidth = this.isRoot ? this.viewport.width : this.width;
}
return this.lastOffsetWidth;
}
@@ -52,11 +79,13 @@ export default class OffsetObserver {
}
private pid: number | undefined;
- private viewport: IViewport;
+ readonly viewport: IViewport;
private isRoot: boolean;
+ readonly node: Node;
constructor(readonly nodeInstance: INodeSelector) {
const { node, instance } = nodeInstance;
+ this.node = node;
const doc = node.document;
const host = doc.simulator!;
this.isRoot = isRootNode(node);
@@ -75,16 +104,18 @@ export default class OffsetObserver {
return;
}
- const rect = host.computeComponentInstanceRect(instance!);
+ const rect = host.computeComponentInstanceRect(instance!, node.componentMeta.rectSelector);
if (!rect) {
this.hasOffset = false;
} else {
if (!this.viewport.scrolling || !this.hasOffset) {
- this.height = rect.height;
- this.width = rect.width;
- this.left = rect.left;
- this.top = rect.top;
+ this._height = rect.height;
+ this._width = rect.width;
+ this._left = rect.left;
+ this._top = rect.top;
+ this._right = rect.right;
+ this._bottom = rect.bottom;
this.hasOffset = true;
}
}
diff --git a/packages/designer/src/designer/simulator.ts b/packages/designer/src/designer/simulator.ts
index e21b5e8c9..99c73ad47 100644
--- a/packages/designer/src/designer/simulator.ts
+++ b/packages/designer/src/designer/simulator.ts
@@ -134,7 +134,7 @@ export interface ISimulator extends ISensor {
computeRect(node: Node): DOMRect | null;
- computeComponentInstanceRect(instance: ComponentInstance): DOMRect | null;
+ computeComponentInstanceRect(instance: ComponentInstance, selector?: string): DOMRect | null;
findDOMNodes(instance: ComponentInstance): Array | null;
diff --git a/packages/designer/src/locale/en-US.json b/packages/designer/src/locale/en-US.json
new file mode 100644
index 000000000..722b8a4c6
--- /dev/null
+++ b/packages/designer/src/locale/en-US.json
@@ -0,0 +1,4 @@
+{
+ "copy": "Copy",
+ "remove": "Remove"
+}
diff --git a/packages/designer/src/locale/index.ts b/packages/designer/src/locale/index.ts
new file mode 100644
index 000000000..32205fb5c
--- /dev/null
+++ b/packages/designer/src/locale/index.ts
@@ -0,0 +1,10 @@
+import { createIntl } from '../../../globals';
+import en_US from './en-US.json';
+import zh_CN from './zh-CN.json';
+
+const { intl, getLocale, setLocale } = createIntl({
+ 'en-US': en_US,
+ 'zh-CN': zh_CN,
+});
+
+export { intl, getLocale, setLocale };
diff --git a/packages/designer/src/locale/zh-CN.json b/packages/designer/src/locale/zh-CN.json
new file mode 100644
index 000000000..f90c1c8a8
--- /dev/null
+++ b/packages/designer/src/locale/zh-CN.json
@@ -0,0 +1,4 @@
+{
+ "copy": "复制",
+ "remove": "删除"
+}
diff --git a/packages/editor/src/config/assets.js b/packages/editor/src/config/assets.js
index ce83e3438..d8506368f 100644
--- a/packages/editor/src/config/assets.js
+++ b/packages/editor/src/config/assets.js
@@ -1196,7 +1196,8 @@ export default {
isContainer: true,
nestingRule: {
childWhitelist: 'Select.Option'
- }
+ },
+ rectSelector: '.next-select',
},
props: [
{
@@ -1762,6 +1763,26 @@ export default {
}
}
}
+ },
+ Dialog: {
+ componentName: 'Dialog',
+ title: '弹窗',
+ devMode: 'proCode',
+ npm: {
+ package: '@alifd/next',
+ version: '1.19.18',
+ destructuring: true,
+ exportName: 'Dialog'
+ },
+ props: [{
+ name: 'title',
+ propType: 'string'
+ }],
+ configure: {
+ component: {
+ rectSelector: '.next-dialog'
+ }
+ }
}
},
componentList: [
@@ -1889,6 +1910,30 @@ export default {
}
}
]
+ },
+ {
+ componentName: 'Dialog',
+ libraryId: 3,
+ title: '弹窗',
+ icon: '',
+ snippets: [
+ {
+ title: '弹窗',
+ screenshot: '',
+ schema: {
+ componentName: 'Dialog',
+ props: {
+ title: '这是一个dialog',
+ visible: true
+ },
+ children: [
+ {
+ compoentName: 'Div'
+ }
+ ]
+ }
+ }
+ ]
}
]
}
diff --git a/packages/editor/src/plugins/designer/index.tsx b/packages/editor/src/plugins/designer/index.tsx
index 7c559c311..b953f4b6e 100644
--- a/packages/editor/src/plugins/designer/index.tsx
+++ b/packages/editor/src/plugins/designer/index.tsx
@@ -168,7 +168,7 @@ export default class DesignerPlugin extends PureComponent {
className="lowcode-plugin-designer"
defaultSchema={SCHEMA as any}
eventPipe={editor as any}
- componentsDescription={Object.values(assets.components) as any}
+ componentMetadatas={Object.values(assets.components) as any}
simulatorProps={{
library: Object.values(assets.packages),
}}
diff --git a/packages/globals/.eslintignore b/packages/globals/.eslintignore
new file mode 100644
index 000000000..1fb2edf7c
--- /dev/null
+++ b/packages/globals/.eslintignore
@@ -0,0 +1,6 @@
+.idea/
+.vscode/
+build/
+.*
+~*
+node_modules
diff --git a/packages/globals/.eslintrc b/packages/globals/.eslintrc
new file mode 100644
index 000000000..db78d35d1
--- /dev/null
+++ b/packages/globals/.eslintrc
@@ -0,0 +1,3 @@
+{
+ "extends": "./node_modules/@recore/config/.eslintrc"
+}
diff --git a/packages/globals/.prettierrc b/packages/globals/.prettierrc
new file mode 100644
index 000000000..8748c5ed3
--- /dev/null
+++ b/packages/globals/.prettierrc
@@ -0,0 +1,6 @@
+{
+ "semi": true,
+ "singleQuote": true,
+ "printWidth": 120,
+ "trailingComma": "all"
+}
diff --git a/packages/globals/README.md b/packages/globals/README.md
new file mode 100644
index 000000000..070f5ca3b
--- /dev/null
+++ b/packages/globals/README.md
@@ -0,0 +1 @@
+shared globals
diff --git a/packages/globals/package.json b/packages/globals/package.json
new file mode 100644
index 000000000..26761d9ba
--- /dev/null
+++ b/packages/globals/package.json
@@ -0,0 +1,43 @@
+{
+ "name": "@ali/lowcode-globals",
+ "version": "0.0.0",
+ "description": "xxx for Ali lowCode engine",
+ "main": "src/index.ts",
+ "files": [
+ "lib"
+ ],
+ "scripts": {
+ "build": "tsc",
+ "test": "ava",
+ "test:snapshot": "ava --update-snapshots"
+ },
+ "dependencies": {
+ "@alifd/next": "^1.19.16",
+ "classnames": "^2.2.6",
+ "react": "^16",
+ "react-dom": "^16.7.0"
+ },
+ "devDependencies": {
+ "@recore/config": "^2.0.0",
+ "@types/classnames": "^2.2.7",
+ "@types/node": "^13.7.1",
+ "@types/react": "^16",
+ "@types/react-dom": "^16",
+ "eslint": "^6.5.1",
+ "prettier": "^1.18.2",
+ "tslib": "^1.9.3",
+ "typescript": "^3.1.3",
+ "ts-node": "^8.0.1"
+ },
+ "ava": {
+ "compileEnhancements": false,
+ "snapshotDir": "test/fixtures/__snapshots__",
+ "extensions": [
+ "ts"
+ ],
+ "require": [
+ "ts-node/register"
+ ]
+ },
+ "license": "MIT"
+}
diff --git a/packages/globals/src/components/index.ts b/packages/globals/src/components/index.ts
new file mode 100644
index 000000000..f6eb9a1ff
--- /dev/null
+++ b/packages/globals/src/components/index.ts
@@ -0,0 +1,2 @@
+export * from './tip';
+export * from './title';
diff --git a/packages/plugin-settings/src/tip/embed-tip.tsx b/packages/globals/src/components/tip/embed-tip.tsx
similarity index 90%
rename from packages/plugin-settings/src/tip/embed-tip.tsx
rename to packages/globals/src/components/tip/embed-tip.tsx
index fa68e8d08..fd8b3d4f8 100644
--- a/packages/plugin-settings/src/tip/embed-tip.tsx
+++ b/packages/globals/src/components/tip/embed-tip.tsx
@@ -1,4 +1,4 @@
-import { uniqueId } from '../../../utils/unique-id';
+import { uniqueId } from '../../../../utils/unique-id';
import { Component, ReactNode } from 'react';
import { saveTips } from './tip-handler';
diff --git a/packages/plugin-settings/src/tip/index.ts b/packages/globals/src/components/tip/index.ts
similarity index 100%
rename from packages/plugin-settings/src/tip/index.ts
rename to packages/globals/src/components/tip/index.ts
diff --git a/packages/plugin-settings/src/tip/style.less b/packages/globals/src/components/tip/style.less
similarity index 100%
rename from packages/plugin-settings/src/tip/style.less
rename to packages/globals/src/components/tip/style.less
diff --git a/packages/plugin-settings/src/tip/tip-container.tsx b/packages/globals/src/components/tip/tip-container.tsx
similarity index 100%
rename from packages/plugin-settings/src/tip/tip-container.tsx
rename to packages/globals/src/components/tip/tip-container.tsx
diff --git a/packages/plugin-settings/src/tip/tip-handler.ts b/packages/globals/src/components/tip/tip-handler.ts
similarity index 100%
rename from packages/plugin-settings/src/tip/tip-handler.ts
rename to packages/globals/src/components/tip/tip-handler.ts
diff --git a/packages/plugin-settings/src/tip/tip.tsx b/packages/globals/src/components/tip/tip.tsx
similarity index 100%
rename from packages/plugin-settings/src/tip/tip.tsx
rename to packages/globals/src/components/tip/tip.tsx
diff --git a/packages/plugin-settings/src/tip/utils.ts b/packages/globals/src/components/tip/utils.ts
similarity index 100%
rename from packages/plugin-settings/src/tip/utils.ts
rename to packages/globals/src/components/tip/utils.ts
diff --git a/packages/plugin-settings/src/title/index.tsx b/packages/globals/src/components/title/index.tsx
similarity index 72%
rename from packages/plugin-settings/src/title/index.tsx
rename to packages/globals/src/components/title/index.tsx
index 266a947de..226a5f15e 100644
--- a/packages/plugin-settings/src/title/index.tsx
+++ b/packages/globals/src/components/title/index.tsx
@@ -3,12 +3,7 @@ import { Icon } from '@alifd/next';
import classNames from 'classnames';
import EmbedTip, { TipConfig } from '../tip/embed-tip';
import './title.less';
-
-export interface IconConfig {
- type: string;
- size?: number | 'small' | 'xxs' | 'xs' | 'medium' | 'large' | 'xl' | 'xxl' | 'xxxl' | 'inherit';
- className?: string;
-}
+import { IconConfig, createIcon } from '../../utils';
export interface TitleConfig {
label?: ReactNode;
@@ -19,7 +14,7 @@ export interface TitleConfig {
export type TitleContent = string | ReactElement | TitleConfig;
-export default class Title extends Component<{ title: TitleContent; onClick?: () => void }> {
+export class Title extends Component<{ title: TitleContent; onClick?: () => void }> {
render() {
let { title } = this.props;
if (isValidElement(title)) {
@@ -29,15 +24,7 @@ export default class Title extends Component<{ title: TitleContent; onClick?: ()
title = { label: title }; // tslint:disable-line
}
- let icon = null;
- if (title.icon) {
- if (isValidElement(title.icon)) {
- icon = title.icon;
- } else {
- const iconProps = typeof title.icon === 'string' ? { type: title.icon } : title.icon;
- icon = ;
- }
- }
+ const icon = title.icon ? createIcon(title.icon) : null;
let tip: any = null;
if (title.tip) {
diff --git a/packages/plugin-settings/src/title/title.less b/packages/globals/src/components/title/title.less
similarity index 100%
rename from packages/plugin-settings/src/title/title.less
rename to packages/globals/src/components/title/title.less
diff --git a/packages/globals/src/icons/clone.tsx b/packages/globals/src/icons/clone.tsx
new file mode 100644
index 000000000..57dd701db
--- /dev/null
+++ b/packages/globals/src/icons/clone.tsx
@@ -0,0 +1,11 @@
+import { IconBase, IconBaseProps } from "./icon-base";
+
+export function Clone(props: IconBaseProps) {
+ return (
+
+
+
+ );
+}
+
+Clone.displayName = 'Clone';
diff --git a/packages/globals/src/icons/hidden.tsx b/packages/globals/src/icons/hidden.tsx
new file mode 100644
index 000000000..3abdc4448
--- /dev/null
+++ b/packages/globals/src/icons/hidden.tsx
@@ -0,0 +1,10 @@
+import { IconBase, IconBaseProps } from "./icon-base";
+
+export function Hidden(props: IconBaseProps) {
+ return (
+
+
+
+ );
+}
+Hidden.displayName = 'Hidden';
diff --git a/packages/globals/src/icons/icon-base.tsx b/packages/globals/src/icons/icon-base.tsx
new file mode 100644
index 000000000..843c3d700
--- /dev/null
+++ b/packages/globals/src/icons/icon-base.tsx
@@ -0,0 +1,40 @@
+import { ReactNode } from 'react';
+
+const SizePresets: any = {
+ xsmall: 8,
+ small: 12,
+ medium: 16,
+ large: 20,
+ xlarge: 30,
+};
+
+export interface IconBaseProps {
+ className?: string;
+ fill?: string;
+ size?: 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | number;
+ viewBox: string;
+ children?: ReactNode;
+ style?: object;
+};
+
+export function IconBase({ fill, size = 'medium', viewBox, style, children, ...props }: IconBaseProps) {
+ if (SizePresets.hasOwnProperty(size)) {
+ size = SizePresets[size];
+ }
+
+ return (
+
+ );
+}
diff --git a/packages/globals/src/icons/index.ts b/packages/globals/src/icons/index.ts
new file mode 100644
index 000000000..f843f3a52
--- /dev/null
+++ b/packages/globals/src/icons/index.ts
@@ -0,0 +1,5 @@
+export * from './clone';
+export * from './hidden';
+export * from './remove';
+export * from './settings';
+export * from './icon-base';
diff --git a/packages/globals/src/icons/remove.tsx b/packages/globals/src/icons/remove.tsx
new file mode 100644
index 000000000..9f90088e7
--- /dev/null
+++ b/packages/globals/src/icons/remove.tsx
@@ -0,0 +1,10 @@
+import { IconBase, IconBaseProps } from './icon-base';
+
+export function Remove(props: IconBaseProps) {
+ return (
+
+
+
+ );
+}
+Remove.displayName = 'Remove';
diff --git a/packages/globals/src/icons/settings.tsx b/packages/globals/src/icons/settings.tsx
new file mode 100644
index 000000000..05628a7c1
--- /dev/null
+++ b/packages/globals/src/icons/settings.tsx
@@ -0,0 +1,12 @@
+import { IconBase, IconBaseProps } from './icon-base';
+
+export function Setting(props: IconBaseProps) {
+ return (
+
+
+
+
+ );
+}
+
+Setting.displayName = 'Setting';
diff --git a/packages/globals/src/index.ts b/packages/globals/src/index.ts
new file mode 100644
index 000000000..bbef70f75
--- /dev/null
+++ b/packages/globals/src/index.ts
@@ -0,0 +1,4 @@
+export * from './intl';
+export * from './components';
+export * from './utils';
+export * from './icons';
diff --git a/packages/globals/src/intl/ali-global-locale.ts b/packages/globals/src/intl/ali-global-locale.ts
new file mode 100644
index 000000000..37d97a115
--- /dev/null
+++ b/packages/globals/src/intl/ali-global-locale.ts
@@ -0,0 +1,124 @@
+import { EventEmitter } from 'events';
+const languageMap: { [key: string]: string } = {
+ en: 'en-US',
+ zh: 'zh-CN',
+ zt: 'zh-TW',
+ es: 'es-ES',
+ pt: 'pt-PT',
+ fr: 'fr-FR',
+ de: 'de-DE',
+ it: 'it-IT',
+ ru: 'ru-RU',
+ ja: 'ja-JP',
+ ko: 'ko-KR',
+ ar: 'ar-SA',
+ tr: 'tr-TR',
+ th: 'th-TH',
+ vi: 'vi-VN',
+ nl: 'nl-NL',
+ he: 'iw-IL',
+ id: 'in-ID',
+ pl: 'pl-PL',
+ hi: 'hi-IN',
+ uk: 'uk-UA',
+ ms: 'ms-MY',
+ tl: 'tl-PH',
+};
+
+const LowcodeConfigKey = 'ali-lowcode-config';
+
+class AliGlobalLocale {
+ private locale: string = '';
+ private emitter = new EventEmitter();
+
+ constructor() {
+ this.emitter.setMaxListeners(0);
+ }
+
+ setLocale(locale: string) {
+ this.locale = locale;
+ if (hasLocalStorage(window)) {
+ const store = window.localStorage;
+ let config: any;
+ try {
+ config = JSON.parse(store.getItem(LowcodeConfigKey) || '');
+ } catch (e) {
+ // ignore;
+ }
+
+ if (config && typeof config === 'object') {
+ config.locale = locale;
+ } else {
+ config = { locale };
+ }
+
+ store.setItem(LowcodeConfigKey, JSON.stringify(config));
+ }
+ }
+
+ getLocale() {
+ if (this.locale) {
+ return this.locale;
+ }
+
+ const { g_config, navigator } = window as any;
+ if (hasLocalStorage(window)) {
+ const store = window.localStorage;
+ let config: any;
+ try {
+ config = JSON.parse(store.getItem(LowcodeConfigKey) || '');
+ } catch (e) {
+ // ignore;
+ }
+ if (config?.locale) {
+ this.locale = (config.locale || '').replace('_', '-');
+ return this.locale;
+ }
+ } else if (g_config) {
+ if (g_config.locale) {
+ this.locale = languageMap[g_config.locale] || (g_config.locale || '').replace('_', '-');
+ return this.locale;
+ }
+ }
+
+ if (navigator.language) {
+ this.locale = (navigator.language as string).replace('_', '-');
+ }
+
+ // IE10 及更低版本使用 browserLanguage
+ if (navigator.browserLanguage) {
+ const it = navigator.browserLanguage.split('-');
+ this.locale = it[0];
+ if (it[1]) {
+ this.locale += '-' + it[1].toUpperCase();
+ }
+ }
+
+ if (!this.locale) {
+ this.locale = 'zh-CN';
+ }
+
+ return this.locale;
+ }
+
+ onLocaleChange(fn: (locale: string) => void): () => void {
+ this.emitter.on('localechange', fn);
+ return () => {
+ this.emitter.removeListener('localechange', fn);
+ };
+ }
+}
+
+function hasLocalStorage(obj: any): obj is WindowLocalStorage {
+ return obj.localStorage;
+}
+
+let globalLocale: AliGlobalLocale;
+if ((window as any).__aliGlobalLocale) {
+ globalLocale = (window as any).__aliGlobalLocale as any;
+} else {
+ globalLocale = new AliGlobalLocale();
+ (window as any).__aliGlobalLocale = globalLocale;
+}
+
+export { globalLocale };
diff --git a/packages/globals/src/intl/index.tsx b/packages/globals/src/intl/index.tsx
new file mode 100644
index 000000000..1f54012f7
--- /dev/null
+++ b/packages/globals/src/intl/index.tsx
@@ -0,0 +1,122 @@
+import { globalLocale } from './ali-global-locale';
+import { PureComponent, ReactNode } from 'react';
+
+function injectVars(template: string, params: any): string {
+ if (!template || !params) {
+ return template;
+ }
+ return template.replace(/({\w+})/g, (_, $1) => {
+ const key = (/\d+/.exec($1) || [])[0] as any;
+ if (key && params[key] != null) {
+ return params[key];
+ }
+ return $1;
+ });
+}
+
+export interface I18nData {
+ type: 'i18n';
+ [key: string]: string;
+}
+
+export function isI18nData(obj: any): obj is I18nData {
+ return obj && obj.type === 'i18n';
+}
+
+export function localeFormat(data: any, params?: object): string {
+ if (!isI18nData(data)) {
+ return data;
+ }
+ const locale = globalLocale.getLocale();
+ const tpl = data[locale];
+ if (tpl == null) {
+ return `##intl null@${locale}##`;
+ }
+ return injectVars(tpl, params);
+}
+
+class Intl extends PureComponent<{ data: any; params?: object }> {
+ private dispose = globalLocale.onLocaleChange(() => this.forceUpdate());
+ componentWillUnmount() {
+ this.dispose();
+ }
+ render() {
+ const { data, params } = this.props;
+ return localeFormat(data, params);
+ }
+}
+
+export function intl(data: any, params?: object): ReactNode {
+ if (isI18nData(data)) {
+ return ;
+ }
+ return data;
+}
+
+export function createIntl(
+ instance: string | object,
+): {
+ intl(id: string, params?: object): ReactNode;
+ getIntlString(id: string, params?: object): string;
+ getLocale(): string;
+ setLocale(locale: string): void;
+} {
+ let lastLocale: string | undefined;
+ let data: any = {};
+ function useLocale(locale: string) {
+ lastLocale = locale;
+ if (typeof instance === 'string') {
+ if ((window as any)[instance]) {
+ data = (window as any)[instance][locale] || {};
+ } else {
+ const key = `${instance}_${locale.toLocaleLowerCase()}`;
+ data = (window as any)[key] || {};
+ }
+ } else if (instance && typeof instance === 'object') {
+ data = (instance as any)[locale] || {};
+ }
+ }
+
+ useLocale(globalLocale.getLocale());
+
+ function getIntlString(key: string, params?: object): string {
+ const str = data[key];
+
+ if (str == null) {
+ return `##intl null@${key}##`;
+ }
+
+ return injectVars(str, params);
+ }
+
+ class Intl extends PureComponent<{ id: string; params?: object }> {
+ private dispose = globalLocale.onLocaleChange(locale => {
+ if (lastLocale !== locale) {
+ useLocale(locale);
+ this.forceUpdate();
+ }
+ });
+ componentWillUnmount() {
+ this.dispose();
+ }
+ render() {
+ const { id, params } = this.props;
+ return getIntlString(id, params);
+ }
+ }
+
+ return {
+ intl(id: string, params?: object) {
+ return ;
+ },
+ getIntlString,
+ getLocale() {
+ return globalLocale.getLocale();
+ },
+ setLocale(locale: string) {
+ globalLocale.setLocale(locale);
+ },
+ };
+}
+
+export { globalLocale };
diff --git a/packages/globals/src/utils/create-icon.tsx b/packages/globals/src/utils/create-icon.tsx
new file mode 100644
index 000000000..728d2fcdd
--- /dev/null
+++ b/packages/globals/src/utils/create-icon.tsx
@@ -0,0 +1,34 @@
+import { Icon } from '@alifd/next';
+import { isValidElement, ReactNode, ComponentType, createElement, cloneElement, ReactElement } from 'react';
+import { isReactComponent } from './is-react';
+
+export interface IconConfig {
+ type: string;
+ size?: number | 'small' | 'xxs' | 'xs' | 'medium' | 'large' | 'xl' | 'xxl' | 'xxxl' | 'inherit';
+ className?: string;
+}
+
+export type IconType = string | ReactElement | ComponentType | IconConfig;
+
+const URL_RE = /^(https?:)\/\//i;
+
+export function createIcon(icon: IconType, props?: object): ReactNode {
+ if (typeof icon === 'string') {
+ if (URL_RE.test(icon)) {
+ return
;
+ }
+ return ;
+ }
+ if (isValidElement(icon)) {
+ return cloneElement(icon, {...props});
+ }
+ if (isReactComponent(icon)) {
+ return createElement(icon, {...props});
+ }
+
+ if (icon) {
+ return ;
+ }
+
+ return null;
+}
diff --git a/packages/globals/src/utils/index.ts b/packages/globals/src/utils/index.ts
new file mode 100644
index 000000000..365722a71
--- /dev/null
+++ b/packages/globals/src/utils/index.ts
@@ -0,0 +1,2 @@
+export * from './create-icon';
+export * from './is-react';
diff --git a/packages/globals/src/utils/is-react.ts b/packages/globals/src/utils/is-react.ts
new file mode 100644
index 000000000..1f755138a
--- /dev/null
+++ b/packages/globals/src/utils/is-react.ts
@@ -0,0 +1,9 @@
+import { ComponentClass, Component, ComponentType } from 'react';
+
+export function isReactClass(obj: any): obj is ComponentClass {
+ return obj && obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component);
+}
+
+export function isReactComponent(obj: any): obj is ComponentType {
+ return obj && (isReactClass(obj) || typeof obj === 'function');
+}
diff --git a/packages/globals/tsconfig.json b/packages/globals/tsconfig.json
new file mode 100644
index 000000000..aad669598
--- /dev/null
+++ b/packages/globals/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./node_modules/@recore/config/tsconfig",
+ "compilerOptions": {
+ "experimentalDecorators": true
+ },
+ "include": [
+ "./src/"
+ ]
+}
diff --git a/packages/plugin-settings/src/builtin-setters/array-setter/index.tsx b/packages/plugin-settings/src/builtin-setters/array-setter/index.tsx
index 96688d593..1e889ce30 100644
--- a/packages/plugin-settings/src/builtin-setters/array-setter/index.tsx
+++ b/packages/plugin-settings/src/builtin-setters/array-setter/index.tsx
@@ -5,7 +5,7 @@ import { SettingField, SetterType, FieldConfig, SetterConfig } from '../../main'
import './style.less';
import { createSettingFieldView } from '../../settings-pane';
import { PopupContext, PopupPipe } from '../../popup';
-import Title from '../../title';
+import { Title } from '../../../../globals';
interface ArraySetterState {
items: SettingField[];
diff --git a/packages/plugin-settings/src/builtin-setters/object-setter/index.tsx b/packages/plugin-settings/src/builtin-setters/object-setter/index.tsx
index 32dbf25e9..36da0db58 100644
--- a/packages/plugin-settings/src/builtin-setters/object-setter/index.tsx
+++ b/packages/plugin-settings/src/builtin-setters/object-setter/index.tsx
@@ -3,7 +3,7 @@ import { Icon, Button } from '@alifd/next';
import { FieldConfig, SettingField, SetterType } from '../../main';
import { createSettingFieldView } from '../../settings-pane';
import { PopupContext, PopupPipe } from '../../popup';
-import Title from '../../title';
+import { Title } from '../../../..//globals';
import './style.less';
export default class ObjectSetter extends Component<{
diff --git a/packages/plugin-settings/src/field/index.tsx b/packages/plugin-settings/src/field/index.tsx
index a1e6e4bad..db80cf72c 100644
--- a/packages/plugin-settings/src/field/index.tsx
+++ b/packages/plugin-settings/src/field/index.tsx
@@ -1,7 +1,7 @@
import { Component } from 'react';
import classNames from 'classnames';
import { Icon } from '@alifd/next';
-import Title, { TitleContent } from '../title';
+import { Title, TitleContent } from '../../../globals';
import './index.less';
export interface FieldProps {
diff --git a/packages/plugin-settings/src/index.tsx b/packages/plugin-settings/src/index.tsx
index 36f6fc754..8ed11d15b 100644
--- a/packages/plugin-settings/src/index.tsx
+++ b/packages/plugin-settings/src/index.tsx
@@ -2,13 +2,12 @@ import React, { Component } from 'react';
import { Tab, Breadcrumb, Icon } from '@alifd/next';
import { SettingsMain, SettingField, isSettingField } from './main';
import './style.less';
-import Title from './title';
+import { Title, TipContainer } from '../../globals';
import SettingsPane, { registerSetter, createSetterContent, getSetter, createSettingFieldView } from './settings-pane';
import Node from '../../designer/src/designer/document/node/node';
import ArraySetter from './builtin-setters/array-setter';
import ObjectSetter from './builtin-setters/object-setter';
import './register-transducer';
-import { TipContainer } from './tip';
export default class SettingsMainView extends Component {
private main: SettingsMain;
diff --git a/packages/plugin-settings/src/main.ts b/packages/plugin-settings/src/main.ts
index 7c07e91f2..2cd28bbfc 100644
--- a/packages/plugin-settings/src/main.ts
+++ b/packages/plugin-settings/src/main.ts
@@ -2,7 +2,7 @@ import { EventEmitter } from 'events';
import { uniqueId } from '../../utils/unique-id';
import { ComponentMeta } from '../../designer/src/designer/component-meta';
import Node from '../../designer/src/designer/document/node/node';
-import { TitleContent } from './title';
+import { TitleContent } from '../../globals';
import { ReactElement, ComponentType as ReactComponentType, isValidElement } from 'react';
import { isReactComponent } from '../../utils/is-react';
import Designer from '../../designer/src/designer/designer';
diff --git a/packages/plugin-settings/src/register-transducer.ts b/packages/plugin-settings/src/register-transducer.ts
index 8229a62b3..5c1ba15d7 100644
--- a/packages/plugin-settings/src/register-transducer.ts
+++ b/packages/plugin-settings/src/register-transducer.ts
@@ -70,7 +70,7 @@ export function propTypeToSetter(propType: PropType): SetterType {
};
case 'element':
- case 'node':
+ case 'node': // TODO: use Mixin
return {
// slotSetter
componentName: 'NodeSetter',
@@ -156,22 +156,9 @@ export function propTypeToSetter(propType: PropType): SetterType {
const EVENT_RE = /^on[A-Z][\w]*$/;
+// parseProps
registerMetadataTransducer(metadata => {
- if (metadata.configure) {
- if (Array.isArray(metadata.configure)) {
- return {
- ...metadata,
- configure: {
- props: metadata.configure,
- },
- };
- }
- if (metadata.configure.props) {
- return metadata as any;
- }
- }
-
- const { configure = {} } = metadata;
+ const { configure } = metadata;
if (!metadata.props) {
return {
@@ -237,46 +224,7 @@ registerMetadataTransducer(metadata => {
};
});
-registerMetadataTransducer(metadata => {
- const { configure = {}, componentName } = metadata;
- const { component = {} } = configure as any;
- if (!component.nestingRule) {
- let m;
- // uri match xx.Group set subcontrolling: true, childWhiteList
- if ((m = /^(.+)\.Group$/.exec(componentName))) {
- // component.subControlling = true;
- if (!component.nestingRule) {
- component.nestingRule = {
- childWhitelist: [`${m[1]}`],
- };
- }
- }
- // uri match xx.Node set selfControlled: false, parentWhiteList
- else if ((m = /^(.+)\.Node$/.exec(componentName))) {
- // component.selfControlled = false;
- component.nestingRule = {
- parentWhitelist: [`${m[1]}`, componentName],
- };
- }
- // uri match .Item .Node .Option set parentWhiteList
- else if ((m = /^(.+)\.(Item|Node|Option)$/.exec(componentName))) {
- component.nestingRule = {
- parentWhitelist: [`${m[1]}`],
- };
- }
- }
- if (component.isModal == null && /Dialog/.test(componentName)) {
- component.isModal = true;
- }
- return {
- ...metadata,
- configure: {
- ...configure,
- component,
- },
- };
-});
-
+// addon/platform custom
registerMetadataTransducer(metadata => {
const { componentName, configure = {} } = metadata;
if (componentName === 'Leaf') {
diff --git a/packages/plugin-settings/src/settings-pane.tsx b/packages/plugin-settings/src/settings-pane.tsx
index 8d01b8c14..710210597 100644
--- a/packages/plugin-settings/src/settings-pane.tsx
+++ b/packages/plugin-settings/src/settings-pane.tsx
@@ -11,8 +11,7 @@ import {
DynamicProps,
} from './main';
import { Field, FieldGroup } from './field';
-import { TitleContent } from './title';
-import { Balloon } from '@alifd/next';
+import { TitleContent } from '../../globals';
import PopupService from './popup';
export type RegisteredSetter = {