/** App shell prop types — @see docs/COMPONENTS.md#app */ import type { Locale } from "date-fns"; import type { DayPickerProps } from "react-day-picker"; import type { AppLocale, AppRequestHeaders, AppTimeFormat, AppTimezone, AppTimezoneDefault, AppDateFormat } from "../../app/types.js"; import type { AppBrand, AppDensity, AppFontSize, AppTheme } from "../../app/theme-axes.js"; import type { AppPreferenceAxis } from "../../app/storage.js"; import type { AppSettingPickerAppearanceProp, AppSettingToggleAppearanceProp, ChildrenProp, ClassNameProp, DisabledProp, IdProp, NameProp, OnValueChangeProp, ValueProp } from "../vocabulary/index.js"; /** @see AppProvider */ export type AppProviderProp = { children: ChildrenProp; /** Initial locale when nothing in storage. Default: `vi`. */ defaultLocale?: AppLocale; /** Fallback when a translation key is missing. Default: `en`. */ fallbackLocale?: AppLocale; /** Initial timezone: IANA id, `browser`, or `system`. Default: `browser`. */ defaultTimezone?: AppTimezoneDefault; /** Backend/system timezone when `defaultTimezone` is `system`. */ systemTimezone?: AppTimezone; /** Initial clock format. `"locale"` derives from `defaultLocale`. */ defaultTimeFormat?: AppTimeFormat | "locale"; /** Initial date display format. `"locale"` derives from `defaultLocale`. */ defaultDateFormat?: AppDateFormat | "locale"; /** * IANA ids offered by the timezone-picker recipe (`useAppContext().timezoneOptions`). Omit for * the full IANA list; set to restrict (e.g. */ timezoneOptions?: readonly AppTimezone[]; /** localStorage key. Default: `godxjp.app`. */ storageKey?: string; /** * Which viewer preferences survive a reload. `true` (default) every axis, `false` none, or a * LIST of axes — `["theme", "density", "fontSize"]`. * * The list exists because the axes do not share an owner. `theme` / `brand` / `density` / * `fontSize` / `scaling` are the VIEWER's and belong in this browser. `locale` / `timezone` / * `timeFormat` / `dateFormat` are frequently the SERVER's, resolved per request from a cookie, * an account row or a header — and a stored copy then WINS over the value the server just sent, * because storage is read after the props. Faced with one all-or-nothing flag, that consumer * sets `persist={false}` and loses the viewer's theme along with it; naming the axes keeps both. */ persist?: boolean | readonly AppPreferenceAxis[]; /** * Initial theme choice. `"light"` / `"dark"` are written straight to ``; * `"system"` defers to `prefers-color-scheme` and is re-resolved whenever the OS changes. * Default: `"light"`. */ theme?: AppTheme; /** * Initial brand palette preset — written to ``. OPT-IN: omit * (or `null`) to keep the brand `--primary` your own `theme.css` defines. */ brand?: AppBrand | null; /** Initial density — written to ``. Default: `"default"`. */ density?: AppDensity; /** Initial base type size — written to ``. Default: `"default"`. */ fontSize?: AppFontSize; /** * Continuous global size multiplier — sets inline `--scaling` on ``. Every size token * (spacing, control/table/checkbox/switch heights, radius) rescales in proportion (Radix-style). */ scaling?: number | null; /** * Emit a native `name` on every control a `FormField` wraps, taken from the field's key (`field` * → `name` → `id`). `data-field` is inert metadata and is always emitted; `name` is NOT — it * changes what a native `