chore(project): 添加项目配置文件和忽略规则

- 添加 Babel 配置文件支持 ES6+ 语法转换
- 添加 ESLint 忽略规则和配置文件
- 添加 Git 忽略规则文件
- 添加 Travis CI 配置文件
- 添加 1.4.2 版本变更日志文件
- 添加 Helm 图表辅助模板文件
- 添加 Helm 忽略规则文件
This commit is contained in:
2026-03-27 17:36:48 +08:00
commit c2453d6434
1703 changed files with 277582 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
const global = {
trackable: process.env.NODE_ENV === 'production',
version: process.env.GG_EDITOR_VERSION,
};
export default {
get(key) {
return global[key];
},
set(key, value) {
global[key] = value;
},
};

View File

@@ -0,0 +1,72 @@
export const FLOW_CONTAINER = 'J_FlowContainer';
export const MIND_CONTAINER = 'J_MindContainer';
export const KONI_CONTAINER = 'J_KoniContainer';
export const TOOLBAR_CONTAINER = 'J_ToolbarContainer';
export const MINIMAP_CONTAINER = 'J_MinimapContainer';
export const CONTEXT_MENU_CONTAINER = 'J_ContextMenuContainer';
export const FLOW_CLASS_NAME = 'Flow';
export const MIND_CLASS_NAME = 'Mind';
export const KONI_CLASS_NAME = 'Koni';
export const EVENT_BEFORE_ADD_PAGE = 'beforeAddPage';
export const EVENT_AFTER_ADD_PAGE = 'afterAddPage';
export const STATUS_CANVAS_SELECTED = 'canvas-selected';
export const STATUS_NODE_SELECTED = 'node-selected';
export const STATUS_EDGE_SELECTED = 'edge-selected';
export const STATUS_GROUP_SELECTED = 'group-selected';
export const STATUS_MULTI_SELECTED = 'multi-selected';
export const GRAPH_MOUSE_REACT_EVENTS = {
click: 'Click',
contextmenu: 'ContextMenu',
dblclick: 'DoubleClick',
drag: 'Drag',
dragend: 'DragEnd',
dragenter: 'DragEnter',
dragleave: 'DragLeave',
dragstart: 'DragStart',
drop: 'Drop',
mousedown: 'MouseDown',
mouseenter: 'MouseEnter',
mouseleave: 'MouseLeave',
mousemove: 'MouseMove',
mouseup: 'MouseUp',
};
export const GRAPH_OTHER_REACT_EVENTS = {
afterchange: 'onAfterChange',
afterchangesize: 'onAfterChangeSize',
afterviewportchange: 'onAfterViewportChange',
beforechange: 'onBeforeChange',
beforechangesize: 'onBeforeChangeSize',
beforeviewportchange: 'onBeforeViewportChange',
keydown: 'onKeyDown',
keyup: 'onKeyUp',
mousewheel: 'onMouseWheel',
};
export const PAGE_REACT_EVENTS = {
afteritemactived: 'onAfterItemActived',
afteriteminactivated: 'onAfterItemInactivated',
afteritemselected: 'onAfterItemSelected',
afteritemunactived: 'onAfterItemInactivated',
afteritemunselected: 'onAfterItemUnselected',
beforeitemactived: 'onBeforeItemActived',
beforeiteminactivated: 'onBeforeItemInactivated',
beforeitemselected: 'onBeforeItemSelected',
beforeitemunactived: 'onBeforeItemInactivated',
beforeitemunselected: 'onBeforeItemUnselected',
keyUpEditLabel: 'onKeyUpEditLabel',
};
export const EDITOR_REACT_EVENTS = {
aftercommandexecute: 'onAfterCommandExecute',
beforecommandexecute: 'onBeforeCommandExecute',
};
export const GRAPH_MOUSE_EVENTS = Object.keys(GRAPH_MOUSE_REACT_EVENTS);
export const GRAPH_OTHER_EVENTS = Object.keys(GRAPH_OTHER_REACT_EVENTS);
export const PAGE_EVENTS = Object.keys(PAGE_REACT_EVENTS);
export const EDITOR_EVENTS = Object.keys(EDITOR_REACT_EVENTS);

View File

@@ -0,0 +1,3 @@
import React from 'react';
export default React.createContext({});

View File

