111 lines
3.7 KiB
TypeScript
111 lines
3.7 KiB
TypeScript
export type VMStatus = "idle" | "loading" | "ready" | "empty" | "error";
|
|
|
|
export type VMState<T> =
|
|
| { status: "idle"; data?: undefined; error?: undefined }
|
|
| { status: "loading"; data?: T; error?: undefined }
|
|
| { status: "ready"; data: T; error?: undefined }
|
|
| { status: "empty"; data?: undefined; error?: undefined }
|
|
| { status: "error"; data?: T; error: { messageKey: string; code?: string } };
|
|
|
|
export type ActionCallbacks<T> = {
|
|
readonly onCreate?: (draft?: Partial<T>) => void | Promise<void>;
|
|
readonly onUpdate?: (item: T) => void | Promise<void>;
|
|
readonly onDelete?: (item: T) => void | Promise<void>;
|
|
readonly onRefresh?: () => void | Promise<void>;
|
|
};
|
|
|
|
export type I18nLabel = {
|
|
readonly labelKey: string;
|
|
readonly descriptionKey?: string;
|
|
};
|
|
|
|
export type RegistryGate = {
|
|
readonly permission?: string;
|
|
readonly flag?: string;
|
|
};
|
|
|
|
export type SidebarRegistryItem = I18nLabel &
|
|
RegistryGate & {
|
|
readonly id: string;
|
|
readonly href: string;
|
|
readonly icon?: string;
|
|
readonly children?: readonly SidebarRegistryItem[];
|
|
};
|
|
|
|
export type BreadcrumbRegistryItem = I18nLabel &
|
|
RegistryGate & {
|
|
readonly id: string;
|
|
readonly href?: string;
|
|
};
|
|
|
|
export type MobileRegistryItem = I18nLabel &
|
|
RegistryGate & {
|
|
readonly id: string;
|
|
readonly href: string;
|
|
readonly priority?: number;
|
|
};
|
|
|
|
export type PortalRegistryItem = I18nLabel &
|
|
RegistryGate & {
|
|
readonly id: string;
|
|
readonly slot: string;
|
|
readonly order?: number;
|
|
};
|
|
|
|
export type ShellRegistries = {
|
|
readonly sidebar?: readonly SidebarRegistryItem[];
|
|
readonly breadcrumbs?: readonly BreadcrumbRegistryItem[];
|
|
readonly mobile?: readonly MobileRegistryItem[];
|
|
readonly portals?: readonly PortalRegistryItem[];
|
|
};
|
|
|
|
// --- Subframe-Adapter contract (M015) ---
|
|
/** Swappable UI implementation: renders a serializable component model to HTML. */
|
|
export type UiRenderer<Model> = (model: Model) => string;
|
|
|
|
export type DataTableColumn = I18nLabel & { readonly key: string; readonly align?: "left" | "right" | "center" };
|
|
export type DataTableRow = { readonly id: string; readonly cells: Readonly<Record<string, string>> };
|
|
/** Domain View-Model a loader builds for a tabular list. */
|
|
export type DataTableVM = {
|
|
readonly caption?: I18nLabel;
|
|
readonly columns: readonly DataTableColumn[];
|
|
readonly rows: readonly DataTableRow[];
|
|
readonly emptyLabelKey?: string;
|
|
};
|
|
/** Normalized component prop-model the UI implementation renders. */
|
|
export type DataTableModel = {
|
|
readonly captionKey?: string;
|
|
readonly columns: readonly { readonly key: string; readonly labelKey: string; readonly align: "left" | "right" | "center" }[];
|
|
readonly rows: readonly DataTableRow[];
|
|
readonly emptyLabelKey: string;
|
|
readonly rowCount: number;
|
|
};
|
|
|
|
export function ready<T>(data: T): VMState<T> {
|
|
return { status: "ready", data };
|
|
}
|
|
|
|
export function empty<T>(): VMState<T> {
|
|
return { status: "empty" };
|
|
}
|
|
|
|
export function assertI18nLabel(label: I18nLabel): I18nLabel {
|
|
if (!/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/.test(label.labelKey)) {
|
|
throw new Error(`Registry labels must use i18n keys: ${label.labelKey}`);
|
|
}
|
|
if (label.descriptionKey && !/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/.test(label.descriptionKey)) {
|
|
throw new Error(`Registry descriptions must use i18n keys: ${label.descriptionKey}`);
|
|
}
|
|
return label;
|
|
}
|
|
|
|
// Domain View-Models (M013-Konvention: src/<domain>/*.vm.ts)
|
|
export * from "./walking-skeleton/walking-skeleton.vm.js";
|
|
export * from "./auth/session-list.vm.js";
|
|
export * from "./auth/select-tenant.vm.js";
|
|
export * from "./files/file-browser.vm.js";
|
|
export * from "./files/file-detail.vm.js";
|
|
export * from "./files/file-upload.vm.js";
|
|
export * from "./tasks/task-list.vm.js";
|
|
export * from "./tasks/task-detail.vm.js";
|