@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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/{dist → es}/components/code-gen-action/index.d.ts +2 -1
  3. package/es/components/code-gen-action/index.js +330 -0
  4. package/es/components/code-gen-action/index.less +20 -0
  5. package/es/components/code-gen-preview/fixPreviewCode.js +100 -0
  6. package/{dist → es}/components/code-gen-preview/index.d.ts +3 -2
  7. package/es/components/code-gen-preview/index.js +5 -0
  8. package/es/components/code-gen-preview/index.less +16 -0
  9. package/{dist → es}/components/code-gen-result/index.d.ts +2 -2
  10. package/es/components/code-gen-result/index.js +207 -0
  11. package/es/components/code-gen-result/index.less +20 -0
  12. package/{dist → es}/components/codesandbox-preview/index.d.ts +2 -1
  13. package/es/components/codesandbox-preview/index.js +192 -0
  14. package/es/components/codesandbox-preview/index.less +18 -0
  15. package/{dist → es}/components/file-tree/index.d.ts +3 -2
  16. package/es/components/file-tree/index.js +162 -0
  17. package/es/components/file-tree/index.less +54 -0
  18. package/{dist → es}/components/file-type-icon/index.d.ts +2 -2
  19. package/es/components/file-type-icon/index.js +12 -0
  20. package/es/components/file-type-icon/index.less +77 -0
  21. package/{dist → es}/components/sources-view/index.d.ts +2 -1
  22. package/es/components/sources-view/index.js +128 -0
  23. package/es/components/sources-view/index.less +12 -0
  24. package/{dist → es}/index.d.ts +3 -4
  25. package/es/index.js +67 -0
  26. package/es/style.js +9 -0
  27. package/{dist → es}/types/index.d.ts +3 -3
  28. package/es/types/index.js +1 -0
  29. package/lib/components/code-gen-action/index.d.ts +7 -0
  30. package/lib/components/code-gen-action/index.js +336 -0
  31. package/lib/components/code-gen-action/index.less +20 -0
  32. package/lib/components/code-gen-preview/fixPreviewCode.d.ts +2 -0
  33. package/lib/components/code-gen-preview/fixPreviewCode.js +105 -0
  34. package/lib/components/code-gen-preview/index.d.ts +9 -0
  35. package/lib/components/code-gen-preview/index.js +9 -0
  36. package/lib/components/code-gen-preview/index.less +16 -0
  37. package/lib/components/code-gen-result/index.d.ts +14 -0
  38. package/lib/components/code-gen-result/index.js +215 -0
  39. package/lib/components/code-gen-result/index.less +20 -0
  40. package/lib/components/codesandbox-preview/index.d.ts +4 -0
  41. package/lib/components/codesandbox-preview/index.js +199 -0
  42. package/lib/components/codesandbox-preview/index.less +18 -0
  43. package/lib/components/file-tree/index.d.ts +21 -0
  44. package/lib/components/file-tree/index.js +170 -0
  45. package/lib/components/file-tree/index.less +54 -0
  46. package/lib/components/file-type-icon/index.d.ts +6 -0
  47. package/lib/components/file-type-icon/index.js +17 -0
  48. package/lib/components/file-type-icon/index.less +77 -0
  49. package/lib/components/sources-view/index.d.ts +8 -0
  50. package/lib/components/sources-view/index.js +135 -0
  51. package/lib/components/sources-view/index.less +12 -0
  52. package/lib/index.d.ts +27 -0
  53. package/lib/index.js +74 -0
  54. package/lib/style.js +9 -0
  55. package/lib/types/index.d.ts +17 -0
  56. package/lib/types/index.js +3 -0
  57. package/package.json +27 -19
  58. package/dist/components/code-gen-action/index.css +0 -18
  59. package/dist/components/code-gen-action/index.js +0 -203
  60. package/dist/components/code-gen-preview/fixPreviewCode.js +0 -119
  61. package/dist/components/code-gen-preview/index.css +0 -18
  62. package/dist/components/code-gen-preview/index.js +0 -9
  63. package/dist/components/code-gen-result/index.css +0 -18
  64. package/dist/components/code-gen-result/index.js +0 -147
  65. package/dist/components/codesandbox-preview/index.css +0 -17
  66. package/dist/components/codesandbox-preview/index.js +0 -147
  67. package/dist/components/file-tree/index.css +0 -55
  68. package/dist/components/file-tree/index.js +0 -138
  69. package/dist/components/file-type-icon/index.css +0 -73
  70. package/dist/components/file-type-icon/index.js +0 -10
  71. package/dist/components/sources-view/index.css +0 -11
  72. package/dist/components/sources-view/index.js +0 -128
  73. package/dist/index.js +0 -50
  74. package/dist/types/index.js +0 -1
  75. /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): import("react/jsx-runtime").JSX.Element;
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) => import("react/jsx-runtime").JSX.Element;
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): import("react/jsx-runtime").JSX.Element;
6
+ export declare function FileTypeIcon({ type, ...props }: FileTypeIconProps): JSX.Element;