Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

线上ide组件 #48

Merged
merged 24 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6c5da98
feat: 初始化Monaco Editor
Sep 29, 2023
d0f56de
feat: jsx编译
Oct 1, 2023
3ac00ad
feat: 支持实时修改编译
Oct 1, 2023
779d2f6
feat: web worker处理编译&通信优化
Oct 3, 2023
c29be7f
feat: 本地自动保存
Oct 4, 2023
f3c2a19
feat: tabs组件初始化
Oct 6, 2023
184e16f
feat: tabs组件滚动条动画
Oct 7, 2023
effa22a
feat: tabs卡片样式&global bg token
Oct 7, 2023
9c6c543
feat: 编辑器引入Tabs
Oct 7, 2023
4773d34
feat: 抽离单多模型editor&弃用useControlled&useLocalStorage
1360151219 Oct 8, 2023
12cf38c
chore: ts noPropertyAccessFromIndexSignature
1360151219 Oct 9, 2023
6363ba9
feat: multiple editor localStorage存储
1360151219 Oct 10, 2023
cf2c05a
Merge branch 'featue-editor' of https://github.com/Pivot-Studio/pivot…
1360151219 Oct 10, 2023
cce4d10
fix: compiler worker重复启动&modules
1360151219 Oct 10, 2023
fb4c3ed
feat: css相对模块引入
1360151219 Oct 10, 2023
c684f94
fix: onChange无法触发
1360151219 Oct 10, 2023
3e8fc22
fix: 切换时value不会改变
1360151219 Oct 12, 2023
6cde6ef
feat: 支持sass编译
1360151219 Oct 13, 2023
3e7eb63
fix: 更新不生效
1360151219 Oct 14, 2023
b46976f
feat: 构造依赖关系图(相对依赖)
1360151219 Oct 14, 2023
b64ef22
feat: import map 第三方依赖动态生成
1360151219 Oct 15, 2023
a0eaa0c
feat: fetch后端code runner MVP
1360151219 Oct 18, 2023
7b71c4d
feat: 引入react、react-dom types
1360151219 Oct 24, 2023
11ff44b
chore: 代码优化
1360151219 Nov 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"editor.formatOnSaveMode": "file",
"files.eol": "\n",
"[typescriptreact]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
Expand Down
1 change: 1 addition & 0 deletions packages/demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@mdx-js/loader": "^2.1.5",
"babel-plugin-prismjs": "^2.1.0",
"gsap": "^3.11.5",
"node-polyfill-webpack-plugin": "^2.0.1",
"pivot-design": "workspace:*",
"pivot-design-icon": "workspace:*",
"prismjs": "^1.29.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/demo/src/components/Editor/.catalog.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const list = []
export const list = [{"h2":"基本用法","h3":[]}]
2 changes: 1 addition & 1 deletion packages/demo/src/components/Editor/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Props from './props.mdx';

## 基本用法

<CodeBlock id="基本示例">
<CodeBlock id="基本示例" style={{ padding: 0 }}>
<Base />
</CodeBlock>

Expand Down
3 changes: 0 additions & 3 deletions packages/demo/src/components/_CodeBlock/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
justify-content: center;
align-items: center;
background-color: var(--semi-color-fill-0);
> :not(.PIVOT-draggable-item) {
margin: 0 24px;
}
}

