@synergy-design-system/components
Version:
This package provides the base of the Synergy Design System as native web components. It uses [lit](https://www.lit.dev) and parts of [shoelace](https://shoelace.style/). Synergy officially supports the latest two versions of all major browsers (as define
213 lines (208 loc) • 6.46 kB
JavaScript
import {
filterOnlyNavItems,
getAssignedElementsForSlot,
hideNavigationItem,
showNavigationItem
} from "./chunk.OJ3N7TWP.js";
import {
prio_nav_styles_default
} from "./chunk.74N5WLM5.js";
import {
SynNavItem
} from "./chunk.VI5FLXBL.js";
import {
SynMenu
} from "./chunk.2UFVMHUX.js";
import {
SynDropdown
} from "./chunk.L5NLWYJZ.js";
import {
SynIcon
} from "./chunk.RCBSMXQH.js";
import {
LocalizeController
} from "./chunk.OAQRCZOO.js";
import {
component_styles_default
} from "./chunk.NLYVOJGK.js";
import {
SynergyElement
} from "./chunk.3THJTCRO.js";
import {
__decorateClass
} from "./chunk.Z4XV3SMG.js";
// src/components/prio-nav/prio-nav.component.ts
import { classMap } from "lit/directives/class-map.js";
import { html } from "lit/static-html.js";
import { query, state } from "lit/decorators.js";
var SynPrioNav = class extends SynergyElement {
constructor() {
super(...arguments);
this.localize = new LocalizeController(this);
this.itemPositionsCached = false;
this.amountOfNavItems = 0;
this.amountOfVisibleItems = 0;
this.hasItemsInDropdown = false;
}
/**
* Get a list of all slotted `<syn-nav-item />` elements
* that are either in the main slot or the priority menu slot
*/
getSlottedNavItems() {
const navItemsInDefaultSlot = filterOnlyNavItems(getAssignedElementsForSlot(this.defaultSlot));
const navItemsInMenuSlot = filterOnlyNavItems(getAssignedElementsForSlot(this.menuSlot));
return navItemsInDefaultSlot.concat(navItemsInMenuSlot);
}
/**
* Cache the items right offset position to make faster checks placement into priority menu
* @param items The items to cache the position for
*/
cacheItemPositions(items) {
const { left } = this.horizontalNav.getBoundingClientRect();
items.forEach((item) => {
item.removeAttribute("slot");
const { right } = item.getBoundingClientRect();
item.dataset.right = (right - left).toString();
});
this.itemPositionsCached = true;
}
/**
* Determines which items should be shown or hidden, depending on the current width
*/
handlePriorityMenu() {
const navItems = this.getSlottedNavItems();
if (!this.itemPositionsCached) {
this.cacheItemPositions(navItems);
}
const { width } = this.horizontalNav.getBoundingClientRect();
const reservedPrioMenuSize = this.priorityMenu.classList.contains("priority-menu--hidden") ? 0 : this.priorityMenu.clientWidth;
const finalWidth = width - reservedPrioMenuSize;
let firstHiddenItemRightPos;
const lastNavItem = navItems.at(-1);
const itemVisibilities = navItems.map((item) => {
const measureWidth = item === lastNavItem ? width : finalWidth;
const isHidden = !!(firstHiddenItemRightPos || parseFloat(item.dataset.right) > measureWidth);
if (isHidden && !firstHiddenItemRightPos) {
firstHiddenItemRightPos = parseFloat(item.dataset.right);
}
return {
isHidden,
item
};
});
const visibleItems = itemVisibilities.filter(({ isHidden }) => !isHidden).length;
const hasOnlyOneItem = visibleItems === 1;
itemVisibilities.forEach(({ item, isHidden }) => {
if (isHidden || hasOnlyOneItem) {
hideNavigationItem(item);
} else {
showNavigationItem(item);
}
});
this.hasItemsInDropdown = visibleItems !== navItems.length;
this.amountOfVisibleItems = hasOnlyOneItem ? 0 : visibleItems;
}
renderPriorityMenu() {
return html`
<syn-dropdown
class=${classMap({
"priority-menu": true,
"priority-menu--has-visible-items": this.amountOfVisibleItems !== 0,
"priority-menu--hidden": !this.hasItemsInDropdown
})}
part="priority-menu"
placement="bottom-end"
>
<syn-nav-item class="priority-menu__nav-item" slot="trigger" horizontal part="priority-menu-nav-item">
<syn-icon
class="priority-menu__icon"
label="More"
library="system"
name="more"
part="priority-menu-icon"
slot="prefix"
>
</syn-icon>
<span
class=${classMap({
"priority-menu__label": true,
"priority-menu__label--visible": this.amountOfVisibleItems === 0
})}
part="priority-menu-label"
>
${this.localize.term("menu")}
</span>
</syn-nav-item>
<syn-menu part="priority-menu-container">
<slot name="menu"></slot>
</syn-menu>
</syn-dropdown>
`;
}
slotChange() {
const slottedItems = this.getSlottedNavItems();
if (slottedItems.length !== this.amountOfNavItems) {
this.cacheItemPositions(slottedItems);
this.handlePriorityMenu();
this.amountOfNavItems = slottedItems.length;
}
}
firstUpdated() {
this.getSlottedNavItems().forEach((item) => {
var _a;
item.dataset.originalRole = (_a = item.getAttribute("role")) != null ? _a : "";
});
}
connectedCallback() {
super.connectedCallback();
this.resizeObserver = new ResizeObserver(() => this.handlePriorityMenu());
this.resizeObserver.observe(this);
}
disconnectedCallback() {
super.disconnectedCallback();
this.resizeObserver.unobserve(this);
}
render() {
return html`
<nav class="horizontal-nav" part="base">
<slot @slotchange=${this.slotChange}></slot>
${this.renderPriorityMenu()}
</nav>
`;
}
};
SynPrioNav.styles = [component_styles_default, prio_nav_styles_default];
SynPrioNav.dependencies = {
"syn-dropdown": SynDropdown,
"syn-icon": SynIcon,
"syn-menu": SynMenu,
"syn-nav-item": SynNavItem
};
__decorateClass([
query("slot:not([name])")
], SynPrioNav.prototype, "defaultSlot", 2);
__decorateClass([
query("slot[name=menu]")
], SynPrioNav.prototype, "menuSlot", 2);
__decorateClass([
query(".horizontal-nav")
], SynPrioNav.prototype, "horizontalNav", 2);
__decorateClass([
query(".priority-menu")
], SynPrioNav.prototype, "priorityMenu", 2);
__decorateClass([
state()
], SynPrioNav.prototype, "itemPositionsCached", 2);
__decorateClass([
state()
], SynPrioNav.prototype, "amountOfNavItems", 2);
__decorateClass([
state()
], SynPrioNav.prototype, "amountOfVisibleItems", 2);
__decorateClass([
state()
], SynPrioNav.prototype, "hasItemsInDropdown", 2);
export {
SynPrioNav
};
//# sourceMappingURL=chunk.6CTU4ASM.js.map