From 63971a46aed75ee1994dc682db53cd0334355063 Mon Sep 17 00:00:00 2001 From: Bowen Tan Date: Mon, 6 Jun 2022 16:42:19 +0800 Subject: [PATCH] feat(arco-table): support render component and update example --- .../arco-lib/src/components/Pagination.tsx | 2 +- packages/arco-lib/src/components/Radio.tsx | 2 +- packages/arco-lib/src/components/Select.tsx | 2 +- packages/arco-lib/src/components/Switch.tsx | 2 +- .../arco-lib/src/components/Table/Table.tsx | 95 ++++++-- packages/arco-lib/src/components/Tabs.tsx | 2 +- packages/arco-lib/src/components/TextArea.tsx | 2 +- .../arco-lib/src/components/TreeSelect.tsx | 2 +- .../examples/pages/table/customComponent.ts | 209 ++++++++++++++++++ .../src/examples/pages/table/index.tsx | 7 + .../arco-lib/src/generated/types/Table.ts | 20 ++ 11 files changed, 314 insertions(+), 31 deletions(-) create mode 100644 packages/arco-lib/src/examples/pages/table/customComponent.ts diff --git a/packages/arco-lib/src/components/Pagination.tsx b/packages/arco-lib/src/components/Pagination.tsx index 40539e1d..d477de27 100644 --- a/packages/arco-lib/src/components/Pagination.tsx +++ b/packages/arco-lib/src/components/Pagination.tsx @@ -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({ diff --git a/packages/arco-lib/src/components/Radio.tsx b/packages/arco-lib/src/components/Radio.tsx index 5e91c463..ca117969 100644 --- a/packages/arco-lib/src/components/Radio.tsx +++ b/packages/arco-lib/src/components/Radio.tsx @@ -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, diff --git a/packages/arco-lib/src/components/Select.tsx b/packages/arco-lib/src/components/Select.tsx index e2934f5f..bbdbf3a0 100644 --- a/packages/arco-lib/src/components/Select.tsx +++ b/packages/arco-lib/src/components/Select.tsx @@ -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, diff --git a/packages/arco-lib/src/components/Switch.tsx b/packages/arco-lib/src/components/Switch.tsx index 13d6fbac..23a89bb2 100644 --- a/packages/arco-lib/src/components/Switch.tsx +++ b/packages/arco-lib/src/components/Switch.tsx @@ -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, diff --git a/packages/arco-lib/src/components/Table/Table.tsx b/packages/arco-lib/src/components/Table/Table.tsx index dc779bf3..4940b295 100644 --- a/packages/arco-lib/src/components/Table/Table.tsx +++ b/packages/arco-lib/src/components/Table/Table.tsx @@ -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 = { type: 'text', filter: true, displayValue: '', + componentSlotIndex: 0, }, { title: 'Salary', @@ -89,6 +92,7 @@ export const exampleProperties: Static = { filter: false, type: 'text', displayValue: '', + componentSlotIndex: 0, }, { title: 'Link', @@ -97,19 +101,7 @@ export const exampleProperties: Static = { 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 ( +
+ Cannot find child with index {column.componentSlotIndex} in slot. +
+ ); + } + + const _childrenSchema = { + ...childSchema, + id: `${component.id}_${childSchema.id}_${index}`, + }; + + colItem = ( + + ); + break; default: const text = evaledColumn.displayValue || value; colItem = {text}; @@ -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, diff --git a/packages/arco-lib/src/components/Tabs.tsx b/packages/arco-lib/src/components/Tabs.tsx index 650f75d8..d488166e 100644 --- a/packages/arco-lib/src/components/Tabs.tsx +++ b/packages/arco-lib/src/components/Tabs.tsx @@ -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({ diff --git a/packages/arco-lib/src/components/TextArea.tsx b/packages/arco-lib/src/components/TextArea.tsx index 2e2fecbf..a3c41826 100644 --- a/packages/arco-lib/src/components/TextArea.tsx +++ b/packages/arco-lib/src/components/TextArea.tsx @@ -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, diff --git a/packages/arco-lib/src/components/TreeSelect.tsx b/packages/arco-lib/src/components/TreeSelect.tsx index 92520285..dfe6bea2 100644 --- a/packages/arco-lib/src/components/TreeSelect.tsx +++ b/packages/arco-lib/src/components/TreeSelect.tsx @@ -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({ diff --git a/packages/arco-lib/src/examples/pages/table/customComponent.ts b/packages/arco-lib/src/examples/pages/table/customComponent.ts new file mode 100644 index 00000000..0f8713cb --- /dev/null +++ b/packages/arco-lib/src/examples/pages/table/customComponent.ts @@ -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, + }, + }, + ], + }, + }, + ], + }, + ], + }, +}; diff --git a/packages/arco-lib/src/examples/pages/table/index.tsx b/packages/arco-lib/src/examples/pages/table/index.tsx index 12f0488c..860e893e 100644 --- a/packages/arco-lib/src/examples/pages/table/index.tsx +++ b/packages/arco-lib/src/examples/pages/table/index.tsx @@ -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 = () => { You can easily open or close the properties of the table + Custom Column Component + + You can use any Sunmao component as column element instead of plain text. + + + Sort and filter Configure the sortable or filterable of{' '} diff --git a/packages/arco-lib/src/generated/types/Table.ts b/packages/arco-lib/src/generated/types/Table.ts index 5d4bfcc6..f1769108 100644 --- a/packages/arco-lib/src/generated/types/Table.ts +++ b/packages/arco-lib/src/generated/types/Table.ts @@ -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({