@ray-js/code-sandbox 0.0.2

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 (48) hide show
  1. package/README.md +121 -0
  2. package/lib/catch-error/index.d.ts +15 -0
  3. package/lib/catch-error/index.js +25 -0
  4. package/lib/codesandbox/index.d.ts +7 -0
  5. package/lib/codesandbox/index.js +50 -0
  6. package/lib/codesandbox/index.module.less +18 -0
  7. package/lib/decoder/index.d.ts +7 -0
  8. package/lib/decoder/index.js +17 -0
  9. package/lib/index.d.ts +6 -0
  10. package/lib/index.js +6 -0
  11. package/lib/listener/index.css +1 -0
  12. package/lib/listener/index.d.ts +10 -0
  13. package/lib/listener/index.js +5 -0
  14. package/lib/listener/index.json +4 -0
  15. package/lib/listener/index.sjs +8 -0
  16. package/lib/listener/index.tyml +6 -0
  17. package/lib/loading/index.d.ts +5 -0
  18. package/lib/loading/index.js +22 -0
  19. package/lib/loading/index.module.less +8 -0
  20. package/lib/txp/codesandbox/code-editor/index.d.ts +42 -0
  21. package/lib/txp/codesandbox/code-editor/index.js +152 -0
  22. package/lib/txp/codesandbox/index.d.ts +19 -0
  23. package/lib/txp/codesandbox/index.js +121 -0
  24. package/lib/txp/codesandbox/index.style.d.ts +7 -0
  25. package/lib/txp/codesandbox/index.style.js +28 -0
  26. package/lib/txp/codesandbox/postSandboxCode.d.ts +2 -0
  27. package/lib/txp/codesandbox/postSandboxCode.js +36 -0
  28. package/lib/txp/demo/index.d.ts +13 -0
  29. package/lib/txp/demo/index.js +54 -0
  30. package/lib/txp/demo/index.style.d.ts +2 -0
  31. package/lib/txp/demo/index.style.js +14 -0
  32. package/lib/txp/hooks/useAsync.d.ts +14 -0
  33. package/lib/txp/hooks/useAsync.js +37 -0
  34. package/lib/txp/hooks/useTestUrl.d.ts +1 -0
  35. package/lib/txp/hooks/useTestUrl.js +12 -0
  36. package/lib/txp/index.d.ts +3 -0
  37. package/lib/txp/index.js +3 -0
  38. package/lib/txp/sandbox/index.d.ts +7 -0
  39. package/lib/txp/sandbox/index.js +32 -0
  40. package/lib/txp/sandbox/index.style.d.ts +17 -0
  41. package/lib/txp/sandbox/index.style.js +20 -0
  42. package/lib/txp/services/index.d.ts +4 -0
  43. package/lib/txp/services/index.js +12 -0
  44. package/lib/txp/services/interface.d.ts +9 -0
  45. package/lib/txp/services/interface.js +1 -0
  46. package/lib/txp/utils/theme-vars.d.ts +1032 -0
  47. package/lib/txp/utils/theme-vars.js +1032 -0
  48. package/package.json +77 -0
