diff --git a/index.ts b/index.ts new file mode 100644 index 000000000..362b5d8b6 --- /dev/null +++ b/index.ts @@ -0,0 +1,7 @@ +import renderer from './packages/react-simulator-renderer/src/renderer'; + +if (typeof window !== 'undefined') { + (window as any).SimulatorRenderer = renderer; +} + +export default renderer; diff --git a/packages/demo/public/index.html b/packages/demo/public/index.html index 32d4da9b4..d0da148ba 100644 --- a/packages/demo/public/index.html +++ b/packages/demo/public/index.html @@ -6,13 +6,13 @@ LowCodeEngine Editor DEMO - - + + - + diff --git a/packages/demo/public/schema.json b/packages/demo/public/schema.json index 91880b822..4da399da7 100644 --- a/packages/demo/public/schema.json +++ b/packages/demo/public/schema.json @@ -1,465 +1,542 @@ { - "componentName":"Page", - "id":"node_dockcviv8fo1", - "props":{ - "ref":"outterView", - "autoLoading":true, - "style":{ - "padding":"0 5px 0 5px" - } - }, - "fileName":"test", - "dataSource":{ - "list":[ - ] - }, - "state":{ - "text":"outter", - "isShowDialog":false - }, - "css":"body {font-size: 12px;} .botton{width:100px;color:#ff00ff}", - "lifeCycles":{ - "componentDidMount":{ - "type":"JSFunction", - "value":"function() {\n console.log('did mount');\n }" + "componentsTree": [ + { + "componentName": "Page", + "id": "node_dockcviv8fo1", + "props": { + "ref": "outterView", + "autoLoading": true, + "style": { + "padding": "0 5px 0 5px" + } }, - "componentWillUnmount":{ - "type":"JSFunction", - "value":"function() {\n console.log('will umount');\n }" - } - }, - "methods":{ - "testFunc":{ - "type":"JSFunction", - "value":"function() {\n console.log('test func');\n }" + "fileName": "a", + "dataSource": { + "list": [] }, - "onClick":{ - "type":"JSFunction", - "value":"function(){\n this.setState({\n isShowDialog:true\n })\n\t}" - } - }, - "children":[ - { - "componentName":"Box", - "id":"node_dockcy8n9xed", - "props":{ - "style":{ - "backgroundColor":"rgba(31,56,88,0.1)", - "padding":"12px 12px 12px 12px" - } + "state": { + "text": "outter", + "isShowDialog": false + }, + "css": "body {font-size: 12px;} .botton{width:100px;color:#ff00ff}", + "lifeCycles": { + "componentDidMount": { + "type": "JSFunction", + "value": "function() {\n console.log('did mount');\n }" + }, + "componentWillUnmount": { + "type": "JSFunction", + "value": "function() {\n console.log('will umount');\n }" + } + }, + "methods": { + "testFunc": { + "type": "JSFunction", + "value": "function() {\n console.log('test func');\n }" + }, + "onClick": { + "type": "JSFunction", + "value": "function(){\n this.setState({\n isShowDialog:true\n })\n\t}" + } + }, + "children": [ + { + "componentName": "Box", + "id": "node_dockcy8n9xed", + "props": { + "style": { + "backgroundColor": "rgba(31,56,88,0.1)", + "padding": "12px 12px 12px 12px" + } }, - "children":[ - { - "componentName":"Box", - "id":"node_dockcy8n9xee", - "props":{ - "style":{ - "padding":"12px 12px 12px 12px", - "backgroundColor":"#ffffff" - } - }, - "children":[ - { - "componentName":"Breadcrumb", - "id":"node_dockcy8n9xef", - "props":{ - "prefix":"next-", - "maxNode":100, - "component":"nav" - }, - "children":[ - { - "componentName":"Breadcrumb.Item", - "id":"node_dockcy8n9xeg", - "props":{ - "prefix":"next-", - "children":[ - "首页"] - } - }, - { - "componentName":"Breadcrumb.Item", - "id":"node_dockcy8n9xei", - "props":{ - "prefix":"next-", - "children":[ - "品质中台"] - } - }, - { - "componentName":"Breadcrumb.Item", - "id":"node_dockcy8n9xek", - "props":{ - "prefix":"next-", - "children":[ - "商家品质页面管理"] - } - }, - { - "componentName":"Breadcrumb.Item", - "id":"node_dockcy8n9xem", - "props":{ - "prefix":"next-", - "children":[ - "质检知识条配置"] - } - }] - }] + "children": [ + { + "componentName": "Box", + "id": "node_dockcy8n9xee", + "props": { + "style": { + "padding": "12px 12px 12px 12px", + "backgroundColor": "#ffffff" + } }, - { - "componentName":"Box", - "id":"node_dockcy8n9xeo", - "props":{ - "style":{ - "marginTop":"12px", - "backgroundColor":"#ffffff" - } + "children": [ + { + "componentName": "Breadcrumb", + "id": "node_dockcy8n9xef", + "props": { + "prefix": "next-", + "maxNode": 100, + "component": "nav" }, - "children":[ - { - "componentName":"Form", - "id":"node_dockcy8n9xep", - "props":{ - "inline":true, - "style":{ - "marginTop":"12px", - "marginRight":"12px", - "marginLeft":"12px" - }, - "__events":[ - ] - }, - "children":[ - { - "componentName":"Form.Item", - "id":"node_dockcy8n9xeq", - "props":{ - "style":{ - "marginBottom":"0" - }, - "label":"类目名:" - }, - "children":[ - { - "componentName":"Select", - "id":"node_dockcy8n9xer", - "props":{ - "mode":"single", - "hasArrow":true, - "cacheValue":true, - "style":{ - "width":"150px" - } - } - }] - }, - { - "componentName":"Form.Item", - "id":"node_dockcy8n9xes", - "props":{ - "style":{ - "marginBottom":"0" - }, - "label":"项目类型:" - }, - "children":[ - { - "componentName":"Select", - "id":"node_dockcy8n9xet", - "props":{ - "mode":"single", - "hasArrow":true, - "cacheValue":true, - "style":{ - "width":"200px" - } - } - }] - }, - { - "componentName":"Form.Item", - "id":"node_dockcy8n9xeu", - "props":{ - "style":{ - "marginBottom":"0" - }, - "label":"项目 ID:" - }, - "children":[ - { - "componentName":"Input", - "id":"node_dockcy8n9xev", - "props":{ - "hasBorder":true, - "size":"medium", - "autoComplete":"off", - "style":{ - "width":"200px" - } - } - }] - }, - { - "componentName":"Button.Group", - "id":"node_dockcy8n9xew", - "props":{ - }, - "children":[ - { - "componentName":"Button", - "id":"node_dockcy8n9xex", - "props":{ - "type":"primary", - "style":{ - "margin":"0 5px 0 5px" - }, - "htmlType":"submit", - "children":[ - { - "componentName":"Icon", - "id":"node_dockcy8n9xey", - "props":{ - "type":"success" - } - }, - "搜索"] - } - }, - { - "componentName":"Button", - "id":"node_dockcy8n9xe10", - "props":{ - "type":"normal", - "style":{ - "margin":"0 5px 0 5px" - }, - "htmlType":"reset", - "children":[ - "清空"] - } - }] - }] - }] - }, - { - "componentName":"Box", - "id":"node_dockcy8n9xe12", - "props":{ - "style":{ - "justifyContent":"flex-end", - "display":"flex", - "backgroundColor":"#ffffff", - "flexDirection":"row", - "paddingRight":"24px" + "children": [ + { + "componentName": "Breadcrumb.Item", + "id": "node_dockcy8n9xeg", + "props": { + "prefix": "next-", + "children": ["首页"] } - }, - "children":[ - { - "componentName":"Button", - "id":"node_dockcy8n9xe13", - "props":{ - "prefix":"next-", - "type":"primary", - "size":"medium", - "htmlType":"button", - "component":"button", - "style":{ - "width":"100px" - }, - "children":["新建配置"], - "events":{ - "onClick":{ - "type":"JSFunction", - "value":"function(){ this.onClick() }", - "__eventData":{ - "type":"componentEvent", - "name":"onClick", - "relatedEventName":"onClick" - } - } - }, - "__events":[ - { - "type":"componentEvent", - "name":"onClick", - "relatedEventName":"onClick" - }], - "onClick":{ - "type":"JSFunction", - "value":"function(){ this.onClick() }" - } - } - }] - }, - { - "componentName":"Box", - "id":"node_dockcy8n9xe15", - "props":{ - "style":{ - "backgroundColor":"#ffffff" + }, + { + "componentName": "Breadcrumb.Item", + "id": "node_dockcy8n9xei", + "props": { + "prefix": "next-", + "children": ["品质中台"] } - }, - "children":[ - { - "componentName":"Table", - "id":"node_dockcy8n9xe16", - "props":{ - "dataSource":[ - { - "firstCategory":"其他", - "secondCategory":"新品预览", - "leafCategory":"", - "projectType":"标识判断", - "projectId":"", - "title":"其他类目->新品预览类目类型知识库", - "url":"其他", - "operation":"编辑" - }, - { - "firstCategory":"其他", - "secondCategory":"新品预览", - "leafCategory":"", - "projectType":"", - "projectId":"1", - "title":"其他类目->新品预览项目Id知识库", - "url":"其他", - "operation":"编辑" - }], - "size":"medium", - "prefix":"next-", - "hasBorder":true, - "hasHeader":true, - "isZebra":false, - "loading":false, - "expandedIndexSimulate":false, - "primaryKey":"id", - "locale":"zhCN.Table", - "crossline":false, - "style":{ - "margin":"24px 12px 24px 12px" - } - }, - "children":[ - { - "componentName":"Table.Column", - "id":"node_dockcy8n9xe17", - "props":{ - "title":"一级类目", - "dataIndex":"firstCategory" - } - }, - { - "componentName":"Table.Column", - "id":"node_dockcy8n9xe18", - "props":{ - "title":"二级类目", - "dataIndex":"secondCategory" - } - }, - { - "componentName":"Table.Column", - "id":"node_dockcy8n9xe19", - "props":{ - "title":"叶子类目", - "dataIndex":"leafCategory" - } - }, - { - "componentName":"Table.Column", - "id":"node_dockcy8n9xe1a", - "props":{ - "title":"项目类型", - "dataIndex":"projectType" - } - }, - { - "componentName":"Table.Column", - "id":"node_dockcy8n9xe1b", - "props":{ - "title":"项目 ID", - "dataIndex":"projectId" - } - }, - { - "componentName":"Table.Column", - "id":"node_dockcy8n9xe1c", - "props":{ - "title":"知识条标题", - "dataIndex":"title" - } - }, - { - "componentName":"Table.Column", - "id":"node_dockcy8n9xe1d", - "props":{ - "title":"知识条链接", - "dataIndex":"url" - } - }, - { - "componentName":"Table.Column", - "id":"node_dockcy8n9xe1e", - "props":{ - "title":"操作", - "dataIndex":"operation" - } - }] - }] - }, - { - "componentName":"Box", - "id":"node_dockcy8n9xe1f", - "props":{ - "style":{ - "backgroundColor":"#ffffff", - "paddingBottom":"24px" + }, + { + "componentName": "Breadcrumb.Item", + "id": "node_dockcy8n9xek", + "props": { + "prefix": "next-", + "children": ["商家品质页面管理"] } - }, - "children":[ - { - "componentName":"Pagination", - "id":"node_dockcy8n9xe1g", - "props":{ - "prefix":"next-", - "type":"normal", - "shape":"normal", - "size":"medium", - "defaultCurrent":1, - "total":100, - "pageShowCount":5, - "pageSize":10, - "pageSizePosition":"start", - "showJump":true, - "style":{ - "display":"flex", - "justifyContent":"flex-end" - } - } - }] - }] - }, - { - "componentName":"Dialog", - "id":"node_dockcy8n9xe1h", - "props":{ - "prefix":"next-", - "footerAlign":"right", - "footerActions":[ - "ok", - "cancel"], - "closeable":"esc,close", - "hasMask":true, - "align":"cc cc", - "minMargin":40, - "visible":{ - "type":"JSExpression", - "value":"this.state.isShowDialog" - }, - - "title":"标题", - - "events":[ + }, + { + "componentName": "Breadcrumb.Item", + "id": "node_dockcy8n9xem", + "props": { + "prefix": "next-", + "children": ["质检知识条配置"] + } + } + ] + } ] + }, + { + "componentName": "Box", + "id": "node_dockcy8n9xeo", + "props": { + "style": { + "marginTop": "12px", + "backgroundColor": "#ffffff" + } + }, + "children": [ + { + "componentName": "Form", + "id": "node_dockcy8n9xep", + "props": { + "inline": true, + "style": { + "marginTop": "12px", + "marginRight": "12px", + "marginLeft": "12px" + }, + "__events": [] + }, + "children": [ + { + "componentName": "Form.Item", + "id": "node_dockcy8n9xeq", + "props": { + "style": { + "marginBottom": "0" + }, + "label": "类目名:" + }, + "children": [ + { + "componentName": "Select", + "id": "node_dockcy8n9xer", + "props": { + "mode": "single", + "hasArrow": true, + "cacheValue": true, + "style": { + "width": "150px" + } + } + } + ] + }, + { + "componentName": "Form.Item", + "id": "node_dockcy8n9xes", + "props": { + "style": { + "marginBottom": "0" + }, + "label": "项目类型:" + }, + "children": [ + { + "componentName": "Select", + "id": "node_dockcy8n9xet", + "props": { + "mode": "single", + "hasArrow": true, + "cacheValue": true, + "style": { + "width": "200px" + } + } + } + ] + }, + { + "componentName": "Form.Item", + "id": "node_dockcy8n9xeu", + "props": { + "style": { + "marginBottom": "0" + }, + "label": "项目 ID:" + }, + "children": [ + { + "componentName": "Input", + "id": "node_dockcy8n9xev", + "props": { + "hasBorder": true, + "size": "medium", + "autoComplete": "off", + "style": { + "width": "200px" + } + } + } + ] + }, + { + "componentName": "Button.Group", + "id": "node_dockcy8n9xew", + "props": {}, + "children": [ + { + "componentName": "Button", + "id": "node_dockcy8n9xex", + "props": { + "type": "primary", + "style": { + "margin": "0 5px 0 5px" + }, + "htmlType": "submit", + "children": [ + { + "componentName": "Icon", + "id": "node_dockcy8n9xey", + "props": { + "type": "success" + } + }, + "搜索" + ] + } + }, + { + "componentName": "Button", + "id": "node_dockcy8n9xe10", + "props": { + "type": "normal", + "style": { + "margin": "0 5px 0 5px" + }, + "htmlType": "reset", + "children": ["清空"] + } + } + ] + } + ] + } + ] + }, + { + "componentName": "Box", + "id": "node_dockcy8n9xe12", + "props": { + "style": { + "justifyContent": "flex-end", + "display": "flex", + "backgroundColor": "#ffffff", + "flexDirection": "row", + "paddingRight": "24px" + } + }, + "children": [ + { + "componentName": "Button", + "id": "node_dockcy8n9xe13", + "props": { + "prefix": "next-", + "type": "primary", + "size": "medium", + "htmlType": "button", + "component": "button", + "style": { + "width": "100px" + }, + "children": ["新建配置"], + "events": { + "onClick": { + "type": "JSFunction", + "value": "function(){ this.onClick() }", + "__eventData": { + "type": "componentEvent", + "name": "onClick", + "relatedEventName": "onClick" + } + } + }, + "__events": [ + { + "type": "componentEvent", + "name": "onClick", + "relatedEventName": "onClick" + } + ], + "onClick": { + "type": "JSFunction", + "value": "function(){ this.onClick() }" + } + } + } + ] + }, + { + "componentName": "Box", + "id": "node_dockcy8n9xe15", + "props": { + "style": { + "backgroundColor": "#ffffff" + } + }, + "children": [ + { + "componentName": "Table", + "id": "node_dockcy8n9xe16", + "props": { + "dataSource": [ + { + "firstCategory": "其他", + "secondCategory": "新品预览", + "leafCategory": "", + "projectType": "标识判断", + "projectId": "", + "title": "其他类目->新品预览类目类型知识库", + "url": "其他", + "operation": "编辑" + }, + { + "firstCategory": "其他", + "secondCategory": "新品预览", + "leafCategory": "", + "projectType": "", + "projectId": "1", + "title": "其他类目->新品预览项目Id知识库", + "url": "其他", + "operation": "编辑" + } + ], + "size": "medium", + "prefix": "next-", + "hasBorder": true, + "hasHeader": true, + "isZebra": false, + "loading": false, + "expandedIndexSimulate": false, + "primaryKey": "id", + "locale": "zhCN.Table", + "crossline": false, + "style": { + "margin": "24px 12px 24px 12px" + } + }, + "children": [ + { + "componentName": "Table.Column", + "id": "node_dockcy8n9xe17", + "props": { + "title": "一级类目", + "dataIndex": "firstCategory" + } + }, + { + "componentName": "Table.Column", + "id": "node_dockcy8n9xe18", + "props": { + "title": "二级类目", + "dataIndex": "secondCategory" + } + }, + { + "componentName": "Table.Column", + "id": "node_dockcy8n9xe19", + "props": { + "title": "叶子类目", + "dataIndex": "leafCategory" + } + }, + { + "componentName": "Table.Column", + "id": "node_dockcy8n9xe1a", + "props": { + "title": "项目类型", + "dataIndex": "projectType" + } + }, + { + "componentName": "Table.Column", + "id": "node_dockcy8n9xe1b", + "props": { + "title": "项目 ID", + "dataIndex": "projectId" + } + }, + { + "componentName": "Table.Column", + "id": "node_dockcy8n9xe1c", + "props": { + "title": "知识条标题", + "dataIndex": "title" + } + }, + { + "componentName": "Table.Column", + "id": "node_dockcy8n9xe1d", + "props": { + "title": "知识条链接", + "dataIndex": "url" + } + }, + { + "componentName": "Table.Column", + "id": "node_dockcy8n9xe1e", + "props": { + "title": "操作", + "dataIndex": "operation" + } + } + ] + } + ] + }, + { + "componentName": "Box", + "id": "node_dockcy8n9xe1f", + "props": { + "style": { + "backgroundColor": "#ffffff", + "paddingBottom": "24px" + } + }, + "children": [ + { + "componentName": "Pagination", + "id": "node_dockcy8n9xe1g", + "props": { + "prefix": "next-", + "type": "normal", + "shape": "normal", + "size": "medium", + "defaultCurrent": 1, + "total": 100, + "pageShowCount": 5, + "pageSize": 10, + "pageSizePosition": "start", + "showJump": true, + "style": { + "display": "flex", + "justifyContent": "flex-end" + } + } + } + ] + } + ] + }, + { + "componentName": "Dialog", + "id": "node_dockcy8n9xe1h", + "props": { + "prefix": "next-", + "footerAlign": "right", + "footerActions": ["ok", "cancel"], + "closeable": "esc,close", + "hasMask": true, + "align": "cc cc", + "minMargin": 40, + "visible": { + "type": "JSExpression", + "value": "this.state.isShowDialog" + }, + + "title": "标题", + + "events": [] } - }] + } + ] + }, + { + "componentName": "Page", + "props": { + "ref": "outterView", + "autoLoading": true, + "style": { + "padding": "0 5px 0 5px" + } + }, + "fileName": "b", + "dataSource": { + "list": [] + }, + "state": { + "text": "outter", + "isShowDialog": false + }, + "css": "body {font-size: 12px;} .botton{width:100px;color:#ff00ff}", + "lifeCycles": { + "componentDidMount": { + "type": "JSFunction", + "value": "function() {\n console.log('did mount');\n }" + }, + "componentWillUnmount": { + "type": "JSFunction", + "value": "function() {\n console.log('will umount');\n }" + } + }, + "methods": { + "testFunc": { + "type": "JSFunction", + "value": "function() {\n console.log('test func');\n }" + }, + "onClick": { + "type": "JSFunction", + "value": "function(){\n this.setState({\n isShowDialog:true\n })\n\t}" + } + }, + "children": [ + { + "componentName": "Button", + "id": "node_dockcy8n9xe13", + "props": { + "prefix": "next-", + "type": "primary", + "size": "medium", + "htmlType": "button", + "component": "button", + "style": { + "width": "100px" + }, + "children": ["新建配置"], + "__events": [ + { + "type": "componentEvent", + "name": "onClick", + "relatedEventName": "onClick" + } + ], + "onClick": { + "type": "JSFunction", + "value": "function(){ this.utils.router.push('/a') }" + } + } + } + ] + } + ] } diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx index eb3084bc5..8fb2dd6c8 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx @@ -58,6 +58,7 @@ export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> { @computed get current() { const host = this.props.host; const doc = host.currentDocument; + console.info(doc); if (!doc) { return null; } diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 0b9fcb6cb..fcd674b31 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -376,6 +376,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost this.createDocument(data))[0].open(); } else { // auto open should be string of fileName this.open(autoOpen); diff --git a/packages/plugin-designer/src/index.tsx b/packages/plugin-designer/src/index.tsx index aac7dab28..00af01548 100644 --- a/packages/plugin-designer/src/index.tsx +++ b/packages/plugin-designer/src/index.tsx @@ -53,7 +53,7 @@ export default class DesignerPlugin extends PureComponent { - designer.project.open(schema); + designer.project.load(schema, true); }); }; diff --git a/packages/react-simulator-renderer/src/renderer-view.tsx b/packages/react-simulator-renderer/src/renderer-view.tsx index a3eac58d9..ffbe14121 100644 --- a/packages/react-simulator-renderer/src/renderer-view.tsx +++ b/packages/react-simulator-renderer/src/renderer-view.tsx @@ -41,21 +41,32 @@ export default class SimulatorRendererView extends Component<{ rendererContainer return ( - - {rendererContainer.documentInstances.map((instance) => ( - } - /> - ))} - + ); } } +@observer +export class Routes extends Component<{ rendererContainer: SimulatorRendererContainer }> { + render() { + const { rendererContainer } = this.props; + return ( + + {rendererContainer.documentInstances.map((instance) => { + return ( + } + /> + ); + })} + + ); + } +} function ucfirst(s: string) { return s.charAt(0).toUpperCase() + s.substring(1); } diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts index 9c5edc171..b8dcf6f74 100644 --- a/packages/react-simulator-renderer/src/renderer.ts +++ b/packages/react-simulator-renderer/src/renderer.ts @@ -13,6 +13,7 @@ import { BuiltinSimulatorRenderer, NodeInstance, Component, DocumentModel, Node import { createMemoryHistory, MemoryHistory } from 'history'; import Slot from './builtin-components/slot'; import Leaf from './builtin-components/leaf'; +import { withQueryParams, parseQuery } from './utils/url'; export class DocumentInstance { private instancesMap = new Map(); @@ -154,7 +155,8 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { this._device = host.device; }); const documentInstanceMap = new Map(); - host.autorun(() => { + let initialEntry = '/'; + host.autorun(({ firstRun }) => { this._documentInstances = host.project.documents.map((doc) => { let inst = documentInstanceMap.get(doc.id); if (!inst) { @@ -163,16 +165,23 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { } return inst; }); - console.info('instances', this._documentInstances); + const path = host.project.currentDocument + ? documentInstanceMap.get(host.project.currentDocument.id)!.path + : '/'; + if (firstRun) { + initialEntry = path; + } else { + if (this.history.location.pathname !== path) { + this.history.replace(path); + } + } }); - const initialEntry = host.project.currentDocument - ? documentInstanceMap.get(host.project.currentDocument.id)!.path - : '/'; - this.history = createMemoryHistory({ + const history = createMemoryHistory({ initialEntries: [initialEntry], }); - this.history.listen((location, action) => { - console.info(location); + this.history = history; + history.listen((location, action) => { + host.project.open(location.pathname.substr(1)); }); host.componentsConsumer.consume(async (componentsAsset) => { if (componentsAsset) { @@ -180,17 +189,27 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { this.buildComponents(); } }); - host.injectionConsumer.consume((data) => { - // sync utils, i18n, contants,... config - this._appContext = { - utils: { - router: { - push() {}, - replace() {}, + this._appContext = { + utils: { + router: { + push(path: string, params?: object) { + history.push(withQueryParams(path, params)); + }, + replace(path: string, params?: object) { + history.replace(withQueryParams(path, params)); }, }, - constants: {}, - }; + legaoBuiltins: { + getUrlParams() { + const search = history.location.search; + return parseQuery(search); + } + } + }, + constants: {}, + }; + host.injectionConsumer.consume((data) => { + // sync utils, i18n, contants,... config }); } diff --git a/packages/react-simulator-renderer/src/utils/url.ts b/packages/react-simulator-renderer/src/utils/url.ts new file mode 100644 index 000000000..d720323b3 --- /dev/null +++ b/packages/react-simulator-renderer/src/utils/url.ts @@ -0,0 +1,74 @@ +/** + * Parse queryString + * @param {String} str '?q=query&b=test' + * @return {Object} + */ +export function parseQuery(str: string): object { + const ret: any = {}; + + if (typeof str !== 'string') { + return ret; + } + + const s = str.trim().replace(/^(\?|#|&)/, ''); + + if (!s) { + return ret; + } + + s.split('&').forEach((param) => { + const parts = param.replace(/\+/g, ' ').split('='); + let key = parts.shift()!; + let val: any = parts.length > 0 ? parts.join('=') : undefined; + + key = decodeURIComponent(key); + + val = val === undefined ? null : decodeURIComponent(val); + + if (ret[key] === undefined) { + ret[key] = val; + } else if (Array.isArray(ret[key])) { + ret[key].push(val); + } else { + ret[key] = [ret[key], val]; + } + }); + + return ret; +} + +/** + * Stringify object to query parammeters + * @param {Object} obj + * @return {String} + */ +export function stringifyQuery(obj: any): string { + const param: string[] = []; + Object.keys(obj).forEach((key) => { + let value = obj[key]; + if (value && typeof value === 'object') { + value = JSON.stringify(value); + } + param.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`); + }); + return param.join('&'); +} + +export function uriEncode(uri: string) { + return encodeURIComponent(uri); +} + +export function uriDecode(uri: string) { + return decodeURIComponent(uri); +} + +export function withQueryParams(url: string, params?: object) { + const queryStr = params ? stringifyQuery(params) : ''; + if (queryStr === '') { + return url; + } + const urlSplit = url.split('#'); + const hash = urlSplit[1] ? `#${urlSplit[1]}` : ''; + const urlWithoutHash = urlSplit[0]; + return `${urlWithoutHash}${~urlWithoutHash.indexOf('?') ? '&' : '?'}${queryStr}${hash}`; +} diff --git a/packages/react-simulator-renderer/tsconfig.json b/packages/react-simulator-renderer/tsconfig.json index c37b76ecc..9519ab847 100644 --- a/packages/react-simulator-renderer/tsconfig.json +++ b/packages/react-simulator-renderer/tsconfig.json @@ -4,6 +4,6 @@ "outDir": "lib" }, "include": [ - "./src/" + "./src/", "../../index.ts" ] }