@@ -0,0 +1,18 @@
import React from 'react';
import GGEditorContext from '@common/context/GGEditorContext';
export default function (WrappedComponent) {
class InjectGGEditorContext extends React.Component {
render() {
const { forwardRef, ...rest } = this.props;
return (
<GGEditorContext.Consumer>
{context => <WrappedComponent ref={forwardRef} {...rest} {...context} />}
</GGEditorContext.Consumer>
);
}
}
return React.forwardRef((props, ref) => <InjectGGEditorContext {...props} forwardRef={ref} />);
}

View File

@@ -0,0 +1,3 @@
import React from 'react';
export default React.createContext({});

View File

@@ -0,0 +1,21 @@
class PropsAPI {
editor = null;
constructor(editor) {
this.editor = editor;
['executeCommand'].forEach((key) => {
this[key] = (...params) => this.editor[key](...params);
});
['read', 'save', 'add', 'find', 'update', 'remove', 'getSelected'].forEach((key) => {
this[key] = (...params) => this.currentPage[key](...params);
});
}
get currentPage() {
return this.editor.getCurrentPage();
}
}
export default PropsAPI;

View File

@@ -0,0 +1,18 @@
import React from 'react';
import PropsAPIContext from '@common/context/PropsAPIContext';
export default function (WrappedComponent) {
class InjectPropsAPI extends React.Component {
render() {
const { forwardRef, ...rest } = this.props;
return (
<PropsAPIContext.Consumer>
{propsAPI => <WrappedComponent ref={forwardRef} {...rest} propsAPI={propsAPI} />}
</PropsAPIContext.Consumer>
);
}
}
return React.forwardRef((props, ref) => <InjectPropsAPI {...props} forwardRef={ref} />);
}

View File

@@ -0,0 +1,16 @@
import GGEditorCore from '@gg-editor-core/bundle';
import { EVENT_BEFORE_ADD_PAGE } from '@common/constants';
import track from '@helpers/track';
import { uniqueId } from '@utils';
export default class Editor extends GGEditorCore {
constructor(options) {
super(options);
this.id = uniqueId();
this.on(EVENT_BEFORE_ADD_PAGE, ({ className }) => {
track({ c1: className });
});
}
}

View File

@@ -0,0 +1,15 @@
import React from 'react';
class Command extends React.Component {
render() {
const { name, children } = this.props;
return (
<div className="command" data-command={name}>
{children}
</div>
);
}
}
export default Command;

View File

@@ -0,0 +1,30 @@
import React from 'react';
class Menu extends React.Component {
static create = function (type) {
return class TypedMenu extends Menu {
constructor(props) {
super(props, type);
}
};
}
constructor(props, type) {
super(props);
this.type = type;
}
render() {
const { children } = this.props;
const { type } = this;
return (
<div className="menu" data-status={`${type}-selected`}>
{children}
</div>
);
}
}
export default Menu;

View File

@@ -0,0 +1,44 @@
import React from 'react';
import { pick } from '@utils';
import Editor from '@components/Base/Editor';
import { CONTEXT_MENU_CONTAINER } from '@common/constants';
import withGGEditorContext from '@common/context/GGEditorContext/withGGEditorContext';
import Menu from './Menu';
class ContextMenu extends React.Component {
contextMenu = null;
get containerId() {
const { editor } = this.props;
return `${CONTEXT_MENU_CONTAINER}_${editor.id}`;
}
componentDidMount() {
const { editor } = this.props;
this.contextMenu = new Editor.Contextmenu({
container: this.containerId,
});
editor.add(this.contextMenu);
}
render() {
const { children } = this.props;
return (
<div id={this.containerId} {...pick(this.props, ['style', 'className'])}>
{children}
</div>
);
}
}
export const NodeMenu = Menu.create('node');
export const EdgeMenu = Menu.create('edge');
export const GroupMenu = Menu.create('group');
export const MultiMenu = Menu.create('multi');
export const CanvasMenu = Menu.create('canvas');
export default withGGEditorContext(ContextMenu);

View File

@@ -0,0 +1,35 @@
import React from 'react';
import { pick } from '@utils';
class Panel extends React.Component {
static create = function (type) {
return class TypedPanel extends Panel {
constructor(props) {
super(props, type);
}
};
}
constructor(props, type) {
super(props);
this.type = type;
}
render() {
const { status, children } = this.props;
const { type } = this;
if (`${type}-selected` !== status) {
return null;
}
return (
<div {...pick(this.props, ['style', 'className'])}>
{children}
</div>
);
}
}
export default Panel;

