import * as React from 'react' ; import styles from './TreeView.module.scss' ; import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox' ; import { Icon } from 'office-ui-fabric-react/lib/Icon' ; import { IconButton } from 'office-ui-fabric-react/lib/Button' ; import * as strings from 'ControlStrings' ; import { ITreeItem } from './ITreeItem' ; import { TreeViewSelectionMode } from './ITreeViewProps' ; import TreeItemActionsControl from './TreeItemActionsControl' ; import { TreeItemActionsDisplayMode } from './ITreeItemActions' ; import { css } from 'office-ui-fabric-react/lib/Utilities' ; /**
 * TreeItem properties interface
 */ export interface ITreeItemProps { /**
     * Current tree item.
     */ treeItem : ITreeItem ; /**
     * Selection mode of tree item.
     */ selectionMode : TreeViewSelectionMode ; /**
     * Specifies the left padding for current tree item based on hierarchy.
     */ leftOffset : number ; /**
     * Specifies whether current tree item is a root.
     */ isFirstRender : boolean ; /**
     * Specifies whether current tree item should be rendered as an expanded.
     */ defaultExpanded : boolean ; /**
     * Specifies whether current tree item should be rendered as an expanded.
     */ showCheckboxes : boolean ; /**
     * Stores the selected tree items
     */ activeItems : ITreeItem [ ] ; /**
     * Display mode of the tree item actions.
     */ treeItemActionsDisplayMode ? : TreeItemActionsDisplayMode ; /**
     * Callback function called when an item is expanded / collapsed.
     */ parentCallbackExpandCollapse : ( item : ITreeItem , isExpanded : boolean ) => void ; /**
     * Callback function called when an item is selected.
     */ parentCallbackOnSelect : ( item : ITreeItem , isSelected : boolean ) => void ; /**
     * Customize how item is rendered.
     */ onRenderItem ? : ( item : ITreeItem ) => JSX . Element ; nodesToExpand : any [ ] ; /**
    * Specifies whether current tree item's children should be rendered as expanded.
    */ defaultExpandedChildren ? : boolean ; } /**
 * TreeItem state interface
 */ export interface ITreeItemState { /**
     * Specifies whether current tree item is selected
     */ selected ? : boolean ; /**
     * Specifies whether current tree item is expanded
     */ expanded ? : boolean ; } /**
 * CSS styles for checkbox
 */ const checkBoxStyle = { display : "inline-flex" } ; /**
 * Renders the controls for TreeItem component
 */ export default class TreeItem extends React . Component < ITreeItemProps , ITreeItemState > { param props constructor ( props , state ) { super ( props ) ; let active = props . activeItems . filter ( item => item . key === props . treeItem . key ) ; let expanded = props . defaultExpanded ; if ( props . nodesToExpand . indexOf ( props . treeItem . key ) != - 1 ) { expanded = true ; } this . state = { selected : active . length > 0 , expanded : expanded } ; this . _itemSelected = this . _itemSelected . bind ( this ) ; this . _handleExpandCollapse = this . _handleExpandCollapse . bind ( this ) ; } /**
     * Handle the checkbox change trigger
     */ private _itemSelected ( ev , isChecked ) { this . setState ( { selected : ! this . state . selected } ) ; this . props . parentCallbackOnSelect ( this . props . treeItem , isChecked ) ; } /**
     * Handle the click event: collapse or expand
     */ private _handleExpandCollapse ( ) { this . setState ( { expanded : ! this . state . expanded } ) ; this . props . parentCallbackExpandCollapse ( this . props . treeItem , ! this . state . expanded ) ; } param nextProps param nextContext public componentWillReceiveProps ( nextProps ) { if ( this . props . selectionMode != TreeViewSelectionMode . None ) { let active = nextProps . activeItems . filter ( item => item . key === this . props . treeItem . key ) ; this . setState ( { selected : active . length > 0 , expanded : this . state . expanded } ) ; } } /**
     * Default or custom rendering of tree item
     */ private renderItem ( item ) { if ( typeof this . props . onRenderItem === "function" ) { return this . props . onRenderItem ( item ) ; } else { return ( < div className = { styles . labels } onClick = { ( e ) => { if ( this . props . selectionMode != TreeViewSelectionMode . None && item . selectable != false ) { e . stopPropagation ( ) ; if ( ! item . disabled ) { this . _itemSelected ( e , ! this . state . selected ) ; } } } } > { this . props . showCheckboxes && item . selectable == false && ! item . children && < span className = { styles . blankspace } > & nbsp ; < /span>} { item . iconProps && < span > < Icon className = { styles . icon } iconName = { item . iconProps . iconName } style = { item . iconProps . style } / > & nbsp ; < /span>} { item . label } { item . subLabel && < div className = { styles . itemSubLabel } > { item . subLabel } < /div>} < /div>); } } /**
     * Process the child nodes
     */ public createChildNodes = ( list , paddingLeft ) => { if ( list . length ) { const { treeItem , selectionMode , activeItems , parentCallbackExpandCollapse , parentCallbackOnSelect , onRenderItem , showCheckboxes , treeItemActionsDisplayMode , defaultExpandedChildren } = this . props ; const { expanded } = this . state ; let childrenWithHandlers = list . map ( ( item , index ) => { return ( < TreeItem treeItem = { item } defaultExpanded = { defaultExpandedChildren ? expanded : expanded && ! item . hasOwnProperty ( 'children' ) } defaultExpandedChildren = { defaultExpandedChildren } leftOffset = { paddingLeft } selectionMode = { selectionMode } activeItems = { activeItems } isFirstRender = { ! paddingLeft ? true : false } parentCallbackExpandCollapse = { parentCallbackExpandCollapse } parentCallbackOnSelect = { parentCallbackOnSelect } onRenderItem = { onRenderItem } showCheckboxes = { showCheckboxes } treeItemActionsDisplayMode = { treeItemActionsDisplayMode } nodesToExpand = { this . props . nodesToExpand } / > ) ; } ) ; return childrenWithHandlers ; } } ; private treeItemActionCallback = ( ) : void => { } ; public render ( ) { const { treeItem , leftOffset , showCheckboxes , selectionMode , treeItemActionsDisplayMode } = this . props ; const { expanded , selected } = this . state ; const styleProps = { marginLeft : `${ leftOffset }px` } ; const contentStyles = { marginLeft : treeItem . children ? '0' : `${ leftOffset }px` } ; return ( < div > < div className = { `${ styles . listItem } ${ styles . tree }` } > < div className = { `${ styles . treeSelector }` } > { treeItem . children && < IconButton iconProps = { expanded ? { iconName : 'ChevronDown' } : { iconName : 'ChevronRight' } } alt = { expanded ? strings . TreeViewCollapseTitle : strings . TreeViewExpandTitle } title = { expanded ? strings . TreeViewCollapseTitle : strings . TreeViewExpandTitle } onClick = { ( ) => this . _handleExpandCollapse ( ) } > < /IconButton>} < /div> < div className = { css ( { [ styles . itemContent ] : true , [ styles . noCheckBox ] : ! showCheckboxes , [ styles . checked ] : selected , [ styles . disabled ] : ! ! treeItem . disabled } ) } style = { contentStyles } onClick = { ( e ) => { if ( this . props . selectionMode != TreeViewSelectionMode . None && treeItem . selectable != false ) { e . stopPropagation ( ) ; if ( ! treeItem . disabled && e . currentTarget === e . target ) { this . _itemSelected ( e , ! this . state . selected ) ; } } } } > { ( treeItem . selectable != false ) && selectionMode != TreeViewSelectionMode . None && showCheckboxes && < Checkbox checked = { selected } disabled = { treeItem . disabled } className = { styles . checkbox } onChange = { this . _itemSelected } / > } { this . renderItem ( treeItem ) } { treeItem . actions && < div className = { styles . itemMenu } > < TreeItemActionsControl treeItem = { treeItem } treeItemActions = { { actions : treeItem . actions , treeItemActionsDisplayMode : treeItemActionsDisplayMode } } treeItemActionCallback = { this . treeItemActionCallback } / > < /div>} < /div> < /div> < div style = { styleProps || { } } > { expanded && treeItem . children ? this . createChildNodes ( treeItem . children , leftOffset ) : null } < /div> < /div>); } }