init list

This commit is contained in:
Bowen Tan 2021-08-27 16:33:36 +08:00
parent 4ea2299400
commit b9de19bd56
6 changed files with 242 additions and 3 deletions

View File

@ -0,0 +1,122 @@
<!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: list component</title>
</head>
<body>
<div id="root"></div>
<script type="module">
import renderApp from '../../src/main.tsx';
renderApp({
version: 'example/v1',
metadata: {
name: 'list_component',
description: 'list component example',
},
spec: {
components: [
{
id: 'root',
type: 'chakra_ui/v1/root',
properties: {},
traits: [
{
type: 'core/v1/state',
properties: {
key: 'listTitle',
initialValue: 'UserList',
},
},
],
},
{
id: 'list',
type: 'chakra_ui/v1/list',
properties: {
listData: [
{
id: 1,
name: 'Hanson Deck',
email: 'hanson@deck.com',
sales: 37,
},
{
id: 2,
name: 'Max Conversation',
email: 'Max@conversation.com',
sales: 424,
},
{
id: 3,
name: 'Jason Response',
email: 'jason@response.com',
sales: 55,
},
{
id: 4,
name: 'Sue Shei',
email: 'sueshei@example.com',
sales: 550,
},
{
id: 5,
name: 'Eric Widget',
email: 'eric@widget.org',
sales: 243,
},
],
template: {
id: 'listItemTemplate',
type: 'chakra_ui/v1/button',
properties: {
text: {
raw: '`name: ${$listItem.name} email: ${$listItem.email}`',
format: 'plain',
},
},
traits: [
{
type: 'core/v1/event',
parsedType: {
version: 'core/v1',
name: 'event',
},
properties: {
events: [
{
event: 'click',
componentId: '$utils',
method: {
name: 'alert',
parameters: '`click: ${$listItem.name}`',
},
wait: {},
disabled: 'false',
},
],
},
},
],
},
},
traits: [
{
type: 'core/v1/slot',
properties: {
container: {
id: 'root',
slot: 'root',
},
},
},
],
},
],
},
});
</script>
</body>
</html>

View File

@ -29,7 +29,7 @@ type ArrayElement<ArrayType extends readonly unknown[]> =
type ApplicationComponent = RuntimeApplication['spec']['components'][0];
type ApplicationTrait = ArrayElement<ApplicationComponent['traits']>;
const ImplWrapper = React.forwardRef<
export const ImplWrapper = React.forwardRef<
HTMLDivElement,
{
component: ApplicationComponent;

View File

@ -0,0 +1,93 @@
import React, { useEffect, useRef } from 'react';
import { createComponent } from '@meta-ui/core';
import { Static, Type } from '@sinclair/typebox';
import {
List as BaseList,
ListItem as BaseListItem,
ListIcon,
} from '@chakra-ui/react';
import Text, { TextProps, TextPropertySchema } from '../_internal/Text';
import { ComponentImplementation } from '../../registry';
import { ImplWrapper } from '../../App';
import { mapValuesDeep } from '../../store';
import { values } from 'lodash';
import { parseType } from '../../util-methods';
const List: ComponentImplementation<{
listData: Static<typeof ListDataPropertySchema>;
template: Static<typeof TemplatePropertySchema>;
onClick?: () => void;
}> = ({ listData, template, mergeState, subscribeMethods, app }) => {
// useEffect(() => {
// mergeState({ value: text.raw });
// }, [text.raw]);
// const ref = useRef<HTMLListElement>(null);
// useEffect(() => {
// subscribeMethods({
// click() {
// ref.current?.click();
// },
// });
// }, []);
const listItems = listData.map((listItem, i) => {
// const evaledText = eval(template.properties.value.raw)
const evaledComponent = mapValuesDeep(template, ({ value, key }) => {
console.log(value);
// what will happen if listData was uglified?
if (typeof value === 'string' && value.includes('$listItem')) {
const expression = value.replaceAll('$listItem', 'listData[i]');
console.log('expression', expression);
return eval(expression);
}
return value;
});
evaledComponent.parsedType = parseType(evaledComponent.type);
console.log('evaled', evaledComponent);
return (
<BaseListItem key={listItem.name} spacing={3}>
<ListIcon color="green.500" />
<ImplWrapper
component={evaledComponent}
slotsMap={undefined}
targetSlot={null}
app={app}
/>
</BaseListItem>
);
});
return <BaseList>{listItems}</BaseList>;
};
const ListDataPropertySchema = Type.Array(
Type.Object(Type.String(), Type.String())
);
const TemplatePropertySchema = Type.Object(Type.String(), Type.Unknown());
export default {
...createComponent({
version: 'chakra_ui/v1',
metadata: {
name: 'list',
description: 'chakra-ui list',
},
spec: {
properties: [
{
name: 'listData',
...ListDataPropertySchema,
},
{
name: 'template',
...TemplatePropertySchema,
},
],
acceptTraits: [],
methods: [],
state: {},
},
}),
impl: List,
};

View File

@ -1,5 +1,9 @@
import React, { CSSProperties } from 'react';
import { RuntimeComponent, RuntimeTrait } from '@meta-ui/core';
import {
RuntimeApplication,
RuntimeComponent,
RuntimeTrait,
} from '@meta-ui/core';
import { SlotsMap } from './App';
// components
/* --- plain --- */
@ -15,6 +19,7 @@ import ChakraUITable from './components/chakra-ui/Table';
import ChakraUIInput from './components/chakra-ui/Input';
import ChakraUIBox from './components/chakra-ui/Box';
import ChakraUIKbd from './components/chakra-ui/Kbd';
import ChakraUIKList from './components/chakra-ui/List';
import ChakraUINumberInput from './components/chakra-ui/NumberInput';
import ChakraUICheckboxGroup from './components/chakra-ui/CheckboxGroup';
import ChakraUICheckbox from './components/chakra-ui/Checkbox';
@ -140,6 +145,7 @@ registry.registerComponent(ChakraUICheckboxGroup);
registry.registerComponent(ChakraUIStack);
registry.registerComponent(ChakraUIHStack);
registry.registerComponent(ChakraUIVStack);
registry.registerComponent(ChakraUIKList);
registry.registerComponent(LabEditor);
registry.registerComponent(CoreRouter);

View File

@ -66,7 +66,7 @@ function maskedEval(raw: string) {
}
}
const mapValuesDeep = (
export const mapValuesDeep = (
obj: any,
fn: (params: {
value: any;

View File

@ -1,3 +1,4 @@
import { Version } from '../../core/typings/version';
import { apiService } from './api-service';
export function mountUtilMethods() {
@ -15,3 +16,20 @@ export function mountUtilMethods() {
}
});
}
// parse component Type
export function parseType(v: string) {
const TYPE_REG = /^([a-zA-Z0-9_\d]+\/[a-zA-Z0-9_\d]+)\/([a-zA-Z0-9_\d]+)$/;
function isValidType(v: string): boolean {
return TYPE_REG.test(v);
}
if (!isValidType(v)) {
throw new Error(`Invalid type string: "${v}"`);
}
const [, version, name] = v.match(TYPE_REG)!;
return {
version,
name,
};
}