mirror of
https://github.com/smartxworks/sunmao-ui.git
synced 2025-02-23 17:49:49 +08:00
Merge pull request #100 from webzard-io/user-center
Some small features
This commit is contained in:
commit
2d7d22a9f8
@ -45,7 +45,7 @@
|
||||
"babel-jest": "^27.2.1",
|
||||
"jest": "^27.2.1",
|
||||
"typescript": "^4.4.3",
|
||||
"vite": "^2.5.10"
|
||||
"vite": "^2.6.13"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { flatten } from 'lodash-es';
|
||||
import { FormControl, FormLabel, Input, VStack } from '@chakra-ui/react';
|
||||
import { FormControl, FormLabel, Input, Textarea, VStack } from '@chakra-ui/react';
|
||||
import { EmotionJSX } from '@emotion/react/types/jsx-namespace';
|
||||
import { TSchema } from '@sinclair/typebox';
|
||||
import { Application } from '@meta-ui/core';
|
||||
@ -27,7 +27,7 @@ export const renderField = (properties: {
|
||||
}) => {
|
||||
const { value, type, fullKey, selectedId } = properties;
|
||||
if (typeof value !== 'object') {
|
||||
const ref = React.createRef<HTMLInputElement>();
|
||||
const ref = React.createRef<HTMLTextAreaElement>();
|
||||
const onBlur = () => {
|
||||
const operation = type
|
||||
? new ModifyTraitPropertyOperation(selectedId, type, fullKey, ref.current?.value)
|
||||
@ -37,7 +37,7 @@ export const renderField = (properties: {
|
||||
return (
|
||||
<FormControl key={`${selectedId}-${fullKey}`}>
|
||||
<FormLabel>{fullKey}</FormLabel>
|
||||
<Input ref={ref} onBlur={onBlur} defaultValue={value as string} />
|
||||
<Textarea ref={ref} onBlur={onBlur} defaultValue={value as string} />
|
||||
</FormControl>
|
||||
);
|
||||
} else {
|
||||
|
@ -96,7 +96,7 @@ export const Editor = () => {
|
||||
<Tab>UI Tree</Tab>
|
||||
<Tab>State</Tab>
|
||||
</TabList>
|
||||
<TabPanels flex="1">
|
||||
<TabPanels flex="1" overflow="auto">
|
||||
<TabPanel p={0}>
|
||||
<StructureTree
|
||||
app={app}
|
||||
|
@ -12,121 +12,424 @@ export const DefaultAppSchema: Application = {
|
||||
spec: {
|
||||
components: [
|
||||
{
|
||||
id: 'root',
|
||||
type: 'chakra_ui/v1/root',
|
||||
properties: {},
|
||||
id: 'grid_layout1',
|
||||
type: 'core/v1/grid_layout',
|
||||
properties: {
|
||||
layout: [
|
||||
{
|
||||
w: 10,
|
||||
h: 15,
|
||||
x: 0,
|
||||
y: 0,
|
||||
i: 'tabs1',
|
||||
moved: false,
|
||||
static: false,
|
||||
isDraggable: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
traits: [],
|
||||
},
|
||||
{
|
||||
id: 'btn',
|
||||
type: 'plain/v1/button',
|
||||
properties: {
|
||||
text: {
|
||||
raw: '**Open Dialog**',
|
||||
format: 'md',
|
||||
},
|
||||
colorScheme: 'red',
|
||||
},
|
||||
id: 'fetchUsers',
|
||||
type: 'core/v1/dummy',
|
||||
properties: {},
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
type: 'core/v1/fetch',
|
||||
properties: {
|
||||
container: {
|
||||
id: 'root',
|
||||
slot: 'root',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'core/v1/event',
|
||||
properties: {
|
||||
handlers: [
|
||||
{
|
||||
type: 'onClick',
|
||||
componentId: 'dialog',
|
||||
method: {
|
||||
name: 'openDialog',
|
||||
parameters: {
|
||||
title: 'hi',
|
||||
},
|
||||
},
|
||||
wait: {},
|
||||
},
|
||||
],
|
||||
url: 'https://6177d4919c328300175f5b99.mockapi.io/users',
|
||||
method: 'get',
|
||||
lazy: false,
|
||||
headers: {},
|
||||
body: {},
|
||||
onComplete: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'dialog',
|
||||
type: 'chakra_ui/v1/dialog',
|
||||
id: 'usersTable',
|
||||
type: 'chakra_ui/v1/table',
|
||||
properties: {
|
||||
title: 'This is a dialog',
|
||||
confirmButton: {
|
||||
text: 'hello',
|
||||
colorScheme: 'pink',
|
||||
},
|
||||
cancelButton: {
|
||||
text: 'thanks',
|
||||
},
|
||||
data: '{{fetchUsers.fetch.data}}',
|
||||
columns: [
|
||||
{ key: 'username', title: '用户名', type: 'link' },
|
||||
{ key: 'job', title: '职位', type: 'text' },
|
||||
{ key: 'area', title: '地区', type: 'text' },
|
||||
{
|
||||
key: 'createdTime',
|
||||
title: '创建时间',
|
||||
displayValue: "{{dayjs($listItem.createdTime).format('LL')}}",
|
||||
},
|
||||
],
|
||||
majorKey: 'id',
|
||||
rowsPerPage: '3',
|
||||
isMultiSelect: 'false',
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: {
|
||||
id: 'root',
|
||||
slot: 'root',
|
||||
},
|
||||
},
|
||||
},
|
||||
// dialog events
|
||||
{
|
||||
type: 'core/v1/event',
|
||||
properties: {
|
||||
handlers: [
|
||||
// when click confirm
|
||||
{
|
||||
type: 'confirmDialog',
|
||||
componentId: 'dialog',
|
||||
method: {
|
||||
name: 'confirmDialog',
|
||||
},
|
||||
wait: {},
|
||||
disabled: 'false',
|
||||
},
|
||||
// when cancel confirm
|
||||
{
|
||||
type: 'cancelDialog',
|
||||
componentId: 'dialog',
|
||||
method: {
|
||||
name: 'cancelDialog',
|
||||
},
|
||||
wait: {},
|
||||
disabled: 'false',
|
||||
},
|
||||
],
|
||||
container: { id: 'tabContentVStack', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'dialogContent',
|
||||
id: 'userInfoContainer',
|
||||
type: 'chakra_ui/v1/vstack',
|
||||
properties: { spacing: '2', align: 'stretch' },
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'tabContentVStack', slot: 'content' },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'core/v1/style',
|
||||
properties: {
|
||||
styleSlot: 'content',
|
||||
style: "{{!usersTable.selectedItem ? 'display: none' : ''}}",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'userInfoTitle',
|
||||
type: 'core/v1/text',
|
||||
properties: { value: { raw: '**基本信息**', format: 'md' } },
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'userInfoContainer', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'hstack1',
|
||||
type: 'chakra_ui/v1/hstack',
|
||||
properties: { spacing: '24px', hideBorder: '' },
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'userInfoContainer', slot: 'content' },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'core/v1/style',
|
||||
properties: {
|
||||
styleSlot: 'content',
|
||||
style: 'padding: 0; border: none',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'usernameLabel',
|
||||
type: 'core/v1/text',
|
||||
properties: { value: { raw: '**用户名**', format: 'md' } },
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'hstack1', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'usernameValue',
|
||||
type: 'core/v1/text',
|
||||
properties: {
|
||||
value: {
|
||||
raw: '**This is a dialog**',
|
||||
format: 'md',
|
||||
raw: "{{usersTable.selectedItem ? usersTable.selectedItem.username : ''}}",
|
||||
format: 'plain',
|
||||
},
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: {
|
||||
id: 'dialog',
|
||||
slot: 'content',
|
||||
},
|
||||
container: { id: 'hstack1', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'divider1',
|
||||
type: 'chakra_ui/v1/divider',
|
||||
properties: {},
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'userInfoContainer', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'jobLabel',
|
||||
type: 'core/v1/text',
|
||||
properties: { value: { raw: '**职位**', format: 'md' } },
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'hstack2', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'hstack2',
|
||||
type: 'chakra_ui/v1/hstack',
|
||||
properties: { spacing: '24px', hideBorder: '' },
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'userInfoContainer', slot: 'content' },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'core/v1/style',
|
||||
properties: {
|
||||
styleSlot: 'content',
|
||||
style: 'padding: 0; border: none',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'areaLabel',
|
||||
type: 'core/v1/text',
|
||||
properties: { value: { raw: '**地区**', format: 'md' } },
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'hstack3', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'areaValue',
|
||||
type: 'core/v1/text',
|
||||
properties: {
|
||||
value: {
|
||||
raw: "{{usersTable.selectedItem ? usersTable.selectedItem.area : ''}}",
|
||||
format: 'plain',
|
||||
},
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'hstack3', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'divider2',
|
||||
type: 'chakra_ui/v1/divider',
|
||||
properties: {},
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'userInfoContainer', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'createdTimeLabel',
|
||||
type: 'core/v1/text',
|
||||
properties: { value: { raw: '**创建时间**', format: 'md' } },
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'hstack4', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'createdTimeValue',
|
||||
type: 'core/v1/text',
|
||||
properties: {
|
||||
value: {
|
||||
raw: "{{usersTable.selectedItem ? dayjs(usersTable.selectedItem.createdTime).format('LL') : ''}}",
|
||||
format: 'plain',
|
||||
},
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'hstack4', slot: 'content' },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'core/v1/style',
|
||||
properties: { string: { kind: {}, type: {} } },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'hstack3',
|
||||
type: 'chakra_ui/v1/hstack',
|
||||
properties: { spacing: '24px', hideBorder: '' },
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'userInfoContainer', slot: 'content' },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'core/v1/style',
|
||||
properties: {
|
||||
styleSlot: 'content',
|
||||
style: 'padding: 0; border: none',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'divider3',
|
||||
type: 'chakra_ui/v1/divider',
|
||||
properties: {},
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'userInfoContainer', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'hstack4',
|
||||
type: 'chakra_ui/v1/hstack',
|
||||
properties: { spacing: '24px', hideBorder: '' },
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'userInfoContainer', slot: 'content' },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'core/v1/style',
|
||||
properties: {
|
||||
styleSlot: 'content',
|
||||
style: 'padding: 0; border: none',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'tabs1',
|
||||
type: 'chakra_ui/v1/tabs',
|
||||
properties: {
|
||||
tabNames: ['用户信息', '角色'],
|
||||
initialSelectedTabIndex: 0,
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'grid_layout1', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'tabContentVStack',
|
||||
type: 'chakra_ui/v1/vstack',
|
||||
properties: { spacing: '24px' },
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: { container: { id: 'tabs1', slot: 'content' } },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'testtext',
|
||||
type: 'core/v1/text',
|
||||
properties: { value: { raw: '**测试角色**', format: 'md' } },
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: { container: { id: 'tabs1', slot: 'content' } },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'jobValue',
|
||||
type: 'chakra_ui/v1/vstack',
|
||||
properties: { spacing: '1', align: 'stretch' },
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'hstack2', slot: 'content' },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'core/v1/style',
|
||||
properties: {
|
||||
styleSlot: 'content',
|
||||
style: 'padding: 0; border: none',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'link1',
|
||||
type: 'chakra_ui/v1/link',
|
||||
properties: {
|
||||
text: {
|
||||
raw: "{{usersTable.selectedItem ? usersTable.selectedItem.job : ''}}",
|
||||
format: 'plain',
|
||||
},
|
||||
href: 'https://www.google.com',
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'jobValue', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'link2',
|
||||
type: 'chakra_ui/v1/link',
|
||||
properties: {
|
||||
text: {
|
||||
raw: "{{usersTable.selectedItem ? usersTable.selectedItem.job : ''}}",
|
||||
format: 'plain',
|
||||
},
|
||||
href: 'https://www.google.com',
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/slot',
|
||||
properties: {
|
||||
container: { id: 'jobValue', slot: 'content' },
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -43,18 +43,15 @@
|
||||
{
|
||||
type: 'core/v1/style',
|
||||
properties: {
|
||||
style: {
|
||||
tabItem: {
|
||||
'&:hover': {
|
||||
color: 'red',
|
||||
},
|
||||
},
|
||||
tabContent: {
|
||||
'&:hover': {
|
||||
color: 'green',
|
||||
},
|
||||
},
|
||||
},
|
||||
styleSlot: 'tabItem',
|
||||
style: `color: red`,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'core/v1/style',
|
||||
properties: {
|
||||
styleSlot: 'tabContent',
|
||||
style: `color: green`,
|
||||
},
|
||||
},
|
||||
],
|
||||
@ -74,7 +71,7 @@
|
||||
properties: {
|
||||
container: {
|
||||
id: 'tabs',
|
||||
slot: 'tab_content_0',
|
||||
slot: 'content',
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -85,7 +82,7 @@
|
||||
type: 'core/v1/text',
|
||||
properties: {
|
||||
value: {
|
||||
raw: 'hover me',
|
||||
raw: 'hover me2',
|
||||
format: 'plain',
|
||||
},
|
||||
},
|
||||
@ -95,7 +92,7 @@
|
||||
properties: {
|
||||
container: {
|
||||
id: 'tabs',
|
||||
slot: 'tab_content_1',
|
||||
slot: 'content',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -68,6 +68,6 @@
|
||||
"jest": "^27.1.0",
|
||||
"tsup": "^5.5.0",
|
||||
"typescript": "^4.3.2",
|
||||
"vite": "^2.3.8"
|
||||
"vite": "^2.6.13"
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,6 @@ import 'react-resizable/css/styles.css';
|
||||
import { DROP_EXAMPLE_SIZE_PREFIX, GRID_HEIGHT } from '../../constants';
|
||||
import { decodeDragDataTransfer } from '../../utils/encodeDragDataTransfer';
|
||||
|
||||
// hack: add onDropDragOver to ReactGridLayoutProps definition
|
||||
const ReactGridLayout: React.FC<RGL.ReactGridLayoutProps & { onDropDragOver: any }> =
|
||||
RGL as any;
|
||||
|
||||
const GridLayout: React.FC<RGL.ReactGridLayoutProps> = props => {
|
||||
const { children } = props;
|
||||
const spacing = 10;
|
||||
@ -25,12 +21,12 @@ const GridLayout: React.FC<RGL.ReactGridLayoutProps> = props => {
|
||||
background-position: 0px ${spacing / 2}px;
|
||||
`;
|
||||
|
||||
const onDropDragOver = (e: React.DragEvent) => {
|
||||
const onDropDragOver = (e: any) => {
|
||||
// Here we need to get data in dataTransfer
|
||||
// but normally we cannot access dataTransfer in onDragOver, so I use a hack
|
||||
// I use the key of dataTransfer to store data, the key will look like 'exampleSize: [1,4]'
|
||||
// https://stackoverflow.com/questions/28487352/dragndrop-datatransfer-getdata-empty
|
||||
const key = e.dataTransfer.types
|
||||
const key = (e as React.DragEvent).dataTransfer.types
|
||||
.map(decodeDragDataTransfer)
|
||||
.find(t => t.startsWith(DROP_EXAMPLE_SIZE_PREFIX));
|
||||
const componentSize = JSON.parse(key?.replace(DROP_EXAMPLE_SIZE_PREFIX, '') || '');
|
||||
@ -39,7 +35,7 @@ const GridLayout: React.FC<RGL.ReactGridLayoutProps> = props => {
|
||||
|
||||
return (
|
||||
<div ref={ref} css={bgCss}>
|
||||
<ReactGridLayout
|
||||
<RGL
|
||||
cols={12}
|
||||
compactType={null}
|
||||
preventCollision={true}
|
||||
@ -51,7 +47,7 @@ const GridLayout: React.FC<RGL.ReactGridLayoutProps> = props => {
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</ReactGridLayout>
|
||||
</RGL>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
31
packages/runtime/src/components/chakra-ui/Divider.tsx
Normal file
31
packages/runtime/src/components/chakra-ui/Divider.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { Divider } from '@chakra-ui/react';
|
||||
import { createComponent } from '@meta-ui/core';
|
||||
import { ComponentImplementation } from '../../services/registry';
|
||||
|
||||
const DividerImpl: ComponentImplementation = () => {
|
||||
return <Divider />;
|
||||
};
|
||||
|
||||
export default {
|
||||
...createComponent({
|
||||
version: 'chakra_ui/v1',
|
||||
metadata: {
|
||||
name: 'divider',
|
||||
displayName: 'Divider',
|
||||
description: 'chakra-ui divider',
|
||||
isDraggable: true,
|
||||
isResizable: true,
|
||||
exampleProperties: {},
|
||||
exampleSize: [4, 1],
|
||||
},
|
||||
spec: {
|
||||
properties: {},
|
||||
state: {},
|
||||
methods: [],
|
||||
slots: [],
|
||||
styleSlots: [],
|
||||
events: [],
|
||||
},
|
||||
}),
|
||||
impl: DividerImpl,
|
||||
};
|
@ -1,4 +1,5 @@
|
||||
import { createComponent } from '@meta-ui/core';
|
||||
import { css } from '@emotion/react';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { HStack as BaseHStack } from '@chakra-ui/react';
|
||||
import { ComponentImplementation } from '../../services/registry';
|
||||
@ -18,6 +19,7 @@ const HStack: ComponentImplementation<Static<typeof PropsSchema>> = ({
|
||||
justify,
|
||||
spacing,
|
||||
slotsMap,
|
||||
customStyle,
|
||||
}) => {
|
||||
return (
|
||||
<BaseHStack
|
||||
@ -28,6 +30,9 @@ const HStack: ComponentImplementation<Static<typeof PropsSchema>> = ({
|
||||
border="1px solid"
|
||||
borderColor="gray.200"
|
||||
borderRadius="4"
|
||||
css={css`
|
||||
${customStyle?.content}
|
||||
`}
|
||||
{...{ direction, wrap, align, justify, spacing }}
|
||||
>
|
||||
<Slot slotsMap={slotsMap} slot="content" />
|
||||
|
53
packages/runtime/src/components/chakra-ui/Link.tsx
Normal file
53
packages/runtime/src/components/chakra-ui/Link.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { Link } from '@chakra-ui/react';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { createComponent } from '@meta-ui/core';
|
||||
import { ComponentImplementation } from '../../services/registry';
|
||||
import Text, { TextPropertySchema } from '../_internal/Text';
|
||||
|
||||
const LinkImpl: ComponentImplementation<Static<typeof PropsSchema>> = ({
|
||||
text,
|
||||
href,
|
||||
isExternal,
|
||||
}) => {
|
||||
return (
|
||||
<Link href={href} isExternal={isExternal} color="blue.500">
|
||||
<Text value={text} />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const PropsSchema = Type.Object({
|
||||
text: TextPropertySchema,
|
||||
href: Type.String(),
|
||||
isExternal: Type.Optional(Type.Boolean()),
|
||||
});
|
||||
|
||||
export default {
|
||||
...createComponent({
|
||||
version: 'chakra_ui/v1',
|
||||
metadata: {
|
||||
name: 'link',
|
||||
displayName: 'Link',
|
||||
description: 'chakra-ui link',
|
||||
isDraggable: true,
|
||||
isResizable: true,
|
||||
exampleProperties: {
|
||||
text: {
|
||||
raw: 'link',
|
||||
format: 'plain',
|
||||
},
|
||||
href: 'https://www.google.com',
|
||||
},
|
||||
exampleSize: [2, 1],
|
||||
},
|
||||
spec: {
|
||||
properties: PropsSchema,
|
||||
state: {},
|
||||
methods: [],
|
||||
slots: [],
|
||||
styleSlots: [],
|
||||
events: [],
|
||||
},
|
||||
}),
|
||||
impl: LinkImpl,
|
||||
};
|
@ -95,8 +95,8 @@ const List: ComponentImplementation<Static<typeof PropsSchema>> = ({
|
||||
};
|
||||
|
||||
const PropsSchema = Type.Object({
|
||||
listData: Type.Array(Type.Object(Type.String(), Type.String())),
|
||||
template: Type.Object(Type.String(), Type.Array(Type.Object(Type.String()))),
|
||||
listData: Type.Array(Type.Record(Type.String(), Type.String())),
|
||||
template: Type.Array(Type.Any()),
|
||||
});
|
||||
|
||||
const exampleProperties = {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Static } from '@sinclair/typebox';
|
||||
import { ColumnSchema } from './TableTypes';
|
||||
import { Button, Td } from '@chakra-ui/react';
|
||||
import { Button, Link, Td } from '@chakra-ui/react';
|
||||
import { LIST_ITEM_EXP } from '../../../constants';
|
||||
import { MetaUIServices } from 'src/types/RuntimeSchema';
|
||||
|
||||
@ -20,11 +20,17 @@ export const TableTd: React.FC<{
|
||||
}
|
||||
|
||||
let content = value;
|
||||
|
||||
switch (column.type) {
|
||||
case 'image':
|
||||
content = <img src={value} />;
|
||||
break;
|
||||
case 'link':
|
||||
content = (
|
||||
<Link href={value} color="blue.600">
|
||||
{value}
|
||||
</Link>
|
||||
);
|
||||
break;
|
||||
case 'button':
|
||||
const onClick = () => {
|
||||
onClickItem();
|
||||
|
@ -16,6 +16,7 @@ export const TdTypeSchema = Type.KeyOf(
|
||||
Type.Object({
|
||||
text: Type.String(),
|
||||
image: Type.String(),
|
||||
link: Type.String(),
|
||||
button: Type.String(),
|
||||
})
|
||||
);
|
||||
|
@ -1,23 +1,23 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { createComponent } from '@meta-ui/core';
|
||||
import { Tabs as BaseTabs, TabList, Tab, TabPanels, TabPanel } from '@chakra-ui/react';
|
||||
import { Type, Static } from '@sinclair/typebox';
|
||||
import { ComponentImplementation } from '../../services/registry';
|
||||
import Slot from '../_internal/Slot';
|
||||
import { getSlots } from '../_internal/Slot';
|
||||
|
||||
const Tabs: ComponentImplementation<Static<typeof PropsSchema>> = ({
|
||||
tabNames,
|
||||
mergeState,
|
||||
initialSelectedTabIndex,
|
||||
slotsMap,
|
||||
style,
|
||||
customStyle,
|
||||
}) => {
|
||||
const [selectedTabIndex, setSelectedTabIndex] = useState(initialSelectedTabIndex ?? 0);
|
||||
|
||||
useEffect(() => {
|
||||
mergeState({ selectedTabIndex });
|
||||
}, [selectedTabIndex]);
|
||||
|
||||
return (
|
||||
<BaseTabs
|
||||
defaultIndex={initialSelectedTabIndex}
|
||||
@ -25,17 +25,24 @@ const Tabs: ComponentImplementation<Static<typeof PropsSchema>> = ({
|
||||
>
|
||||
<TabList>
|
||||
{tabNames.map((name, idx) => (
|
||||
<Tab key={idx} css={style?.tabItem}>
|
||||
<Tab key={idx} css={css`${customStyle?.tabItem}}`}>
|
||||
{name}
|
||||
</Tab>
|
||||
))}
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
{tabNames.map((_, idx) => (
|
||||
<TabPanel key={idx} css={style?.tabContent}>
|
||||
<Slot slotsMap={slotsMap} slot={`tab_content_${idx}`} />
|
||||
</TabPanel>
|
||||
))}
|
||||
{getSlots(slotsMap, 'content').map((content, idx) => {
|
||||
return (
|
||||
<TabPanel
|
||||
key={idx}
|
||||
css={css`
|
||||
${customStyle?.tabContent}
|
||||
`}
|
||||
>
|
||||
{content}
|
||||
</TabPanel>
|
||||
);
|
||||
})}
|
||||
</TabPanels>
|
||||
</BaseTabs>
|
||||
);
|
||||
@ -70,8 +77,8 @@ export default {
|
||||
state: StateSchema,
|
||||
methods: [],
|
||||
// tab slot is dynamic
|
||||
slots: [],
|
||||
styleSlots: [],
|
||||
slots: ['content'],
|
||||
styleSlots: ['tabItem', 'tabContent'],
|
||||
events: [],
|
||||
},
|
||||
}),
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { createComponent } from '@meta-ui/core';
|
||||
import { css } from '@emotion/react';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { VStack as BaseVStack } from '@chakra-ui/react';
|
||||
import { ComponentImplementation } from '../../services/registry';
|
||||
@ -18,6 +19,7 @@ const VStack: ComponentImplementation<Static<typeof PropsSchema>> = ({
|
||||
justify,
|
||||
spacing,
|
||||
slotsMap,
|
||||
customStyle,
|
||||
}) => {
|
||||
return (
|
||||
<BaseVStack
|
||||
@ -28,6 +30,9 @@ const VStack: ComponentImplementation<Static<typeof PropsSchema>> = ({
|
||||
border="1px solid"
|
||||
borderColor="gray.200"
|
||||
borderRadius="4"
|
||||
css={css`
|
||||
${customStyle?.content}
|
||||
`}
|
||||
{...{ direction, wrap, align, justify, spacing }}
|
||||
>
|
||||
<Slot slotsMap={slotsMap} slot="content" />
|
||||
|
@ -123,11 +123,8 @@ export const ImplWrapper = React.forwardRef<HTMLDivElement, ImplWrapperProps>(
|
||||
if (result.props?.effects) {
|
||||
effects = effects?.concat(result.props?.effects);
|
||||
}
|
||||
return {
|
||||
...prevProps,
|
||||
...result.props,
|
||||
effects,
|
||||
};
|
||||
|
||||
return merge(prevProps, result.props, { effects });
|
||||
},
|
||||
{} as TraitResult['props']
|
||||
);
|
||||
|
@ -13,10 +13,12 @@ import ChakraUITabs from '../components/chakra-ui/Tabs';
|
||||
import ChakraUITable from '../components/chakra-ui/Table';
|
||||
import ChakraUIInput from '../components/chakra-ui/Input';
|
||||
import ChakraUIBox from '../components/chakra-ui/Box';
|
||||
import ChakraUIDivider from '../components/chakra-ui/Divider';
|
||||
import ChakraUIFormControl from '../components/chakra-ui/Form/FormControl';
|
||||
import ChakraUIForm from '../components/chakra-ui/Form/Form';
|
||||
import ChakraUIKbd from '../components/chakra-ui/Kbd';
|
||||
import ChakraUIList from '../components/chakra-ui/List';
|
||||
import ChakraUILink from '../components/chakra-ui/Link';
|
||||
import ChakraUINumberInput from '../components/chakra-ui/NumberInput';
|
||||
import ChakraUICheckboxGroup from '../components/chakra-ui/CheckboxGroup';
|
||||
import ChakraUICheckbox from '../components/chakra-ui/Checkbox';
|
||||
@ -130,10 +132,12 @@ export function initRegistry(): Registry {
|
||||
registry.registerComponent(ChakraUITable);
|
||||
registry.registerComponent(ChakraUIInput);
|
||||
registry.registerComponent(ChakraUIBox);
|
||||
registry.registerComponent(ChakraUIDivider);
|
||||
registry.registerComponent(ChakraUIFormControl);
|
||||
registry.registerComponent(ChakraUIForm);
|
||||
registry.registerComponent(ChakraUIKbd);
|
||||
registry.registerComponent(ChakraUIList);
|
||||
registry.registerComponent(ChakraUILink);
|
||||
registry.registerComponent(ChakraUINumberInput);
|
||||
registry.registerComponent(ChakraUICheckbox);
|
||||
registry.registerComponent(ChakraUICheckboxGroup);
|
||||
|
@ -1,11 +1,17 @@
|
||||
import { toNumber, mapValues, isArray, isPlainObject, set } from 'lodash-es';
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
import isLeapYear from 'dayjs/plugin/isLeapYear';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import LocalizedFormat from 'dayjs/plugin/localizedFormat';
|
||||
import { reactive } from '@vue/reactivity';
|
||||
import { watch } from '../utils/watchReactivity';
|
||||
import { LIST_ITEM_EXP, LIST_ITEM_INDEX_EXP } from '../constants';
|
||||
|
||||
dayjs.extend(relativeTime);
|
||||
dayjs.extend(isLeapYear);
|
||||
dayjs.extend(LocalizedFormat);
|
||||
dayjs.locale('zh-cn');
|
||||
|
||||
type ExpChunk = {
|
||||
expression: string;
|
||||
|
@ -32,6 +32,14 @@ const useFetchTrait: TraitImplementation<Static<typeof FetchTraitPropertiesSchem
|
||||
}
|
||||
}
|
||||
|
||||
mergeState({
|
||||
fetch: {
|
||||
loading: true,
|
||||
data: undefined,
|
||||
error: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
// fetch data
|
||||
fetch(url, {
|
||||
method,
|
||||
|
@ -1,16 +1,13 @@
|
||||
import { CSSProperties } from 'react';
|
||||
import { createTrait } from '@meta-ui/core';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { TraitImplementation } from 'src/types/RuntimeSchema';
|
||||
|
||||
const useHiddenTrait: TraitImplementation<Static<typeof PropsSchema>> = ({ hidden }) => {
|
||||
const style: CSSProperties = {};
|
||||
if (hidden) {
|
||||
style.display = 'none';
|
||||
}
|
||||
return {
|
||||
props: {
|
||||
style,
|
||||
customStyle: {
|
||||
content: hidden ? 'display: none' : '',
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@ -2,19 +2,24 @@ import { createTrait } from '@meta-ui/core';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { TraitImplementation } from 'src/types/RuntimeSchema';
|
||||
|
||||
const StyleTrait: TraitImplementation<{
|
||||
style: Static<typeof PropsSchema>;
|
||||
}> = ({ style }) => {
|
||||
const StyleTrait: TraitImplementation<Static<typeof PropsSchema>> = ({
|
||||
styleSlot,
|
||||
style,
|
||||
}) => {
|
||||
return {
|
||||
props: {
|
||||
style: style,
|
||||
customStyle: {
|
||||
[styleSlot]: style,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const PropsSchema = Type.Object({
|
||||
string: Type.Object(Type.String()),
|
||||
styleSlot: Type.String(),
|
||||
style: Type.String(),
|
||||
});
|
||||
|
||||
export default {
|
||||
...createTrait({
|
||||
version: 'core/v1',
|
||||
|
@ -74,7 +74,7 @@ export type ComponentImplementationProps = ImplWrapperProps &
|
||||
export type TraitResult = {
|
||||
props: {
|
||||
data?: unknown;
|
||||
style?: Record<string, any>;
|
||||
customStyle?: Record<string, string>;
|
||||
callbackMap?: CallbackMap;
|
||||
effects?: Array<() => void>;
|
||||
} | null;
|
||||
|
Loading…
Reference in New Issue
Block a user