@gant-lowcode/plugin-code-generator 1.0.10 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/{dist → es}/components/code-gen-action/index.d.ts +2 -1
- package/es/components/code-gen-action/index.js +330 -0
- package/es/components/code-gen-action/index.less +20 -0
- package/es/components/code-gen-preview/fixPreviewCode.js +100 -0
- package/{dist → es}/components/code-gen-preview/index.d.ts +3 -2
- package/es/components/code-gen-preview/index.js +5 -0
- package/es/components/code-gen-preview/index.less +16 -0
- package/{dist → es}/components/code-gen-result/index.d.ts +2 -2
- package/es/components/code-gen-result/index.js +207 -0
- package/es/components/code-gen-result/index.less +20 -0
- package/{dist → es}/components/codesandbox-preview/index.d.ts +2 -1
- package/es/components/codesandbox-preview/index.js +192 -0
- package/es/components/codesandbox-preview/index.less +18 -0
- package/{dist → es}/components/file-tree/index.d.ts +3 -2
- package/es/components/file-tree/index.js +162 -0
- package/es/components/file-tree/index.less +54 -0
- package/{dist → es}/components/file-type-icon/index.d.ts +2 -2
- package/es/components/file-type-icon/index.js +12 -0
- package/es/components/file-type-icon/index.less +77 -0
- package/{dist → es}/components/sources-view/index.d.ts +2 -1
- package/es/components/sources-view/index.js +128 -0
- package/es/components/sources-view/index.less +12 -0
- package/{dist → es}/index.d.ts +3 -4
- package/es/index.js +67 -0
- package/es/style.js +9 -0
- package/{dist → es}/types/index.d.ts +3 -3
- package/es/types/index.js +1 -0
- package/lib/components/code-gen-action/index.d.ts +7 -0
- package/lib/components/code-gen-action/index.js +336 -0
- package/lib/components/code-gen-action/index.less +20 -0
- package/lib/components/code-gen-preview/fixPreviewCode.d.ts +2 -0
- package/lib/components/code-gen-preview/fixPreviewCode.js +105 -0
- package/lib/components/code-gen-preview/index.d.ts +9 -0
- package/lib/components/code-gen-preview/index.js +9 -0
- package/lib/components/code-gen-preview/index.less +16 -0
- package/lib/components/code-gen-result/index.d.ts +14 -0
- package/lib/components/code-gen-result/index.js +215 -0
- package/lib/components/code-gen-result/index.less +20 -0
- package/lib/components/codesandbox-preview/index.d.ts +4 -0
- package/lib/components/codesandbox-preview/index.js +199 -0
- package/lib/components/codesandbox-preview/index.less +18 -0
- package/lib/components/file-tree/index.d.ts +21 -0
- package/lib/components/file-tree/index.js +170 -0
- package/lib/components/file-tree/index.less +54 -0
- package/lib/components/file-type-icon/index.d.ts +6 -0
- package/lib/components/file-type-icon/index.js +17 -0
- package/lib/components/file-type-icon/index.less +77 -0
- package/lib/components/sources-view/index.d.ts +8 -0
- package/lib/components/sources-view/index.js +135 -0
- package/lib/components/sources-view/index.less +12 -0
- package/lib/index.d.ts +27 -0
- package/lib/index.js +74 -0
- package/lib/style.js +9 -0
- package/lib/types/index.d.ts +17 -0
- package/lib/types/index.js +3 -0
- package/package.json +27 -19
- package/dist/components/code-gen-action/index.css +0 -18
- package/dist/components/code-gen-action/index.js +0 -203
- package/dist/components/code-gen-preview/fixPreviewCode.js +0 -119
- package/dist/components/code-gen-preview/index.css +0 -18
- package/dist/components/code-gen-preview/index.js +0 -9
- package/dist/components/code-gen-result/index.css +0 -18
- package/dist/components/code-gen-result/index.js +0 -147
- package/dist/components/codesandbox-preview/index.css +0 -17
- package/dist/components/codesandbox-preview/index.js +0 -147
- package/dist/components/file-tree/index.css +0 -55
- package/dist/components/file-tree/index.js +0 -138
- package/dist/components/file-type-icon/index.css +0 -73
- package/dist/components/file-type-icon/index.js +0 -10
- package/dist/components/sources-view/index.css +0 -11
- package/dist/components/sources-view/index.js +0 -128
- package/dist/index.js +0 -50
- package/dist/types/index.js +0 -1
- /package/{dist → es}/components/code-gen-preview/fixPreviewCode.d.ts +0 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import _Empty from "antd/es/empty";
|
|
3
|
+
import _message from "antd/es/message";
|
|
4
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
5
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
6
|
+
import React, { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
|
7
|
+
import FileSaver from "file-saver";
|
|
8
|
+
import JSZip from "jszip";
|
|
9
|
+
// import { CodeGenPreview } from "../code-gen-preview/index";
|
|
10
|
+
import { SourcesView } from "../sources-view/index";
|
|
11
|
+
import "./index.less";
|
|
12
|
+
export var CodeGenResult = /*#__PURE__*/forwardRef(function CodeGenResult(_ref, ref) {
|
|
13
|
+
var result = _ref.result,
|
|
14
|
+
schema = _ref.schema;
|
|
15
|
+
var _useState = useState({
|
|
16
|
+
expandedKeys: ["sources", "preview"]
|
|
17
|
+
}),
|
|
18
|
+
paneState = _useState[0],
|
|
19
|
+
setPaneState = _useState[1];
|
|
20
|
+
var _useState2 = useState(null),
|
|
21
|
+
gravityCode = _useState2[0],
|
|
22
|
+
setGravityCode = _useState2[1];
|
|
23
|
+
var _useState3 = useState(0),
|
|
24
|
+
refresh = _useState3[0],
|
|
25
|
+
setRefresh = _useState3[1];
|
|
26
|
+
useEffect(function () {
|
|
27
|
+
console.log("--result, schema", result, schema);
|
|
28
|
+
setGravityCode(convertCodeGenResult(result, schema));
|
|
29
|
+
}, [result]);
|
|
30
|
+
var codeZip = /*#__PURE__*/function () {
|
|
31
|
+
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
32
|
+
var zip;
|
|
33
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
34
|
+
while (1) switch (_context.prev = _context.next) {
|
|
35
|
+
case 0:
|
|
36
|
+
zip = new JSZip();
|
|
37
|
+
Object.values((gravityCode === null || gravityCode === void 0 ? void 0 : gravityCode.modules) || {}).forEach(function (file) {
|
|
38
|
+
zip.file(file.fpath.replace(/^\/+/, ""), file.code);
|
|
39
|
+
});
|
|
40
|
+
_context.next = 4;
|
|
41
|
+
return zip.generateAsync({
|
|
42
|
+
type: "blob"
|
|
43
|
+
});
|
|
44
|
+
case 4:
|
|
45
|
+
return _context.abrupt("return", _context.sent);
|
|
46
|
+
case 5:
|
|
47
|
+
case "end":
|
|
48
|
+
return _context.stop();
|
|
49
|
+
}
|
|
50
|
+
}, _callee);
|
|
51
|
+
}));
|
|
52
|
+
return function codeZip() {
|
|
53
|
+
return _ref2.apply(this, arguments);
|
|
54
|
+
};
|
|
55
|
+
}();
|
|
56
|
+
useImperativeHandle(ref, function () {
|
|
57
|
+
return {
|
|
58
|
+
codeZip: codeZip
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
if (!result) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
var handleDownloadSources = /*#__PURE__*/function () {
|
|
65
|
+
var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(e) {
|
|
66
|
+
var content;
|
|
67
|
+
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
68
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
69
|
+
case 0:
|
|
70
|
+
_context2.prev = 0;
|
|
71
|
+
e.preventDefault();
|
|
72
|
+
e.stopPropagation();
|
|
73
|
+
_context2.next = 5;
|
|
74
|
+
return codeZip();
|
|
75
|
+
case 5:
|
|
76
|
+
content = _context2.sent;
|
|
77
|
+
FileSaver.saveAs(content, "gant-lowcode-generated-sources.zip");
|
|
78
|
+
_context2.next = 13;
|
|
79
|
+
break;
|
|
80
|
+
case 9:
|
|
81
|
+
_context2.prev = 9;
|
|
82
|
+
_context2.t0 = _context2["catch"](0);
|
|
83
|
+
console.log("failed to download sources: ", _context2.t0);
|
|
84
|
+
_message.error("下载失败!");
|
|
85
|
+
case 13:
|
|
86
|
+
case "end":
|
|
87
|
+
return _context2.stop();
|
|
88
|
+
}
|
|
89
|
+
}, _callee2, null, [[0, 9]]);
|
|
90
|
+
}));
|
|
91
|
+
return function handleDownloadSources(_x) {
|
|
92
|
+
return _ref3.apply(this, arguments);
|
|
93
|
+
};
|
|
94
|
+
}();
|
|
95
|
+
console.log("--gravityCode", gravityCode);
|
|
96
|
+
|
|
97
|
+
// const items: TabsProps["items"] = [
|
|
98
|
+
// {
|
|
99
|
+
// key: "sources",
|
|
100
|
+
// label: (
|
|
101
|
+
// <span>
|
|
102
|
+
// 出码生成的源代码{" "}
|
|
103
|
+
// <a href="javascript:void(0)" onClick={handleDownloadSources}>
|
|
104
|
+
// 导出/下载 zip 包
|
|
105
|
+
// </a>
|
|
106
|
+
// </span>
|
|
107
|
+
// ),
|
|
108
|
+
// children: gravityCode != null && (
|
|
109
|
+
// <SourcesView code={gravityCode} onCodeChange={setGravityCode} />
|
|
110
|
+
// ),
|
|
111
|
+
// },
|
|
112
|
+
// {
|
|
113
|
+
// key: "preview",
|
|
114
|
+
// label: (
|
|
115
|
+
// <span>
|
|
116
|
+
// 在线预览{" "}
|
|
117
|
+
// <a
|
|
118
|
+
// href="#refresh"
|
|
119
|
+
// onClick={(e) => {
|
|
120
|
+
// e.preventDefault();
|
|
121
|
+
// e.stopPropagation();
|
|
122
|
+
// setRefresh(Date.now());
|
|
123
|
+
// }}
|
|
124
|
+
// >
|
|
125
|
+
// 刷新
|
|
126
|
+
// </a>
|
|
127
|
+
// </span>
|
|
128
|
+
// ),
|
|
129
|
+
// children: (
|
|
130
|
+
// <div
|
|
131
|
+
// className="code-gen-result-gravity-demo"
|
|
132
|
+
// style={{ height: "100%" }}
|
|
133
|
+
// >
|
|
134
|
+
// <CodeGenPreview
|
|
135
|
+
// code={gravityCode}
|
|
136
|
+
// height={"100%"}
|
|
137
|
+
// refresh={refresh}
|
|
138
|
+
// />
|
|
139
|
+
// </div>
|
|
140
|
+
// ),
|
|
141
|
+
// },
|
|
142
|
+
// ];
|
|
143
|
+
|
|
144
|
+
// return <Tabs className="code-gen-tabs" items={items} />;
|
|
145
|
+
|
|
146
|
+
if (!gravityCode) return /*#__PURE__*/React.createElement(_Empty, null);
|
|
147
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
148
|
+
className: "code-gen-source-view"
|
|
149
|
+
}, /*#__PURE__*/React.createElement(SourcesView, {
|
|
150
|
+
code: gravityCode,
|
|
151
|
+
onCodeChange: setGravityCode
|
|
152
|
+
}));
|
|
153
|
+
});
|
|
154
|
+
function convertCodeGenResult(result, schema) {
|
|
155
|
+
var schemaFiles = {
|
|
156
|
+
"/.project-schema.json": {
|
|
157
|
+
fpath: "/.project-schema.json",
|
|
158
|
+
code: JSON.stringify(schema, null, 2) + "\n"
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
if (!result || !Array.isArray(result) || !result.length) {
|
|
162
|
+
return {
|
|
163
|
+
type: "demo",
|
|
164
|
+
modules: schemaFiles
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
var code = {
|
|
168
|
+
type: "demo",
|
|
169
|
+
modules: result.reduce(function (acc, file) {
|
|
170
|
+
var _extends2;
|
|
171
|
+
return _extends({}, acc, (_extends2 = {}, _extends2["/" + file.pathName] = {
|
|
172
|
+
fpath: "/" + file.pathName,
|
|
173
|
+
code: file.content,
|
|
174
|
+
entry: undefined,
|
|
175
|
+
packagejson: ["package.json"].includes(file.pathName) ? 1 : undefined
|
|
176
|
+
}, _extends2));
|
|
177
|
+
}, {})
|
|
178
|
+
};
|
|
179
|
+
var foundEntry = false;
|
|
180
|
+
|
|
181
|
+
// 设置入口文件
|
|
182
|
+
["index.js", "index.ts", "index.tsx", "app.js", "app.ts", "app.tsx"].forEach(function (fileName) {
|
|
183
|
+
if (!foundEntry) {
|
|
184
|
+
var filePath = "/src/" + fileName;
|
|
185
|
+
if (code.modules[filePath]) {
|
|
186
|
+
foundEntry = true;
|
|
187
|
+
if (fileName === "index.js") {
|
|
188
|
+
code.modules[filePath].entry = 1;
|
|
189
|
+
} else {
|
|
190
|
+
code.modules["/src/index.js"] = {
|
|
191
|
+
fpath: "/src/index.js",
|
|
192
|
+
entry: 1,
|
|
193
|
+
code: "import \"./" + fileName.replace(/\.\w+$/, "") + "\""
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
if (!foundEntry) {
|
|
200
|
+
console.warn("Failed to find entry file for demo.");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// 补充 schema 文件
|
|
204
|
+
// Object.assign(code.modules, schemaFiles);
|
|
205
|
+
|
|
206
|
+
return code;
|
|
207
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
.code-gen-tabs {
|
|
2
|
+
height: 100%;
|
|
3
|
+
|
|
4
|
+
.ant-tabs-nav {
|
|
5
|
+
margin: 0;
|
|
6
|
+
}
|
|
7
|
+
.ant-tabs-content, .ant-tabs-tabpane {
|
|
8
|
+
height: 100%;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.code-gen-source-view {
|
|
13
|
+
height: 100%;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.source-view-header {
|
|
17
|
+
position: absolute;
|
|
18
|
+
top: 18px;
|
|
19
|
+
right: 20px;
|
|
20
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
1
2
|
import type { CodeGenPreviewProps } from "../code-gen-preview/index";
|
|
2
3
|
import "./index.less";
|
|
3
|
-
export declare function CodeSandboxPreview({ code, height }: CodeGenPreviewProps):
|
|
4
|
+
export declare function CodeSandboxPreview({ code, height }: CodeGenPreviewProps): JSX.Element;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import _Spin from "antd/es/spin";
|
|
2
|
+
import _Alert from "antd/es/alert";
|
|
3
|
+
import _Button from "antd/es/button";
|
|
4
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
5
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
6
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
7
|
+
import React, { useMemo, useState, useEffect } from "react";
|
|
8
|
+
import { fixPreviewCode } from "../code-gen-preview/fixPreviewCode";
|
|
9
|
+
import "./index.less";
|
|
10
|
+
// 使用 CodeSandbox 来进行预览
|
|
11
|
+
// @see https://codesandbox.io/docs/api#get-request
|
|
12
|
+
export function CodeSandboxPreview(_ref) {
|
|
13
|
+
var code = _ref.code,
|
|
14
|
+
height = _ref.height;
|
|
15
|
+
var parameters = useMemo(function () {
|
|
16
|
+
var files = {};
|
|
17
|
+
if (code && code.modules) {
|
|
18
|
+
var fixedCode = fixPreviewCode(code);
|
|
19
|
+
if (fixedCode) {
|
|
20
|
+
Object.values(fixedCode.modules).forEach(function (file) {
|
|
21
|
+
var _file$fpath;
|
|
22
|
+
files[file === null || file === void 0 ? void 0 : (_file$fpath = file.fpath) === null || _file$fpath === void 0 ? void 0 : _file$fpath.slice(1)] = {
|
|
23
|
+
isBinary: false,
|
|
24
|
+
content: file.code
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 入口文件需要顺便引入下样式
|
|
30
|
+
files["src/index.js"] = {
|
|
31
|
+
isBinary: false,
|
|
32
|
+
content: "\n // \u76EE\u524D\u9700\u8981\u5355\u72EC\u5F15\u5165\u4E0B\u6837\u5F0F\u6587\u4EF6\n import \"@alifd/next/dist/next.css\";\n import \"@alifd/pro-layout/dist/AlifdProLayout.css\";\n\n // \u5F15\u5165\u5165\u53E3\u6587\u4EF6\n import './app';\n"
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
files: files,
|
|
37
|
+
template: "create-react-app"
|
|
38
|
+
};
|
|
39
|
+
}, [code]);
|
|
40
|
+
var _useState = useState({
|
|
41
|
+
parameters: parameters,
|
|
42
|
+
sandboxId: "",
|
|
43
|
+
isCreating: false,
|
|
44
|
+
hasError: false,
|
|
45
|
+
error: null
|
|
46
|
+
}),
|
|
47
|
+
state = _useState[0],
|
|
48
|
+
setState = _useState[1];
|
|
49
|
+
useEffect(function () {
|
|
50
|
+
if (state.parameters !== parameters || state.sandboxId === "retry" || !state.sandboxId) {
|
|
51
|
+
var hasCanceled = false;
|
|
52
|
+
setState(function (prev) {
|
|
53
|
+
return _extends({}, prev, {
|
|
54
|
+
hasError: false,
|
|
55
|
+
code: code,
|
|
56
|
+
parameters: parameters,
|
|
57
|
+
isCreating: true
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
61
|
+
var sandboxId;
|
|
62
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
63
|
+
while (1) switch (_context.prev = _context.next) {
|
|
64
|
+
case 0:
|
|
65
|
+
_context.prev = 0;
|
|
66
|
+
_context.next = 3;
|
|
67
|
+
return createCodeSandbox(parameters);
|
|
68
|
+
case 3:
|
|
69
|
+
sandboxId = _context.sent;
|
|
70
|
+
if (!hasCanceled) {
|
|
71
|
+
setState(function (prev) {
|
|
72
|
+
return _extends({}, prev, {
|
|
73
|
+
hasError: false,
|
|
74
|
+
isCreating: false,
|
|
75
|
+
sandboxId: sandboxId
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
_context.next = 10;
|
|
80
|
+
break;
|
|
81
|
+
case 7:
|
|
82
|
+
_context.prev = 7;
|
|
83
|
+
_context.t0 = _context["catch"](0);
|
|
84
|
+
if (!hasCanceled) {
|
|
85
|
+
setState(function (prev) {
|
|
86
|
+
return _extends({}, prev, {
|
|
87
|
+
hasError: true,
|
|
88
|
+
error: _context.t0,
|
|
89
|
+
isCreating: false
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
case 10:
|
|
94
|
+
case "end":
|
|
95
|
+
return _context.stop();
|
|
96
|
+
}
|
|
97
|
+
}, _callee, null, [[0, 7]]);
|
|
98
|
+
}))();
|
|
99
|
+
return function () {
|
|
100
|
+
hasCanceled = true;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return function () {};
|
|
104
|
+
}, [parameters, state.sandboxId, state.parameters]);
|
|
105
|
+
var handleRetry = function handleRetry() {
|
|
106
|
+
setState(function (prev) {
|
|
107
|
+
return _extends({}, prev, {
|
|
108
|
+
hasError: false,
|
|
109
|
+
sandboxId: "retry"
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
114
|
+
className: "code-gen-plugin-code-sandbox-preview",
|
|
115
|
+
style: {
|
|
116
|
+
height: height
|
|
117
|
+
},
|
|
118
|
+
"data-code-sandbox-id": state.sandboxId
|
|
119
|
+
}, function () {
|
|
120
|
+
if (state.hasError) {
|
|
121
|
+
return /*#__PURE__*/React.createElement(_Alert, {
|
|
122
|
+
message: "\u751F\u6210 CodeSandbox \u9884\u89C8\u5E94\u7528\u5931\u8D25",
|
|
123
|
+
description: /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("p", null, "\u8BE6\u7EC6\u9519\u8BEF\uFF1A", "" + (state.error || "网络开小差了")), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement(_Button, {
|
|
124
|
+
onClick: handleRetry
|
|
125
|
+
}, "\u91CD\u65B0\u5C1D\u8BD5\u4E0B")))
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return state.sandboxId ? /*#__PURE__*/React.createElement("iframe", {
|
|
129
|
+
src: "https://codesandbox.io/embed/" + state.sandboxId + "?autoresize=1&fontsize=14&hidenavigation=1&theme=dark&view=preview",
|
|
130
|
+
title: "CodeSandbox Preview",
|
|
131
|
+
allow: "accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking",
|
|
132
|
+
sandbox: "allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
|
|
133
|
+
}) : /*#__PURE__*/React.createElement(_Spin, {
|
|
134
|
+
spinning: true,
|
|
135
|
+
tip: "\u6B63\u5728\u751F\u6210 CodeSandbox \u9884\u89C8\u5E94\u7528..."
|
|
136
|
+
});
|
|
137
|
+
}());
|
|
138
|
+
}
|
|
139
|
+
function createCodeSandbox(_x) {
|
|
140
|
+
return _createCodeSandbox.apply(this, arguments);
|
|
141
|
+
}
|
|
142
|
+
function _createCodeSandbox() {
|
|
143
|
+
_createCodeSandbox = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(parameters) {
|
|
144
|
+
var res, json, _ref3, sandbox_id;
|
|
145
|
+
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
146
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
147
|
+
case 0:
|
|
148
|
+
if (Object.entries((parameters === null || parameters === void 0 ? void 0 : parameters.files) || {}).length) {
|
|
149
|
+
_context2.next = 2;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
return _context2.abrupt("return", "");
|
|
153
|
+
case 2:
|
|
154
|
+
_context2.next = 4;
|
|
155
|
+
return fetch("https://codesandbox.io/api/v1/sandboxes/define?json=1", {
|
|
156
|
+
method: "POST",
|
|
157
|
+
headers: {
|
|
158
|
+
"Content-Type": "application/json",
|
|
159
|
+
Accept: "application/json"
|
|
160
|
+
},
|
|
161
|
+
body: JSON.stringify(parameters)
|
|
162
|
+
});
|
|
163
|
+
case 4:
|
|
164
|
+
res = _context2.sent;
|
|
165
|
+
if (res.ok) {
|
|
166
|
+
_context2.next = 7;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
throw new Error("\u521B\u5EFA CodeSandbox \u5931\u8D25\uFF0C\u9519\u8BEF\u7801\uFF1A" + res.status + " " + res.statusText);
|
|
170
|
+
case 7:
|
|
171
|
+
_context2.next = 9;
|
|
172
|
+
return res.json()["catch"](function (err) {
|
|
173
|
+
throw new Error("\u521B\u5EFA CodeSandbox \u5931\u8D25\uFF0C\u670D\u52A1\u5F02\u5E38(" + ((err === null || err === void 0 ? void 0 : err.message) || err || "未知异常") + ")");
|
|
174
|
+
});
|
|
175
|
+
case 9:
|
|
176
|
+
json = _context2.sent;
|
|
177
|
+
_ref3 = json || {}, sandbox_id = _ref3.sandbox_id;
|
|
178
|
+
if (!(!sandbox_id || typeof sandbox_id !== "string")) {
|
|
179
|
+
_context2.next = 13;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
throw new Error("\u521B\u5EFA CodeSandbox \u5931\u8D25\uFF0C\u670D\u52A1\u54CD\u5E94\u5F02\u5E38");
|
|
183
|
+
case 13:
|
|
184
|
+
return _context2.abrupt("return", sandbox_id);
|
|
185
|
+
case 14:
|
|
186
|
+
case "end":
|
|
187
|
+
return _context2.stop();
|
|
188
|
+
}
|
|
189
|
+
}, _callee2);
|
|
190
|
+
}));
|
|
191
|
+
return _createCodeSandbox.apply(this, arguments);
|
|
192
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.code-gen-plugin-code-sandbox-preview {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: row;
|
|
4
|
+
align-items: center;
|
|
5
|
+
align-content: center;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
justify-items: center;
|
|
8
|
+
height: 100%;
|
|
9
|
+
|
|
10
|
+
iframe {
|
|
11
|
+
width: 100%;
|
|
12
|
+
height: 100%;
|
|
13
|
+
min-height: 300px;
|
|
14
|
+
border: 0;
|
|
15
|
+
border-radius: 0;
|
|
16
|
+
overflow: hidden;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
1
2
|
import { CodeModules } from "../../types";
|
|
2
3
|
import "./index.less";
|
|
3
4
|
interface FileTreeProps {
|
|
@@ -5,8 +6,8 @@ interface FileTreeProps {
|
|
|
5
6
|
onSelect?(key: string): void;
|
|
6
7
|
selectedKeys?: string[];
|
|
7
8
|
}
|
|
8
|
-
export declare const FileTree: (props: FileTreeProps) =>
|
|
9
|
-
type TreeNode = {
|
|
9
|
+
export declare const FileTree: (props: FileTreeProps) => JSX.Element;
|
|
10
|
+
declare type TreeNode = {
|
|
10
11
|
id: string;
|
|
11
12
|
label: string;
|
|
12
13
|
folder: boolean;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import React, { useState, memo } from "react";
|
|
2
|
+
import { FixedSizeList as List, areEqual } from "react-window";
|
|
3
|
+
import AutoSizer from "react-virtualized-auto-sizer";
|
|
4
|
+
import cls from "classnames";
|
|
5
|
+
import memoizeOne from "memoize-one";
|
|
6
|
+
import naturalCompare from "string-natural-compare";
|
|
7
|
+
import { FileTypeIcon } from "../file-type-icon/index";
|
|
8
|
+
import "./index.less";
|
|
9
|
+
var FILE_TYPES_ICON_MAP = {
|
|
10
|
+
js: "js",
|
|
11
|
+
jsx: "jsx",
|
|
12
|
+
ts: "ts",
|
|
13
|
+
tsx: "ts",
|
|
14
|
+
json: "json",
|
|
15
|
+
scss: "scss",
|
|
16
|
+
css: "css",
|
|
17
|
+
less: "less",
|
|
18
|
+
tsconfig: "tsconfig",
|
|
19
|
+
html: "html"
|
|
20
|
+
};
|
|
21
|
+
function getFileIcon(file) {
|
|
22
|
+
var type = FILE_TYPES_ICON_MAP[(file || "").split(".").pop() || ""] || "text";
|
|
23
|
+
return /*#__PURE__*/React.createElement(FileTypeIcon, {
|
|
24
|
+
type: type
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
var Row = /*#__PURE__*/memo(function (_ref) {
|
|
28
|
+
var data = _ref.data,
|
|
29
|
+
index = _ref.index,
|
|
30
|
+
style = _ref.style;
|
|
31
|
+
var flattenedData = data.flattenedData,
|
|
32
|
+
onOpen = data.onOpen,
|
|
33
|
+
onSelect = data.onSelect,
|
|
34
|
+
selectedKeys = data.selectedKeys;
|
|
35
|
+
var node = flattenedData[index];
|
|
36
|
+
var left = node.depth * 20;
|
|
37
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
38
|
+
className: cls("tree-node", {
|
|
39
|
+
"tree-node-selected": selectedKeys === null || selectedKeys === void 0 ? void 0 : selectedKeys.includes(node.id)
|
|
40
|
+
}),
|
|
41
|
+
style: style,
|
|
42
|
+
onClick: function onClick() {
|
|
43
|
+
return onOpen(node);
|
|
44
|
+
}
|
|
45
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
46
|
+
className: cls("tree-item", {
|
|
47
|
+
"tree-folder": node.folder,
|
|
48
|
+
"tree-item-expanded": node.expanded,
|
|
49
|
+
"tree-item-open": !node.expanded
|
|
50
|
+
}),
|
|
51
|
+
onClick: function onClick(e) {
|
|
52
|
+
return onSelect(e, node);
|
|
53
|
+
},
|
|
54
|
+
style: {
|
|
55
|
+
left: left + "px",
|
|
56
|
+
width: "calc(100% - " + left + "px)"
|
|
57
|
+
}
|
|
58
|
+
}, !node.folder && getFileIcon(node.label), /*#__PURE__*/React.createElement("span", {
|
|
59
|
+
className: "label-name"
|
|
60
|
+
}, node.label)));
|
|
61
|
+
}, areEqual);
|
|
62
|
+
var getItemData = memoizeOne(function (onOpen, onSelect, flattenedData, selectedKeys) {
|
|
63
|
+
return {
|
|
64
|
+
onOpen: onOpen,
|
|
65
|
+
onSelect: onSelect,
|
|
66
|
+
flattenedData: flattenedData,
|
|
67
|
+
selectedKeys: selectedKeys
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
export var FileTree = function FileTree(props) {
|
|
71
|
+
var modules = props.modules,
|
|
72
|
+
_props$selectedKeys = props.selectedKeys,
|
|
73
|
+
selectedKeys = _props$selectedKeys === void 0 ? [] : _props$selectedKeys;
|
|
74
|
+
var _useState = useState([]),
|
|
75
|
+
openedNodeIds = _useState[0],
|
|
76
|
+
setOpenedNodeIds = _useState[1];
|
|
77
|
+
var onOpen = function onOpen(node) {
|
|
78
|
+
if (!node.folder) return;
|
|
79
|
+
!node.expanded ? setOpenedNodeIds([].concat(openedNodeIds, [node.id])) : setOpenedNodeIds(openedNodeIds.filter(function (id) {
|
|
80
|
+
return id !== node.id;
|
|
81
|
+
}));
|
|
82
|
+
};
|
|
83
|
+
var onSelect = function onSelect(e, node) {
|
|
84
|
+
var _props$onSelect;
|
|
85
|
+
//e.stopPropagation();
|
|
86
|
+
if (node.folder) return;
|
|
87
|
+
(_props$onSelect = props.onSelect) === null || _props$onSelect === void 0 ? void 0 : _props$onSelect.call(props, node.id);
|
|
88
|
+
};
|
|
89
|
+
var flattenedData = createFlattenTree(modules, openedNodeIds);
|
|
90
|
+
var itemData = getItemData(onOpen, onSelect, flattenedData, selectedKeys);
|
|
91
|
+
return /*#__PURE__*/React.createElement(AutoSizer, null, function (_ref2) {
|
|
92
|
+
var height = _ref2.height,
|
|
93
|
+
width = _ref2.width;
|
|
94
|
+
return /*#__PURE__*/React.createElement(List, {
|
|
95
|
+
className: "code-file-tree",
|
|
96
|
+
height: height,
|
|
97
|
+
itemCount: flattenedData.length,
|
|
98
|
+
itemSize: 22,
|
|
99
|
+
width: width,
|
|
100
|
+
itemKey: function itemKey(index) {
|
|
101
|
+
return flattenedData[index].id;
|
|
102
|
+
},
|
|
103
|
+
itemData: itemData
|
|
104
|
+
}, Row);
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
export function createFlattenTree(data, expandedKeys) {
|
|
108
|
+
var flatTree = [];
|
|
109
|
+
var filePaths = Object.keys(data);
|
|
110
|
+
// console.log(JSON.parse(JSON.stringify(filePaths)))
|
|
111
|
+
// filePaths.sort((a, b) => {
|
|
112
|
+
// // 检查字符串a是否包含斜杠
|
|
113
|
+
// const hasSlashA = a.substring(1).lastIndexOf('/');
|
|
114
|
+
// // 检查字符串b是否包含斜杠
|
|
115
|
+
// const hasSlashB = b.substring(1).lastIndexOf('/');
|
|
116
|
+
// console.log('---a', hasSlashA)
|
|
117
|
+
// console.log('---b', hasSlashB)
|
|
118
|
+
// // 如果a包含斜杠,而b不包含,则a应该排在b之后
|
|
119
|
+
// if (hasSlashA > -1 && hasSlashB > -1) {
|
|
120
|
+
// return hasSlashB - hasSlashA;
|
|
121
|
+
// }
|
|
122
|
+
|
|
123
|
+
// return naturalCompare(a, b, {
|
|
124
|
+
// caseInsensitive: true,
|
|
125
|
+
// }); // 包含斜杠的字符串按字典顺序排序
|
|
126
|
+
// });
|
|
127
|
+
// console.log(filePaths)
|
|
128
|
+
filePaths.forEach(function (key) {
|
|
129
|
+
var parts = key.split("/");
|
|
130
|
+
var fileNames = [];
|
|
131
|
+
var _loop = function _loop() {
|
|
132
|
+
var path = parts.slice(0, i).join("/");
|
|
133
|
+
var expanded = expandedKeys.includes(path);
|
|
134
|
+
if (path && !flatTree.some(function (node) {
|
|
135
|
+
return node.id === path;
|
|
136
|
+
})) {
|
|
137
|
+
fileNames.push({
|
|
138
|
+
id: path,
|
|
139
|
+
label: parts[i - 1] || "/",
|
|
140
|
+
// 当前层的名称
|
|
141
|
+
folder: i < parts.length,
|
|
142
|
+
// 如果不是最后一层,则为文件夹
|
|
143
|
+
depth: i - 1,
|
|
144
|
+
// 层级深度,从 0 开始
|
|
145
|
+
expanded: expanded // 默认展开
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
if (expanded) return 1; // break
|
|
149
|
+
};
|
|
150
|
+
for (var i = 1; i <= parts.length; i++) {
|
|
151
|
+
if (_loop()) break;
|
|
152
|
+
}
|
|
153
|
+
// console.log('--fileNames', fileNames);
|
|
154
|
+
fileNames.sort(function (a, b) {
|
|
155
|
+
return naturalCompare(a.id, b.id, {
|
|
156
|
+
caseInsensitive: true
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
flatTree.push.apply(flatTree, fileNames);
|
|
160
|
+
});
|
|
161
|
+
return flatTree;
|
|
162
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
.code-file-tree {
|
|
2
|
+
white-space: nowrap;
|
|
3
|
+
|
|
4
|
+
.tree-node {
|
|
5
|
+
display: flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
user-select: none;
|
|
9
|
+
|
|
10
|
+
&:hover,
|
|
11
|
+
&.tree-node-selected {
|
|
12
|
+
background-color: rgba(207, 208, 209, 1);
|
|
13
|
+
cursor: pointer;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.tree-item {
|
|
18
|
+
position: absolute;
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: left;
|
|
22
|
+
|
|
23
|
+
& > i {
|
|
24
|
+
margin-right: 8px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.label-name {
|
|
28
|
+
flex: 1;
|
|
29
|
+
min-width: 0;
|
|
30
|
+
overflow: hidden;
|
|
31
|
+
text-overflow: ellipsis;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.tree-folder::after {
|
|
36
|
+
content: "";
|
|
37
|
+
display: block;
|
|
38
|
+
width: 0;
|
|
39
|
+
height: 0;
|
|
40
|
+
margin-left: 20px;
|
|
41
|
+
border-top: 6px solid rgba(0, 0, 0, 0.7);
|
|
42
|
+
border-right: 6px solid transparent;
|
|
43
|
+
border-left: 6px solid transparent;
|
|
44
|
+
opacity: 0.7;
|
|
45
|
+
position: absolute;
|
|
46
|
+
left: -36px;
|
|
47
|
+
transition: transform 0.3s;
|
|
48
|
+
transform: translate(0, 0);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.tree-item-expanded::after {
|
|
52
|
+
transform: rotate(-90deg);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import './index.less';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
export type FileTypeIconProps = React.HtmlHTMLAttributes<HTMLSpanElement> & {
|
|
3
|
+
export declare type FileTypeIconProps = React.HtmlHTMLAttributes<HTMLSpanElement> & {
|
|
4
4
|
type: string;
|
|
5
5
|
};
|
|
6
|
-
export declare function FileTypeIcon({ type, ...props }: FileTypeIconProps):
|
|
6
|
+
export declare function FileTypeIcon({ type, ...props }: FileTypeIconProps): JSX.Element;
|