View File

@@ -0,0 +1,58 @@
import React from 'react';
import { pick } from '@utils';
import { STATUS_CANVAS_SELECTED } from '@common/constants';
import withGGEditorContext from '@common/context/GGEditorContext/withGGEditorContext';
import Panel from './Panel';
class DetailPanel extends React.Component {
state = {
status: '',
}
constructor(props) {
super(props);
this.bindEvent();
}
bindEvent() {
const { onAfterAddPage } = this.props;
onAfterAddPage(({ page }) => {
this.setState({
status: STATUS_CANVAS_SELECTED,
});
page.on('statuschange', ({ status }) => {
this.setState({ status });
});
});
}
render() {
const { children } = this.props;
const { status } = this.state;
if (!status) {
return null;
}
return (
<div {...pick(this.props, ['style', 'className'])}>
{
React.Children.toArray(children).map(child => React.cloneElement(child, {
status,
}))
}
</div>
);
}
}
export const NodePanel = Panel.create('node');
export const EdgePanel = Panel.create('edge');
export const GroupPanel = Panel.create('group');
export const MultiPanel = Panel.create('multi');
export const CanvasPanel = Panel.create('canvas');
export default withGGEditorContext(DetailPanel);

View File

@@ -0,0 +1,38 @@
import Editor from '@components/Base/Editor';
import {
FLOW_CONTAINER,
FLOW_CLASS_NAME,
EVENT_BEFORE_ADD_PAGE,
EVENT_AFTER_ADD_PAGE,
} from '@common/constants';
import Page from '@components/Page';
import withGGEditorContext from '@common/context/GGEditorContext/withGGEditorContext';
class Flow extends Page {
static defaultProps = {
data: {
nodes: [],
edges: [],
},
};
get pageId() {
const { editor } = this.props;
return `${FLOW_CONTAINER}_${editor.id}`;
}
initPage() {
const { editor } = this.props;
editor.emit(EVENT_BEFORE_ADD_PAGE, { className: FLOW_CLASS_NAME });
this.page = new Editor.Flow(this.config);
editor.add(this.page);
editor.emit(EVENT_AFTER_ADD_PAGE, { page: this.page });
}
}
export default withGGEditorContext(Flow);

View File

@@ -0,0 +1,85 @@
import React from 'react';
import Editor from '@components/Base/Editor';
import {
EDITOR_EVENTS,
EDITOR_REACT_EVENTS,
EVENT_BEFORE_ADD_PAGE,
EVENT_AFTER_ADD_PAGE,
} from '@common/constants';
import { pick } from '@utils';
import Global from '@common/Global';
import GGEditorContext from '@common/context/GGEditorContext';
import PropsAPIContext from '@common/context/PropsAPIContext';
import PropsAPI from '@common/context/PropsAPIContext/propsAPI';
class GGEditor extends React.Component {
static setTrackable(value) {
Global.set('trackable', Boolean(value));
}
editor = null;
get currentPage() {
return this.editor.getCurrentPage();
}
constructor(props) {
super(props);
this.init();
this.bindEvent();
}
addListener = (target, eventName, handler) => {
if (typeof handler === 'function') target.on(eventName, handler);
};
handleBeforeAddPage = (func) => {
this.editor.on(EVENT_BEFORE_ADD_PAGE, func);
};
handleAfterAddPage = (func) => {
const { currentPage: page } = this;
if (page) {
func({ page });
return;
}
this.editor.on(EVENT_AFTER_ADD_PAGE, func);
};
init() {
this.editor = new Editor();
this.ggEditor = {
editor: this.editor,
onBeforeAddPage: this.handleBeforeAddPage,
onAfterAddPage: this.handleAfterAddPage,
};
this.propsAPI = new PropsAPI(this.editor);
}
bindEvent() {
EDITOR_EVENTS.forEach((event) => {
this.addListener(this.editor, [event], this.props[EDITOR_REACT_EVENTS[event]]);
});
}
componentWillUnmount() {
this.editor.destroy();
}
render() {
const { children } = this.props;
return (
<GGEditorContext.Provider value={this.ggEditor}>
<PropsAPIContext.Provider value={this.propsAPI}>
<div {...pick(this.props, ['style', 'className'])}>{children}</div>
</PropsAPIContext.Provider>
</GGEditorContext.Provider>
);
}
}
export default GGEditor;

View File

