Merge pull request #1458 from umbraco/feature/active-menu-item
Feature: Active menu/tree item
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { html, customElement, property, ifDefined } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { html, customElement, property, ifDefined, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { debounce } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
/**
|
||||
* @element umb-menu-item-layout
|
||||
@@ -36,8 +37,32 @@ export class UmbMenuItemLayoutElement extends UmbLitElement {
|
||||
@property({ type: String })
|
||||
public href?: string;
|
||||
|
||||
@state()
|
||||
private _isActive = false;
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
window.addEventListener('navigationend', this.#debouncedCheckIsActive);
|
||||
}
|
||||
|
||||
#debouncedCheckIsActive = debounce(() => this.#checkIsActive(), 100);
|
||||
|
||||
#checkIsActive() {
|
||||
if (!this.href) {
|
||||
this._isActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const location = window.location.pathname;
|
||||
this._isActive = location.includes(this.href);
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<uui-menu-item href="${ifDefined(this.href)}" label=${this.label} ?has-children=${this.hasChildren}>
|
||||
return html`<uui-menu-item
|
||||
href="${ifDefined(this.href)}"
|
||||
label=${this.label}
|
||||
?active=${this._isActive}
|
||||
?has-children=${this.hasChildren}>
|
||||
<umb-icon slot="icon" name=${this.iconName}></umb-icon>
|
||||
${this.entityType
|
||||
? html`<umb-entity-actions-bundle
|
||||
@@ -45,11 +70,16 @@ export class UmbMenuItemLayoutElement extends UmbLitElement {
|
||||
.entityType=${this.entityType}
|
||||
.unique=${null}
|
||||
.label=${this.label}>
|
||||
</umb-entity-actions-bundle>`
|
||||
</umb-entity-actions-bundle>`
|
||||
: ''}
|
||||
<slot></slot>
|
||||
</uui-menu-item>`;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
window.removeEventListener('navigationend', this.#debouncedCheckIsActive);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
import { UMB_ACTION_EVENT_CONTEXT, type UmbActionEventContext } from '@umbraco-cms/backoffice/action';
|
||||
import type { UmbEntityActionEvent } from '@umbraco-cms/backoffice/entity-action';
|
||||
import { UmbPaginationManager } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbPaginationManager, debounce } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbChangeEvent, UmbRequestReloadStructureForEntityEvent } from '@umbraco-cms/backoffice/event';
|
||||
|
||||
export type UmbTreeItemUniqueFunction<TreeItemType extends UmbTreeItemModelBase> = (
|
||||
@@ -101,6 +101,8 @@ export abstract class UmbTreeItemContextBase<TreeItemType extends UmbTreeItemMod
|
||||
this.loadChildren();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('navigationend', this.#debouncedCheckIsActive);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,6 +252,7 @@ export abstract class UmbTreeItemContextBase<TreeItemType extends UmbTreeItemMod
|
||||
if (value === true) {
|
||||
const isSelectable = this.treeContext?.selectableFilter?.(this.getTreeItem()!) ?? true;
|
||||
this.#isSelectable.setValue(isSelectable);
|
||||
this.#checkIsActive();
|
||||
}
|
||||
},
|
||||
'observeIsSelectable',
|
||||
@@ -277,6 +280,7 @@ export abstract class UmbTreeItemContextBase<TreeItemType extends UmbTreeItemMod
|
||||
if (!pathname || !this.entityType || this.unique === undefined) return;
|
||||
const path = this.constructPath(pathname, this.entityType, this.unique);
|
||||
this.#path.setValue(path);
|
||||
this.#checkIsActive();
|
||||
},
|
||||
'observeSectionPath',
|
||||
);
|
||||
@@ -349,6 +353,23 @@ export abstract class UmbTreeItemContextBase<TreeItemType extends UmbTreeItemMod
|
||||
this.loadChildren();
|
||||
};
|
||||
|
||||
#debouncedCheckIsActive = debounce(() => this.#checkIsActive(), 100);
|
||||
|
||||
#checkIsActive() {
|
||||
// don't set the active state if the item is selectable
|
||||
const isSelectable = this.#isSelectable.getValue();
|
||||
|
||||
if (isSelectable) {
|
||||
this.#isActive.setValue(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const path = this.#path.getValue();
|
||||
const location = window.location.pathname;
|
||||
const isActive = location.includes(path);
|
||||
this.#isActive.setValue(isActive);
|
||||
}
|
||||
|
||||
// TODO: use router context
|
||||
constructPath(pathname: string, entityType: string, unique: string | null) {
|
||||
return `section/${pathname}/workspace/${entityType}/edit/${unique}`;
|
||||
@@ -359,6 +380,7 @@ export abstract class UmbTreeItemContextBase<TreeItemType extends UmbTreeItemMod
|
||||
UmbReloadTreeItemChildrenRequestEntityActionEvent.TYPE,
|
||||
this.#onReloadRequest as EventListener,
|
||||
);
|
||||
window.removeEventListener('navigationend', this.#debouncedCheckIsActive);
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ export abstract class UmbTreeItemElementBase<TreeItemModelType extends UmbTreeIt
|
||||
this.#initTreeItem();
|
||||
}
|
||||
|
||||
@state()
|
||||
private _isActive = false;
|
||||
|
||||
@state()
|
||||
private _childItems?: TreeItemModelType[];
|
||||
|
||||
@@ -62,6 +65,7 @@ export abstract class UmbTreeItemElementBase<TreeItemModelType extends UmbTreeIt
|
||||
this.observe(this.#treeItemContext.treeItem, (value) => (this._item = value));
|
||||
this.observe(this.#treeItemContext.childItems, (value) => (this._childItems = value));
|
||||
this.observe(this.#treeItemContext.hasChildren, (value) => (this._hasChildren = value));
|
||||
this.observe(this.#treeItemContext.isActive, (value) => (this._isActive = value));
|
||||
this.observe(this.#treeItemContext.isLoading, (value) => (this._isLoading = value));
|
||||
this.observe(this.#treeItemContext.isSelectableContext, (value) => (this._isSelectableContext = value));
|
||||
this.observe(this.#treeItemContext.isSelectable, (value) => (this._isSelectable = value));
|
||||
@@ -107,6 +111,7 @@ export abstract class UmbTreeItemElementBase<TreeItemModelType extends UmbTreeIt
|
||||
@show-children=${this._onShowChildren}
|
||||
@selected=${this._handleSelectedItem}
|
||||
@deselected=${this._handleDeselectedItem}
|
||||
?active=${this._isActive}
|
||||
?disabled=${this._isSelectableContext && !this._isSelectable}
|
||||
?selectable=${this._isSelectable}
|
||||
?selected=${this._isSelected}
|
||||
|
||||
Reference in New Issue
Block a user