// src/layout/StatusBar.tsx
import { useCallback, useRef, useEffect, useMemo, useSyncExternalStore, type ReactNode } from 'react'
import type { StatusBarActionManager } from '../plugin/ui/status-bar-action-manager'
import type { StatusBarItem } from '../plugin/ui/status-bar-action-types'
import { SaveStatusIndicator } from '../sync/SaveStatusIndicator'
import type { SaveStatus } from '../sync/sync-contract'
import './StatusBar.css'
function subscribeOnline(listener: () => void): () => void {
window.addEventListener('online', listener)
window.addEventListener('offline', listener)
return () => {
window.removeEventListener('online', listener)
window.removeEventListener('offline', listener)
}
}
function isOnline(): boolean { return navigator.onLine }
interface StatusBarProps {
/** The status bar action manager */
statusBarActions: StatusBarActionManager
/** Current save status. When provided, renders a save indicator on the left side. */
saveStatus?: SaveStatus
/** Whether the same document is open in another tab. */
isConcurrentTabOpen?: boolean
/** Additional React content rendered on the right side before plugin items. */
extraRightItems?: ReactNode
/** Additional React content rendered on the left side after the save indicator. */
extraLeftItems?: ReactNode
}
/**
* Status bar component that displays plugin-registered items.
*
* Subscribes to StatusBarActionManager via useSyncExternalStore and renders
* each plugin's HTMLElement by mounting it into a wrapper div via useEffect + ref.
* Right-aligned, positioned inside .app-shell-main, above the formatting toolbar.
*/
export function StatusBar({ statusBarActions, saveStatus, isConcurrentTabOpen, extraRightItems, extraLeftItems }: StatusBarProps) {
const online = useSyncExternalStore(subscribeOnline, isOnline, () => true)
const subscribe = useCallback(
(cb: () => void) => statusBarActions.subscribe(cb),
[statusBarActions]
)
const getSnapshot = useCallback(
() => statusBarActions.getSnapshot(),
[statusBarActions]
)
const orderedItems = useSyncExternalStore(subscribe, getSnapshot)
// Subscribe to visibility setting
const isVisible = useSyncExternalStore(
subscribe,
useCallback(() => statusBarActions.isVisible(), [statusBarActions])
)
const elements = useMemo(() => {
return orderedItems.map((item: StatusBarItem) => (