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.
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user