mirror of
https://github.com/smartxworks/sunmao-ui.git
synced 2024-11-21 03:15:49 +08:00
impl basic grid layout
This commit is contained in:
parent
e5a2895758
commit
011ccde187
88
packages/runtime/example/grid-layout/basic.html
Normal file
88
packages/runtime/example/grid-layout/basic.html
Normal file
@ -0,0 +1,88 @@
|
||||
<!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: basic grid layout</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module">
|
||||
import renderApp from "../../src/main.tsx";
|
||||
renderApp({
|
||||
version: "example/v1",
|
||||
metadata: {
|
||||
name: "basic_grid_layout",
|
||||
description: "basic grid layout example",
|
||||
},
|
||||
spec: {
|
||||
components: [
|
||||
{
|
||||
id: "grid_container",
|
||||
type: "core/v1/grid_layout",
|
||||
properties: {
|
||||
layout: [
|
||||
{
|
||||
x: 4,
|
||||
y: 0,
|
||||
w: 4,
|
||||
h: 9,
|
||||
i: "box1",
|
||||
},
|
||||
{
|
||||
x: 8,
|
||||
y: 0,
|
||||
w: 2,
|
||||
h: 12,
|
||||
i: "box2",
|
||||
},
|
||||
],
|
||||
},
|
||||
traits: [],
|
||||
},
|
||||
{
|
||||
id: "box1",
|
||||
type: "chakra_ui/v1/box",
|
||||
properties: {
|
||||
border: "2px solid blue",
|
||||
w: "100%",
|
||||
h: "100%",
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: "core/v1/slot",
|
||||
properties: {
|
||||
container: {
|
||||
id: "grid_container",
|
||||
slot: "container",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "box2",
|
||||
type: "chakra_ui/v1/box",
|
||||
properties: {
|
||||
bgColor: "pink",
|
||||
w: "100%",
|
||||
h: "100%",
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: "core/v1/slot",
|
||||
properties: {
|
||||
container: {
|
||||
id: "grid_container",
|
||||
slot: "container",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -17,6 +17,7 @@
|
||||
"nanoid": "^3.1.23",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0",
|
||||
"react-grid-layout": "^1.2.5",
|
||||
"react-markdown": "^6.0.2",
|
||||
"zustand": "^3.5.5"
|
||||
},
|
||||
@ -24,6 +25,7 @@
|
||||
"@types/lodash": "^4.14.170",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@types/react-grid-layout": "^1.1.2",
|
||||
"@vitejs/plugin-react-refresh": "^1.3.1",
|
||||
"typescript": "^4.3.2",
|
||||
"vite": "^2.3.8"
|
||||
|
@ -16,10 +16,13 @@ import { setStore, useStore, emitter } from "./store";
|
||||
import { ContainerPropertySchema } from "./traits/core/slot";
|
||||
import { Static } from "@sinclair/typebox";
|
||||
|
||||
const ImplWrapper: React.FC<{
|
||||
component: RuntimeApplication["spec"]["components"][0];
|
||||
slotsMap: SlotsMap | undefined;
|
||||
}> = ({ component: c, slotsMap }) => {
|
||||
const ImplWrapper = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
{
|
||||
component: RuntimeApplication["spec"]["components"][0];
|
||||
slotsMap: SlotsMap | undefined;
|
||||
}
|
||||
>(({ component: c, slotsMap, ...props }, ref) => {
|
||||
const Impl = registry.getComponent(
|
||||
c.parsedType.version,
|
||||
c.parsedType.name
|
||||
@ -90,8 +93,13 @@ const ImplWrapper: React.FC<{
|
||||
C = <W>{C}</W>;
|
||||
}
|
||||
|
||||
return C;
|
||||
};
|
||||
return (
|
||||
<div key={c.id} data-meta-ui-id={c.id} ref={ref} {...props}>
|
||||
{C}
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const DebugStore: React.FC = () => {
|
||||
const store = useStore();
|
||||
@ -129,7 +137,13 @@ const DebugEvent: React.FC = () => {
|
||||
};
|
||||
|
||||
export type ComponentsMap = Map<string, SlotsMap>;
|
||||
export type SlotsMap = Map<string, Array<React.FC>>;
|
||||
export type SlotsMap = Map<
|
||||
string,
|
||||
Array<{
|
||||
component: React.FC;
|
||||
id: string;
|
||||
}>
|
||||
>;
|
||||
export function resolveNestedComponents(app: RuntimeApplication): {
|
||||
topLevelComponents: RuntimeApplication["spec"]["components"];
|
||||
componentsMap: ComponentsMap;
|
||||
@ -154,9 +168,17 @@ export function resolveNestedComponents(app: RuntimeApplication): {
|
||||
componentsMap
|
||||
.get(id)
|
||||
?.get(slot)
|
||||
?.push(() => (
|
||||
<ImplWrapper component={c} slotsMap={componentsMap.get(c.id)} />
|
||||
));
|
||||
?.push({
|
||||
component: React.forwardRef<HTMLDivElement, any>((props, ref) => (
|
||||
<ImplWrapper
|
||||
component={c}
|
||||
slotsMap={componentsMap.get(c.id)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
)),
|
||||
id: c.id,
|
||||
});
|
||||
} else {
|
||||
topLevelComponents.push(c);
|
||||
}
|
||||
|
29
packages/runtime/src/components/_internal/GridLayout.tsx
Normal file
29
packages/runtime/src/components/_internal/GridLayout.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import React from "react";
|
||||
import RGL, { WidthProvider } from "react-grid-layout";
|
||||
import { Static, Type } from "@sinclair/typebox";
|
||||
import "react-grid-layout/css/styles.css";
|
||||
import "react-resizable/css/styles.css";
|
||||
|
||||
const ReactGridLayout = WidthProvider(RGL);
|
||||
|
||||
export const LayoutPropertySchema = Type.Array(
|
||||
Type.Object({
|
||||
x: Type.Number(),
|
||||
y: Type.Number(),
|
||||
w: Type.Number(),
|
||||
h: Type.Number(),
|
||||
i: Type.String(),
|
||||
})
|
||||
);
|
||||
|
||||
const GridLayout: React.FC<{
|
||||
layout: Static<typeof LayoutPropertySchema>;
|
||||
}> = ({ children, layout }) => {
|
||||
return (
|
||||
<ReactGridLayout rowHeight={30} layout={layout}>
|
||||
{children}
|
||||
</ReactGridLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default GridLayout;
|
@ -1,17 +1,17 @@
|
||||
import React from "react";
|
||||
import { SlotsMap } from "../../App";
|
||||
|
||||
export function getSlots(slotsMap: SlotsMap | undefined, slot: string) {
|
||||
return (slotsMap?.get(slot) || []).map(({ component: ImplWrapper, id }) => (
|
||||
<ImplWrapper key={id} />
|
||||
));
|
||||
}
|
||||
|
||||
const Slot: React.FC<{ slotsMap: SlotsMap | undefined; slot: string }> = ({
|
||||
slotsMap,
|
||||
slot,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
{(slotsMap?.get(slot) || []).map((ImplWrapper, idx) => (
|
||||
<ImplWrapper key={idx} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
return <>{getSlots(slotsMap, slot)}</>;
|
||||
};
|
||||
|
||||
export default Slot;
|
||||
|
39
packages/runtime/src/components/core/GridLayout.tsx
Normal file
39
packages/runtime/src/components/core/GridLayout.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import React, { Suspense } from "react";
|
||||
import { ComponentImplementation } from "../../registry";
|
||||
import { createComponent } from "@meta-ui/core";
|
||||
import { getSlots } from "../_internal/Slot";
|
||||
import { LayoutPropertySchema } from "../../components/_internal/GridLayout";
|
||||
import { Static } from "@sinclair/typebox";
|
||||
|
||||
const BaseGridLayout = React.lazy(
|
||||
() => import("../../components/_internal/GridLayout")
|
||||
);
|
||||
|
||||
const GridLayout: ComponentImplementation<{
|
||||
layout: Static<typeof LayoutPropertySchema>;
|
||||
}> = ({ slotsMap, layout = [] }) => {
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<BaseGridLayout layout={layout}>
|
||||
{getSlots(slotsMap, "container")}
|
||||
</BaseGridLayout>
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
...createComponent({
|
||||
version: "core/v1",
|
||||
metadata: {
|
||||
name: "grid_layout",
|
||||
description: "drag and drop to layout in a grid",
|
||||
},
|
||||
spec: {
|
||||
properties: [{ name: "layout", ...LayoutPropertySchema }],
|
||||
acceptTraits: [],
|
||||
state: {},
|
||||
methods: [],
|
||||
},
|
||||
}),
|
||||
impl: GridLayout,
|
||||
};
|
@ -6,6 +6,7 @@ import { SlotsMap } from "./App";
|
||||
/* --- plain --- */
|
||||
import PlainButton from "./components/plain/Button";
|
||||
import CoreText from "./components/core/Text";
|
||||
import CoreGridLayout from "./components/core/GridLayout";
|
||||
/* --- chakra-ui --- */
|
||||
import ChakraUIRoot from "./components/chakra-ui/Root";
|
||||
import ChakraUIButton from "./components/chakra-ui/Button";
|
||||
@ -102,6 +103,7 @@ export const registry = new Registry();
|
||||
|
||||
registry.registerComponent(PlainButton);
|
||||
registry.registerComponent(CoreText);
|
||||
registry.registerComponent(CoreGridLayout);
|
||||
registry.registerComponent(ChakraUIRoot);
|
||||
registry.registerComponent(ChakraUIButton);
|
||||
registry.registerComponent(ChakraUITabs);
|
||||
|
@ -16,7 +16,7 @@ const Hidden: React.FC<HiddenProps> = ({ hidden: _hidden, children }) => {
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
const useHiddenState: TraitImplementation<HiddenProps> = ({ hidden }) => {
|
||||
const useHiddenTrait: TraitImplementation<HiddenProps> = ({ hidden }) => {
|
||||
return {
|
||||
props: null,
|
||||
component: (props) => <Hidden {...props} hidden={hidden} />,
|
||||
@ -43,5 +43,5 @@ export default {
|
||||
methods: [],
|
||||
},
|
||||
}),
|
||||
impl: useHiddenState,
|
||||
impl: useHiddenTrait,
|
||||
};
|
||||
|
46
yarn.lock
46
yarn.lock
@ -2267,6 +2267,13 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-grid-layout@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/@types/react-grid-layout/-/react-grid-layout-1.1.2.tgz#be46ac453e5193f512b0c4c90f36342e9e82258c"
|
||||
integrity sha512-jGpMO5VTXgrCsOoxGHSzfM/9sihlN6GDNyssaMdl73Q7Vtrbe0VVYxoavodommoRXS29hLW/2RLbQ/Oj5++slg==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^17.0.0":
|
||||
version "17.0.14"
|
||||
resolved "http://192.168.26.29:7001/@types/react/download/@types/react-17.0.14.tgz#f0629761ca02945c4e8fea99b8177f4c5c61fb0f"
|
||||
@ -2937,6 +2944,11 @@ cjs-module-lexer@^1.0.0:
|
||||
resolved "http://192.168.26.29:7001/cjs-module-lexer/download/cjs-module-lexer-1.2.1.tgz#2fd46d9906a126965aa541345c499aaa18e8cd73"
|
||||
integrity sha1-L9RtmQahJpZapUE0XEmaqhjozXM=
|
||||
|
||||
classnames@2.3.1, classnames@^2.2.5:
|
||||
version "2.3.1"
|
||||
resolved "http://192.168.26.29:7001/classnames/download/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
|
||||
integrity sha1-38+jiR4wbsHa0QXQ6I9EF7hTXo4=
|
||||
|
||||
clean-stack@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "http://192.168.26.29:7001/clean-stack/download/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
|
||||
@ -5405,6 +5417,11 @@ lodash.clonedeep@^4.5.0:
|
||||
resolved "http://192.168.26.29:7001/lodash.clonedeep/download/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
|
||||
|
||||
lodash.isequal@^4.0.0:
|
||||
version "4.5.0"
|
||||
resolved "http://192.168.26.29:7001/lodash.isequal/download/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
|
||||
|
||||
lodash.ismatch@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "http://192.168.26.29:7001/lodash.ismatch/download/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37"
|
||||
@ -6523,7 +6540,7 @@ promzard@^0.3.0:
|
||||
dependencies:
|
||||
read "1"
|
||||
|
||||
prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
prop-types@15.x, prop-types@^15.0.0, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "http://192.168.26.29:7001/prop-types/download/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
integrity sha1-UsQedbjIfnK52TYOAga5ncv/psU=
|
||||
@ -6612,6 +6629,14 @@ react-dom@^17.0.0:
|
||||
object-assign "^4.1.1"
|
||||
scheduler "^0.20.2"
|
||||
|
||||
react-draggable@^4.0.0, react-draggable@^4.0.3:
|
||||
version "4.4.3"
|
||||
resolved "http://192.168.26.29:7001/react-draggable/download/react-draggable-4.4.3.tgz#0727f2cae5813e36b0e4962bf11b2f9ef2b406f3"
|
||||
integrity sha1-ByfyyuWBPjaw5JYr8RsvnvK0BvM=
|
||||
dependencies:
|
||||
classnames "^2.2.5"
|
||||
prop-types "^15.6.0"
|
||||
|
||||
react-fast-compare@3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "http://192.168.26.29:7001/react-fast-compare/download/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
|
||||
@ -6629,6 +6654,17 @@ react-focus-lock@2.5.0:
|
||||
use-callback-ref "^1.2.1"
|
||||
use-sidecar "^1.0.1"
|
||||
|
||||
react-grid-layout@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "http://192.168.26.29:7001/react-grid-layout/download/react-grid-layout-1.2.5.tgz#fa40288d5a1fa783484c44ce78b1e10eb5313d26"
|
||||
integrity sha1-+kAojVofp4NITETOeLHhDrUxPSY=
|
||||
dependencies:
|
||||
classnames "2.3.1"
|
||||
lodash.isequal "^4.0.0"
|
||||
prop-types "^15.0.0"
|
||||
react-draggable "^4.0.0"
|
||||
react-resizable "^3.0.1"
|
||||
|
||||
react-is@^16.7.0, react-is@^16.8.1:
|
||||
version "16.13.1"
|
||||
resolved "http://192.168.26.29:7001/react-is/download/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
@ -6682,6 +6718,14 @@ react-remove-scroll@2.4.1:
|
||||
use-callback-ref "^1.2.3"
|
||||
use-sidecar "^1.0.1"
|
||||
|
||||
react-resizable@^3.0.1:
|
||||
version "3.0.4"
|
||||
resolved "http://192.168.26.29:7001/react-resizable/download/react-resizable-3.0.4.tgz#aa20108eff28c52c6fddaa49abfbef8abf5e581b"
|
||||
integrity sha1-qiAQjv8oxSxv3apJq/vvir9eWBs=
|
||||
dependencies:
|
||||
prop-types "15.x"
|
||||
react-draggable "^4.0.3"
|
||||
|
||||
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