@@ -0,0 +1,43 @@
import React from 'react';
import withGGEditorContext from '@common/context/GGEditorContext/withGGEditorContext';
class Item extends React.Component {
constructor(props) {
super(props);
this.bindEvent();
}
handleMouseDown = () => {
const { type, size, shape, model } = this.props;
if (this.page) {
this.page.beginAdd(type, {
type,
size,
shape,
...model,
});
}
}
bindEvent() {
const { onAfterAddPage } = this.props;
onAfterAddPage(({ page }) => {
this.page = page;
});
}
render() {
const { src, shape, children } = this.props;
return (
<div style={{ cursor: 'pointer' }} onMouseDown={this.handleMouseDown}>
{src ? <img src={src} alt={shape} draggable={false} /> : children}
</div>
);
}
}
export default withGGEditorContext(Item);

View File

@@ -0,0 +1,46 @@
import React from 'react';
import { pick } from '@utils';
import withGGEditorContext from '@common/context/GGEditorContext/withGGEditorContext';
import Item from './Item';
class ItemPanel extends React.Component {
page = null;
constructor(props) {
super(props);
this.bindEvent();
}
handleMouseUp = () => {
this.page.cancelAdd();
}
bindEvent() {
const { onAfterAddPage } = this.props;
onAfterAddPage(({ page }) => {
this.page = page;
document.addEventListener('mouseup', this.handleMouseUp);
});
}
componentWillUnmount() {
document.removeEventListener('mouseup', this.handleMouseUp);
}
render() {
const { children } = this.props;
return (
<div id={this.containerId} {...pick(this.props, ['style', 'className'])}>
{children}
</div>
);
}
}
export { Item };
export default withGGEditorContext(ItemPanel);

View File

@@ -0,0 +1,38 @@
import Editor from '@components/Base/Editor';
import {
KONI_CONTAINER,
KONI_CLASS_NAME,
EVENT_BEFORE_ADD_PAGE,
EVENT_AFTER_ADD_PAGE,
} from '@common/constants';
import Page from '@components/Page';
import withGGEditorContext from '@common/context/GGEditorContext/withGGEditorContext';
class Koni extends Page {
static defaultProps = {
data: {
nodes: [],
edges: [],
},
};
get pageId() {
const { editor } = this.props;
return `${KONI_CONTAINER}_${editor.id}`;
}
initPage() {
const { editor } = this.props;
editor.emit(EVENT_BEFORE_ADD_PAGE, { className: KONI_CLASS_NAME });
this.page = new Editor.Koni(this.config);
editor.add(this.page);
editor.emit(EVENT_AFTER_ADD_PAGE, { page: this.page });
}
}
export default withGGEditorContext(Koni);

View File

@@ -0,0 +1,52 @@
import Editor from '@components/Base/Editor';
import {
MIND_CONTAINER,
MIND_CLASS_NAME,
EVENT_BEFORE_ADD_PAGE,
EVENT_AFTER_ADD_PAGE,
} from '@common/constants';
import Page from '@components/Page';
import withGGEditorContext from '@common/context/GGEditorContext/withGGEditorContext';
class Mind extends Page {
get pageId() {
const { editor } = this.props;
return `${MIND_CONTAINER}_${editor.id}`;
}
initPage() {
const { editor } = this.props;
editor.emit(EVENT_BEFORE_ADD_PAGE, { className: MIND_CLASS_NAME });
this.page = new Editor.Mind(this.config);
editor.add(this.page);
editor.emit(EVENT_AFTER_ADD_PAGE, { page: this.page });
}
bindEvent() {
super.bindEvent();
this.bindKeyUpEditLabel();
}
bindKeyUpEditLabel() {
const editLabel = this.page.get('labelTextArea');
editLabel.on('keyup', (e) => {
e.stopPropagation();
const item = editLabel.focusItem;
const text = editLabel.textContent;
this.page.emit('keyUpEditLabel', {
item,
text,
});
});
}
}
export default withGGEditorContext(Mind);

View File