.line-numbers {
Expand Down
4 changes: 0 additions & 4 deletions packages/demo/src/utils/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ export const ComponentPath = [
path: 'card',
title: 'Card 卡片',
},
{
path: 'button',
title: 'Card 卡片',
},
{
path: 'draggable',
title: 'Draggable 拖拽列表',
Expand Down
7 changes: 7 additions & 0 deletions packages/demo/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const path = require('path'); //node环境当前路径
const HtmlWebpackPlugin = require('html-webpack-plugin'); //模板文件插件,能够自动将打包的css和js加入到模板文件中
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
module.exports = {
entry: {
app: './index.tsx', //找到咱们刚才在src下面的入口文件
Expand All @@ -14,6 +15,11 @@ module.exports = {
alias: {
'@': path.resolve(__dirname, './src'),
},
fallback: {
fs: false,
assert: require.resolve('assert'),
path: require.resolve('path-browserify'),
},
},
devServer: {
port: 8080,
Expand Down Expand Up @@ -86,5 +92,6 @@ module.exports = {
removeComments: true, // 移除注释
},
}),
new NodePolyfillPlugin(),
],
};
2 changes: 1 addition & 1 deletion packages/design/.prettierrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"singleQuote": true,
"printWidth": 120
"printWidth": 80
}
19 changes: 19 additions & 0 deletions packages/design/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module.exports = {
// 执行顺序由右往左,所以先处理ts,再处理jsx,最后再试一下babel转换为低版本语法
presets: [
[
'@babel/preset-env',
{
// 设置兼容目标浏览器版本,这里可以不写,babel-loader会自动寻找上面配置好的文件.browserslistrc
// "targets": {
// "chrome": 35,
// "ie": 9
// },
useBuiltIns: 'usage', // 根据配置的浏览器兼容,以及代码中使用到的api进行引入polyfill按需添加
corejs: 3, // 配置使用core-js低版本
},
],
['@babel/preset-react', { runtime: 'automatic' }],
'@babel/preset-typescript',
],
};
3 changes: 3 additions & 0 deletions packages/design/components/MonacoEditor/code/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default as useEventCode } from './useEvent';
export { default as usePreviousCode } from './usePrevious';
export { default as testCode } from './test';
12 changes: 12 additions & 0 deletions packages/design/components/MonacoEditor/code/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default `import ReactDom from 'react-dom/client';
import React from 'react';
function App() {
return (
<section>
<h1 style={{ color: '#fff' }}>Pivot Design Editor</h1>
</section>
);
}

ReactDom.createRoot(document.getElementById('root')).render(<App />)
`;
61 changes: 61 additions & 0 deletions packages/design/components/MonacoEditor/code/useEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
export default `import ReactDom from 'react-dom/client';
import React, {
useEffect,
useCallback,
useLayoutEffect,
useRef,
useState
} from "react";
function getRandomColor() {
const colors = ["green", "blue", "purple", "red", "pink"];
return colors[Math.floor(Math.random() * colors.length)];
}
function useEvent(handler) {
// todo
const handlerRef = useRef(handler);
useEffect(() => {
handlerRef.current = handler;
});
return useCallback(() => {
const fn = handlerRef.current;
fn();
}, []);
}
export default function App() {
const [color, setColor] = useState(getRandomColor());
const ButtonRef = useRef<HTMLButtonElement>(null);
const handleClick = () => {
function getNewColor() {
const newColor = getRandomColor();
if (color === newColor) {
getNewColor();
} else {
setColor(newColor);
}
}
getNewColor();
console.log("===", color);
};
// todo
const handleEventClick = useEvent(handleClick);
useEffect(() => {
ButtonRef.current.addEventListener("click", handleEventClick);
}, []);
return (
<section style={{ color: '#fff' }}>
<h1>useEvent</h1>
<button className="link" ref={ButtonRef}>
Next
</button>
<article>
<figure>
<p style={{ height:100, width: 100, background: \`$\{color}\` }} />
<figcaption>Current: {color}</figcaption>
</figure>
</article>
</section>
);
}

ReactDom.createRoot(document.getElementById('root')).render(<App />)
`;
45 changes: 45 additions & 0 deletions packages/design/components/MonacoEditor/code/usePrevious.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
export default `import { useEffect, useRef, useState } from "react";
import "./index.scss";
function getRandomColor() {
const colors = ["green", "blue", "purple", "red", "pink"];
return colors[Math.floor(Math.random() * colors.length)];
}
function usePrevious(color: string) {
// todo
}
export default function App() {
const [color, setColor] = useState(getRandomColor());
const previousColor = usePrevious(color);

const handleClick = () => {
function getNewColor() {
const newColor = getRandomColor();
if (color === newColor) {
getNewColor();
} else {
setColor(newColor);
}
}
getNewColor();
};

return (
<section>
<h1>usePrevious</h1>
<button className="link" onClick={handleClick}>
Next
</button>
<article>
<figure>
<p style={{ background: \`$\{previousColor}\` }} />
<figcaption>Previous: {previousColor}</figcaption>
</figure>
<figure>
<p style={{ background: \`$\{color}\` }} />
<figcaption>Current: {color}</figcaption>
</figure>
</article>
</section>
);
}
`;
64 changes: 64 additions & 0 deletions packages/design/components/MonacoEditor/compiler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { transformSync, transform } from '@babel/core';
import ReactPreset from '@babel/preset-react';
import TSPreset from '@babel/preset-typescript';
export const babelTransform = (filename: string, code: string, tabs: Tab[]) => {
let _code = code;
if (filename.endsWith('.tsx')) {
_code = `${code}`;
}

const { code: resultCode } = transformSync(_code, {
filename: 'j.tsx',
presets: [ReactPreset, TSPreset],
// plugins: [
// // Babel plugin to get file import names
// function importGetter() {
// return {
// visitor: {
// ImportDeclaration(path: any) {
// const module: string = path.node.source.value;
// if (module.startsWith('.')) {
// const _module = getInternalModule(tabs, module);
// // handle style file
// if (_module.path.endsWith('.css')) {
// const js = `
// (() => {
// let stylesheet = document.getElementById('${_module.path}');
// if (!stylesheet) {
// stylesheet = document.createElement('style')
// stylesheet.setAttribute('id', '${_module.path}')
// document.head.appendChild(stylesheet)
// }
// const styles = document.createTextNode(\`${_module.content}\`)
// stylesheet.innerHTML = ''
// stylesheet.appendChild(styles)
// })()
// `;
// path.node.source.value = URL.createObjectURL(
// new Blob([js], { type: 'application/javascript' })
// );
// } else {
// // handle ts file
// path.node.source.value = URL.createObjectURL(
// new Blob(
// [babelTransform(_module.path, _module.content, tabs)],
// {
// type: 'application/javascript',
// }
// )
// );
// }
// } else {
// // Third-party modules
// if (!importmap[module]) {
// importmap[module] = `https://esm.sh/${module}`;
// }
// }
// },
// },
// };
// },
// ],
});
return resultCode;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>preview</title>
</head>
<body>
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react",
"react-dom/client": "https://esm.sh/react-dom/client"
}
}
</script>
<div id="root"></div>
</body>
<script>
window.addEventListener('message', (e) => {
const { type, data } = e.data;
const compileScript = document.createElement('script');
compileScript.type = 'module';
compileScript.innerHTML = data;
Fixed Show fixed Hide fixed
document.body.appendChild(compileScript);
});
</script>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useRef } from 'react';
import iframe from '!!raw-loader!./index.html';
import { MessageChangeType } from '../../types';
const src = URL.createObjectURL(new Blob([iframe], { type: 'text/html' }));

