Files
Modrinth-plus/packages/ui/src/composables/use-loading-state-core.ts
Calum H. 176d4301c3 feat: shared loading state + cleanup loading state management (#5835)
* feat: implement shared loading bar component and polished loading states across the app

* feat: align loading states + ensureQueryData changes

* fix: lint + bugs

* fix: skeleton for manage servers page

* fix: merge conflict fix
2026-04-18 18:46:39 +00:00

62 lines
1.6 KiB
TypeScript

import { computed, ref, shallowRef } from 'vue'
import type { LoadingStateProvider } from '#ui/providers/loading-state'
export interface LoadingStateCoreOptions {
/** Initial value of the host kill-switch. Default: true. */
barEnabled?: boolean
}
/**
* Build a token-based `LoadingStateProvider` implementation.
*
* Multiple `ReadyTransition` instances (or any caller) can hold tokens at the
* same time; the bar stays visible while at least one is live. `end(token)`
* is idempotent so a stale token release after unmount is harmless.
*
* SSR safe: timers and DOM access are deferred to component code; this core
* is pure reactive state.
*/
export function createLoadingStateCore(opts: LoadingStateCoreOptions = {}): LoadingStateProvider {
const tokens = shallowRef<Set<symbol>>(new Set())
const barEnabled = ref(opts.barEnabled ?? true)
const pending = computed(() => tokens.value.size > 0)
function begin(): symbol {
const token = Symbol('loading-state-token')
const next = new Set(tokens.value)
next.add(token)
tokens.value = next
return token
}
function end(token: symbol): void {
if (!tokens.value.has(token)) return
const next = new Set(tokens.value)
next.delete(token)
tokens.value = next
}
function beginManual(durationMs = 500): void {
const token = begin()
if (typeof window === 'undefined') {
end(token)
return
}
window.setTimeout(() => end(token), durationMs)
}
function setEnabled(enabled: boolean): void {
barEnabled.value = enabled
}
return {
pending,
barEnabled,
begin,
end,
beginManual,
setEnabled,
}
}