@@ -0,0 +1,89 @@
import React from 'react';
import G6 from '@antv/g6';
import { pick } from '@utils';
import { MINIMAP_CONTAINER } from '@common/constants';
import withGGEditorContext from '@common/context/GGEditorContext/withGGEditorContext';
require('@antv/g6/build/plugin.tool.minimap');
const { Minimap: G6Minimap } = G6.Components;
class Minimap extends React.Component {
minimap = null;
get containerId() {
const { editor } = this.props;
return `${MINIMAP_CONTAINER}_${editor.id}`;
}
get currentPage() {
const { editor } = this.props;
return editor.getCurrentPage();
}
constructor(props) {
super(props);
this.bindEvent();
}
componentDidMount() {
this.init();
this.bindPage();
}
init() {
const {
container = this.containerId,
width,
height,
viewportWindowStyle,
viewportBackStyle,
} = this.props;
const { clientWidth, clientHeight } = document.getElementById(container);
this.minimap = new G6Minimap({
container,
width: width || clientWidth,
height: height || clientHeight,
viewportWindowStyle,
viewportBackStyle,
});
this.minimap.getGraph = () => this.currentPage.getGraph();
}
bindPage() {
if (!this.minimap || !this.currentPage) {
return;
}
const graph = this.currentPage.getGraph();
this.minimap.bindGraph(graph);
this.minimap.debounceRender();
}
bindEvent() {
const { onAfterAddPage } = this.props;
onAfterAddPage(() => {
this.bindPage();
});
}
render() {
const { container } = this.props;
if (container) {
return null;
}
return <div id={this.containerId} {...pick(this.props, ['style', 'className'])} />;
}
}
export default withGGEditorContext(Minimap);

View File

@@ -0,0 +1,121 @@
import React from 'react';
import { pick, merge } from '@utils';
import {
GRAPH_MOUSE_EVENTS,
GRAPH_OTHER_EVENTS,
PAGE_EVENTS,
GRAPH_MOUSE_REACT_EVENTS,
GRAPH_OTHER_REACT_EVENTS,
PAGE_REACT_EVENTS,
} from '@common/constants';
class Page extends React.Component {
page;
get pageId() {
return '';
}
config = {};
componentDidMount() {
this.init();
this.bindEvent();
this.forceUpdate();
}
shouldComponentUpdate(props) {
const { data: newData } = props;
const { data: oldData } = this.props;
const { mode: newMode } = props.graph || {};
const { mode: oldMode } = this.props.graph || {};
if (newMode !== oldMode) {
this.page.changeMode(newMode);
}
if (newData !== oldData) {
// Remove the arrow after the connection point of the compensation type
newData.edges.forEach((item) => {
if (item.type === 'Compensation') {
item.style = {
...item.style,
endArrow: false,
};
}
});
this.page.read(newData);
return true;
}
if (props.className !== this.props.className) return true;
return false;
}
get graph() {
return this.page.getGraph();
}
initPage() { }
readData() {
const { data } = this.config;
if (data) {
this.page.read(data);
}
}
addListener = (target, eventName, handler) => {
if (typeof handler === 'function') target.on(eventName, handler);
};
init() {
merge(this.config, this.props, {
graph: {
container: this.pageId,
},
});
this.initPage();
this.readData();
}
bindEvent() {
const { addListener } = this;
GRAPH_MOUSE_EVENTS.forEach((event) => {
const eventName = GRAPH_MOUSE_REACT_EVENTS[event];
addListener(this.graph, `${event}`, this.props[`on${eventName}`]);
addListener(this.graph, `node:${event}`, this.props[`onNode${eventName}`]);
addListener(this.graph, `edge:${event}`, this.props[`onEdge${eventName}`]);
addListener(this.graph, `group:${event}`, this.props[`onGroup${eventName}`]);
addListener(this.graph, `guide:${event}`, this.props[`onGuide${eventName}`]);
addListener(this.graph, `anchor:${event}`, this.props[`onAnchor${eventName}`]);
});
GRAPH_OTHER_EVENTS.forEach((event) => {
addListener(this.graph, [event], this.props[GRAPH_OTHER_REACT_EVENTS[event]]);
});
PAGE_EVENTS.forEach((event) => {
addListener(this.page, [event], this.props[PAGE_REACT_EVENTS[event]]);
});
}
render() {
const { page, pageId } = this;
const { children } = this.props;
return (
<div id={pageId} {...pick(this.props, ['style', 'className'])}>
{page ? children : null}
</div>
);
}
}
export default Page;

View File

