Skip to content

Commit 170e11d

Browse files
authored
Merge pull request #536 from siddharth-vaghasia/master
Implemented TreeView control
2 parents 13c2559 + 77f990f commit 170e11d

20 files changed

+1558
-3
lines changed
12.7 KB
Loading
573 KB
Loading
10.2 KB
Loading
12.2 KB
Loading
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
## TreeView control
2+
3+
This graphical control allows to present a hierarchical view of information. Each tree item can have a number of subitems. This is often visualized by indentation in a list. An tree item can be expanded to reveal subitems (if exists), and collapsed to hide subitems.
4+
5+
Here is an example of the control in action:
6+
7+
![Tree View control](../assets/TreeView-control.gif)
8+
9+
**With all possible options**
10+
11+
![Tree View control](../assets/TreeView-all-possible-options.png)
12+
13+
**Without check boxes or when selection mode is 'None'**
14+
15+
![Tree View control](../assets/TreeView-without-checkbox.png)
16+
17+
**Without check boxes, and selection mode is multiple**
18+
19+
![Tree View control](../assets/TreeView-without-checkbox-selection-mode.png)
20+
21+
## How to use this control in your solutions
22+
23+
- Check that you installed the `@pnp/spfx-controls-react` dependency. Check out the [getting started](../../#getting-started) page for more information about installing the dependency.
24+
- Import the following modules to your component:
25+
26+
```TypeScript
27+
import { TreeView, ITreeItem } from "@pnp/spfx-controls-react/lib/TreeView";
28+
```
29+
30+
- Use the `TreeView` control in your code as follows:
31+
32+
```TypeScript
33+
<TreeView
34+
items={treeitems}
35+
defaultExpanded={false}
36+
selectionMode={TreeViewSelectionMode.Multiple}
37+
selectChildrenIfParentSelected={true}
38+
showCheckboxes={true}
39+
treeItemActionsDisplayMode={TreeItemActionsDisplayMode.ContextualMenu}
40+
defaultSelectedKeys=['key1', 'key2'],
41+
onSelect={this.onTreeItemSelect}
42+
onExpandCollapse={this.onTreeItemExpandCollapse}
43+
onRenderItem={this.renderCustomTreeItem} />
44+
```
45+
46+
- With the `onSelect` property you can capture the event of when the tree item in the TreeView has changed the selection:
47+
48+
```typescript
49+
private onTreeItemSelect(items: ITreeItem[]) {
50+
console.log("Items selected: ", items);
51+
}
52+
```
53+
54+
- With the `onExpandCollapse` property you can capture the event of when the tree item in the TreeView has expanded or collapsed:
55+
56+
```typescript
57+
private onTreeItemExpandCollapse(item: ITreeItem, isExpanded: boolean) {
58+
console.log((isExpanded ? "Item expanded: " : "Item collapsed: ") + item);
59+
}
60+
```
61+
62+
## Custom Rendering
63+
You can fully customize how tree items are rendered by providing the onRenderItem callback function and returning whatever JSX.Element you want.
64+
65+
For example, you can define your function in a tsx file like this:
66+
67+
```typescript
68+
import * as React from 'react';
69+
70+
private renderCustomTreeItem(item: ITreeItem): JSX.Element {
71+
return (
72+
<span>
73+
{
74+
item.iconProps &&
75+
<i className={"ms-Icon ms-Icon--" + item.iconProps.iconName} style={{ paddingRight: '4px' }} />
76+
}
77+
{item.label}
78+
</span>
79+
);
80+
}
81+
```
82+
83+
## Implementation
84+
85+
The TreeView control can be configured with the following properties:
86+
87+
| Property | Type | Required | Description |
88+
|--------------------------------|----------------------------|----------|------------------------------------------------------------------------------------------------------------------------------------|
89+
| items | ITreeItem[] | yes | An array of tree items to display. refer [example](#example-of-array-of-tree-items-used-to-render-control-as-in-first-screenshot). |
90+
| defaultExpanded | boolean | no | Specify if the tree items are displayed as expanded by default (defaults to false). |
91+
| selectionMode | enum | no | Specify the selection mode of tree view (defaults to Single selection). |
92+
| selectChildrenIfParentSelected | boolean | no | Specify if the childrens should be selected when parent item is selected (defaults to false). |
93+
| showCheckboxes | boolean | yes | Specify if the checkboxes should be displayed for selection. |
94+
| treeItemActionsDisplayMode | TreeItemActionsDisplayMode | no | Specify the display mode of the tree item actions. |
95+
| defaultSelectedKeys | string[] | no | Specify keys of items to be selected by default. |
96+
| onExpandCollapse | function | no | Defines a onExpandCollapse function to raise when the tree item has expanded or collapsed. |
97+
| onSelect | function | no | Captures the event of when the tree item selection has changed. |
98+
| onRenderItem | function | no | Optional callback to provide custom rendering of the item (default is simple text of item label and a checkbox for selection). |
99+
100+
Enum `TreeViewSelectionMode`
101+
102+
Specifies the selection mode of tree item.
103+
| Value |
104+
|----------|
105+
| Single |
106+
| Multiple |
107+
| None |
108+
109+
Interface `ITreeItem`
110+
111+
Each tree item in the `treeitems` property is defined as `ITreeItem` as follows:
112+
113+
| Property | Type | Required | Description |
114+
|------------|-------------------|----------|------------------------------------------------------------------|
115+
| key | string | yes | The unique ID of the tree item. |
116+
| label | string | yes | Text displayed next to checkbox. |
117+
| subLabel | string | no | The sub label of the tree item. |
118+
| iconProps | IIconProps | no | Custom icon to be rendered before label. |
119+
| disabled | boolean | no | Specify if the tree item needs to be disabled. Default is false. |
120+
| selectable | boolean | no | Specify if the tree item can be selected. Default is true. |
121+
| data | any | no | Specify an additional data of the tree item. |
122+
| actions | ITreeItemAction[] | no | Specify list of actions for the tree item. |
123+
| children | ITreeItem[] | no | Specify list of child tree items. |
124+
125+
126+
Interface `ITreeItemAction`
127+
128+
Specifies the list of actions for the tree item.
129+
| Property | Type | Required | Description |
130+
|----------------------|--------------------------------------|----------|----------------------------------------------------------------------------------------------------------------------------|
131+
| id | string | yes | Unique id of the action. |
132+
| title | string | yes | Title of the action. |
133+
| iconProps | IIconProps | no | Name of the icon to be used to display action. |
134+
| hidden | boolean | no | Specify if the action is hidden. This could be used for instance when you want to invoke the action right after rendering. |
135+
| invokeActionOnRender | boolean | no | Specifies if you want to invoke the action on render. |
136+
| actionCallback | (currentTreeItem: ITreeItem) => void | yes | Method to be executed when action is fired. |
137+
138+
Enum `TreeItemActionsDisplayMode`
139+
140+
Specifies the display mode of the tree item action.
141+
| Value |
142+
|----------------|
143+
| Buttons |
144+
| ContextualMenu |
145+
146+
## Example of array of tree items used to render control as in 2nd screenshot
147+
148+
```typescript
149+
items: [
150+
{
151+
key: "R1",
152+
label: "Root",
153+
subLabel: "This is a sub label for node",
154+
iconProps: skypeCheckIcon,
155+
actions: [{
156+
title: "Get item",
157+
iconProps: {
158+
iconName: 'Warning',
159+
style: {
160+
color: 'salmon',
161+
},
162+
},
163+
id: "GetItem",
164+
actionCallback: async (treeItem: ITreeItem) => {
165+
console.log(treeItem);
166+
}
167+
}],
168+
children: [
169+
{
170+
key: "1",
171+
label: "Parent 1",
172+
selectable: false,
173+
children: [
174+
{
175+
key: "3",
176+
label: "Child 1",
177+
subLabel: "This is a sub label for node",
178+
actions: [{
179+
title:"Share",
180+
iconProps: {
181+
iconName: 'Share'
182+
},
183+
id: "GetItem",
184+
actionCallback: async (treeItem: ITreeItem) => {
185+
console.log(treeItem);
186+
}
187+
}],
188+
children: [
189+
{
190+
key: "gc1",
191+
label: "Grand Child 1",
192+
actions: [{
193+
title: "Get Grand Child item",
194+
iconProps: {
195+
iconName: 'Mail'
196+
},
197+
id: "GetItem",
198+
actionCallback: async (treeItem: ITreeItem) => {
199+
console.log(treeItem);
200+
}
201+
}]
202+
}
203+
]
204+
},
205+
{
206+
key: "4",
207+
label: "Child 2",
208+
iconProps: skypeCheckIcon
209+
}
210+
]
211+
},
212+
{
213+
key: "2",
214+
label: "Parent 2"
215+
},
216+
{
217+
key: "5",
218+
label: "Parent 3",
219+
disabled: true
220+
},
221+
{
222+
key: "6",
223+
label: "Parent 4",
224+
selectable: true
225+
}
226+
]
227+
},
228+
{
229+
key: "R2",
230+
label: "Root 2",
231+
children: [
232+
{
233+
key: "8",
234+
label: "Parent 5"
235+
}
236+
]
237+
}
238+
]
239+
```
240+
IconpProps in above example can be declared as below
241+
242+
```typescript
243+
private skypeCheckIcon: IIconProps = { iconName: 'SkypeCheck' };
244+
```
245+
246+

src/TreeView.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './controls/treeView/index';
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import * as React from 'react';
2+
import { CommandBarButton } from 'office-ui-fabric-react/lib/Button';
3+
import { IIconProps } from 'office-ui-fabric-react/lib/Icon';
4+
import { ITreeItemAction, IConcreteTreeItemActionProps } from './ITreeItemActions';
5+
import styles from './TreeView.module.scss';
6+
7+
/**
8+
* Renders the controls for Button TreeItem action component
9+
*/
10+
export default class ButtonTreeItemAction extends React.Component<IConcreteTreeItemActionProps> {
11+
12+
/**
13+
* componentWillMount lifecycle hook
14+
*/
15+
public componentWillMount(): void {
16+
this.checkForImmediateInvocations();
17+
}
18+
19+
/**
20+
* Prepares the command bar button
21+
*/
22+
private prepareCommandBarButton = (treeItemAction: ITreeItemAction): { name: string, text: string, iconProps: IIconProps, btnTitle: string } => {
23+
let name: string = treeItemAction.title;
24+
let text: string = treeItemAction.title;
25+
let iconProps: IIconProps = treeItemAction.iconProps;
26+
let btnTitle: string = treeItemAction.title;
27+
28+
return { name, text, iconProps, btnTitle };
29+
}
30+
31+
/**
32+
* Gets the action button styling
33+
*/
34+
private getTreeItemActionButtonStyle = (treeItemAction: ITreeItemAction): React.CSSProperties => {
35+
let result: React.CSSProperties = {
36+
backgroundColor: "transparent",
37+
height: "32px"
38+
};
39+
40+
return result;
41+
}
42+
43+
/**
44+
* Check if there are action to immediatly invoke
45+
*/
46+
private checkForImmediateInvocations() {
47+
const { treeItemActions } = this.props;
48+
49+
for (const action of treeItemActions) {
50+
if (action.invokeActionOnRender) {
51+
this.onActionExecute(action);
52+
}
53+
}
54+
}
55+
56+
/**
57+
* On action execution
58+
*/
59+
private onActionExecute = async (treeItemAction: ITreeItemAction) => {
60+
await treeItemAction.actionCallback(this.props.treeItem);
61+
this.props.treeItemActionCallback();
62+
}
63+
64+
/**
65+
* Default React render method
66+
*/
67+
public render(): React.ReactElement<IConcreteTreeItemActionProps> {
68+
const { treeItem, treeItemActions } = this.props;
69+
70+
// Check if there are actions to show
71+
const actionsToShow = treeItemActions.filter(a => !a.hidden);
72+
if (actionsToShow && actionsToShow.length === 0) {
73+
return null;
74+
}
75+
76+
return (
77+
<div>
78+
{
79+
treeItemActions &&
80+
treeItemActions.map(treeItemAction => {
81+
const { name, text, iconProps, btnTitle } = this.prepareCommandBarButton(treeItemAction);
82+
83+
return (
84+
treeItemAction.hidden ? (
85+
null
86+
) : (
87+
<div>
88+
<CommandBarButton split={true}
89+
onClick={() => { this.onActionExecute(treeItemAction); }}
90+
iconProps={iconProps}
91+
text={text}
92+
title={btnTitle}
93+
name={name}
94+
key={treeItem.key}
95+
className={styles.actionButton} />
96+
</div>
97+
)
98+
);
99+
})
100+
}
101+
</div>
102+
);
103+
}
104+
}

0 commit comments

Comments
 (0)