Files
dees-catalog/ts_web/elements/00group-appui/dees-appui-base/dees-appui-base.ts

978 lines
28 KiB
TypeScript
Raw Normal View History

2024-01-24 12:18:37 +01:00
import {
DeesElement,
type TemplateResult,
property,
customElement,
html,
css,
cssManager,
state,
2024-01-24 12:18:37 +01:00
} from '@design.estate/dees-element';
import * as domtools from '@design.estate/dees-domtools';
import * as interfaces from '../../interfaces/index.js';
import type { DeesAppuiBar } from '../dees-appui-appbar/index.js';
import type { DeesAppuiMainmenu } from '../dees-appui-mainmenu/dees-appui-mainmenu.js';
import type { DeesAppuiSecondarymenu } from '../dees-appui-secondarymenu/dees-appui-secondarymenu.js';
import type { DeesAppuiMaincontent } from '../dees-appui-maincontent/dees-appui-maincontent.js';
import type { DeesAppuiActivitylog } from '../dees-appui-activitylog/dees-appui-activitylog.js';
import { demoFunc } from './dees-appui-base.demo.js';
// View registry for managing views
import { ViewRegistry } from './view.registry.js';
// Import child components
import '../dees-appui-appbar/index.js';
import '../dees-appui-mainmenu/dees-appui-mainmenu.js';
import '../dees-appui-secondarymenu/dees-appui-secondarymenu.js';
import '../dees-appui-maincontent/dees-appui-maincontent.js';
import '../dees-appui-activitylog/dees-appui-activitylog.js';
2024-01-24 12:18:37 +01:00
declare global {
interface HTMLElementTagNameMap {
'dees-appui-base': DeesAppuiBase;
}
}
2024-01-24 12:18:37 +01:00
@customElement('dees-appui-base')
export class DeesAppuiBase extends DeesElement {
public static demo = demoFunc;
// ==========================================
// REACTIVE OBSERVABLES (RxJS Subjects)
// ==========================================
/** Observable stream of view lifecycle events */
public viewLifecycle$ = new domtools.plugins.smartrx.rxjs.Subject<interfaces.IViewLifecycleEvent>();
/** Observable stream of view change events */
public viewChanged$ = new domtools.plugins.smartrx.rxjs.Subject<interfaces.IViewChangeEvent>();
// ==========================================
// INTERNAL PROPERTIES (Properties for child components)
// ==========================================
// Properties for appbar
@property({ type: Array })
accessor appbarMenuItems: interfaces.IAppBarMenuItem[] = [];
@property({ type: String })
accessor appbarBreadcrumbs: string = '';
@property({ type: String })
accessor appbarBreadcrumbSeparator: string = ' > ';
@property({ type: Boolean })
accessor appbarShowWindowControls: boolean = true;
@property({ type: Object })
accessor appbarUser: interfaces.IAppUser | undefined = undefined;
@property({ type: Array })
accessor appbarProfileMenuItems: interfaces.IAppBarMenuItem[] = [];
@property({ type: Boolean })
accessor appbarShowSearch: boolean = false;
// Properties for mainmenu
@property({ type: String })
accessor mainmenuLogoIcon: string = '';
@property({ type: String })
accessor mainmenuLogoText: string = '';
@property({ type: Array })
accessor mainmenuGroups: interfaces.IMenuGroup[] = [];
@property({ type: Array })
accessor mainmenuBottomTabs: interfaces.ITab[] = [];
@property({ type: Array })
accessor mainmenuTabs: interfaces.ITab[] = [];
@property({ type: Object })
accessor mainmenuSelectedTab: interfaces.ITab | undefined = undefined;
// Properties for secondarymenu
@property({ type: String })
accessor secondarymenuHeading: string = '';
@property({ type: Array })
accessor secondarymenuGroups: interfaces.ISecondaryMenuGroup[] = [];
@property({ type: Object })
accessor secondarymenuSelectedItem: interfaces.ISecondaryMenuItem | undefined = undefined;
// Collapse states
@property({ type: Boolean })
accessor mainmenuCollapsed: boolean = false;
@property({ type: Boolean })
accessor secondarymenuCollapsed: boolean = false;
// Properties for maincontent
@property({ type: Array })
accessor maincontentTabs: interfaces.ITab[] = [];
@property({ type: Object })
accessor maincontentSelectedTab: interfaces.ITab | undefined = undefined;
// References to child components
@state()
accessor appbar: DeesAppuiBar | undefined = undefined;
@state()
accessor mainmenu: DeesAppuiMainmenu | undefined = undefined;
@state()
accessor secondarymenu: DeesAppuiSecondarymenu | undefined = undefined;
@state()
accessor maincontent: DeesAppuiMaincontent | undefined = undefined;
@state()
accessor activitylogElement: DeesAppuiActivitylog | undefined = undefined;
2024-01-24 12:18:37 +01:00
// Current view state
@state()
accessor currentView: interfaces.IViewDefinition | undefined = undefined;
// Internal services
private viewRegistry: ViewRegistry = new ViewRegistry();
private routerCleanup: (() => void) | null = null;
private searchCallback: ((query: string) => void) | null = null;
2024-01-24 12:18:37 +01:00
public static styles = [
cssManager.defaultStyles,
css`
:host {
position: absolute;
height: 100%;
width: 100%;
background: ${cssManager.bdTheme('#f0f0f0', '#1a1a1a')};
2024-01-24 12:18:37 +01:00
}
.maingrid {
position: absolute;
top: 40px;
height: calc(100% - 40px);
width: 100%;
display: grid;
grid-template-columns: auto auto 1fr 240px;
grid-template-rows: 1fr;
2024-01-24 12:18:37 +01:00
}
/* Z-index layering for proper stacking */
.maingrid > dees-appui-mainmenu {
position: relative;
z-index: 3;
}
.maingrid > dees-appui-secondarymenu {
position: relative;
z-index: 2;
}
.maingrid > dees-appui-maincontent {
position: relative;
z-index: 1;
}
.maingrid > dees-appui-activitylog {
position: relative;
z-index: 1;
}
/* View container for dynamically loaded views */
.view-container {
display: contents;
}
.view-container:empty {
display: none;
}
2024-01-24 12:18:37 +01:00
`,
];
public render(): TemplateResult {
return html`
<dees-appui-appbar
.menuItems=${this.appbarMenuItems}
.breadcrumbs=${this.appbarBreadcrumbs}
.breadcrumbSeparator=${this.appbarBreadcrumbSeparator}
.showWindowControls=${this.appbarShowWindowControls}
.user=${this.appbarUser}
.profileMenuItems=${this.appbarProfileMenuItems}
.showSearch=${this.appbarShowSearch}
@menu-select=${(e: CustomEvent) => this.handleAppbarMenuSelect(e)}
@breadcrumb-navigate=${(e: CustomEvent) => this.handleAppbarBreadcrumbNavigate(e)}
@search-click=${() => this.handleAppbarSearchClick()}
@search-query=${(e: CustomEvent) => this.handleAppbarSearchQuery(e)}
@user-menu-open=${() => this.handleAppbarUserMenuOpen()}
@profile-menu-select=${(e: CustomEvent) => this.handleAppbarProfileMenuSelect(e)}
></dees-appui-appbar>
2024-01-24 12:18:37 +01:00
<div class="maingrid">
<dees-appui-mainmenu
.logoIcon=${this.mainmenuLogoIcon}
.logoText=${this.mainmenuLogoText}
.menuGroups=${this.mainmenuGroups}
.bottomTabs=${this.mainmenuBottomTabs}
.tabs=${this.mainmenuTabs}
.selectedTab=${this.mainmenuSelectedTab}
.collapsed=${this.mainmenuCollapsed}
@tab-select=${(e: CustomEvent) => this.handleMainmenuTabSelect(e)}
@collapse-change=${(e: CustomEvent) => this.handleMainmenuCollapseChange(e)}
></dees-appui-mainmenu>
<dees-appui-secondarymenu
.heading=${this.secondarymenuHeading}
.groups=${this.secondarymenuGroups}
.selectedItem=${this.secondarymenuSelectedItem}
.collapsed=${this.secondarymenuCollapsed}
@item-select=${(e: CustomEvent) => this.handleSecondarymenuItemSelect(e)}
@collapse-change=${(e: CustomEvent) => this.handleSecondarymenuCollapseChange(e)}
></dees-appui-secondarymenu>
<dees-appui-maincontent
.tabs=${this.maincontentTabs}
.selectedTab=${this.maincontentSelectedTab}
@tab-select=${(e: CustomEvent) => this.handleContentTabSelect(e)}
>
<div class="view-container"></div>
<slot name="maincontent"></slot>
</dees-appui-maincontent>
2024-01-24 12:18:37 +01:00
<dees-appui-activitylog></dees-appui-activitylog>
</div>
`;
}
async firstUpdated() {
// Get references to child components
this.appbar = this.shadowRoot!.querySelector('dees-appui-appbar') as DeesAppuiBar;
this.mainmenu = this.shadowRoot!.querySelector('dees-appui-mainmenu') as DeesAppuiMainmenu;
this.secondarymenu = this.shadowRoot!.querySelector('dees-appui-secondarymenu') as DeesAppuiSecondarymenu;
this.maincontent = this.shadowRoot!.querySelector('dees-appui-maincontent') as DeesAppuiMaincontent;
this.activitylogElement = this.shadowRoot!.querySelector('dees-appui-activitylog') as DeesAppuiActivitylog;
// Set appui reference in view registry for lifecycle context
this.viewRegistry.setAppuiRef(this as unknown as interfaces.TDeesAppuiBase);
}
async disconnectedCallback() {
await super.disconnectedCallback();
// Clean up router listener
if (this.routerCleanup) {
this.routerCleanup();
this.routerCleanup = null;
}
// Complete subjects
this.viewLifecycle$.complete();
this.viewChanged$.complete();
}
// ==========================================
// PROGRAMMATIC API: APP BAR
// ==========================================
/**
* Set the app bar menu items (File, Edit, View, etc.)
*/
public setAppBarMenus(menus: interfaces.IAppBarMenuItem[]): void {
this.appbarMenuItems = [...menus];
}
/**
* Update a single app bar menu by name
*/
public updateAppBarMenu(name: string, update: Partial<interfaces.IAppBarMenuItem>): void {
this.appbarMenuItems = this.appbarMenuItems.map(menu => {
// Check if it's not a divider and has a name property
if ('name' in menu && menu.name === name) {
return { ...menu, ...update };
}
return menu;
});
}
/**
* Set the breadcrumbs (string or array)
*/
public setBreadcrumbs(breadcrumbs: string | string[]): void {
if (Array.isArray(breadcrumbs)) {
this.appbarBreadcrumbs = breadcrumbs.join(this.appbarBreadcrumbSeparator);
} else {
this.appbarBreadcrumbs = breadcrumbs;
}
}
/**
* Set the current user
*/
public setUser(user: interfaces.IAppUser | undefined): void {
this.appbarUser = user;
}
/**
* Set the profile dropdown menu items
*/
public setProfileMenuItems(items: interfaces.IAppBarMenuItem[]): void {
this.appbarProfileMenuItems = [...items];
}
/**
* Set search bar visibility
*/
public setSearchVisible(visible: boolean): void {
this.appbarShowSearch = visible;
}
/**
* Set window controls visibility
*/
public setWindowControlsVisible(visible: boolean): void {
this.appbarShowWindowControls = visible;
}
/**
* Register a search callback
*/
public onSearch(callback: (query: string) => void): void {
this.searchCallback = callback;
}
// ==========================================
// PROGRAMMATIC API: MAIN MENU
// ==========================================
/**
* Set the entire main menu configuration
*/
public setMainMenu(config: interfaces.IMainMenuConfig): void {
if (config.logoIcon !== undefined) {
this.mainmenuLogoIcon = config.logoIcon;
}
if (config.logoText !== undefined) {
this.mainmenuLogoText = config.logoText;
}
if (config.groups !== undefined) {
this.mainmenuGroups = [...config.groups];
}
if (config.bottomTabs !== undefined) {
this.mainmenuBottomTabs = [...config.bottomTabs];
}
}
/**
* Update a specific menu group by name
*/
public updateMainMenuGroup(groupName: string, update: Partial<interfaces.IMenuGroup>): void {
this.mainmenuGroups = this.mainmenuGroups.map(group =>
group.name === groupName ? { ...group, ...update } : group
);
}
/**
* Add a menu item to a specific group
*/
public addMainMenuItem(groupName: string, tab: interfaces.ITab): void {
this.mainmenuGroups = this.mainmenuGroups.map(group => {
if (group.name === groupName) {
return {
...group,
tabs: [...(group.tabs || []), tab],
};
}
return group;
});
}
/**
* Remove a menu item from a group by key
*/
public removeMainMenuItem(groupName: string, tabKey: string): void {
this.mainmenuGroups = this.mainmenuGroups.map(group => {
if (group.name === groupName) {
return {
...group,
tabs: (group.tabs || []).filter(t => t.key !== tabKey),
};
}
return group;
});
}
/**
* Set the selected main menu item by key
*/
public setMainMenuSelection(tabKey: string): void {
for (const group of this.mainmenuGroups) {
const tab = group.tabs?.find(t => t.key === tabKey);
if (tab) {
this.mainmenuSelectedTab = tab;
return;
}
}
// Check bottom tabs
const bottomTab = this.mainmenuBottomTabs.find(t => t.key === tabKey);
if (bottomTab) {
this.mainmenuSelectedTab = bottomTab;
}
}
/**
* Set main menu collapsed state
*/
public setMainMenuCollapsed(collapsed: boolean): void {
this.mainmenuCollapsed = collapsed;
}
/**
* Set a badge on a main menu item
*/
public setMainMenuBadge(tabKey: string, badge: string | number): void {
this.mainmenuGroups = this.mainmenuGroups.map(group => ({
...group,
tabs: (group.tabs || []).map(tab =>
tab.key === tabKey ? { ...tab, badge } : tab
),
}));
// Also check bottom tabs
this.mainmenuBottomTabs = this.mainmenuBottomTabs.map(tab =>
tab.key === tabKey ? { ...tab, badge } : tab
);
}
/**
* Clear a badge from a main menu item
*/
public clearMainMenuBadge(tabKey: string): void {
this.mainmenuGroups = this.mainmenuGroups.map(group => ({
...group,
tabs: (group.tabs || []).map(tab => {
if (tab.key === tabKey) {
const { badge, ...rest } = tab;
return rest;
}
return tab;
}),
}));
// Also check bottom tabs
this.mainmenuBottomTabs = this.mainmenuBottomTabs.map(tab => {
if (tab.key === tabKey) {
const { badge, ...rest } = tab;
return rest;
}
return tab;
});
}
// ==========================================
// PROGRAMMATIC API: SECONDARY MENU
// ==========================================
/**
* Set the secondary menu configuration
*/
public setSecondaryMenu(config: { heading?: string; groups: interfaces.ISecondaryMenuGroup[] }): void {
if (config.heading !== undefined) {
this.secondarymenuHeading = config.heading;
}
this.secondarymenuGroups = [...config.groups];
}
/**
* Update a specific secondary menu group
*/
public updateSecondaryMenuGroup(groupName: string, update: Partial<interfaces.ISecondaryMenuGroup>): void {
this.secondarymenuGroups = this.secondarymenuGroups.map(group =>
group.name === groupName ? { ...group, ...update } : group
);
}
/**
* Add an item to a secondary menu group
*/
public addSecondaryMenuItem(
groupName: string,
item: interfaces.ISecondaryMenuGroup['items'][0]
): void {
this.secondarymenuGroups = this.secondarymenuGroups.map(group => {
if (group.name === groupName) {
return {
...group,
items: [...group.items, item],
};
}
return group;
});
}
/**
* Set the selected secondary menu item by key
*/
public setSecondaryMenuSelection(itemKey: string): void {
for (const group of this.secondarymenuGroups) {
const item = group.items.find(i => i.key === itemKey);
if (item) {
this.secondarymenuSelectedItem = item;
return;
}
}
}
/**
* Clear the secondary menu
*/
public clearSecondaryMenu(): void {
this.secondarymenuHeading = '';
this.secondarymenuGroups = [];
this.secondarymenuSelectedItem = undefined;
}
// ==========================================
// PROGRAMMATIC API: CONTENT TABS
// ==========================================
/**
* Set the content tabs
*/
public setContentTabs(tabs: interfaces.ITab[]): void {
this.maincontentTabs = [...tabs];
if (tabs.length > 0 && !this.maincontentSelectedTab) {
this.maincontentSelectedTab = tabs[0];
}
}
/**
* Add a content tab
*/
public addContentTab(tab: interfaces.ITab): void {
this.maincontentTabs = [...this.maincontentTabs, tab];
}
/**
* Remove a content tab by key
*/
public removeContentTab(tabKey: string): void {
this.maincontentTabs = this.maincontentTabs.filter(t => t.key !== tabKey);
if (this.maincontentSelectedTab?.key === tabKey) {
this.maincontentSelectedTab = this.maincontentTabs[0];
}
}
/**
* Select a content tab by key
*/
public selectContentTab(tabKey: string): void {
const tab = this.maincontentTabs.find(t => t.key === tabKey);
if (tab) {
this.maincontentSelectedTab = tab;
}
}
/**
* Get the currently selected content tab
*/
public getSelectedContentTab(): interfaces.ITab | undefined {
return this.maincontentSelectedTab;
}
// ==========================================
// PROGRAMMATIC API: ACTIVITY LOG
// ==========================================
/**
* Get the activity log API
*/
public get activityLog(): interfaces.IActivityLogAPI {
if (!this.activitylogElement) {
// Return a deferred API that will work after firstUpdated
return {
add: (entry) => {
this.updateComplete.then(() => this.activitylogElement?.add(entry));
},
addMany: (entries) => {
this.updateComplete.then(() => this.activitylogElement?.addMany(entries));
},
clear: () => {
this.updateComplete.then(() => this.activitylogElement?.clear());
},
getEntries: () => this.activitylogElement?.getEntries() || [],
filter: (criteria) => this.activitylogElement?.filter(criteria) || [],
search: (query) => this.activitylogElement?.search(query) || [],
};
}
return {
add: (entry) => this.activitylogElement!.add(entry),
addMany: (entries) => this.activitylogElement!.addMany(entries),
clear: () => this.activitylogElement!.clear(),
getEntries: () => this.activitylogElement!.getEntries(),
filter: (criteria) => this.activitylogElement!.filter(criteria),
search: (query) => this.activitylogElement!.search(query),
};
}
// ==========================================
// PROGRAMMATIC API: NAVIGATION
// ==========================================
/**
* Navigate to a view by ID
*/
public async navigateToView(viewId: string, params?: Record<string, string>): Promise<boolean> {
const view = this.viewRegistry.get(viewId);
if (!view) {
console.warn(`Cannot navigate to unknown view: ${viewId}`);
return false;
}
// Check if current view allows navigation
const canLeave = await this.viewRegistry.canLeaveCurrentView();
if (canLeave !== true) {
if (typeof canLeave === 'string') {
// Show confirmation dialog
const confirmed = window.confirm(canLeave);
if (!confirmed) return false;
} else {
return false;
}
}
// Emit loading event
this.viewLifecycle$.next({ type: 'loading', viewId });
try {
await this.loadView(view, params);
// Update URL hash
const route = view.route || viewId;
const newHash = `#${route}`;
if (window.location.hash !== newHash) {
window.history.pushState({ viewId }, '', newHash);
}
return true;
} catch (error) {
this.viewLifecycle$.next({ type: 'loadError', viewId, error });
return false;
}
}
/**
* Get the current view
*/
public getCurrentView(): interfaces.IViewDefinition | undefined {
return this.currentView;
}
/**
* Get access to the view registry (for advanced use)
*/
public getViewRegistry(): ViewRegistry {
return this.viewRegistry;
}
// ==========================================
// UNIFIED CONFIGURATION
// ==========================================
/**
* Configure the app shell with a unified config object
*/
public configure(config: interfaces.IAppConfig): void {
// Register views
if (config.views) {
this.viewRegistry.clear();
this.viewRegistry.registerAll(config.views);
}
// Apply branding
if (config.branding) {
this.mainmenuLogoIcon = config.branding.logoIcon || '';
this.mainmenuLogoText = config.branding.logoText || '';
}
// Apply app bar config
if (config.appBar) {
this.appbarMenuItems = config.appBar.menuItems || [];
this.appbarBreadcrumbs = config.appBar.breadcrumbs || '';
this.appbarBreadcrumbSeparator = config.appBar.breadcrumbSeparator || ' > ';
this.appbarShowWindowControls = config.appBar.showWindowControls ?? true;
this.appbarShowSearch = config.appBar.showSearch ?? false;
this.appbarUser = config.appBar.user;
this.appbarProfileMenuItems = config.appBar.profileMenuItems || [];
}
// Build main menu from view references or direct config
if (config.mainMenu) {
if (config.mainMenu.sections) {
this.mainmenuGroups = this.buildMainMenuFromSections(config);
} else if (config.mainMenu.groups) {
this.mainmenuGroups = config.mainMenu.groups;
}
if (config.mainMenu.logoIcon) {
this.mainmenuLogoIcon = config.mainMenu.logoIcon;
}
if (config.mainMenu.logoText) {
this.mainmenuLogoText = config.mainMenu.logoText;
}
if (config.mainMenu.bottomTabs) {
this.mainmenuBottomTabs = config.mainMenu.bottomTabs;
} else if (config.mainMenu.bottomItems) {
this.mainmenuBottomTabs = this.buildBottomTabsFromItems(config.mainMenu.bottomItems);
}
}
// Setup domtools.router integration
this.setupRouterIntegration(config);
// Bind event callbacks
if (config.onViewChange) {
this.viewChanged$.subscribe((event) => {
config.onViewChange!(event.viewId, event.view);
});
}
if (config.onSearch) {
this.searchCallback = config.onSearch;
}
// Navigate to default view
if (config.defaultView) {
this.navigateToView(config.defaultView);
}
}
// ==========================================
// PRIVATE HELPER METHODS
// ==========================================
private setupRouterIntegration(config: interfaces.IAppConfig): void {
// Handle hash change events
const handleHashChange = () => {
const hash = window.location.hash.slice(1); // Remove #
if (!hash) return;
const match = this.viewRegistry.findByRoute(hash);
if (match) {
this.navigateToView(match.view.id, match.params);
}
};
window.addEventListener('hashchange', handleHashChange);
// Store cleanup function
this.routerCleanup = () => {
window.removeEventListener('hashchange', handleHashChange);
};
// Handle initial route from hash
const currentHash = window.location.hash.slice(1);
if (currentHash) {
const match = this.viewRegistry.findByRoute(currentHash);
if (match) {
// Use setTimeout to allow component to fully initialize
setTimeout(() => this.navigateToView(match.view.id, match.params), 0);
}
}
}
private buildMainMenuFromSections(config: interfaces.IAppConfig): interfaces.IMenuGroup[] {
if (!config.mainMenu?.sections) return [];
return config.mainMenu.sections.map((section) => ({
name: section.name,
tabs: section.views
.map((viewId) => {
const view = this.viewRegistry.get(viewId);
if (!view) {
console.warn(`View "${viewId}" not found in registry`);
return null;
}
return {
key: view.id,
iconName: view.iconName,
action: () => this.navigateToView(viewId),
badge: view.badge,
} as interfaces.ITab;
})
.filter(Boolean) as interfaces.ITab[],
}));
}
private buildBottomTabsFromItems(items: string[]): interfaces.ITab[] {
return items
.map((viewId) => {
const view = this.viewRegistry.get(viewId);
if (!view) {
console.warn(`View "${viewId}" not found in registry`);
return null;
}
return {
key: view.id,
iconName: view.iconName,
action: () => this.navigateToView(viewId),
} as interfaces.ITab;
})
.filter(Boolean) as interfaces.ITab[];
}
private async loadView(
view: interfaces.IViewDefinition,
params?: Record<string, string>
): Promise<void> {
const previousView = this.currentView;
this.currentView = view;
// Get view container
const viewContainer = this.maincontent?.querySelector('.view-container')
|| this.shadowRoot?.querySelector('.view-container');
if (viewContainer) {
// Activate view with caching and lifecycle hooks
const element = await this.viewRegistry.activateView(
view.id,
viewContainer as HTMLElement,
params
);
if (element) {
// Emit lifecycle event
this.viewLifecycle$.next({
type: 'activated',
viewId: view.id,
element,
params,
});
}
}
// Apply view-specific secondary menu
if (view.secondaryMenu) {
this.secondarymenuGroups = view.secondaryMenu;
this.secondarymenuHeading = view.name;
}
// Apply view-specific content tabs
if (view.contentTabs) {
this.maincontentTabs = view.contentTabs;
}
// Update main menu selection
this.setMainMenuSelection(view.id);
// Emit view change event
const changeEvent: interfaces.IViewChangeEvent = {
viewId: view.id,
view,
previousView,
params,
};
this.viewChanged$.next(changeEvent);
// Also dispatch DOM event for backwards compatibility
this.dispatchEvent(
new CustomEvent('view-change', {
detail: changeEvent,
bubbles: true,
composed: true,
})
);
}
// ==========================================
// EVENT HANDLERS (Internal)
// ==========================================
private handleAppbarMenuSelect(e: CustomEvent) {
this.dispatchEvent(new CustomEvent('appbar-menu-select', {
detail: e.detail,
bubbles: true,
composed: true
}));
}
private handleAppbarBreadcrumbNavigate(e: CustomEvent) {
this.dispatchEvent(new CustomEvent('appbar-breadcrumb-navigate', {
detail: e.detail,
bubbles: true,
composed: true
}));
}
private handleAppbarSearchClick() {
this.dispatchEvent(new CustomEvent('appbar-search-click', {
bubbles: true,
composed: true
}));
}
private handleAppbarSearchQuery(e: CustomEvent) {
if (this.searchCallback) {
this.searchCallback(e.detail.query);
}
this.dispatchEvent(new CustomEvent('search-query', {
detail: e.detail,
bubbles: true,
composed: true
}));
}
private handleAppbarUserMenuOpen() {
this.dispatchEvent(new CustomEvent('appbar-user-menu-open', {
bubbles: true,
composed: true
}));
}
private handleAppbarProfileMenuSelect(e: CustomEvent) {
this.dispatchEvent(new CustomEvent('appbar-profile-menu-select', {
detail: e.detail,
bubbles: true,
composed: true
}));
}
private handleMainmenuTabSelect(e: CustomEvent) {
this.mainmenuSelectedTab = e.detail.tab;
this.dispatchEvent(new CustomEvent('mainmenu-tab-select', {
detail: e.detail,
bubbles: true,
composed: true
}));
}
private handleSecondarymenuItemSelect(e: CustomEvent) {
this.secondarymenuSelectedItem = e.detail.item;
this.dispatchEvent(new CustomEvent('secondarymenu-item-select', {
detail: e.detail,
bubbles: true,
composed: true
}));
}
private handleMainmenuCollapseChange(e: CustomEvent) {
this.mainmenuCollapsed = e.detail.collapsed;
this.dispatchEvent(new CustomEvent('mainmenu-collapse-change', {
detail: e.detail,
bubbles: true,
composed: true
}));
}
private handleSecondarymenuCollapseChange(e: CustomEvent) {
this.secondarymenuCollapsed = e.detail.collapsed;
this.dispatchEvent(new CustomEvent('secondarymenu-collapse-change', {
detail: e.detail,
bubbles: true,
composed: true
}));
}
private handleContentTabSelect(e: CustomEvent) {
this.maincontentSelectedTab = e.detail.tab;
this.dispatchEvent(new CustomEvent('content-tab-select', {
detail: e.detail,
bubbles: true,
composed: true
}));
}
2024-01-24 12:18:37 +01:00
}