11import * as React from 'react' ;
22import { storiesOf } from '@storybook/react' ;
33
4+ import DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined' ;
5+ import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight' ;
6+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore' ;
47import FolderIcon from '@mui/icons-material/Folder' ;
58import FolderOpenIcon from '@mui/icons-material/FolderOpen' ;
69import InsertDriveFileOutlinedIcon from '@mui/icons-material/InsertDriveFileOutlined' ;
@@ -16,6 +19,8 @@ import {
1619} from '@table-library/react-table-library/table' ;
1720
1821import { useTree , CellTree , TreeExpandClickTypes } from '@table-library/react-table-library/tree' ;
22+ import { useTheme } from '@table-library/react-table-library/theme' ;
23+ import { findNodeById } from '@table-library/react-table-library/common' ;
1924
2025import { nodes } from '../data' ;
2126
@@ -395,6 +400,79 @@ storiesOf('Features/Tree', module)
395400 </ Table >
396401 ) ;
397402 } )
403+ . add ( 'double icon' , ( ) => {
404+ const data = { nodes } ;
405+
406+ const tree = useTree (
407+ data ,
408+ {
409+ onChange : onTreeChange ,
410+ } ,
411+ {
412+ treeIcon : {
413+ margin : '4px' ,
414+ iconDefault : (
415+ < div style = { { display : 'flex' , alignItems : 'center' } } >
416+ < div style = { { height : '20px' , width : '20px' } } />
417+ < DescriptionOutlinedIcon fontSize = "small" />
418+ </ div >
419+ ) ,
420+ iconRight : (
421+ < div style = { { display : 'flex' , alignItems : 'center' } } >
422+ < KeyboardArrowRightIcon fontSize = "small" />
423+ < FolderIcon fontSize = "small" />
424+ </ div >
425+ ) ,
426+ iconDown : (
427+ < div style = { { display : 'flex' , alignItems : 'center' } } >
428+ < ExpandMoreIcon fontSize = "small" />
429+ < FolderOpenIcon fontSize = "small" />
430+ </ div >
431+ ) ,
432+ } ,
433+ } ,
434+ ) ;
435+
436+ function onTreeChange ( action , state ) {
437+ console . log ( action , state ) ;
438+ }
439+
440+ return (
441+ < Table data = { data } tree = { tree } >
442+ { ( tableList ) => (
443+ < >
444+ < Header >
445+ < HeaderRow >
446+ < HeaderCell > Task</ HeaderCell >
447+ < HeaderCell > Deadline</ HeaderCell >
448+ < HeaderCell > Type</ HeaderCell >
449+ < HeaderCell > Complete</ HeaderCell >
450+ < HeaderCell > Tasks</ HeaderCell >
451+ </ HeaderRow >
452+ </ Header >
453+
454+ < Body >
455+ { tableList . map ( ( item ) => (
456+ < Row key = { item . id } item = { item } >
457+ < CellTree item = { item } > { item . name } </ CellTree >
458+ < Cell >
459+ { item . deadline . toLocaleDateString ( 'en-US' , {
460+ year : 'numeric' ,
461+ month : '2-digit' ,
462+ day : '2-digit' ,
463+ } ) }
464+ </ Cell >
465+ < Cell > { item . type } </ Cell >
466+ < Cell > { item . isComplete . toString ( ) } </ Cell >
467+ < Cell > { item . nodes ?. length } </ Cell >
468+ </ Row >
469+ ) ) }
470+ </ Body >
471+ </ >
472+ ) }
473+ </ Table >
474+ ) ;
475+ } )
398476 . add ( 'no icon margin' , ( ) => {
399477 const data = { nodes } ;
400478
@@ -606,4 +684,207 @@ storiesOf('Features/Tree', module)
606684 ) }
607685 </ Table >
608686 ) ;
687+ } )
688+ . add ( 'custom lines' , ( ) => {
689+ const data = { nodes } ;
690+
691+ const isLastChild = ( nodes , node ) => {
692+ const parentNode = findNodeById (
693+ nodes ,
694+ node . parentNode ?. id ? node . parentNode . id . toString ( ) : null ,
695+ ) ;
696+
697+ if ( ! parentNode && nodes [ nodes . length - 1 ] . id === node . id ) {
698+ return true ;
699+ } else if ( ! parentNode && nodes [ nodes . length - 1 ] . id !== node . id ) {
700+ return false ;
701+ }
702+
703+ if ( ! parentNode ?. nodes ) return true ;
704+ return parentNode ?. nodes [ parentNode ?. nodes . length - 1 ] . id === node . id ;
705+ } ;
706+
707+ const isFirstChild = ( nodes , node ) => {
708+ return nodes [ 0 ] . id === node . id ;
709+ } ;
710+
711+ const theme = useTheme ( {
712+ Cell : `
713+ height: 40px;
714+
715+ position: relative;
716+
717+ &:nth-of-type(1) {
718+ margin-left: 8px;
719+ padding-left: 8px;
720+ }
721+
722+ & .line {
723+ background-color: #0097e0;
724+ }
725+
726+ &:first-of-type div {
727+ max-width: 100%;
728+
729+ height: 100%;
730+ display: flex;
731+ align-items: center;
732+ }
733+
734+ & .line-icon-container > * {
735+ position: absolute;
736+ pointer-events: none;
737+ }
738+ ` ,
739+ } ) ;
740+
741+ const tree = useTree (
742+ data ,
743+ {
744+ onChange : onTreeChange ,
745+ } ,
746+ {
747+ treeIcon : {
748+ margin : '4px' ,
749+ iconDefault : (
750+ < LineIcon >
751+ < InsertDriveFileOutlinedIcon fontSize = "small" />
752+ </ LineIcon >
753+ ) ,
754+ iconRight : (
755+ < LineIcon >
756+ < FolderIcon fontSize = "small" />
757+ </ LineIcon >
758+ ) ,
759+ iconDown : (
760+ < LineIcon >
761+ < FolderOpenIcon fontSize = "small" />
762+ </ LineIcon >
763+ ) ,
764+ } ,
765+ } ,
766+ ) ;
767+
768+ function onTreeChange ( action , state ) {
769+ console . log ( action , state ) ;
770+ }
771+
772+ return (
773+ < Table data = { data } theme = { theme } tree = { tree } >
774+ { ( tableList ) => (
775+ < >
776+ < Header >
777+ < HeaderRow >
778+ < HeaderCell > Task</ HeaderCell >
779+ < HeaderCell > Deadline</ HeaderCell >
780+ < HeaderCell > Type</ HeaderCell >
781+ < HeaderCell > Complete</ HeaderCell >
782+ < HeaderCell > Tasks</ HeaderCell >
783+ </ HeaderRow >
784+ </ Header >
785+
786+ < Body >
787+ { tableList . map ( ( item , index ) => (
788+ < Row key = { item . id } item = { item } >
789+ < CellTree item = { item } >
790+ < Line
791+ isFirst = { isFirstChild ( data . nodes , item ) }
792+ isLast = { isLastChild ( data . nodes , item ) }
793+ treeXLevel = { item . treeXLevel }
794+ >
795+ { item . name }
796+ </ Line >
797+ </ CellTree >
798+ < Cell >
799+ { item . deadline . toLocaleDateString ( 'en-US' , {
800+ year : 'numeric' ,
801+ month : '2-digit' ,
802+ day : '2-digit' ,
803+ } ) }
804+ </ Cell >
805+ < Cell > { item . type } </ Cell >
806+ < Cell > { item . isComplete . toString ( ) } </ Cell >
807+ < Cell > { item . nodes ?. length } </ Cell >
808+ </ Row >
809+ ) ) }
810+ </ Body >
811+ </ >
812+ ) }
813+ </ Table >
814+ ) ;
609815 } ) ;
816+
817+ const LineIcon = ( { children } ) => (
818+ < div
819+ className = "line-icon-container"
820+ style = { {
821+ zIndex : 2 ,
822+ width : 24 ,
823+ height : 24 ,
824+ color : '#5472d3' ,
825+ display : 'flex' ,
826+ justifyContent : 'center' ,
827+ alignItems : 'center' ,
828+ position : 'relative' ,
829+ pointerEvents : 'none' ,
830+ } }
831+ >
832+ < div style = { { height : '20px' , width : '20px' , backgroundColor : '#ffffff' } } />
833+ { children }
834+ </ div >
835+ ) ;
836+
837+ const Line = ( { isFirst, isLast, treeXLevel, children } ) => {
838+ return (
839+ < >
840+ < div
841+ style = { {
842+ zIndex : 1 ,
843+ display : 'inline-block' ,
844+ width : '9px' ,
845+ height : '40px' ,
846+ pointerEvents : 'none' ,
847+ } }
848+ >
849+ < div
850+ className = "line"
851+ style = { {
852+ position : 'absolute' ,
853+ top : isFirst ? '20px' : '0' ,
854+ left : `${ 19 + treeXLevel * 20 } px` ,
855+ width : '1px' ,
856+ height : isLast ? '20px' : '40px' ,
857+ } }
858+ />
859+ < div
860+ className = "line"
861+ style = { {
862+ position : 'absolute' ,
863+ top : '20px' ,
864+ left : `${ 19 + treeXLevel * 20 } px` ,
865+ width : '18px' ,
866+ height : '1px' ,
867+ } }
868+ />
869+ </ div >
870+
871+ < span
872+ style = { {
873+ display : 'flex' ,
874+ alignItems : 'center' ,
875+ minWidth : 0 ,
876+ } }
877+ >
878+ < span
879+ style = { {
880+ whiteSpace : 'nowrap' ,
881+ textOverflow : 'ellipsis' ,
882+ overflow : 'hidden' ,
883+ } }
884+ >
885+ { children }
886+ </ span >
887+ </ span >
888+ </ >
889+ ) ;
890+ } ;
0 commit comments