feat: generator add function of getDataSource from ref

This commit is contained in:
helloqian12138 2021-12-20 21:45:05 +08:00
parent 8593e235d7
commit 8fc99d2a25
11 changed files with 128 additions and 95 deletions

View File

@ -1,3 +1,4 @@
/* stylelint-disable selector-class-pattern */
.__dumi-default-layout[data-route="/drip-table-generator/preview"] {
padding-top: 64px;
padding-left: 0;
@ -12,5 +13,9 @@
padding: 16px 16px;
border-bottom: 1px solid #e6e6ee;
box-shadow: 0 1px 4px -1px rgba(0, 0, 0, .05);
.header-button {
margin: 0 12px;
}
}
}

View File

@ -8,7 +8,7 @@ import React from 'react';
import { Button, Row } from 'antd';
import { DripTableSchema } from 'drip-table';
import DripTableDriverAntDesign from 'drip-table-driver-antd';
import DripTableGenerator from 'drip-table-generator';
import DripTableGenerator, { DripTableGeneratorHandler } from 'drip-table-generator';
import 'antd/dist/antd.css';
import 'drip-table-generator/index.css';
@ -53,9 +53,7 @@ const initialSchema: DripTableSchema = {
const Demo = (props: { showHeader: boolean }) => {
const generator: React.MutableRefObject<null | {
getSchemaValue: () => void;
}> = React.useRef(null);
const generator: React.MutableRefObject<DripTableGeneratorHandler | null> = React.useRef(null);
const views = {
demoHeader: props.showHeader !== false,
@ -65,17 +63,18 @@ const Demo = (props: { showHeader: boolean }) => {
<React.Fragment>
{ views.demoHeader && (
<Row className="sample-header-extra-container">
<Button type="primary" onClick={() => { console.log(generator.current?.getSchemaValue()); }}>schema</Button>
<Button className="header-button" type="primary" onClick={() => { console.log(generator.current?.getSchemaValue()); }}>schema</Button>
<Button className="header-button" type="primary" onClick={() => { console.log(generator.current?.getDataSource()); }}>dataSource</Button>
</Row>
)}
<DripTableGenerator
ref={generator}
style={{ height: 720 }}
style={{ height: 640 }}
driver={DripTableDriverAntDesign}
schema={initialSchema}
dataSource={mockData.slice(0, 4)}
dataFields={['id', 'name', 'status', 'description', 'ext.state']}
onExportSchema={(schema) => { console.log(schema); }}
onExportSchema={schema => { console.log(schema); }}
customComponents={{ custom: { TextComponent } }}
customComponentPanel={components}
/>

View File

@ -1,7 +1,4 @@
import { createContext } from 'react';
import { DripTableRecordTypeBase } from 'drip-table';
import { DripTableGeneratorProps } from '@/typing';
export type IDripTableGeneratorContext<RecordType extends DripTableRecordTypeBase> = DripTableGeneratorProps<RecordType>;
export const Ctx = createContext<IDripTableGeneratorContext<Record<string, unknown>>>({});
export const Ctx = createContext<DripTableGeneratorProps>({});

View File

@ -1,17 +1,19 @@
import React, { useState, forwardRef, useImperativeHandle, useRef } from 'react';
import { ConfigProvider } from 'antd';
import { ColumnConfig, DripTableRecordTypeBase, DripTableSchema } from 'drip-table';
import { ColumnConfig, DripTableSchema } from 'drip-table';
import zhCN from 'antd/lib/locale/zh_CN';
import { Ctx } from '@/context';
import { DripTableGeneratorProps, DripTableGeneratorHandler } from '@/typing';
import { defaultState, GlobalStore } from '@/store';
import { defaultState, DripTableGeneratorState, GlobalStore } from '@/store';
import Wrapper from './wrapper';
import Wrapper, { GeneratorWrapperHandler } from './wrapper';
import 'antd/dist/antd.less';
const useTableRoot = (props, store, wrapper) => {
const useTableRoot = (
props: DripTableGeneratorProps,
store: [DripTableGeneratorState, React.Dispatch<React.SetStateAction<DripTableGeneratorState>>],
wrapper: React.MutableRefObject<GeneratorWrapperHandler | null>,
) => {
const [state, setState] = store;
const getSchemaValue = (): DripTableSchema => {
@ -36,24 +38,34 @@ const useTableRoot = (props, store, wrapper) => {
};
};
const getDataSource = () => {
if (wrapper.current) {
const currentState = wrapper.current.getState();
return currentState.previewDataSource;
}
return state.previewDataSource;
};
const context = {
...props,
...state,
getSchemaValue,
getDataSource,
setGlobalData: setState,
};
return context;
};
const Container = <RecordType extends DripTableRecordTypeBase>(props: DripTableGeneratorProps<RecordType>, ref: React.ForwardedRef<DripTableGeneratorHandler>) => {
const wrapper = useRef({});
const Container = (props: DripTableGeneratorProps, ref: React.ForwardedRef<DripTableGeneratorHandler>) => {
const wrapper = useRef(null);
const initialState = defaultState();
const store = useState(initialState);
const context = useTableRoot(props, store, wrapper);
useImperativeHandle(ref, () => context);
const WrapperRef = forwardRef<unknown, DripTableGeneratorProps<RecordType> & { store: GlobalStore }>(Wrapper);
const WrapperRef = forwardRef<GeneratorWrapperHandler, DripTableGeneratorProps & { store: GlobalStore }>(Wrapper);
return (
<ConfigProvider locale={zhCN}>

View File

@ -7,7 +7,7 @@
*/
import React from 'react';
import { Result, Tabs } from 'antd';
import { Alert, Result, Tabs } from 'antd';
import { ExclamationCircleTwoTone } from '@ant-design/icons';
import { DripTableSchema } from 'drip-table';
import MonacoEditor from '@monaco-editor/react';
@ -38,12 +38,14 @@ const { TabPane } = Tabs;
const AttributeLayout = (props: Props & { store: GlobalStore }) => {
const { dataFields } = useGlobalData();
const [state, setState] = props.store;
const store = { state, setState };
const [activeKey, setActiveKey] = React.useState('0');
const [state, actions] = props.store;
const store = { state, setState: actions };
const [codeErrorMessage, setCodeErrorMessage] = React.useState('');
const [code, setCode] = React.useState(JSON.stringify(state.dataSource, null, 4));
const code = JSON.stringify(state.previewDataSource, null, 4);
const getActiveKey = () => {
if (activeKey === '0') {
@ -129,17 +131,22 @@ const AttributeLayout = (props: Props & { store: GlobalStore }) => {
} as DripTableColumn;
};
/** TODO: 报错逻辑后续优化 */
function submitDataWithoutThrottle() {
/** TODO:
*
* @param {string} codeValue JSON
*/
const submitDataWithoutDebounce = (codeValue: string) => {
setCodeErrorMessage('');
try {
state.dataSource = JSON.parse(code);
globalActions.updateDataSource(store);
state.previewDataSource = JSON.parse(codeValue);
setState({ ...state });
globalActions.updatePreviewDataSource(store);
} catch (error) {
console.error(error);
}
setCodeErrorMessage((error as Error).message);
}
};
const submitTableData = debounce(submitDataWithoutThrottle, 1000);
const submitTableData = debounce(submitDataWithoutDebounce, 1000);
const renderGlobalForm = () => (
<CustomForm<GlobalSchema>
@ -169,7 +176,7 @@ const AttributeLayout = (props: Props & { store: GlobalStore }) => {
return;
}
if (uiProps.from === 'dataSource') {
uiProps.options = Object.keys(state.dataSource[0] || {})
uiProps.options = Object.keys(state.previewDataSource[0] || {})
.map(key => ({ label: key, value: key }));
} else if (uiProps.from === 'dataFields') {
uiProps.options = dataFields?.map(key => ({ label: key, value: key })) || [];
@ -181,7 +188,7 @@ const AttributeLayout = (props: Props & { store: GlobalStore }) => {
return;
}
if (itemUiProps.from === 'dataSource') {
itemUiProps.options = Object.keys(state.dataSource[0] || {})
itemUiProps.options = Object.keys(state.previewDataSource[0] || {})
.map(key => ({ label: key, value: key }));
} else if (itemUiProps.from === 'dataFields') {
itemUiProps.options = dataFields?.map(key => ({ label: key, value: key })) || [];
@ -226,13 +233,14 @@ const AttributeLayout = (props: Props & { store: GlobalStore }) => {
</TabPane>
<TabPane tab="表格数据" key="3" style={{ height: tabHeight, overflow: 'auto' }}>
<div className={styles['attributes-code-panel']}>
{ codeErrorMessage && <Alert style={{ margin: '8px 0' }} message={codeErrorMessage} type="error" showIcon /> }
<MonacoEditor
width="100%"
height={400}
language="json"
theme="vs-dark"
value={code || ''}
onChange={(value) => { setCode(value || ''); submitTableData(); }}
onChange={(value) => { submitTableData(value); }}
/>
</div>
</TabPane>

View File

@ -18,12 +18,12 @@ import Draggable from '@/components/Draggable';
import styles from './index.module.less';
import { get } from '@/utils';
interface Props<RecordType extends DripTableRecordTypeBase> {
driver: DripTableDriver<RecordType>;
customComponents: DripTableProps<RecordType>['components'] | undefined;
interface Props {
driver: DripTableDriver<DripTableRecordTypeBase>;
customComponents: DripTableProps<DripTableRecordTypeBase>['components'] | undefined;
}
const EditableTable = <RecordType extends DripTableRecordTypeBase>(props: Props<RecordType> & { store: GlobalStore }) => {
const EditableTable = (props: Props & { store: GlobalStore }) => {
const [state, actions] = props.store;
const store = { state, setState: actions };
@ -36,8 +36,8 @@ const EditableTable = <RecordType extends DripTableRecordTypeBase>(props: Props<
const DripTableComponent = column['ui:type'].startsWith('custom::')
? customComponents[column['ui:type'].replace('custom::', '')]
: builtInComponents[column['ui:type']];
const hasRecord = !(!state.dataSource || state.dataSource.length <= 0);
const record = state.dataSource[0] || {} as Record<string, unknown>;
const hasRecord = !(!state.previewDataSource || state.previewDataSource.length <= 0);
const record = state.previewDataSource[0] || {} as Record<string, unknown>;
const value = column.dataIndex ? get(record, column.dataIndex) : record;
const errorBoundary = () => {

View File

@ -13,12 +13,12 @@ import { GlobalStore } from '@/store';
import styles from './index.module.less';
interface Props<RecordType extends DripTableRecordTypeBase> {
driver: DripTableDriver<RecordType>;
customComponents: DripTableProps<RecordType>['components'];
interface Props {
driver: DripTableDriver<DripTableRecordTypeBase>;
customComponents: DripTableProps<DripTableRecordTypeBase>['components'];
}
const PreviewTable = <RecordType extends DripTableRecordTypeBase>(props: Props<RecordType> & { store: GlobalStore }) => {
const PreviewTable = (props: Props & { store: GlobalStore }) => {
const [state] = props.store;
const schema: DripTableSchema = {
@ -28,14 +28,14 @@ const PreviewTable = <RecordType extends DripTableRecordTypeBase>(props: Props<R
},
columns: state.columns as ColumnConfig[],
};
const totalPage = state.globalConfigs?.pagination && state.globalConfigs?.pagination.pageSize ? state.dataSource.length : 1;
const totalPage = state.globalConfigs?.pagination && state.globalConfigs?.pagination.pageSize ? state.previewDataSource.length : 1;
return (
<div className={styles['table-preview-wrapper']}>
<DripTable<RecordType>
<DripTable
driver={(props.driver || DripTableDriverAntDesign)}
schema={schema}
total={totalPage}
dataSource={state.dataSource as RecordType[]}
dataSource={state.previewDataSource}
components={props.customComponents}
/>
</div>

View File

@ -109,6 +109,7 @@ const ToolLayout = (props: { store: GlobalStore }) => {
globalData.onExportSchema(getSchemaValue());
}
}
message.success('复制成功');
setModalStatus('');
setCode('');
}}

View File

@ -23,7 +23,7 @@ export interface DripTableGeneratorState {
currentColumn?: DripTableColumn;
globalConfigs: DripTableSchema['configs'];
/** 表格数据generator不需要知道数据格式是什么直接交给drip-table即可 */
dataSource: Record<string, unknown>[];
previewDataSource: Record<string, unknown>[];
}
export const defaultState: () => DripTableGeneratorState = () => ({
@ -37,7 +37,7 @@ export const defaultState: () => DripTableGeneratorState = () => ({
pagination: false,
},
/** 数据 */
dataSource: [],
previewDataSource: [],
});
export type GlobalStore = [DripTableGeneratorState, React.Dispatch<React.SetStateAction<DripTableGeneratorState>>];
@ -51,7 +51,7 @@ export type GlobalActions = {
toggleEditMode: (store?: GlobalStoreObject) => void;
editColumns: (store?: GlobalStoreObject) => void;
checkColumn: (store?: GlobalStoreObject) => void;
updateDataSource: (store?: GlobalStoreObject) => void;
updatePreviewDataSource: (store?: GlobalStoreObject) => void;
updateGlobalConfig: (store?: GlobalStoreObject) => void;
}
@ -65,8 +65,8 @@ export const globalActions: GlobalActions = {
checkColumn(store) {
store?.setState({ ...store.state, currentColumn: store.state.currentColumn ? { ...store.state?.currentColumn } : void 0 });
},
updateDataSource(store) {
store?.setState({ ...store.state, dataSource: [...store.state.dataSource] });
updatePreviewDataSource(store) {
store?.setState({ ...store.state, previewDataSource: [...store.state.previewDataSource] });
},
updateGlobalConfig(store) {
store?.setState({ ...store.state, globalConfigs: { ...store.state.globalConfigs } });

View File

@ -48,19 +48,27 @@ export interface DripTableGeneratorHandler extends DripTableGeneratorState {
* @returns { DripTableSchema } DripTableSchema配置
*/
getSchemaValue: () => DripTableSchema;
/**
*
*
* @returns {Record<string, unknown>[]}
*/
getDataSource: () => Record<string, unknown>[];
}
export interface DripTableGeneratorProps<RecordType extends DripTableRecordTypeBase, CustomComponentEvent extends EventLike = never, Ext = unknown> {
export interface DripTableGeneratorProps<CustomComponentEvent extends EventLike = never, Ext = unknown> {
style?: CSSProperties;
driver?: DripTableDriver<RecordType>;
driver?: DripTableDriver<DripTableRecordTypeBase>;
showComponentLayout?: boolean;
componentLayoutStyle?: CSSProperties;
rightLayoutStyle?: CSSProperties;
showToolLayout?: boolean;
dataSource?: RecordType[];
/** generator无需关心DataSource数据类型是什么唯一做的是直接传递给drip-table */
dataSource?: DripTableRecordTypeBase[];
dataFields?: string[];
schema?: DripTableSchema;
customComponents?: DripTableProps<RecordType, CustomComponentEvent, Ext>['components'];
customComponents?: DripTableProps<DripTableRecordTypeBase, CustomComponentEvent, Ext>['components'];
customComponentPanel?: {
mode: 'add' | 'replace';
components: DripTableComponentConfig[];

View File

@ -1,5 +1,4 @@
import React, { useState, useImperativeHandle } from 'react';
import { DripTableRecordTypeBase } from 'drip-table';
import DripTableDriverAntDesign from 'drip-table-driver-antd';
import { useGlobalData } from './hooks';
import { defaultState, DripTableGeneratorState, GlobalStore, setState } from './store';
@ -12,9 +11,13 @@ import { DripTableGeneratorProps } from './typing';
import styles from './index.module.less';
const Wrapper = <RecordType extends DripTableRecordTypeBase>(props: DripTableGeneratorProps<RecordType> & {
export type GeneratorWrapperHandler = {
getState: () => DripTableGeneratorState;
}
const Wrapper = (props: DripTableGeneratorProps & {
store: GlobalStore;
}, ref) => {
}, ref: React.ForwardedRef<GeneratorWrapperHandler>) => {
const {
style = {},
driver,
@ -22,12 +25,12 @@ const Wrapper = <RecordType extends DripTableRecordTypeBase>(props: DripTableGen
componentLayoutStyle = {},
rightLayoutStyle = {},
showToolLayout = true,
dataSource = [],
dataSource,
schema,
customComponentPanel,
customComponents,
} = useGlobalData();
const initialData = { dataSource } as DripTableGeneratorState;
const initialData = { previewDataSource: dataSource } as DripTableGeneratorState;
if (schema) {
initialData.globalConfigs = schema.configs;
initialData.columns = schema.columns?.map((item, index) => ({ key: index, sort: index, ...item }));