Merge pull request #37 from webzard-io/runtime

define UI API service, related to #9
This commit is contained in:
yz-yu 2021-08-11 17:14:59 +08:00 committed by GitHub
commit b1f41cdaff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 93 additions and 56 deletions

View File

@ -8,7 +8,7 @@
<body>
<div id="root"></div>
<script type="module">
import renderApp from "../../src/main.tsx";
import renderApp, { runTest } from "../../src/main.tsx";
renderApp({
version: "example/v1",
metadata: {

View File

@ -7,10 +7,6 @@
</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";

View File

@ -12,6 +12,7 @@
"@sinclair/typebox": "^0.19.2",
"@vue-reactivity/watch": "^0.1.6",
"@vue/reactivity": "^3.1.5",
"copy-to-clipboard": "^3.3.1",
"dayjs": "^1.10.6",
"framer-motion": "^4",
"lodash": "^4.17.21",

View File

@ -12,11 +12,13 @@ import {
} from "@meta-ui/core";
import { merge } from "lodash";
import { registry } from "./registry";
import { emitter, stateStore, deepEval } from "./store";
import { stateStore, deepEval } from "./store";
import { apiService } from "./api-service";
import { ContainerPropertySchema } from "./traits/core/slot";
import { Static } from "@sinclair/typebox";
import { watch } from "@vue-reactivity/watch";
import _ from "lodash";
import copy from "copy-to-clipboard";
const ImplWrapper = React.forwardRef<
HTMLDivElement,
@ -39,16 +41,23 @@ const ImplWrapper = React.forwardRef<
const handlerMap = useRef<Record<string, (parameters?: any) => void>>({});
useEffect(() => {
const handler = (s: { name: string; parameters?: any }) => {
const handler = (s: {
componentId: string;
name: string;
parameters?: any;
}) => {
if (s.componentId !== c.id) {
return;
}
if (!handlerMap.current[s.name]) {
// maybe log?
return;
}
handlerMap.current[s.name](s.parameters);
};
emitter.on(c.id, handler);
apiService.on("uiMethod", handler);
return () => {
emitter.off(c.id, handler);
apiService.off("uiMethod", handler);
};
}, []);
@ -180,26 +189,35 @@ const DebugEvent: React.FC = () => {
useEffect(() => {
const handler = (type: string, event: unknown) => {
setEvents((cur) =>
cur.concat({ type, event, t: new Date().toLocaleString() })
);
setEvents((cur) => cur.concat({ type, event, t: new Date() }));
};
emitter.on("*", handler);
return () => emitter.off("*", handler);
apiService.on("*", handler);
return () => apiService.off("*", handler);
}, []);
return (
<div
style={{
padding: "0.5em",
border: "2px solid black",
maxHeight: "200px",
overflow: "auto",
}}
>
{events.map((event, idx) => (
<pre key={idx}>{JSON.stringify(event)}</pre>
))}
<div>
<div>
<button
onClick={() => {
copy(JSON.stringify(events));
}}
>
copy test case
</button>
</div>
<div
style={{
padding: "0.5em",
border: "2px solid black",
maxHeight: "200px",
overflow: "auto",
}}
>
{events.map((event, idx) => (
<pre key={idx}>{JSON.stringify(event)}</pre>
))}
</div>
</div>
);
};

View File

@ -0,0 +1,19 @@
import mitt from "mitt";
const emitter = mitt<{
/**
* @description: trigger component's method
* @example: { componentId: "btn1", name: "click" }
*/
uiMethod: {
componentId: string;
name: string;
parameters?: any;
};
}>();
export const apiService = {
on: emitter.on,
off: emitter.off,
send: emitter.emit,
};

View File

@ -2,6 +2,9 @@ import React from "react";
import ReactDOM from "react-dom";
import { Application } from "@meta-ui/core";
import App from "./App";
import { mountUtilMethods } from "./util-methods";
mountUtilMethods();
export default function renderApp(options: Application) {
ReactDOM.render(

View File

@ -1,5 +1,4 @@
import _ from "lodash";
import mitt from "mitt";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { reactive } from "@vue/reactivity";
@ -30,15 +29,6 @@ function parseExpression(raw: string): {
};
}
export const emitter = mitt<Record<string, any>>();
// EXPERIMENT: utils
emitter.on("$utils", ({ name, parameters }) => {
if (name === "alert") {
window.alert(parameters);
}
});
function isNumeric(x: string | number) {
return !isNaN(Number(x));
}

View File

@ -1,32 +1,22 @@
import { useEffect, useMemo, useRef } from "react";
import { useCallback, useEffect, useMemo, useRef } from "react";
import { createTrait } from "@meta-ui/core";
import { Static, Type } from "@sinclair/typebox";
import { nanoid } from "nanoid";
import { debounce, throttle, delay } from "lodash";
import { TraitImplementation } from "../../registry";
import { emitter } from "../../store";
import { apiService } from "../../api-service";
const useEventTrait: TraitImplementation<{
events: Static<typeof EventsPropertySchema>;
}> = ({ events }) => {
const hookId = useMemo(() => {
return nanoid();
}, []);
const handlerMap = useRef<Record<string, Array<(parameters?: any) => void>>>(
{}
);
useEffect(() => {
const handler = (s: { name: string; parameters?: any }) => {
if (!handlerMap.current[s.name]) {
// maybe log?
return;
}
handlerMap.current[s.name].forEach((fn) => fn(s.parameters));
};
emitter.on(hookId, handler);
return () => {
emitter.off(hookId, handler);
};
const eventHandler = useCallback((s: { name: string; parameters?: any }) => {
if (!handlerMap.current[s.name]) {
// maybe log?
return;
}
handlerMap.current[s.name].forEach((fn) => fn(s.parameters));
}, []);
useEffect(() => {
@ -42,7 +32,8 @@ const useEventTrait: TraitImplementation<{
if (disabled) {
return;
}
emitter.emit(event.componentId, {
apiService.send("uiMethod", {
componentId: event.componentId,
name: event.method.name,
parameters: event.method.parameters,
});
@ -66,7 +57,9 @@ const useEventTrait: TraitImplementation<{
return {
// HARDCODE
onClick() {
emitter.emit(hookId, { name: "click" });
eventHandler({
name: "click",
});
},
};
}, []);

View File

@ -0,0 +1,17 @@
import { apiService } from "./api-service";
export function mountUtilMethods() {
apiService.on("uiMethod", ({ componentId, name, parameters }) => {
if (componentId !== "$utils") {
return;
}
switch (name) {
case "alert":
window.alert(parameters);
break;
default:
break;
}
});
}

View File

@ -3226,7 +3226,7 @@ convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0,
dependencies:
safe-buffer "~5.1.1"
copy-to-clipboard@3.3.1:
copy-to-clipboard@3.3.1, copy-to-clipboard@^3.3.1:
version "3.3.1"
resolved "http://192.168.26.29:7001/copy-to-clipboard/download/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae"
integrity sha1-EVqhqZmP+rYZb5MHatbaO5E2Yq4=