const Preview = ({ compiler }) => {
const iframeRef = useRef<HTMLIFrameElement>(null);
compiler.addEventListener('message', (e) => {
const { data, type } = e.data;
if (type === MessageChangeType.Compile) {
iframeRef.current?.contentWindow?.postMessage({
type,
data,
});
}
});

return (
<iframe
ref={iframeRef}
src={src}
sandbox="allow-scripts allow-same-origin"
frameBorder="1"
width="100%"
height={800}
/>
);
};
export default Preview;
20 changes: 20 additions & 0 deletions packages/design/components/MonacoEditor/context/context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { FC, PropsWithChildren, createContext, useContext, useReducer } from 'react';
import { reducer } from './reducer';

export interface MonacoEditorContextDescriptor {}

export const defaultMonacoEditorValue: MonacoEditorContextDescriptor = {};

const Context = createContext<MonacoEditorContextDescriptor>(defaultMonacoEditorValue);

export const EditorContextProvider: FC<PropsWithChildren<MonacoEditorContextDescriptor>> = ({ children, ...props }) => {
const [state, dispatch] = useReducer(reducer, {
...defaultMonacoEditorValue,
...props,
});
return <Context.Provider value={{ ...state, dispatch }}>{children}</Context.Provider>;
};

export const useEditorContext = () => {
return useContext(Context);
};
11 changes: 11 additions & 0 deletions packages/design/components/MonacoEditor/context/reducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { MonacoEditorContextDescriptor } from './context';

export function reducer(state: MonacoEditorContextDescriptor, action): MonacoEditorContextDescriptor {
switch (action.type) {
case '': {
return { ...state };
}
default:
return { ...state };
}
}
Loading