@@ -0,0 +1,57 @@
import React from 'react';
import Editor from '@components/Base/Editor';
import { upperFirst } from '@utils';
import withGGEditorContext from '@common/context/GGEditorContext/withGGEditorContext';
class Register extends React.Component {
static create = function (type) {
class TypedRegister extends Register {
constructor(props) {
super(props, type);
}
}
return withGGEditorContext(TypedRegister);
}
constructor(props, type) {
super(props);
this.type = type;
this.bindEvent();
}
bindEvent() {
const { type } = this;
const { onBeforeAddPage } = this.props;
onBeforeAddPage(({ className }) => {
let host = Editor[className];
let keys = ['name', 'config', 'extend'];
if (type === 'command') {
host = Editor;
}
if (type === 'behaviour') {
keys = ['name', 'behaviour', 'dependences'];
}
const args = keys.map(key => this.props[key]);
host[`register${upperFirst(type)}`](...args);
});
}
render() {
return null;
}
}
export const RegisterNode = Register.create('node');
export const RegisterEdge = Register.create('edge');
export const RegisterGroup = Register.create('group');
export const RegisterGuide = Register.create('guide');
export const RegisterCommand = Register.create('command');
export const RegisterBehaviour = Register.create('behaviour');

View File

@@ -0,0 +1,41 @@
import React from 'react';
import Editor from '@components/Base/Editor';
import { pick } from '@utils';
import { TOOLBAR_CONTAINER } from '@common/constants';
import withGGEditorContext from '@common/context/GGEditorContext/withGGEditorContext';
class Toolbar extends React.Component {
toolbar = null;
get containerId() {
const { editor } = this.props;
return `${TOOLBAR_CONTAINER}_${editor.id}`;
}
constructor(props) {
super(props);
const { editor, onAfterAddPage } = props;
onAfterAddPage(() => {
this.toolbar = new Editor.Toolbar({
container: this.containerId,
});
editor.add(this.toolbar);
});
}
render() {
const { children } = this.props;
return (
<div id={this.containerId} {...pick(this.props, ['style', 'className'])}>
{children}
</div>
);
}
}
export default withGGEditorContext(Toolbar);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,34 @@
import Global from '@common/Global';
import { toQueryString } from '@utils';
const BASE_URL = 'http://gm.mmstat.com/fsp.1.1';
const track = (options) => {
const trackable = Global.get('trackable');
const version = Global.get('version');
if (!trackable) {
return;
}
const { location, navigator } = window;
const image = new Image();
const params = toQueryString({
pid: 'ggeditor',
code: '11',
msg: 'syslog',
page: `${location.protocol}//${location.host}${location.pathname}`,
hash: location.hash,
ua: navigator.userAgent,
rel: version,
...options,
});
image.src = `${BASE_URL}?${params}`;
};
export default (options) => {
setTimeout(() => {
track(options);
}, 1000);
};

View File

@@ -0,0 +1,63 @@
import Flow from '@components/Flow';
import Mind from '@components/Mind';
import Koni from '@components/Koni';
import {
RegisterNode,
RegisterEdge,
RegisterGroup,
RegisterGuide,
RegisterCommand,
RegisterBehaviour,
} from '@components/Register';
import Command from '@components/Command';
import Minimap from '@components/Minimap';
import ContextMenu, {
NodeMenu,
EdgeMenu,
GroupMenu,
MultiMenu,
CanvasMenu,
} from '@components/ContextMenu';
import Toolbar from '@components/Toolbar';
import ItemPanel, { Item } from '@components/ItemPanel';
import DetailPanel, {
NodePanel,
EdgePanel,
GroupPanel,
MultiPanel,
CanvasPanel,
} from '@components/DetailPanel';
import withPropsAPI from '@common/context/PropsAPIContext/withPropsAPI';
import GGEditor from '@components/GGEditor';
export {
Flow,
Mind,
Koni,
RegisterNode,
RegisterEdge,
RegisterGroup,
RegisterGuide,
RegisterCommand,
RegisterBehaviour,
Command,
Minimap,
NodeMenu,
EdgeMenu,
GroupMenu,
MultiMenu,
CanvasMenu,
ContextMenu,
Toolbar,
Item,
ItemPanel,
NodePanel,
EdgePanel,
GroupPanel,
MultiPanel,
CanvasPanel,
DetailPanel,
withPropsAPI,
};
export default GGEditor;

View File

@@ -0,0 +1,14 @@
import merge from 'lodash/merge';
import pick from 'lodash/pick';
import uniqueId from 'lodash/uniqueId';
import upperFirst from 'lodash/upperFirst';
const toQueryString = obj => Object.keys(obj).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`).join('&');
export {
merge,
pick,
toQueryString,
uniqueId,
upperFirst,
};