Files
bface/src/security/runtime/account-tabs.js
Amer Agovic 94a9f32969 Initial commit: bface library, build fixes, and refreshed docs
- Externalize all @tamagui/* and tamagui subpaths so dist no longer vendors Tamagui.
- Emit TypeScript declarations with vite-plugin-dts; fix package exports types for ui/*.
- Align initEnv with profiles: displayName, brandLogo, api.baseURL, themeColor, uiShell.
- Stabilize tests with Node localStorage file; env tests pass.
- Update README and component docs for services, menus, API client, and development.
2026-04-18 10:43:52 -05:00

59 lines
1.4 KiB
JavaScript

import { useSyncExternalStore } from 'react';
const accountTabs = [];
const listeners = new Set();
let cachedTabs = [];
function rebuildSnapshot() {
cachedTabs = [...accountTabs].sort((a, b) => (a.order || 0) - (b.order || 0));
}
function emit() {
listeners.forEach((listener) => {
try {
listener();
} catch (error) {
console.warn('[Security] Account tab listener failed:', error);
}
});
}
export function publishAccountTab(tab) {
if (!tab || !tab.id || !tab.label || !tab.component) {
console.warn('[Security] publishAccountTab() requires id, label, and component');
return;
}
const existingIndex = accountTabs.findIndex((item) => item.id === tab.id);
if (existingIndex >= 0) {
accountTabs[existingIndex] = tab;
} else {
accountTabs.push(tab);
}
rebuildSnapshot();
emit();
}
export function retractAccountTab(tabId) {
const nextTabs = accountTabs.filter((tab) => tab.id !== tabId);
if (nextTabs.length !== accountTabs.length) {
accountTabs.length = 0;
accountTabs.push(...nextTabs);
rebuildSnapshot();
emit();
}
}
export function getAccountTabs() {
return cachedTabs;
}
export function subscribeToAccountTabs(listener) {
listeners.add(listener);
return () => listeners.delete(listener);
}
export function useAccountTabs() {
return useSyncExternalStore(subscribeToAccountTabs, getAccountTabs, getAccountTabs);
}