Skip to content

Commit 47b38cc

Browse files
authoredJul 23, 2020
feat(ui5-side-navigation): initial implementation (#1889)
1 parent a7488cd commit 47b38cc

20 files changed

+891
-10
lines changed
 

‎packages/base/src/UI5Element.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,10 @@ class UI5Element extends HTMLElement {
493493
* @private
494494
*/
495495
_invalidate() {
496+
if (this._shouldInvalidateParent) {
497+
this.parentNode._invalidate();
498+
}
499+
496500
if (!this._upToDate) {
497501
// console.log("already invalidated", this, ...arguments);
498502
return;
@@ -502,10 +506,6 @@ class UI5Element extends HTMLElement {
502506
this._upToDate = false;
503507
// console.log("INVAL", this, ...arguments);
504508
RenderScheduler.renderDeferred(this);
505-
506-
if (this._shouldInvalidateParent) {
507-
this.parentNode._invalidate();
508-
}
509509
}
510510
}
511511

‎packages/fiori/bundle.esm.js

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import "./dist/features/CoPilotAnimation.js";
1010
import FlexibleColumnLayout from "./dist/FlexibleColumnLayout.js";
1111
import ProductSwitch from "./dist/ProductSwitch.js";
1212
import ProductSwitchItem from "./dist/ProductSwitchItem.js";
13+
import SideNavigation from "./dist/SideNavigation.js";
14+
import SideNavigationItem from "./dist/SideNavigationItem.js";
15+
import SideNavigationSubItem from "./dist/SideNavigationSubItem.js";
1316
import ShellBar from "./dist/ShellBar.js";
1417
import ShellBarItem from "./dist/ShellBarItem.js";
1518
import UploadCollection from "./dist/UploadCollection.js";

‎packages/fiori/src/SideNavigation.hbs

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<div class="ui5-sn-root">
2+
{{> header }}
3+
4+
{{#if items.length}}
5+
<ui5-tree
6+
id="ui5-sn-items-tree"
7+
mode="None"
8+
?_minimal="{{collapsed}}"
9+
_toggle-button-end
10+
@ui5-item-click="{{handleTreeItemClick}}"
11+
>
12+
{{#each _items}}
13+
<ui5-tree-item
14+
icon="{{this.item.icon}}"
15+
.associatedItem="{{this.item}}"
16+
text="{{this.item.text}}"
17+
?has-children="{{this.item.items.length}}"
18+
?expanded="{{this.item.expanded}}"
19+
?selected="{{this.selected}}"
20+
>
21+
{{#unless ../collapsed}}
22+
{{#each this.item.items}}
23+
<ui5-tree-item
24+
.associatedItem="{{this}}"
25+
text="{{this.text}}"
26+
?selected="{{this.selected}}"
27+
>
28+
</ui5-tree-item>
29+
{{/each}}
30+
{{/unless}}
31+
</ui5-tree-item>
32+
{{/each}}
33+
</ui5-tree>
34+
{{/if}}
35+
36+
<div class="ui5-sn-spacer"></div>
37+
38+
{{#if fixedItems.length}}
39+
<div>
40+
<div class="ui5-sn-bottom-content-border">
41+
<span></span>
42+
</div>
43+
<ui5-tree
44+
id="ui5-sn-fixed-items-tree"
45+
mode="None"
46+
?_minimal="{{collapsed}}"
47+
_toggle-button-end
48+
@ui5-item-click="{{handleTreeItemClick}}"
49+
>
50+
{{#each _fixedItems}}
51+
<ui5-tree-item
52+
icon="{{this.item.icon}}"
53+
.associatedItem="{{this.item}}"
54+
text="{{this.item.text}}"
55+
?has-children="{{this.item.items.length}}"
56+
?expanded="{{this.item.expanded}}"
57+
?selected="{{this.selected}}"
58+
>
59+
{{#unless ../collapsed}}
60+
{{#each this.item.items}}
61+
<ui5-tree-item
62+
.associatedItem="{{this}}"
63+
text="{{this.text}}"
64+
?selected="{{this.selected}}"
65+
>
66+
</ui5-tree-item>
67+
{{/each}}
68+
{{/unless}}
69+
</ui5-tree-item>
70+
{{/each}}
71+
</ui5-tree>
72+
</div>
73+
{{/if}}
74+
75+
{{> footer }}
76+
</div>
77+
78+
{{#*inline header}}{{/inline}}
79+
80+
{{#*inline footer}}{{/inline}}

‎packages/fiori/src/SideNavigation.js

+238
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
2+
import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
3+
import ResponsivePopover from "@ui5/webcomponents/dist/ResponsivePopover.js";
4+
import Tree from "@ui5/webcomponents/dist/Tree.js";
5+
import SideNavigationTemplate from "./generated/templates/SideNavigationTemplate.lit.js";
6+
import SideNavigationItemPopoverContentTemplate from "./generated/templates/SideNavigationItemPopoverContentTemplate.lit.js";
7+
8+
// Styles
9+
import SideNavigationCss from "./generated/themes/SideNavigation.css.js";
10+
11+
/**
12+
* @public
13+
*/
14+
const metadata = {
15+
tag: "ui5-side-navigation",
16+
managedSlots: true,
17+
properties: /** @lends sap.ui.webcomponents.fiori.SideNavigation.prototype */ {
18+
/**
19+
* Defines whether the <code>ui5-side-navigation</code> is expanded or collapsed.
20+
*
21+
* @public
22+
* @type {boolean}
23+
* @defaultvalue false
24+
*/
25+
collapsed: {
26+
type: Boolean,
27+
},
28+
29+
/**
30+
* @private
31+
*/
32+
_popoverContent: {
33+
type: Object,
34+
},
35+
},
36+
slots: /** @lends sap.ui.webcomponents.fiori.SideNavigation.prototype */ {
37+
/**
38+
* Defines the main items of the <code>ui5-side-navigation</code>. Use the <code>ui5-side-navigation-item</code> component
39+
* for the top-level items, and the <code>ui5-side-navigation-subitem</code> component for second-level items, nested
40+
* inside the items.
41+
*
42+
* @public
43+
* @slot
44+
*/
45+
"default": {
46+
propertyName: "items",
47+
invalidateParent: true,
48+
type: HTMLElement,
49+
},
50+
51+
/**
52+
* Defines the fixed items at the bottom of the <code>ui5-side-navigation</code>. Use the <code>ui5-side-navigation-item</code> component
53+
* for the fixed items, and optionally the <code>ui5-side-navigation-subitem</code> component to provide second-level items inside them.
54+
*
55+
* <b>Note:</b> In order to achieve the best user experience, it is recommended that you keep the fixed items "flat" (do not pass sub-items)
56+
*
57+
* @public
58+
* @slot
59+
*/
60+
fixedItems: {
61+
type: HTMLElement,
62+
invalidateParent: true,
63+
},
64+
},
65+
events: /** @lends sap.ui.webcomponents.fiori.SideNavigation.prototype */ {
66+
/**
67+
* Fired when the selection has changed via user interaction
68+
*
69+
* @event sap.ui.webcomponents.fiori.SideNavigation#selection-change
70+
* @param {HTMLElement} item the clicked item.
71+
* @public
72+
*/
73+
"selection-change": {
74+
item: {
75+
type: HTMLElement,
76+
},
77+
},
78+
},
79+
};
80+
81+
/**
82+
* @class
83+
*
84+
* <h3 class="comment-api-title">Overview</h3>
85+
*
86+
*
87+
* <h3>Usage</h3>
88+
*
89+
* <code>ui5-side-navigation</code> is used as a standard menu in applications. In order to add menu items use <code>ui5-side-navigation-items</code>.
90+
*
91+
* For the <code>ui5-side-navigation</code>
92+
* <h3>ES6 Module Import</h3>
93+
*
94+
* <code>import @ui5/webcomponents/dist/SideNavigation.js";</code>
95+
*
96+
* @constructor
97+
* @author SAP SE
98+
* @alias sap.ui.webcomponents.fiori.SideNavigation
99+
* @extends UI5Element
100+
* @tagname ui5-side-navigation
101+
* @since 1.0.0-rc.8
102+
* @appenddocs SideNavigationItem
103+
* @public
104+
*/
105+
class SideNavigation extends UI5Element {
106+
static get metadata() {
107+
return metadata;
108+
}
109+
110+
static get render() {
111+
return litRender;
112+
}
113+
114+
static get styles() {
115+
return SideNavigationCss;
116+
}
117+
118+
static get template() {
119+
return SideNavigationTemplate;
120+
}
121+
122+
static get staticAreaTemplate() {
123+
return SideNavigationItemPopoverContentTemplate;
124+
}
125+
126+
static async onDefine() {
127+
await Promise.all([
128+
Tree.define(),
129+
ResponsivePopover.define(),
130+
]);
131+
}
132+
133+
onBeforeRendering() {
134+
this._items = this.items.map(item => {
135+
return {
136+
item,
137+
selected: ((item.items.some(subItem => subItem.selected) && this.collapsed) || item.selected),
138+
};
139+
});
140+
141+
this._fixedItems = this.fixedItems.map(item => {
142+
return {
143+
item,
144+
selected: ((item.items.some(subItem => subItem.selected) && this.collapsed) || item.selected),
145+
};
146+
});
147+
}
148+
149+
_setSelectedItem(item) {
150+
this._walk(current => {
151+
current.selected = false;
152+
});
153+
item.selected = true;
154+
155+
this.fireEvent("selection-change", { item });
156+
}
157+
158+
_buildPopoverContent(item) {
159+
this._popoverContent = {
160+
mainItem: item,
161+
mainItemSelected: item.selected && !item.items.some(subItem => subItem.selected),
162+
subItems: item.items,
163+
};
164+
}
165+
166+
handleTreeItemClick(event) {
167+
const treeItem = event.detail.item;
168+
const item = treeItem.associatedItem;
169+
170+
if (item.selected && !this.collapsed) {
171+
return;
172+
}
173+
174+
if (this.collapsed && item.items.length) {
175+
this._buildPopoverContent(item);
176+
const currentTree = this._itemsTree === event.target ? this._itemsTree : this._fixedItemsTree;
177+
this.openPicker(currentTree._getListItemForTreeItem(treeItem));
178+
} else {
179+
this._setSelectedItem(item);
180+
}
181+
}
182+
183+
handleListItemClick(event) {
184+
const listItem = event.detail.item;
185+
const item = listItem.associatedItem;
186+
187+
if (item.selected) {
188+
return;
189+
}
190+
191+
this._setSelectedItem(item);
192+
this.closePicker();
193+
}
194+
195+
async getPicker() {
196+
return (await this.getStaticAreaItemDomRef()).querySelector("ui5-responsive-popover");
197+
}
198+
199+
async openPicker(opener) {
200+
const responsivePopover = await this.getPicker();
201+
responsivePopover.open(opener);
202+
}
203+
204+
async closePicker(opener) {
205+
const responsivePopover = await this.getPicker();
206+
responsivePopover.close();
207+
}
208+
209+
get _itemsTree() {
210+
return this.getDomRef().querySelector("#ui5-sn-items-tree");
211+
}
212+
213+
get _fixedItemsTree() {
214+
return this.getDomRef().querySelector("#ui5-sn-fixed-items-tree");
215+
}
216+
217+
_walk(callback) {
218+
this.items.forEach(current => {
219+
callback(current);
220+
221+
current.items.forEach(currentSubitem => {
222+
callback(currentSubitem);
223+
});
224+
});
225+
226+
this.fixedItems.forEach(current => {
227+
callback(current);
228+
229+
current.items.forEach(currentSubitem => {
230+
callback(currentSubitem);
231+
});
232+
});
233+
}
234+
}
235+
236+
SideNavigation.define();
237+
238+
export default SideNavigation;
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
2+
3+
/**
4+
* @public
5+
*/
6+
const metadata = {
7+
tag: "ui5-side-navigation-item",
8+
managedSlots: true,
9+
properties: /** @lends sap.ui.webcomponents.fiori.SideNavigationItem.prototype */ {
10+
/**
11+
* Defines the text of the item.
12+
*
13+
* @public
14+
* @type {string}
15+
* @defaultvalue ""
16+
*/
17+
text: {
18+
type: String,
19+
},
20+
21+
/**
22+
* Defines the icon of the item.
23+
*
24+
* @public
25+
* @type {string}
26+
* @defaultvalue ""
27+
*/
28+
icon: {
29+
type: String,
30+
},
31+
32+
/**
33+
* Defines if the item is expanded
34+
*
35+
* @public
36+
* @type {boolean}
37+
* @defaultvalue false
38+
*/
39+
expanded: {
40+
type: Boolean,
41+
},
42+
43+
/**
44+
* Defines whether the subitem is selected
45+
*
46+
* @public
47+
* @type {boolean}
48+
* @defaultvalue false
49+
*/
50+
selected: {
51+
type: Boolean,
52+
},
53+
},
54+
slots: /** @lends sap.ui.webcomponents.fiori.SideNavigationItem.prototype */ {
55+
/**
56+
* If you wish to nest menus, you can pass inner menu items to the default slot.
57+
*
58+
* @type {HTMLElement[]}
59+
* @public
60+
* @slot
61+
*/
62+
"default": {
63+
propertyName: "items",
64+
invalidateParent: true,
65+
type: HTMLElement,
66+
},
67+
},
68+
};
69+
70+
/**
71+
* @class
72+
*
73+
* <h3 class="comment-api-title">Overview</h3>
74+
*
75+
*
76+
* <h3>Usage</h3>
77+
*
78+
* <code>ui5-side-navigation-item</code> is used within <code>ui5-side-navigation</code> only. Via the <code>ui5-side-navigation-item</code> you control the content of the side navigation.
79+
* For the <code>ui5-side-navigation-item</code>
80+
* <h3>ES6 Module Import</h3>
81+
*
82+
* <code>import @ui5/webcomponents-fiori/dist/SideNavigationItem.js";</code>
83+
*
84+
* @constructor
85+
* @author SAP SE
86+
* @alias sap.ui.webcomponents.fiori.SideNavigationItem
87+
* @extends UI5Element
88+
* @tagname ui5-side-navigation-item
89+
* @public
90+
* @since 1.0.0-rc.8
91+
*/
92+
class SideNavigationItem extends UI5Element {
93+
static get metadata() {
94+
return metadata;
95+
}
96+
}
97+
98+
SideNavigationItem.define();
99+
100+
export default SideNavigationItem;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<ui5-responsive-popover
2+
vertical-align="Top"
3+
>
4+
<ui5-list
5+
mode="None"
6+
@ui5-item-click="{{handleListItemClick}}"
7+
>
8+
<ui5-li
9+
?selected="{{_popoverContent.mainItemSelected}}"
10+
.associatedItem="{{_popoverContent.mainItem}}"
11+
>{{_popoverContent.mainItem.text}}</ui5-li>
12+
13+
{{#each _popoverContent.subItems}}
14+
<ui5-li
15+
?selected="{{this.selected}}"
16+
.associatedItem="{{this}}"
17+
>{{this.text}}</ui5-li>
18+
{{/each}}
19+
</ui5-list>
20+
</ui5-responsive-popover>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
2+
3+
/**
4+
* @public
5+
*/
6+
const metadata = {
7+
tag: "ui5-side-navigation-sub-item",
8+
properties: /** @lends sap.ui.webcomponents.fiori.SideNavigationSubItem.prototype */ {
9+
/**
10+
* Defines the text of the item.
11+
*
12+
* @public
13+
* @type {string}
14+
* @defaultvalue ""
15+
*/
16+
text: {
17+
type: String,
18+
},
19+
20+
/**
21+
* Defines whether the subitem is selected
22+
*
23+
* @public
24+
* @type {boolean}
25+
* @defaultvalue false
26+
*/
27+
selected: {
28+
type: Boolean,
29+
},
30+
},
31+
};
32+
33+
/**
34+
* @class
35+
*
36+
* <h3 class="comment-api-title">Overview</h3>
37+
*
38+
*
39+
* <h3>Usage</h3>
40+
*
41+
* The <code>ui5-side-navigation-sub-item</code> is intended to be used inside a <code>ui5-side-navigation-item</code> only.
42+
*
43+
* For the <code>ui5-side-navigation-sub-item</code>
44+
* <h3>ES6 Module Import</h3>
45+
*
46+
* <code>import @ui5/webcomponents-fiori/dist/SideNavigationSubItem.js";</code>
47+
*
48+
* @constructor
49+
* @author SAP SE
50+
* @alias sap.ui.webcomponents.fiori.SideNavigationSubItem
51+
* @extends UI5Element
52+
* @tagname ui5-side-navigation-sub-item
53+
* @public
54+
* @since 1.0.0-rc.8
55+
*/
56+
class SideNavigationSubItem extends UI5Element {
57+
static get metadata() {
58+
return metadata;
59+
}
60+
}
61+
62+
SideNavigationSubItem.define();
63+
64+
export default SideNavigationSubItem;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
:host(:not([hidden])) {
2+
display: inline-block;
3+
width: 15rem;
4+
height: 100%;
5+
border-right: var(--sapList_BorderWidth) solid var(--sapList_GroupHeaderBorderColor);
6+
transition: width .25s;
7+
--_ui5-tree-toggle-box-width: 1rem;
8+
}
9+
10+
:host([collapsed]) {
11+
width: 3rem;
12+
}
13+
14+
.ui5-sn-bottom-content-border {
15+
width: 100%;
16+
padding: 0 0.5rem;
17+
margin: 0.25rem 0;
18+
display: flex;
19+
justify-content: center;
20+
box-sizing: border-box;
21+
}
22+
23+
.ui5-sn-bottom-content-border > span {
24+
width: 90%;
25+
height: .125rem;
26+
background: var(--sapList_GroupHeaderBorderColor);
27+
}
28+
29+
.ui5-sn-root {
30+
height: 100%;
31+
display: flex;
32+
flex-direction: column;
33+
background: var( --sapList_Background);
34+
}
35+
36+
.ui5-sn-spacer {
37+
flex: auto;
38+
min-height: 3rem;
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<title>Side Navigation</title>
7+
<script>
8+
delete Document.prototype.adoptedStyleSheets
9+
</script>
10+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
11+
12+
<script data-ui5-config type="application/json">
13+
{
14+
"rtl": false
15+
}
16+
</script>
17+
18+
<script src="../../webcomponentsjs/webcomponents-loader.js"></script>
19+
<script src="../../resources/bundle.esm.js" type="module"></script>
20+
<script nomodule src="../../resources/bundle.es5.js"></script>
21+
22+
<style>
23+
html, body {
24+
margin: 0;
25+
padding: 0;
26+
}
27+
28+
body {
29+
height: 100vh;
30+
display: flex;
31+
flex-direction: column;
32+
}
33+
34+
.content {
35+
height: 100%;
36+
}
37+
</style>
38+
</head>
39+
40+
<body style="background-color: var(--sapBackgroundColor);">
41+
<ui5-shellbar
42+
primary-title="UI5 Web Components"
43+
secondary-title="The Best Run SAP"
44+
show-co-pilot
45+
>
46+
<ui5-button icon="menu" slot="startButton" id="startButton"></ui5-button>
47+
</ui5-shellbar>
48+
49+
<div class="content">
50+
<ui5-side-navigation id="sn1">
51+
<ui5-side-navigation-item text="Home" icon="home" ></ui5-side-navigation-item>
52+
<ui5-side-navigation-item text="People" expanded icon="group">
53+
<ui5-side-navigation-sub-item text="From My Team" icon="employee-approvals"></ui5-side-navigation-sub-item>
54+
<ui5-side-navigation-sub-item text="From Other Teams" icon="employee-rejections"></ui5-side-navigation-sub-item>
55+
</ui5-side-navigation-item>
56+
<ui5-side-navigation-item text="Locations" icon="locate-me" selected></ui5-side-navigation-item>
57+
<ui5-side-navigation-item text="Events" icon="calendar">
58+
<ui5-side-navigation-sub-item text="Local"></ui5-side-navigation-sub-item>
59+
<ui5-side-navigation-sub-item text="Others"></ui5-side-navigation-sub-item>
60+
</ui5-side-navigation-item>
61+
62+
<ui5-side-navigation-item slot="fixedItems" text="Usefull Links" icon="chain-link">
63+
<ui5-side-navigation-sub-item text="Vacation Tool"></ui5-side-navigation-sub-item>
64+
<ui5-side-navigation-sub-item text="HR tool"></ui5-side-navigation-sub-item>
65+
</ui5-side-navigation-item>
66+
<ui5-side-navigation-item slot="fixedItems" text="History" icon="history"></ui5-side-navigation-item>
67+
</ui5-side-navigation>
68+
69+
<ui5-input id="counter" value="0"></ui5-input>
70+
</div>
71+
72+
73+
74+
75+
<script>
76+
var sideNavigation = document.querySelector("ui5-side-navigation"),
77+
input = document.querySelector("#counter"),
78+
counter = 0;
79+
document.querySelector("#startButton").addEventListener("click", function(event) {
80+
sideNavigation.collapsed = !sideNavigation.collapsed;
81+
});
82+
83+
sideNavigation.addEventListener("ui5-selection-change", function() {
84+
input.value = ++counter;
85+
});
86+
87+
</script>
88+
</body>
89+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<header class="component-heading">
2+
<h2 class="control-header">Side Navigation</h2>
3+
<div class="component-heading-since">
4+
<span><!--since_tag_marker--></span>
5+
</div>
6+
</header>
7+
8+
<div class="component-package">@ui5/webcomponents</div>
9+
10+
<div class="control-tag">&lt;ui5-side-navigation&gt;</div>
11+
12+
<section>
13+
<h3>Side Navigation in Application</h3>
14+
<div class="snippet" style="height: 40rem;">
15+
<ui5-shellbar primary-title="UI5 Web Components" secondary-title="The Best Run SAP" show-co-pilot
16+
>
17+
<ui5-button icon="menu" slot="startButton" id="startButton"></ui5-button>
18+
</ui5-shellbar>
19+
20+
<ui5-side-navigation>
21+
<ui5-side-navigation-item text="Home" icon="home"></ui5-side-navigation-item>
22+
<ui5-side-navigation-item text="People" expanded icon="group">
23+
<ui5-side-navigation-sub-item text="From My Team" icon="employee-approvals"></ui5-side-navigation-sub-item>
24+
<ui5-side-navigation-sub-item text="From Other Teams" icon="employee-rejections"></ui5-side-navigation-sub-item>
25+
</ui5-side-navigation-item>
26+
<ui5-side-navigation-item text="Locations" icon="locate-me" selected></ui5-side-navigation-item>
27+
<ui5-side-navigation-item text="Events" icon="calendar">
28+
<ui5-side-navigation-sub-item text="Local"></ui5-side-navigation-sub-item>
29+
<ui5-side-navigation-sub-item text="Others"></ui5-side-navigation-sub-item>
30+
</ui5-side-navigation-item>
31+
32+
<ui5-side-navigation-item slot="fixedItems" text="Useful Links" icon="chain-link"></ui5-side-navigation-item>
33+
<ui5-side-navigation-item slot="fixedItems" text="History" icon="history"></ui5-side-navigation-item>
34+
</ui5-side-navigation>
35+
36+
<script>
37+
var sideNavigation = document.querySelector("ui5-side-navigation");
38+
document.querySelector("#startButton").addEventListener("click", function(event) {
39+
sideNavigation.collapsed = !sideNavigation.collapsed;
40+
});
41+
</script>
42+
</div>
43+
<pre class="prettyprint lang-html"><xmp>
44+
<ui5-shellbar
45+
primary-title="UI5 Web Components"
46+
secondary-title="The Best Run SAP"
47+
show-co-pilot
48+
>
49+
<ui5-button icon="menu" slot="startButton" id="startButton"></ui5-button>
50+
</ui5-shellbar>
51+
52+
<ui5-side-navigation>
53+
<ui5-side-navigation-item text="Home" icon="home"></ui5-side-navigation-item>
54+
<ui5-side-navigation-item text="People" expanded icon="group">
55+
<ui5-side-navigation-sub-item text="From My Team" icon="employee-approvals"></ui5-side-navigation-sub-item>
56+
<ui5-side-navigation-sub-item text="From Other Teams" icon="employee-rejections"></ui5-side-navigation-sub-item>
57+
</ui5-side-navigation-item>
58+
<ui5-side-navigation-item text="Locations" icon="locate-me" selected></ui5-side-navigation-item>
59+
<ui5-side-navigation-item text="Events" icon="calendar">
60+
<ui5-side-navigation-sub-item text="Local"></ui5-side-navigation-sub-item>
61+
<ui5-side-navigation-sub-item text="Others"></ui5-side-navigation-sub-item>
62+
</ui5-side-navigation-item>
63+
64+
<ui5-side-navigation-item slot="fixedItems" text="Useful Links" icon="chain-link"></ui5-side-navigation-item>
65+
<ui5-side-navigation-item slot="fixedItems" text="History" icon="history"></ui5-side-navigation-item>
66+
</ui5-side-navigation>
67+
68+
<script>
69+
const sideNavigation = document.querySelector("ui5-side-navigation");
70+
document.querySelector("#startButton").addEventListener("click", event => sideNavigation.collapsed = !sideNavigation.collapsed);
71+
</script>
72+
</xmp></pre>
73+
</section>
74+
75+
76+
77+
<!-- JSDoc marker -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
2+
const assert = require("chai").assert;
3+
4+
describe("Component Behavior", () => {
5+
browser.url("http://localhost:8081/test-resources/pages/SideNavigation.html");
6+
7+
describe("Main functionality", () => {
8+
it("Tests selection-change event", () => {
9+
const input = browser.$("#counter");
10+
const sideNavigation = browser.$("ui5-side-navigation");
11+
let items = sideNavigation.shadow$("ui5-tree").shadow$("ui5-list").$$("ui5-li-tree");
12+
const fixedItems = sideNavigation.shadow$$("ui5-tree")[1].shadow$("ui5-list").$$("ui5-li-tree");
13+
14+
items[0].click();
15+
items[3].click();
16+
17+
assert.strictEqual(input.getProperty("value"), "2", "Event is fired");
18+
19+
fixedItems[0].click();
20+
21+
assert.strictEqual(input.getProperty("value"), "3", "Event is fired");
22+
23+
sideNavigation.setAttribute("collapsed", "true");
24+
items = sideNavigation.shadow$("ui5-tree").shadow$("ui5-list").$$("ui5-li-tree");
25+
26+
items[0].click();
27+
28+
assert.strictEqual(input.getProperty("value"), "4", "Event is fired");
29+
30+
items[1].click();
31+
32+
assert.strictEqual(input.getProperty("value"), "4", "Event is not fired");
33+
34+
const staticAreaItemClassName = browser.getStaticAreaItemClassName("#sn1");
35+
const popover = browser.$(`.${staticAreaItemClassName}`).shadow$("ui5-responsive-popover");
36+
items = popover.$("ui5-list").$$("ui5-li");
37+
38+
items[1].click();
39+
40+
assert.strictEqual(input.getProperty("value"), "5", "Event is fired");
41+
})
42+
});
43+
});

‎packages/main/src/Tree.hbs

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
type="Active"
1515
level="{{this.level}}"
1616
icon="{{this.treeItem.icon}}"
17+
?_toggle-button-end="{{../_toggleButtonEnd}}"
18+
?_minimal="{{../_minimal}}"
1719
.treeItem="{{this.treeItem}}"
1820
.expanded="{{this.treeItem.expanded}}"
1921
.selected="{{this.treeItem.selected}}"

‎packages/main/src/Tree.js

+30
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,26 @@ const metadata = {
7777
type: Object,
7878
multiple: true,
7979
},
80+
81+
/**
82+
* Shows the toggle button at the end, rather than at the beginning of the items
83+
*
84+
* @protected
85+
* @since 1.0.0-rc.8
86+
*/
87+
_toggleButtonEnd: {
88+
type: Boolean,
89+
},
90+
91+
/**
92+
* Represents the tree in a very minimal state - icons only with no text and no toggle buttons
93+
*
94+
* @protected
95+
* @since 1.0.0-rc.8
96+
*/
97+
_minimal: {
98+
type: Boolean,
99+
},
80100
},
81101
managedSlots: true,
82102
slots: /** @lends sap.ui.webcomponents.main.Tree.prototype */ {
@@ -318,6 +338,16 @@ class Tree extends UI5Element {
318338
});
319339
}
320340

341+
/**
342+
* Returns the corresponding list item for a given tree item
343+
*
344+
* @param item The tree item
345+
* @protected
346+
*/
347+
_getListItemForTreeItem(item) {
348+
return this.list.items.find(listItem => listItem.treeItem === item);
349+
}
350+
321351
/**
322352
* Perform Depth-First-Search walk on the tree and run a callback on each node
323353
*

‎packages/main/src/TreeListItem.hbs

+11-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
{{#*inline "listItemPreContent"}}
44
<div class="ui5-li-tree-toggle-box" style="padding-left: {{effectiveLevel}}rem; padding-left: calc(var(--_ui5-tree-indent-step) * {{effectiveLevel}});">
5-
{{#if showToggleButton}}
5+
{{#if _showToggleButtonBeginning}}
66
<ui5-icon
77
class="ui5-li-tree-toggle-icon"
88
name="{{_toggleIconName}}"
@@ -13,7 +13,7 @@
1313
{{/inline}}
1414

1515
{{#*inline "listItemContent"}}
16-
{{#if textContent.length}}
16+
{{#if _showTitle}}
1717
<div part="title" class="ui5-li-title"><slot></slot></div>
1818
{{/if}}
1919
{{/inline}}
@@ -26,4 +26,12 @@
2626
{{/if}}
2727
{{/inline}}
2828

29-
{{#*inline "iconEnd"}}{{/inline}}
29+
{{#*inline "iconEnd"}}
30+
{{#if _showToggleButtonEnd}}
31+
<ui5-icon
32+
class="ui5-li-tree-toggle-icon"
33+
name="{{_toggleIconName}}"
34+
@click="{{_toggleClick}}"
35+
></ui5-icon>
36+
{{/if}}
37+
{{/inline}}

‎packages/main/src/TreeListItem.js

+33
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,27 @@ const metadata = {
6262
expanded: {
6363
type: Boolean,
6464
},
65+
66+
/**
67+
* Defines whether the toggle button is shown at the end, rather than at the beginning of the item
68+
*
69+
* @protected
70+
* @since 1.0.0-rc.8
71+
*/
72+
_toggleButtonEnd: {
73+
type: Boolean,
74+
},
75+
76+
/**
77+
* Defines whether the item shows minimal details - only icon (no text or toggle button)
78+
*
79+
* @protected
80+
* @since 1.0.0-rc.8
81+
*/
82+
_minimal: {
83+
type: Boolean,
84+
},
85+
6586
},
6687
slots: /** @lends sap.ui.webcomponents.main.TreeListItem.prototype */ {
6788
/**
@@ -173,6 +194,18 @@ class TreeListItem extends ListItem {
173194
return this.expanded ? "navigation-down-arrow" : "navigation-right-arrow";
174195
}
175196

197+
get _showToggleButtonBeginning() {
198+
return this.showToggleButton && !this._minimal && !this._toggleButtonEnd;
199+
}
200+
201+
get _showToggleButtonEnd() {
202+
return this.showToggleButton && !this._minimal && this._toggleButtonEnd;
203+
}
204+
205+
get _showTitle() {
206+
return this.textContent.length && !this._minimal;
207+
}
208+
176209
get _accInfo() {
177210
return {
178211
role: "treeitem",

‎packages/main/src/themes/Title.css

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
:host(:not([hidden])) {
22
display: block;
3+
cursor: text;
34
}
45

56
:host {
@@ -24,7 +25,7 @@
2425
-webkit-margin-start: 0;
2526
-webkit-margin-end: 0;
2627
margin: 0;
27-
cursor: text;
28+
cursor: inherit;
2829
}
2930

3031
:host([wrap]) .ui5-title-root {

‎packages/main/src/themes/TreeListItem.css

+48-2
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,66 @@
11
:host(:not([hidden])) {
22
display: block;
3-
cursor: pointer;
3+
cursor: pointer;
4+
position: relative;
5+
}
6+
7+
:host([_minimal]) .ui5-li-tree-toggle-box {
8+
width: 0;
9+
}
10+
11+
:host([_minimal]) .ui5-li-icon {
12+
padding: 0;
13+
}
14+
15+
:host([_minimal]) .ui5-li-content {
16+
justify-content: center;
17+
}
18+
19+
:host([_minimal]) .ui5-li-root-tree {
20+
padding: 0;
21+
}
22+
23+
:host([_minimal][show-toggle-button])::after {
24+
content: "";
25+
width: 0;
26+
height: 0;
27+
border-left: 0.375rem solid transparent;
28+
border-bottom: .375rem solid var(--sapContent_IconColor);
29+
position: absolute;
30+
right: 0.1875rem;
31+
bottom: 0.125rem;
432
}
533

634
.ui5-li-root-tree {
735
padding-left: 0;
836
}
937

38+
:host([selected][has-border]:not([level="1"])),
1039
:host(:not([level="1"])) {
11-
border-bottom: none !important;
40+
border-bottom: none;
41+
}
42+
43+
:host([_toggle-button-end][selected]:not([level="1"])){
44+
border-bottom: var(--ui5-listitem-selected-border-bottom);
45+
}
46+
47+
:host([_toggle-button-end]:not([selected])) .ui5-li-root-tree:hover {
48+
background: var(--sapList_Hover_Background);
49+
cursor: pointer;
1250
}
1351

1452
:host(:not([level="1"])) .ui5-li-root-tree {
1553
background: var(--sapList_AlternatingBackground);
1654
}
1755

56+
:host([_toggle-button-end]:not([level="1"])) .ui5-li-root-tree {
57+
background: var(--ui5-listitem-background-color);
58+
}
59+
60+
:host([_toggle-button-end][selected]:not([level="1"])) .ui5-li-root-tree {
61+
background: var(--sapList_SelectionBackgroundColor);
62+
}
63+
1864
.ui5-li-tree-toggle-box {
1965
width: var(--_ui5-tree-toggle-box-width);
2066
height: var(--_ui5-tree-toggle-box-height);

‎packages/main/src/themes/base/sizes-parameters.css

+6
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@
6161
/* Responsive Popover */
6262
--_ui5-responnsive_popover_header_height: 2.75rem;
6363

64+
/* Side Navigation */
65+
--ui5_side_navigation_item_height: 2.75rem;
66+
6467
/* Tree */
6568
--_ui5-tree-indent-step: 1.5rem;
6669
--_ui5-tree-toggle-box-width: 2.75rem;
@@ -183,6 +186,9 @@
183186
/* Responsive Popover */
184187
--_ui5-responnsive_popover_header_height: 2.5rem;
185188

189+
/* Side Navigation */
190+
--ui5_side_navigation_item_height: 2rem;
191+
186192
/* Tree */
187193
--_ui5-tree-indent-step: 0.5rem;
188194
--_ui5-tree-toggle-box-width: 2rem;

‎packages/playground/build-scripts/samples-prepare.js

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const newComponents = [
2020
"UploadCollection",
2121
"Tree",
2222
"RatingIndicator",
23+
"SideNavigation",
2324
"ProgressIndicator",
2425
];
2526

‎packages/theme-base/css-vars-usage.json

+1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@
156156
"--sapList_AlternatingBackground",
157157
"--sapList_Background",
158158
"--sapList_BorderColor",
159+
"--sapList_BorderWidth",
159160
"--sapList_FooterBackground",
160161
"--sapList_FooterTextColor",
161162
"--sapList_GroupHeaderBackground",

0 commit comments

Comments
 (0)
Please sign in to comment.