forked from SAP/ui5-webcomponents
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ui5-breadcrumbs): Initial implementation (SAP#3166)
- Loading branch information
Showing
7 changed files
with
517 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<nav class="ui5-breadcrumbs-root"> | ||
<ol class="ui5-breadcrumbs-ol"> | ||
|
||
<li class="{{overflowClasses}}"> | ||
<ui5-link @click="{{_toggleRespPopover}}"> | ||
<span>..</span> | ||
<ui5-icon | ||
name="slim-arrow-down" | ||
show-tooltip | ||
accessible-name={{overflowMenuTitle}}></ui5-icon> | ||
</ui5-link> | ||
</li> | ||
|
||
{{#each visibleLinks}} | ||
<li class="ui5-breadcrumbs-link" onclick="this.getRootNode().host._onLinkClick(event)"> | ||
<slot name="{{this._individualSlot}}"></slot> | ||
</li> | ||
{{/each}} | ||
<li class="ui5-breadcrumbs-current"> | ||
<span>{{currentLocation}}</span> | ||
</li> | ||
</ol> | ||
</nav> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,297 @@ | ||
import ItemNavigation from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js"; | ||
import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; | ||
import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; | ||
import NavigationMode from "@ui5/webcomponents-base/dist/types/NavigationMode.js"; | ||
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; | ||
import BreadcrumbsSeparatorStyle from "./types/BreadcrumbsSeparatorStyle.js"; | ||
|
||
// Template | ||
import BreadcrumbsTemplate from "./generated/templates/BreadcrumbsTemplate.lit.js"; | ||
import BreadcrumbsPopoverTemplate from "./generated/templates/BreadcrumbsPopoverTemplate.lit.js"; | ||
|
||
// Styles | ||
import breadcrumbsCss from "./generated/themes/Breadcrumbs.css.js"; | ||
|
||
|
||
/** | ||
* @public | ||
*/ | ||
const metadata = { | ||
tag: "ui5-breadcrumbs", | ||
managedSlots: true, | ||
slots: /** @lends sap.ui.webcomponents.main.Breadcrumbs.prototype */ { | ||
|
||
|
||
/** | ||
* Defines the links of the <code>ui5-breadcrumbs</code>. | ||
* <br><br> | ||
* <b>Note:</b> Use <code>ui5-link</code>. // TODO if precise type can be given in metadata | ||
* | ||
* @type {HTMLElement[]} | ||
* @slot | ||
* @public | ||
*/ | ||
"default": { | ||
propertyName: "links", | ||
type: HTMLElement, | ||
individualSlots: true, | ||
}, | ||
}, | ||
properties: /** @lends sap.ui.webcomponents.main.Breadcrumbs.prototype */ { | ||
|
||
/** | ||
* Defines the <code>ui5-breadcrumbs</code> current location text. | ||
* | ||
* @type {string} | ||
* @defaultvalue "" | ||
* @public | ||
*/ | ||
currentLocation: { | ||
type: String, | ||
}, | ||
|
||
/** | ||
* Determines the visual style of the separator between the Breadcrumbs elements. | ||
* | ||
* @type {BreadcrumbsSeparatorStyle} | ||
* @defaultvalue "Slash" | ||
* @public | ||
*/ | ||
separatorStyle: { | ||
type: BreadcrumbsSeparatorStyle, | ||
defaultValue: BreadcrumbsSeparatorStyle.Slash, | ||
}, | ||
|
||
_overflowLength: { | ||
type: String, | ||
noAttribute: true, | ||
} | ||
|
||
}, | ||
events: /** @lends sap.ui.webcomponents.main.Breadcrumbs.prototype */ { | ||
|
||
/** | ||
* Fired when a link is activated. | ||
* | ||
* @event sap.ui.webcomponents.main.Breadcrumbs#item-click | ||
* @param {HTMLElement} item The clicked item. | ||
* @public | ||
*/ | ||
"link-click": { | ||
detail: { | ||
link: { type: HTMLElement }, | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
/** | ||
* @class | ||
* | ||
* <h3 class="comment-api-title">Overview</h3> | ||
* | ||
* | ||
* @constructor | ||
* @author SAP SE | ||
* @alias sap.ui.webcomponents.main.Breadcrumbs | ||
* @extends UI5Element | ||
* @tagname ui5-breadcrumbs | ||
* @public | ||
*/ | ||
class Breadcrumbs extends UI5Element { | ||
static get metadata() { | ||
return metadata; | ||
} | ||
|
||
static get render() { | ||
return litRender; | ||
} | ||
|
||
static get template() { | ||
return BreadcrumbsTemplate; | ||
} | ||
|
||
static get staticAreaTemplate() { | ||
return BreadcrumbsPopoverTemplate; | ||
} | ||
|
||
static get styles() { | ||
return breadcrumbsCss; | ||
} | ||
|
||
constructor() { | ||
super(); | ||
this.initItemNavigation(); | ||
|
||
this._onResizeHandler = this._onResize.bind(this); | ||
this._onContentResizeHandler = this._onContentResize.bind(this); | ||
|
||
this.widthsCache = null; | ||
} | ||
|
||
get hasData() { | ||
return this.getSlottedNodes("items").length !== 0; | ||
} | ||
|
||
onBeforeRendering() { | ||
this._olDOM && ResizeHandler.deregister(this._olDOM, this._onContentResizeHandler); | ||
} | ||
|
||
onAfterRendering() { | ||
this._cacheWidths(); | ||
this._applyLayout(); | ||
this._olDOM = this.shadowRoot.querySelector(".ui5-breadcrumbs-ol"); | ||
ResizeHandler.register(this._olDOM, this._onContentResizeHandler); | ||
} | ||
|
||
onEnterDOM() { | ||
ResizeHandler.register(this, this._onResizeHandler); | ||
} | ||
|
||
onExitDOM() { | ||
ResizeHandler.deregister(this, this._onResizeHandler); | ||
} | ||
|
||
initItemNavigation() { | ||
this._itemNavigation = new ItemNavigation(this, { | ||
navigationMode: NavigationMode.Horizontal, | ||
getItemsCallback: () => this.getSlottedNodes("links"), | ||
}); | ||
} | ||
|
||
onInvalidation(changeInfo) { | ||
console.log(changeInfo); | ||
} | ||
|
||
get shouldShowOverflow() { | ||
return Number(this._overflowLength) > 0; | ||
} | ||
|
||
get overflowMenuTitle() { | ||
return "More"; | ||
} | ||
|
||
_onResize() { | ||
this._applyLayout(); | ||
} | ||
|
||
_onContentResize() { | ||
this._cacheWidths(); | ||
this._applyLayout(); | ||
} | ||
|
||
_cacheWidths() { | ||
if (!this.widthsCache) { | ||
this.widthsCache = new WeakMap(); | ||
} | ||
let map = this.widthsCache; | ||
const linkItems = this.shadowRoot.querySelectorAll(".ui5-breadcrumbs-link"); | ||
|
||
for(let i = 0; i< linkItems.length; i++) { | ||
let link = linkItems[i].querySelector("slot").assignedElements()[0]; | ||
map.set(link, linkItems[i].offsetWidth); | ||
} | ||
|
||
if (!this._overflowItemWith) { | ||
const overflow = this.shadowRoot.querySelector(".ui5-breadcrumbs-overflow"); | ||
overflow.classList.toggle("hidden", false); | ||
this._overflowItemWith = overflow.clientWidth; | ||
overflow.classList.toggle("hidden", true); | ||
} | ||
} | ||
|
||
_applyLayout() { | ||
let iAvailableWidth = this.shadowRoot.querySelector("nav").offsetWidth, | ||
nonOverflowingContentWidth, | ||
links, | ||
newOverflowLength; | ||
|
||
if (iAvailableWidth === 0) { | ||
return; | ||
} | ||
|
||
nonOverflowingContentWidth = this.shadowRoot.querySelector(".ui5-breadcrumbs-current").clientWidth + this._overflowItemWith; | ||
links = this.getSlottedNodes("links").reverse(); | ||
newOverflowLength = links.length; | ||
|
||
for(let i = 0; i < links.length ; i++) { | ||
let link = links[i], | ||
linkWidth = this.widthsCache.get(link) || 0; | ||
nonOverflowingContentWidth += linkWidth; | ||
if (nonOverflowingContentWidth > iAvailableWidth) { | ||
break; | ||
} | ||
newOverflowLength--; | ||
if (newOverflowLength === 1) { | ||
nonOverflowingContentWidth -= this._overflowItemWith; | ||
} | ||
} | ||
|
||
this._overflowLength = String(newOverflowLength); | ||
} | ||
|
||
get _isPickerOpen() { | ||
return !!this.responsivePopover && this.responsivePopover.opened; | ||
} | ||
|
||
async _respPopover() { | ||
const staticAreaItem = await this.getStaticAreaItemDomRef(); | ||
return staticAreaItem.querySelector("[ui5-responsive-popover]"); | ||
} | ||
|
||
async _toggleRespPopover() { | ||
this._iconPressed = true; | ||
this.responsivePopover = await this._respPopover(); | ||
|
||
if (this._isPickerOpen) { | ||
this.responsivePopover.close(); | ||
} else { | ||
this.responsivePopover.open(this); | ||
} | ||
} | ||
|
||
_onLinkClick(event) { | ||
let link = event.target; | ||
this.fireEvent("link-click", {link}); | ||
} | ||
|
||
_getSelectedItemIndex(item) { | ||
return [].indexOf.call(item.parentElement.children, item); | ||
} | ||
|
||
_onOverflowListItemSelect(event) { | ||
const item = event.detail.item; | ||
const selectedItemIndex = this._getSelectedItemIndex(item); | ||
const selectedLink = this.getSlottedNodes("links")[selectedItemIndex]; | ||
window.open(selectedLink.href, selectedLink.target || "_blank"); | ||
console.log(selectedLink.href); | ||
this._toggleRespPopover(); | ||
this.fireEvent("link-click", {link: selectedLink}); | ||
} | ||
|
||
get visibleLinks() { | ||
let overflowLength = Number(this._overflowLength) || 0; | ||
return this.getSlottedNodes("links") | ||
.slice(Number(overflowLength)); | ||
} | ||
|
||
get overflowingLinks() { | ||
let overflowLength = Number(this._overflowLength) || 0; | ||
return this.getSlottedNodes("links").slice(0, overflowLength).reverse(); | ||
} | ||
get overflowClasses() { | ||
let classes = "ui5-breadcrumbs-overflow"; | ||
if (!this.shouldShowOverflow) { | ||
classes += " hidden"; | ||
} | ||
return classes; | ||
} | ||
|
||
static get dependencies() { | ||
return []; | ||
} | ||
} | ||
|
||
Breadcrumbs.define(); | ||
|
||
export default Breadcrumbs; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<ui5-responsive-popover | ||
id="{{_id}}-overflowMenu" | ||
horizontal-align="Right" | ||
placement-type="Bottom" | ||
content-only-on-desktop | ||
with-padding | ||
no-arrow | ||
_hide-header> | ||
<ui5-list @ui5-item-press="{{_onOverflowListItemSelect}}"> | ||
{{#each overflowingLinks}} | ||
<ui5-li | ||
id="{{this.id}}-li"> | ||
{{this.textContent}} | ||
</ui5-li> | ||
{{/each}} | ||
</ui5-list> | ||
<div slot="footer" class="ui5-responsive-popover-footer"> | ||
<ui5-button | ||
design="Transparent" | ||
@click="{{_toggleRespPopover}}" | ||
>Cancel</ui5-button> | ||
</div> | ||
</ui5-responsive-popover> |
Oops, something went wrong.