You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/lib/ext/app/app.svelte.ts

134 lines
3.6 KiB

import { Context } from 'runed';
import { createActiveDom } from '$uix/adom';
import type {
AppOptions,
AppDom,
AppLangs,
AppNums,
AppMoney,
AppDates,
AppUnits,
AppPresentation,
AppLogger,
Direction,
DateOrder,
HourCycle
} from './types';
import { fallbackDom, fallbackLangs, fallbackPresentation, consoleLogger } from './defaults';
/**
* App — root service compositor.
*
* Holds references to all domain services. Owns no preferences directly —
* each service owns its own state. App provides convenience getters/setters
* that delegate to the appropriate service.
*
* All services that depend on locale receive `langs` at construction and
* subscribe to `onLocaleChange` internally. When locale changes, each
* recalculates its defaults unless the user has set an explicit override.
*/
export class App {
// ── Services ────────────────────────────────────────────────────────
readonly dom: AppDom;
readonly langs: AppLangs;
readonly nums: AppNums | undefined;
readonly money: AppMoney | undefined;
readonly dates: AppDates | undefined;
readonly units: AppUnits | undefined;
readonly presentation: AppPresentation;
readonly logger: AppLogger;
constructor(opts: AppOptions) {
this.dom = opts.dom ?? createActiveDom();
this.langs = opts.langs;
this.nums = opts.nums;
this.money = opts.money;
this.dates = opts.dates;
this.units = opts.units;
this.presentation = opts.presentation;
this.logger = opts.logger ?? consoleLogger;
}
// ── Convenience getters (delegate to services) ──────────────────────
get currency(): string | undefined {
return this.money?.getCurrency();
}
get dateOrder(): DateOrder | undefined {
return this.dates?.getDateOrder();
}
get hourCycle(): HourCycle | undefined {
return this.dates?.getHourCycle();
}
get theme(): string {
return this.presentation.getTheme();
}
get mode(): 'light' | 'dark' {
return this.presentation.getMode();
}
// ── Convenience setters (delegate to services) ──────────────────────
setLocale(locale: string) {
this.langs.setLocale(locale);
}
setCurrency(currency: string) {
this.money?.setCurrency(currency);
}
setDir(dir: Direction | 'auto') {
this.presentation.setDir(dir);
}
setTheme(theme: string) {
this.presentation.setTheme(theme);
}
setMode(mode: 'light' | 'dark' | 'auto') {
this.presentation.setMode(mode);
}
// ── Static distribution methods ─────────────────────────────────────
static create(opts: AppOptions): App {
const app = new App(opts);
return _ctx.set(app);
}
static get(): App {
return _ctx.getOr(_fallback);
}
static require(): App {
const app = _ctx.getOr(null as unknown as App);
if (!app) {
throw new Error(
'[app] No App found. Make sure this component is rendered inside a App.create() scope.'
);
}
return app;
}
}
// ── Module-level context ────────────────────────────────────────────────────
const _ctx = new Context<App>('App');
/**
* Fallback App used when no <App> ancestor exists.
* Only provides core services (langs, presentation, logger).
* Optional services (nums, money, dates, units) are undefined —
* components must handle their absence gracefully.
*/
const _fallback = new App({
dom: fallbackDom,
langs: fallbackLangs,
presentation: fallbackPresentation,
logger: consoleLogger
});

Powered by TurnKey Linux.