@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
357 lines (347 loc) • 10.8 kB
JavaScript
import {
nav_item_styles_default
} from "./chunk.FCYQT7CQ.js";
import {
SynDivider
} from "./chunk.YOAPSA7L.js";
import {
HasSlotController
} from "./chunk.WVVQK5TE.js";
import {
SynIcon
} from "./chunk.RCBSMXQH.js";
import {
watch
} from "./chunk.BVZQ6QSY.js";
import {
component_styles_default
} from "./chunk.NLYVOJGK.js";
import {
SynergyElement
} from "./chunk.3THJTCRO.js";
import {
__decorateClass
} from "./chunk.Z4XV3SMG.js";
// src/components/nav-item/nav-item.component.ts
import { classMap } from "lit/directives/class-map.js";
import { html, literal } from "lit/static-html.js";
import { property, query, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
var SynNavItem = class extends SynergyElement {
constructor() {
super(...arguments);
this.hasSlotController = new HasSlotController(this, "[default]", "children", "prefix", "suffix");
this.hasFocus = false;
this.showPrefixOnly = false;
this.currentMarkedChild = false;
this.isMultiLine = false;
this.rel = "noreferrer noopener";
this.current = false;
this.disabled = false;
this.horizontal = false;
this.chevron = false;
this.open = false;
this.divider = false;
}
isButton() {
return !this.href && !this.hasSlotController.test("children");
}
isLink() {
return !!this.href && !this.hasSlotController.test("children");
}
isAccordion() {
return this.hasSlotController.test("children");
}
// eslint-disable-next-line class-methods-use-this
getNavItemChildren(childrenSlot) {
return Array.from(
(childrenSlot == null ? void 0 : childrenSlot.assignedElements({
flatten: true
})) || []
).map((slottedElement) => slottedElement.tagName.toLowerCase() === "syn-nav-item" ? slottedElement : Array.from(slottedElement.querySelectorAll(":scope > syn-nav-item"))).flat();
}
getAllNestedNavItems(childrenSlot) {
const allNavItems = this.getNavItemChildren(childrenSlot);
const nestedNavItems = allNavItems.map((item) => item.getAllNestedNavItems(item.childrenSlot)).flat();
return allNavItems.concat(nestedNavItems);
}
handleCurrentMarkedChild() {
const sideNav = this.closest("syn-side-nav");
if (!this.open || !!((sideNav == null ? void 0 : sideNav.variant) === "rail")) {
this.currentMarkedChild = this.getAllNestedNavItems(this.childrenSlot).some((item) => item.current);
}
}
handleClickButton(e) {
if (this.disabled) {
e.preventDefault();
e.stopPropagation();
}
}
handleClickSummary(e) {
e.preventDefault();
e.stopPropagation();
if (this.disabled) return;
if (this.open) {
this.hideDetails();
} else {
this.showDetails();
}
}
hideDetails() {
this.open = false;
this.emit("syn-hide", {
cancelable: true
});
}
showDetails() {
this.open = true;
this.emit("syn-show", {
cancelable: true
});
}
/**
* Automatically add the correct level of indentation for sub items if none is provided
*/
handleSlotChange() {
const computedStyle = getComputedStyle(this);
const lengthStyle = computedStyle.length;
if (lengthStyle === 0) {
setTimeout(() => {
this.handleSlotChange();
});
return;
}
this.handleCurrentMarkedChild();
const level = computedStyle.getPropertyValue("--indentation");
const nextLevel = Math.min(parseInt(level, 10) + 1, 2);
this.getNavItemChildren(this.childrenSlot).forEach((item) => {
item.style.setProperty("--indentation", nextLevel.toFixed(0));
});
}
handleBlur() {
this.hasFocus = false;
this.emit("syn-blur");
}
handleFocus() {
this.hasFocus = true;
this.emit("syn-focus");
}
handleWidth(entries) {
entries.forEach((entry) => {
requestAnimationFrame(() => {
if (entry.contentRect.width < 100) {
const hasPrefix = this.hasSlotController.test("prefix");
this.showPrefixOnly = hasPrefix;
} else {
this.showPrefixOnly = false;
}
if (entry.contentRect.height > 48) {
this.isMultiLine = true;
} else {
this.isMultiLine = false;
}
});
});
}
handleHorizontalChange() {
if (this.horizontal) {
this.resizeObserver.disconnect();
} else {
this.resizeObserver.observe(this);
}
}
connectedCallback() {
super.connectedCallback();
this.resizeObserver = new ResizeObserver((entries) => this.handleWidth(entries));
if (!this.horizontal) {
this.resizeObserver.observe(this);
}
}
firstUpdated(_changedProperties) {
super.firstUpdated(_changedProperties);
this.mutationObserver = new MutationObserver(() => {
if (this.childrenSlot) {
this.handleCurrentMarkedChild();
}
});
this.mutationObserver.observe(this, {
attributeFilter: ["current", "open"],
childList: true,
subtree: true
});
}
disconnectedCallback() {
var _a, _b;
super.disconnectedCallback();
(_a = this.resizeObserver) == null ? void 0 : _a.disconnect();
(_b = this.mutationObserver) == null ? void 0 : _b.disconnect();
}
/**
* Removes focus from the button.
*/
blur() {
this.control.blur();
}
/**
* Simulates a click on the nav-items button, link or summary.
*/
click() {
this.control.click();
}
/**
* Sets focus on the nav-item
*/
focus(options) {
this.control.focus(options);
}
// eslint-disable-next-line complexity
render() {
const isButton = this.isButton();
const isLink = this.isLink();
const isAccordion = this.isAccordion();
const sideNav = this.closest("syn-side-nav");
const showCurrentIndicatorForNested = this.currentMarkedChild && !this.open || this.currentMarkedChild && this.open && !!((sideNav == null ? void 0 : sideNav.variant) === "rail") && !(sideNav == null ? void 0 : sideNav.open);
let tag = literal`button`;
if (isAccordion) tag = literal`summary`;
else if (isLink) tag = literal`a`;
const hasChevron = (this.chevron || isAccordion) && !this.horizontal;
let clickAction;
if (isAccordion) {
clickAction = this.handleClickSummary;
} else if (isButton) {
clickAction = this.handleClickButton;
}
const root = html`
<${tag}
aria-controls=${ifDefined(isAccordion ? "navigation-item-details" : void 0)}
aria-current=${ifDefined(this.current ? "page" : void 0)}
aria-disabled=${this.disabled}
=${this.handleBlur}
class=${classMap({
"nav-item": true,
"nav-item--current": this.current || showCurrentIndicatorForNested,
"nav-item--disabled": this.disabled,
"nav-item--focused": this.hasFocus,
"nav-item--has-content": this.hasSlotController.test("[default]"),
"nav-item--has-prefix": this.hasSlotController.test("prefix"),
"nav-item--has-suffix": this.hasSlotController.test("suffix"),
"nav-item--horizontal": this.horizontal,
"nav-item--is-link": isLink,
"nav-item--multi-line": this.isMultiLine,
"nav-item--show-prefix-only": this.showPrefixOnly,
"nav-item--vertical": !this.horizontal,
"nav-item-is-accordion": isAccordion
})}
=${clickAction}
?disabled=${ifDefined(isLink ? void 0 : this.disabled)}
=${this.handleFocus}
href=${ifDefined(isLink ? this.href : void 0)}
part="base"
role=${isLink ? "link" : "button"}
rel=${ifDefined(isLink ? this.rel : void 0)}
tabindex=${this.disabled ? "-1" : "0"}
target=${ifDefined(isLink ? this.target : void 0)}
>
${this.divider && !this.horizontal ? html`<syn-divider class="divider" part="divider"></syn-divider>` : ""}
<div class="nav-item__content" part="content-wrapper">
<slot name="prefix" part="prefix" class="nav-item__prefix"></slot>
<div part="content-container" class="nav-item__content-container">
<slot part="content"></slot>
</div>
<slot name="suffix" part="suffix" class="nav-item__suffix"></slot>
${hasChevron ? html`
<syn-icon
class=${classMap({
"nav-item__chevron": true,
"nav-item__chevron-open": this.open
})}
library="system"
name="chevron-down"
part="chevron"
/></syn-icon>` : ""}
<div
class=${classMap({
"current-indicator": true,
"current-indicator--disabled": this.disabled,
"current-indicator--visible": this.current || showCurrentIndicatorForNested
})}
part="current-indicator"
>
</div>
</div>
</${tag}>
`;
return isAccordion ? html`
<details
id="navigation-item-details"
?open=${this.open}
part="details"
>
${root}
<slot
class="children"
name="children"
part="children"
=${this.handleSlotChange}
></slot>
</details>
` : root;
}
};
SynNavItem.styles = [component_styles_default, nav_item_styles_default];
SynNavItem.dependencies = {
"syn-divider": SynDivider,
"syn-icon": SynIcon
};
__decorateClass([
state()
], SynNavItem.prototype, "hasFocus", 2);
__decorateClass([
state()
], SynNavItem.prototype, "showPrefixOnly", 2);
__decorateClass([
state()
], SynNavItem.prototype, "currentMarkedChild", 2);
__decorateClass([
state()
], SynNavItem.prototype, "isMultiLine", 2);
__decorateClass([
query('slot[name="children"]')
], SynNavItem.prototype, "childrenSlot", 2);
__decorateClass([
query(".nav-item")
], SynNavItem.prototype, "control", 2);
__decorateClass([
property({ reflect: true, type: String })
], SynNavItem.prototype, "href", 2);
__decorateClass([
property()
], SynNavItem.prototype, "target", 2);
__decorateClass([
property()
], SynNavItem.prototype, "rel", 2);
__decorateClass([
property({ reflect: true, type: Boolean })
], SynNavItem.prototype, "current", 2);
__decorateClass([
property({ reflect: true, type: Boolean })
], SynNavItem.prototype, "disabled", 2);
__decorateClass([
property({ reflect: true, type: Boolean })
], SynNavItem.prototype, "horizontal", 2);
__decorateClass([
property({ reflect: true, type: Boolean })
], SynNavItem.prototype, "chevron", 2);
__decorateClass([
property({ reflect: true, type: Boolean })
], SynNavItem.prototype, "open", 2);
__decorateClass([
property({ reflect: true, type: Boolean })
], SynNavItem.prototype, "divider", 2);
__decorateClass([
watch("horizontal", { waitUntilFirstUpdate: true })
], SynNavItem.prototype, "handleHorizontalChange", 1);
export {
SynNavItem
};
//# sourceMappingURL=chunk.VI5FLXBL.js.map