mirror of
https://github.com/smartxworks/sunmao-ui.git
synced 2025-01-18 16:54:00 +08:00
Merge pull request #35 from webzard-io/runtime
experimental editor component
This commit is contained in:
commit
d9117b824b
52
packages/runtime/example/editor/index.html
Normal file
52
packages/runtime/example/editor/index.html
Normal file
@ -0,0 +1,52 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>meta-ui runtime example: app editor</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script>
|
||||
// https://github.com/satya164/react-simple-code-editor/issues/86
|
||||
const global = globalThis;
|
||||
</script>
|
||||
<script type="module">
|
||||
import renderApp from "../../src/main.tsx";
|
||||
|
||||
renderApp({
|
||||
version: "example/v1",
|
||||
metadata: {
|
||||
name: "editor",
|
||||
description: "nested meta-ui editor",
|
||||
},
|
||||
spec: {
|
||||
components: [
|
||||
{
|
||||
id: "root",
|
||||
type: "chakra_ui/v1/root",
|
||||
properties: {},
|
||||
traits: [],
|
||||
},
|
||||
{
|
||||
id: "editor",
|
||||
type: "lab/v1/editor",
|
||||
properties: {},
|
||||
traits: [
|
||||
{
|
||||
type: "core/v1/slot",
|
||||
properties: {
|
||||
container: {
|
||||
id: "root",
|
||||
slot: "root",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -17,13 +17,16 @@
|
||||
"lodash": "^4.17.21",
|
||||
"mitt": "^3.0.0",
|
||||
"nanoid": "^3.1.23",
|
||||
"prismjs": "^1.24.1",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0",
|
||||
"react-grid-layout": "^1.2.5",
|
||||
"react-markdown": "^6.0.2"
|
||||
"react-markdown": "^6.0.2",
|
||||
"react-simple-code-editor": "^0.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.170",
|
||||
"@types/prismjs": "^1.16.6",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@types/react-grid-layout": "^1.1.2",
|
||||
|
@ -260,7 +260,11 @@ export function resolveNestedComponents(app: RuntimeApplication): {
|
||||
};
|
||||
}
|
||||
|
||||
const App: React.FC<{ options: Application }> = ({ options }) => {
|
||||
const App: React.FC<{
|
||||
options: Application;
|
||||
debugStore?: boolean;
|
||||
debugEvent?: boolean;
|
||||
}> = ({ options, debugStore = true, debugEvent = true }) => {
|
||||
const app = createApplication(options);
|
||||
const { topLevelComponents, componentsMap } = useMemo(
|
||||
() => resolveNestedComponents(app),
|
||||
@ -280,8 +284,8 @@ const App: React.FC<{ options: Application }> = ({ options }) => {
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<DebugStore />
|
||||
<DebugEvent />
|
||||
{debugStore && <DebugStore />}
|
||||
{debugEvent && <DebugEvent />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
23
packages/runtime/src/components/_internal/ErrorBoundary.tsx
Normal file
23
packages/runtime/src/components/_internal/ErrorBoundary.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import React from "react";
|
||||
|
||||
class ErrorBoundary extends React.Component<{}, { error: unknown }> {
|
||||
constructor(props: {}) {
|
||||
super(props);
|
||||
this.state = { error: null };
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error: unknown) {
|
||||
console.log("!!!", { error });
|
||||
return { error };
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.error) {
|
||||
return String(this.state.error);
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
export default ErrorBoundary;
|
99
packages/runtime/src/components/lab/Editor.tsx
Normal file
99
packages/runtime/src/components/lab/Editor.tsx
Normal file
@ -0,0 +1,99 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Application, createComponent, createApplication } from "@meta-ui/core";
|
||||
import { Box, Button } from "@chakra-ui/react";
|
||||
import CodeEditor from "react-simple-code-editor";
|
||||
import { highlight, languages } from "prismjs";
|
||||
import "prismjs/components/prism-json";
|
||||
import "prismjs/themes/prism.css";
|
||||
import { ComponentImplementation } from "../../registry";
|
||||
import ErrorBoundary from "../_internal/ErrorBoundary";
|
||||
import App from "../../App";
|
||||
|
||||
const Editor: ComponentImplementation<{}> = () => {
|
||||
const [code, setCode] = useState(
|
||||
JSON.stringify(
|
||||
{
|
||||
version: "example/v1",
|
||||
kind: "Application",
|
||||
metadata: {
|
||||
name: "live_edit",
|
||||
description:
|
||||
"build meta-ui app with a editor component based on meta-ui",
|
||||
},
|
||||
spec: {
|
||||
components: [],
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
const [codeError, setCodeError] = useState("");
|
||||
const [app, setApp] = useState<Application>(() => JSON.parse(code));
|
||||
useEffect(() => {
|
||||
try {
|
||||
const newApp = JSON.parse(code);
|
||||
// as validation
|
||||
createApplication(newApp);
|
||||
setApp(newApp);
|
||||
setCodeError("");
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
setCodeError(String(error));
|
||||
}
|
||||
}, [code]);
|
||||
|
||||
return (
|
||||
<Box display="flex" height="100vh">
|
||||
<Box flex="1" borderRight="2px solid black">
|
||||
<ErrorBoundary key={JSON.stringify(app)}>
|
||||
<App debugStore={false} debugEvent={false} options={app} />
|
||||
</ErrorBoundary>
|
||||
</Box>
|
||||
<Box width="400px">
|
||||
<Box py={1}>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
try {
|
||||
setCode(JSON.stringify(JSON.parse(code), null, 2));
|
||||
} catch {}
|
||||
}}
|
||||
>
|
||||
format
|
||||
</Button>
|
||||
</Box>
|
||||
<Box background={codeError ? "red.50" : "blue.50"}>
|
||||
<CodeEditor
|
||||
value={code}
|
||||
onValueChange={(code) => setCode(code)}
|
||||
highlight={(code) => highlight(code, languages.json, "JSON")}
|
||||
padding={10}
|
||||
style={{
|
||||
fontFamily: '"Fira code", "Fira Mono", monospace',
|
||||
fontSize: 12,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
{codeError && <Box>{codeError}</Box>}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
...createComponent({
|
||||
version: "lab/v1",
|
||||
metadata: {
|
||||
name: "editor",
|
||||
description: "experimental app editor",
|
||||
},
|
||||
spec: {
|
||||
properties: [],
|
||||
acceptTraits: [],
|
||||
state: {},
|
||||
methods: [],
|
||||
},
|
||||
}),
|
||||
impl: Editor,
|
||||
};
|
@ -1,6 +1,5 @@
|
||||
import React from "react";
|
||||
import { RuntimeComponent, RuntimeTrait } from "@meta-ui/core";
|
||||
import { setStore } from "./store";
|
||||
import { SlotsMap } from "./App";
|
||||
// components
|
||||
/* --- plain --- */
|
||||
@ -20,6 +19,8 @@ import ChakraUICheckbox from "./components/chakra-ui/Checkbox";
|
||||
import ChakraUIStack from "./components/chakra-ui/Stack";
|
||||
import ChakraUIHStack from "./components/chakra-ui/HStack";
|
||||
import ChakraUIVStack from "./components/chakra-ui/VStack";
|
||||
/* --- lab --- */
|
||||
import LabEditor from "./components/lab/Editor";
|
||||
// traits
|
||||
import CoreState from "./traits/core/state";
|
||||
import CoreEvent from "./traits/core/event";
|
||||
@ -40,7 +41,7 @@ type SubscribeMethods = <U>(
|
||||
[K in keyof U]: (parameters: U[K]) => void;
|
||||
}
|
||||
) => void;
|
||||
type MergeState = (partialState: Parameters<typeof setStore>[0]) => void;
|
||||
type MergeState = (partialState: any) => void;
|
||||
|
||||
export type ComponentImplementation<T = any> = React.FC<
|
||||
T & {
|
||||
@ -122,6 +123,7 @@ registry.registerComponent(ChakraUICheckbox);
|
||||
registry.registerComponent(ChakraUIStack);
|
||||
registry.registerComponent(ChakraUIHStack);
|
||||
registry.registerComponent(ChakraUIVStack);
|
||||
registry.registerComponent(LabEditor);
|
||||
|
||||
registry.registerTrait(CoreState);
|
||||
registry.registerTrait(CoreEvent);
|
||||
|
15
yarn.lock
15
yarn.lock
@ -2255,6 +2255,11 @@
|
||||
resolved "http://192.168.26.29:7001/@types/prettier/download/@types/prettier-2.3.2.tgz#fc8c2825e4ed2142473b4a81064e6e081463d1b3"
|
||||
integrity sha1-/IwoJeTtIUJHO0qBBk5uCBRj0bM=
|
||||
|
||||
"@types/prismjs@^1.16.6":
|
||||
version "1.16.6"
|
||||
resolved "http://192.168.26.29:7001/@types/prismjs/download/@types/prismjs-1.16.6.tgz#377054f72f671b36dbe78c517ce2b279d83ecc40"
|
||||
integrity sha1-N3BU9y9nGzbb54xRfOKyedg+zEA=
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.4"
|
||||
resolved "http://192.168.26.29:7001/@types/prop-types/download/@types/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
|
||||
@ -6519,6 +6524,11 @@ pretty-format@^27.0.6:
|
||||
ansi-styles "^5.0.0"
|
||||
react-is "^17.0.1"
|
||||
|
||||
prismjs@^1.24.1:
|
||||
version "1.24.1"
|
||||
resolved "http://192.168.26.29:7001/prismjs/download/prismjs-1.24.1.tgz#c4d7895c4d6500289482fa8936d9cdd192684036"
|
||||
integrity sha1-xNeJXE1lACiUgvqJNtnN0ZJoQDY=
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "http://192.168.26.29:7001/process-nextick-args/download/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
||||
@ -6743,6 +6753,11 @@ react-resizable@^3.0.1:
|
||||
prop-types "15.x"
|
||||
react-draggable "^4.0.3"
|
||||
|
||||
react-simple-code-editor@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "http://192.168.26.29:7001/react-simple-code-editor/download/react-simple-code-editor-0.11.0.tgz#bb57c7c29b570f2ab229872599eac184f5bc673c"
|
||||
integrity sha1-u1fHwptXDyqyKYclmerBhPW8Zzw=
|
||||
|
||||
react-style-singleton@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "http://192.168.26.29:7001/react-style-singleton/download/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66"
|
||||
|
Loading…
Reference in New Issue
Block a user