feat(arco-table): support render component and update example

This commit is contained in:
Bowen Tan 2022-06-06 16:42:19 +08:00
parent ab9d8fd96f
commit 63971a46ae
11 changed files with 314 additions and 31 deletions

View File

@ -4,7 +4,7 @@ import { css, cx } from '@emotion/css';
import { Type, Static } from '@sinclair/typebox';
import { FALLBACK_METADATA, getComponentProps } from '../sunmao-helper';
import { PaginationPropsSpec as BasePaginationPropsSpec } from '../generated/types/Pagination';
import { useStateValue } from 'src/hooks/useStateValue';
import { useStateValue } from '../hooks/useStateValue';
const PaginationPropsSpec = Type.Object(BasePaginationPropsSpec);
const PaginationStateSpec = Type.Object({

View File

@ -5,7 +5,7 @@ import { Type, Static } from '@sinclair/typebox';
import { FALLBACK_METADATA, getComponentProps } from '../sunmao-helper';
import { RadioPropsSpec as BaseRadioPropsSpec } from '../generated/types/Radio';
import { useEffect } from 'react';
import { useStateValue } from 'src/hooks/useStateValue';
import { useStateValue } from '../hooks/useStateValue';
const RadioPropsSpec = Type.Object({
...BaseRadioPropsSpec,

View File

@ -6,7 +6,7 @@ import { FALLBACK_METADATA, getComponentProps } from '../sunmao-helper';
import { SelectPropsSpec as BaseSelectPropsSpec } from '../generated/types/Select';
import { useEffect, useRef } from 'react';
import { SelectHandle } from '@arco-design/web-react/es/Select/interface';
import { useStateValue } from 'src/hooks/useStateValue';
import { useStateValue } from '../hooks/useStateValue';
const SelectPropsSpec = Type.Object({
...BaseSelectPropsSpec,

View File

@ -4,7 +4,7 @@ import { css } from '@emotion/css';
import { Type, Static } from '@sinclair/typebox';
import { FALLBACK_METADATA, getComponentProps } from '../sunmao-helper';
import { SwitchPropsSpec as BaseSwitchPropsSpec } from '../generated/types/Switch';
import { useStateValue } from 'src/hooks/useStateValue';
import { useStateValue } from '../hooks/useStateValue';
const SwitchPropsSpec = Type.Object({
...BaseSwitchPropsSpec,

View File

@ -1,4 +1,11 @@
/* eslint-disable @typescript-eslint/ban-types */
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { css } from '@emotion/css';
import { sortBy } from 'lodash-es';
import { ResizeCallbackData } from 'react-resizable';
import { TableInstance } from '@arco-design/web-react/es/Table/table';
import { ColumnProps } from '@arco-design/web-react/es/Table';
import { RefInputType } from '@arco-design/web-react/es/Input/interface';
import {
Button,
Link,
@ -11,19 +18,14 @@ import {
LIST_ITEM_INDEX_EXP,
ModuleRenderer,
implementRuntimeComponent,
ImplWrapper,
} from '@sunmao-ui/runtime';
import { css } from '@emotion/css';
import { sortBy } from 'lodash-es';
import { Type, Static } from '@sinclair/typebox';
import { ResizableTitle } from './ResizableTitle';
import { FALLBACK_METADATA, getComponentProps } from '../../sunmao-helper';
import { TablePropsSpec, ColumnSpec } from '../../generated/types/Table';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { TableInstance } from '@arco-design/web-react/es/Table/table';
import { ColumnProps } from '@arco-design/web-react/es/Table';
import { useStateValue } from 'src/hooks/useStateValue';
import { ResizableTitle } from './ResizableTitle';
import { RefInputType } from '@arco-design/web-react/es/Input/interface';
import { ResizeCallbackData } from 'react-resizable';
import { useStateValue } from '../../hooks/useStateValue';
const TableStateSpec = Type.Object({
clickedRow: Type.Optional(Type.Any()),
@ -80,6 +82,7 @@ export const exampleProperties: Static<typeof TablePropsSpec> = {
type: 'text',
filter: true,
displayValue: '',
componentSlotIndex: 0,
},
{
title: 'Salary',
@ -89,6 +92,7 @@ export const exampleProperties: Static<typeof TablePropsSpec> = {
filter: false,
type: 'text',
displayValue: '',
componentSlotIndex: 0,
},
{
title: 'Link',
@ -97,19 +101,7 @@ export const exampleProperties: Static<typeof TablePropsSpec> = {
filter: true,
sortDirections: ['ascend', 'descend'],
displayValue: '',
},
{
title: 'CustomComponent',
dataIndex: 'customComponent',
type: 'module',
filter: false,
module: {
id: 'clistItemName-{{$listItem.id}}',
handlers: [],
properties: [],
type: 'core/v1/text',
},
displayValue: '',
componentSlotIndex: 0,
},
],
data: Array(13)
@ -156,7 +148,14 @@ export const Table = implementRuntimeComponent({
properties: TablePropsSpec,
state: TableStateSpec,
methods: {},
slots: {},
slots: {
content: {
slotProps: Type.Object({
[LIST_ITEM_EXP]: Type.Any(),
[LIST_ITEM_INDEX_EXP]: Type.Number(),
}),
},
},
styleSlots: ['content'],
events: ['onRowClick', 'onSearch', 'onPageChange', 'onFilter', 'onSort', 'onChange'],
},
@ -355,6 +354,46 @@ export const Table = implementRuntimeComponent({
/>
);
break;
case 'component':
const childrenSchema = app.spec.components.filter(c => {
return c.traits.find(
t =>
t.type === 'core/v1/slot' &&
(t.properties.container as any).id === component.id
);
});
const childSchema = childrenSchema[evaledColumn.componentSlotIndex || 0];
if (!childSchema) {
return (
<div>
Cannot find child with index {column.componentSlotIndex} in slot.
</div>
);
}
const _childrenSchema = {
...childSchema,
id: `${component.id}_${childSchema.id}_${index}`,
};
colItem = (
<ImplWrapper
key={_childrenSchema.id}
component={_childrenSchema}
app={app}
services={services}
childrenMap={{}}
isInModule
evalListItem
slotProps={{
[LIST_ITEM_EXP]: record,
[LIST_ITEM_INDEX_EXP]: index,
}}
/>
);
break;
default:
const text = evaledColumn.displayValue || value;
colItem = <span title={column.ellipsis ? text : ''}>{text}</span>;
@ -365,7 +404,15 @@ export const Table = implementRuntimeComponent({
return newColumn;
})
);
}, [cProps.columns]);
}, [
app,
cProps.columns,
callbackMap,
component.id,
component.properties.columns,
services,
useDefaultFilter,
]);
const handleChange = (
pagination: PaginationProps,

View File

@ -5,7 +5,7 @@ import { Type, Static } from '@sinclair/typebox';
import { FALLBACK_METADATA, getComponentProps } from '../sunmao-helper';
import { TabsPropsSpec as BaseTabsPropsSpec } from '../generated/types/Tabs';
import { useEffect, useRef } from 'react';
import { useStateValue } from 'src/hooks/useStateValue';
import { useStateValue } from '../hooks/useStateValue';
const TabsPropsSpec = Type.Object(BaseTabsPropsSpec);
const TabsStateSpec = Type.Object({

View File

@ -6,7 +6,7 @@ import { FALLBACK_METADATA, getComponentProps } from '../sunmao-helper';
import { TextAreaPropsSpec as BaseTextAreaPropsSpec } from '../generated/types/TextArea';
import { useEffect, useRef } from 'react';
import { RefInputType } from '@arco-design/web-react/es/Input/interface';
import { useStateValue } from 'src/hooks/useStateValue';
import { useStateValue } from '../hooks/useStateValue';
const TextAreaPropsSpec = Type.Object({
...BaseTextAreaPropsSpec,

View File

@ -6,7 +6,7 @@ import { FALLBACK_METADATA, getComponentProps } from '../sunmao-helper';
import { TreeSelectPropsSpec as BaseTreeSelectPropsSpec } from '../generated/types/TreeSelect';
import { useEffect, useRef } from 'react';
import { RefTreeSelectType } from '@arco-design/web-react/es/TreeSelect';
import { useStateValue } from 'src/hooks/useStateValue';
import { useStateValue } from '../hooks/useStateValue';
const TreeSelectPropsSpec = Type.Object(BaseTreeSelectPropsSpec);
const TreeSelectStateSpec = Type.Object({

View File

@ -0,0 +1,209 @@
import { Application } from '@sunmao-ui/core';
export const customComponent: Application = {
version: 'sunmao/v1',
kind: 'Application',
metadata: {
name: 'some App',
},
spec: {
components: [
{
id: 'table',
type: 'arco/v1/table',
properties: {
columns: [
{
title: 'Name',
dataIndex: 'name',
sorter: true,
sortDirections: ['ascend', 'descend'],
type: 'text',
filter: true,
displayValue: '',
componentSlotIndex: 0,
},
{
title: 'Salary',
dataIndex: 'salary',
sorter: true,
sortDirections: ['ascend', 'descend'],
filter: false,
type: 'text',
displayValue: '',
componentSlotIndex: 0,
},
{
title: 'Link',
dataIndex: 'link',
type: 'link',
filter: true,
sortDirections: ['ascend', 'descend'],
displayValue: '',
componentSlotIndex: 0,
},
{
title: 'Hello',
type: 'component',
componentSlotIndex: 0,
dataIndex: '',
displayValue: '',
filter: false,
},
],
data: [
{
key: 'key 0',
name: 'Naomi Cook0',
link: 'link-A',
salary: 272,
},
{
key: 'key 1',
name: 'Kevin Sandra1',
link: 'link-B',
salary: 911,
},
{
key: 'key 2',
name: 'Kevin Sandra2',
link: 'link-B',
salary: 527,
},
{
key: 'key 3',
name: 'Kevin Sandra3',
link: 'link-B',
salary: 906,
},
{
key: 'key 4',
name: 'Naomi Cook4',
link: 'link-A',
salary: 261,
},
{
key: 'key 5',
name: 'Naomi Cook5',
link: 'link-A',
salary: 134,
},
{
key: 'key 6',
name: 'Kevin Sandra6',
link: 'link-A',
salary: 877,
},
{
key: 'key 7',
name: 'Kevin Sandra7',
link: 'link-A',
salary: 287,
},
{
key: 'key 8',
name: 'Naomi Cook8',
link: 'link-B',
salary: 319,
},
{
key: 'key 9',
name: 'Kevin Sandra9',
link: 'link-B',
salary: 105,
},
{
key: 'key 10',
name: 'Naomi Cook10',
link: 'link-B',
salary: 468,
},
{
key: 'key 11',
name: 'Naomi Cook11',
link: 'link-A',
salary: 53,
},
{
key: 'key 12',
name: 'Naomi Cook12',
link: 'link-A',
salary: 195,
},
],
checkCrossPage: true,
pagination: {
enablePagination: true,
pageSize: 6,
defaultCurrent: 1,
updateWhenDefaultPageChanges: false,
useCustomPagination: false,
},
rowClick: false,
tableLayoutFixed: false,
borderCell: false,
stripe: false,
size: 'default',
useDefaultFilter: true,
useDefaultSort: true,
pagePosition: 'bottomCenter',
rowSelectionType: 'single',
border: true,
loading: false,
},
traits: [],
},
{
id: 'button4',
type: 'arco/v1/button',
properties: {
type: 'primary',
status: 'default',
long: false,
size: 'small',
disabled: false,
loading: false,
shape: 'round',
text: 'Click',
},
traits: [
{
type: 'core/v1/slot',
properties: {
container: {
id: 'table',
slot: 'content',
},
},
},
{
type: 'core/v1/event',
properties: {
handlers: [
{
type: 'onClick',
componentId: '$utils',
method: {
name: 'arco/v1/message',
parameters: {
type: 'info',
content: 'Hello{{$slot.$listItem.name}}',
position: 'top',
closable: false,
duration: 1000,
},
},
disabled: false,
wait: {
type: 'delay',
time: 0,
},
},
],
},
},
],
},
],
},
};

View File

@ -4,6 +4,7 @@ import { basicUsage } from './basicUsage';
import { selection } from './selection';
import { attributes } from './attributes';
import { sortAndFilter } from './sortAndFilter';
import { customComponent } from './customComponent';
const { Title, Text, Paragraph } = Typography;
@ -24,6 +25,12 @@ export const TableDemoPage: React.FC = () => {
<Paragraph>You can easily open or close the properties of the table</Paragraph>
<DemoWrapper application={attributes} />
<Divider />
<Title heading={3}>Custom Column Component</Title>
<Paragraph>
You can use any Sunmao component as column element instead of plain text.
</Paragraph>
<DemoWrapper application={customComponent} />
<Divider />
<Title heading={3}>Sort and filter</Title>
<Paragraph>
Configure the <Text code>sortable</Text> or <Text code>filterable</Text> of{' '}

View File

@ -182,12 +182,22 @@ export const ColumnSpec = Type.Object({
link: Type.String(),
button: Type.String(),
module: Type.String(),
component: Type.String(),
}),
{
title: 'Type',
category: Category.Basic,
}
),
componentSlotIndex: Type.Number({
title: 'Component Slot Index',
conditions: [
{
key: 'type',
value: 'component',
},
],
}),
dataIndex: Type.String({
title: 'Key',
category: Category.Basic,
@ -198,6 +208,16 @@ export const ColumnSpec = Type.Object({
title: 'Display Value',
category: Category.Basic,
description: 'The text you want to display instead of raw text',
conditions: [
{
key: 'type',
value: 'link',
},
{
key: 'type',
value: 'text',
},
],
}),
width: Type.Optional(
Type.Number({