@@ -3,7 +3,7 @@ import { Dropdown, DropdownProps, Form, Input, Tabs } from 'antd';
33import { BlockHeader } from 'dt-react-component' ;
44import { IBlockHeaderProps } from 'dt-react-component/blockHeader' ;
55
6- import { InputMode , ITreeNode , useTreeData } from '../useTreeData' ;
6+ import { ITreeNode } from '../useTreeData' ;
77import { CatalogIcon , CloseIcon , DragIcon , EllipsisIcon , SearchIcon } from './icon' ;
88import CatalogueTree , { ICatalogueTree } from './tree' ;
99
@@ -16,36 +16,39 @@ type readOnlyTab = readonly Tab[];
1616
1717type TabKey < T extends readOnlyTab > = T [ number ] [ 'key' ] ;
1818
19- interface NormalCatalogueProps
19+ interface NormalCatalogueProps < U extends Record < string , any > = { } >
2020 extends Pick < IBlockHeaderProps , 'tooltip' | 'addonAfter' | 'addonBefore' | 'title' > ,
21- ICatalogueTree {
21+ ICatalogueTree < U > {
2222 showSearch ?: boolean ;
2323 edit ?: boolean ;
2424 placeholder ?: string ;
2525 loading ?: boolean ;
26- onChange ?: ReturnType < typeof useTreeData > [ 'onChange' ] ;
27- overlay ?: ( item : ITreeNode ) => DropdownProps [ 'overlay' ] ;
26+ onCancelSave ?: ( item : ITreeNode < U > ) => void ;
27+ overlay ?: ( item : ITreeNode < U > ) => DropdownProps [ 'overlay' ] ;
2828 onSearch ?: ( value : string ) => void ;
29- onSave ?: ( data : ITreeNode , value : string ) => Promise < string | void > ;
29+ onSave ?: ( data : ITreeNode < U > , value : string ) => Promise < string | void > ;
3030}
31- interface TabsCatalogueProps < T extends readOnlyTab > extends NormalCatalogueProps {
31+ interface TabsCatalogueProps < U extends Record < string , any > , T extends readOnlyTab >
32+ extends NormalCatalogueProps < U > {
3233 tabList ?: T ;
3334 activeTabKey ?: TabKey < T > ;
3435 defaultTabKey ?: TabKey < T > ;
3536 onTabChange ?: ( key : TabKey < T > ) => void ;
3637}
3738
38- export type CatalogueProps < T extends readOnlyTab = any > =
39- | TabsCatalogueProps < T >
40- | NormalCatalogueProps ;
39+ export type CatalogueProps < U extends Record < string , any > = { } , T extends readOnlyTab = any > =
40+ | TabsCatalogueProps < U , T >
41+ | NormalCatalogueProps < U > ;
4142
42- function isTabMode < T extends readOnlyTab > (
43- props : CatalogueProps < T >
44- ) : props is TabsCatalogueProps < T > {
43+ function isTabMode < U extends Record < string , any > = { } , T extends readOnlyTab = any > (
44+ props : CatalogueProps < U , T >
45+ ) : props is TabsCatalogueProps < U , T > {
4546 return 'tabList' in props ;
4647}
4748
48- const Catalogue = < T extends readOnlyTab > ( props : CatalogueProps < T > ) => {
49+ const Catalogue = < U extends Record < string , any > = { } , T extends readOnlyTab = any > (
50+ props : CatalogueProps < U , T >
51+ ) => {
4952 const {
5053 title,
5154 addonBefore = < CatalogIcon style = { { fontSize : 20 } } /> ,
@@ -56,38 +59,45 @@ const Catalogue = <T extends readOnlyTab>(props: CatalogueProps<T>) => {
5659 edit = true ,
5760 treeData,
5861 draggable,
62+ titleRender,
5963 overlay,
60- onChange,
6164 onSearch,
6265 onSave,
66+ onCancelSave,
6367 ...rest
6468 } = props ;
6569
6670 const [ tabSearch , setTabSearch ] = useState ( false ) ;
6771
6872 const [ form ] = Form . useForm ( ) ;
6973
70- const loopTree = ( data : ITreeNode [ ] ) : ITreeNode [ ] => {
71- return data ?. map ( ( item ) => {
72- const newItem = {
73- ...item ,
74- editable : item ?. editable === undefined ? true : item ?. editable ,
75- addable : item ?. addable === undefined ? true : item ?. addable ,
76- deletable : item ?. deletable === undefined ? true : item ?. deletable ,
77- } ;
78- if ( item . children ) {
79- return {
80- ...newItem ,
81- title : renderTitle ( newItem ) ,
82- children : loopTree ( item . children ) ,
83- } ;
84- }
85- return {
86- ...newItem ,
87- title : renderTitle ( newItem ) ,
88- children : undefined ,
89- } ;
90- } ) ;
74+ const defaultTitleRender = ( item : ITreeNode < U > ) => {
75+ if ( item . edit ) {
76+ return (
77+ < Form form = { form } preserve = { false } >
78+ < Form . Item name = "catalog_input" initialValue = { item ?. title as string } >
79+ < Input
80+ size = "small"
81+ placeholder = { `请输入${ title } 名称` }
82+ maxLength = { 100 }
83+ autoFocus
84+ onFocus = { ( ) => form . setFields ( [ { name : 'catalog_input' , errors : [ ] } ] ) }
85+ onClick = { ( e ) => e . stopPropagation ( ) }
86+ onBlur = { ( { target } ) => handleInputSubmit ( item , target . value ) }
87+ onPressEnter = { ( { target } ) =>
88+ handleInputSubmit ( item , ( target as any ) . value )
89+ }
90+ />
91+ </ Form . Item >
92+ </ Form >
93+ ) ;
94+ }
95+ return (
96+ < div className = "tree__title" >
97+ < div className = "tree__title--text" > { item . title } </ div >
98+ { edit && renderNodeHover ( item ) }
99+ </ div >
100+ ) ;
91101 } ;
92102
93103 const renderHeader = ( ) => {
@@ -138,75 +148,16 @@ const Catalogue = <T extends readOnlyTab>(props: CatalogueProps<T>) => {
138148 ) ;
139149 } ;
140150
141- const handleInputSubmit = ( item : ITreeNode , value : string ) => {
151+ const handleInputSubmit = ( item : ITreeNode < U > , value : string ) => {
142152 if ( ! value ) {
143- return onChange ?.( undefined , undefined ) ;
144- }
145- // item 为当前编辑的数据,对于 Append 的情况需要传入父级的 key
146- if ( item . inputMode === InputMode . Append ) {
147- const findAppendParents = ( data : ITreeNode [ ] , item : ITreeNode ) : ITreeNode | null => {
148- let result : ITreeNode | null = null ;
149- function traverse ( node : ITreeNode , parent : ITreeNode | null ) : void {
150- if ( node . inputMode === 'append' && node . key === item . key && parent ) {
151- result = parent ;
152- }
153- if ( Array . isArray ( node . children ) ) {
154- node . children . forEach ( ( child ) => traverse ( child , node ) ) ;
155- }
156- }
157- data . forEach ( ( item ) => traverse ( item , null ) ) ;
158- return result ;
159- } ;
160- const parentItem = findAppendParents ( treeData , item ) ;
161- return (
162- parentItem &&
163- onSave ?.( { ...parentItem , inputMode : InputMode . Append } , value ) . then ( ( msg ) => {
164- form . setFields ( [ { name : 'catalog_input' , errors : msg ? [ msg ] : [ ] } ] ) ;
165- } )
166- ) ;
153+ return onCancelSave ?.( item ) ;
167154 }
168155 onSave ?.( item , value ) . then ( ( msg ) => {
169156 form . setFields ( [ { name : 'catalog_input' , errors : msg ? [ msg ] : [ ] } ] ) ;
170157 } ) ;
171158 } ;
172159
173- const renderInput = ( item : ITreeNode ) => {
174- return (
175- < div className = "tree__title--input" >
176- < Form form = { form } preserve = { false } >
177- < Form . Item name = "catalog_input" >
178- < Input
179- defaultValue = { item ?. title as string }
180- size = "small"
181- placeholder = { `请输入${ title } 名称` }
182- maxLength = { 100 }
183- autoFocus
184- onFocus = { ( ) => form . setFields ( [ { name : 'catalog_input' , errors : [ ] } ] ) }
185- onClick = { ( e ) => e . stopPropagation ( ) }
186- onBlur = { ( { target } ) => handleInputSubmit ( item , target . value ) }
187- onPressEnter = { ( { target } ) =>
188- handleInputSubmit ( item , ( target as any ) . value )
189- }
190- />
191- </ Form . Item >
192- </ Form >
193- </ div >
194- ) ;
195- } ;
196-
197- const renderTitle = ( item : ITreeNode ) => {
198- if ( item . inputMode ) {
199- return renderInput ( item ) ;
200- }
201- return (
202- < div className = "tree__title" >
203- < div className = "tree__title--text" > { item . title } </ div >
204- { edit && renderNodeHover ( item ) }
205- </ div >
206- ) ;
207- } ;
208-
209- const renderNodeHover = ( item : ITreeNode ) => {
160+ const renderNodeHover = ( item : ITreeNode < U > ) => {
210161 return (
211162 < div
212163 className = "tree__title--operation"
@@ -238,8 +189,9 @@ const Catalogue = <T extends readOnlyTab>(props: CatalogueProps<T>) => {
238189 { renderSearch ( ) }
239190 { renderTab ( ) }
240191 < CatalogueTree
241- treeData = { loopTree ( treeData ) }
192+ treeData = { treeData }
242193 draggable = { draggable ? { icon : false } : false }
194+ titleRender = { titleRender || defaultTitleRender }
243195 { ...rest }
244196 />
245197 </ div >
0 commit comments