Skip to content

Commit

Permalink
feat(ui5-side-navigation): initial implementation (#1889)
Browse files Browse the repository at this point in the history
  • Loading branch information
fifoosid authored Jul 23, 2020
1 parent a7488cd commit 47b38cc
Show file tree
Hide file tree
Showing 20 changed files with 891 additions and 10 deletions.
8 changes: 4 additions & 4 deletions packages/base/src/UI5Element.js
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,10 @@ class UI5Element extends HTMLElement {
* @private
*/
_invalidate() {
if (this._shouldInvalidateParent) {
this.parentNode._invalidate();
}

if (!this._upToDate) {
// console.log("already invalidated", this, ...arguments);
return;
Expand All @@ -502,10 +506,6 @@ class UI5Element extends HTMLElement {
this._upToDate = false;
// console.log("INVAL", this, ...arguments);
RenderScheduler.renderDeferred(this);

if (this._shouldInvalidateParent) {
this.parentNode._invalidate();
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions packages/fiori/bundle.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import "./dist/features/CoPilotAnimation.js";
import FlexibleColumnLayout from "./dist/FlexibleColumnLayout.js";
import ProductSwitch from "./dist/ProductSwitch.js";
import ProductSwitchItem from "./dist/ProductSwitchItem.js";
import SideNavigation from "./dist/SideNavigation.js";
import SideNavigationItem from "./dist/SideNavigationItem.js";
import SideNavigationSubItem from "./dist/SideNavigationSubItem.js";
import ShellBar from "./dist/ShellBar.js";
import ShellBarItem from "./dist/ShellBarItem.js";
import UploadCollection from "./dist/UploadCollection.js";
Expand Down
80 changes: 80 additions & 0 deletions packages/fiori/src/SideNavigation.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<div class="ui5-sn-root">
{{> header }}

{{#if items.length}}
<ui5-tree
id="ui5-sn-items-tree"
mode="None"
?_minimal="{{collapsed}}"
_toggle-button-end
@ui5-item-click="{{handleTreeItemClick}}"
>
{{#each _items}}
<ui5-tree-item
icon="{{this.item.icon}}"
.associatedItem="{{this.item}}"
text="{{this.item.text}}"
?has-children="{{this.item.items.length}}"
?expanded="{{this.item.expanded}}"
?selected="{{this.selected}}"
>
{{#unless ../collapsed}}
{{#each this.item.items}}
<ui5-tree-item
.associatedItem="{{this}}"
text="{{this.text}}"
?selected="{{this.selected}}"
>
</ui5-tree-item>
{{/each}}
{{/unless}}
</ui5-tree-item>
{{/each}}
</ui5-tree>
{{/if}}

<div class="ui5-sn-spacer"></div>

{{#if fixedItems.length}}
<div>
<div class="ui5-sn-bottom-content-border">
<span></span>
</div>
<ui5-tree
id="ui5-sn-fixed-items-tree"
mode="None"
?_minimal="{{collapsed}}"
_toggle-button-end
@ui5-item-click="{{handleTreeItemClick}}"
>
{{#each _fixedItems}}
<ui5-tree-item
icon="{{this.item.icon}}"
.associatedItem="{{this.item}}"
text="{{this.item.text}}"
?has-children="{{this.item.items.length}}"
?expanded="{{this.item.expanded}}"
?selected="{{this.selected}}"
>
{{#unless ../collapsed}}
{{#each this.item.items}}
<ui5-tree-item
.associatedItem="{{this}}"
text="{{this.text}}"
?selected="{{this.selected}}"
>
</ui5-tree-item>
{{/each}}
{{/unless}}
</ui5-tree-item>
{{/each}}
</ui5-tree>
</div>
{{/if}}

{{> footer }}
</div>

{{#*inline header}}{{/inline}}

{{#*inline footer}}{{/inline}}
238 changes: 238 additions & 0 deletions packages/fiori/src/SideNavigation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
import ResponsivePopover from "@ui5/webcomponents/dist/ResponsivePopover.js";
import Tree from "@ui5/webcomponents/dist/Tree.js";
import SideNavigationTemplate from "./generated/templates/SideNavigationTemplate.lit.js";
import SideNavigationItemPopoverContentTemplate from "./generated/templates/SideNavigationItemPopoverContentTemplate.lit.js";

// Styles
import SideNavigationCss from "./generated/themes/SideNavigation.css.js";

/**
* @public
*/
const metadata = {
tag: "ui5-side-navigation",
managedSlots: true,
properties: /** @lends sap.ui.webcomponents.fiori.SideNavigation.prototype */ {
/**
* Defines whether the <code>ui5-side-navigation</code> is expanded or collapsed.
*
* @public
* @type {boolean}
* @defaultvalue false
*/
collapsed: {
type: Boolean,
},

/**
* @private
*/
_popoverContent: {
type: Object,
},
},
slots: /** @lends sap.ui.webcomponents.fiori.SideNavigation.prototype */ {
/**
* Defines the main items of the <code>ui5-side-navigation</code>. Use the <code>ui5-side-navigation-item</code> component
* for the top-level items, and the <code>ui5-side-navigation-subitem</code> component for second-level items, nested
* inside the items.
*
* @public
* @slot
*/
"default": {
propertyName: "items",
invalidateParent: true,
type: HTMLElement,
},

/**
* Defines the fixed items at the bottom of the <code>ui5-side-navigation</code>. Use the <code>ui5-side-navigation-item</code> component
* for the fixed items, and optionally the <code>ui5-side-navigation-subitem</code> component to provide second-level items inside them.
*
* <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)
*
* @public
* @slot
*/
fixedItems: {
type: HTMLElement,
invalidateParent: true,
},
},
events: /** @lends sap.ui.webcomponents.fiori.SideNavigation.prototype */ {
/**
* Fired when the selection has changed via user interaction
*
* @event sap.ui.webcomponents.fiori.SideNavigation#selection-change
* @param {HTMLElement} item the clicked item.
* @public
*/
"selection-change": {
item: {
type: HTMLElement,
},
},
},
};

/**
* @class
*
* <h3 class="comment-api-title">Overview</h3>
*
*
* <h3>Usage</h3>
*
* <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>.
*
* For the <code>ui5-side-navigation</code>
* <h3>ES6 Module Import</h3>
*
* <code>import @ui5/webcomponents/dist/SideNavigation.js";</code>
*
* @constructor
* @author SAP SE
* @alias sap.ui.webcomponents.fiori.SideNavigation
* @extends UI5Element
* @tagname ui5-side-navigation
* @since 1.0.0-rc.8
* @appenddocs SideNavigationItem
* @public
*/
class SideNavigation extends UI5Element {
static get metadata() {
return metadata;
}

static get render() {
return litRender;
}

static get styles() {
return SideNavigationCss;
}

static get template() {
return SideNavigationTemplate;
}

static get staticAreaTemplate() {
return SideNavigationItemPopoverContentTemplate;
}

static async onDefine() {
await Promise.all([
Tree.define(),
ResponsivePopover.define(),
]);
}

onBeforeRendering() {
this._items = this.items.map(item => {
return {
item,
selected: ((item.items.some(subItem => subItem.selected) && this.collapsed) || item.selected),
};
});

this._fixedItems = this.fixedItems.map(item => {
return {
item,
selected: ((item.items.some(subItem => subItem.selected) && this.collapsed) || item.selected),
};
});
}

_setSelectedItem(item) {
this._walk(current => {
current.selected = false;
});
item.selected = true;

this.fireEvent("selection-change", { item });
}

_buildPopoverContent(item) {
this._popoverContent = {
mainItem: item,
mainItemSelected: item.selected && !item.items.some(subItem => subItem.selected),
subItems: item.items,
};
}

handleTreeItemClick(event) {
const treeItem = event.detail.item;
const item = treeItem.associatedItem;

if (item.selected && !this.collapsed) {
return;
}

if (this.collapsed && item.items.length) {
this._buildPopoverContent(item);
const currentTree = this._itemsTree === event.target ? this._itemsTree : this._fixedItemsTree;
this.openPicker(currentTree._getListItemForTreeItem(treeItem));
} else {
this._setSelectedItem(item);
}
}

handleListItemClick(event) {
const listItem = event.detail.item;
const item = listItem.associatedItem;

if (item.selected) {
return;
}

this._setSelectedItem(item);
this.closePicker();
}

async getPicker() {
return (await this.getStaticAreaItemDomRef()).querySelector("ui5-responsive-popover");
}

async openPicker(opener) {
const responsivePopover = await this.getPicker();
responsivePopover.open(opener);
}

async closePicker(opener) {
const responsivePopover = await this.getPicker();
responsivePopover.close();
}

get _itemsTree() {
return this.getDomRef().querySelector("#ui5-sn-items-tree");
}

get _fixedItemsTree() {
return this.getDomRef().querySelector("#ui5-sn-fixed-items-tree");
}

_walk(callback) {
this.items.forEach(current => {
callback(current);

current.items.forEach(currentSubitem => {
callback(currentSubitem);
});
});

this.fixedItems.forEach(current => {
callback(current);

current.items.forEach(currentSubitem => {
callback(currentSubitem);
});
});
}
}

SideNavigation.define();

export default SideNavigation;
Loading

0 comments on commit 47b38cc

Please sign in to comment.