package/README.md ADDED
@@ -0,0 +1,121 @@
1
+ English | [简体中文](./README-zh_CN.md)
2
+
3
+ # @ray/code-sandbox
4
+
5
+ [![latest](https://img.shields.io/npm/v/@ray/code-sandbox/latest.svg)](https://www.npmjs.com/package/@ray/code-sandbox) [![download](https://img.shields.io/npm/dt/@ray/code-sandbox.svg)](https://www.npmjs.com/package/@ray/code-sandbox)
6
+
7
+ > 小程序 CodeSandbox 容器
8
+
9
+ ## Installation
10
+
11
+ ```sh
12
+ $ npm install @ray/code-sandbox
13
+ # or
14
+ $ yarn add @ray/code-sandbox
15
+ ```
16
+
17
+ ## Develop
18
+
19
+ ```sh
20
+ # watch compile component code
21
+ yarn watch
22
+ # watch compile demo
23
+ yarn start:tuya
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ### 小程序对接
29
+
30
+ 安装必须的依赖
31
+
32
+ ```sh
33
+ yarn add @ray/code-sandbox @ray-js/ray @ray-js/smart-ui @tuya-miniapp/smart-ui
34
+ ```
35
+
36
+ pages 目录下新建 playground 页面,内容如下
37
+
38
+ ```tsx
39
+ import React from 'react';
40
+ import CodeSandbox from '@ray/code-sandbox';
41
+
42
+ import * as RayComponents from '@ray-js/ray';
43
+
44
+ export default function Home() {
45
+ return (
46
+ <CodeSandbox
47
+ defaultTitle="CodeSandbox"
48
+ context={{
49
+ // CodeSandbox 中可 import from 的三方库
50
+ '@ray-js/ray': RayComponents,
51
+ }}
52
+ />
53
+ );
54
+ }
55
+ ```
56
+
57
+ 页面 index.config 配置自定义 Topbar
58
+
59
+ ```tsx
60
+ export default {
61
+ navigationStyle: 'custom',
62
+ };
63
+
64
+ ```
65
+
66
+ ### 平台对接
67
+
68
+ 安装必须的依赖
69
+
70
+ ```sh
71
+ yarn add @ray/code-sandbox antd axios styled-components lodash @saber2pr/monaco
72
+ ```
73
+
74
+ 方式1: 引入 CodeSandbox 编辑器到页面中:
75
+
76
+ ```tsx
77
+ import { CodeSandboxButton } from '@ray/code-sandbox/lib/txp'
78
+
79
+ <CodeSandboxButton
80
+ title="Playground" // 编辑器弹窗的标题
81
+ code={`
82
+ import { Button } from '@ray-js/smartui';
83
+
84
+ export default function Demo() {
85
+ return <Button>测试</Button>
86
+ }
87
+
88
+ `}
89
+ txpCode="SmartUi" // 这里填写 TxP 上的组件code
90
+ pageName="playground" // 小程序项目中引入 codesandbox 组件的页面名,例如pages/playground/index,pageName就是playground
91
+ />
92
+ ```
93
+
94
+ 点击按钮后就会弹窗打开 codesandbox 编辑器
95
+
96
+ 方式2: 不使用按钮弹窗,直接接入编辑器+模拟器:
97
+
98
+ ```tsx
99
+ import { CodeSandbox } from '@ray/code-sandbox/lib/txp'
100
+
101
+ <CodeSandbox
102
+ title="Button 组件" // demo 容器中的标题
103
+ code={`
104
+ import { Button } from '@ray-js/smartui';
105
+
106
+ export default function Demo() {
107
+ return <Button>测试</Button>
108
+ }
109
+
110
+ `}
111
+ txpCode="SmartUi" // 这里填写 TxP 上的组件code
112
+ pageName="playground" // 小程序项目中引入 codesandbox 组件的页面名,例如pages/playground/index,pageName就是playground
113
+ />
114
+ ```
115
+
116
+ ### 注意
117
+
118
+ 1. txpCode 指定的组件,需要在 TxP 平台上经过 ci Demo构建才可以接入到 CodeSandbox 模拟器中。
119
+
120
+ 2. 编辑器涉及的资源、组件 Demo 容器都已上传到涂鸦 CDN,可在对外项目中使用。
121
+ 3. 模拟器中大部分 BaseKit 能力支持,部分设备相关的 TTT 方法暂不支持。
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ interface State {
3
+ hasError: boolean;
4
+ }
5
+ interface IProps {
6
+ }
7
+ export default class CatchError extends React.Component<IProps, State> {
8
+ static defaultProps: IProps;
9
+ constructor(props: IProps);
10
+ static getDerivedStateFromError(error: any): {
11
+ hasError: boolean;
12
+ };
13
+ render(): React.ReactNode;
14
+ }
15
+ export {};
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { SandboxLoading } from '../loading';
3
+ // 记录一下react层崩溃
4
+ // react层崩溃会导致后续的eventchannel代码拿不到
5
+ export default class CatchError extends React.Component {
6
+ constructor(props) {
7
+ super(props);
8
+ this.state = {
9
+ hasError: false
10
+ };
11
+ }
12
+ static getDerivedStateFromError() {
13
+ return {
14
+ hasError: true
15
+ };
16
+ }
17
+ render() {
18
+ if (this.state.hasError) {
19
+ return /*#__PURE__*/React.createElement(SandboxLoading, {
20
+ type: "crash"
21
+ });
22
+ }
23
+ return this.props.children;
24
+ }
25
+ }
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ export interface SandboxProps {
3
+ defaultTitle?: string;
4
+ context: any;
5
+ }
6
+ declare const CodeSandbox: React.FC<SandboxProps>;
7
+ export default CodeSandbox;
@@ -0,0 +1,50 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
+ import React, * as ReactLib from 'react';
3
+ import Decoder from '../decoder';
4
+ import { SandboxLoading } from '../loading';
5
+ import styles from './index.module.less';
6
+ import { ScrollView, View } from '@ray-js/ray';
7
+ const CodeSandbox = _ref => {
8
+ let {
9
+ context: __ctx,
10
+ defaultTitle = 'CodeSandbox'
11
+ } = _ref;
12
+ // 创建上下文对象
13
+ // 设置上下文可用的组件
14
+ const context = _objectSpread(_objectSpread({}, __ctx || {}), {}, {
15
+ ___setContent___: () => /*#__PURE__*/React.createElement(React.Fragment, null),
16
+ __loading__: SandboxLoading,
17
+ // CodeSandbox 中可 import from 的三方库
18
+ React,
19
+ react: ReactLib
20
+ });
21
+ const [title, setTitle] = React.useState(defaultTitle);
22
+ const [content, setContent] = React.useState( /*#__PURE__*/React.createElement(context.__loading__, null));
23
+ // @ts-ignore
24
+ context.___setContent___ = setContent;
25
+ // @ts-ignore
26
+ context.___setTitle___ = setTitle;
27
+ return /*#__PURE__*/React.createElement(View, {
28
+ className: styles.contain
29
+ }, /*#__PURE__*/React.createElement(View, {
30
+ className: styles.topbar
31
+ }, title), /*#__PURE__*/React.createElement(ScrollView, {
32
+ className: styles.content,
33
+ scrollY: true,
34
+ refresherTriggered: false
35
+ }, /*#__PURE__*/React.createElement(Decoder, {
36
+ onCodeChange: code => {
37
+ // 获取到txp编辑器发送的js代码
38
+ // 闭包保留变量名
39
+ (function (__ctx__) {
40
+ console.log(__ctx__); // 这里需要引用一下闭包变量来绑定, 请勿删除此行
41
+ try {
42
+ eval(`${code}`);
43
+ } catch (error) {
44
+ console.log('[sandbox] error', error);
45
+ }
46
+ })(context);
47
+ }
48
+ }, content)));
49
+ };
50
+ export default CodeSandbox;
@@ -0,0 +1,18 @@
1
+ page {
2
+ height: 100vh;
3
+ }
4
+
5
+ .contain {
6
+ height: 100vh;
7
+ }
8
+
9
+ .topbar {
10
+ border-bottom: 1px solid #efefef;
11
+ background-color: #fff;
12
+ height: 60px;
13
+ padding-top: 28px;
14
+ }
15
+
16
+ .content {
17
+ height: calc(100vh - 60px);
18
+ }
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ export interface DecoderProps {
3
+ onCodeChange(code: string): void;
4
+ children?: React.ReactNode;
5
+ }
6
+ export declare const Decoder: React.FC<DecoderProps>;
7
+ export default Decoder;
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import Channel from '../listener';
3
+ import * as Bases64 from 'js-base64';
4
+ import CatchError from '../catch-error';
5
+ export const Decoder = _ref => {
6
+ let {
7
+ onCodeChange,
8
+ children
9
+ } = _ref;
10
+ return /*#__PURE__*/React.createElement(CatchError, null, /*#__PURE__*/React.createElement(Channel, {
11
+ binddata: event => {
12
+ const code = Bases64.decode(event.detail);
13
+ onCodeChange(code);
14
+ }
15
+ }), children);
16
+ };
17
+ export default Decoder;
package/lib/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from './catch-error';
2
+ export * from './decoder';
3
+ export * from './listener';
4
+ export * from './loading';
5
+ export * from './codesandbox';
6
+ export { default } from './codesandbox';
package/lib/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './catch-error';
2
+ export * from './decoder';
3
+ export * from './listener';
4
+ export * from './loading';
5
+ export * from './codesandbox';
6
+ export { default } from './codesandbox';
@@ -0,0 +1 @@
1
+ /* pages/sandbox.css */
@@ -0,0 +1,10 @@
1
+ /* eslint-disable react/require-default-props */
2
+ import React from 'react';
3
+
4
+ export interface ChannelProps {
5
+ binddata(event: { detail: string });
6
+ }
7
+
8
+ const Channel: React.FC<ChannelProps>;
9
+
10
+ export default Channel;
@@ -0,0 +1,5 @@
1
+ Component({
2
+ properties: {
3
+ instanceId: String
4
+ }
5
+ });
@@ -0,0 +1,4 @@
1
+ {
2
+ "component": true,
3
+ "usingComponents": {}
4
+ }
@@ -0,0 +1,8 @@
1
+ module.exports = {
2
+ init(newVal, oldVal, ownerInstance) {
3
+ ownerInstance.eventChannel.on('sandbox-jsrun', event => {
4
+ console.log(`[sandbox] trigger `, event);
5
+ ownerInstance.triggerEvent('data', event);
6
+ });
7
+ },
8
+ };
@@ -0,0 +1,6 @@
1
+ <sjs src="./index.sjs" module="computed"></sjs>
2
+
3
+ <view
4
+ id="{{instanceId}}"
5
+ change:id="{{computed.init}}"
6
+ ></view>
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ export interface SandboxLoadingProps {
3
+ type?: 'compile' | 'crash';
4
+ }
5
+ export declare const SandboxLoading: React.FC<SandboxLoadingProps>;
@@ -0,0 +1,22 @@
1
+ import { View } from '@ray-js/ray';
2
+ import React from 'react';
3
+ import { Loading, Button } from '@ray-js/smart-ui';
4
+ import styles from './index.module.less';
5
+ export const SandboxLoading = _ref => {
6
+ let {
7
+ type = 'compile'
8
+ } = _ref;
9
+ return /*#__PURE__*/React.createElement(View, {
10
+ className: styles.loading
11
+ }, /*#__PURE__*/React.createElement(View, null, type === 'compile' ? /*#__PURE__*/React.createElement(Loading, null) : /*#__PURE__*/React.createElement(Button, {
12
+ onClick: () => {
13
+ // reloadSandbox 方法是 ci 打包时注入的 api,和 txp 平台交互(postmessage)
14
+ // @ts-ignore
15
+ ty.reloadSandbox();
16
+ }
17
+ }, "\u70B9\u51FB\u5237\u65B0")), /*#__PURE__*/React.createElement(View, {
18
+ style: {
19
+ marginTop: 16
20
+ }
21
+ }, type === 'compile' ? `小程序 CodeSandbox 编译中` : '语法错误,请修正后刷新'));
22
+ };
@@ -0,0 +1,8 @@
1
+ .loading {
2
+ display: flex;
3
+ flex-direction: column;
4
+ align-items: center;
5
+ justify-content: center;
6
+ height: 200px;
7
+ width: 100%;
8
+ }
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ export interface CodeEditorProps {
3
+ code: string;
4
+ onChange(code: string): void;
5
+ title: string;
6
+ show: boolean;
7
+ height: string;
8
+ txpCode: string;
9
+ baseUri: string;
10
+ }
11
+ export declare const CodeEditor: React.ForwardRefExoticComponent<CodeEditorProps & React.RefAttributes<{
12
+ monaco: typeof import("monaco-editor");
13
+ setValue: (value: string, fileName?: string | undefined) => void;
14
+ getValue: (fileName?: string | undefined) => string;
15
+ getInstance: () => import("monaco-editor").editor.IStandaloneCodeEditor;
16
+ changeModel: (fileName: string) => void;
17
+ getData: () => import("@saber2pr/monaco").EditorData;
18
+ setSize: (width: number, height: number) => void;
19
+ getSize: () => import("monaco-editor").editor.EditorLayoutInfo;
20
+ getModel: (fileName?: string | undefined) => import("monaco-editor").editor.ITextModel;
21
+ getState: (fileName: string) => import("monaco-editor").editor.ICodeEditorViewState;
22
+ setState: (fileName: string, state: any) => void;
23
+ getMarkers: (fileName?: string | undefined) => import("monaco-editor").editor.IMarker[];
24
+ setTheme: (themeName: import("@saber2pr/monaco").ThemeNames) => Promise<void>;
25
+ hasTheme: (theme: string) => any;
26
+ getThemeConfig: (themeFile: string) => Promise<any>;
27
+ getThemeList: () => Promise<any>;
28
+ getOutput: (fileName?: string | undefined) => Promise<{
29
+ markers: import("monaco-editor").editor.IMarker[];
30
+ output: string;
31
+ diagnostics: import("monaco-editor").languages.typescript.Diagnostic[];
32
+ }>;
33
+ addExtraLib: (content: string, filePath?: string | undefined) => import("monaco-editor").IDisposable;
34
+ getTypescriptDefaults: () => import("monaco-editor").languages.typescript.LanguageServiceDefaults;
35
+ compileTS: (uri?: import("monaco-editor").Uri | undefined) => Promise<{
36
+ output: string;
37
+ diagnostics: import("monaco-editor").languages.typescript.Diagnostic[];
38
+ }>;
39
+ updateCompilerOptions: (options: import("monaco-editor").languages.typescript.CompilerOptions) => void;
40
+ addModuleDeclaration: (url: string, moduleName?: string | undefined) => Promise<any>;
41
+ getNavigationBarItems: (uri?: import("monaco-editor").Uri | undefined) => Promise<import("typescript").NavigationBarItem[]>;
42
+ }>>;
@@ -0,0 +1,152 @@
1
+ import { Spin } from 'antd';
2
+ import { getComponentResource } from '../../services';
3
+ import React, { useEffect, useImperativeHandle, useRef, useState } from 'react';
4
+ import { Editor } from '@saber2pr/monaco';
5
+ const timeout = function () {
6
+ let delay = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1000;
7
+ return new Promise(resolve => setTimeout(resolve, delay));
8
+ };
9
+ export const CodeEditor = /*#__PURE__*/React.forwardRef((_ref, parentRef) => {
10
+ let {
11
+ code,
12
+ onChange,
13
+ title,
14
+ show,
15
+ height,
16
+ txpCode,
17
+ baseUri
18
+ } = _ref;
19
+ const [initloading, setInitLoading] = useState(true);
20
+ const ref = useRef();
21
+ const initMonaco = async editor => {
22
+ ref.current = editor;
23
+ editor.setValue(`${code}`);
24
+ editor.getModel().onDidChangeContent(async () => {
25
+ const result = await editor.compileTS();
26
+ onChange(result.output);
27
+ });
28
+ const addTypeLib = async (name, wrapName) => {
29
+ try {
30
+ let smartUiTypes = await getComponentResource(baseUri, txpCode, name);
31
+ if (wrapName) {
32
+ smartUiTypes = `declare module "${wrapName}" { ${smartUiTypes} };`;
33
+ }
34
+ editor.addExtraLib(smartUiTypes, name);
35
+ } catch (error) {}
36
+ };
37
+
38
+ // react
39
+ await addTypeLib('react.d.ts');
40
+ // @ray-js/smartui
41
+ await addTypeLib('smartui.d.ts');
42
+ // @ray-js/ray
43
+ await addTypeLib('ray.d.ts');
44
+ // csstypes
45
+ await addTypeLib('csstype.d.ts', 'csstype');
46
+ // prop-types
47
+ await addTypeLib('prop-types.d.ts', 'prop-types');
48
+
49
+ // BaseKit Kit types
50
+ await addTypeLib('BaseKit.d.ts');
51
+ // BizKit Kit types
52
+ await addTypeLib('BizKit.d.ts');
53
+ // Device Kit types
54
+ await addTypeLib('DeviceKit.d.ts');
55
+ // MiniKit Kit types
56
+ await addTypeLib('MiniKit.d.ts');
57
+
58
+ // rayKit
59
+ await addTypeLib('rayKit.d.ts');
60
+ };
61
+ useEffect(() => {
62
+ const handle = async event => {
63
+ const data = (event === null || event === void 0 ? void 0 : event.data) || {};
64
+ if (data.type === 'sandbox-inited') {
65
+ let editor = ref.current;
66
+
67
+ // wait for editor inited
68
+ // max 30s
69
+ let index = 0;
70
+ while (true) {
71
+ index++;
72
+ if (index > 60) {
73
+ break;
74
+ }
75
+ editor = ref.current;
76
+ if (editor) {
77
+ break;
78
+ }
79
+ await timeout(500);
80
+ }
81
+ if (editor) {
82
+ const result = await editor.compileTS();
83
+ onChange(result.output);
84
+ }
85
+ }
86
+ };
87
+ window.addEventListener('message', handle);
88
+ return () => {
89
+ window.removeEventListener('message', handle);
90
+ };
91
+ }, [show]);
92
+ useEffect(() => {
93
+ const destroyOnClose = () => {
94
+ const api = ref.current;
95
+ if (!show) {
96
+ if (api) {
97
+ const model = api.getModel();
98
+ if (model) {
99
+ model.dispose();
100
+ }
101
+ }
102
+ }
103
+ };
104
+ destroyOnClose();
105
+ return () => {
106
+ destroyOnClose();
107
+ };
108
+ }, [show]);
109
+ useImperativeHandle(parentRef, () => ref.current);
110
+ return /*#__PURE__*/React.createElement(Spin, {
111
+ spinning: initloading
112
+ }, code && /*#__PURE__*/React.createElement(Editor, {
113
+ loaderConfig: {
114
+ paths: {
115
+ vs: `${baseUri}/static/txp-static-txp-monaco-editor/min/vs`
116
+ },
117
+ 'vs/nls': {
118
+ availableLanguages: {
119
+ '*': 'zh-cn'
120
+ }
121
+ },
122
+ themeUri: `${baseUri}/static/txp-static-txp-monaco-editor/themes/`
123
+ },
124
+ theme: "monokai-bright",
125
+ style: {
126
+ height
127
+ },
128
+ options: {
129
+ minimap: {
130
+ enabled: false
131
+ },
132
+ theme: 'vs-dark'
133
+ },
134
+ deps: [title, code],
135
+ modalFiles: {
136
+ 'main.tsx': ''
137
+ },
138
+ tsconfig: {
139
+ strict: false,
140
+ lib: ['esnext', 'dom'],
141
+ module: 3,
142
+ jsx: 2,
143
+ allowJs: true,
144
+ skipLibCheck: true,
145
+ moduleResolution: 2
146
+ },
147
+ onInit: async editor => {
148
+ initMonaco(editor);
149
+ setInitLoading(false);
150
+ }
151
+ }));
152
+ });
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ export interface CodeSandboxProps {
3
+ code: string;
4
+ title: string;
5
+ show?: boolean;
6
+ txpCode: string;
7
+ pageName: string;
8
+ baseUri: string;
9
+ }
10
+ export declare const CodeSandbox: React.FC<CodeSandboxProps>;
11
+ export declare const checkShowCodeSandbox: (code: string) => boolean;
12
+ export declare const CodeSandboxButton: React.FC<{
13
+ code: string;
14
+ title: string;
15
+ txpCode: string;
16
+ tooltip?: string;
17
+ pageName: string;
18
+ baseUri: string;
19
+ }>;