feat(navigation): expose stable read-only workspace navigation API
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
(() => {
|
||||
'use strict';
|
||||
|
||||
const root = document.documentElement;
|
||||
if (root.dataset.uxNavigationApiReady === '1') return;
|
||||
root.dataset.uxNavigationApiReady = '1';
|
||||
|
||||
let observer = null;
|
||||
let lastView = '';
|
||||
|
||||
function activeView() {
|
||||
return document.querySelector('.sidebar-nav .nav-item.active[data-tab]')?.dataset.tab
|
||||
|| document.querySelector('.tab-content.active')?.id
|
||||
|| 'dashboard';
|
||||
}
|
||||
|
||||
function navItem(view) {
|
||||
const normalized = String(view || '').trim();
|
||||
if (!normalized) return null;
|
||||
const items = document.querySelectorAll('.sidebar-nav .nav-item[data-tab]');
|
||||
return [...items].find(item => item.dataset.tab === normalized) || null;
|
||||
}
|
||||
|
||||
function canOpen(view) {
|
||||
const item = navItem(view);
|
||||
return Boolean(item
|
||||
&& !item.hidden
|
||||
&& !item.classList.contains('hidden')
|
||||
&& item.getAttribute('aria-hidden') !== 'true'
|
||||
&& item.getAttribute('aria-disabled') !== 'true');
|
||||
}
|
||||
|
||||
function open(view) {
|
||||
const item = navItem(view);
|
||||
if (!canOpen(view) || typeof item?.click !== 'function') return false;
|
||||
item.click();
|
||||
return true;
|
||||
}
|
||||
|
||||
function emitChange(source = 'observer') {
|
||||
const currentView = activeView();
|
||||
if (currentView === lastView) return;
|
||||
const previousView = lastView || null;
|
||||
lastView = currentView;
|
||||
window.dispatchEvent(new CustomEvent('vendoo:navigation-changed', {
|
||||
detail: { currentView, previousView, source },
|
||||
}));
|
||||
}
|
||||
|
||||
const api = {};
|
||||
Object.defineProperties(api, {
|
||||
currentView: {
|
||||
enumerable: true,
|
||||
get: activeView,
|
||||
},
|
||||
canOpen: {
|
||||
enumerable: true,
|
||||
value: canOpen,
|
||||
},
|
||||
open: {
|
||||
enumerable: true,
|
||||
value: open,
|
||||
},
|
||||
});
|
||||
window.VendooNavigation = Object.freeze(api);
|
||||
|
||||
function observe() {
|
||||
const nav = document.querySelector('.sidebar-nav');
|
||||
if (!nav || observer) return;
|
||||
lastView = activeView();
|
||||
observer = new MutationObserver(() => emitChange('observer'));
|
||||
observer.observe(nav, {
|
||||
subtree: true,
|
||||
attributes: true,
|
||||
attributeFilter: ['class', 'hidden', 'aria-hidden', 'aria-disabled'],
|
||||
});
|
||||
}
|
||||
|
||||
observe();
|
||||
window.addEventListener('beforeunload', () => observer?.disconnect(), { once: true });
|
||||
window.dispatchEvent(new CustomEvent('vendoo:navigation-api-ready', {
|
||||
detail: { currentView: activeView(), version: '1.44.0' },
|
||||
}));
|
||||
})();
|
||||
Reference in New Issue
Block a user