@magicvr/schema-ui-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,43 @@
1
+ import type { ReactNode } from "react";
2
+ export type SortOrder = "asc" | "desc";
3
+ export interface SortState {
4
+ field: string;
5
+ order: SortOrder;
6
+ }
7
+ export interface DataTableColumn<T> {
8
+ key: string;
9
+ /** Cell content or header node (checkboxes render in headers for selection). */
10
+ label: ReactNode;
11
+ sortable?: boolean;
12
+ /** W4 · GOAL-005: render the string fallback single-line truncated with a
13
+ * native title full-text affordance so long values do not crowd out
14
+ * sibling columns. Custom render cells are unaffected. Since the
15
+ * table-style refresh every string cell truncates by default; this flag
16
+ * is kept for schema declarations that opt into the 16rem cap. */
17
+ truncate?: boolean;
18
+ /** Column width hint (px number or CSS length). Content-driven auto layout
19
+ * otherwise; a column that declares a width skips the default max-width
20
+ * cap so it can exceed it (table-layout auto still grows on content). */
21
+ width?: number | string;
22
+ /** Minimum column width (px number or CSS length). */
23
+ minWidth?: number | string;
24
+ render?: (row: T) => ReactNode;
25
+ }
26
+ export interface DataTableProps<T> {
27
+ columns: DataTableColumn<T>[];
28
+ rows: T[];
29
+ rowKey: (row: T) => string;
30
+ sort?: SortState;
31
+ onSortChange?: (sort: SortState | null) => void;
32
+ loading?: boolean;
33
+ error?: string | null;
34
+ emptyMessage?: string;
35
+ caption?: string;
36
+ /** Invoked when a data row is clicked (row selection, S4 · GOAL-007). */
37
+ onRowClick?: (row: T) => void;
38
+ /** Row key of the currently selected row (highlight), S4 · GOAL-007. */
39
+ selectedKey?: string;
40
+ /** W15-F02: retry control shown in the error state. */
41
+ onRetry?: () => void;
42
+ }
43
+ export declare function DataTable<T>({ columns, rows, rowKey, sort, onSortChange, loading, error, emptyMessage, caption, onRowClick, selectedKey, onRetry, }: DataTableProps<T>): import("react").JSX.Element;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Shared pure state determination for async display regions (S4 · GOAL-004).
3
+ *
4
+ * statCard / chart / list-table each fetch a resource independently and used
5
+ * to invent their own ad-hoc "Loading…" text placeholder. This module
6
+ * centralizes the loading / error / empty / ready decision into one pure,
7
+ * directly-testable function so every consumer renders the same sequence
8
+ * (Skeleton while loading, a `role="alert"` message on error, a muted empty
9
+ * message otherwise) instead of drifting independently.
10
+ */
11
+ export type AsyncDisplayState = "loading" | "error" | "empty" | "ready";
12
+ export interface AsyncDisplayInput {
13
+ /** True while the underlying fetch/request has not yet settled. */
14
+ loading: boolean;
15
+ /** Non-null when the fetch/request failed. */
16
+ error: string | null;
17
+ /** True when the fetch succeeded but produced no renderable rows/points. */
18
+ isEmpty?: boolean;
19
+ }
20
+ /**
21
+ * Resolves the single display state a region should show.
22
+ *
23
+ * Precedence: `error` wins over `loading` (a failed fetch is not "still
24
+ * loading" even if a stale loading flag lingers), and `loading` wins over
25
+ * `isEmpty` (emptiness is unknown until the fetch settles).
26
+ */
27
+ export declare function resolveAsyncDisplayState({ loading, error, isEmpty, }: AsyncDisplayInput): AsyncDisplayState;
@@ -0,0 +1,9 @@
1
+ import * as React from "react";
2
+ import { type VariantProps } from "class-variance-authority";
3
+ declare const badgeVariants: (props?: ({
4
+ variant?: "default" | "secondary" | "destructive" | "success" | "outline" | null | undefined;
5
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
+ export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
7
+ }
8
+ declare function Badge({ className, variant, ...props }: BadgeProps): React.JSX.Element;
9
+ export { Badge, badgeVariants };
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Breadcrumb navigation for nested admin pages (GOAL-015).
3
+ *
4
+ * Semantic hierarchy, not visit history (user ruling 2026-08-14):
5
+ * the trail is the page's place in the manifest navigation tree
6
+ * (slot → group labels → page) plus consumer-declared parents for
7
+ * inner pages reached by row navigation (e.g. dictionary-entries →
8
+ * data-dictionary, task-runs → scheduled-tasks). No protocol change:
9
+ * the parent map is a web-shell declaration (BREADCRUMB_PAGE_PARENTS).
10
+ *
11
+ * Trail shape: 首页 => 一级页 => ... => n级内页 — the home page
12
+ * (manifest homePageRef, the domain-root default) always leads, then nav
13
+ * group labels and declared parents, then the current page. Visual: compact
14
+ * 12px trail — muted clickable ancestors (hover brighten + underline), thin
15
+ * "/" separators, brighter non-clickable current item, and an optional
16
+ * small circular ghost back button (semantic parent) at the far left.
17
+ */
18
+ import { type MessageParams } from "@/i18n/catalog";
19
+ export interface BreadcrumbEntry {
20
+ /** Page id (manifest pageId); group labels use the label text as key. */
21
+ pageId: string;
22
+ label: string;
23
+ /** Application route of this ancestor; empty for group labels. */
24
+ route: string;
25
+ /** True for the current (deepest) page. */
26
+ current: boolean;
27
+ }
28
+ export interface BreadcrumbPage {
29
+ pageId: string;
30
+ title?: string;
31
+ titleKey?: string;
32
+ route: string;
33
+ }
34
+ interface BreadcrumbNavItem {
35
+ pageRef?: string;
36
+ label?: string;
37
+ labelKey?: string;
38
+ items?: BreadcrumbNavItem[];
39
+ }
40
+ export declare function Breadcrumbs({ entries, onNavigate, onBack, showBack, }: {
41
+ entries: BreadcrumbEntry[];
42
+ onNavigate: (route: string) => void;
43
+ onBack: () => void;
44
+ /** Compact circular ghost back button (semantic parent), far left. */
45
+ showBack?: boolean;
46
+ }): import("react").JSX.Element | null;
47
+ /**
48
+ * Resolves the SEMANTIC breadcrumb trail for a matched page.
49
+ *
50
+ * Sources, in order:
51
+ * 1. manifest navigation tree — a page rendered under a group shows the
52
+ * group labels as non-clickable ancestors (outermost first);
53
+ * 2. declared parents (options.parents) — inner pages reached by row
54
+ * navigation declare their parent pageId; the chain walks up until a
55
+ * page with no declared parent (its nav group chain, if any, is
56
+ * included). Unknown declared parents fail safe (skipped).
57
+ * 3. pages not in the tree and without a declared parent are
58
+ * single-level (no trail UI).
59
+ *
60
+ * This is NOT the visit history: the same page always shows the same
61
+ * trail regardless of how the user got there (user ruling 2026-08-14).
62
+ */
63
+ export declare function resolveBreadcrumbTrail(pages: BreadcrumbPage[], currentPage: BreadcrumbPage | undefined, t: (key: string, params?: MessageParams, literalFallback?: string) => string, options?: {
64
+ navigation?: {
65
+ top?: BreadcrumbNavItem[];
66
+ sidebar?: BreadcrumbNavItem[];
67
+ user?: BreadcrumbNavItem[];
68
+ };
69
+ /** Consumer-declared parent pageId per inner page (web-shell level). */
70
+ parents?: Record<string, string>;
71
+ /**
72
+ * Home pageId (manifest app.homePageRef — the domain-root default page,
73
+ * not necessarily the dashboard). The trail ALWAYS starts with it:
74
+ * 首页 => 一级页 => ... => n级内页 (user spec 2026-08-14).
75
+ */
76
+ homePageId?: string;
77
+ }): BreadcrumbEntry[];
78
+ export {};
@@ -0,0 +1,11 @@
1
+ import * as React from "react";
2
+ import { type VariantProps } from "class-variance-authority";
3
+ declare const buttonVariants: (props?: ({
4
+ variant?: "default" | "secondary" | "outline" | "ghost" | null | undefined;
5
+ size?: "default" | "sm" | "lg" | null | undefined;
6
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
+ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
8
+ asChild?: boolean;
9
+ }
10
+ declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
11
+ export { Button, buttonVariants };
@@ -0,0 +1,8 @@
1
+ import * as React from "react";
2
+ declare const Card: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
3
+ declare const CardHeader: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
4
+ declare const CardTitle: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLHeadingElement> & React.RefAttributes<HTMLParagraphElement>>;
5
+ declare const CardDescription: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>>;
6
+ declare const CardContent: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
7
+ declare const CardFooter: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
8
+ export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @schema-ui/ui 聚合导出:设计系统原子 + DataTable 核心(R3 六包化)。
3
+ */
4
+ export * from "./async-state";
5
+ export * from "./badge";
6
+ export * from "./breadcrumbs";
7
+ export * from "./button";
8
+ export * from "./card";
9
+ export * from "./input";
10
+ export * from "./label";
11
+ export * from "./skeleton";
12
+ export * from "./textarea";
13
+ export * from "../data-table";
@@ -0,0 +1,5 @@
1
+ import * as React from "react";
2
+ export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
3
+ }
4
+ declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
5
+ export { Input };
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare const Label: React.ForwardRefExoticComponent<React.LabelHTMLAttributes<HTMLLabelElement> & React.RefAttributes<HTMLLabelElement>>;
3
+ export { Label };
@@ -0,0 +1,2 @@
1
+ declare function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): import("react").JSX.Element;
2
+ export { Skeleton };
@@ -0,0 +1,5 @@
1
+ import * as React from "react";
2
+ export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
3
+ }
4
+ declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>;
5
+ export { Textarea };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Translation catalog (S1 · C2/C3).
3
+ *
4
+ * Catalogs are pure data files under `messages/`; `en-US` is the canonical
5
+ * baseline. Resolution order for a key in locale L:
6
+ *
7
+ * catalog[L] → catalog[en-US] → observable missing-key event → key itself
8
+ *
9
+ * A key is "missing" only when neither the current catalog nor the en-US
10
+ * catalog has it; the en-US fallback is silent (designed behavior). Missing
11
+ * keys never render empty, never throw, and never block the flow; they are
12
+ * observable via the `schema-ui:missing-translation` window event (deduped
13
+ * per locale+key, so the first occurrence always reports).
14
+ */
15
+ import { type Locale } from "./locale";
16
+ export type MessageParams = Record<string, string | number>;
17
+ export interface MissingTranslationDetail {
18
+ locale: Locale;
19
+ key: string;
20
+ /** Optional rendering context (e.g. "nav.sidebar", "page.users.form"). */
21
+ path?: string;
22
+ }
23
+ export declare const MISSING_TRANSLATION_EVENT = "schema-ui:missing-translation";
24
+ /** True when the key exists in the given locale catalog. */
25
+ export declare function hasTranslation(key: string, locale: Locale): boolean;
26
+ /** Raw catalog text for a key, or null when the locale catalog lacks it. */
27
+ export declare function lookupTranslation(key: string, locale: Locale): string | null;
28
+ /** Replaces `{name}` placeholders with params; unknown placeholders stay. */
29
+ export declare function interpolate(template: string, params?: MessageParams): string;
30
+ /** Publishes a deduped missing-key report to the window event bus. */
31
+ export declare function reportMissingTranslation(detail: MissingTranslationDetail): void;
32
+ /** Resets the missing-key dedupe set (test seam). */
33
+ export declare function resetMissingTranslationReports(): void;
34
+ /**
35
+ * Resolves a message key for a locale with the frozen fallback chain.
36
+ * Never throws, never returns an empty string for a missing key.
37
+ *
38
+ * Fallback order: catalog[locale] → catalog[en-US] → `literalFallback`
39
+ * (protocol literal text, when supplied) → key itself.
40
+ */
41
+ export declare function translate(key: string, params?: MessageParams, locale?: Locale, path?: string, literalFallback?: string): string;
42
+ /** Binds a locale (+ optional context path) to a translate function. */
43
+ export declare function createTranslator(locale: Locale, options?: {
44
+ path?: string;
45
+ }): (key: string, params?: MessageParams, literalFallback?: string) => string;
46
+ /**
47
+ * Resolves a schema/manifest text prop pair — the `*Key` field wins over the
48
+ * literal protocol text, and the literal text is the last fallback before the
49
+ * key itself (frozen chain: 当前语种 → en-US → 字面文本 → key).
50
+ */
51
+ export declare function resolveTextProp(props: Record<string, unknown> | undefined, keyProp: string, literalProp: string, t: (key: string, params?: MessageParams, literalFallback?: string) => string, fallback?: string): string;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Locale-aware date/number formatting (S1 · C5).
3
+ *
4
+ * Formatting follows the effective locale through Intl.* — no custom format
5
+ * templates (VP-007: "首版不暴露任意日期/数字格式模板,随有效 locale").
6
+ * Formatting is fail-safe: invalid inputs render empty, invalid timezones
7
+ * degrade to the locale's default zone instead of throwing.
8
+ */
9
+ import { type Locale } from "./locale";
10
+ export interface FormatOptions {
11
+ /** IANA timezone name; omitted = the environment's default zone. */
12
+ timeZone?: string;
13
+ }
14
+ /** Formats a date value in the given locale. Returns "" for invalid input. */
15
+ export declare function formatDate(value: Date | string | number, locale?: Locale, options?: FormatOptions): string;
16
+ /** Formats a finite number in the given locale. Returns "" for invalid input. */
17
+ export declare function formatNumber(value: number, locale?: Locale, options?: Intl.NumberFormatOptions): string;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Locale pure-logic unit (S1 · C1).
3
+ *
4
+ * `resolveLocale` is a side-effect-free function that computes the effective
5
+ * locale from the user's explicit choice, the system default, and the browser
6
+ * language preferences. Keeping the decision logic in a plain function lets
7
+ * vitest exercise every branch without a browser.
8
+ *
9
+ * Frozen priority (VP-007 / D-002 §I-L10N-002, user-confirmed 2026-08-09):
10
+ *
11
+ * user explicit choice → system default (non-auto) → browser preference
12
+ * (auto) → en-US safe fallback
13
+ */
14
+ export declare const SUPPORTED_LOCALES: readonly ["zh-CN", "en-US"];
15
+ export type Locale = (typeof SUPPORTED_LOCALES)[number];
16
+ /** The user-facing choice; "auto" defers to system/browser preference. */
17
+ export type LocalePreference = Locale | "auto";
18
+ export declare const DEFAULT_LOCALE: Locale;
19
+ export interface LocaleResolutionInput {
20
+ /**
21
+ * localStorage["schema-ui:locale"] — the user's explicit choice.
22
+ * null / undefined / invalid → no explicit choice.
23
+ */
24
+ stored: string | null;
25
+ /**
26
+ * System default from the public bootstrap (/api/branding defaultLocale).
27
+ * "auto" or null → no system default.
28
+ */
29
+ systemDefault: string | null;
30
+ /** Browser language preferences in order (navigator.languages). */
31
+ browserLanguages: readonly string[];
32
+ }
33
+ export declare function isSupportedLocale(raw: string | null | undefined): raw is Locale;
34
+ /**
35
+ * Normalizes a BCP 47-ish candidate to a supported locale.
36
+ * Accepts exact tags, case variants, underscore separators, and language-only
37
+ * prefixes ("zh", "zh-cn", "zh_CN", "en-US", "en", "en-us", "en-GB" → en-US).
38
+ * Returns null for anything else (including "auto").
39
+ */
40
+ export declare function normalizeLocaleCandidate(raw: string | null | undefined): Locale | null;
41
+ /**
42
+ * Resolves the effective locale using the frozen priority. Pure — no I/O.
43
+ */
44
+ export declare function resolveLocale(input: LocaleResolutionInput): Locale;
45
+ /**
46
+ * Normalizes a raw stored value into a LocalePreference.
47
+ * Any value that is not a supported locale resolves to "auto".
48
+ */
49
+ export declare function normalizePreference(raw: string | null | undefined): LocalePreference;
50
+ /** Real browser inputs for the boot path (provider default). */
51
+ export declare function defaultBrowserLanguages(): readonly string[];
@@ -0,0 +1,90 @@
1
+ /**
2
+ * I18n React runtime (S1 · C4/C5).
3
+ *
4
+ * - Resolves the effective locale via `resolveLocale` (frozen priority).
5
+ * - Persists the user's explicit choice in localStorage["schema-ui:locale"]
6
+ * (single channel, same pattern as the theme mechanism; login/logout never
7
+ * clears it — D-002 §I-L10N-002).
8
+ * - Applies `document.documentElement.lang` on locale change.
9
+ * - Exposes `t` / `formatDate` / `formatNumber` to components.
10
+ */
11
+ import { type ReactNode } from "react";
12
+ import { type MessageParams } from "./catalog";
13
+ import { type Locale, type LocalePreference } from "./locale";
14
+ import { type TimezonePreference } from "./timezone";
15
+ export declare const LOCALE_STORAGE_KEY = "schema-ui:locale";
16
+ export declare function readStoredLocale(): string | null;
17
+ export declare function writeStoredLocale(preference: LocalePreference): void;
18
+ /** Applies the effective locale to <html lang>. No-op outside a browser. */
19
+ export declare function applyLocaleToDocument(locale: Locale): void;
20
+ /** Returns the provider's currently effective locale (defaults en-US). */
21
+ export declare function getActiveLocale(): Locale;
22
+ /** Internal: keeps the registry in sync with the provider's effective locale. */
23
+ export declare function setActiveLocale(locale: Locale): void;
24
+ export interface I18nState {
25
+ /** Effective (resolved) locale — always a supported locale. */
26
+ locale: Locale;
27
+ /** User preference; "auto" defers to system/browser defaults. */
28
+ preference: LocalePreference;
29
+ /** Sets the user preference and persists it (localStorage single channel). */
30
+ setPreference: (preference: LocalePreference) => void;
31
+ /** Effective timezone (IANA name or "auto" per contract §2 / L1–L4). */
32
+ timezone: string;
33
+ /** User timezone preference; "auto" defers to session/site defaults. */
34
+ timezonePreference: TimezonePreference;
35
+ /** Sets the user timezone preference and persists it (single channel). */
36
+ setTimezonePreference: (preference: TimezonePreference) => void;
37
+ /**
38
+ * Site-wide default currency (ISO 4217 from /api/branding; "" = unset).
39
+ * Money consumers use this as the explicit currency before falling back
40
+ * to the embedded per-locale map (contract §4.1 / §4.3).
41
+ */
42
+ defaultCurrency: string;
43
+ /** Translate a catalog key with the effective locale. */
44
+ t: (key: string, params?: MessageParams) => string;
45
+ /** Locale-aware date formatting (defaults to the effective timezone). */
46
+ formatDate: (value: Date | string | number, options?: {
47
+ timeZone?: string;
48
+ }) => string;
49
+ /** Locale-aware number formatting. */
50
+ formatNumber: (value: number, options?: Intl.NumberFormatOptions) => string;
51
+ }
52
+ export interface I18nProviderProps {
53
+ children: ReactNode;
54
+ /** System default locale from the public bootstrap; null/"auto" = none. */
55
+ systemDefault?: string | null;
56
+ /** Test seam: explicit stored preference (defaults to localStorage). */
57
+ stored?: string | null;
58
+ /** Test seam: browser language list (defaults to navigator.languages). */
59
+ browserLanguages?: readonly string[];
60
+ /**
61
+ * Site default timezone from /api/branding (contract §2 · L3). The provider
62
+ * also captures it from `systemDefaultUrl` when present; this prop wins.
63
+ */
64
+ siteTimezone?: string | null;
65
+ /** Test seam: explicit stored timezone preference (defaults to localStorage). */
66
+ storedTimezone?: string | null;
67
+ /** Test seam: session timezone probe (defaults to detectBrowserTimezone). */
68
+ detectTimezone?: () => string;
69
+ /** Site default currency (ISO 4217); test seam for /api/branding. */
70
+ siteDefaultCurrency?: string | null;
71
+ /**
72
+ * When set, the provider fetches this public startup endpoint once and
73
+ * re-resolves the system default locale from `defaultLocale` (VP-007 S3:
74
+ * the shell/login apply the site-wide default when the user has no
75
+ * explicit choice) and the site default timezone from `siteTimezone`
76
+ * (workspace-020 · contract §2 · L3). Applies after the initial resolve.
77
+ */
78
+ systemDefaultUrl?: string;
79
+ }
80
+ export declare function I18nProvider({ children, systemDefault, stored, browserLanguages, siteTimezone, storedTimezone, detectTimezone, siteDefaultCurrency, systemDefaultUrl, }: I18nProviderProps): import("react").JSX.Element;
81
+ export declare function useI18n(): I18nState;
82
+ /**
83
+ * Tolerant translator hook for deep renderer internals.
84
+ *
85
+ * Returns the provider's translator, or a safe default (en-US resolution +
86
+ * missing-key observable fallback) when no provider is mounted. Production
87
+ * always mounts I18nProvider; bare component tests and pre-provider surfaces
88
+ * degrade to the documented safe fallback instead of throwing.
89
+ */
90
+ export declare function useTranslate(): (key: string, params?: MessageParams) => string;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Timezone pure-logic unit (workspace-020 · R2 · C1).
3
+ *
4
+ * `resolveEffectiveTimezone` computes the effective timezone from the user's
5
+ * explicit override, the session probe, and the site default, per contract
6
+ * GOAL-002 D-001 §2 (user-confirmed I-001, 2026-08-26):
7
+ *
8
+ * L1 user override (localStorage "schema-ui:timezone") → L2 session probe
9
+ * (Intl) → L3 site default (siteTimezone) → L4 "auto" fallback
10
+ *
11
+ * Keeping the decision logic in plain functions lets vitest exercise every
12
+ * branch; the probe is injectable so tests do not depend on the host zone.
13
+ */
14
+ export declare const TIMEZONE_STORAGE_KEY = "schema-ui:timezone";
15
+ export declare const AUTO_TIMEZONE = "auto";
16
+ /** The user-facing choice; a timezone IANA name or "auto". */
17
+ export type TimezonePreference = string | "auto";
18
+ export interface TimezoneResolutionInput {
19
+ /**
20
+ * localStorage["schema-ui:timezone"] — the user's explicit override.
21
+ * null / undefined / invalid / "auto" → no override (skip to L2).
22
+ */
23
+ stored: string | null;
24
+ /**
25
+ * Site default from the public bootstrap (/api/branding siteTimezone).
26
+ * "auto" / "" / null → unset (skip to L4 when L2 is empty).
27
+ */
28
+ siteDefault: string | null;
29
+ /**
30
+ * Session probe of the host zone (injectable; real default is
31
+ * `detectBrowserTimezone`). Invalid or empty results are skipped.
32
+ */
33
+ detect: () => string;
34
+ }
35
+ /**
36
+ * Validates an IANA timezone name via Intl (RangeError on invalid names).
37
+ * Side-effect-free apart from the noexcept Intl probe; returns false for
38
+ * empty / non-string / unknown zones instead of throwing.
39
+ */
40
+ export declare function isValidIanaTimeZone(raw: string | null | undefined): raw is string;
41
+ /**
42
+ * Normalizes a raw stored/site value into a TimezonePreference.
43
+ * Any value that is not a valid IANA name resolves to "auto".
44
+ */
45
+ export declare function normalizeTimezonePreference(raw: string | null | undefined): TimezonePreference;
46
+ /** Reads the stored user override; best-effort (privacy mode → null). */
47
+ export declare function readStoredTimezone(): string | null;
48
+ /** Persists the user override; "auto" removes the key (single channel). */
49
+ export declare function writeStoredTimezone(preference: TimezonePreference): void;
50
+ /** Real session probe: the host zone from Intl.resolvedOptions(). */
51
+ export declare function detectBrowserTimezone(): string;
52
+ /**
53
+ * Resolves the effective timezone per contract §2 (L1 → L2 → L3 → L4).
54
+ * Returns an IANA name, or "auto" when nothing is configured/detectable —
55
+ * consumers then fall back to the locale's default zone.
56
+ */
57
+ export declare function resolveEffectiveTimezone(input: TimezoneResolutionInput): string;