@karni/ui 0.3.1 → 0.4.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.
- package/README.md +712 -72
- package/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +8660 -4725
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +18 -1
- package/dist/script-BVJ9BbPm.cjs +2 -0
- package/dist/script-BVJ9BbPm.cjs.map +1 -0
- package/dist/script-D1fn4Dm4.js +6 -0
- package/dist/script-D1fn4Dm4.js.map +1 -0
- package/dist/src/auth/AuthGuard.d.ts +69 -4
- package/dist/src/auth/LoginForm.d.ts +41 -7
- package/dist/src/auth/engine.d.ts +15 -13
- package/dist/src/auth/provider.d.ts +10 -10
- package/dist/src/auth/storage.d.ts +1 -1
- package/dist/src/auth/types.d.ts +3 -3
- package/dist/src/components/brand/karni-mark.d.ts +4 -4
- package/dist/src/components/chart/data-chart.d.ts +66 -11
- package/dist/src/components/empty-state/empty-state.d.ts +22 -2
- package/dist/src/components/file-upload/FileUpload.d.ts +67 -3
- package/dist/src/components/layout/layout.d.ts +104 -9
- package/dist/src/components/layout/route-focus.d.ts +43 -0
- package/dist/src/components/modal/modal.d.ts +49 -8
- package/dist/src/components/page/page.d.ts +36 -5
- package/dist/src/components/primitives/button.d.ts +1 -0
- package/dist/src/components/primitives/checkbox.d.ts +4 -1
- package/dist/src/components/primitives/dropdown-menu.d.ts +1 -1
- package/dist/src/components/primitives/icons.d.ts +9 -1
- package/dist/src/components/primitives/input.d.ts +4 -1
- package/dist/src/components/primitives/label.d.ts +4 -1
- package/dist/src/components/primitives/select.d.ts +37 -6
- package/dist/src/components/primitives/skeleton.d.ts +4 -1
- package/dist/src/components/primitives/switch.d.ts +4 -1
- package/dist/src/components/primitives/tabs.d.ts +2 -2
- package/dist/src/components/primitives/textarea.d.ts +4 -1
- package/dist/src/components/resource/ResourceDetail.d.ts +3 -3
- package/dist/src/components/resource/ResourceForm.d.ts +4 -3
- package/dist/src/components/resource/ResourceSelect.d.ts +3 -1
- package/dist/src/components/resource/ResourceTable.d.ts +9 -3
- package/dist/src/components/resource/audit-fields.d.ts +1 -1
- package/dist/src/components/resource/detail/ResourceDetail.d.ts +109 -11
- package/dist/src/components/resource/empty-value.d.ts +17 -0
- package/dist/src/components/resource/form/ResourceForm.d.ts +65 -6
- package/dist/src/components/resource/form/field-inputs.d.ts +15 -1
- package/dist/src/components/resource/form/form-states.d.ts +87 -0
- package/dist/src/components/resource/form/prepare.d.ts +3 -3
- package/dist/src/components/resource/form/server-errors.d.ts +14 -0
- package/dist/src/components/resource/history/ChangeHistory.d.ts +46 -4
- package/dist/src/components/resource/import/ResourceImport.d.ts +73 -7
- package/dist/src/components/resource/nouns.d.ts +12 -0
- package/dist/src/components/resource/query-state.d.ts +20 -0
- package/dist/src/components/resource/resource-names.d.ts +23 -0
- package/dist/src/components/resource/select/ResourceSelect.d.ts +39 -8
- package/dist/src/components/resource/select/select-states.d.ts +68 -0
- package/dist/src/components/resource/select/use-option-pages.d.ts +37 -0
- package/dist/src/components/resource/select/venue-backend.d.ts +144 -0
- package/dist/src/components/resource/table/BulkActionsBar.d.ts +62 -5
- package/dist/src/components/resource/table/CardList.d.ts +31 -0
- package/dist/src/components/resource/table/ConfirmDialog.d.ts +28 -0
- package/dist/src/components/resource/table/ExportButtons.d.ts +2 -2
- package/dist/src/components/resource/table/FilterBar.d.ts +3 -3
- package/dist/src/components/resource/table/PaginationControls.d.ts +15 -3
- package/dist/src/components/resource/table/ResourceTable.d.ts +79 -14
- package/dist/src/components/resource/table/RowCard.d.ts +31 -0
- package/dist/src/components/resource/table/TableView.d.ts +29 -0
- package/dist/src/components/resource/table/ViewOptions.d.ts +19 -0
- package/dist/src/components/resource/table/access.d.ts +12 -0
- package/dist/src/components/resource/table/derive-columns.d.ts +2 -2
- package/dist/src/components/resource/table/grid-navigation.d.ts +23 -0
- package/dist/src/components/resource/table/layout.d.ts +37 -0
- package/dist/src/components/resource/table/preferences.d.ts +12 -0
- package/dist/src/components/resource/table/slots.d.ts +41 -0
- package/dist/src/components/resource/table/states.d.ts +91 -0
- package/dist/src/components/resource/table/story-fixtures.d.ts +25 -0
- package/dist/src/components/resource/table/structural-columns.d.ts +25 -0
- package/dist/src/components/resource/table/table-icons.d.ts +16 -0
- package/dist/src/components/resource/table/table-utils.d.ts +27 -3
- package/dist/src/components/resource/table/url-state.d.ts +67 -0
- package/dist/src/components/resource/table/use-container-width.d.ts +10 -0
- package/dist/src/components/resource/testapp-fixtures.d.ts +78 -0
- package/dist/src/components/stat/stat.d.ts +36 -6
- package/dist/src/components/toast/toast-store.d.ts +1 -1
- package/dist/src/components/toast/toaster.d.ts +39 -6
- package/dist/src/components/toast/use-toast.d.ts +1 -1
- package/dist/src/hooks/keys.d.ts +4 -4
- package/dist/src/hooks/multipart.d.ts +9 -9
- package/dist/src/hooks/params.d.ts +1 -1
- package/dist/src/hooks/types.d.ts +3 -3
- package/dist/src/hooks/useChangeHistory.d.ts +3 -2
- package/dist/src/hooks/useResourceImport.d.ts +2 -2
- package/dist/src/hooks/useResourceMutations.d.ts +2 -2
- package/dist/src/hooks/useUnsavedChangesGuard.d.ts +31 -0
- package/dist/src/index.d.ts +49 -31
- package/dist/src/lib/roles.d.ts +4 -4
- package/dist/src/lib/variants.d.ts +1 -1
- package/dist/src/primitives/registry.d.ts +81 -0
- package/dist/src/schema/client.d.ts +10 -10
- package/dist/src/schema/parse.d.ts +2 -2
- package/dist/src/schema/provider.d.ts +10 -3
- package/dist/src/schema/types.d.ts +18 -9
- package/dist/src/schema/useSchema.d.ts +5 -1
- package/dist/src/states/ErrorState.d.ts +43 -0
- package/dist/src/states/PendingButton.d.ts +16 -0
- package/dist/src/states/describe-error.d.ts +25 -0
- package/dist/src/states/hooks.d.ts +10 -0
- package/dist/src/theme/script.d.ts +12 -0
- package/dist/src/theme/theme.d.ts +45 -0
- package/dist/styles.css +174 -13
- package/dist/tailwind-preset.cjs +2 -2
- package/dist/tailwind-preset.cjs.map +1 -1
- package/dist/tailwind-preset.d.ts +83 -1
- package/dist/tailwind-preset.js +181 -62
- package/dist/tailwind-preset.js.map +1 -1
- package/dist/tailwind-v4.css +31 -0
- package/dist/vite-plugin.cjs +2 -0
- package/dist/vite-plugin.cjs.map +1 -0
- package/dist/vite-plugin.d.ts +19 -0
- package/dist/vite-plugin.js +16 -0
- package/dist/vite-plugin.js.map +1 -0
- package/eslint-plugin/index.js +4 -0
- package/eslint-plugin/rules/max-page-lines.js +1 -1
- package/eslint-plugin/rules/no-deep-imports.js +1 -1
- package/eslint-plugin/rules/no-direct-http.js +1 -1
- package/eslint-plugin/rules/no-raw-elements.js +1 -1
- package/eslint-plugin/rules/no-style-literals.js +222 -0
- package/eslint-plugin/rules.json +10 -4
- package/package.json +22 -19
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/lib/cn.ts","../src/lib/roles.ts","../src/lib/variants.ts","../src/components/primitives/button.tsx","../src/components/primitives/input.tsx","../src/components/primitives/textarea.tsx","../src/components/primitives/icons.tsx","../src/components/primitives/select.tsx","../src/components/primitives/checkbox.tsx","../src/components/primitives/switch.tsx","../src/components/primitives/label.tsx","../src/components/primitives/tabs.tsx","../src/components/primitives/dropdown-menu.tsx","../src/components/primitives/skeleton.tsx","../src/hooks/params.ts","../src/hooks/keys.ts","../src/schema/provider.tsx","../src/hooks/useResourceList.ts","../src/hooks/multipart.ts","../src/hooks/useResourceMutations.ts","../src/schema/parse.ts","../src/schema/useSchema.ts","../src/components/empty-state/empty-state.tsx","../src/components/resource/audit-fields.ts","../src/components/resource/displayLabel.ts","../src/components/resource/table/BulkActionsBar.tsx","../src/components/resource/table/table-utils.ts","../src/components/resource/table/derive-columns.tsx","../src/hooks/useResourceImport.ts","../src/components/resource/table/ExportButtons.tsx","../src/hooks/useResourceItem.ts","../src/components/resource/select/use-debounced-value.ts","../src/components/resource/select/ResourceSelect.tsx","../src/components/resource/table/FilterBar.tsx","../src/components/resource/table/PaginationControls.tsx","../src/components/resource/table/use-debounced-value.ts","../src/components/resource/table/ResourceTable.tsx","../src/schema/zod.ts","../src/components/file-upload/FileUpload.tsx","../src/components/resource/form/prepare.ts","../src/components/resource/form/field-inputs.tsx","../src/components/resource/form/ResourceForm.tsx","../src/components/resource/detail/ResourceDetail.tsx","../src/hooks/useChangeHistory.ts","../src/components/resource/history/ChangeHistory.tsx","../src/components/resource/import/ResourceImport.tsx","../src/schema/client.ts","../src/auth/engine.ts","../src/auth/storage.ts","../src/auth/provider.tsx","../src/auth/AuthGuard.tsx","../src/auth/LoginForm.tsx","../src/auth/usePermission.ts","../src/components/page/page.tsx","../src/components/brand/mark-paths.ts","../src/components/brand/karni-mark.tsx","../src/components/layout/layout.tsx","../src/components/modal/modal.tsx","../src/components/toast/toast-store.ts","../src/components/toast/use-toast.ts","../src/components/toast/toaster.tsx","../src/components/stat/stat.tsx","../src/components/chart/data-chart.tsx"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merges class names: clsx semantics for conditionals plus tailwind-merge\n * conflict resolution, so consumer-supplied `className` always wins over a\n * component's own Tailwind classes. Every @karni/ui component funnels its\n * `className` prop through this.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Component role registry (enforcement contract §4 + F11).\n *\n * Every top-level component claims a semantic role (\"data-table\",\n * \"resource-form\", …) at module scope. Two components claiming the same role\n * is a conflict: it throws at import time (so vitest and the dev server both\n * surface it) and `scripts/generate-manifest.mjs` fails the build on the same\n * duplicate via a static scan of these call sites.\n *\n * Conventions:\n * - The `role` argument MUST be a string literal — the build-time scan rejects\n * any non-literal first argument.\n * - Same role + same component name is idempotent (modules re-evaluate under\n * HMR and across test files).\n * - Replacing on purpose is explicit and must carry a reason:\n * `{ replace: true, reason: \"<why>\" }` — an empty reason throws.\n * - Under Vite HMR (`import.meta.hot`) an accidental conflict logs a\n * console.error and replaces instead of throwing, so a rename mid-edit does\n * not kill the dev server.\n * - The registry reflects imported modules only (accepted v0.1 trade-off).\n */\n\nexport interface RegisterComponentRoleOptions {\n /** Replace an existing registration on purpose. Requires `reason`. */\n replace?: boolean;\n /** Why the replacement is intentional — required with `replace: true`. */\n reason?: string;\n}\n\nconst registry = new Map<string, string>();\n\n/**\n * `import.meta.hot` is defined by Vite's dev server and undefined in prod\n * builds. Vitest also ships an import.meta.hot stub, but tests must throw on\n * conflicts (F11), so the test environment is explicitly excluded.\n */\nfunction defaultHotDetector(): boolean {\n try {\n const meta = import.meta as ImportMeta & { hot?: unknown; env?: { MODE?: string } };\n if (!meta.hot) return false;\n if (meta.env?.MODE === \"test\") return false;\n if (typeof process !== \"undefined\" && process.env?.VITEST !== undefined) return false;\n return true;\n } catch {\n return false;\n }\n}\n\nlet detectHot: () => boolean = defaultHotDetector;\n\n/**\n * Test-only override for HMR detection; pass `null` to restore the default.\n * Not exported from the package barrel.\n * @internal\n */\nexport function __setHotDetectorForTests(detector: (() => boolean) | null): void {\n detectHot = detector ?? defaultHotDetector;\n}\n\n/**\n * Test-only registry reset. Not exported from the package barrel.\n * @internal\n */\nexport function __resetRoleRegistryForTests(): void {\n registry.clear();\n}\n\n/**\n * Claims a UI role (such as `data-table`) for a component, so a second component with the same role fails the build. The first argument must be a string literal\n * (build-scan convention, F11).\n */\nexport function registerComponentRole(\n role: string,\n component: string,\n options?: RegisterComponentRoleOptions,\n): void {\n if (options?.replace) {\n const reason = options.reason?.trim() ?? \"\";\n if (reason === \"\") {\n throw new Error(\n `[karni] registerComponentRole: replacing role \"${role}\" requires a non-empty reason — ` +\n `pass { replace: true, reason: \"<why>\" }.`,\n );\n }\n const previous = registry.get(role);\n if (previous !== undefined && previous !== component) {\n console.warn(\n `[karni] component role \"${role}\" replaced: \"${previous}\" -> \"${component}\" (${reason})`,\n );\n }\n registry.set(role, component);\n return;\n }\n\n const existing = registry.get(role);\n if (existing === undefined || existing === component) {\n // Idempotent: first registration, or the same component re-registering.\n registry.set(role, component);\n return;\n }\n\n const message =\n `[karni] duplicate component role \"${role}\": already registered by \"${existing}\", now ` +\n `claimed by \"${component}\". Compose or extend the existing component instead, or replace ` +\n `it on purpose with { replace: true, reason: \"<why>\" }.`;\n\n if (detectHot()) {\n // Dev HMR: a module re-evaluating mid-rename must not kill the app.\n console.error(message);\n registry.set(role, component);\n return;\n }\n throw new Error(message);\n}\n\n/** Snapshot of the current registry ({ role: component }) for tooling. */\nexport function getRoleRegistry(): Readonly<Record<string, string>> {\n return Object.freeze(Object.fromEntries(registry));\n}\n","import { cn } from \"./cn\";\n\n/**\n * Hand-rolled cva-style variant utility (no extra dependency).\n *\n * Every class string appears whole in source (contract D7): a variant map\n * value is a complete Tailwind class list, selected — never concatenated —\n * at call time and merged through cn().\n */\n\n/** A map of variant group name → allowed value → whole Tailwind class string. */\nexport type VariantShape = Record<string, Record<string, string>>;\n\n/** The props accepted for a given variant shape (each group optional). */\nexport type VariantSelection<V extends VariantShape> = {\n [K in keyof V]?: Extract<keyof V[K], string> | null;\n};\n\nexport interface VariantsConfig<V extends VariantShape> {\n /** Classes always applied, before any variant classes. */\n base?: string;\n variants: V;\n defaultVariants?: VariantSelection<V>;\n /** Extra classes applied when every listed variant value is selected. */\n compoundVariants?: ReadonlyArray<VariantSelection<V> & { className: string }>;\n}\n\nexport type VariantFn<V extends VariantShape> = (\n props?: VariantSelection<V> & { className?: string },\n) => string;\n\n/**\n * Extracts the variant props of a variant function, for typing component\n * props: `type ButtonVariantProps = VariantProps<typeof buttonVariants>`.\n */\nexport type VariantProps<F> = F extends VariantFn<infer V> ? VariantSelection<V> : never;\n\n/** Builds a typed class-name function from variant definitions, the way every themed component declares its looks. */\nexport function variants<V extends VariantShape>(config: VariantsConfig<V>): VariantFn<V> {\n const groupNames = Object.keys(config.variants) as Array<Extract<keyof V, string>>;\n\n return (props) => {\n const { className, ...rest } = props ?? {};\n const selection = rest as VariantSelection<V>;\n const chosen: Partial<Record<Extract<keyof V, string>, string>> = {};\n const classes: string[] = [];\n\n if (config.base) {\n classes.push(config.base);\n }\n\n for (const group of groupNames) {\n const value = selection[group] ?? config.defaultVariants?.[group];\n if (value == null) {\n continue;\n }\n chosen[group] = value;\n const groupClasses = config.variants[group][value];\n if (groupClasses) {\n classes.push(groupClasses);\n }\n }\n\n for (const compound of config.compoundVariants ?? []) {\n const { className: compoundClassName, ...rest } = compound;\n // TS cannot relate Omit<VariantSelection<V> & {...}, \"className\"> back to\n // the per-group selection shape, so narrow through unknown once here.\n const conditions = rest as unknown as Partial<\n Record<Extract<keyof V, string>, string | null>\n >;\n const conditionKeys = Object.keys(conditions) as Array<Extract<keyof V, string>>;\n const matches = conditionKeys.every((key) => {\n const expected = conditions[key];\n return expected != null && chosen[key] === expected;\n });\n if (matches) {\n classes.push(compoundClassName);\n }\n }\n\n return cn(...classes, className);\n };\n}\n","import * as React from \"react\";\nimport { variants, type VariantProps } from \"../../lib/variants\";\n\n/**\n * Exported for composition (escape hatch): render any element as a button\n * lookalike with `className={buttonVariants({ variant: \"outline\" })}`.\n */\nexport const buttonVariants = variants({\n base: \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive: \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n outline: \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n});\n\nexport type ButtonVariantProps = VariantProps<typeof buttonVariants>;\n\nexport type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & ButtonVariantProps;\n\n/**\n * Themed button. `type` defaults to \"button\" (pass type=\"submit\" in forms).\n * `className` is merged via cn(), so consumer classes win.\n */\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, type, ...props }, ref) => (\n <button\n ref={ref}\n type={type ?? \"button\"}\n className={buttonVariants({ variant, size, className })}\n {...props}\n />\n ),\n);\nButton.displayName = \"Button\";\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\n\nexport type InputProps = React.InputHTMLAttributes<HTMLInputElement>;\n\n/** Themed text input; every native `<input>` prop passes through. */\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, ...props }, ref) => (\n <input\n ref={ref}\n className={cn(\n \"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n {...props}\n />\n ),\n);\nInput.displayName = \"Input\";\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\n\nexport type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\n/** Themed multi-line text input; every native `<textarea>` prop passes through. */\nexport const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, ...props }, ref) => (\n <textarea\n ref={ref}\n className={cn(\n \"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n {...props}\n />\n ),\n);\nTextarea.displayName = \"Textarea\";\n","import * as React from \"react\";\n\n/**\n * Minimal inline SVG icons used by the primitives (no icon dependency).\n * All strokes use `currentColor`, so they follow the text color tokens.\n * Internal to @karni/ui — not part of the public barrel.\n */\n\ntype IconProps = React.SVGAttributes<SVGSVGElement>;\n\nfunction baseProps(props: IconProps): IconProps {\n return {\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n \"aria-hidden\": true,\n focusable: false,\n ...props,\n };\n}\n\nexport function CheckIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n );\n}\n\nexport function ChevronDownIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n );\n}\n\nexport function ChevronUpIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <polyline points=\"18 15 12 9 6 15\" />\n </svg>\n );\n}\n","import * as SelectPrimitive from \"@radix-ui/react-select\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { CheckIcon, ChevronDownIcon, ChevronUpIcon } from \"./icons\";\n\n/**\n * The value that stands for \"nothing selected\" inside Radix Select, which reserves the empty string.\n *\n * This package maps the empty state through this sentinel at the component boundary (contract D8). Consumers of\n * the composed <Select> never see it: `value`/`onValueChange` use `null`.\n */\nexport const KARNI_SELECT_EMPTY = \"__karni_empty__\";\n\n// ---------------------------------------------------------------------------\n// Low-level styled Radix parts (escape hatch for fully custom selects)\n// ---------------------------------------------------------------------------\n\n/** Radix Select root, for composing a custom select from the styled parts. */\nexport const SelectRoot = SelectPrimitive.Root;\n/** Groups related options inside `SelectContent`. */\nexport const SelectGroup = SelectPrimitive.Group;\n/** Shows the selected option's label inside `SelectTrigger`. */\nexport const SelectValue = SelectPrimitive.Value;\n\n/** The styled button that opens the select. */\nexport const SelectTrigger = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1\",\n className,\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <ChevronDownIcon className=\"h-4 w-4 shrink-0 opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n));\nSelectTrigger.displayName = \"SelectTrigger\";\n\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollUpButton\n ref={ref}\n className={cn(\"flex cursor-default items-center justify-center py-1\", className)}\n {...props}\n >\n <ChevronUpIcon className=\"h-4 w-4\" />\n </SelectPrimitive.ScrollUpButton>\n));\nSelectScrollUpButton.displayName = \"SelectScrollUpButton\";\n\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollDownButton\n ref={ref}\n className={cn(\"flex cursor-default items-center justify-center py-1\", className)}\n {...props}\n >\n <ChevronDownIcon className=\"h-4 w-4\" />\n </SelectPrimitive.ScrollDownButton>\n));\nSelectScrollDownButton.displayName = \"SelectScrollDownButton\";\n\n/** The styled dropdown panel that lists the options. */\nexport const SelectContent = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>\n>(({ className, children, position = \"popper\", ...props }, ref) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n position={position}\n className={cn(\n \"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md\",\n position === \"popper\" &&\n \"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\",\n className,\n )}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n \"p-1\",\n position === \"popper\" &&\n \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]\",\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n));\nSelectContent.displayName = \"SelectContent\";\n\n/** A heading inside a `SelectGroup`. */\nexport const SelectLabel = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Label\n ref={ref}\n className={cn(\"py-1.5 pl-8 pr-2 text-sm font-semibold\", className)}\n {...props}\n />\n));\nSelectLabel.displayName = \"SelectLabel\";\n\n/** One selectable option; `value` is what the select reports. */\nexport const SelectItem = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <CheckIcon className=\"h-4 w-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n));\nSelectItem.displayName = \"SelectItem\";\n\n/** A divider line between option groups. */\nexport const SelectSeparator = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\n {...props}\n />\n));\nSelectSeparator.displayName = \"SelectSeparator\";\n\n// ---------------------------------------------------------------------------\n// Composed, options-driven Select (what ResourceForm / the filter bar use)\n// ---------------------------------------------------------------------------\n\nexport interface SelectOption {\n /** Must be non-empty and not the reserved sentinel. */\n value: string;\n label: React.ReactNode;\n disabled?: boolean;\n}\n\nexport interface SelectProps {\n /** `null`/`\"\"`/`undefined` all mean \"no selection\". */\n value: string | null | undefined;\n /** Receives `null` when the clear item is chosen, else the option value. */\n onValueChange?: (value: string | null) => void;\n options: readonly SelectOption[];\n placeholder?: React.ReactNode;\n /**\n * Renders a clear item at the top of the list (contract D8): pass it for\n * nullable fields (label \"—\" by default) and filter contexts (e.g. \"All\").\n * Choosing it emits `null`.\n */\n clearable?: boolean;\n clearLabel?: React.ReactNode;\n disabled?: boolean;\n /** Forwarded to the hidden native select for HTML form submission. */\n name?: string;\n id?: string;\n /** Merged onto the trigger. */\n className?: string;\n contentClassName?: string;\n \"aria-label\"?: string;\n /** Extra <SelectItem>/<SelectGroup> nodes appended after `options` (escape hatch). */\n children?: React.ReactNode;\n}\n\n/**\n * Styled select for a list of `options`, with `null` for no selection. Maps the\n * empty state through the KARNI_SELECT_EMPTY sentinel so `\"\"` never reaches\n * Radix (D8). For fully custom composition use SelectRoot/SelectTrigger/\n * SelectContent/SelectItem directly.\n */\nexport const Select = React.forwardRef<HTMLButtonElement, SelectProps>((props, ref) => {\n const {\n value,\n onValueChange,\n options,\n placeholder,\n clearable = false,\n clearLabel = \"—\",\n disabled,\n name,\n id,\n className,\n contentClassName,\n children,\n \"aria-label\": ariaLabel,\n } = props;\n\n const safeOptions = React.useMemo(() => {\n const filtered = options.filter(\n (option) => option.value !== \"\" && option.value !== KARNI_SELECT_EMPTY,\n );\n if (filtered.length !== options.length) {\n console.warn(\n `[karni-ui] <Select> option values \"\" and \"${KARNI_SELECT_EMPTY}\" are reserved; those options were dropped. Use the \\`clearable\\` prop for an empty choice.`,\n );\n }\n return filtered;\n }, [options]);\n\n const isEmpty = value == null || value === \"\";\n // With a clear item present, the sentinel is a real Radix value, so the\n // trigger shows the clear label and the item renders checked. Without one,\n // \"\" makes Radix show the placeholder.\n const radixValue = isEmpty ? (clearable ? KARNI_SELECT_EMPTY : \"\") : value;\n\n const handleValueChange = React.useCallback(\n (next: string) => {\n onValueChange?.(next === KARNI_SELECT_EMPTY ? null : next);\n },\n [onValueChange],\n );\n\n return (\n <SelectRoot\n value={radixValue}\n onValueChange={handleValueChange}\n disabled={disabled}\n name={name}\n >\n <SelectTrigger ref={ref} id={id} className={className} aria-label={ariaLabel}>\n <SelectValue placeholder={placeholder} />\n </SelectTrigger>\n <SelectContent className={contentClassName}>\n {clearable ? (\n <SelectItem value={KARNI_SELECT_EMPTY} className=\"text-muted-foreground\">\n {clearLabel}\n </SelectItem>\n ) : null}\n {safeOptions.map((option) => (\n <SelectItem key={option.value} value={option.value} disabled={option.disabled}>\n {option.label}\n </SelectItem>\n ))}\n {children}\n </SelectContent>\n </SelectRoot>\n );\n});\nSelect.displayName = \"Select\";\n","import * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { CheckIcon } from \"./icons\";\n\nexport type CheckboxProps = React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>;\n\n/** Themed checkbox (Radix Checkbox) with a check mark indicator. */\nexport const Checkbox = React.forwardRef<\n React.ElementRef<typeof CheckboxPrimitive.Root>,\n CheckboxProps\n>(({ className, ...props }, ref) => (\n <CheckboxPrimitive.Root\n ref={ref}\n className={cn(\n \"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground\",\n className,\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator className=\"flex items-center justify-center text-current\">\n <CheckIcon className=\"h-3.5 w-3.5\" />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n));\nCheckbox.displayName = \"Checkbox\";\n","import * as SwitchPrimitive from \"@radix-ui/react-switch\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\n\nexport type SwitchProps = React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root>;\n\n/** Themed on/off toggle (Radix Switch). */\nexport const Switch = React.forwardRef<React.ElementRef<typeof SwitchPrimitive.Root>, SwitchProps>(\n ({ className, ...props }, ref) => (\n <SwitchPrimitive.Root\n ref={ref}\n className={cn(\n \"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input\",\n className,\n )}\n {...props}\n >\n <SwitchPrimitive.Thumb className=\"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0\" />\n </SwitchPrimitive.Root>\n ),\n);\nSwitch.displayName = \"Switch\";\n","import * as LabelPrimitive from \"@radix-ui/react-label\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\n\nexport type LabelProps = React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>;\n\n/** Themed form label (Radix Label) that dims when its field is disabled. */\nexport const Label = React.forwardRef<React.ElementRef<typeof LabelPrimitive.Root>, LabelProps>(\n ({ className, ...props }, ref) => (\n <LabelPrimitive.Root\n ref={ref}\n className={cn(\n \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\",\n className,\n )}\n {...props}\n />\n ),\n);\nLabel.displayName = \"Label\";\n","import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\n\n/** Tab set root (Radix Tabs); holds the selected value. */\nexport const Tabs = TabsPrimitive.Root;\n\n/** The row of tab buttons. */\nexport const TabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.List\n ref={ref}\n className={cn(\n \"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground\",\n className,\n )}\n {...props}\n />\n));\nTabsList.displayName = \"TabsList\";\n\n/** One tab button; `value` names the panel it opens. */\nexport const TabsTrigger = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm\",\n className,\n )}\n {...props}\n />\n));\nTabsTrigger.displayName = \"TabsTrigger\";\n\n/** The panel shown while its `value` is the selected tab. */\nexport const TabsContent = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Content\n ref={ref}\n className={cn(\n \"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n className,\n )}\n {...props}\n />\n));\nTabsContent.displayName = \"TabsContent\";\n","import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { CheckIcon } from \"./icons\";\n\n/** Dropdown menu root (Radix DropdownMenu). */\nexport const DropdownMenu = DropdownMenuPrimitive.Root;\n/** The element that opens the menu. */\nexport const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n/** Groups related menu items. */\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\n/** Renders the menu into `document.body`. */\nexport const DropdownMenuPortal = DropdownMenuPrimitive.Portal;\n\n/** The styled menu panel. */\nexport const DropdownMenuContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md\",\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = \"DropdownMenuContent\";\n\n/** One menu item; `onSelect` runs the action. */\nexport const DropdownMenuItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n inset && \"pl-8\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuItem.displayName = \"DropdownMenuItem\";\n\n/** A menu item with a check mark that toggles `checked`. */\nexport const DropdownMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n checked={checked}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon className=\"h-4 w-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName = \"DropdownMenuCheckboxItem\";\n\n/** A non-interactive heading inside the menu. */\nexport const DropdownMenuLabel = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\"px-2 py-1.5 text-sm font-semibold\", inset && \"pl-8\", className)}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = \"DropdownMenuLabel\";\n\n/** A divider line between menu items. */\nexport const DropdownMenuSeparator = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = \"DropdownMenuSeparator\";\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\n\nexport type SkeletonProps = React.HTMLAttributes<HTMLDivElement>;\n\n/** Loading placeholder block; size it with width/height utility classes. */\nexport const Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"animate-pulse rounded-md bg-muted\", className)} {...props} />\n ),\n);\nSkeleton.displayName = \"Skeleton\";\n","/**\n * Query-param construction and key normalization for the resource hooks\n * (contract \"Hooks\" + D4).\n *\n * `buildListQuery` / `buildItemQuery` turn the typed param objects into the\n * flat record that is sent to the backend (page → `page`, pageSize →\n * `page_size`, expand → comma-joined per api contract B9, filters spread\n * flat). `normalizeParams` produces the canonical representation used inside\n * query keys (D4): undefined/null dropped, keys sorted recursively, values\n * stringified exactly as they hit the query string — so two call sites that\n * describe the same request always share one cache entry.\n *\n * Internal module: not re-exported from the barrel.\n */\nimport type { FilterValue, ResourceItemParams, ResourceListParams } from \"./types\";\n\n/** Canonical param value shape stored inside query keys (D4). */\nexport type NormalizedParamValue = string | readonly string[] | NormalizedParams;\nexport type NormalizedParams = { readonly [key: string]: NormalizedParamValue };\n\nfunction stringifyScalar(value: string | number | boolean): string {\n return typeof value === \"string\" ? value : String(value);\n}\n\nfunction isScalarArray(value: FilterValue): value is ReadonlyArray<string | number | boolean> {\n return Array.isArray(value);\n}\n\n/**\n * Flattens ResourceListParams into the query record sent to the server.\n * Explicit params win over a `filters` entry of the same name. Empty\n * `search`/`ordering` strings and empty `expand` arrays are omitted (they\n * describe \"no constraint\", and sending them would fragment the cache).\n */\nexport function buildListQuery(\n params?: ResourceListParams,\n): Record<string, string | readonly string[]> {\n const query: Record<string, string | readonly string[]> = {};\n if (params === undefined) return query;\n\n if (params.filters !== undefined) {\n for (const [key, value] of Object.entries(params.filters)) {\n if (value === null || value === undefined) continue;\n if (isScalarArray(value)) {\n if (value.length > 0) query[key] = value.map(stringifyScalar);\n } else {\n query[key] = stringifyScalar(value);\n }\n }\n }\n\n if (params.page !== undefined) query.page = String(params.page);\n if (params.pageSize !== undefined) query.page_size = String(params.pageSize);\n if (params.ordering !== undefined && params.ordering !== \"\") query.ordering = params.ordering;\n if (params.search !== undefined && params.search !== \"\") query.search = params.search;\n if (params.expand !== undefined && params.expand.length > 0) {\n query.expand = params.expand.join(\",\");\n }\n return query;\n}\n\n/** Detail requests only carry `expand` (api contract B9). */\nexport function buildItemQuery(params?: ResourceItemParams): Record<string, string> {\n const query: Record<string, string> = {};\n if (params?.expand !== undefined && params.expand.length > 0) {\n query.expand = params.expand.join(\",\");\n }\n return query;\n}\n\n/**\n * D4 normalization: drop undefined/null, sort keys recursively, stringify\n * values as they hit the query string. The result is what `karniKeys` embeds\n * in list keys.\n */\nexport function normalizeParams(value: Record<string, unknown>): NormalizedParams {\n const out: Record<string, NormalizedParamValue> = {};\n for (const key of Object.keys(value).sort()) {\n const normalized = normalizeValue(value[key]);\n if (normalized !== undefined) out[key] = normalized;\n }\n return out;\n}\n\nfunction normalizeValue(value: unknown): NormalizedParamValue | undefined {\n if (value === null || value === undefined) return undefined;\n if (Array.isArray(value)) {\n return (value as readonly unknown[])\n .filter((item) => item !== null && item !== undefined)\n .map((item) =>\n typeof item === \"object\" && item !== null ? JSON.stringify(item) : String(item),\n );\n }\n if (typeof value === \"object\") {\n return normalizeParams(value as Record<string, unknown>);\n }\n return String(value);\n}\n\n/** `/events/` for resource \"events\" (the DRF router prefix, api B13). */\nexport function listPath(resource: string): string {\n const trimmed = resource.replace(/^\\/+|\\/+$/g, \"\");\n return `/${trimmed}/`;\n}\n\n/** `/events/5/` — ids are encoded so UUIDs and slugs are safe. */\nexport function detailPath(resource: string, id: string | number): string {\n return `${listPath(resource)}${encodeURIComponent(String(id))}/`;\n}\n","/**\n * Query-key factory for every cache entry @karni/ui creates (contract D4).\n *\n * Key shapes:\n * - `[\"karni\", \"$schema\"]` — the parsed OpenAPI schema (staleTime Infinity).\n * - `[\"karni\", resource]` — the invalidation root for one resource.\n * - `[\"karni\", resource, \"list\", normalizedParams]` — one list page.\n * - `[\"karni\", resource, \"detail\", String(id)]` — one item; when the item was\n * fetched with params (e.g. `expand`), the normalized params are appended as\n * a fifth element so differently-shaped payloads never share a cache entry.\n * Prefix invalidation via `karniKeys.resource(...)` still reaches them.\n *\n * Use this factory for any manual cache work (`setQueryData`,\n * `invalidateQueries`, prefetching) so your keys and the library's keys never\n * drift.\n *\n * NEVER invalidate the bare `[\"karni\"]` root: it would also blow away the\n * schema entry (`[\"karni\", \"$schema\"]`), refetching and re-parsing the whole\n * OpenAPI document. Invalidate `karniKeys.resource(resource)` instead — the\n * `\"$\"` prefix guarantees the schema key can never collide with a real\n * resource name (DRF router prefixes cannot contain `$`).\n */\nimport { buildItemQuery, buildListQuery, normalizeParams } from \"./params\";\nimport type { ResourceItemParams, ResourceListParams } from \"./types\";\n\n/** TanStack Query keys for the schema, a resource, its lists and its items; invalidate `karniKeys.resource(name)` to refresh every view of a resource. */\nexport const karniKeys = {\n /** Cache key of the parsed OpenAPI schema document. */\n schema(): readonly unknown[] {\n return [\"karni\", \"$schema\"] as const;\n },\n\n /**\n * The invalidation root for one resource — every list and detail key of\n * `resource` lives under this prefix.\n */\n resource(resource: string): readonly unknown[] {\n return [\"karni\", resource] as const;\n },\n\n /**\n * Key for one list page. Params are normalized (D4): undefined/null\n * dropped, keys sorted recursively, values stringified as they hit the\n * query string — `{search: \"x\", page: 2}` and `{page: 2, search: \"x\"}`\n * share one entry.\n */\n list(resource: string, params?: ResourceListParams): readonly unknown[] {\n return [\"karni\", resource, \"list\", normalizeParams(buildListQuery(params))] as const;\n },\n\n /**\n * Key for one item. The id is always stringified, so `detail(\"events\", 5)`\n * and `detail(\"events\", \"5\")` share one entry. Params (expand) append a\n * normalized fifth element — see the module docs.\n */\n detail(resource: string, id: string | number, params?: ResourceItemParams): readonly unknown[] {\n const query = buildItemQuery(params);\n if (Object.keys(query).length > 0) {\n return [\"karni\", resource, \"detail\", String(id), normalizeParams(query)] as const;\n }\n return [\"karni\", resource, \"detail\", String(id)] as const;\n },\n};\n","/**\n * <KarniProvider> — wires the Karni client into React (contract \"Schema\n * client\"). Wraps TanStack's QueryClientProvider, creating a QueryClient when\n * none is given (the `queryClient` prop is the escape hatch for apps that\n * already have one), and provides the client via context for every hook and\n * component in the package.\n */\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { createContext, useContext, useState } from \"react\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport type { KarniClient } from \"./client\";\n\nconst KarniClientContext = createContext<KarniClient | null>(null);\n\nexport interface KarniProviderProps {\n client: KarniClient;\n /** Bring your own QueryClient; one is created (once) when omitted. */\n queryClient?: QueryClient;\n children?: ReactNode;\n}\n\n/** Provides the Karni client and a TanStack QueryClient to everything inside it; render it once at the app root. */\nexport function KarniProvider(props: KarniProviderProps): ReactElement {\n const { client, queryClient, children } = props;\n // Lazy initial state so the fallback QueryClient is created exactly once\n // per provider instance, never on re-renders.\n const [ownQueryClient] = useState(() => queryClient ?? new QueryClient());\n return (\n <QueryClientProvider client={queryClient ?? ownQueryClient}>\n <KarniClientContext.Provider value={client}>{children}</KarniClientContext.Provider>\n </QueryClientProvider>\n );\n}\n\n/** Returns the Karni client from `KarniProvider`; throws a descriptive error outside one. */\nexport function useKarniClient(): KarniClient {\n const client = useContext(KarniClientContext);\n if (client === null) {\n throw new Error(\n \"useKarniClient must be used within <KarniProvider>. \" +\n \"Wrap your app in <KarniProvider client={createKarniClient({ baseUrl })}>.\",\n );\n }\n return client;\n}\n","/**\n * Paginated list hook for one resource (contract \"Hooks\" + D11).\n *\n * `useResourceList<Event>(\"events\", { page: 2, search: \"conf\" })` fetches\n * `GET /<resource>/?page=2&search=conf` through the KarniClient (auth-aware\n * inside an <AuthProvider>) and caches it under\n * `karniKeys.list(resource, params)`. The response is the raw DRF page:\n * `{ count, next, previous, results }`.\n *\n * Escape hatch: `options` forwards every TanStack Query option except\n * `queryKey`/`queryFn` (e.g. `enabled`, `placeholderData`, `staleTime`,\n * `select`).\n */\nimport { useQuery, type UseQueryOptions, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useKarniClient } from \"../schema/provider\";\nimport { karniKeys } from \"./keys\";\nimport { buildListQuery, listPath } from \"./params\";\nimport type { Paginated, ResourceListParams } from \"./types\";\n\n/** Fetches one page of a resource's list (`GET /<resource>/`) with filters, search, ordering and `?expand=`. */\nexport function useResourceList<T = Record<string, unknown>>(\n resource: string,\n params?: ResourceListParams,\n options?: Omit<UseQueryOptions<Paginated<T>>, \"queryKey\" | \"queryFn\">,\n): UseQueryResult<Paginated<T>> {\n const client = useKarniClient();\n return useQuery<Paginated<T>>({\n ...options,\n queryKey: karniKeys.list(resource, params),\n queryFn: ({ signal }) =>\n client.request<Paginated<T>>(listPath(resource), { query: buildListQuery(params), signal }),\n });\n}\n","/**\n * Mutation body encoding (contract D2) + PATCH file-URL omission.\n *\n * D2: after the form's `transformSubmit` has run, a payload containing any\n * top-level `File` (or an array containing one) is encoded as `FormData`;\n * everything else is sent as JSON. FormData rules:\n * - arrays append as repeated keys,\n * - plain objects/arrays-of-objects (json fields) are JSON-stringified,\n * - numbers/booleans are stringified,\n * - `null`/`undefined` entries are OMITTED — multipart cannot express null\n * (DRF would parse the string \"null\"); to null a field, send a JSON PATCH\n * without the file field instead,\n * - Content-Type is never set manually: fetch derives the multipart boundary.\n *\n * PATCH omission (D2): a string value on a file-kind field is the unchanged\n * display URL the backend returned (D1: response-side `format: uri`); sending\n * it back would 400 (\"not a file\"), so it is dropped from PATCH payloads.\n * Field kinds come from the cached parsed schema when present; without it the\n * payload passes through untouched (graceful degradation).\n *\n * Internal module: not re-exported from the barrel.\n */\n\nfunction isFileValue(value: unknown): value is File {\n return typeof File !== \"undefined\" && value instanceof File;\n}\n\nfunction isBlobValue(value: unknown): value is Blob {\n return typeof Blob !== \"undefined\" && value instanceof Blob;\n}\n\n/** True when any top-level value is a File, or an array containing one (D2). */\nexport function containsFile(values: Record<string, unknown>): boolean {\n return Object.values(values).some(\n (value) =>\n isFileValue(value) || (Array.isArray(value) && value.some((item) => isFileValue(item))),\n );\n}\n\nfunction appendFormValue(form: FormData, key: string, value: unknown): void {\n if (value === null || value === undefined) return;\n if (isFileValue(value) || isBlobValue(value)) {\n form.append(key, value);\n return;\n }\n if (typeof value === \"object\") {\n form.append(key, JSON.stringify(value));\n return;\n }\n form.append(key, String(value));\n}\n\n/** Encodes a payload as FormData per the D2 rules above. */\nexport function toFormData(values: Record<string, unknown>): FormData {\n const form = new FormData();\n for (const [key, value] of Object.entries(values)) {\n if (value === null || value === undefined) continue;\n if (Array.isArray(value)) {\n for (const item of value) appendFormValue(form, key, item);\n } else {\n appendFormValue(form, key, value);\n }\n }\n return form;\n}\n\n/**\n * D2 dispatch: FormData when a top-level File is present, the payload itself\n * (JSON-serialized by the client) otherwise. Applies to create AND PATCH.\n */\nexport function encodeBody(values: Record<string, unknown>): Record<string, unknown> | FormData {\n return containsFile(values) ? toFormData(values) : values;\n}\n\n/**\n * Extracts the file-kind field names of `resource` from the cached parsed\n * schema (`karniKeys.schema()`'s cache entry). Every access is guarded: an\n * absent cache entry or an unexpected shape yields an empty set, never a\n * throw.\n */\nexport function fileFieldNames(cachedSchema: unknown, resource: string): ReadonlySet<string> {\n const names = new Set<string>();\n if (typeof cachedSchema !== \"object\" || cachedSchema === null) return names;\n const resources = (cachedSchema as Record<string, unknown>).resources;\n if (typeof resources !== \"object\" || resources === null) return names;\n const entry = (resources as Record<string, unknown>)[resource];\n if (typeof entry !== \"object\" || entry === null) return names;\n const fields = (entry as Record<string, unknown>).fields;\n if (!Array.isArray(fields)) return names;\n for (const field of fields as readonly unknown[]) {\n if (typeof field !== \"object\" || field === null) continue;\n const { name, kind } = field as Record<string, unknown>;\n if (typeof name === \"string\" && kind === \"file\") names.add(name);\n }\n return names;\n}\n\nfunction isStringOrStringArray(value: unknown): boolean {\n if (typeof value === \"string\") return true;\n return Array.isArray(value) && value.every((item) => typeof item === \"string\");\n}\n\n/**\n * Drops unchanged file values — strings (or arrays of strings) on file-kind\n * fields are the backend's display URLs, not new uploads — from a PATCH\n * payload (D2).\n */\nexport function omitUnchangedFileUrls(\n values: Record<string, unknown>,\n fileFields: ReadonlySet<string>,\n): Record<string, unknown> {\n if (fileFields.size === 0) return values;\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(values)) {\n if (fileFields.has(key) && isStringOrStringArray(value)) continue;\n out[key] = value;\n }\n return out;\n}\n","/**\n * Create / update / remove mutations for one resource (contract \"Hooks\" +\n * D2, D3, D11).\n *\n * - `create` → `POST /<resource>/`\n * - `update` → `PATCH /<resource>/<id>/` with `{ id, values }`\n * - `remove` → `DELETE /<resource>/<id>/`\n *\n * Every successful mutation invalidates `karniKeys.resource(resource)` (all\n * list + detail entries of the resource) plus any `options.invalidateKeys` —\n * never the bare `[\"karni\"]` root (D4), which would nuke the cached schema.\n *\n * ## Multipart (D2)\n * Payloads containing a top-level `File` (or an array containing one) are\n * encoded as FormData — on create AND PATCH — with arrays as repeated keys,\n * json values JSON-stringified, and no manual Content-Type. Unchanged file\n * values (the URL string the backend returned) are omitted from PATCH\n * payloads so they are never re-submitted as uploads.\n *\n * ## PATCH granularity — contract for the form builder (D3)\n * `update` sends EXACTLY the keys present in `values`; it never diffs or\n * drops fields itself (beyond the file-URL omission above). ResourceForm\n * must therefore build `values` at TOP-LEVEL FIELD granularity from\n * react-hook-form's `dirtyFields`: when ANY leaf inside a field's subtree is\n * dirty (nested object, array member, multi-relation), include that field's\n * ENTIRE current value — never a partial subtree, because DRF PATCH replaces\n * the whole field value. An emptied nullable field must be sent as `null`\n * (not `\"\"`/`undefined`): a key that is absent is simply left unchanged by\n * the backend, and `undefined` does not survive JSON serialization.\n */\nimport { useMutation, useQueryClient, type UseMutationResult } from \"@tanstack/react-query\";\nimport { useCallback } from \"react\";\nimport { useKarniClient } from \"../schema/provider\";\nimport { karniKeys } from \"./keys\";\nimport { encodeBody, fileFieldNames, omitUnchangedFileUrls } from \"./multipart\";\nimport { detailPath, listPath } from \"./params\";\nimport type { ResourceMutationsOptions } from \"./types\";\n\n/** Result bundle — the three mutations, each a full TanStack mutation object. */\nexport interface ResourceMutations<T> {\n create: UseMutationResult<T, unknown, Record<string, unknown>>;\n update: UseMutationResult<T, unknown, { id: string | number; values: Record<string, unknown> }>;\n remove: UseMutationResult<void, unknown, string | number>;\n}\n\n/** Create, update and remove mutations for a resource; each success refreshes the resource's cached lists and items. */\nexport function useResourceMutations<T = Record<string, unknown>>(\n resource: string,\n options?: ResourceMutationsOptions,\n): ResourceMutations<T> {\n const client = useKarniClient();\n const queryClient = useQueryClient();\n const invalidateKeys = options?.invalidateKeys;\n\n const invalidate = useCallback(async (): Promise<void> => {\n await queryClient.invalidateQueries({ queryKey: karniKeys.resource(resource) });\n if (invalidateKeys !== undefined) {\n await Promise.all(\n invalidateKeys.map((queryKey) => queryClient.invalidateQueries({ queryKey })),\n );\n }\n }, [queryClient, resource, invalidateKeys]);\n\n const create = useMutation<T, unknown, Record<string, unknown>>({\n mutationFn: (values) =>\n client.request<T>(listPath(resource), { method: \"POST\", body: encodeBody(values) }),\n onSuccess: () => invalidate(),\n });\n\n const update = useMutation<T, unknown, { id: string | number; values: Record<string, unknown> }>({\n mutationFn: ({ id, values }) => {\n const fileFields = fileFieldNames(queryClient.getQueryData(karniKeys.schema()), resource);\n const prepared = omitUnchangedFileUrls(values, fileFields);\n return client.request<T>(detailPath(resource, id), {\n method: \"PATCH\",\n body: encodeBody(prepared),\n });\n },\n onSuccess: () => invalidate(),\n });\n\n // `void` lives in the annotation, not in call-site type arguments: eslint's\n // strict no-invalid-void-type only permits it in type-reference positions.\n const remove: UseMutationResult<void, unknown, string | number> = useMutation({\n mutationFn: async (id: string | number): Promise<void> => {\n await client.request(detailPath(resource, id), { method: \"DELETE\" });\n },\n onSuccess: () => invalidate(),\n });\n\n return { create, update, remove };\n}\n","/**\n * OpenAPI → ResourceSchema parser (contract \"Schema client\" + amendment D1).\n *\n * Parses the real drf-spectacular dialect (OAS 3.0.3):\n * - resolves $ref against components.schemas (cycle-guarded),\n * - unwraps single-member allOf, merging its siblings (drf-spectacular uses\n * `allOf: [$ref] + readOnly/description` for annotated enum fields),\n * - maps oneOf [XEnum, NullEnum | BlankEnum] → kind \"enum\" (+ nullable from\n * NullEnum; BlankEnum's \"\" excluded from enumValues),\n * - handles `nullable: true` (3.0) and `type: [T, \"null\"]` (future-proofing),\n * - split-components merge algebra (COMPONENT_SPLIT_REQUEST=True, api B14):\n * fields = union(response props, create-request props); readOnly = flagged\n * OR response-only; writeOnly = flagged OR request-only; required = the\n * CREATE REQUEST body's required array ONLY; resources without a create op\n * fall back to response-only, all readOnly,\n * - kind \"file\" = request-side `format: binary` (the response-side format: uri\n * is just the display URL),\n * - unknown/unsupported constructs land as kind \"unknown\" (never crash).\n *\n * This module is internal to @karni/ui (not re-exported from the barrel), but\n * sibling builders (hooks/auth/components) import it relatively.\n */\n\nimport type {\n FieldDef,\n FieldKind,\n OperationDef,\n ParsedSchema,\n RelationRef,\n ResourceSchema,\n} from \"./types\";\n\n// minimal structural OpenAPI types\n\nexport interface KarniRelationExtension {\n resource?: string;\n many?: boolean;\n}\n\nexport interface SchemaObject {\n default?: unknown;\n $ref?: string;\n type?: string | readonly string[];\n format?: string;\n title?: string;\n description?: string;\n enum?: ReadonlyArray<string | number | null>;\n nullable?: boolean;\n readOnly?: boolean;\n writeOnly?: boolean;\n required?: readonly string[];\n properties?: Record<string, SchemaObject>;\n items?: SchemaObject;\n allOf?: readonly SchemaObject[];\n oneOf?: readonly SchemaObject[];\n anyOf?: readonly SchemaObject[];\n maxLength?: number;\n minLength?: number;\n minimum?: number;\n maximum?: number;\n \"x-karni-relation\"?: KarniRelationExtension;\n [extension: string]: unknown;\n}\n\nexport interface ParameterObject {\n name?: string;\n in?: string;\n required?: boolean;\n schema?: SchemaObject;\n [extension: string]: unknown;\n}\n\nexport interface MediaTypeObject {\n schema?: SchemaObject;\n [extension: string]: unknown;\n}\n\nexport interface RequestBodyObject {\n content?: Record<string, MediaTypeObject>;\n required?: boolean;\n [extension: string]: unknown;\n}\n\nexport interface ResponseObject {\n description?: string;\n content?: Record<string, MediaTypeObject>;\n [extension: string]: unknown;\n}\n\nexport interface OperationObject {\n operationId?: string;\n parameters?: readonly ParameterObject[];\n requestBody?: RequestBodyObject;\n responses?: Record<string, ResponseObject>;\n \"x-karni-resource\"?: string;\n [extension: string]: unknown;\n}\n\nexport interface PathItemObject {\n get?: OperationObject;\n post?: OperationObject;\n put?: OperationObject;\n patch?: OperationObject;\n delete?: OperationObject;\n [extension: string]: unknown;\n}\n\nexport interface OpenApiDocument {\n openapi?: string;\n paths?: Record<string, PathItemObject>;\n components?: { schemas?: Record<string, SchemaObject>; [extension: string]: unknown };\n \"x-karni-auth-mode\"?: string;\n [extension: string]: unknown;\n}\n\n// helpers\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** \"starts_at\" → \"Starts at\"; \"is_public\" → \"Is public\". */\nexport function humanize(name: string): string {\n const spaced = name.replace(/[_-]+/g, \" \").trim();\n return spaced.length === 0 ? name : spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\nconst REF_PREFIX = \"#/components/schemas/\";\n\nfunction lookupRef(doc: OpenApiDocument, ref: string): SchemaObject | undefined {\n if (!ref.startsWith(REF_PREFIX)) return undefined;\n return doc.components?.schemas?.[ref.slice(REF_PREFIX.length)];\n}\n\n/**\n * Resolves $ref chains and unwraps single-member allOf, merging siblings over\n * the resolved target (so `{allOf: [$ref StatusEnum], readOnly: true}` yields\n * the enum schema plus readOnly). Cycle-guarded; a cycle resolves to {}.\n */\nexport function resolveSchema(\n doc: OpenApiDocument,\n schema: SchemaObject | undefined,\n seen: readonly string[] = [],\n): SchemaObject | undefined {\n if (schema === undefined) return undefined;\n\n if (typeof schema.$ref === \"string\") {\n if (seen.includes(schema.$ref)) return {};\n const target = lookupRef(doc, schema.$ref);\n if (target === undefined) return {};\n const resolved = resolveSchema(doc, target, [...seen, schema.$ref]) ?? {};\n const siblings: SchemaObject = { ...schema };\n delete siblings.$ref;\n return { ...resolved, ...siblings };\n }\n\n if (Array.isArray(schema.allOf) && schema.allOf.length === 1) {\n const inner = resolveSchema(doc, schema.allOf[0], seen) ?? {};\n const siblings: SchemaObject = { ...schema };\n delete siblings.allOf;\n return { ...inner, ...siblings };\n }\n\n return schema;\n}\n\n// per-property analysis\n\ninterface PropertyInfo {\n kind: FieldKind;\n nullable: boolean;\n enumValues?: ReadonlyArray<string | number>;\n enumLabels?: Readonly<Record<string, string>>;\n maxLength?: number;\n min?: number;\n max?: number;\n format?: string;\n description?: string;\n title?: string;\n default?: unknown;\n readOnly: boolean;\n writeOnly: boolean;\n relation?: RelationRef;\n relationValueType?: \"uuid\" | \"integer\" | \"string\";\n /** True when this side emits format: binary (request side of a file field). */\n binary: boolean;\n}\n\nfunction normalizeType(schema: SchemaObject): { type: string | undefined; nullable: boolean } {\n // `type: [T, \"null\"]` is handled as future-proofing only (D1).\n if (Array.isArray(schema.type)) {\n const nonNull = schema.type.filter((t) => t !== \"null\");\n return { type: nonNull[0], nullable: schema.type.includes(\"null\") || schema.nullable === true };\n }\n return {\n type: typeof schema.type === \"string\" ? schema.type : undefined,\n nullable: schema.nullable === true,\n };\n}\n\nfunction relationFromExtension(schema: SchemaObject): RelationRef | undefined {\n const ext = schema[\"x-karni-relation\"];\n if (isRecord(ext) && typeof ext.resource === \"string\" && ext.resource.length > 0) {\n return { resource: ext.resource, many: ext.many === true };\n }\n return undefined;\n}\n\nfunction relationValueTypeOf(schema: SchemaObject): \"uuid\" | \"integer\" | \"string\" {\n const { type } = normalizeType(schema);\n if (type === \"integer\" || type === \"number\") return \"integer\";\n if (schema.format === \"uuid\") return \"uuid\";\n return \"string\";\n}\n\n/**\n * Combines oneOf/anyOf members when they follow the drf-spectacular enum\n * pattern `[XEnum, BlankEnum?, NullEnum?]`. Returns undefined for any other\n * composition (which then lands as kind \"unknown\").\n */\nfunction combineEnumMembers(\n doc: OpenApiDocument,\n members: readonly SchemaObject[],\n seen: readonly string[],\n): { values: Array<string | number>; nullable: boolean; description?: string } | undefined {\n const values: Array<string | number> = [];\n let nullable = false;\n let description: string | undefined;\n for (const member of members) {\n const resolved = resolveSchema(doc, member, seen);\n if (resolved === undefined || !Array.isArray(resolved.enum)) return undefined;\n if (description === undefined && resolved.description !== undefined && values.length === 0) {\n description = resolved.description; // the XEnum member carries the choice list\n }\n for (const value of resolved.enum) {\n if (value === null) {\n nullable = true; // NullEnum\n } else if (value !== \"\") {\n values.push(value); // BlankEnum's \"\" excluded from enumValues (D1)\n }\n }\n }\n return { values, nullable, description };\n}\n\nconst CHOICE_LINE = /^\\* `(.+?)` - (.*)$/;\n\n/**\n * Splits drf-spectacular's generated choice list (\"* `draft` - Draft\" per\n * line, appended to a ChoiceField's description) into labels by value and\n * the human help text that remains (undefined when nothing remains). The\n * raw list is markdown a form would otherwise show verbatim as help text.\n */\nexport function choiceLabels(description: string | undefined): {\n labels?: Record<string, string>;\n rest?: string;\n} {\n if (description === undefined) return {};\n const labels: Record<string, string> = {};\n const rest: string[] = [];\n for (const line of description.split(\"\\n\")) {\n const match = CHOICE_LINE.exec(line.trim());\n if (match !== null && match[1] !== undefined && match[2] !== undefined) {\n labels[match[1]] = match[2].trim();\n } else {\n rest.push(line);\n }\n }\n const text = rest.join(\"\\n\").trim();\n return {\n ...(Object.keys(labels).length > 0 ? { labels } : {}),\n ...(text !== \"\" ? { rest: text } : {}),\n };\n}\n\nfunction applyChoiceLabels(info: PropertyInfo, description: string | undefined): void {\n const { labels, rest } = choiceLabels(description);\n if (labels !== undefined) info.enumLabels = labels;\n info.description = rest;\n}\n\n/** True for drf-spectacular's JSONField output: a schema with no constraints at all. */\nfunction isAnySchema(schema: SchemaObject): boolean {\n return (\n schema.type === undefined &&\n schema.enum === undefined &&\n schema.properties === undefined &&\n schema.items === undefined &&\n schema.oneOf === undefined &&\n schema.anyOf === undefined &&\n schema.allOf === undefined &&\n schema.$ref === undefined\n );\n}\n\nfunction analyzeProperty(doc: OpenApiDocument, raw: SchemaObject): PropertyInfo {\n const resolved = resolveSchema(doc, raw) ?? {};\n const relation = relationFromExtension(resolved);\n const { type, nullable: typeNullable } = normalizeType(resolved);\n\n const info: PropertyInfo = {\n kind: \"unknown\",\n nullable: typeNullable,\n format: resolved.format,\n description: resolved.description,\n title: resolved.title,\n default: resolved.default,\n readOnly: resolved.readOnly === true,\n writeOnly: resolved.writeOnly === true,\n maxLength: resolved.maxLength,\n min: resolved.minimum,\n max: resolved.maximum,\n relation,\n binary: false,\n };\n\n // drf-spectacular nullable/blank enums: oneOf [XEnum, BlankEnum?, NullEnum?].\n const composition = resolved.oneOf ?? resolved.anyOf;\n if (Array.isArray(composition)) {\n const combined = combineEnumMembers(doc, composition, []);\n if (combined !== undefined) {\n info.kind = \"enum\";\n info.enumValues = combined.values;\n info.nullable = info.nullable || combined.nullable;\n applyChoiceLabels(info, resolved.description ?? combined.description);\n return info;\n }\n return info; // unsupported composition → kind \"unknown\"\n }\n\n if (Array.isArray(resolved.enum)) {\n info.kind = \"enum\";\n info.nullable = info.nullable || resolved.enum.includes(null);\n info.enumValues = resolved.enum.filter(\n (value): value is string | number => value !== null && value !== \"\",\n );\n applyChoiceLabels(info, resolved.description);\n return info;\n }\n\n if (relation !== undefined && !relation.many) {\n info.kind = \"relation\";\n info.relationValueType = relationValueTypeOf(resolved);\n return info;\n }\n\n switch (type) {\n case \"string\": {\n if (resolved.format === \"binary\") {\n info.kind = \"file\";\n info.binary = true;\n } else if (resolved.format === \"date\") {\n info.kind = \"date\";\n } else if (resolved.format === \"date-time\") {\n info.kind = \"datetime\";\n } else if (resolved.format === undefined && resolved.maxLength === undefined) {\n // CharField always emits maxLength; a bare string is a TextField.\n info.kind = \"text\";\n } else {\n info.kind = \"string\";\n }\n return info;\n }\n case \"integer\":\n info.kind = \"integer\";\n return info;\n case \"number\":\n info.kind = \"number\";\n return info;\n case \"boolean\":\n info.kind = \"boolean\";\n return info;\n case \"array\": {\n if (relation !== undefined) {\n info.kind = \"relation\";\n const items = resolveSchema(doc, resolved.items) ?? {};\n info.relationValueType = relationValueTypeOf(items);\n } else {\n info.kind = \"array\";\n }\n return info;\n }\n case \"object\":\n info.kind = \"json\";\n return info;\n default: {\n if (relation !== undefined) {\n // Extension present but value type undeclared — still a relation.\n info.kind = \"relation\";\n info.relationValueType = relationValueTypeOf(resolved);\n } else if (isAnySchema(resolved)) {\n // drf-spectacular emits `{}` for JSONField (\"any\" schema).\n info.kind = \"json\";\n }\n return info;\n }\n }\n}\n\n// split-components field merge (D1)\n\nfunction mergeField(\n name: string,\n responseInfo: PropertyInfo | undefined,\n requestInfo: PropertyInfo | undefined,\n requiredSet: ReadonlySet<string>,\n hasCreateRequest: boolean,\n order: number,\n): FieldDef {\n // Request side wins for write-facing facts; response side fills the gaps.\n // kind \"file\" is request-side format: binary (D1) — the response side of the\n // same field is a display URL (format: uri) and must not mask it.\n let kind: FieldKind;\n if (requestInfo?.binary === true) {\n kind = \"file\";\n } else if (requestInfo !== undefined && requestInfo.kind !== \"unknown\") {\n kind = requestInfo.kind;\n } else if (responseInfo !== undefined && responseInfo.kind !== \"unknown\") {\n kind = responseInfo.kind;\n } else {\n kind = \"unknown\";\n }\n\n const relation = requestInfo?.relation ?? responseInfo?.relation;\n const title = requestInfo?.title ?? responseInfo?.title;\n\n const field: FieldDef = {\n name,\n label: title !== undefined && title.length > 0 ? title : humanize(name),\n kind,\n required: requiredSet.has(name),\n readOnly:\n !hasCreateRequest ||\n responseInfo?.readOnly === true ||\n requestInfo?.readOnly === true ||\n (hasCreateRequest && responseInfo !== undefined && requestInfo === undefined),\n writeOnly:\n requestInfo?.writeOnly === true ||\n responseInfo?.writeOnly === true ||\n (responseInfo === undefined && requestInfo !== undefined),\n // Write-facing: a file is a nullable URL on the way out and a plain upload\n // on the way in, and only the request side says what a form may send.\n nullable: requestInfo !== undefined ? requestInfo.nullable : (responseInfo?.nullable ?? false),\n order,\n };\n\n const enumValues = requestInfo?.enumValues ?? responseInfo?.enumValues;\n const fallback = requestInfo?.default ?? responseInfo?.default;\n if (fallback !== undefined) field.default = fallback;\n if (enumValues !== undefined) field.enumValues = enumValues;\n const enumLabels = requestInfo?.enumLabels ?? responseInfo?.enumLabels;\n if (enumLabels !== undefined) field.enumLabels = enumLabels;\n const maxLength = requestInfo?.maxLength ?? responseInfo?.maxLength;\n if (maxLength !== undefined) field.maxLength = maxLength;\n const min = requestInfo?.min ?? responseInfo?.min;\n if (min !== undefined) field.min = min;\n const max = requestInfo?.max ?? responseInfo?.max;\n if (max !== undefined) field.max = max;\n const format = requestInfo?.format ?? responseInfo?.format;\n if (format !== undefined) field.format = format;\n const description = responseInfo?.description ?? requestInfo?.description;\n if (description !== undefined) field.description = description;\n if (relation !== undefined) {\n field.relation = relation;\n const valueType = requestInfo?.relationValueType ?? responseInfo?.relationValueType;\n if (valueType !== undefined) field.relationValueType = valueType;\n }\n\n return field;\n}\n\n// operation extraction\n\nfunction operationDef(\n doc: OpenApiDocument,\n path: string,\n method: OperationDef[\"method\"],\n op: OperationObject,\n): OperationDef {\n const queryParams: string[] = [];\n let expandEnum: readonly string[] | undefined;\n for (const param of op.parameters ?? []) {\n if (!isRecord(param) || param.in !== \"query\" || typeof param.name !== \"string\") continue;\n queryParams.push(param.name);\n if (param.name === \"expand\") {\n const schema = resolveSchema(doc, param.schema);\n const items = resolveSchema(doc, schema?.items);\n const values = schema?.enum ?? items?.enum;\n if (Array.isArray(values)) {\n expandEnum = values.filter((value): value is string => typeof value === \"string\");\n }\n }\n }\n const def: OperationDef = {\n path,\n method,\n queryParams,\n hasSearch: queryParams.includes(\"search\"),\n };\n if (typeof op.operationId === \"string\") def.operationId = op.operationId;\n if (expandEnum !== undefined) def.expandEnum = expandEnum;\n return def;\n}\n\n/** Unwraps a DRF paginated list response down to the item component schema. */\nfunction listItemSchema(doc: OpenApiDocument, op: OperationObject): SchemaObject | undefined {\n const response =\n op.responses?.[\"200\"] ?? op.responses?.[\"201\"] ?? Object.values(op.responses ?? {})[0];\n const media = response?.content?.[\"application/json\"];\n const body = resolveSchema(doc, media?.schema);\n if (body === undefined) return undefined;\n const results = resolveSchema(doc, body.properties?.[\"results\"]);\n if (results !== undefined && results.type === \"array\") {\n return resolveSchema(doc, results.items);\n }\n if (body.type === \"array\") return resolveSchema(doc, body.items);\n return body;\n}\n\nfunction createRequestSchema(doc: OpenApiDocument, op: OperationObject): SchemaObject | undefined {\n const content = op.requestBody?.content;\n if (!isRecord(content)) return undefined;\n const media =\n content[\"application/json\"] ?? content[\"multipart/form-data\"] ?? Object.values(content)[0];\n return resolveSchema(doc, media?.schema);\n}\n\n// the parser\n\nconst METHODS = [\"get\", \"post\", \"put\", \"patch\", \"delete\"] as const;\n\n/**\n * Parses an OpenAPI document (fetched from the backend's schemaUrl) into the\n * normalized registry. Tolerates anything it does not understand: unknown\n * constructs become kind \"unknown\" fields, paths without x-karni-resource are\n * ignored, and a malformed document yields an empty registry.\n */\nexport function parseOpenApi(input: unknown): ParsedSchema {\n const doc: OpenApiDocument = isRecord(input) ? (input as OpenApiDocument) : {};\n const paths = isRecord(doc.paths) ? doc.paths : {};\n\n const resources: Record<string, ResourceSchema> = {};\n const rawAuthMode = doc[\"x-karni-auth-mode\"];\n const authMode = rawAuthMode === \"jwt\" || rawAuthMode === \"session\" ? rawAuthMode : undefined;\n\n // Pass 1: find every list operation via its x-karni-resource marker.\n const listOps: Array<{ resource: string; path: string; item: PathItemObject }> = [];\n for (const [path, item] of Object.entries(paths)) {\n if (!isRecord(item)) continue;\n const get = item.get;\n if (isRecord(get) && typeof get[\"x-karni-resource\"] === \"string\") {\n listOps.push({ resource: get[\"x-karni-resource\"], path, item });\n }\n }\n\n for (const { resource, path, item } of listOps) {\n const listOp = item.get;\n if (!isRecord(listOp)) continue;\n\n // The item path is the collection path plus a single `{param}/` segment.\n const itemEntry = Object.entries(paths).find(([candidate]) => {\n if (!candidate.startsWith(path)) return false;\n const rest = candidate.slice(path.length);\n return /^\\{[^/{}]+\\}\\/?$/.test(rest);\n });\n const itemPath = itemEntry?.[0];\n const itemItem = itemEntry !== undefined && isRecord(itemEntry[1]) ? itemEntry[1] : undefined;\n\n const operations: ResourceSchema[\"operations\"] = {\n list: operationDef(doc, path, \"get\", listOp),\n };\n const createOp = isRecord(item.post) ? item.post : undefined;\n if (createOp !== undefined) operations.create = operationDef(doc, path, \"post\", createOp);\n // karni.transfer (P6): the export and import actions live under the list path.\n const exportItem = paths[`${path}export/`];\n const exportOp = isRecord(exportItem) && isRecord(exportItem.get) ? exportItem.get : undefined;\n if (exportOp !== undefined) {\n operations.export = operationDef(doc, `${path}export/`, \"get\", exportOp);\n }\n const importItem = paths[`${path}import/`];\n const importOp =\n isRecord(importItem) && isRecord(importItem.post) ? importItem.post : undefined;\n if (importOp !== undefined) {\n operations.import = operationDef(doc, `${path}import/`, \"post\", importOp);\n }\n if (itemPath !== undefined && itemItem !== undefined) {\n for (const method of METHODS) {\n const op = itemItem[method];\n if (!isRecord(op)) continue;\n if (method === \"get\") operations.detail = operationDef(doc, itemPath, \"get\", op);\n else if (method === \"patch\") operations.update = operationDef(doc, itemPath, \"patch\", op);\n else if (method === \"put\" && operations.update === undefined)\n operations.update = operationDef(doc, itemPath, \"put\", op);\n else if (method === \"delete\") operations.remove = operationDef(doc, itemPath, \"delete\", op);\n }\n }\n\n // Field derivation: response component of the list op + create request body.\n const responseSchema = listItemSchema(doc, listOp);\n const requestSchema = createOp !== undefined ? createRequestSchema(doc, createOp) : undefined;\n const hasCreateRequest = requestSchema !== undefined;\n\n const responseProps = isRecord(responseSchema?.properties) ? responseSchema.properties : {};\n const requestProps = isRecord(requestSchema?.properties) ? requestSchema.properties : {};\n // required comes from the CREATE REQUEST body only — never the response (D1).\n const requiredSet = new Set<string>(\n Array.isArray(requestSchema?.required) ? requestSchema.required : [],\n );\n\n const fields: FieldDef[] = [];\n let order = 0;\n for (const [name, prop] of Object.entries(responseProps)) {\n const responseInfo = analyzeProperty(doc, prop);\n const requestProp = requestProps[name];\n const requestInfo = requestProp !== undefined ? analyzeProperty(doc, requestProp) : undefined;\n fields.push(\n mergeField(name, responseInfo, requestInfo, requiredSet, hasCreateRequest, order),\n );\n order += 1;\n }\n for (const [name, prop] of Object.entries(requestProps)) {\n if (name in responseProps) continue;\n const requestInfo = analyzeProperty(doc, prop);\n fields.push(mergeField(name, undefined, requestInfo, requiredSet, hasCreateRequest, order));\n order += 1;\n }\n\n resources[resource] = { resource, operations, fields };\n }\n\n const parsed: ParsedSchema = { resources };\n if (authMode !== undefined) parsed.authMode = authMode;\n return parsed;\n}\n","/**\n * useSchema — the schema registry hook (contract \"Schema client\").\n *\n * The OpenAPI document is fetched under the pinned [\"karni\", \"$schema\"] key\n * with staleTime Infinity and parsed ONCE inside the query function, so every\n * consumer shares a single ParsedSchema instance per fetch. The key literal\n * is duplicated from karniKeys.schema() (hooks/keys.ts) by design: both\n * modules are bound to the same D4-pinned shape and neither imports the\n * other at runtime.\n *\n * Asking for a resource the backend does not expose — after the schema has\n * loaded — throws during render (error-boundary friendly) with the list of\n * known resources, which catches typos immediately instead of rendering an\n * empty table.\n */\nimport { useQuery } from \"@tanstack/react-query\";\nimport type { UseQueryResult } from \"@tanstack/react-query\";\nimport { parseOpenApi } from \"./parse\";\nimport { useKarniClient } from \"./provider\";\nimport type { ParsedSchema, ResourceSchema } from \"./types\";\n\n/** D4-pinned query key for the parsed schema document. */\nexport const SCHEMA_QUERY_KEY = [\"karni\", \"$schema\"] as const;\n\n/**\n * The whole parsed registry (resources + root x-karni-auth-mode). Internal to\n * the package — the auth layer reads `data.authMode` from here; apps use\n * useSchema(resource).\n */\nexport function useParsedSchema(): UseQueryResult<ParsedSchema> {\n const client = useKarniClient();\n return useQuery<ParsedSchema>({\n queryKey: SCHEMA_QUERY_KEY,\n staleTime: Infinity,\n queryFn: async () => parseOpenApi(await client.request<unknown>(client.schemaUrl)),\n });\n}\n\nexport interface UseSchemaResult {\n data: ResourceSchema | undefined;\n isLoading: boolean;\n error: unknown;\n}\n\n/** Returns one resource's parsed schema (fields, types, relations, operations) from the backend's OpenAPI document, fetched once per app. */\nexport function useSchema(resource: string): UseSchemaResult {\n const query = useParsedSchema();\n\n if (query.data !== undefined) {\n const schema = query.data.resources[resource];\n if (schema === undefined) {\n const known = Object.keys(query.data.resources).sort();\n throw new Error(\n `Unknown resource \"${resource}\". Known resources: ` +\n `${known.length > 0 ? known.join(\", \") : \"(none — does the schema expose x-karni-resource?)\"}.`,\n );\n }\n return { data: schema, isLoading: false, error: query.error };\n }\n\n return { data: undefined, isLoading: query.isPending, error: query.error };\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\n\nregisterComponentRole(\"empty-state\", \"EmptyState\");\n\nexport interface EmptyStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Optional illustration/icon slot, rendered above the title. */\n icon?: React.ReactNode;\n /** Short headline (\"No events yet\"). */\n title: React.ReactNode;\n /** Optional supporting copy under the title. */\n description?: React.ReactNode;\n /** Slot for a call to action (e.g. a \"Create\" button). */\n action?: React.ReactNode;\n children?: React.ReactNode;\n}\n\n/**\n * Centered placeholder for empty collections: icon, title, description and\n * an action slot. Used by ResourceTable's `empty` slot and reusable anywhere.\n *\n * Escape hatches: every visual part is a slot; `className` merges via cn();\n * extra children render under the action.\n */\nexport const EmptyState = React.forwardRef<HTMLDivElement, EmptyStateProps>(\n ({ icon, title, description, action, className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"flex w-full flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-border bg-background px-6 py-12 text-center\",\n className,\n )}\n {...props}\n >\n {icon != null && (\n <div aria-hidden=\"true\" className=\"mb-2 text-muted-foreground [&>svg]:h-10 [&>svg]:w-10\">\n {icon}\n </div>\n )}\n <h3 className=\"text-base font-semibold text-foreground\">{title}</h3>\n {description != null && (\n <p className=\"max-w-sm text-sm text-muted-foreground\">{description}</p>\n )}\n {action != null && <div className=\"mt-3 flex items-center gap-2\">{action}</div>}\n {children}\n </div>\n ),\n);\nEmptyState.displayName = \"EmptyState\";\n","/**\n * Audit fields: the columns every Karni resource carries because every model\n * inherits BaseModel (`deleted_at` is never exposed by the API). They are\n * record bookkeeping, not domain data, so the generic resource components\n * de-emphasise them: ResourceTable hides them by default (escape hatches:\n * `columns` entries and `showAuditFields`), ResourceDetail renders them last\n * in a muted \"Record\" group.\n *\n * This list is the single source of truth — edit it here and every generic\n * component follows. Its order is also the display order whenever audit\n * fields are shown, whatever order the schema declares them in.\n */\nimport type { FieldDef } from \"../../schema/types\";\n\n/** The audit field names (`created_at`, `created_by`, …) that tables hide and detail views group last. */\nexport const AUDIT_FIELDS: readonly string[] = Object.freeze([\n \"id\",\n \"created_at\",\n \"updated_at\",\n \"created_by\",\n \"updated_by\",\n]);\n\n/**\n * True for a schema field that is one of AUDIT_FIELDS. The backend always\n * emits these readOnly; a writable field that merely shares a name (a natural\n * `id` key, say) is domain data and is never treated as audit.\n */\nexport function isAuditField(field: Pick<FieldDef, \"name\" | \"readOnly\">): boolean {\n return field.readOnly && AUDIT_FIELDS.includes(field.name);\n}\n\n/**\n * Splits fields into domain fields (schema order kept) and audit fields\n * (AUDIT_FIELDS order).\n */\nexport function partitionAuditFields<F extends Pick<FieldDef, \"name\" | \"readOnly\">>(\n fields: readonly F[],\n): { domain: F[]; audit: F[] } {\n const domain: F[] = [];\n const audit: F[] = [];\n for (const field of fields) {\n (isAuditField(field) ? audit : domain).push(field);\n }\n audit.sort((a, b) => AUDIT_FIELDS.indexOf(a.name) - AUDIT_FIELDS.indexOf(b.name));\n return { domain, audit };\n}\n","/**\n * Human label heuristic for resource objects (contract \"ResourceTable\").\n *\n * Used by ResourceTable's relation cells, ResourceSelect's options and\n * ResourceDetail's relation values. Overridable everywhere it is used:\n * ResourceTable takes `getRowLabel`, ResourceSelect takes `getOptionLabel`.\n */\n\nconst LABEL_KEYS = [\"name\", \"title\", \"label\", \"email\", \"str\"] as const;\n\n/**\n * Returns the first non-empty string among the `name` → `title` → `label` →\n * `email` → `str` keys, falling back to `String(id)` and finally \"\".\n */\nexport function displayLabel(obj: Record<string, unknown>): string {\n for (const key of LABEL_KEYS) {\n const value = obj[key];\n if (typeof value === \"string\" && value.trim().length > 0) return value;\n }\n const id = obj[\"id\"];\n if (id !== null && id !== undefined) return String(id);\n return \"\";\n}\n","/**\n * Selected-count toolbar for ResourceTable's bulk select (D5): shows how many\n * rows are selected (selection persists across pages), a clear affordance and\n * one button per configured bulk action.\n * Internal to @karni/ui — the public surface is ResourceTable's props.\n */\nimport * as React from \"react\";\nimport { cn } from \"../../../lib/cn\";\nimport { Button } from \"../../primitives/button\";\n\nexport interface BulkAction {\n label: React.ReactNode;\n onClick: (selectedIds: string[]) => void;\n destructive?: boolean;\n}\n\nexport interface BulkActionsBarProps {\n /** Row ids (String(row.id), D5) currently selected, across all pages. */\n selectedIds: readonly string[];\n bulkActions: ReadonlyArray<BulkAction>;\n onClear: () => void;\n className?: string;\n}\n\nexport function BulkActionsBar(props: BulkActionsBarProps): React.ReactElement {\n const { selectedIds, bulkActions, onClear, className } = props;\n return (\n <div\n role=\"toolbar\"\n aria-label=\"Bulk actions\"\n className={cn(\n \"flex flex-wrap items-center gap-2 rounded-md border border-border bg-muted px-3 py-2\",\n className,\n )}\n >\n <p className=\"text-sm font-medium text-foreground\">{selectedIds.length} selected</p>\n <Button variant=\"ghost\" size=\"sm\" onClick={onClear}>\n Clear\n </Button>\n <div className=\"ml-auto flex flex-wrap items-center gap-2\">\n {bulkActions.map((action, index) => (\n <Button\n key={index}\n variant={action.destructive === true ? \"destructive\" : \"outline\"}\n size=\"sm\"\n onClick={() => action.onClick([...selectedIds])}\n >\n {action.label}\n </Button>\n ))}\n </div>\n </div>\n );\n}\n","/**\n * Internal helpers for ResourceTable (contract \"ResourceTable\" + D5).\n * Pure functions, unit-tested directly; not part of the public barrel.\n */\nimport type { SortingState } from \"@tanstack/react-table\";\n\n/**\n * Maps TanStack sorting state to the DRF `ordering` query parameter.\n * Column ids equal schema field names verbatim — that IS the ordering\n * contract (D5) — so `[{id: \"title\", desc: true}]` becomes `-title`.\n */\nexport function sortingToOrdering(sorting: SortingState): string | undefined {\n if (sorting.length === 0) return undefined;\n return sorting.map((entry) => (entry.desc ? `-${entry.id}` : entry.id)).join(\",\");\n}\n\n/**\n * Duck-typed 404 check (works with KarniApiError or any error exposing a\n * numeric `status`), used for the D5 page-clamp: a list 404 with page > 1\n * decrements the page and refetches as loading, never as an error.\n */\nexport function isNotFoundError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"status\" in error &&\n (error as { status: unknown }).status === 404\n );\n}\n\nexport function pageCountFor(count: number | undefined, pageSize: number): number {\n if (count === undefined || count <= 0 || pageSize <= 0) return 1;\n return Math.max(1, Math.ceil(count / pageSize));\n}\n\n/** Safe record view of an unknown row (rows are plain JSON objects). */\nexport function asRecord(value: unknown): Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\n/** Best-effort human message from a KarniApiError-shaped or plain Error. */\nexport function errorMessage(error: unknown): string {\n if (typeof error === \"object\" && error !== null) {\n const data = (error as { data?: unknown }).data;\n if (typeof data === \"object\" && data !== null) {\n const detail = (data as { detail?: unknown }).detail;\n if (typeof detail === \"string\" && detail.length > 0) return detail;\n }\n const message = (error as { message?: unknown }).message;\n if (typeof message === \"string\" && message.length > 0) return message;\n }\n return \"Something went wrong while loading this table.\";\n}\n\n/**\n * Display label for an enum member: ALL_CAPS and lower_snake constants are\n * prettified (\"DRAFT\" → \"Draft\", \"in_progress\" → \"In progress\"); mixed-case\n * values (\"iOS\") pass through untouched.\n */\nexport function enumLabel(\n value: string | number,\n labels?: Readonly<Record<string, string>>,\n): string {\n const known = labels?.[String(value)];\n if (known !== undefined) return known;\n if (typeof value === \"number\") return String(value);\n const simple = /^[A-Za-z0-9_ ]+$/.test(value);\n if (simple && (value === value.toUpperCase() || value === value.toLowerCase())) {\n const spaced = value.toLowerCase().replace(/_+/g, \" \").trim();\n if (spaced.length === 0) return value;\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n }\n return value;\n}\n","/**\n * Schema → TanStack column derivation (contract \"ResourceTable\" + D5).\n *\n * - Domain fields first, in declaration order; writeOnly / json / file /\n * unknown fields are skipped unless the consumer explicitly names them in\n * the `columns` prop.\n * - Audit fields (AUDIT_FIELDS: id, created_at, updated_at, created_by,\n * updated_by) are hidden by default. A `columns` entry naming one (without\n * `hidden: true`) or `showAuditFields` brings it back, after the domain\n * columns, in AUDIT_FIELDS order.\n * - Column ids equal schema field names verbatim — that IS the DRF `ordering`\n * contract (D5).\n * - relation / json / file / array / unknown columns are unsortable by\n * default; the per-field `sortable` override wins both ways.\n * - Cells: booleans → check icon, dates localized, enum labels prettified,\n * relations → displayLabel of the expanded object else the raw id in\n * <code>. The label heuristic is overridable via `getRowLabel`.\n */\nimport type { ColumnDef } from \"@tanstack/react-table\";\nimport * as React from \"react\";\nimport { humanize } from \"../../../schema/parse\";\nimport type { FieldDef, FieldKind } from \"../../../schema/types\";\nimport { CheckIcon } from \"../../primitives/icons\";\nimport { isAuditField, partitionAuditFields } from \"../audit-fields\";\nimport { displayLabel } from \"../displayLabel\";\nimport { asRecord, enumLabel } from \"./table-utils\";\n\n/** Per-field override merged over the schema-derived column. */\nexport interface ResourceColumn<T = Record<string, unknown>> {\n field: string;\n header?: React.ReactNode;\n cell?: (row: T) => React.ReactNode;\n hidden?: boolean;\n sortable?: boolean;\n}\n\ntype RowLabeler = (row: Record<string, unknown>) => string;\n\nconst DEFAULT_SKIPPED_KINDS: ReadonlySet<FieldKind> = new Set([\"json\", \"file\", \"unknown\"]);\nconst UNSORTABLE_KINDS: ReadonlySet<FieldKind> = new Set([\n \"relation\",\n \"json\",\n \"file\",\n \"array\",\n \"unknown\",\n]);\n\nfunction EmptyValue(): React.ReactElement {\n return (\n <span aria-hidden=\"true\" className=\"text-muted-foreground\">\n –\n </span>\n );\n}\n\nfunction BooleanCell({ value }: { value: boolean }): React.ReactElement {\n return value ? (\n <span className=\"inline-flex items-center text-foreground\">\n <CheckIcon className=\"h-4 w-4\" />\n <span className=\"sr-only\">Yes</span>\n </span>\n ) : (\n <span className=\"inline-flex items-center text-muted-foreground\">\n <span aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">No</span>\n </span>\n );\n}\n\nfunction IdCode({ value }: { value: unknown }): React.ReactElement {\n return <code className=\"rounded bg-muted px-1 py-0.5 text-xs\">{String(value)}</code>;\n}\n\nfunction relationItem(item: unknown, label: RowLabeler): React.ReactNode {\n if (item === null || item === undefined) return <EmptyValue />;\n if (typeof item === \"object\" && !Array.isArray(item)) return label(asRecord(item));\n return <IdCode value={item} />;\n}\n\nfunction RelationCell({ value, label }: { value: unknown; label: RowLabeler }): React.ReactElement {\n if (value === null || value === undefined) return <EmptyValue />;\n if (Array.isArray(value)) {\n if (value.length === 0) return <EmptyValue />;\n return (\n <span className=\"inline-flex flex-wrap items-center gap-x-2 gap-y-1\">\n {value.map((item, index) => (\n <React.Fragment key={index}>{relationItem(item, label)}</React.Fragment>\n ))}\n </span>\n );\n }\n return <>{relationItem(value, label)}</>;\n}\n\nfunction dateText(value: unknown, withTime: boolean): string {\n const parsed = new Date(String(value));\n if (Number.isNaN(parsed.getTime())) return String(value);\n return withTime ? parsed.toLocaleString() : parsed.toLocaleDateString();\n}\n\nfunction FileCell({ value }: { value: unknown }): React.ReactElement {\n if (typeof value === \"string\" && value.length > 0) {\n const name = value.split(\"/\").filter(Boolean).pop() ?? value;\n return (\n <a\n href={value}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-primary underline underline-offset-4\"\n onClick={(event) => event.stopPropagation()}\n >\n {name}\n </a>\n );\n }\n if (typeof File !== \"undefined\" && value instanceof File) return <>{value.name}</>;\n return <EmptyValue />;\n}\n\nfunction JsonCell({ value }: { value: unknown }): React.ReactElement {\n let text: string;\n try {\n text = JSON.stringify(value) ?? String(value);\n } catch {\n text = String(value);\n }\n const shown = text.length > 80 ? `${text.slice(0, 80)}…` : text;\n return (\n <code className=\"rounded bg-muted px-1 py-0.5 text-xs\" title={text}>\n {shown}\n </code>\n );\n}\n\n/**\n * Default cell renderer for a schema field's value. Exported for reuse by\n * custom cells that want the stock formatting for other fields.\n */\nexport function renderFieldCell(\n field: FieldDef,\n value: unknown,\n getRowLabel?: RowLabeler,\n): React.ReactNode {\n if (value === null || value === undefined) return <EmptyValue />;\n switch (field.kind) {\n case \"boolean\":\n return <BooleanCell value={value === true} />;\n case \"date\":\n return dateText(value, false);\n case \"datetime\":\n return dateText(value, true);\n case \"enum\":\n return typeof value === \"string\" || typeof value === \"number\"\n ? enumLabel(value, field.enumLabels)\n : String(value);\n case \"relation\":\n return <RelationCell value={value} label={getRowLabel ?? displayLabel} />;\n case \"number\":\n case \"integer\":\n return (\n <span className=\"tabular-nums\">\n {typeof value === \"number\" ? value.toLocaleString() : String(value)}\n </span>\n );\n case \"file\":\n return <FileCell value={value} />;\n case \"json\":\n return <JsonCell value={value} />;\n case \"array\":\n return Array.isArray(value) ? value.map((item) => String(item)).join(\", \") : String(value);\n case \"text\":\n return (\n <span className=\"block max-w-xs truncate\" title={String(value)}>\n {String(value)}\n </span>\n );\n default:\n return String(value);\n }\n}\n\n/** ColumnDef.header only takes a string or a render function — wrap nodes. */\nfunction headerTemplate<T>(content: React.ReactNode): ColumnDef<T>[\"header\"] {\n return typeof content === \"string\" ? content : () => content;\n}\n\nexport interface DeriveColumnsArgs<T> {\n fields: readonly FieldDef[];\n columns?: ReadonlyArray<ResourceColumn<T>>;\n getRowLabel?: RowLabeler;\n /** Show every audit field (AUDIT_FIELDS) without naming each in `columns`. */\n showAuditFields?: boolean;\n}\n\nfunction columnForField<T>(\n field: FieldDef,\n override: ResourceColumn<T> | undefined,\n getRowLabel: RowLabeler | undefined,\n): ColumnDef<T> {\n const customCell = override?.cell;\n return {\n id: field.name,\n accessorFn: (row) => asRecord(row)[field.name],\n header: headerTemplate(override?.header ?? field.label),\n cell:\n customCell !== undefined\n ? (ctx) => customCell(ctx.row.original)\n : (ctx) => renderFieldCell(field, ctx.getValue(), getRowLabel),\n enableSorting: override?.sortable ?? !UNSORTABLE_KINDS.has(field.kind),\n };\n}\n\n/**\n * Builds the derived column set: domain columns (schema order), then any\n * shown audit columns (AUDIT_FIELDS order), then `columns` entries naming\n * fields the schema does not declare — plain accessor columns (escape hatch\n * for computed or server-extra keys). `columns` overrides merge onto their\n * fields; naming a default-skipped field (json, audit, ...) shows it.\n */\nexport function deriveColumns<T>(args: DeriveColumnsArgs<T>): Array<ColumnDef<T>> {\n const pending = new Map<string, ResourceColumn<T>>(\n (args.columns ?? []).map((column) => [column.field, column]),\n );\n const defs: Array<ColumnDef<T>> = [];\n const { domain, audit } = partitionAuditFields(args.fields);\n\n for (const field of [...domain, ...audit]) {\n const override = pending.get(field.name);\n pending.delete(field.name);\n if (override?.hidden === true) continue;\n if (override === undefined) {\n if (field.writeOnly || DEFAULT_SKIPPED_KINDS.has(field.kind)) continue;\n if (args.showAuditFields !== true && isAuditField(field)) continue;\n }\n defs.push(columnForField(field, override, args.getRowLabel));\n }\n\n for (const [name, override] of pending) {\n if (override.hidden === true) continue;\n const customCell = override.cell;\n defs.push({\n id: name,\n accessorFn: (row) => asRecord(row)[name],\n header: headerTemplate(override.header ?? humanize(name)),\n cell:\n customCell !== undefined\n ? (ctx) => customCell(ctx.row.original)\n : (ctx) => {\n const value = ctx.getValue();\n return value === null || value === undefined ? <EmptyValue /> : String(value);\n },\n enableSorting: override.sortable ?? false,\n });\n }\n\n return defs;\n}\n","/**\n * Import and export hooks (karni.transfer, ADR 0002 P6).\n *\n * - `downloadResourceExport(client, resource, params, format)` fetches\n * `GET /<resource>/export/` with the list's own query (filters, search,\n * ordering) and hands the file to the browser — what ResourceTable's export\n * buttons call.\n * - `useImportDescribe(resource)` reads `GET /<resource>/import/`: the\n * importable fields and the user's remembered mapping.\n * - `useImportJob(resource, jobId)` reads one job's state and polls while the\n * backend is previewing or committing it in Celery.\n * - `useImportActions(resource)` holds the three mutations: upload (creates\n * the job), preview (the mandatory dry run, with the mapping) and commit.\n *\n * The backend decides everything that matters: which fields the role may\n * write, which rows are in scope, what a row's errors are. The hooks render\n * its answers without filtering.\n */\nimport {\n useMutation,\n useQuery,\n useQueryClient,\n type UseMutationResult,\n type UseQueryOptions,\n type UseQueryResult,\n} from \"@tanstack/react-query\";\nimport type { KarniClient, KarniQueryValue } from \"../schema/client\";\nimport { useKarniClient } from \"../schema/provider\";\nimport { karniKeys } from \"./keys\";\nimport { buildListQuery, listPath } from \"./params\";\nimport type { ResourceListParams } from \"./types\";\n\nexport type ExportFormat = \"csv\" | \"xlsx\";\n\nexport type ImportColumnKind =\n | \"text\"\n | \"integer\"\n | \"decimal\"\n | \"boolean\"\n | \"date\"\n | \"datetime\"\n | \"choice\"\n | \"relation\"\n | \"relations\"\n | \"json\"\n | \"file\"\n | \"other\";\n\nexport interface ImportColumn {\n name: string;\n label: string;\n kind: ImportColumnKind;\n required: boolean;\n readable: boolean;\n writable: boolean;\n choices: ReadonlyArray<{ value: string; label: string }>;\n /** `app_label.model` of a relation's target. */\n target: string | null;\n /** The target field a relation column carries (its natural key), else the id. */\n lookup: string | null;\n help: string;\n /** The column an import matches existing rows on. */\n key: boolean;\n}\n\nexport interface ImportDescription {\n fields: ImportColumn[];\n /** The mapping the user last confirmed for this resource (header → field). */\n mapping: Record<string, string>;\n /** Files with more rows than this run in Celery; poll the job. */\n inline_rows: number;\n max_rows: number;\n key: string | null;\n}\n\nexport type ImportStatus =\n \"uploaded\" | \"previewing\" | \"previewed\" | \"committing\" | \"done\" | \"failed\";\n\nexport interface ImportResult {\n rows_total: number;\n created: number;\n updated: number;\n unchanged: number;\n errors: number;\n skipped: number;\n}\n\nexport interface ImportProblem {\n /** The line in the file (the header is line 1). */\n row: number;\n field: string;\n message: string;\n}\n\nexport interface ImportJob {\n id: string;\n model: string | null;\n status: ImportStatus;\n file_name: string;\n format: string;\n columns: string[];\n mapping: Record<string, string>;\n rows_total: number;\n rows_done: number;\n async: boolean;\n result: ImportResult | null;\n problems: ImportProblem[];\n error: string | null;\n batch: number | null;\n created_at: string | null;\n fields?: ImportColumn[];\n}\n\n/** The query key of a resource's import description. */\nexport function importDescribeKey(resource: string): readonly unknown[] {\n return [...karniKeys.resource(resource), \"import\", \"describe\"] as const;\n}\n\n/** The query key of one import job. */\nexport function importJobKey(resource: string, jobId: string): readonly unknown[] {\n return [...karniKeys.resource(resource), \"import\", \"job\", jobId] as const;\n}\n\nfunction importPath(resource: string, suffix = \"\"): string {\n return `${listPath(resource)}import/${suffix}`;\n}\n\nconst IN_FLIGHT: ReadonlySet<ImportStatus> = new Set<ImportStatus>([\"previewing\", \"committing\"]);\n\n/** True while an import job is previewing or committing (the states worth polling). */\nexport function isImportInFlight(job: ImportJob | undefined): boolean {\n return job !== undefined && IN_FLIGHT.has(job.status);\n}\n\n/** The name the backend suggested, else \"<resource>.<format>\". */\nfunction filenameFrom(response: Response, fallback: string): string {\n const header = response.headers.get(\"content-disposition\") ?? \"\";\n const match = /filename=\"?([^\";]+)\"?/i.exec(header);\n return match?.[1] ?? fallback;\n}\n\n/**\n * Fetches `GET /<resource>/export/?format=…` with the list's query and saves\n * it through a temporary object URL. Resolves with the file name. Throws the\n * `KarniApiError` the backend answered (a 400 with code E803 when the export\n * is larger than `KARNI_EXPORT_MAX_ROWS`).\n */\nexport async function downloadResourceExport(\n client: KarniClient,\n resource: string,\n params: ResourceListParams | undefined,\n format: ExportFormat = \"csv\",\n): Promise<string> {\n const query: Record<string, KarniQueryValue> = { ...buildListQuery(params), format };\n delete query[\"page\"];\n delete query[\"page_size\"];\n const response = await client.requestRaw(`${listPath(resource)}export/`, { query });\n const blob = await response.blob();\n const filename = filenameFrom(response, `${resource}.${format}`);\n saveBlob(blob, filename);\n return filename;\n}\n\n/** Hands a blob to the browser as a download (a no-op outside a DOM, e.g. SSR). */\nexport function saveBlob(blob: Blob, filename: string): void {\n if (typeof document === \"undefined\" || typeof URL.createObjectURL !== \"function\") return;\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = filename;\n document.body.appendChild(anchor);\n anchor.click();\n anchor.remove();\n URL.revokeObjectURL(url);\n}\n\n/** Fetches `GET /<resource>/import/template/?format=…` and saves it (the headers, an example, allowed values). */\nexport async function downloadImportTemplate(\n client: KarniClient,\n resource: string,\n format: ExportFormat = \"xlsx\",\n): Promise<string> {\n const response = await client.requestRaw(importPath(resource, \"template/\"), {\n query: { format },\n });\n const blob = await response.blob();\n const filename = filenameFrom(response, `${resource}-template.${format}`);\n saveBlob(blob, filename);\n return filename;\n}\n\n/** Fetches what a resource's import accepts: its columns, required fields and allowed values. */\nexport function useImportDescribe(\n resource: string,\n options?: Omit<UseQueryOptions<ImportDescription>, \"queryKey\" | \"queryFn\">,\n): UseQueryResult<ImportDescription> {\n const client = useKarniClient();\n return useQuery<ImportDescription>({\n ...options,\n queryKey: importDescribeKey(resource),\n queryFn: ({ signal }) => client.request<ImportDescription>(importPath(resource), { signal }),\n });\n}\n\nexport interface UseImportJobOptions {\n /** Polling interval while the job is previewing/committing. Default 1500 ms. */\n pollMs?: number;\n}\n\n/** Fetches one import job and polls it while it runs. */\nexport function useImportJob(\n resource: string,\n jobId: string | undefined,\n options?: UseImportJobOptions,\n): UseQueryResult<ImportJob> {\n const client = useKarniClient();\n const pollMs = options?.pollMs ?? 1500;\n return useQuery<ImportJob>({\n queryKey: importJobKey(resource, jobId ?? \"\"),\n enabled: jobId !== undefined,\n queryFn: ({ signal }) =>\n client.request<ImportJob>(importPath(resource, `${encodeURIComponent(jobId ?? \"\")}/`), {\n signal,\n }),\n refetchInterval: (query) => (isImportInFlight(query.state.data) ? pollMs : false),\n });\n}\n\nexport interface UploadImportInput {\n file: File;\n /** An explicit mapping; otherwise the backend suggests or remembers one. */\n mapping?: Record<string, string>;\n}\n\nexport interface PreviewImportInput {\n jobId: string;\n mapping: Record<string, string>;\n}\n\nexport interface ImportActions {\n upload: UseMutationResult<ImportJob, unknown, UploadImportInput>;\n preview: UseMutationResult<ImportJob, unknown, PreviewImportInput>;\n commit: UseMutationResult<ImportJob, unknown, string>;\n}\n\n/** Upload, preview and commit mutations for a resource's import jobs. */\nexport function useImportActions(resource: string): ImportActions {\n const client = useKarniClient();\n const queryClient = useQueryClient();\n\n const store = (job: ImportJob): ImportJob => {\n queryClient.setQueryData(importJobKey(resource, job.id), job);\n return job;\n };\n\n const upload = useMutation<ImportJob, unknown, UploadImportInput>({\n mutationFn: async ({ file, mapping }) => {\n const form = new FormData();\n form.append(\"file\", file);\n if (mapping !== undefined) form.append(\"mapping\", JSON.stringify(mapping));\n return store(\n await client.request<ImportJob>(importPath(resource), { method: \"POST\", body: form }),\n );\n },\n });\n\n const preview = useMutation<ImportJob, unknown, PreviewImportInput>({\n mutationFn: async ({ jobId, mapping }) =>\n store(\n await client.request<ImportJob>(\n importPath(resource, `${encodeURIComponent(jobId)}/preview/`),\n {\n method: \"POST\",\n body: { mapping },\n },\n ),\n ),\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: importDescribeKey(resource) });\n },\n });\n\n const commit = useMutation<ImportJob, unknown, string>({\n mutationFn: async (jobId) =>\n store(\n await client.request<ImportJob>(\n importPath(resource, `${encodeURIComponent(jobId)}/commit/`),\n {\n method: \"POST\",\n body: {},\n },\n ),\n ),\n onSuccess: (job) => {\n if (job.status === \"done\") {\n void queryClient.invalidateQueries({ queryKey: karniKeys.resource(resource) });\n }\n },\n });\n\n return { upload, preview, commit };\n}\n","/**\n * ResourceTable's export buttons (karni.transfer, ADR 0002 P6): one per\n * format, each downloading `GET /<resource>/export/` with the table's current\n * filters, search and ordering — the backend applies the row scope and the\n * role's field visibility, so the file is exactly what the table may show.\n *\n * Internal to @karni/ui — the public surface is ResourceTable's `exportFormats`.\n */\nimport * as React from \"react\";\nimport type { ResourceListParams } from \"../../../hooks/types\";\nimport { downloadResourceExport, type ExportFormat } from \"../../../hooks/useResourceImport\";\nimport { useKarniClient } from \"../../../schema/provider\";\nimport { Button } from \"../../primitives/button\";\n\nexport interface ExportButtonsProps {\n resource: string;\n params: ResourceListParams;\n formats: readonly ExportFormat[];\n}\n\nfunction describe(error: unknown): string {\n if (error instanceof Error) {\n const data = (error as { data?: unknown }).data;\n if (typeof data === \"object\" && data !== null && \"detail\" in data) {\n const detail = (data as { detail?: unknown }).detail;\n if (typeof detail === \"string\") return detail;\n }\n return error.message;\n }\n return \"The export failed.\";\n}\n\nexport function ExportButtons({\n resource,\n params,\n formats,\n}: ExportButtonsProps): React.ReactElement {\n const client = useKarniClient();\n const [busy, setBusy] = React.useState<ExportFormat | null>(null);\n const [error, setError] = React.useState<string | null>(null);\n\n const run = (format: ExportFormat): void => {\n setBusy(format);\n setError(null);\n downloadResourceExport(client, resource, params, format)\n .catch((failure: unknown) => setError(describe(failure)))\n .finally(() => setBusy(null));\n };\n\n return (\n <div className=\"flex items-center gap-2\" data-testid=\"resource-table-export\">\n {formats.map((format) => (\n <Button\n key={format}\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={busy !== null}\n onClick={() => run(format)}\n aria-label={`Export as ${format.toUpperCase()}`}\n >\n {busy === format ? \"Exporting…\" : `Export ${format.toUpperCase()}`}\n </Button>\n ))}\n {error !== null && (\n <span role=\"alert\" className=\"text-sm text-destructive\">\n {error}\n </span>\n )}\n </div>\n );\n}\n","/**\n * Single-item hook for one resource (contract \"Hooks\" + D11).\n *\n * `useResourceItem<Event>(\"events\", id, { expand: [\"venue\"] })` fetches\n * `GET /<resource>/<id>/?expand=venue` and caches it under\n * `karniKeys.detail(resource, id, params)` — params participate in the key,\n * so an expanded detail view and an unexpanded edit form never clobber each\n * other's cache entry, while `karniKeys.resource(resource)` invalidation\n * still reaches both.\n *\n * Escape hatch: `options` forwards every TanStack Query option except\n * `queryKey`/`queryFn` (e.g. `enabled` for \"fetch only when an id exists\").\n */\nimport { useQuery, type UseQueryOptions, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useKarniClient } from \"../schema/provider\";\nimport { karniKeys } from \"./keys\";\nimport { buildItemQuery, detailPath } from \"./params\";\nimport type { ResourceItemParams } from \"./types\";\n\n/** Fetches one row of a resource (`GET /<resource>/<id>/`), optionally expanded. */\nexport function useResourceItem<T = Record<string, unknown>>(\n resource: string,\n id: string | number,\n params?: ResourceItemParams,\n options?: Omit<UseQueryOptions<T>, \"queryKey\" | \"queryFn\">,\n): UseQueryResult<T> {\n const client = useKarniClient();\n return useQuery<T>({\n ...options,\n queryKey: karniKeys.detail(resource, id, params),\n queryFn: ({ signal }) =>\n client.request<T>(detailPath(resource, id), { query: buildItemQuery(params), signal }),\n });\n}\n","import * as React from \"react\";\n\n/** Returns `value` after it has been stable for `delayMs` (D8: search debounce). */\nexport function useDebouncedValue<T>(value: T, delayMs: number): T {\n const [debounced, setDebounced] = React.useState(value);\n\n React.useEffect(() => {\n if (delayMs <= 0) {\n setDebounced(value);\n return undefined;\n }\n const timer = setTimeout(() => setDebounced(value), delayMs);\n return () => clearTimeout(timer);\n }, [value, delayMs]);\n\n return debounced;\n}\n","import * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { useResourceItem } from \"../../../hooks/useResourceItem\";\nimport { useResourceList } from \"../../../hooks/useResourceList\";\nimport type { ResourceListParams } from \"../../../hooks/types\";\nimport { cn } from \"../../../lib/cn\";\nimport { CheckIcon, ChevronDownIcon } from \"../../primitives/icons\";\nimport { displayLabel } from \"../displayLabel\";\nimport { useDebouncedValue } from \"./use-debounced-value\";\nimport { registerComponentRole } from \"../../../lib/roles\";\n\nregisterComponentRole(\"async-select\", \"ResourceSelect\");\n\ntype ResourceItemRecord = Record<string, unknown>;\n\nexport interface ResourceSelectProps {\n resource: string;\n value: string | number | ReadonlyArray<string | number> | null;\n onChange: (value: string | number | Array<string | number> | null) => void;\n multiple?: boolean;\n disabled?: boolean;\n placeholder?: string;\n /** Defaults to displayLabel(). */\n getOptionLabel?: (item: Record<string, unknown>) => React.ReactNode;\n /** Extra filter params sent with the search request. */\n filter?: Record<string, string | number | boolean>;\n id?: string;\n className?: string;\n /** Page size for the option request (only the first page is fetched, D8). */\n pageSize?: number;\n /** Set false to hide the clear affordance (which emits null). Default true. */\n clearable?: boolean;\n /** Debounce for the ?search= request in ms. Default 300 (D8). */\n searchDebounceMs?: number;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n}\n\nfunction idOf(item: ResourceItemRecord): string | number {\n const value = item[\"id\"];\n if (typeof value === \"string\" || typeof value === \"number\") return value;\n return String(value);\n}\n\nfunction optionDomId(listboxId: string, index: number): string {\n return `${listboxId}-option-${index}`;\n}\n\nfunction XIcon(props: React.SVGAttributes<SVGSVGElement>): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Searchable picker for a related row, querying the related resource as you type.\n *\n * Contract D8.\n *\n * A text input drives a debounced `?search=` list request; options render in\n * a NON-MODAL Radix Popover whose auto-focus is prevented so keyboard focus\n * never leaves the input. The input implements the ARIA 1.2 combobox pattern\n * (combobox → listbox with aria-activedescendant). Pre-selected ids that were\n * never seen in a result page are resolved through detail fetches, and the\n * clear affordance emits `null`.\n */\nexport function ResourceSelect(props: ResourceSelectProps): React.ReactElement {\n const {\n resource,\n value,\n onChange,\n multiple = false,\n disabled = false,\n placeholder,\n getOptionLabel,\n filter,\n id,\n className,\n pageSize,\n clearable = true,\n searchDebounceMs = 300,\n } = props;\n\n const reactId = React.useId();\n const inputId = id ?? reactId;\n const listboxId = `${inputId}-listbox`;\n\n const [open, setOpen] = React.useState(false);\n const [inputText, setInputText] = React.useState(\"\");\n const [activeIndex, setActiveIndex] = React.useState(0);\n const [cache, setCache] = React.useState<Record<string, ResourceItemRecord>>({});\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const contentRef = React.useRef<HTMLDivElement>(null);\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n const debouncedSearch = useDebouncedValue(inputText.trim(), searchDebounceMs);\n\n const selected: ReadonlyArray<string | number> = React.useMemo(() => {\n if (value == null) return [];\n return Array.isArray(value) ? value : [value as string | number];\n }, [value]);\n\n const listParams: ResourceListParams = React.useMemo(() => {\n const params: ResourceListParams = { page: 1 };\n if (pageSize !== undefined) params.pageSize = pageSize;\n if (debouncedSearch !== \"\") params.search = debouncedSearch;\n if (filter !== undefined) params.filters = filter;\n return params;\n }, [pageSize, debouncedSearch, filter]);\n\n const listQuery = useResourceList(resource, listParams, { enabled: open && !disabled });\n const results: readonly ResourceItemRecord[] = listQuery.data?.results ?? [];\n\n // Remember every row we have seen, so selected values can always be labelled.\n React.useEffect(() => {\n const rows = listQuery.data?.results;\n if (rows === undefined || rows.length === 0) return;\n setCache((previous) => {\n let changed = false;\n const next = { ...previous };\n for (const row of rows) {\n const key = String(idOf(row));\n if (!(key in next)) {\n next[key] = row;\n changed = true;\n }\n }\n return changed ? next : previous;\n });\n }, [listQuery.data]);\n\n // Pre-selected ids never seen in a result page are resolved one at a time\n // through the detail endpoint (D8 selected-id resolution).\n const unresolvedId = selected.find((sel) => !(String(sel) in cache));\n const itemQuery = useResourceItem(resource, unresolvedId ?? \"\", undefined, {\n enabled: unresolvedId !== undefined && !disabled,\n retry: false,\n });\n const resolvedItem = itemQuery.data;\n const resolveError = itemQuery.error;\n\n React.useEffect(() => {\n if (unresolvedId === undefined) return;\n if (resolvedItem !== undefined) {\n setCache((previous) => ({ ...previous, [String(unresolvedId)]: resolvedItem }));\n } else if (resolveError != null) {\n // Give up on this id (the raw id becomes its label) so resolution of any\n // remaining ids can continue instead of refetching forever.\n setCache((previous) => ({ ...previous, [String(unresolvedId)]: { id: unresolvedId } }));\n }\n }, [unresolvedId, resolvedItem, resolveError]);\n\n const labelOf = React.useCallback(\n (item: ResourceItemRecord): React.ReactNode =>\n getOptionLabel !== undefined ? getOptionLabel(item) : displayLabel(item),\n [getOptionLabel],\n );\n\n const textOf = React.useCallback(\n (sel: string | number): string => {\n const item = cache[String(sel)];\n if (item === undefined) return String(sel);\n const label = getOptionLabel !== undefined ? getOptionLabel(item) : displayLabel(item);\n if (typeof label === \"string\") return label;\n if (typeof label === \"number\") return String(label);\n return displayLabel(item);\n },\n [cache, getOptionLabel],\n );\n\n const openPopover = React.useCallback(() => {\n if (disabled) return;\n setInputText(\"\");\n setActiveIndex(0);\n setOpen(true);\n }, [disabled]);\n\n const closePopover = React.useCallback(() => {\n setOpen(false);\n setInputText(\"\");\n }, []);\n\n const isSelected = React.useCallback(\n (optionId: string | number): boolean =>\n selected.some((sel) => String(sel) === String(optionId)),\n [selected],\n );\n\n const toggleOption = (item: ResourceItemRecord): void => {\n const optionId = idOf(item);\n setCache((previous) =>\n String(optionId) in previous ? previous : { ...previous, [String(optionId)]: item },\n );\n if (multiple) {\n const next = isSelected(optionId)\n ? selected.filter((sel) => String(sel) !== String(optionId))\n : [...selected, optionId];\n onChange([...next]);\n } else {\n onChange(optionId);\n closePopover();\n }\n };\n\n const clearSelection = (): void => {\n onChange(null);\n setInputText(\"\");\n inputRef.current?.focus();\n };\n\n const singleText = !multiple && selected.length > 0 ? textOf(selected[0]) : \"\";\n const inputValue = open ? inputText : multiple ? \"\" : singleText;\n\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>): void => {\n const next = event.target.value;\n if (!open) {\n if (disabled) return;\n setActiveIndex(0);\n setOpen(true);\n // While closed the input showed the selected label; typing appends to\n // it, so strip the label prefix and keep only the fresh keystrokes.\n setInputText(\n singleText !== \"\" && next.startsWith(singleText) ? next.slice(singleText.length) : next,\n );\n return;\n }\n setActiveIndex(0);\n setInputText(next);\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {\n if (disabled) return;\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n if (!open) openPopover();\n else if (results.length > 0) setActiveIndex((index) => (index + 1) % results.length);\n break;\n case \"ArrowUp\":\n event.preventDefault();\n if (!open) openPopover();\n else if (results.length > 0) {\n setActiveIndex((index) => (index - 1 + results.length) % results.length);\n }\n break;\n case \"Enter\":\n if (open) {\n event.preventDefault();\n const item = results[activeIndex];\n if (item !== undefined) toggleOption(item);\n }\n break;\n case \"Escape\":\n if (open) {\n event.preventDefault();\n event.stopPropagation();\n closePopover();\n }\n break;\n case \"Backspace\":\n if (multiple && inputText === \"\" && selected.length > 0) {\n onChange([...selected.slice(0, -1)]);\n }\n break;\n case \"Tab\":\n if (open) closePopover();\n break;\n default:\n break;\n }\n };\n\n const handleBlur = (event: React.FocusEvent<HTMLInputElement>): void => {\n const next = event.relatedTarget as Node | null;\n if (\n next !== null &&\n (rootRef.current?.contains(next) === true || contentRef.current?.contains(next) === true)\n ) {\n return;\n }\n if (open) closePopover();\n };\n\n const listContent = ((): React.ReactNode => {\n if (listQuery.isLoading) {\n return <div className=\"px-2 py-1.5 text-sm text-muted-foreground\">Loading…</div>;\n }\n if (listQuery.error != null) {\n return (\n <div role=\"alert\" className=\"px-2 py-1.5 text-sm text-destructive\">\n Failed to load options.\n </div>\n );\n }\n if (results.length === 0) {\n return <div className=\"px-2 py-1.5 text-sm text-muted-foreground\">No results</div>;\n }\n return results.map((item, index) => {\n const optionId = idOf(item);\n const optionSelected = isSelected(optionId);\n return (\n <div\n key={String(optionId)}\n id={optionDomId(listboxId, index)}\n role=\"option\"\n aria-selected={optionSelected}\n data-highlighted={index === activeIndex ? \"true\" : undefined}\n className=\"flex cursor-default select-none items-center justify-between gap-2 rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted=true]:bg-accent data-[highlighted=true]:text-accent-foreground\"\n onMouseDown={(event) => event.preventDefault()}\n onMouseMove={() => setActiveIndex(index)}\n onClick={() => toggleOption(item)}\n >\n <span className=\"truncate\">{labelOf(item)}</span>\n {optionSelected ? <CheckIcon className=\"h-4 w-4 shrink-0\" /> : null}\n </div>\n );\n });\n })();\n\n return (\n <PopoverPrimitive.Root\n open={open}\n onOpenChange={(next) => {\n if (!next) closePopover();\n }}\n modal={false}\n >\n <PopoverPrimitive.Anchor asChild>\n <div\n ref={rootRef}\n onClick={() => {\n if (disabled) return;\n inputRef.current?.focus();\n if (!open) openPopover();\n }}\n className={cn(\n \"flex min-h-10 w-full flex-wrap items-center gap-1.5 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2\",\n disabled && \"cursor-not-allowed opacity-50\",\n className,\n )}\n >\n {multiple\n ? selected.map((sel) => {\n const chipText = textOf(sel);\n return (\n <span\n key={String(sel)}\n className=\"inline-flex items-center gap-1 rounded-sm bg-secondary px-1.5 py-0.5 text-xs text-secondary-foreground\"\n >\n {chipText}\n {!disabled ? (\n <button\n type=\"button\"\n aria-label={`Remove ${chipText}`}\n className=\"rounded-sm opacity-70 hover:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n onClick={(event) => {\n event.stopPropagation();\n onChange([...selected.filter((other) => String(other) !== String(sel))]);\n }}\n >\n <XIcon className=\"h-3 w-3\" />\n </button>\n ) : null}\n </span>\n );\n })\n : null}\n <input\n ref={inputRef}\n id={inputId}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={listboxId}\n aria-autocomplete=\"list\"\n aria-activedescendant={\n open && results.length > 0 ? optionDomId(listboxId, activeIndex) : undefined\n }\n aria-label={props[\"aria-label\"]}\n aria-labelledby={props[\"aria-labelledby\"]}\n autoComplete=\"off\"\n disabled={disabled}\n placeholder={selected.length === 0 ? placeholder : undefined}\n value={inputValue}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onClick={() => {\n if (!open) openPopover();\n }}\n onBlur={handleBlur}\n className=\"min-w-16 flex-1 bg-transparent outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed\"\n />\n {clearable && selected.length > 0 && !disabled ? (\n <button\n type=\"button\"\n aria-label=\"Clear selection\"\n className=\"rounded-sm p-0.5 text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n onMouseDown={(event) => event.preventDefault()}\n onClick={(event) => {\n event.stopPropagation();\n clearSelection();\n }}\n >\n <XIcon className=\"h-4 w-4\" />\n </button>\n ) : null}\n <ChevronDownIcon className=\"h-4 w-4 shrink-0 opacity-50\" />\n </div>\n </PopoverPrimitive.Anchor>\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={contentRef}\n side=\"bottom\"\n align=\"start\"\n sideOffset={4}\n onOpenAutoFocus={(event) => event.preventDefault()}\n onCloseAutoFocus={(event) => event.preventDefault()}\n onInteractOutside={(event) => {\n const target = event.target;\n if (\n rootRef.current !== null &&\n target instanceof Node &&\n rootRef.current.contains(target)\n ) {\n event.preventDefault();\n }\n }}\n className=\"z-50 max-h-72 w-[var(--radix-popover-trigger-width)] min-w-[12rem] overflow-y-auto rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md\"\n >\n <div role=\"listbox\" id={listboxId} aria-multiselectable={multiple || undefined}>\n {listContent}\n </div>\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n );\n}\n","/**\n * ResourceTable's search box + declared-params-derived filter bar (D5).\n *\n * The parent decides WHICH fields filter (enum/boolean/relation fields ∩ the\n * list operation's declared query params, cap 4, `filters` prop overrides);\n * this component only renders the controls:\n * - enum → clearable <Select> (\"All\" clears),\n * - boolean → clearable Yes/No <Select>,\n * - relation → <ResourceSelect> (multiple for many-relations).\n *\n * Internal to @karni/ui — the public surface is ResourceTable's props.\n */\nimport * as React from \"react\";\nimport type { FilterValue } from \"../../../hooks/types\";\nimport type { FieldDef } from \"../../../schema/types\";\nimport { cn } from \"../../../lib/cn\";\nimport { Input } from \"../../primitives/input\";\nimport { Select } from \"../../primitives/select\";\nimport { ResourceSelect } from \"../ResourceSelect\";\nimport { enumLabel } from \"./table-utils\";\n\nexport interface FilterBarProps {\n /** Whether the list operation declares a `search` query param. */\n searchEnabled: boolean;\n searchValue: string;\n onSearchChange: (value: string) => void;\n searchPlaceholder?: string;\n /** Already-derived filter fields, in render order. */\n filterFields: readonly FieldDef[];\n values: Readonly<Record<string, FilterValue>>;\n onFilterChange: (field: FieldDef, value: FilterValue) => void;\n className?: string;\n}\n\nfunction toSelectValue(value: FilterValue): string | null {\n if (value === null || value === undefined || typeof value === \"object\") return null;\n return String(value);\n}\n\nfunction toRelationValue(\n value: FilterValue,\n): string | number | ReadonlyArray<string | number> | null {\n if (value === null || value === undefined || typeof value === \"boolean\") return null;\n if (Array.isArray(value)) {\n return value.filter(\n (item): item is string | number => typeof item === \"string\" || typeof item === \"number\",\n );\n }\n return value as string | number;\n}\n\nfunction EnumFilter({\n field,\n value,\n onFilterChange,\n}: {\n field: FieldDef;\n value: FilterValue;\n onFilterChange: FilterBarProps[\"onFilterChange\"];\n}): React.ReactElement {\n const options = (field.enumValues ?? []).map((member) => ({\n value: String(member),\n label: enumLabel(member, field.enumLabels),\n }));\n return (\n <Select\n aria-label={field.label}\n className=\"h-9 w-auto min-w-36\"\n value={toSelectValue(value)}\n options={options}\n placeholder={field.label}\n clearable\n clearLabel=\"All\"\n onValueChange={(next) => {\n if (next === null) {\n onFilterChange(field, null);\n return;\n }\n // Preserve the member's original type (numeric enums stay numbers).\n const member = (field.enumValues ?? []).find((candidate) => String(candidate) === next);\n onFilterChange(field, member ?? next);\n }}\n />\n );\n}\n\nfunction BooleanFilter({\n field,\n value,\n onFilterChange,\n}: {\n field: FieldDef;\n value: FilterValue;\n onFilterChange: FilterBarProps[\"onFilterChange\"];\n}): React.ReactElement {\n return (\n <Select\n aria-label={field.label}\n className=\"h-9 w-auto min-w-36\"\n value={typeof value === \"boolean\" ? String(value) : null}\n options={[\n { value: \"true\", label: \"Yes\" },\n { value: \"false\", label: \"No\" },\n ]}\n placeholder={field.label}\n clearable\n clearLabel=\"All\"\n onValueChange={(next) => onFilterChange(field, next === null ? null : next === \"true\")}\n />\n );\n}\n\n/** Search box + up to four filter controls in one wrapping row. */\nexport function FilterBar(props: FilterBarProps): React.ReactElement {\n const {\n searchEnabled,\n searchValue,\n onSearchChange,\n searchPlaceholder = \"Search…\",\n filterFields,\n values,\n onFilterChange,\n className,\n } = props;\n\n return (\n <div className={cn(\"flex flex-wrap items-center gap-2\", className)}>\n {searchEnabled && (\n <Input\n type=\"search\"\n aria-label=\"Search\"\n placeholder={searchPlaceholder}\n value={searchValue}\n onChange={(event) => onSearchChange(event.target.value)}\n className=\"h-9 w-full max-w-xs\"\n />\n )}\n {filterFields.map((field) => {\n const value = values[field.name];\n if (field.kind === \"enum\") {\n return (\n <EnumFilter\n key={field.name}\n field={field}\n value={value}\n onFilterChange={onFilterChange}\n />\n );\n }\n if (field.kind === \"boolean\") {\n return (\n <BooleanFilter\n key={field.name}\n field={field}\n value={value}\n onFilterChange={onFilterChange}\n />\n );\n }\n if (field.kind === \"relation\" && field.relation !== undefined) {\n return (\n <div key={field.name} className=\"min-w-36\">\n <ResourceSelect\n resource={field.relation.resource}\n multiple={field.relation.many}\n value={toRelationValue(value)}\n placeholder={field.label}\n onChange={(next) => onFilterChange(field, next)}\n />\n </div>\n );\n }\n return null;\n })}\n </div>\n );\n}\n","/**\n * ResourceTable's server-mode pagination row (DRF PageNumberPagination:\n * `{count, next, previous, results}` with `page` / `page_size` params).\n * Internal to @karni/ui — the public surface is ResourceTable's props.\n */\nimport * as React from \"react\";\nimport { cn } from \"../../../lib/cn\";\nimport { Button } from \"../../primitives/button\";\n\nexport interface PaginationControlsProps {\n /** 1-based current page. */\n page: number;\n pageCount: number;\n /** Total item count across all pages (DRF `count`). */\n totalCount: number;\n /** From DRF `previous` / `next` — the server is the authority. */\n hasPrevious: boolean;\n hasNext: boolean;\n onPageChange: (page: number) => void;\n className?: string;\n}\n\nexport function PaginationControls(props: PaginationControlsProps): React.ReactElement {\n const { page, pageCount, totalCount, hasPrevious, hasNext, onPageChange, className } = props;\n return (\n <nav\n aria-label=\"Pagination\"\n className={cn(\"flex flex-wrap items-center justify-between gap-3\", className)}\n >\n <p className=\"text-sm text-muted-foreground\">\n Page {page} of {pageCount} · {totalCount} {totalCount === 1 ? \"item\" : \"items\"}\n </p>\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={!hasPrevious}\n onClick={() => onPageChange(Math.max(1, page - 1))}\n >\n Previous\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={!hasNext}\n onClick={() => onPageChange(page + 1)}\n >\n Next\n </Button>\n </div>\n </nav>\n );\n}\n","/**\n * Tiny debounce hook for ResourceTable's search box, so a keystroke burst\n * becomes one list query. Internal to @karni/ui.\n */\nimport * as React from \"react\";\n\nexport function useDebouncedValue<T>(value: T, delayMs: number): T {\n const [debounced, setDebounced] = React.useState(value);\n React.useEffect(() => {\n const timer = setTimeout(() => setDebounced(value), delayMs);\n return () => clearTimeout(timer);\n }, [value, delayMs]);\n return debounced;\n}\n","/**\n * ResourceTable — the schema-driven data table (contract \"ResourceTable\" + D5).\n *\n * `<Page title=\"Events\"><ResourceTable resource=\"events\" /></Page>` is a\n * complete screen: columns derive from the parsed OpenAPI schema, sorting maps\n * to DRF `ordering`, the search box renders only when the list operation\n * declares `search`, the filter bar derives from the declared query params,\n * and pagination speaks `page` / `page_size`.\n *\n * Audit fields (AUDIT_FIELDS — id, created_at, updated_at, created_by,\n * updated_by, carried by every BaseModel resource) are hidden by default so\n * domain fields lead; rows stay keyed by `id` regardless (getRowId, row\n * actions, onRowClick, bulk selection). Show one with a `columns` entry\n * (`{ field: \"created_at\" }`), or all of them with `showAuditFields`.\n *\n * Escape hatches: `columns` (per-field overrides), `extraColumns` (ColumnDef\n * passthrough), `columnsOverride` (applied last over the derived + merged\n * domain columns; the selection and actions columns are structural and follow\n * `bulkActions` / `rowActions` / `onEdit` / `enableDelete`), `rowActions`,\n * `bulkActions`, `filters`, `toolbar` / `empty` / `footer` slots,\n * `getRowLabel`, and `className`.\n */\nimport { keepPreviousData, useQueryClient } from \"@tanstack/react-query\";\nimport {\n flexRender,\n getCoreRowModel,\n useReactTable,\n type ColumnDef,\n type RowSelectionState,\n type SortingState,\n type Updater,\n} from \"@tanstack/react-table\";\nimport * as React from \"react\";\nimport { karniKeys } from \"../../../hooks/keys\";\nimport type { FilterValue, ResourceListParams } from \"../../../hooks/types\";\nimport { useResourceList } from \"../../../hooks/useResourceList\";\nimport type { KarniQueryValue } from \"../../../schema/client\";\nimport { useResourceMutations } from \"../../../hooks/useResourceMutations\";\nimport { cn } from \"../../../lib/cn\";\nimport type { FieldDef } from \"../../../schema/types\";\nimport { useSchema } from \"../../../schema/useSchema\";\nimport { EmptyState } from \"../../empty-state/empty-state\";\nimport { Button } from \"../../primitives/button\";\nimport { Checkbox } from \"../../primitives/checkbox\";\nimport { ChevronDownIcon, ChevronUpIcon } from \"../../primitives/icons\";\nimport { Skeleton } from \"../../primitives/skeleton\";\nimport { isAuditField, partitionAuditFields } from \"../audit-fields\";\nimport { displayLabel } from \"../displayLabel\";\nimport type { ExportFormat } from \"../../../hooks/useResourceImport\";\nimport { BulkActionsBar, type BulkAction } from \"./BulkActionsBar\";\nimport { deriveColumns, type ResourceColumn } from \"./derive-columns\";\nimport { ExportButtons } from \"./ExportButtons\";\nimport { FilterBar } from \"./FilterBar\";\nimport { PaginationControls } from \"./PaginationControls\";\nimport {\n asRecord,\n errorMessage,\n isNotFoundError,\n pageCountFor,\n sortingToOrdering,\n} from \"./table-utils\";\nimport { useDebouncedValue } from \"./use-debounced-value\";\nimport { registerComponentRole } from \"../../../lib/roles\";\n\nregisterComponentRole(\"data-table\", \"ResourceTable\");\n\nexport type { BulkAction, ResourceColumn };\n\nexport const DEFAULT_PAGE_SIZE = 25;\nconst SEARCH_DEBOUNCE_MS = 300;\nconst MAX_DERIVED_FILTERS = 4;\n\nexport interface ResourceTableProps<T = Record<string, unknown>> {\n resource: string;\n /**\n * Per-field overrides. Naming a default-hidden field (an audit field such\n * as `created_at`, or a json/file field) shows it; `hidden: true` hides one.\n */\n columns?: ReadonlyArray<ResourceColumn<T>>;\n /**\n * Show the audit columns (AUDIT_FIELDS: id, created_at, updated_at,\n * created_by, updated_by) after the domain columns, and let audit fields\n * into the derived filter bar. Default false: they are hidden.\n */\n showAuditFields?: boolean;\n /** TanStack ColumnDef pass-through, appended after derived columns. */\n extraColumns?: ReadonlyArray<ColumnDef<T>>;\n /** Full escape hatch, applied last over the derived + merged columns. */\n columnsOverride?: (derived: Array<ColumnDef<T>>) => Array<ColumnDef<T>>;\n rowActions?: (row: T) => React.ReactNode;\n /** Passing this enables the default edit row action. */\n onEdit?: (row: T) => void;\n /** Enables the default delete row action (uses useResourceMutations). */\n enableDelete?: boolean;\n bulkActions?: ReadonlyArray<BulkAction>;\n onRowClick?: (row: T) => void;\n /**\n * `expand` query values. Default: single-relation field names ∩ the list\n * operation's expand enum — never guessed beyond the schema (D5).\n */\n expand?: readonly string[];\n initialSorting?: SortingState;\n /** Sent as `page_size`. Default 25. */\n pageSize?: number;\n /**\n * Field names to build the filter bar from; `false` disables it. Default:\n * (enum/boolean/relation fields) ∩ declared list query params, domain\n * fields first, audit fields only with `showAuditFields`, cap 4 (D5).\n * Only enum, boolean and relation fields get controls.\n */\n filters?: readonly string[] | false;\n /**\n * Fixed filters sent with every request and hidden from the filter bar —\n * e.g. `{ event: eventId }` for \"the bookings of this event\". A user filter\n * on the same field never overrides them.\n */\n params?: Readonly<Record<string, KarniQueryValue>>;\n /**\n * Export buttons (one per format) when the resource serves\n * `GET /<resource>/export/` — every Karni BaseViewSet does. The file carries\n * the table's current filters, search and ordering; the backend applies the\n * row scope and field visibility. Default `[\"csv\", \"xlsx\"]`; `false` hides them.\n */\n exportFormats?: readonly ExportFormat[] | false;\n /** Extra toolbar content, rendered to the right of the search/filter row. */\n toolbar?: React.ReactNode;\n /** Replaces the default EmptyState when the list has no results. */\n empty?: React.ReactNode;\n /** Rendered under the pagination row. */\n footer?: React.ReactNode;\n /** Overrides displayLabel() for relation cells (and the delete confirm). */\n getRowLabel?: (row: Record<string, unknown>) => string;\n className?: string;\n}\n\n// structural columns\n\nfunction selectionColumn<T>(): ColumnDef<T> {\n return {\n id: \"__select__\",\n enableSorting: false,\n header: ({ table }) => (\n <Checkbox\n aria-label=\"Select all rows\"\n checked={\n table.getIsAllPageRowsSelected()\n ? true\n : table.getIsSomePageRowsSelected()\n ? \"indeterminate\"\n : false\n }\n onCheckedChange={(checked) => table.toggleAllPageRowsSelected(checked === true)}\n />\n ),\n cell: ({ row }) => (\n <div className=\"flex items-center\" onClick={(event) => event.stopPropagation()}>\n <Checkbox\n aria-label=\"Select row\"\n checked={row.getIsSelected()}\n onCheckedChange={(checked) => row.toggleSelected(checked === true)}\n />\n </div>\n ),\n };\n}\n\nfunction DeleteRowButton(props: {\n resource: string;\n row: Record<string, unknown>;\n getRowLabel?: (row: Record<string, unknown>) => string;\n}): React.ReactElement {\n const mutations = useResourceMutations(props.resource);\n const label = (props.getRowLabel ?? displayLabel)(props.row);\n return (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-destructive hover:text-destructive\"\n disabled={mutations.remove.isPending}\n onClick={() => {\n const id = props.row[\"id\"];\n if (id === null || id === undefined) return;\n const confirmed =\n typeof window === \"undefined\" ||\n typeof window.confirm !== \"function\" ||\n window.confirm(`Delete \"${label}\"? This cannot be undone.`);\n if (confirmed) mutations.remove.mutate(id as string | number);\n }}\n >\n Delete\n </Button>\n );\n}\n\nfunction actionsColumn<T>(options: {\n resource: string;\n rowActions?: (row: T) => React.ReactNode;\n onEdit?: (row: T) => void;\n enableDelete?: boolean;\n getRowLabel?: (row: Record<string, unknown>) => string;\n}): ColumnDef<T> {\n const { resource, rowActions, onEdit, enableDelete, getRowLabel } = options;\n return {\n id: \"__actions__\",\n enableSorting: false,\n header: () => <span className=\"sr-only\">Actions</span>,\n cell: ({ row }) => (\n <div\n className=\"flex items-center justify-end gap-1\"\n onClick={(event) => event.stopPropagation()}\n >\n {onEdit !== undefined && (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => onEdit(row.original)}>\n Edit\n </Button>\n )}\n {rowActions?.(row.original)}\n {enableDelete === true && (\n <DeleteRowButton\n resource={resource}\n row={asRecord(row.original)}\n getRowLabel={getRowLabel}\n />\n )}\n </div>\n ),\n };\n}\n\n// states\n\nfunction TableSkeleton({ rows = 8 }: { rows?: number }): React.ReactElement {\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className=\"flex w-full flex-col gap-3 rounded-md border border-border p-4\"\n >\n <span className=\"sr-only\">Loading…</span>\n <Skeleton className=\"h-6 w-1/3\" />\n {Array.from({ length: rows }, (_, index) => (\n <Skeleton key={index} className=\"h-8 w-full\" />\n ))}\n </div>\n );\n}\n\nfunction ErrorPanel(props: { error: unknown; onRetry?: () => void }): React.ReactElement {\n return (\n <div\n role=\"alert\"\n className=\"flex w-full flex-col items-center gap-3 rounded-md border border-destructive/50 bg-destructive/10 px-6 py-8 text-center\"\n >\n <p className=\"text-sm font-medium text-destructive\">{errorMessage(props.error)}</p>\n {props.onRetry !== undefined && (\n <Button variant=\"outline\" size=\"sm\" onClick={props.onRetry}>\n Retry\n </Button>\n )}\n </div>\n );\n}\n\n/** Mounted only on schema errors, so the hook never runs otherwise. */\nfunction SchemaErrorPanel(props: { error: unknown }): React.ReactElement {\n const queryClient = useQueryClient();\n return (\n <ErrorPanel\n error={props.error}\n onRetry={() => {\n void queryClient.invalidateQueries({ queryKey: karniKeys.schema() });\n }}\n />\n );\n}\n\n// the table\n\n/** Schema-driven data table for one resource: columns, sorting, filters, search, pagination, row actions and bulk select, all derived from the OpenAPI schema. */\nexport function ResourceTable<T = Record<string, unknown>>(\n props: ResourceTableProps<T>,\n): React.ReactElement {\n const {\n resource,\n columns,\n showAuditFields,\n extraColumns,\n columnsOverride,\n rowActions,\n onEdit,\n enableDelete,\n bulkActions,\n onRowClick,\n expand,\n initialSorting,\n pageSize,\n filters,\n params,\n exportFormats,\n toolbar,\n empty,\n footer,\n getRowLabel,\n className,\n } = props;\n\n const schemaResult = useSchema(resource);\n const schema = schemaResult.data;\n\n // server-mode state (TanStack manual)\n const [sorting, setSorting] = React.useState<SortingState>(initialSorting ?? []);\n const [rowSelection, setRowSelection] = React.useState<RowSelectionState>({});\n const [page, setPage] = React.useState(1);\n const [searchInput, setSearchInput] = React.useState(\"\");\n const [filterValues, setFilterValues] = React.useState<Record<string, FilterValue>>({});\n\n const effectivePageSize = pageSize ?? DEFAULT_PAGE_SIZE;\n const debouncedSearch = useDebouncedValue(searchInput, SEARCH_DEBOUNCE_MS);\n\n // A settled search change starts over from page 1 (skip the initial value).\n const lastSearch = React.useRef(debouncedSearch);\n React.useEffect(() => {\n if (lastSearch.current !== debouncedSearch) {\n lastSearch.current = debouncedSearch;\n setPage(1);\n }\n }, [debouncedSearch]);\n\n const handleSortingChange = React.useCallback((updater: Updater<SortingState>) => {\n setSorting((old) => (typeof updater === \"function\" ? updater(old) : updater));\n setPage(1);\n }, []);\n\n const handleFilterChange = React.useCallback((field: FieldDef, value: FilterValue) => {\n setFilterValues((old) => {\n const cleared =\n value === null ||\n value === undefined ||\n value === \"\" ||\n (Array.isArray(value) && value.length === 0);\n if (cleared) {\n return Object.fromEntries(Object.entries(old).filter(([key]) => key !== field.name));\n }\n return { ...old, [field.name]: value };\n });\n setPage(1);\n }, []);\n\n // schema-derived behaviour (D5)\n const expandList = React.useMemo<readonly string[]>(() => {\n if (expand !== undefined) return expand;\n const allowed = schema?.operations.list?.expandEnum;\n if (schema === undefined || allowed === undefined) return [];\n return schema.fields\n .filter(\n (field) =>\n field.kind === \"relation\" &&\n field.relation !== undefined &&\n !field.relation.many &&\n allowed.includes(field.name),\n )\n .map((field) => field.name);\n }, [expand, schema]);\n\n const pinned = React.useMemo(() => new Set(Object.keys(params ?? {})), [params]);\n const filterFields = React.useMemo<readonly FieldDef[]>(() => {\n if (filters === false || schema === undefined) return [];\n if (filters !== undefined) {\n const byName = new Map(schema.fields.map((field) => [field.name, field]));\n return filters\n .filter((name) => !pinned.has(name))\n .map((name) => byName.get(name))\n .filter((field): field is FieldDef => field !== undefined);\n }\n const declared = new Set(schema.operations.list?.queryParams ?? []);\n const { domain, audit } = partitionAuditFields(schema.fields);\n return [...domain, ...audit]\n .filter(\n (field) =>\n !field.writeOnly &&\n !pinned.has(field.name) &&\n (showAuditFields === true || !isAuditField(field)) &&\n declared.has(field.name) &&\n (field.kind === \"enum\" ||\n field.kind === \"boolean\" ||\n (field.kind === \"relation\" && field.relation !== undefined)),\n )\n .slice(0, MAX_DERIVED_FILTERS);\n }, [filters, pinned, schema, showAuditFields]);\n\n const searchEnabled = schema?.operations.list?.hasSearch === true;\n\n // the list query\n const trimmedSearch = debouncedSearch.trim();\n const listParams = React.useMemo<ResourceListParams>(\n () => ({\n page,\n pageSize: effectivePageSize,\n ordering: sortingToOrdering(sorting),\n search: searchEnabled && trimmedSearch.length > 0 ? trimmedSearch : undefined,\n filters:\n Object.keys(filterValues).length > 0 || params !== undefined\n ? { ...filterValues, ...params }\n : undefined,\n expand: expandList.length > 0 ? expandList : undefined,\n }),\n [\n page,\n effectivePageSize,\n sorting,\n searchEnabled,\n trimmedSearch,\n filterValues,\n params,\n expandList,\n ],\n );\n\n const list = useResourceList<T>(resource, listParams, {\n enabled: schema !== undefined,\n placeholderData: keepPreviousData,\n // A 404 is the page-clamp signal (D5) — retrying it only delays the clamp.\n retry: (failureCount, error) => !isNotFoundError(error) && failureCount < 3,\n });\n\n // D5 page-clamp: list 404 with page > 1 → decrement + refetch as loading.\n const clamping = isNotFoundError(list.error) && page > 1;\n React.useEffect(() => {\n if (clamping) setPage((current) => Math.max(1, current - 1));\n }, [clamping, page]);\n\n // columns\n const hasBulkSelect = bulkActions !== undefined && bulkActions.length > 0;\n const hasActions = rowActions !== undefined || onEdit !== undefined || enableDelete === true;\n\n const columnDefs = React.useMemo<Array<ColumnDef<T>>>(() => {\n if (schema === undefined) return [];\n let defs = deriveColumns<T>({ fields: schema.fields, columns, getRowLabel, showAuditFields });\n if (extraColumns !== undefined) defs = [...defs, ...extraColumns];\n if (columnsOverride !== undefined) defs = columnsOverride(defs);\n const leading: Array<ColumnDef<T>> = hasBulkSelect ? [selectionColumn<T>()] : [];\n const trailing: Array<ColumnDef<T>> = hasActions\n ? [actionsColumn<T>({ resource, rowActions, onEdit, enableDelete, getRowLabel })]\n : [];\n return [...leading, ...defs, ...trailing];\n }, [\n schema,\n columns,\n getRowLabel,\n showAuditFields,\n extraColumns,\n columnsOverride,\n hasBulkSelect,\n hasActions,\n resource,\n rowActions,\n onEdit,\n enableDelete,\n ]);\n\n const rows = React.useMemo<T[]>(() => list.data?.results ?? [], [list.data]);\n const count = list.data?.count;\n const pageCount = pageCountFor(count, effectivePageSize);\n\n const table = useReactTable<T>({\n data: rows,\n columns: columnDefs,\n state: { sorting, rowSelection },\n manualSorting: true,\n manualPagination: true,\n manualFiltering: true,\n pageCount,\n enableRowSelection: hasBulkSelect,\n onSortingChange: handleSortingChange,\n onRowSelectionChange: setRowSelection,\n // D5: selection is keyed by String(row.id) and persists across pages —\n // rows always carry `id`, even while its column is hidden.\n getRowId: (row) => String(asRecord(row).id),\n getCoreRowModel: getCoreRowModel(),\n });\n\n const selectedIds = React.useMemo(\n () => Object.keys(rowSelection).filter((id) => rowSelection[id]),\n [rowSelection],\n );\n\n const hasActiveNarrowing = trimmedSearch.length > 0 || Object.keys(filterValues).length > 0;\n\n // render\n let body: React.ReactNode;\n if (schemaResult.error !== null && schemaResult.error !== undefined) {\n body = <SchemaErrorPanel error={schemaResult.error} />;\n } else if (schemaResult.isLoading || schema === undefined || list.isPending || clamping) {\n body = <TableSkeleton />;\n } else if (list.error !== null && list.error !== undefined) {\n body = (\n <ErrorPanel\n error={list.error}\n onRetry={() => {\n void list.refetch();\n }}\n />\n );\n } else if (rows.length === 0) {\n body =\n empty ??\n (hasActiveNarrowing ? (\n <EmptyState title=\"No results\" description=\"Try adjusting your search or filters.\" />\n ) : (\n <EmptyState title=\"Nothing here yet\" description=\"Records will appear here once created.\" />\n ));\n } else {\n body = (\n <>\n <div\n className={cn(\n \"w-full overflow-x-auto rounded-md border border-border\",\n list.isFetching && \"opacity-60\",\n )}\n >\n <table className=\"w-full caption-bottom text-sm\" aria-busy={list.isFetching}>\n <thead className=\"border-b border-border bg-muted\">\n <tr>\n {table.getFlatHeaders().map((header) => {\n const canSort = header.column.getCanSort();\n const direction = header.column.getIsSorted();\n return (\n <th\n key={header.id}\n scope=\"col\"\n aria-sort={\n direction === \"asc\"\n ? \"ascending\"\n : direction === \"desc\"\n ? \"descending\"\n : undefined\n }\n className=\"h-10 px-3 text-left align-middle text-xs font-medium text-muted-foreground\"\n >\n {header.isPlaceholder ? null : canSort ? (\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 rounded-sm hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n onClick={(event) => header.column.getToggleSortingHandler()?.(event)}\n >\n {flexRender(header.column.columnDef.header, header.getContext())}\n {direction === \"asc\" ? (\n <ChevronUpIcon className=\"h-3.5 w-3.5\" />\n ) : direction === \"desc\" ? (\n <ChevronDownIcon className=\"h-3.5 w-3.5\" />\n ) : null}\n </button>\n ) : (\n flexRender(header.column.columnDef.header, header.getContext())\n )}\n </th>\n );\n })}\n </tr>\n </thead>\n <tbody>\n {table.getRowModel().rows.map((row) => (\n <tr\n key={row.id}\n data-state={row.getIsSelected() ? \"selected\" : undefined}\n onClick={onRowClick !== undefined ? () => onRowClick(row.original) : undefined}\n className={cn(\n \"border-b border-border transition-colors last:border-0 hover:bg-muted data-[state=selected]:bg-muted\",\n onRowClick !== undefined && \"cursor-pointer\",\n )}\n >\n {row.getVisibleCells().map((cell) => (\n <td key={cell.id} className=\"px-3 py-2 align-middle\">\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {count !== undefined && count > 0 && (\n <PaginationControls\n page={page}\n pageCount={pageCount}\n totalCount={count}\n hasPrevious={list.data?.previous !== null && list.data?.previous !== undefined}\n hasNext={list.data?.next !== null && list.data?.next !== undefined}\n onPageChange={setPage}\n />\n )}\n </>\n );\n }\n\n const exportList: readonly ExportFormat[] =\n exportFormats === undefined ? [\"csv\", \"xlsx\"] : exportFormats === false ? [] : exportFormats;\n const exportEnabled = exportList.length > 0 && schema?.operations.export !== undefined;\n\n const showFilterRow =\n schema !== undefined &&\n (searchEnabled || filterFields.length > 0 || toolbar !== undefined || exportEnabled);\n\n return (\n <div className={cn(\"flex w-full flex-col gap-3\", className)}>\n {showFilterRow && (\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <FilterBar\n searchEnabled={searchEnabled}\n searchValue={searchInput}\n onSearchChange={setSearchInput}\n filterFields={filterFields}\n values={filterValues}\n onFilterChange={handleFilterChange}\n className=\"min-w-0 flex-1\"\n />\n {(toolbar !== undefined || exportEnabled) && (\n <div className=\"flex shrink-0 items-center gap-2\">\n {exportEnabled && (\n <ExportButtons resource={resource} params={listParams} formats={exportList} />\n )}\n {toolbar}\n </div>\n )}\n </div>\n )}\n {hasBulkSelect && selectedIds.length > 0 && (\n <BulkActionsBar\n selectedIds={selectedIds}\n bulkActions={bulkActions}\n onClear={() => setRowSelection({})}\n />\n )}\n {body}\n {footer}\n </div>\n );\n}\n","/**\n * zodFor — runtime Zod schema generation from a ResourceSchema (contract\n * \"Schema client\" + D3).\n *\n * Rules:\n * - mode \"create\": the create request's required fields are required, the\n * rest are `.optional()`; mode \"update\": ALL fields are optional, with\n * `.nullable()` nested INSIDE `.optional()` so `undefined` means \"not\n * touched\" and `null` means \"clear this nullable field\".\n * - readOnly fields are excluded, writeOnly fields are included.\n * - nullable / maxLength / min / max and the email / url / uuid string\n * formats map onto the obvious Zod validators.\n * - enum → z.enum when every member is a string, otherwise a union of\n * z.literal; \"\" (BlankEnum) and null (NullEnum) are never members — the\n * parser already stripped them, nullability travels on the field.\n * - relation values take their schema from the property's own emitted\n * type/format (integer pk vs uuid pk), arrays of it when `many`.\n * - file → File-or-string; when `File` does not exist (SSR) it degrades to\n * z.string() so imports never crash.\n * - json → z.unknown(); number/integer coerce (form inputs produce strings).\n * - datetime accepts datetime-local input (\"YYYY-MM-DDTHH:mm[:ss]\") and\n * transforms it to full ISO-8601 with offset on submit (D3).\n */\nimport { z } from \"zod\";\nimport type { ZodObject, ZodRawShape, ZodTypeAny } from \"zod\";\nimport type { FieldDef, ResourceSchema } from \"./types\";\n\nconst REQUIRED_MESSAGE = \"This field is required.\";\n\n/** datetime-local output: no timezone designator at the end. */\nconst LOCAL_DATETIME = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d{1,6})?)?$/;\n\nfunction toIsoWithOffset(value: string): string {\n if (!LOCAL_DATETIME.test(value)) return value; // already zoned (or server-side format)\n const date = new Date(value); // datetime-local strings parse as local time\n if (Number.isNaN(date.getTime())) return value;\n return date.toISOString();\n}\n\nfunction enumSchema(values: ReadonlyArray<string | number>): ZodTypeAny {\n if (values.length === 0) return z.never();\n if (values.every((value): value is string => typeof value === \"string\")) {\n return z.enum(values as [string, ...string[]]);\n }\n const literals = values.map((value) => z.literal(value));\n if (literals.length === 1) return literals[0];\n return z.union(literals as unknown as [ZodTypeAny, ZodTypeAny, ...ZodTypeAny[]]);\n}\n\nfunction stringSchema(field: FieldDef, requireNonEmpty: boolean): ZodTypeAny {\n let schema = z.string();\n if (field.format === \"email\") schema = schema.email();\n else if (field.format === \"uri\" || field.format === \"url\") schema = schema.url();\n else if (field.format === \"uuid\") schema = schema.uuid();\n if (field.maxLength !== undefined) schema = schema.max(field.maxLength);\n if (requireNonEmpty) schema = schema.min(1, REQUIRED_MESSAGE);\n return schema;\n}\n\nfunction numberSchema(field: FieldDef, integer: boolean): ZodTypeAny {\n let schema = z.coerce.number();\n if (integer) schema = schema.int();\n if (field.min !== undefined) schema = schema.min(field.min);\n if (field.max !== undefined) schema = schema.max(field.max);\n return schema;\n}\n\nfunction relationValueSchema(field: FieldDef, coerce: boolean): ZodTypeAny {\n switch (field.relationValueType) {\n case \"uuid\":\n return z.string({ required_error: REQUIRED_MESSAGE }).uuid();\n case \"integer\":\n return coerce\n ? z.coerce.number().int()\n : z.number({ required_error: REQUIRED_MESSAGE }).int();\n default:\n return z.string({ required_error: REQUIRED_MESSAGE }).min(1, REQUIRED_MESSAGE);\n }\n}\n\n/**\n * A single relation input left empty arrives as \"\" (an untouched select) or\n * null (a cleared one). A nullable relation then carries null (DRF's\n * allow_null); a required non-nullable one fails with REQUIRED_MESSAGE\n * instead of \"Invalid uuid\" / \"Expected string, received null\"; an optional\n * non-nullable one is omitted. Integer ids typed as strings are coerced.\n */\nfunction singleRelationSchema(field: FieldDef, requireNonEmpty: boolean): ZodTypeAny {\n const value = relationValueSchema(field, false);\n let target: ZodTypeAny = field.nullable ? value.nullable() : value;\n if (!requireNonEmpty) target = target.optional();\n return z.preprocess((raw) => {\n if (raw === \"\" || raw === null || raw === undefined) return field.nullable ? null : undefined;\n if (field.relationValueType === \"integer\" && typeof raw === \"string\" && raw.trim() !== \"\") {\n const parsed = Number(raw);\n return Number.isNaN(parsed) ? raw : parsed;\n }\n return raw;\n }, target);\n}\n\nfunction fileSchema(): ZodTypeAny {\n if (typeof File === \"undefined\") return z.string();\n return z.union([z.instanceof(File), z.string()]);\n}\n\nfunction baseSchemaFor(field: FieldDef, requireNonEmpty: boolean): ZodTypeAny {\n switch (field.kind) {\n case \"string\":\n case \"text\":\n return stringSchema(field, requireNonEmpty);\n case \"integer\":\n return numberSchema(field, true);\n case \"number\":\n return numberSchema(field, false);\n case \"boolean\":\n return z.boolean();\n case \"date\": {\n const schema = z.string();\n return requireNonEmpty ? schema.min(1, REQUIRED_MESSAGE) : schema;\n }\n case \"datetime\": {\n const schema = requireNonEmpty ? z.string().min(1, REQUIRED_MESSAGE) : z.string();\n return schema.transform(toIsoWithOffset);\n }\n case \"enum\":\n return enumSchema(field.enumValues ?? []);\n case \"relation\": {\n if (field.relation?.many === true) return z.array(relationValueSchema(field, true));\n return singleRelationSchema(field, requireNonEmpty);\n }\n case \"file\":\n return fileSchema();\n case \"json\":\n return z.unknown();\n case \"array\":\n return z.array(z.unknown());\n case \"unknown\":\n return z.unknown();\n }\n}\n\n/** Builds a Zod validator for a resource's create or update payload from its schema. */\nexport function zodFor(schema: ResourceSchema, mode: \"create\" | \"update\"): ZodObject<ZodRawShape> {\n const shape: ZodRawShape = {};\n\n for (const field of schema.fields) {\n if (field.readOnly) continue; // writeOnly stays in (D3)\n\n // A required string provided as \"\" must fail in BOTH modes: DRF rejects\n // blank values on required CharFields; in update mode the field may be\n // omitted entirely instead.\n const requireNonEmpty = field.required;\n let fieldSchema = baseSchemaFor(field, requireNonEmpty);\n\n if (field.nullable) fieldSchema = fieldSchema.nullable();\n // D3: in update mode .nullable() sits INSIDE .optional() — undefined\n // means untouched, null clears.\n if (mode === \"update\" || !field.required) fieldSchema = fieldSchema.optional();\n\n shape[field.name] = fieldSchema;\n }\n\n return z.object(shape);\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\n\nregisterComponentRole(\"file-upload\", \"FileUpload\");\n\n/** Why a file was refused by <FileUpload> (surfaced through `onReject`). */\nexport type FileUploadRejectReason = \"accept\" | \"size\";\n\nexport interface FileUploadProps {\n /**\n * Current value. A `string` is an existing uploaded file (the display URL a\n * karni backend returns); a `File` is a pending upload. Arrays are for\n * `multiple` mode and may mix both.\n */\n value?: File | string | ReadonlyArray<File | string> | null;\n /**\n * Emits the newly chosen `File` (or `File[]` when `multiple`), and `null`\n * when the value is cleared. Existing URL strings are display-only: they\n * can be removed (emitting `null` / the remaining files) but never re-emitted.\n */\n onChange?: (value: File | File[] | null) => void;\n /** Same grammar as the native `accept` attribute (\".png,image/*,application/pdf\"). */\n accept?: string;\n multiple?: boolean;\n disabled?: boolean;\n /** Maximum size per file, in bytes. Larger files are rejected via `onReject`. */\n maxSize?: number;\n /** Called once per refused file with the reason (\"accept\" | \"size\"). */\n onReject?: (file: File, reason: FileUploadRejectReason) => void;\n id?: string;\n /** Forwarded to the hidden native file input. */\n name?: string;\n className?: string;\n /** Replaces the default dropzone content (escape hatch). */\n children?: React.ReactNode;\n /** Set false to hide the per-file remove affordance. Default true. */\n clearable?: boolean;\n \"aria-label\"?: string;\n}\n\nfunction matchesAccept(file: File, accept: string | undefined): boolean {\n if (accept === undefined || accept.trim() === \"\") return true;\n const tokens = accept\n .split(\",\")\n .map((token) => token.trim().toLowerCase())\n .filter((token) => token !== \"\");\n if (tokens.length === 0) return true;\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return tokens.some((token) => {\n if (token.startsWith(\".\")) return name.endsWith(token);\n if (token.endsWith(\"/*\")) return type.startsWith(token.slice(0, -1));\n return type === token;\n });\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction fileBasename(url: string): string {\n const withoutQuery = url.split(/[?#]/, 1)[0] ?? url;\n const segments = withoutQuery.split(\"/\").filter((segment) => segment !== \"\");\n return segments[segments.length - 1] ?? url;\n}\n\nfunction UploadIcon(props: React.SVGAttributes<SVGSVGElement>): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <path d=\"M21 15v3a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3v-3\" />\n <polyline points=\"7 8 12 3 17 8\" />\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" />\n </svg>\n );\n}\n\nfunction XIcon(props: React.SVGAttributes<SVGSVGElement>): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Drag-and-drop or click-to-browse file picker that shows the current file and the pending ones.\n *\n * Contract \"FileUpload\".\n *\n * Shows an existing uploaded value (URL string) as a link, pending `File`\n * values with name and size, and emits `File` objects — the hooks layer turns\n * them into multipart bodies per amendment D2.\n */\nexport function FileUpload(props: FileUploadProps): React.ReactElement {\n const {\n value = null,\n onChange,\n accept,\n multiple = false,\n disabled = false,\n maxSize,\n onReject,\n id,\n name,\n className,\n children,\n clearable = true,\n } = props;\n\n const inputRef = React.useRef<HTMLInputElement>(null);\n const [dragging, setDragging] = React.useState(false);\n\n const entries: ReadonlyArray<File | string> =\n value == null ? [] : Array.isArray(value) ? value : [value as File | string];\n\n const acceptFiles = (list: ArrayLike<File>): void => {\n if (disabled) return;\n const accepted: File[] = [];\n for (const file of Array.from(list)) {\n if (!matchesAccept(file, accept)) {\n onReject?.(file, \"accept\");\n continue;\n }\n if (maxSize !== undefined && file.size > maxSize) {\n onReject?.(file, \"size\");\n continue;\n }\n accepted.push(file);\n }\n if (accepted.length === 0) return;\n onChange?.(multiple ? accepted : accepted[0]);\n };\n\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>): void => {\n if (event.target.files !== null) acceptFiles(event.target.files);\n // Reset so selecting the same file again re-fires the change event.\n event.target.value = \"\";\n };\n\n const handleDrop = (event: React.DragEvent<HTMLButtonElement>): void => {\n event.preventDefault();\n setDragging(false);\n if (disabled) return;\n acceptFiles(event.dataTransfer.files);\n };\n\n const handleDragOver = (event: React.DragEvent<HTMLButtonElement>): void => {\n event.preventDefault();\n if (!disabled) setDragging(true);\n };\n\n const removeEntry = (index: number): void => {\n if (onChange === undefined) return;\n const remaining = entries.filter((_, i) => i !== index);\n if (remaining.length === 0) {\n onChange(null);\n return;\n }\n // Existing URL strings cannot be re-emitted (onChange carries File values\n // only); the remaining pending files are kept.\n const files = remaining.filter((entry): entry is File => typeof entry !== \"string\");\n if (multiple) {\n onChange(files);\n } else {\n onChange(files[0] ?? null);\n }\n };\n\n return (\n <div className={cn(\"space-y-2\", className)}>\n <button\n type=\"button\"\n id={id}\n disabled={disabled}\n aria-label={props[\"aria-label\"]}\n onClick={() => inputRef.current?.click()}\n onDragOver={handleDragOver}\n onDragEnter={handleDragOver}\n onDragLeave={() => setDragging(false)}\n onDrop={handleDrop}\n data-dragging={dragging ? \"true\" : undefined}\n className=\"flex w-full flex-col items-center justify-center gap-1 rounded-md border border-dashed border-input bg-background px-4 py-6 text-sm text-muted-foreground transition-colors hover:border-ring hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[dragging=true]:border-ring data-[dragging=true]:bg-accent data-[dragging=true]:text-accent-foreground\"\n >\n {children ?? (\n <>\n <UploadIcon className=\"h-5 w-5\" />\n <span>\n {multiple\n ? \"Drag and drop files here, or click to browse\"\n : \"Drag and drop a file here, or click to browse\"}\n </span>\n </>\n )}\n </button>\n <input\n ref={inputRef}\n type=\"file\"\n name={name}\n accept={accept}\n multiple={multiple}\n disabled={disabled}\n onChange={handleInputChange}\n tabIndex={-1}\n aria-hidden=\"true\"\n className=\"sr-only\"\n />\n {entries.length > 0 ? (\n <ul className=\"space-y-1\">\n {entries.map((entry, index) => {\n const label = typeof entry === \"string\" ? fileBasename(entry) : entry.name;\n return (\n <li\n key={typeof entry === \"string\" ? `url-${entry}` : `file-${entry.name}-${index}`}\n className=\"flex items-center justify-between gap-2 rounded-md border border-border bg-muted/50 px-3 py-1.5 text-sm\"\n >\n {typeof entry === \"string\" ? (\n <a\n href={entry}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"truncate font-medium text-primary underline underline-offset-4\"\n >\n {label}\n </a>\n ) : (\n <span className=\"truncate\">\n {entry.name}\n <span className=\"ml-2 text-xs text-muted-foreground\">\n {formatFileSize(entry.size)}\n </span>\n </span>\n )}\n {clearable && !disabled ? (\n <button\n type=\"button\"\n aria-label={`Remove ${label}`}\n onClick={() => removeEntry(index)}\n className=\"rounded-sm p-1 text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <XIcon className=\"h-4 w-4\" />\n </button>\n ) : null}\n </li>\n );\n })}\n </ul>\n ) : null}\n </div>\n );\n}\n","/**\n * Pure helpers behind <ResourceForm>: initial-value construction, the D3\n * submit pipeline (dirty-field PATCH granularity, null-clearing, input\n * coercions) and small formatting utilities shared with <ResourceDetail>.\n */\nimport type { FieldDef } from \"../../../schema/types\";\n\nexport type FormValues = Record<string, unknown>;\n\n/** \"published_on\" / \"draft-mode\" → \"Published on\" / \"Draft mode\". */\nexport function humanizeValue(value: string): string {\n const spaced = value.replace(/[_-]+/g, \" \").trim();\n if (spaced === \"\") return value;\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\nfunction pad(n: number): string {\n return String(n).padStart(2, \"0\");\n}\n\n/** ISO-8601 (any offset) → the local \"YYYY-MM-DDTHH:mm\" a datetime-local input needs. */\nexport function toDatetimeLocal(value: string): string {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return value;\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(\n date.getHours(),\n )}:${pad(date.getMinutes())}`;\n}\n\nconst HAS_ZONE = /(?:Z|[+-]\\d{2}:?\\d{2})$/i;\n\n/**\n * datetime-local value (\"YYYY-MM-DDTHH:mm[:ss]\", implicitly local) →\n * ISO-8601 with an explicit UTC offset, per the submit rule in the contract.\n * Values that already carry a zone pass through untouched.\n */\nexport function toIsoWithOffset(value: string): string {\n if (HAS_ZONE.test(value)) return value;\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return value;\n const offsetMinutes = -date.getTimezoneOffset();\n const sign = offsetMinutes >= 0 ? \"+\" : \"-\";\n const abs = Math.abs(offsetMinutes);\n const offset = `${sign}${pad(Math.floor(abs / 60))}:${pad(abs % 60)}`;\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(\n date.getHours(),\n )}:${pad(date.getMinutes())}:${pad(date.getSeconds())}${offset}`;\n}\n\n/**\n * D3 dirtiness at TOP-LEVEL field granularity: a react-hook-form dirtyFields\n * entry counts as dirty when anything in its subtree is truthy, and the whole\n * field value is then sent (DRF PATCH replaces whole field values).\n */\nexport function isDirtyEntry(entry: unknown): boolean {\n if (entry === true) return true;\n if (Array.isArray(entry)) return entry.some(isDirtyEntry);\n if (entry !== null && typeof entry === \"object\") {\n return Object.values(entry).some(isDirtyEntry);\n }\n return false;\n}\n\n/** Unwraps an (accidentally expanded) relation object to its pk. */\nfunction pkOf(value: unknown): unknown {\n if (value !== null && typeof value === \"object\" && !Array.isArray(value) && \"id\" in value) {\n return (value as { id: unknown }).id;\n }\n return value;\n}\n\nexport interface BuildFormValuesInput {\n fields: readonly FieldDef[];\n /** Edit mode: the UNEXPANDED detail record (D10). Wins over defaultValues. */\n item?: Record<string, unknown>;\n defaultValues?: Record<string, unknown>;\n}\n\nfunction initialFieldValue(field: FieldDef, value: unknown): unknown {\n switch (field.kind) {\n case \"string\":\n case \"text\":\n return value == null ? \"\" : String(value);\n case \"number\":\n case \"integer\":\n return value == null ? \"\" : value;\n case \"boolean\":\n return Boolean(value);\n case \"date\":\n return value == null || value === \"\" ? \"\" : String(value).slice(0, 10);\n case \"datetime\":\n return value == null || value === \"\" ? \"\" : toDatetimeLocal(String(value));\n case \"enum\":\n return value == null ? null : value;\n case \"relation\":\n if (field.relation?.many === true) {\n return Array.isArray(value) ? value.map(pkOf) : [];\n }\n return value == null ? null : pkOf(value);\n case \"file\":\n return value == null ? null : value;\n case \"json\":\n return value == null ? \"\" : JSON.stringify(value, null, 2);\n default:\n return value;\n }\n}\n\n/**\n * Builds the react-hook-form value map: every form field gets a defined,\n * controlled-input-safe initial value. Unmatched `defaultValues` keys are kept\n * verbatim (they seed `extraFields`).\n */\nexport function buildFormValues({ fields, item, defaultValues }: BuildFormValuesInput): FormValues {\n const out: FormValues = {};\n for (const field of fields) {\n let source: unknown = defaultValues?.[field.name];\n if (source === undefined) source = field.default; // the model default, on create\n if (item !== undefined && field.name in item) source = item[field.name];\n out[field.name] = initialFieldValue(field, source);\n }\n if (defaultValues !== undefined) {\n for (const [key, value] of Object.entries(defaultValues)) {\n if (!(key in out)) out[key] = value;\n }\n }\n return out;\n}\n\ntype CoercionResult =\n { kind: \"value\"; value: unknown } | { kind: \"omit\" } | { kind: \"error\"; message: string };\n\nfunction val(value: unknown): CoercionResult {\n return { kind: \"value\", value };\n}\n\nconst OMIT: CoercionResult = { kind: \"omit\" };\n\n/** D3: an emptied nullable field is sent as null; a non-nullable one is omitted. */\nfunction emptied(field: FieldDef): CoercionResult {\n return field.nullable ? val(null) : OMIT;\n}\n\nfunction coerceFieldValue(field: FieldDef, value: unknown): CoercionResult {\n switch (field.kind) {\n case \"string\":\n case \"text\": {\n if (value == null) return emptied(field);\n const text = String(value);\n if (text === \"\" && field.nullable) return val(null);\n return val(text);\n }\n case \"number\":\n case \"integer\": {\n if (value == null || value === \"\") return emptied(field);\n const numeric = typeof value === \"number\" ? value : Number(value);\n if (!Number.isFinite(numeric)) return emptied(field);\n return val(numeric);\n }\n case \"boolean\":\n if (value == null) return emptied(field);\n return val(Boolean(value));\n case \"date\":\n if (value == null || value === \"\") return emptied(field);\n return val(String(value).slice(0, 10));\n case \"datetime\":\n if (value == null || value === \"\") return emptied(field);\n return val(toIsoWithOffset(String(value)));\n case \"enum\": {\n if (value == null || value === \"\") return emptied(field);\n const member = (field.enumValues ?? []).find(\n (candidate) => String(candidate) === String(value),\n );\n return val(member ?? value);\n }\n case \"relation\": {\n if (field.relation?.many === true) {\n // M2M fields are cleared with [] — null is not a valid DRF value here.\n if (value == null) return val([]);\n return val(Array.isArray(value) ? value.map(pkOf) : [pkOf(value)]);\n }\n if (value == null || value === \"\") return emptied(field);\n return val(pkOf(value));\n }\n case \"file\": {\n if (value == null) return emptied(field);\n // An unchanged string value is the existing file's URL — never resent (D2).\n if (typeof value === \"string\") return OMIT;\n return val(value);\n }\n case \"json\": {\n if (typeof value !== \"string\") {\n return value == null ? emptied(field) : val(value);\n }\n if (value.trim() === \"\") return emptied(field);\n try {\n return val(JSON.parse(value));\n } catch {\n return { kind: \"error\", message: \"Enter valid JSON.\" };\n }\n }\n default:\n return val(value);\n }\n}\n\nexport interface JsonFieldError {\n name: string;\n message: string;\n}\n\nexport interface PrepareSubmitInput {\n /** The writable schema fields rendered by the form. */\n fields: readonly FieldDef[];\n /** Resolver output from handleSubmit. */\n raw: FormValues;\n mode: \"create\" | \"update\";\n /** react-hook-form dirtyFields; only consulted in \"update\" mode (D3). */\n dirtyFields?: Record<string, unknown>;\n}\n\nexport interface PreparedSubmit {\n values: Record<string, unknown>;\n /** Per-field validation failures (invalid JSON) that must block the submit. */\n jsonErrors: JsonFieldError[];\n}\n\n/**\n * The D3 submit pipeline. Create mode sends every defined value; update mode\n * sends only fields whose dirtyFields subtree is truthy — always the WHOLE\n * field value. Keys without a schema field (extraFields) pass through as-is.\n */\nexport function prepareSubmit({\n fields,\n raw,\n mode,\n dirtyFields,\n}: PrepareSubmitInput): PreparedSubmit {\n const byName = new Map(fields.map((field) => [field.name, field]));\n const values: Record<string, unknown> = {};\n const jsonErrors: JsonFieldError[] = [];\n\n for (const [name, rawValue] of Object.entries(raw)) {\n if (mode === \"update\" && !isDirtyEntry(dirtyFields?.[name])) continue;\n const field = byName.get(name);\n if (field === undefined) {\n if (rawValue !== undefined) values[name] = rawValue;\n continue;\n }\n const result = coerceFieldValue(field, rawValue);\n if (result.kind === \"error\") {\n jsonErrors.push({ name, message: result.message });\n } else if (result.kind === \"value\" && result.value !== undefined) {\n values[name] = result.value;\n }\n }\n\n return { values, jsonErrors };\n}\n","/**\n * Default per-kind inputs for <ResourceForm> (contract: string → Input,\n * text → Textarea, number/integer → Input[type=number], boolean → Switch,\n * date/datetime → native inputs, enum → Select, relation → ResourceSelect\n * (multiple for many), file → FileUpload, json → Textarea with validation).\n */\nimport * as React from \"react\";\nimport { Controller } from \"react-hook-form\";\nimport type { Control, FieldValues } from \"react-hook-form\";\nimport type { FieldDef } from \"../../../schema/types\";\nimport { FileUpload } from \"../../file-upload/FileUpload\";\nimport { Input } from \"../../primitives/input\";\nimport { Select } from \"../../primitives/select\";\nimport { Switch } from \"../../primitives/switch\";\nimport { Textarea } from \"../../primitives/textarea\";\nimport { ResourceSelect } from \"../select/ResourceSelect\";\nimport { humanizeValue } from \"./prepare\";\n\nexport interface DefaultFieldControlProps {\n field: FieldDef;\n control: Control<FieldValues>;\n inputId: string;\n describedBy?: string;\n invalid: boolean;\n disabled?: boolean;\n /** FieldOverride.props pass-through, spread onto the rendered input. */\n inputProps?: Record<string, unknown>;\n}\n\nfunction stringInputType(field: FieldDef): string {\n switch (field.format) {\n case \"email\":\n return \"email\";\n case \"uri\":\n case \"url\":\n return \"url\";\n case \"password\":\n return \"password\";\n default:\n return \"text\";\n }\n}\n\nexport function DefaultFieldControl({\n field,\n control,\n inputId,\n describedBy,\n invalid,\n disabled,\n inputProps,\n}: DefaultFieldControlProps): React.ReactElement {\n const aria = {\n \"aria-invalid\": invalid || undefined,\n \"aria-describedby\": describedBy,\n } as const;\n\n return (\n <Controller\n control={control}\n name={field.name}\n render={({ field: rhf }) => {\n switch (field.kind) {\n case \"text\":\n return (\n <Textarea\n id={inputId}\n rows={4}\n maxLength={field.maxLength}\n disabled={disabled}\n value={rhf.value == null ? \"\" : String(rhf.value)}\n onChange={(event) => rhf.onChange(event.target.value)}\n onBlur={rhf.onBlur}\n {...aria}\n {...inputProps}\n />\n );\n case \"number\":\n case \"integer\":\n return (\n <Input\n id={inputId}\n type=\"number\"\n inputMode={field.kind === \"integer\" ? \"numeric\" : \"decimal\"}\n step={field.kind === \"integer\" ? 1 : \"any\"}\n min={field.min}\n max={field.max}\n disabled={disabled}\n value={rhf.value == null ? \"\" : (rhf.value as number | string)}\n onChange={(event) => rhf.onChange(event.target.value)}\n onBlur={rhf.onBlur}\n {...aria}\n {...inputProps}\n />\n );\n case \"boolean\":\n return (\n <Switch\n id={inputId}\n disabled={disabled}\n checked={Boolean(rhf.value)}\n onCheckedChange={(checked) => rhf.onChange(checked)}\n onBlur={rhf.onBlur}\n {...aria}\n {...inputProps}\n />\n );\n case \"date\":\n return (\n <Input\n id={inputId}\n type=\"date\"\n disabled={disabled}\n value={rhf.value == null ? \"\" : String(rhf.value)}\n onChange={(event) => rhf.onChange(event.target.value)}\n onBlur={rhf.onBlur}\n {...aria}\n {...inputProps}\n />\n );\n case \"datetime\":\n return (\n <Input\n id={inputId}\n type=\"datetime-local\"\n disabled={disabled}\n value={rhf.value == null ? \"\" : String(rhf.value)}\n onChange={(event) => rhf.onChange(event.target.value)}\n onBlur={rhf.onBlur}\n {...aria}\n {...inputProps}\n />\n );\n case \"enum\": {\n const members = field.enumValues ?? [];\n const options = members.map((member) => ({\n value: String(member),\n label: field.enumLabels?.[String(member)] ?? humanizeValue(String(member)),\n }));\n return (\n <Select\n id={inputId}\n disabled={disabled}\n value={rhf.value == null ? null : String(rhf.value)}\n options={options}\n clearable={field.nullable}\n placeholder=\"Select…\"\n onValueChange={(next) => {\n if (next === null) {\n rhf.onChange(null);\n return;\n }\n const member = members.find((candidate) => String(candidate) === next);\n rhf.onChange(member ?? next);\n }}\n {...inputProps}\n />\n );\n }\n case \"relation\": {\n const relation = field.relation;\n if (relation === undefined) {\n // Degraded mode: no x-karni-relation extension, edit the raw pk.\n return (\n <Input\n id={inputId}\n type=\"text\"\n disabled={disabled}\n value={rhf.value == null ? \"\" : String(rhf.value)}\n onChange={(event) => rhf.onChange(event.target.value)}\n onBlur={rhf.onBlur}\n {...aria}\n {...inputProps}\n />\n );\n }\n return (\n <ResourceSelect\n id={inputId}\n resource={relation.resource}\n multiple={relation.many}\n disabled={disabled}\n value={\n (rhf.value ?? null) as string | number | ReadonlyArray<string | number> | null\n }\n onChange={(next) => rhf.onChange(next)}\n {...inputProps}\n />\n );\n }\n case \"file\":\n return (\n <FileUpload\n id={inputId}\n disabled={disabled}\n value={(rhf.value ?? null) as File | string | null}\n onChange={(next) => rhf.onChange(next)}\n {...inputProps}\n />\n );\n case \"json\":\n return (\n <Textarea\n id={inputId}\n rows={5}\n disabled={disabled}\n className=\"font-mono\"\n value={\n typeof rhf.value === \"string\"\n ? rhf.value\n : rhf.value == null\n ? \"\"\n : JSON.stringify(rhf.value, null, 2)\n }\n onChange={(event) => rhf.onChange(event.target.value)}\n onBlur={rhf.onBlur}\n {...aria}\n {...inputProps}\n />\n );\n default:\n return (\n <Input\n id={inputId}\n type={stringInputType(field)}\n maxLength={field.maxLength}\n disabled={disabled}\n value={rhf.value == null ? \"\" : String(rhf.value)}\n onChange={(event) => rhf.onChange(event.target.value)}\n onBlur={rhf.onBlur}\n {...aria}\n {...inputProps}\n />\n );\n }\n }}\n />\n );\n}\n","import { zodResolver } from \"@hookform/resolvers/zod\";\nimport * as React from \"react\";\nimport { FormProvider, useForm } from \"react-hook-form\";\nimport type { Control, FieldValues, Resolver, UseFormReturn } from \"react-hook-form\";\nimport { useResourceItem } from \"../../../hooks/useResourceItem\";\nimport { useResourceMutations } from \"../../../hooks/useResourceMutations\";\nimport { cn } from \"../../../lib/cn\";\nimport type { FieldDef, ResourceSchema } from \"../../../schema/types\";\nimport { useSchema } from \"../../../schema/useSchema\";\nimport { zodFor } from \"../../../schema/zod\";\nimport { Button } from \"../../primitives/button\";\nimport { Label } from \"../../primitives/label\";\nimport { Skeleton } from \"../../primitives/skeleton\";\nimport { DefaultFieldControl } from \"./field-inputs\";\nimport { buildFormValues, prepareSubmit } from \"./prepare\";\nimport { registerComponentRole } from \"../../../lib/roles\";\n\nregisterComponentRole(\"resource-form\", \"ResourceForm\");\n\n/** Props passed to a custom field component (the `fields` escape hatch). */\nexport interface KarniFieldProps {\n field: FieldDef;\n name: string;\n label: string;\n required: boolean;\n control: Control<FieldValues>;\n error?: string;\n disabled?: boolean;\n /** Pass-through from FieldOverride.props. */\n props?: Record<string, unknown>;\n}\n\nexport interface FieldOverride {\n component?: React.ComponentType<KarniFieldProps>;\n label?: string;\n hidden?: boolean;\n props?: Record<string, unknown>;\n}\n\nexport interface ResourceFormProps {\n resource: string;\n /** Present → edit mode: loads the UNEXPANDED item, PATCHes dirty fields only (D10). */\n id?: string | number;\n defaultValues?: Record<string, unknown>;\n onSuccess?: (result: Record<string, unknown>) => void;\n onError?: (error: unknown) => void;\n fields?: Record<string, FieldOverride>;\n /** Custom RHF-registered nodes appended after the derived fields. */\n extraFields?: React.ReactNode;\n transformSubmit?: (values: Record<string, unknown>) => Record<string, unknown>;\n /** Replaces the submit row. */\n actions?: React.ReactNode;\n className?: string;\n}\n\n/** Field kinds the generic form knows how to render (others need an override). */\nconst EDITABLE_KINDS: ReadonlySet<string> = new Set([\n \"string\",\n \"text\",\n \"number\",\n \"integer\",\n \"boolean\",\n \"date\",\n \"datetime\",\n \"enum\",\n \"relation\",\n \"file\",\n \"json\",\n]);\n\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n return String(error);\n}\n\nfunction FormSkeleton({ className }: { className?: string }): React.ReactElement {\n return (\n <div role=\"status\" aria-label=\"Loading form\" className={cn(\"space-y-5\", className)}>\n {[0, 1, 2].map((row) => (\n <div key={row} className=\"space-y-2\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n ))}\n <Skeleton className=\"h-10 w-28\" />\n </div>\n );\n}\n\nfunction FormErrorPanel({\n error,\n className,\n}: {\n error: unknown;\n className?: string;\n}): React.ReactElement {\n return (\n <div\n role=\"alert\"\n className={cn(\n \"rounded-md border border-destructive/50 bg-destructive/10 p-4 text-sm text-destructive\",\n className,\n )}\n >\n {errorMessage(error)}\n </div>\n );\n}\n\n/**\n * Maps a DRF 400 body ({field: [messages], non_field_errors: [...], detail})\n * onto react-hook-form errors. Unknown keys and non-field messages land on\n * `root.server`.\n */\nfunction applyServerErrors(\n error: unknown,\n knownNames: ReadonlySet<string>,\n methods: UseFormReturn<FieldValues>,\n): void {\n if (typeof error !== \"object\" || error === null) return;\n const maybe = error as { status?: unknown; data?: unknown };\n if (maybe.status !== 400) return;\n const data = maybe.data;\n if (Array.isArray(data)) {\n methods.setError(\"root.server\", { type: \"server\", message: data.map(String).join(\" \") });\n return;\n }\n if (typeof data !== \"object\" || data === null) return;\n const rootMessages: string[] = [];\n for (const [key, messages] of Object.entries(data as Record<string, unknown>)) {\n const message = Array.isArray(messages) ? messages.map(String).join(\" \") : String(messages);\n if (key === \"non_field_errors\" || key === \"detail\") {\n rootMessages.push(message);\n } else if (knownNames.has(key)) {\n methods.setError(key, { type: \"server\", message });\n } else {\n rootMessages.push(`${key}: ${message}`);\n }\n }\n if (rootMessages.length > 0) {\n methods.setError(\"root.server\", { type: \"server\", message: rootMessages.join(\" \") });\n }\n}\n\ninterface FormFieldRowProps {\n field: FieldDef;\n override?: FieldOverride;\n control: Control<FieldValues>;\n error?: string;\n disabled?: boolean;\n}\n\nfunction FormFieldRow({\n field,\n override,\n control,\n error,\n disabled,\n}: FormFieldRowProps): React.ReactElement {\n const inputId = React.useId();\n const label = override?.label ?? field.label;\n\n if (override?.component !== undefined) {\n const Component = override.component;\n return (\n <Component\n field={field}\n name={field.name}\n label={label}\n required={field.required}\n control={control}\n error={error}\n disabled={disabled}\n props={override.props}\n />\n );\n }\n\n const errorId = `${inputId}-error`;\n const descriptionId = `${inputId}-description`;\n const describedBy =\n [field.description !== undefined ? descriptionId : null, error !== undefined ? errorId : null]\n .filter((part): part is string => part !== null)\n .join(\" \") || undefined;\n\n return (\n <div className=\"space-y-2\">\n <Label htmlFor={inputId}>\n {label}\n {field.required ? (\n <span aria-hidden=\"true\" className=\"text-destructive\">\n {\" *\"}\n </span>\n ) : null}\n </Label>\n <DefaultFieldControl\n field={field}\n control={control}\n inputId={inputId}\n describedBy={describedBy}\n invalid={error !== undefined}\n disabled={disabled}\n inputProps={override?.props}\n />\n {field.description !== undefined ? (\n <p id={descriptionId} className=\"text-sm text-muted-foreground\">\n {field.description}\n </p>\n ) : null}\n {error !== undefined ? (\n <p id={errorId} className=\"text-sm font-medium text-destructive\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n\ninterface ResourceFormInnerProps extends ResourceFormProps {\n schema: ResourceSchema;\n item?: Record<string, unknown>;\n}\n\nfunction ResourceFormInner(props: ResourceFormInnerProps): React.ReactElement {\n const {\n resource,\n id,\n defaultValues,\n onSuccess,\n onError,\n fields: fieldOverrides,\n extraFields,\n transformSubmit,\n actions,\n className,\n schema,\n item,\n } = props;\n const mode = id === undefined ? \"create\" : \"update\";\n const mutations = useResourceMutations(resource);\n\n const formFields = React.useMemo(\n () =>\n schema.fields.filter(\n (field) =>\n !field.readOnly &&\n (EDITABLE_KINDS.has(field.kind) || fieldOverrides?.[field.name]?.component !== undefined),\n ),\n [schema, fieldOverrides],\n );\n\n const initialValues = React.useMemo(\n () => buildFormValues({ fields: formFields, item, defaultValues }),\n [formFields, item, defaultValues],\n );\n\n const resolver = React.useMemo<Resolver<FieldValues>>(() => {\n const base = zodResolver(zodFor(schema, mode)) as unknown as Resolver<FieldValues>;\n // A cleared optional, non-nullable field (a select's \"no selection\") is\n // omitted from the request (D3), so it must not fail validation as null.\n // Many relations are cleared with [] and stay.\n const omittable = new Set(\n schema.fields\n .filter(\n (field) =>\n !field.required &&\n !field.nullable &&\n !(field.kind === \"relation\" && field.relation?.many === true),\n )\n .map((field) => field.name),\n );\n return (values, context, options) => {\n const cleaned: FieldValues = Object.fromEntries(\n Object.entries(values).filter(([name, value]) => !(value === null && omittable.has(name))),\n );\n return base(cleaned, context, options);\n };\n }, [schema, mode]);\n\n const methods = useForm<FieldValues>({\n resolver,\n values: initialValues,\n resetOptions: { keepDirtyValues: true },\n });\n\n const { formState } = methods;\n const submitting =\n formState.isSubmitting || mutations.create.isPending || mutations.update.isPending;\n\n const onSubmit = methods.handleSubmit(async (raw) => {\n methods.clearErrors(\"root.server\");\n const { values, jsonErrors } = prepareSubmit({\n fields: formFields,\n raw,\n mode,\n dirtyFields: methods.formState.dirtyFields,\n });\n if (jsonErrors.length > 0) {\n for (const jsonError of jsonErrors) {\n methods.setError(jsonError.name, { type: \"validate\", message: jsonError.message });\n }\n return;\n }\n const payload = transformSubmit !== undefined ? transformSubmit(values) : values;\n try {\n const result =\n id === undefined\n ? await mutations.create.mutateAsync(payload)\n : await mutations.update.mutateAsync({ id, values: payload });\n if (id === undefined) {\n methods.reset();\n } else {\n // Keep the (possibly server-normalized) values but clear dirtiness.\n methods.reset(undefined, { keepValues: true });\n }\n onSuccess?.(result);\n } catch (error) {\n const knownNames = new Set([...formFields.map((field) => field.name), ...Object.keys(raw)]);\n applyServerErrors(error, knownNames, methods);\n onError?.(error);\n }\n });\n\n const rootError = formState.errors.root?.[\"server\"]?.message ?? formState.errors.root?.message;\n\n const fieldError = (name: string): string | undefined => {\n const entry = formState.errors[name];\n return typeof entry?.message === \"string\" ? entry.message : undefined;\n };\n\n return (\n <FormProvider {...methods}>\n <form\n onSubmit={(event) => {\n void onSubmit(event);\n }}\n noValidate\n aria-busy={submitting || undefined}\n className={cn(\"space-y-5\", className)}\n >\n {typeof rootError === \"string\" ? (\n <div\n role=\"alert\"\n className=\"rounded-md border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive\"\n >\n {rootError}\n </div>\n ) : null}\n {formFields.map((field) => {\n const override = fieldOverrides?.[field.name];\n if (override?.hidden === true) return null;\n return (\n <FormFieldRow\n key={field.name}\n field={field}\n override={override}\n control={methods.control}\n error={fieldError(field.name)}\n disabled={submitting}\n />\n );\n })}\n {extraFields}\n {actions !== undefined ? (\n actions\n ) : (\n <div className=\"flex items-center justify-end gap-3 pt-2\">\n <Button type=\"submit\" disabled={submitting}>\n {id === undefined ? \"Create\" : \"Save changes\"}\n </Button>\n </div>\n )}\n </form>\n </FormProvider>\n );\n}\n\n/**\n * Schema-driven create and edit form for one resource: inputs, validation and\n * server errors derived from the OpenAPI schema.\n *\n * Contract \"ResourceForm\" + D2/D3/D10.\n *\n * Create mode POSTs every prepared value; edit mode loads the UNEXPANDED\n * detail record and PATCHes only dirty fields at top-level granularity, with\n * emptied nullable fields sent as null (D3). DRF 400 bodies map onto field\n * errors via setError (non_field_errors → root). Escape hatches: per-field\n * overrides (`fields`), `extraFields`, `transformSubmit` and the `actions`\n * slot.\n */\nexport function ResourceForm(props: ResourceFormProps): React.ReactElement {\n const { resource, id } = props;\n const schemaResult = useSchema(resource);\n const isEdit = id !== undefined;\n const itemQuery = useResourceItem(resource, id ?? \"\", undefined, { enabled: isEdit });\n\n if (schemaResult.error != null) {\n return <FormErrorPanel error={schemaResult.error} className={props.className} />;\n }\n if (isEdit && itemQuery.error != null) {\n return <FormErrorPanel error={itemQuery.error} className={props.className} />;\n }\n if (schemaResult.data === undefined || (isEdit && itemQuery.data === undefined)) {\n return <FormSkeleton className={props.className} />;\n }\n return (\n <ResourceFormInner\n {...props}\n schema={schemaResult.data}\n item={isEdit ? itemQuery.data : undefined}\n />\n );\n}\n","import * as React from \"react\";\nimport { useResourceItem } from \"../../../hooks/useResourceItem\";\nimport type { ResourceItemParams } from \"../../../hooks/types\";\nimport { cn } from \"../../../lib/cn\";\nimport type { FieldDef } from \"../../../schema/types\";\nimport { useSchema } from \"../../../schema/useSchema\";\nimport { Button } from \"../../primitives/button\";\nimport { Skeleton } from \"../../primitives/skeleton\";\nimport { partitionAuditFields } from \"../audit-fields\";\nimport { displayLabel } from \"../displayLabel\";\nimport { humanizeValue } from \"../form/prepare\";\nimport { registerComponentRole } from \"../../../lib/roles\";\n\nregisterComponentRole(\"detail-view\", \"ResourceDetail\");\n\nexport interface ResourceDetailFieldOverride {\n label?: string;\n hidden?: boolean;\n render?: (value: unknown, item: Record<string, unknown>) => React.ReactNode;\n}\n\nexport interface ResourceDetailProps {\n resource: string;\n id: string | number;\n fields?: Record<string, ResourceDetailFieldOverride>;\n /** Appended below the field list (e.g. a child <ResourceTable>). */\n sections?: ReadonlyArray<React.ReactNode>;\n expand?: readonly string[];\n title?: React.ReactNode;\n actions?: React.ReactNode;\n className?: string;\n}\n\nfunction fileBasename(url: string): string {\n const withoutQuery = url.split(/[?#]/, 1)[0] ?? url;\n const segments = withoutQuery.split(\"/\").filter((segment) => segment !== \"\");\n return segments[segments.length - 1] ?? url;\n}\n\nfunction formatDate(value: string): string {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(value);\n if (match !== null) {\n const date = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]));\n return date.toLocaleDateString();\n }\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? value : date.toLocaleDateString();\n}\n\nfunction formatDateTime(value: string): string {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? value : date.toLocaleString();\n}\n\nfunction RelationEntry({ value }: { value: unknown }): React.ReactElement {\n if (value !== null && typeof value === \"object\") {\n return <>{displayLabel(value as Record<string, unknown>)}</>;\n }\n return <code className=\"rounded bg-muted px-1 py-0.5 font-mono text-xs\">{String(value)}</code>;\n}\n\nfunction RelationValue({ value }: { value: unknown }): React.ReactElement {\n if (Array.isArray(value)) {\n if (value.length === 0) return <EmptyValue />;\n return (\n <span className=\"flex flex-wrap gap-1.5\">\n {value.map((entry, index) => (\n <span\n key={index}\n className=\"inline-flex items-center rounded-sm bg-secondary px-1.5 py-0.5 text-xs text-secondary-foreground\"\n >\n <RelationEntry value={entry} />\n </span>\n ))}\n </span>\n );\n }\n return <RelationEntry value={value} />;\n}\n\nfunction EmptyValue(): React.ReactElement {\n return <span className=\"text-muted-foreground\">—</span>;\n}\n\n/** Default value renderer per field kind; overridable per field via `fields`. */\nfunction DefaultValue({ field, value }: { field: FieldDef; value: unknown }): React.ReactElement {\n if (value === undefined || value === null || value === \"\") return <EmptyValue />;\n switch (field.kind) {\n case \"boolean\":\n return <>{value ? \"Yes\" : \"No\"}</>;\n case \"date\":\n return <>{formatDate(String(value))}</>;\n case \"datetime\":\n return <>{formatDateTime(String(value))}</>;\n case \"enum\":\n return <>{field.enumLabels?.[String(value)] ?? humanizeValue(String(value))}</>;\n case \"relation\":\n return <RelationValue value={value} />;\n case \"file\":\n return (\n <a\n href={String(value)}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"font-medium text-primary underline underline-offset-4\"\n >\n {fileBasename(String(value))}\n </a>\n );\n case \"json\":\n return (\n <pre className=\"overflow-x-auto rounded-md bg-muted p-3 text-xs\">\n {JSON.stringify(value, null, 2)}\n </pre>\n );\n case \"number\":\n case \"integer\":\n return <>{typeof value === \"number\" ? value.toLocaleString() : String(value)}</>;\n case \"array\":\n return <>{Array.isArray(value) ? value.map(String).join(\", \") : String(value)}</>;\n default:\n return <>{String(value)}</>;\n }\n}\n\nfunction DetailSkeleton({ className }: { className?: string }): React.ReactElement {\n return (\n <div role=\"status\" aria-label=\"Loading details\" className={cn(\"space-y-4\", className)}>\n {[0, 1, 2, 3].map((row) => (\n <div key={row} className=\"grid grid-cols-1 gap-2 sm:grid-cols-3 sm:gap-4\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-4 w-48 sm:col-span-2\" />\n </div>\n ))}\n </div>\n );\n}\n\nfunction DetailError({\n error,\n onRetry,\n className,\n}: {\n error: unknown;\n onRetry: () => void;\n className?: string;\n}): React.ReactElement {\n return (\n <div\n role=\"alert\"\n className={cn(\n \"space-y-3 rounded-md border border-destructive/50 bg-destructive/10 p-4 text-sm text-destructive\",\n className,\n )}\n >\n <p>{error instanceof Error ? error.message : String(error)}</p>\n <Button variant=\"outline\" size=\"sm\" onClick={onRetry}>\n Retry\n </Button>\n </div>\n );\n}\n\nfunction DetailRow(props: {\n field: FieldDef;\n item: Record<string, unknown>;\n override: ResourceDetailFieldOverride | undefined;\n muted: boolean;\n}): React.ReactElement {\n const { field, item, override, muted } = props;\n const value = item[field.name];\n return (\n <div\n className={cn(\n \"grid grid-cols-1 gap-1 sm:grid-cols-3 sm:gap-4\",\n muted ? \"py-2 text-xs\" : \"py-3 text-sm\",\n )}\n >\n <dt className=\"font-medium text-muted-foreground\">{override?.label ?? field.label}</dt>\n <dd className={cn(\"sm:col-span-2\", muted ? \"text-muted-foreground\" : \"text-foreground\")}>\n {override?.render !== undefined ? (\n override.render(value, item)\n ) : (\n <DefaultValue field={field} value={value} />\n )}\n </dd>\n </div>\n );\n}\n\n/**\n * Schema-driven read view of one row: every readable field, labelled and formatted.\n *\n * Contract \"ResourceDetail\": a definition list of\n * every non-writeOnly field — domain fields first (schema order), then the\n * audit fields (AUDIT_FIELDS: id, created_at, updated_at, created_by,\n * updated_by) in a visually muted \"Record\" group. Relations render through\n * displayLabel when the object is expanded (the field is in `expand`), else\n * as the raw id in <code>. Escape hatches: per-field `fields` overrides\n * (label/hidden/render — audit fields included), appended `sections`, and the\n * title/actions header slots.\n */\nexport function ResourceDetail(props: ResourceDetailProps): React.ReactElement {\n const { resource, id, fields, sections, expand, title, actions, className } = props;\n const recordHeadingId = React.useId();\n const schemaResult = useSchema(resource);\n const params: ResourceItemParams | undefined = React.useMemo(\n () => (expand !== undefined && expand.length > 0 ? { expand } : undefined),\n [expand],\n );\n const itemQuery = useResourceItem(resource, id, params);\n\n const error = schemaResult.error ?? itemQuery.error;\n if (error != null) {\n return (\n <DetailError\n error={error}\n onRetry={() => {\n void itemQuery.refetch();\n }}\n className={className}\n />\n );\n }\n if (schemaResult.data === undefined || itemQuery.data === undefined) {\n return <DetailSkeleton className={className} />;\n }\n\n const item = itemQuery.data;\n const visibleFields = schemaResult.data.fields.filter(\n (field) =>\n !field.writeOnly && field.kind !== \"unknown\" && fields?.[field.name]?.hidden !== true,\n );\n const { domain, audit } = partitionAuditFields(visibleFields);\n\n return (\n <div className={cn(\"space-y-6\", className)}>\n {title !== undefined || actions !== undefined ? (\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n {title !== undefined ? (\n <h2 className=\"text-lg font-semibold tracking-tight\">{title}</h2>\n ) : (\n <div />\n )}\n {actions !== undefined ? <div className=\"flex items-center gap-2\">{actions}</div> : null}\n </div>\n ) : null}\n <dl className=\"divide-y divide-border\">\n {domain.map((field) => (\n <DetailRow\n key={field.name}\n field={field}\n item={item}\n override={fields?.[field.name]}\n muted={false}\n />\n ))}\n </dl>\n {audit.length > 0 ? (\n <section\n aria-labelledby={recordHeadingId}\n className=\"rounded-md border border-border bg-muted/40 px-4 py-2\"\n >\n <h3\n id={recordHeadingId}\n className=\"py-1 text-xs font-medium uppercase tracking-wide text-muted-foreground\"\n >\n Record\n </h3>\n <dl className=\"divide-y divide-border\">\n {audit.map((field) => (\n <DetailRow\n key={field.name}\n field={field}\n item={item}\n override={fields?.[field.name]}\n muted\n />\n ))}\n </dl>\n </section>\n ) : null}\n {sections !== undefined && sections.length > 0 ? (\n <div className=\"space-y-6\">\n {sections.map((section, index) => (\n <div key={index}>{section}</div>\n ))}\n </div>\n ) : null}\n </div>\n );\n}\n","/**\n * useChangeHistory — one row's field-level change history (karni.audit, ADR 0002 P4).\n *\n * `useChangeHistory(\"prices\", id)` fetches `GET /<resource>/<id>/history/`,\n * the paginated list a `BaseViewSet` serves for models that opt in with\n * `class Karni: audit = True`. The backend answers 404 for the rest, and\n * hides from each entry's `diff` the fields the requesting role may not see,\n * so the hook renders whatever it is given without filtering.\n */\nimport { useQuery, type UseQueryOptions, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useKarniClient } from \"../schema/provider\";\nimport { karniKeys } from \"./keys\";\nimport { detailPath } from \"./params\";\n\nexport type ChangeAction = \"create\" | \"update\" | \"delete\" | \"restore\";\n\nexport interface ChangeLogEntry {\n id: number;\n timestamp: string;\n actor: { id: string | number; email?: string } | null;\n action: ChangeAction;\n /** `{ field: [old, new] }`; a redacted field carries `\"[redacted]\"` on both sides. */\n diff: Record<string, [unknown, unknown]>;\n fields_changed: string[];\n}\n\nexport interface ChangeHistoryPage {\n count: number;\n next: string | null;\n previous: string | null;\n results: ChangeLogEntry[];\n}\n\nexport interface ChangeHistoryParams {\n /** Entries per page (the backend caps it). Default: the API's page size. */\n pageSize?: number;\n page?: number;\n}\n\n/** The query key of one row's change history. */\nexport function changeHistoryKey(\n resource: string,\n id: string | number,\n params?: ChangeHistoryParams,\n): readonly unknown[] {\n return [...karniKeys.resource(resource), \"history\", String(id), params ?? {}] as const;\n}\n\n/** Fetches one row's field-level change history (`GET /<resource>/<id>/history/`) for models with `audit = True`. */\nexport function useChangeHistory(\n resource: string,\n id: string | number,\n params?: ChangeHistoryParams,\n options?: Omit<UseQueryOptions<ChangeHistoryPage>, \"queryKey\" | \"queryFn\">,\n): UseQueryResult<ChangeHistoryPage> {\n const client = useKarniClient();\n return useQuery<ChangeHistoryPage>({\n ...options,\n queryKey: changeHistoryKey(resource, id, params),\n queryFn: ({ signal }) =>\n client.request<ChangeHistoryPage>(`${detailPath(resource, id)}history/`, {\n query: { page_size: params?.pageSize, page: params?.page },\n signal,\n }),\n });\n}\n","import * as React from \"react\";\nimport { useChangeHistory, type ChangeLogEntry } from \"../../../hooks/useChangeHistory\";\nimport { cn } from \"../../../lib/cn\";\nimport { registerComponentRole } from \"../../../lib/roles\";\nimport { Skeleton } from \"../../primitives/skeleton\";\n\nregisterComponentRole(\"change-history\", \"ChangeHistory\");\n\nexport interface ChangeHistoryProps {\n resource: string;\n id: string | number;\n /** Entries to show (the backend paginates; default: the API's page size). */\n pageSize?: number;\n title?: React.ReactNode;\n /** Shown when the row has no recorded changes. */\n empty?: React.ReactNode;\n className?: string;\n}\n\nconst ACTION_LABEL: Record<ChangeLogEntry[\"action\"], string> = {\n create: \"Created\",\n update: \"Updated\",\n delete: \"Deleted\",\n restore: \"Restored\",\n};\n\nfunction formatWhen(value: string): string {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? value : date.toLocaleString();\n}\n\nfunction Value({ value }: { value: unknown }): React.ReactElement {\n if (value === null || value === undefined || value === \"\") {\n return <span className=\"text-muted-foreground\">—</span>;\n }\n if (value === \"[redacted]\") {\n return <span className=\"italic text-muted-foreground\">redacted</span>;\n }\n const text = typeof value === \"object\" ? JSON.stringify(value) : String(value);\n return <span className=\"break-words\">{text}</span>;\n}\n\nfunction Entry({ entry }: { entry: ChangeLogEntry }): React.ReactElement {\n const fields = Object.entries(entry.diff);\n return (\n <li className=\"rounded-md border bg-card p-3 text-sm\" data-action={entry.action}>\n <div className=\"flex flex-wrap items-baseline gap-x-3 gap-y-1\">\n <span className=\"font-medium\">{ACTION_LABEL[entry.action] ?? entry.action}</span>\n <time dateTime={entry.timestamp} className=\"text-muted-foreground\">\n {formatWhen(entry.timestamp)}\n </time>\n <span className=\"text-muted-foreground\">{entry.actor?.email ?? \"—\"}</span>\n </div>\n {fields.length > 0 ? (\n <dl className=\"mt-2 grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1\">\n {fields.map(([name, [before, after]]) => (\n <React.Fragment key={name}>\n <dt className=\"font-mono text-xs text-muted-foreground\">{name}</dt>\n <dd className=\"flex flex-wrap items-center gap-2\">\n <Value value={before} />\n <span aria-hidden=\"true\" className=\"text-muted-foreground\">\n →\n </span>\n <Value value={after} />\n </dd>\n </React.Fragment>\n ))}\n </dl>\n ) : (\n <p className=\"mt-2 text-muted-foreground\">No visible field changed.</p>\n )}\n </li>\n );\n}\n\n/**\n * The field-level change history of one row: when, by whom, what changed\n * from what to what. Reads `GET /<resource>/<id>/history/` (models that opt\n * in with `class Karni: audit = True`); fields the role may not see are\n * already absent from each diff, redacted ones say so.\n */\nexport function ChangeHistory({\n resource,\n id,\n pageSize,\n title = \"History\",\n empty = \"No changes recorded.\",\n className,\n}: ChangeHistoryProps): React.ReactElement {\n const query = useChangeHistory(resource, id, pageSize !== undefined ? { pageSize } : undefined);\n return (\n <section className={cn(\"space-y-3\", className)} aria-label=\"Change history\">\n {title !== null ? <h3 className=\"text-base font-semibold\">{title}</h3> : null}\n {query.isPending ? (\n <div className=\"space-y-2\" data-testid=\"change-history-loading\">\n <Skeleton className=\"h-16 w-full\" />\n <Skeleton className=\"h-16 w-full\" />\n </div>\n ) : query.error ? (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {query.error instanceof Error ? query.error.message : \"History could not be loaded.\"}\n </p>\n ) : query.data.results.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">{empty}</p>\n ) : (\n <ol className=\"space-y-2\">\n {query.data.results.map((entry) => (\n <Entry key={entry.id} entry={entry} />\n ))}\n </ol>\n )}\n </section>\n );\n}\n","import * as React from \"react\";\nimport {\n downloadImportTemplate,\n isImportInFlight,\n useImportActions,\n useImportDescribe,\n useImportJob,\n type ImportColumn,\n type ImportJob,\n} from \"../../../hooks/useResourceImport\";\nimport { cn } from \"../../../lib/cn\";\nimport { registerComponentRole } from \"../../../lib/roles\";\nimport { useKarniClient } from \"../../../schema/provider\";\nimport { Button } from \"../../primitives/button\";\nimport { Select } from \"../../primitives/select\";\nimport { Skeleton } from \"../../primitives/skeleton\";\n\nregisterComponentRole(\"resource-import\", \"ResourceImport\");\n\nexport interface ResourceImportProps {\n resource: string;\n title?: React.ReactNode;\n /** Called when a commit finishes (the job is `done`). */\n onDone?: (job: ImportJob) => void;\n className?: string;\n}\n\nfunction errorText(error: unknown): string {\n if (error instanceof Error) {\n const data = (error as { data?: unknown }).data;\n if (typeof data === \"object\" && data !== null && \"detail\" in data) {\n const detail = (data as { detail?: unknown }).detail;\n if (typeof detail === \"string\") return detail;\n }\n return error.message;\n }\n return \"Something went wrong.\";\n}\n\nfunction Stats({ job }: { job: ImportJob }): React.ReactElement | null {\n if (job.result === null) return null;\n const { created, updated, skipped, unchanged, errors } = job.result;\n return (\n <dl className=\"flex flex-wrap gap-6\" data-testid=\"import-stats\">\n <div>\n <dt className=\"text-xs uppercase text-muted-foreground\">Created</dt>\n <dd className=\"text-2xl font-semibold\">{created}</dd>\n </div>\n <div>\n <dt className=\"text-xs uppercase text-muted-foreground\">Updated</dt>\n <dd className=\"text-2xl font-semibold\">{updated}</dd>\n </div>\n <div>\n <dt className=\"text-xs uppercase text-muted-foreground\">Skipped</dt>\n <dd className=\"text-2xl font-semibold\">\n {skipped}{\" \"}\n <span className=\"text-sm font-normal text-muted-foreground\">\n ({unchanged} unchanged, {errors} with errors)\n </span>\n </dd>\n </div>\n </dl>\n );\n}\n\nfunction Problems({ job }: { job: ImportJob }): React.ReactElement | null {\n if (job.problems.length === 0) return null;\n return (\n <div className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full text-sm\" aria-label=\"Rows with errors\">\n <thead className=\"bg-muted text-left text-xs uppercase text-muted-foreground\">\n <tr>\n <th className=\"px-3 py-2\">Row</th>\n <th className=\"px-3 py-2\">Field</th>\n <th className=\"px-3 py-2\">Problem</th>\n </tr>\n </thead>\n <tbody>\n {job.problems.map((problem, index) => (\n <tr key={`${problem.row}-${problem.field}-${index}`} className=\"border-t border-border\">\n <td className=\"px-3 py-2 tabular-nums\">{problem.row}</td>\n <td className=\"px-3 py-2 font-mono text-xs\">{problem.field || \"—\"}</td>\n <td className=\"px-3 py-2 text-destructive\">{problem.message}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\nfunction Progress({ job }: { job: ImportJob }): React.ReactElement {\n const percent = job.rows_total > 0 ? Math.round((job.rows_done * 100) / job.rows_total) : 0;\n return (\n <div className=\"space-y-2\" role=\"status\" aria-live=\"polite\">\n <p className=\"text-sm\">\n {job.status === \"previewing\" ? \"Previewing\" : \"Committing\"}… {job.rows_done} /{\" \"}\n {job.rows_total} rows\n </p>\n <div className=\"h-2 w-full overflow-hidden rounded bg-muted\">\n <div className=\"h-full bg-primary transition-all\" style={{ width: `${percent}%` }} />\n </div>\n </div>\n );\n}\n\nfunction MappingTable(props: {\n job: ImportJob;\n fields: readonly ImportColumn[];\n mapping: Record<string, string>;\n onChange: (header: string, field: string) => void;\n}): React.ReactElement {\n const { job, fields, mapping, onChange } = props;\n const options = fields.map((field) => ({\n value: field.name,\n label: `${field.name}${field.required ? \" *\" : \"\"}${field.key ? \" (key)\" : \"\"}`,\n }));\n return (\n <div className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full text-sm\" aria-label=\"Column mapping\">\n <thead className=\"bg-muted text-left text-xs uppercase text-muted-foreground\">\n <tr>\n <th className=\"px-3 py-2\">Column in the file</th>\n <th className=\"px-3 py-2\">Field</th>\n </tr>\n </thead>\n <tbody>\n {job.columns.map((header) => (\n <tr key={header} className=\"border-t border-border\">\n <td className=\"px-3 py-2\">{header}</td>\n <td className=\"px-3 py-2\">\n <Select\n aria-label={`Field for ${header}`}\n className=\"h-9 w-auto min-w-48\"\n value={mapping[header] ?? \"\"}\n options={options}\n clearable\n clearLabel=\"— ignore —\"\n onValueChange={(next) => onChange(header, next ?? \"\")}\n />\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\n/**\n * Import a CSV or XLSX file into a resource: upload, map columns to fields,\n * preview (the mandatory dry run — N created / updated / skipped with every\n * row's errors), then commit. Drives `/<resource>/import/…`; the backend\n * validates every row through the same serializer the API uses, keeps rows\n * inside the user's scope and refuses fields the role may not write. Large\n * files run in the background with progress.\n */\nexport function ResourceImport({\n resource,\n title = \"Import\",\n onDone,\n className,\n}: ResourceImportProps): React.ReactElement {\n const client = useKarniClient();\n const describe = useImportDescribe(resource);\n const actions = useImportActions(resource);\n const [jobId, setJobId] = React.useState<string | undefined>(undefined);\n const [mapping, setMapping] = React.useState<Record<string, string>>({});\n const [remap, setRemap] = React.useState(false);\n const [templateError, setTemplateError] = React.useState<string | null>(null);\n const fileRef = React.useRef<HTMLInputElement>(null);\n const jobQuery = useImportJob(resource, jobId);\n const job = jobQuery.data;\n\n // The job's mapping (suggested or remembered) seeds the editable one.\n const seededFor = React.useRef<string | undefined>(undefined);\n React.useEffect(() => {\n if (job !== undefined && seededFor.current !== job.id) {\n seededFor.current = job.id;\n setMapping(job.mapping);\n }\n }, [job]);\n\n React.useEffect(() => {\n if (job?.status === \"done\") onDone?.(job);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- fire once per completion\n }, [job?.status, job?.id]);\n\n const fields = job?.fields ?? describe.data?.fields ?? [];\n const busy = actions.upload.isPending || actions.preview.isPending || actions.commit.isPending;\n const mutationError = actions.upload.error ?? actions.preview.error ?? actions.commit.error;\n\n const handleUpload = (event: React.FormEvent<HTMLFormElement>): void => {\n event.preventDefault();\n const file = fileRef.current?.files?.[0];\n if (file === undefined) return;\n setRemap(false);\n actions.upload.mutate({ file }, { onSuccess: (created) => setJobId(created.id) });\n };\n\n const handlePreview = (): void => {\n if (job === undefined) return;\n setRemap(false);\n actions.preview.mutate({ jobId: job.id, mapping });\n };\n\n const handleTemplate = (format: \"xlsx\" | \"csv\"): void => {\n setTemplateError(null);\n downloadImportTemplate(client, resource, format).catch((error: unknown) =>\n setTemplateError(errorText(error)),\n );\n };\n\n let body: React.ReactNode;\n if (describe.isPending) {\n body = <Skeleton className=\"h-24 w-full\" data-testid=\"resource-import-loading\" />;\n } else if (job === undefined || (jobId !== undefined && jobQuery.isPending)) {\n body = (\n <form onSubmit={handleUpload} className=\"flex flex-wrap items-end gap-3\">\n <label className=\"flex flex-col gap-1 text-sm\">\n <span>CSV or XLSX file</span>\n <input\n ref={fileRef}\n type=\"file\"\n name=\"file\"\n accept=\".csv,.xlsx\"\n required\n className=\"text-sm\"\n aria-label=\"File to import\"\n />\n </label>\n <Button type=\"submit\" disabled={busy}>\n Upload\n </Button>\n </form>\n );\n } else if (isImportInFlight(job)) {\n body = <Progress job={job} />;\n } else if (job.status === \"uploaded\" || job.status === \"failed\" || remap) {\n body = (\n <div className=\"space-y-3\">\n {job.error !== null && (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {job.error}\n </p>\n )}\n <p className=\"text-sm text-muted-foreground\">\n {job.file_name} — {job.rows_total} rows. Map each column to a field; blank cells leave a\n field unchanged.\n </p>\n <MappingTable\n job={job}\n fields={fields}\n mapping={mapping}\n onChange={(header, field) => setMapping((old) => ({ ...old, [header]: field }))}\n />\n <div className=\"flex flex-wrap gap-2\">\n <Button onClick={handlePreview} disabled={busy}>\n Preview\n </Button>\n <Button variant=\"outline\" onClick={() => setJobId(undefined)} disabled={busy}>\n Upload another file\n </Button>\n </div>\n </div>\n );\n } else {\n body = (\n <div className=\"space-y-3\">\n <p className=\"text-sm text-muted-foreground\">\n {job.file_name} — {job.rows_total} rows,{\" \"}\n {job.status === \"done\" ? \"imported.\" : \"previewed; nothing is saved yet.\"}\n </p>\n <Stats job={job} />\n <Problems job={job} />\n <div className=\"flex flex-wrap gap-2\">\n {job.status === \"previewed\" ? (\n <>\n <Button onClick={() => actions.commit.mutate(job.id)} disabled={busy}>\n Commit\n </Button>\n <Button variant=\"outline\" onClick={() => setRemap(true)} disabled={busy}>\n Change the mapping\n </Button>\n </>\n ) : (\n <Button variant=\"outline\" onClick={() => setJobId(undefined)}>\n Import another file\n </Button>\n )}\n </div>\n </div>\n );\n }\n\n return (\n <section className={cn(\"space-y-3\", className)} aria-label=\"Import\">\n <div className=\"flex flex-wrap items-baseline justify-between gap-2\">\n {title !== null ? <h3 className=\"text-base font-semibold\">{title}</h3> : null}\n <div className=\"flex gap-2 text-sm\">\n <button\n type=\"button\"\n className=\"text-primary underline-offset-4 hover:underline\"\n onClick={() => handleTemplate(\"xlsx\")}\n >\n Download template (XLSX)\n </button>\n <button\n type=\"button\"\n className=\"text-primary underline-offset-4 hover:underline\"\n onClick={() => handleTemplate(\"csv\")}\n >\n CSV\n </button>\n </div>\n </div>\n {describe.error !== null && describe.error !== undefined ? (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {errorText(describe.error)}\n </p>\n ) : null}\n {mutationError !== null && mutationError !== undefined ? (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {errorText(mutationError)}\n </p>\n ) : null}\n {templateError !== null ? (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {templateError}\n </p>\n ) : null}\n {body}\n </section>\n );\n}\n","/**\n * createKarniClient — the typed fetch wrapper every @karni/ui layer sits on\n * (contract \"Schema client\" + D6).\n *\n * Responsibilities:\n * - URL joining + query-string serialization (arrays become repeated keys,\n * null/undefined are dropped),\n * - JSON request/response handling; a FormData body is passed through\n * untouched with NO manual Content-Type (the D2 multipart rule),\n * - DRF error passthrough: non-2xx responses throw KarniApiError carrying the\n * parsed body (field errors / detail / non_field_errors) verbatim,\n * - auth hook points per D6's client-owns-tokens design: the auth layer (not\n * React) registers token injection, extra headers (session CSRF),\n * credentials mode and a 401 handler via `setAuthHooks`. The client calls\n * `onUnauthorized` at most ONCE per request and retries at most ONCE — a\n * request that 401s again after a successful refresh is surfaced, never\n * re-triggers refresh (the single-flight refresh promise itself lives in\n * the auth layer behind this hook).\n */\n\nexport interface KarniClientOptions {\n /**\n * Origin (plus optional path prefix) requests resolve against, e.g.\n * \"https://api.example.com\" or \"\" for same-origin. Paths that already start\n * with the prefix are not double-prefixed, so operation paths taken from\n * the OpenAPI document (\"/api/events/\") work with any baseUrl.\n */\n baseUrl: string;\n /** Path of the OpenAPI document. Default \"/api/schema/\". */\n schemaUrl?: string;\n /** Initial access-token getter; `setAuthHooks` can replace it later (D6). */\n getAccessToken?: () => string | null;\n /** Custom fetch implementation (tests, SSR). Resolved per request. */\n fetch?: typeof globalThis.fetch;\n}\n\nexport type KarniQueryValue =\n string | number | boolean | ReadonlyArray<string | number | boolean> | null | undefined;\n\nexport interface KarniRequestOptions {\n method?: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n query?: Record<string, KarniQueryValue>;\n /** JSON-serialized unless it is FormData (multipart rule D2). */\n body?: unknown;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n /**\n * Skip the 401 → onUnauthorized → retry cycle for this request. The auth\n * layer sets it on its own login/refresh/logout calls so a failing refresh\n * can never recurse into another refresh (D6).\n */\n skipAuthRefresh?: boolean;\n}\n\n/**\n * Hook points the auth layer registers on the client (D6). Keys present in\n * the object passed to `setAuthHooks` override the current value (an explicit\n * `undefined` clears one); absent keys are kept.\n */\nexport interface KarniAuthHooks {\n /** Called before every request; a non-null return is sent as Bearer. */\n getAccessToken?: () => string | null;\n /**\n * Called once when a request gets a 401 (unless `skipAuthRefresh`). Return\n * true to retry the request once with freshly-injected credentials, false\n * to surface the error. Single-flight refresh lives behind this hook.\n */\n onUnauthorized?: (error: KarniApiError) => Promise<boolean>;\n /** Extra headers merged into every request (session-mode X-CSRFToken). */\n getHeaders?: () => Record<string, string>;\n /** fetch credentials mode; session mode sets \"include\". */\n credentials?: RequestCredentials;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction defaultMessage(status: number, data: unknown): string {\n if (isRecord(data) && typeof data[\"detail\"] === \"string\") return data[\"detail\"];\n return `Karni API request failed with status ${status}`;\n}\n\n/** Thrown for non-2xx responses; `data` carries the parsed DRF error body. */\nexport class KarniApiError extends Error {\n readonly status: number;\n /** Parsed body when JSON (field errors, detail, non_field_errors), else text. */\n readonly data: unknown;\n\n constructor(status: number, data: unknown, message?: string) {\n super(message ?? defaultMessage(status, data));\n this.name = \"KarniApiError\";\n this.status = status;\n this.data = data;\n }\n}\n\nexport interface KarniClient {\n readonly baseUrl: string;\n readonly schemaUrl: string;\n request<T>(path: string, options?: KarniRequestOptions): Promise<T>;\n /**\n * The same request (auth, query, 401 retry) returning the raw `Response`\n * instead of a parsed body — for file downloads (`GET /<resource>/export/`).\n * Non-2xx responses still throw `KarniApiError` with the parsed error body.\n */\n requestRaw(path: string, options?: KarniRequestOptions): Promise<Response>;\n /** D6 hook point: the auth layer wires tokens/CSRF/401 handling here. */\n setAuthHooks(hooks: KarniAuthHooks): void;\n}\n\n// URL handling\n\nfunction splitBaseUrl(baseUrl: string): { origin: string; basePath: string } {\n const match = /^(https?:\\/\\/[^/]+)(\\/.*)?$/.exec(baseUrl);\n if (match !== null) {\n return { origin: match[1] ?? \"\", basePath: (match[2] ?? \"\").replace(/\\/+$/, \"\") };\n }\n return { origin: \"\", basePath: baseUrl.replace(/\\/+$/, \"\") };\n}\n\nfunction joinUrl(baseUrl: string, path: string): string {\n if (/^https?:\\/\\//.test(path)) return path;\n const { origin, basePath } = splitBaseUrl(baseUrl);\n const normalized = path.startsWith(\"/\") ? path : `/${path}`;\n if (basePath !== \"\" && (normalized === basePath || normalized.startsWith(`${basePath}/`))) {\n return origin + normalized;\n }\n return origin + basePath + normalized;\n}\n\nfunction appendQuery(url: string, query: Record<string, KarniQueryValue> | undefined): string {\n if (query === undefined) return url;\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value === null || value === undefined) continue;\n if (Array.isArray(value)) {\n for (const item of value) params.append(key, String(item));\n } else {\n params.append(key, String(value));\n }\n }\n const qs = params.toString();\n if (qs === \"\") return url;\n return url.includes(\"?\") ? `${url}&${qs}` : `${url}?${qs}`;\n}\n\n// body handling\n\nasync function parseBody(response: Response): Promise<unknown> {\n if (response.status === 204 || response.status === 205) return undefined;\n const text = await response.text();\n if (text === \"\") return undefined;\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"json\")) {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }\n return text;\n}\n\n// the client\n\n/** Creates the fetch client every hook in this package uses: base URL, JSON and multipart bodies, DRF errors as `KarniApiError`, and auth hooks. */\nexport function createKarniClient(options: KarniClientOptions): KarniClient {\n const { baseUrl, schemaUrl = \"/api/schema/\", fetch: fetchOption } = options;\n\n let hooks: KarniAuthHooks = {};\n if (options.getAccessToken !== undefined) {\n hooks = { getAccessToken: options.getAccessToken };\n }\n\n async function perform(url: string, requestOptions: KarniRequestOptions): Promise<Response> {\n const headers = new Headers({ accept: \"application/json\" });\n const hookHeaders = hooks.getHeaders?.();\n if (hookHeaders !== undefined) {\n for (const [name, value] of Object.entries(hookHeaders)) headers.set(name, value);\n }\n if (requestOptions.headers !== undefined) {\n for (const [name, value] of Object.entries(requestOptions.headers)) {\n headers.set(name, value);\n }\n }\n const token = hooks.getAccessToken?.() ?? null;\n if (token !== null && token !== \"\") headers.set(\"authorization\", `Bearer ${token}`);\n\n let body: BodyInit | undefined;\n if (typeof FormData !== \"undefined\" && requestOptions.body instanceof FormData) {\n body = requestOptions.body; // the runtime sets the multipart boundary (D2)\n } else if (requestOptions.body !== undefined) {\n body = JSON.stringify(requestOptions.body);\n if (!headers.has(\"content-type\")) headers.set(\"content-type\", \"application/json\");\n }\n\n const init: RequestInit = { method: requestOptions.method ?? \"GET\", headers };\n if (body !== undefined) init.body = body;\n if (requestOptions.signal !== undefined) init.signal = requestOptions.signal;\n if (hooks.credentials !== undefined) init.credentials = hooks.credentials;\n\n const fetchImpl = fetchOption ?? globalThis.fetch;\n return fetchImpl(url, init);\n }\n\n async function requestRaw(\n path: string,\n requestOptions: KarniRequestOptions = {},\n ): Promise<Response> {\n const url = appendQuery(joinUrl(baseUrl, path), requestOptions.query);\n\n let response = await perform(url, requestOptions);\n if (response.ok) return response;\n\n const error = new KarniApiError(response.status, await parseBody(response));\n if (\n response.status === 401 &&\n hooks.onUnauthorized !== undefined &&\n requestOptions.skipAuthRefresh !== true\n ) {\n const shouldRetry = await hooks.onUnauthorized(error);\n if (shouldRetry) {\n response = await perform(url, requestOptions);\n if (response.ok) return response;\n // A 401 (or anything else) after a successful refresh is surfaced\n // as-is — it never re-triggers refresh (D6).\n throw new KarniApiError(response.status, await parseBody(response));\n }\n }\n throw error;\n }\n\n return {\n baseUrl,\n schemaUrl,\n\n async request<T>(path: string, requestOptions: KarniRequestOptions = {}): Promise<T> {\n const response = await requestRaw(path, requestOptions);\n return (await parseBody(response)) as T;\n },\n\n requestRaw,\n\n setAuthHooks(next: KarniAuthHooks): void {\n hooks = { ...hooks, ...next };\n },\n };\n}\n","/**\n * The non-React auth core (contract \"Hooks + auth\" + D6): the client side\n * owns tokens and refresh; <AuthProvider> merely mirrors this engine's state\n * into React.\n *\n * The engine registers itself on the KarniClient via its D6 hook points\n * (`setAuthHooks`): access-token injection, extra headers (session CSRF),\n * credentials mode, and the 401 handler. EVERY request made through the\n * client — resource hooks, schema loading, custom calls — therefore carries\n * credentials and takes part in the refresh flow, with no per-callsite\n * wiring.\n *\n * ## JWT mode (D6)\n * - The access token lives in memory only; the refresh token lives in the\n * pluggable TokenStorage (localStorage by default).\n * - On a 401 the client calls `onUnauthorized` (at most once per request):\n * the engine runs ONE shared in-flight refresh (`POST\n * <authBasePath>/refresh/`) — every concurrent 401 awaits the same\n * promise. A rotated refresh token is persisted BEFORE that promise\n * resolves, so queued retries can never observe the stale token. The\n * client then retries each request exactly once; a request that 401s\n * AFTER a successful refresh is surfaced and never re-triggers refresh.\n * - Refresh failure clears the storage and flips the engine to \"anonymous\";\n * the original 401s surface to the queued callers.\n * - The engine's own auth calls (login/refresh/me/logout/csrf) set\n * `skipAuthRefresh`, so a 401 from them can never recurse into another\n * refresh. During a refresh the in-memory access token is nulled, so the\n * refresh request itself never carries a stale Bearer header (which would\n * trip DRF authentication/throttling before the view runs).\n * - Multi-tab: tabs do not coordinate (documented limitation). With\n * refresh-token rotation + blacklisting, a refresh in tab A can invalidate\n * the token tab B just read, logging tab B out on its next refresh.\n * Storage events are intentionally not consumed in v0.1.\n *\n * ## Session mode (A4)\n * Django's session cookie authenticates requests; the engine registers\n * `credentials: \"include\"` and a header hook that mirrors the CSRF cookie\n * (\"csrftoken\") into the CSRF header (\"X-CSRFToken\") — names pinned by A4,\n * both overridable. When the cookie is absent it is bootstrapped via\n * `GET <authBasePath>/csrf/` (204 + ensure_csrf_cookie) during initialization\n * and before login. Cross-origin note: `credentials: \"include\"` is only\n * registered once the mode is known — pass `mode=\"session\"` to\n * <AuthProvider> (skipping async schema detection) so the very first\n * requests already include cookies.\n *\n * ## Mode resolution\n * `modeOverride` prop → cached parsed schema (`authMode`) → the schema\n * document's root `x-karni-auth-mode` (api B14) → \"jwt\".\n *\n * Internal module: not re-exported from the barrel.\n */\nimport type { KarniClient } from \"../schema/client\";\nimport type { TokenStorage } from \"./storage\";\nimport type { AuthStatus, KarniUser, LoginResult } from \"./types\";\n\nexport type AuthMode = \"jwt\" | \"session\";\n\nexport interface AuthEngineOptions {\n client: KarniClient;\n tokenStorage: TokenStorage;\n /** Skips schema-based mode detection entirely when set. */\n modeOverride?: AuthMode;\n /** Session-mode CSRF cookie name (A4 pin). Default \"csrftoken\". */\n csrfCookieName?: string;\n /** Session-mode CSRF header name (A4 pin). Default \"X-CSRFToken\". */\n csrfHeaderName?: string;\n /** Path prefix of the auth endpoints, relative to the client's baseUrl. */\n authBasePath?: string;\n /**\n * Reads whatever the schema loader cached under karniKeys.schema() —\n * consulted (shape-guarded) for `authMode` before fetching the document.\n */\n readCachedSchema?: () => unknown;\n}\n\nexport interface AuthSnapshot {\n readonly status: AuthStatus;\n readonly user: KarniUser | null;\n readonly mode: AuthMode | null;\n}\n\n/**\n * Reads the auth mode out of either a ParsedSchema (`authMode`) or a raw\n * OpenAPI document (root `x-karni-auth-mode`), shape-guarded.\n */\nexport function readAuthMode(value: unknown): AuthMode | undefined {\n if (typeof value !== \"object\" || value === null) return undefined;\n const record = value as Record<string, unknown>;\n const candidate = record[\"authMode\"] ?? record[\"x-karni-auth-mode\"];\n return candidate === \"jwt\" || candidate === \"session\" ? candidate : undefined;\n}\n\n/** Validates/normalizes a `me` payload into a KarniUser (roles default []). */\nexport function normalizeUser(value: unknown): KarniUser | null {\n if (typeof value !== \"object\" || value === null) return null;\n const record = value as Record<string, unknown>;\n const { id, email } = record;\n if (typeof id !== \"string\" && typeof id !== \"number\") return null;\n if (typeof email !== \"string\") return null;\n const roles = Array.isArray(record.roles)\n ? record.roles.filter((role): role is string => typeof role === \"string\")\n : [];\n return { ...record, id, email, roles };\n}\n\nfunction readCookie(name: string): string | null {\n if (typeof document === \"undefined\") return null;\n try {\n for (const part of document.cookie.split(\";\")) {\n const trimmed = part.trim();\n const separator = trimmed.indexOf(\"=\");\n if (separator === -1) continue;\n if (trimmed.slice(0, separator) === name) {\n return decodeURIComponent(trimmed.slice(separator + 1));\n }\n }\n } catch {\n // Cookie access can throw in sandboxed documents.\n }\n return null;\n}\n\nfunction describeShape(value: unknown): string {\n if (typeof value !== \"object\" || value === null) return `a ${typeof value}`;\n const keys = Object.keys(value);\n return keys.length === 0 ? \"an empty object\" : `an object with keys [${keys.join(\", \")}]`;\n}\n\nfunction read2fa(value: unknown): { ephemeralToken: string } | null {\n if (typeof value !== \"object\" || value === null) return null;\n const record = value as Record<string, unknown>;\n if (record.requires_2fa !== true) return null;\n return typeof record.ephemeral_token === \"string\"\n ? { ephemeralToken: record.ephemeral_token }\n : null;\n}\n\nexport class AuthEngine {\n private readonly client: KarniClient;\n private readonly tokenStorage: TokenStorage;\n private readonly modeOverride: AuthMode | undefined;\n private readonly csrfCookieName: string;\n private readonly csrfHeaderName: string;\n private readonly authBasePath: string;\n private readonly readCachedSchema: (() => unknown) | undefined;\n\n private mode: AuthMode | null;\n private accessToken: string | null = null;\n private refreshPromise: Promise<boolean> | null = null;\n private initPromise: Promise<void> | null = null;\n private readonly listeners = new Set<() => void>();\n private state: AuthSnapshot;\n\n constructor(options: AuthEngineOptions) {\n this.client = options.client;\n this.tokenStorage = options.tokenStorage;\n this.modeOverride = options.modeOverride;\n this.csrfCookieName = options.csrfCookieName ?? \"csrftoken\";\n this.csrfHeaderName = options.csrfHeaderName ?? \"X-CSRFToken\";\n this.authBasePath = (options.authBasePath ?? \"/auth\").replace(/\\/+$/, \"\");\n this.readCachedSchema = options.readCachedSchema;\n this.mode = options.modeOverride ?? null;\n this.state = { status: \"loading\", user: null, mode: this.mode };\n // Register the hook points during construction (render phase), not in an\n // effect: children of <AuthProvider> fire their first queries from\n // effects that run BEFORE the parent's own effects, and those requests\n // must already flow through the auth machinery.\n this.attach();\n }\n\n // client hook registration\n\n /** Registers the D6 hook points on the client. Idempotent. */\n attach(): void {\n this.client.setAuthHooks({\n getAccessToken: () => this.accessToken,\n onUnauthorized: () => this.handleUnauthorized(),\n getHeaders: () => this.csrfHeaders(),\n ...(this.mode === \"session\" ? { credentials: \"include\" as RequestCredentials } : {}),\n });\n }\n\n /**\n * Clears every hook this engine registered (including a `getAccessToken`\n * the app passed to createKarniClient — an unmounted AuthProvider leaves\n * the client fully unauthenticated by design).\n */\n detach(): void {\n this.client.setAuthHooks({\n getAccessToken: undefined,\n onUnauthorized: undefined,\n getHeaders: undefined,\n credentials: undefined,\n });\n }\n\n private csrfHeaders(): Record<string, string> {\n if (this.mode !== \"session\") return {};\n const token = readCookie(this.csrfCookieName);\n return token === null ? {} : { [this.csrfHeaderName]: token };\n }\n\n /**\n * The client calls this at most once per 401-ing request (D6). Returning\n * true makes the client retry that request exactly once with\n * freshly-injected credentials; the retry's outcome is always surfaced.\n */\n private async handleUnauthorized(): Promise<boolean> {\n await this.ensureInitialized();\n if (this.mode !== \"jwt\") {\n // The session evaporated server-side; mirror it.\n if (this.state.status === \"authenticated\") this.setState(\"anonymous\", null);\n return false;\n }\n if (this.tokenStorage.get() === null) return false;\n return this.ensureRefresh();\n }\n\n // --- state mirroring (consumed by <AuthProvider> via useSyncExternalStore)\n\n readonly subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n readonly getSnapshot = (): AuthSnapshot => this.state;\n\n private setState(status: AuthStatus, user: KarniUser | null): void {\n this.state = { status, user, mode: this.mode };\n for (const listener of this.listeners) listener();\n }\n\n // bootstrap\n\n /** Idempotent: the first call kicks off mode resolution + session restore. */\n ensureInitialized(): Promise<void> {\n this.initPromise ??= this.initialize();\n return this.initPromise;\n }\n\n private async initialize(): Promise<void> {\n try {\n this.mode =\n this.modeOverride ??\n readAuthMode(this.readCachedSchema?.()) ??\n (await this.fetchSchemaAuthMode()) ??\n \"jwt\";\n if (this.mode === \"session\") {\n this.client.setAuthHooks({ credentials: \"include\" });\n await this.ensureCsrfToken(); // A4: bootstrap the cookie when absent.\n await this.syncUser();\n return;\n }\n if (this.tokenStorage.get() === null) {\n this.setState(\"anonymous\", null);\n return;\n }\n const refreshed = await this.ensureRefresh();\n if (!refreshed) return; // performRefresh already cleared + emitted.\n await this.syncUser();\n } catch {\n this.setState(\"anonymous\", null);\n }\n }\n\n private async fetchSchemaAuthMode(): Promise<AuthMode | undefined> {\n try {\n // joinUrl never double-prefixes, so passing the absolute schema path is\n // safe with any baseUrl; the client's accept header selects JSON.\n const document = await this.client.request<unknown>(this.client.schemaUrl, {\n skipAuthRefresh: true,\n });\n return readAuthMode(document);\n } catch {\n return undefined;\n }\n }\n\n /** Fetches `/me/` and mirrors the result; any failure means anonymous. */\n private async syncUser(): Promise<void> {\n try {\n const data = await this.client.request<unknown>(`${this.authBasePath}/me/`, {\n skipAuthRefresh: true,\n });\n const user = normalizeUser(data);\n if (user === null) {\n this.setState(\"anonymous\", null);\n } else {\n this.setState(\"authenticated\", user);\n }\n } catch {\n this.setState(\"anonymous\", null);\n }\n }\n\n /**\n * Reads the CSRF cookie, bootstrapping it via `GET <authBasePath>/csrf/`\n * when absent (A4). Returns null when the cookie stays unreadable (e.g.\n * CSRF_COOKIE_HTTPONLY) — requests then go out without the header and the\n * backend's 403 surfaces, which is the honest failure mode.\n */\n private async ensureCsrfToken(): Promise<string | null> {\n let token = readCookie(this.csrfCookieName);\n if (token === null) {\n try {\n await this.client.request<unknown>(`${this.authBasePath}/csrf/`, {\n method: \"GET\",\n skipAuthRefresh: true,\n });\n } catch {\n // Bootstrap is best-effort; the cookie re-read below decides.\n }\n token = readCookie(this.csrfCookieName);\n }\n return token;\n }\n\n // refresh (D6)\n\n /** ONE shared in-flight refresh; resolves true on success. */\n private ensureRefresh(): Promise<boolean> {\n if (this.refreshPromise === null) {\n this.refreshPromise = this.performRefresh().finally(() => {\n this.refreshPromise = null;\n });\n }\n return this.refreshPromise;\n }\n\n private async performRefresh(): Promise<boolean> {\n const refreshToken = this.tokenStorage.get();\n if (refreshToken === null) {\n this.accessToken = null;\n this.setState(\"anonymous\", null);\n return false;\n }\n // Null the stale access token for the duration of the refresh so the\n // refresh request itself (and anything racing it) never carries a Bearer\n // header the backend would reject before reaching the view.\n this.accessToken = null;\n try {\n const data = await this.client.request<unknown>(`${this.authBasePath}/refresh/`, {\n method: \"POST\",\n body: { refresh: refreshToken },\n skipAuthRefresh: true, // a 401 here can never recurse (D6)\n });\n const record =\n typeof data === \"object\" && data !== null ? (data as Record<string, unknown>) : {};\n const access = record.access;\n if (typeof access !== \"string\" || access === \"\") {\n throw new Error(\n `Karni auth: ${this.authBasePath}/refresh/ returned ${describeShape(data)} ` +\n \"instead of { access, refresh? }.\",\n );\n }\n // Persist the rotated refresh token BEFORE this promise resolves, so\n // every queued 401 retry runs against the rotated token (D6).\n const rotated = record.refresh;\n if (typeof rotated === \"string\" && rotated !== \"\") {\n this.tokenStorage.set(rotated);\n }\n this.accessToken = access;\n return true;\n } catch {\n this.tokenStorage.clear();\n this.accessToken = null;\n this.setState(\"anonymous\", null);\n return false;\n }\n }\n\n // public auth actions\n\n async login(email: string, password: string): Promise<LoginResult> {\n await this.ensureInitialized();\n const path = `${this.authBasePath}/login/`;\n if (this.mode === \"session\") {\n await this.ensureCsrfToken(); // header rides in via the getHeaders hook\n const data = await this.client.request<unknown>(path, {\n method: \"POST\",\n body: { email, password },\n skipAuthRefresh: true,\n });\n const twoFactor = read2fa(data);\n if (twoFactor !== null) {\n return { requires2fa: true, ephemeralToken: twoFactor.ephemeralToken };\n }\n const user = normalizeUser(data) ?? (await this.fetchMe(path));\n this.setState(\"authenticated\", user);\n return { ok: true, user };\n }\n\n const data = await this.client.request<unknown>(path, {\n method: \"POST\",\n body: { email, password },\n skipAuthRefresh: true,\n });\n const twoFactor = read2fa(data);\n if (twoFactor !== null) {\n return { requires2fa: true, ephemeralToken: twoFactor.ephemeralToken };\n }\n const record =\n typeof data === \"object\" && data !== null ? (data as Record<string, unknown>) : {};\n const { access, refresh } = record;\n if (typeof access !== \"string\" || typeof refresh !== \"string\") {\n throw new Error(\n `Karni auth: unexpected response from POST ${path} — expected ` +\n \"{ access, refresh } (JWT mode) or { requires_2fa, ephemeral_token }, got \" +\n `${describeShape(data)}. Check the backend's KARNI_AUTH_MODE and the ` +\n 'AuthProvider \"mode\" prop.',\n );\n }\n this.tokenStorage.set(refresh);\n this.accessToken = access;\n const user = normalizeUser(record.user) ?? (await this.fetchMe(path));\n this.setState(\"authenticated\", user);\n return { ok: true, user };\n }\n\n private async fetchMe(loginPath: string): Promise<KarniUser> {\n const data = await this.client.request<unknown>(`${this.authBasePath}/me/`, {\n skipAuthRefresh: true,\n });\n const user = normalizeUser(data);\n if (user === null) {\n throw new Error(\n `Karni auth: POST ${loginPath} succeeded but ${this.authBasePath}/me/ returned ` +\n `${describeShape(data)} instead of a user object with id and email.`,\n );\n }\n return user;\n }\n\n /** Best-effort server logout, then always clears local state (anonymous). */\n async logout(): Promise<void> {\n await this.ensureInitialized();\n try {\n if (this.mode === \"session\") {\n await this.ensureCsrfToken();\n await this.client.request<unknown>(`${this.authBasePath}/logout/`, {\n method: \"POST\",\n skipAuthRefresh: true,\n });\n } else {\n const refresh = this.tokenStorage.get();\n if (refresh !== null) {\n await this.client.request<unknown>(`${this.authBasePath}/logout/`, {\n method: \"POST\",\n body: { refresh },\n skipAuthRefresh: true,\n });\n }\n }\n } catch {\n // Server-side logout is best effort; local state clears regardless.\n }\n this.accessToken = null;\n this.tokenStorage.clear();\n this.setState(\"anonymous\", null);\n }\n\n /**\n * Adopts tokens issued out of band — what `@karni/impersonation-ui` does\n * when a support user starts or stops impersonating (the backend answers\n * with tokens for the other identity). JWT mode only; in session mode the\n * server-side session already changed, so this just re-syncs `/me/`.\n */\n async adoptTokens(access: string | null, refresh: string | null): Promise<void> {\n await this.ensureInitialized();\n if (this.mode === \"jwt\") {\n if (typeof refresh === \"string\" && refresh !== \"\") this.tokenStorage.set(refresh);\n if (typeof access === \"string\" && access !== \"\") this.accessToken = access;\n }\n await this.syncUser();\n }\n\n /**\n * Re-syncs the session: rotates the tokens in JWT mode (A3: /refresh/ is\n * 405 in session mode, so session mode only re-fetches /me/).\n */\n async refresh(): Promise<void> {\n await this.ensureInitialized();\n if (this.mode === \"jwt\") {\n const refreshed = await this.ensureRefresh();\n if (!refreshed) return; // Already anonymous + cleared.\n }\n await this.syncUser();\n }\n}\n","/**\n * Pluggable refresh-token storage for JWT mode (contract \"Hooks + auth\").\n *\n * The default adapter is `localStorage`: it survives reloads and is the\n * simplest thing that works, but any XSS on your page can read it. Stricter\n * setups use `createMemoryTokenStorage()` (logout on reload) or implement\n * the three-method `TokenStorage` interface themselves (e.g. backed by a\n * worker, or by an HttpOnly-cookie BFF). Session mode needs no storage.\n */\n\nexport interface TokenStorage {\n get(): string | null;\n set(token: string): void;\n clear(): void;\n}\n\n/**\n * Keeps the refresh token in localStorage; the default storage. `key` defaults to \"karni.refreshToken\". Every storage\n * access is guarded: when localStorage is unavailable (SSR, private windows,\n * blocked site data) the adapter degrades to a no-op that returns `null`\n * instead of throwing.\n */\nexport function createLocalStorageTokenStorage(key = \"karni.refreshToken\"): TokenStorage {\n return {\n get(): string | null {\n try {\n return globalThis.localStorage.getItem(key);\n } catch {\n return null;\n }\n },\n set(token: string): void {\n try {\n globalThis.localStorage.setItem(key, token);\n } catch {\n // Storage unavailable — the session simply won't survive a reload.\n }\n },\n clear(): void {\n try {\n globalThis.localStorage.removeItem(key);\n } catch {\n // Nothing stored, nothing to clear.\n }\n },\n };\n}\n\n/**\n * In-memory adapter: most secure (nothing persisted anywhere), but a page\n * reload logs the user out.\n */\nexport function createMemoryTokenStorage(): TokenStorage {\n let token: string | null = null;\n return {\n get: () => token,\n set: (next: string) => {\n token = next;\n },\n clear: () => {\n token = null;\n },\n };\n}\n","/**\n * <AuthProvider> + useAuth (contract \"Hooks + auth\" + D6).\n *\n * The provider instantiates the non-React AuthEngine — which owns the tokens\n * and the single-flight refresh machinery, and registers itself on the\n * KarniClient's auth hook points (see ./engine.ts) — and mirrors its state\n * into React. It must be rendered inside <KarniProvider>: it takes the\n * KarniClient from context and uses the shared QueryClient to peek at the\n * cached schema for `x-karni-auth-mode`.\n *\n * Because the engine hooks into the client itself, EVERY request made\n * through the client while an <AuthProvider> is mounted — resource hooks,\n * schema loading, custom `client.request` calls — carries credentials\n * (Bearer in JWT mode; CSRF header + `credentials: \"include\"` in session\n * mode) and takes part in the 401 → refresh → retry flow.\n *\n * Escape hatches: `mode` pins the auth mode (skipping schema detection —\n * recommended for cross-origin session setups so the very first requests\n * already include cookies), `tokenStorage` swaps the refresh-token store,\n * `csrfCookieName` / `csrfHeaderName` re-pin the session CSRF names (A4),\n * and `authBasePath` moves the auth endpoints off `/auth`.\n *\n * The OpenAPI document is generated per role (`Karni.field_roles`, ADR 0002\n * P3): a field a role may not read is absent from its schema. When the\n * identity changes (login, logout, a refresh that lands on another user) the\n * provider invalidates the cached schema, so tables, forms and detail views\n * follow the new user's field set without any per-role component code.\n *\n * Known limitations (D6): browser tabs do not coordinate refreshes — with\n * refresh-token rotation, a refresh in one tab can log another tab out on\n * its next refresh. Identity changes also do not auto-invalidate resource\n * queries; call `queryClient.invalidateQueries({ queryKey:\n * karniKeys.resource(...) })` after login/logout where it matters.\n */\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { karniKeys } from \"../hooks/keys\";\nimport { useKarniClient } from \"../schema/provider\";\nimport { AuthEngine } from \"./engine\";\nimport { createLocalStorageTokenStorage, type TokenStorage } from \"./storage\";\nimport type { AuthStatus, KarniUser, LoginResult } from \"./types\";\n\nexport interface AuthProviderProps {\n /**\n * \"jwt\" | \"session\"; when omitted, the mode comes from the schema root's\n * x-karni-auth-mode (D6), falling back to \"jwt\" when the schema does not\n * declare one.\n */\n mode?: \"jwt\" | \"session\";\n /** JWT mode refresh-token storage; default localStorage adapter. */\n tokenStorage?: TokenStorage;\n /** Session mode CSRF cookie name; default \"csrftoken\" (D6/A4). */\n csrfCookieName?: string;\n /** Session mode CSRF header name; default \"X-CSRFToken\" (D6/A4). */\n csrfHeaderName?: string;\n /** Path prefix of the auth endpoints relative to baseUrl; default \"/auth\". */\n authBasePath?: string;\n children?: ReactNode;\n}\n\nexport interface AuthContextValue {\n user: KarniUser | null;\n roles: string[];\n status: AuthStatus;\n login(email: string, password: string): Promise<LoginResult>;\n logout(): Promise<void>;\n refresh(): Promise<void>;\n /**\n * Adopts tokens issued out of band (JWT mode; session mode re-syncs `/me/`),\n * e.g. after starting or stopping an impersonated session.\n */\n adoptTokens(access: string | null, refresh: string | null): Promise<void>;\n}\n\n/**\n * The React mirror of the auth engine's state. Exported for advanced\n * composition (stories, tests, custom providers); application code should\n * use <AuthProvider> + useAuth().\n */\nexport const AuthContext = createContext<AuthContextValue | null>(null);\n\n/** Holds the signed-in user and attaches credentials (JWT or session) to every request; render it inside `KarniProvider`. */\nexport function AuthProvider({\n mode,\n tokenStorage,\n csrfCookieName,\n csrfHeaderName,\n authBasePath,\n children,\n}: AuthProviderProps): ReactElement {\n const client = useKarniClient();\n const queryClient = useQueryClient();\n const storage = useMemo(() => tokenStorage ?? createLocalStorageTokenStorage(), [tokenStorage]);\n\n // The engine registers the client auth hooks in its constructor (render\n // phase) so that children's first queries — fired from effects that run\n // BEFORE this component's own effects — already flow through it.\n const engine = useMemo(\n () =>\n new AuthEngine({\n client,\n tokenStorage: storage,\n ...(mode !== undefined ? { modeOverride: mode } : {}),\n ...(csrfCookieName !== undefined ? { csrfCookieName } : {}),\n ...(csrfHeaderName !== undefined ? { csrfHeaderName } : {}),\n ...(authBasePath !== undefined ? { authBasePath } : {}),\n readCachedSchema: () => queryClient.getQueryData(karniKeys.schema()),\n }),\n [client, queryClient, storage, mode, csrfCookieName, csrfHeaderName, authBasePath],\n );\n\n useEffect(() => {\n engine.attach(); // re-assert after StrictMode remounts / engine swaps\n void engine.ensureInitialized();\n return () => {\n engine.detach();\n };\n }, [engine]);\n\n const snapshot = useSyncExternalStore(engine.subscribe, engine.getSnapshot, engine.getSnapshot);\n\n // The schema is per role: a new identity (or none) means a new field set.\n const identity = snapshot.user?.id ?? null;\n const previousIdentity = useRef(identity);\n useEffect(() => {\n if (previousIdentity.current === identity) return;\n previousIdentity.current = identity;\n void queryClient.invalidateQueries({ queryKey: karniKeys.schema() });\n }, [identity, queryClient]);\n\n const value = useMemo<AuthContextValue>(\n () => ({\n user: snapshot.user,\n roles: snapshot.user?.roles ?? [],\n status: snapshot.status,\n login: (email, password) => engine.login(email, password),\n logout: () => engine.logout(),\n refresh: () => engine.refresh(),\n adoptTokens: (access, refresh) => engine.adoptTokens(access, refresh),\n }),\n [engine, snapshot],\n );\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n\n/** Returns the signed-in user, auth status, `login` and `logout`; throws a descriptive error outside `AuthProvider`. */\nexport function useAuth(): AuthContextValue {\n const value = useContext(AuthContext);\n if (value === null) {\n throw new Error(\n \"useAuth must be used within an <AuthProvider> (itself inside <KarniProvider>). \" +\n \"Wrap your tree: <KarniProvider client={...}><AuthProvider>...</AuthProvider></KarniProvider>.\",\n );\n }\n return value;\n}\n","/**\n * <AuthGuard> — renders children only for authenticated users (optionally\n * holding one of the given roles); otherwise the `fallback` slot (contract\n * \"Hooks + auth\").\n *\n * While the initial auth state resolves, the `loading` slot renders\n * (default: nothing) so protected content never flashes a login screen\n * during session restore.\n */\nimport type { ReactElement, ReactNode } from \"react\";\nimport { useAuth } from \"./provider\";\nimport { registerComponentRole } from \"../lib/roles\";\n\nregisterComponentRole(\"auth-guard\", \"AuthGuard\");\n\nexport interface AuthGuardProps {\n /** Grant access when the user holds AT LEAST ONE of these role names. */\n roles?: string[];\n /** Rendered for anonymous users and role mismatches; default nothing. */\n fallback?: ReactNode;\n /** Rendered while the auth status is still \"loading\"; default nothing. */\n loading?: ReactNode;\n children?: ReactNode;\n}\n\n/** Renders its children only for a signed-in user, optionally with one of the given roles; otherwise its `fallback`. */\nexport function AuthGuard({\n roles,\n fallback = null,\n loading = null,\n children,\n}: AuthGuardProps): ReactElement | null {\n const { status, user } = useAuth();\n if (status === \"loading\") return <>{loading}</>;\n if (status !== \"authenticated\" || user === null) return <>{fallback}</>;\n if (roles !== undefined && roles.length > 0 && !roles.some((role) => user.roles.includes(role))) {\n return <>{fallback}</>;\n }\n return <>{children}</>;\n}\n","/**\n * LoginForm — the sign-in form every app needs (contract: auth).\n *\n * Email + password against `useAuth().login`, with the error inline. On\n * success it calls `onSuccess(user)` (navigate there). When the backend's\n * 2FA gate fires, `on2FA` receives the ephemeral token so the app can render\n * its code step (`POST <authBasePath>/2fa/login/`); without a handler the\n * form explains that a code is required. Render it inside `AuthProvider`,\n * e.g. as `AuthGuard`'s `fallback`.\n */\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { registerComponentRole } from \"../lib/roles\";\nimport { Button } from \"../components/primitives/button\";\nimport { Input } from \"../components/primitives/input\";\nimport { Label } from \"../components/primitives/label\";\nimport { useAuth } from \"./provider\";\nimport type { KarniUser } from \"./types\";\n\nregisterComponentRole(\"login-form\", \"LoginForm\");\n\nexport interface LoginFormProps {\n /** Called with the signed-in user; navigate from here. */\n onSuccess?: (user: KarniUser) => void;\n /** Called when the account needs a second factor (the token completes it). */\n on2FA?: (ephemeralToken: string) => void;\n /** Heading above the fields; `null` renders none. Default \"Sign in\". */\n title?: React.ReactNode;\n /** Text under the heading (demo logins, a signup link, ...). */\n description?: React.ReactNode;\n /** The submit button's label. Default \"Sign in\". */\n submitLabel?: React.ReactNode;\n /** Shown while the auth status is \"loading\" is irrelevant here; this disables the form. */\n disabled?: boolean;\n className?: string;\n}\n\n/** Email and password sign-in form with inline errors and a callback for the two-factor step. */\nexport function LoginForm({\n onSuccess,\n on2FA,\n title = \"Sign in\",\n description,\n submitLabel = \"Sign in\",\n disabled = false,\n className,\n}: LoginFormProps) {\n const { login } = useAuth();\n const id = React.useId();\n const [busy, setBusy] = React.useState(false);\n const [error, setError] = React.useState<string | null>(null);\n\n async function submit(event: React.FormEvent<HTMLFormElement>) {\n event.preventDefault();\n const data = new FormData(event.currentTarget);\n setBusy(true);\n setError(null);\n try {\n const result = await login(\n String(data.get(\"email\") ?? \"\"),\n String(data.get(\"password\") ?? \"\"),\n );\n if (\"ok\" in result) {\n onSuccess?.(result.user);\n } else if (on2FA !== undefined) {\n on2FA(result.ephemeralToken);\n } else {\n setError(\"This account needs a two-factor code; the app has not enabled that step.\");\n }\n } catch {\n setError(\"That email and password do not match.\");\n } finally {\n setBusy(false);\n }\n }\n\n return (\n <form\n className={cn(\"space-y-4\", className)}\n onSubmit={(event) => void submit(event)}\n aria-busy={busy}\n noValidate={false}\n >\n {title !== null ? <h2 className=\"text-lg font-semibold\">{title}</h2> : null}\n {description !== undefined ? (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n ) : null}\n <div className=\"space-y-1\">\n <Label htmlFor={`${id}-email`}>Email</Label>\n <Input\n id={`${id}-email`}\n name=\"email\"\n type=\"email\"\n autoComplete=\"email\"\n required\n disabled={disabled || busy}\n />\n </div>\n <div className=\"space-y-1\">\n <Label htmlFor={`${id}-password`}>Password</Label>\n <Input\n id={`${id}-password`}\n name=\"password\"\n type=\"password\"\n autoComplete=\"current-password\"\n required\n disabled={disabled || busy}\n />\n </div>\n {error !== null ? (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {error}\n </p>\n ) : null}\n <Button type=\"submit\" disabled={disabled || busy}>\n {submitLabel}\n </Button>\n </form>\n );\n}\n","/**\n * Role helpers over the authenticated user (contract \"Hooks + auth\",\n * accounts A15: the me endpoint returns `roles: string[]`).\n */\nimport { useMemo } from \"react\";\nimport { useAuth } from \"./provider\";\n\nexport interface PermissionHelpers {\n /** True when the user has at least one of the given role names. */\n hasRole(...names: string[]): boolean;\n isAuthenticated: boolean;\n}\n\n/** `isAuthenticated` and `hasRole(...names)` for the signed-in user. */\nexport function usePermission(): PermissionHelpers {\n const { roles, status } = useAuth();\n return useMemo<PermissionHelpers>(\n () => ({\n isAuthenticated: status === \"authenticated\",\n hasRole: (...names: string[]) =>\n status === \"authenticated\" && names.some((name) => roles.includes(name)),\n }),\n [roles, status],\n );\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\n\nregisterComponentRole(\"page-shell\", \"Page\");\n\nexport interface PageProps extends Omit<React.HTMLAttributes<HTMLElement>, \"title\"> {\n /** Page heading, rendered as an <h1>. */\n title: React.ReactNode;\n /** Optional sub-heading under the title. */\n description?: React.ReactNode;\n /** Slot rendered to the right of the title (buttons, menus, …). */\n actions?: React.ReactNode;\n /**\n * Escape hatch: replaces the entire derived header (title/description/\n * actions are ignored when given).\n */\n header?: React.ReactNode;\n /** Extra classes for the derived header row. */\n headerClassName?: string;\n /** Extra classes for the content area under the header. */\n contentClassName?: string;\n children?: React.ReactNode;\n}\n\n/**\n * Standard page chrome: an <h1> title row with an actions slot, then the\n * content. The target usage `<Page title=\"Events\"><ResourceTable … /></Page>`\n * is a complete screen.\n *\n * Escape hatches: `header` replaces the whole derived header; `className`,\n * `headerClassName` and `contentClassName` merge through cn(); every other\n * prop passes through to the root <section>.\n */\nexport const Page = React.forwardRef<HTMLElement, PageProps>(\n (\n {\n title,\n description,\n actions,\n header,\n headerClassName,\n contentClassName,\n className,\n children,\n ...props\n },\n ref,\n ) => (\n <section ref={ref} className={cn(\"flex w-full flex-col gap-6\", className)} {...props}>\n {header ?? (\n <header className={cn(\"flex flex-wrap items-start justify-between gap-4\", headerClassName)}>\n <div className=\"grid gap-1\">\n <h1 className=\"text-2xl font-semibold tracking-tight text-foreground\">{title}</h1>\n {description != null && <p className=\"text-sm text-muted-foreground\">{description}</p>}\n </div>\n {actions != null && <div className=\"flex shrink-0 items-center gap-2\">{actions}</div>}\n </header>\n )}\n <div className={cn(\"flex flex-col gap-4\", contentClassName)}>{children}</div>\n </section>\n ),\n);\nPage.displayName = \"Page\";\n","// Generated by scripts/brand/render.mjs from assets/brand/ — do not edit.\nexport const MARK_VIEWBOX = \"0 0 1000 1000\";\n/** The full mark: ground, rings, strokes. */\nexport const MARK_PATHS: ReadonlyArray<{ readonly fill: string; readonly d: string }> = [\n {\n \"fill\": \"#000000\",\n \"d\": \"M495.8 884.4C366.3 877.9 255.3 816.3 182.4 710.5C128.6 632.2 103.2 521.3 115 415.5C128.3 296.3 188.2 205.8 290.9 150.2C389.1 97 470.1 78.3 564.8 87C689.6 98.4 790.1 167.2 844.3 278.1C896.3 384.6 901.7 498.4 860.4 619.6C833.4 698.7 806.7 746.3 766.3 787.1C699.4 854.6 601.9 889.7 495.8 884.4Z\"\n },\n {\n \"fill\": \"#FB5D08\",\n \"d\": \"M355.6 514.1C355.6 509.2 355.7 507.3 355.8 509.8C355.9 512.3 355.9 516.3 355.8 518.7C355.7 521 355.6 519 355.6 514.1ZM677.1 423C637.3 415.7 624.1 366.4 654.9 340.2C672.8 325 696 324.3 713.7 338.5C741 360.3 735.8 403.2 704.1 418.6C696.1 422.4 684.6 424.3 677.1 423ZM330.5 421.6C299.1 415 283.8 379.9 300.6 352.7C317.1 325.8 352.4 320.7 373.7 342.2C398.9 367.6 387.2 410.3 352.3 420.8C347.4 422.3 335.7 422.7 330.5 421.6ZM504.5 399.6C466.4 392.2 453.2 345.4 481.5 318.2C509.6 291.1 556 308.2 560.5 347.3C564.1 377.9 534.5 405.5 504.5 399.6ZM349.4 395.9C367.2 387.1 367.7 363.1 350.2 354.5C329.3 344.3 308.5 369.4 321.8 388.6C327.9 397.5 339.8 400.7 349.4 395.9ZM694 395.9C716 385.1 709 352 684.8 352C665.4 352 654.8 375.3 667.3 390.4C673.5 397.8 685.2 400.2 694 395.9ZM522.4 373.7C534.6 368 539.9 353.6 534.2 341.9C525.3 323.9 501.3 323.8 492.5 341.8C482.8 361.3 503 382.8 522.4 373.7Z\"\n },\n {\n \"fill\": \"#FFFFFF\",\n \"d\": \"M363 677.8C348.7 675.4 341.3 657.2 334.1 606.9C326.6 554.4 325.7 485.2 332.2 459.2C336.3 442.9 349.3 435.9 362.9 442.6C374.7 448.4 394.4 475.1 427.1 529.5C428.9 532.4 430.5 534.9 430.8 534.9C431 534.9 433.5 530.7 436.3 525.6C486 435.8 497.3 419.9 512.2 419.2C523.9 418.6 531.9 426.3 550 455.6C555.3 464.3 582.5 513.2 591.4 530.3C592.7 532.8 594 534.9 594.2 534.9C594.4 534.9 595.9 532.7 597.5 530C621.8 490.2 643.6 458.3 652.7 449.5C668.6 434.2 686.9 437.8 692.6 457.4C703.9 496.4 693.7 637.6 677.5 666.3C673 674.5 663.4 679.5 655.8 677.8C642.6 674.9 633.9 663.4 598.7 602.7C592.7 592.3 593.3 593.1 592.3 594.4C590.8 596.2 572.8 626.4 560.2 648.2C546.9 671 546 672.4 541.7 674.3C531.2 679.1 519.1 669.5 522.1 658.7C523.4 654.4 551 607 571.8 573.6C575 568.5 577.6 564.2 577.6 564C577.6 563.7 560.8 532.5 547.2 507.4C527.8 471.7 514.9 450.1 513.1 450.1C512.4 450.1 510.6 452.9 504.3 463.4C492.7 482.5 447.9 562.5 447.9 564C447.9 564.3 449.8 567.6 452.1 571.4C475.2 609.2 501.1 653.4 502.6 657.5C506.1 667.6 496.6 677.8 485.8 675.3C479.8 673.9 479.1 673.1 468.6 655.1C464.9 648.8 456 633.6 448.7 621.3C441.5 608.9 434.9 597.8 434.2 596.5C432.8 594 431.8 593 431.5 593.9C431.3 594.5 427.1 601.6 414 623.8C386.6 670 377.1 680.1 363 677.8ZM373.8 636.7C376.1 632.9 382.1 622.9 387.1 614.4C408.9 577.2 413.5 569.4 414.6 567.2L415.7 564.9L411.3 557.5C374 495.9 359.9 473.9 357.6 473.9C355.5 473.9 355.1 527.7 357.1 556.7C359.2 587.2 364.9 630.4 368.5 642.5C369 644.1 369.4 643.7 373.8 636.7ZM658.1 639.2C666.8 598 672.3 509 668.1 476.6C667.7 473.1 667.4 473.2 663.8 478C657.6 486.3 651.5 495.7 631.2 529C626.9 536.1 622.1 543.9 620.5 546.5C618.9 549.1 615.7 554.3 613.4 558.1L609.1 565L610.6 567.5C611.4 568.9 616.6 577.6 622.1 586.9C627.5 596.2 634.1 607.5 636.7 611.9C649.4 633.6 655.7 643.4 656.8 643.4C657 643.4 657.6 641.5 658.1 639.2Z\"\n }\n];\n/** The small-size variant's SVG body (use at 32px and below). */\nexport const MARK_SIMPLE_BODY = \"<path fill=\\\"#000000\\\" d=\\\"M495.8 884.4C291.9 874.2 135.4 724 114.7 518.5C97.9 351.3 160.2 221 290.9 150.2C372.3 106.1 439.7 86.4 513.6 85.2C686 82.3 812.9 171.5 867 333.5C903.9 444 890.2 573.8 828.6 698.6C766.8 823.4 644.3 891.8 495.8 884.4Z\\\"/>\\n<circle cx=\\\"340\\\" cy=\\\"300\\\" r=\\\"44\\\" fill=\\\"#FB5D08\\\"/>\\n<circle cx=\\\"500\\\" cy=\\\"276\\\" r=\\\"44\\\" fill=\\\"#FB5D08\\\"/>\\n<circle cx=\\\"660\\\" cy=\\\"300\\\" r=\\\"44\\\" fill=\\\"#FB5D08\\\"/>\\n<path fill=\\\"none\\\" stroke=\\\"#FFFFFF\\\" stroke-width=\\\"58\\\" stroke-linecap=\\\"round\\\" stroke-linejoin=\\\"round\\\"\\n d=\\\"M318 420v280l182-250 182 250V420M500 450 410 700M500 450l90 250\\\"/>\";\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { MARK_PATHS, MARK_SIMPLE_BODY, MARK_VIEWBOX } from \"./mark-paths\";\n\nexport interface KarniMarkProps extends Omit<React.SVGAttributes<SVGSVGElement>, \"children\"> {\n /** Rendered size in px (width and height). Default 28. */\n size?: number;\n /**\n * Which drawing: the full mark, the small-size variant, or `auto` (the\n * default) — the small variant at 32px and below, the full mark above.\n */\n variant?: \"auto\" | \"full\" | \"simple\";\n /** Accessible name; pass an empty string to hide a purely decorative mark. */\n title?: string;\n}\n\n/**\n * The Karni mark, inline SVG — no asset to load or bundle.\n *\n * It is the default content of `<Layout>`'s `sidebarHeader` slot so a bare\n * shell is never nameless; a project replaces it by passing its own\n * `sidebarHeader` (the scaffold already does). Do not recolour or restyle it:\n * the mark is Karni's, see assets/brand/README.md in the repository.\n */\nexport const KarniMark = React.forwardRef<SVGSVGElement, KarniMarkProps>(\n ({ size = 28, variant = \"auto\", title = \"Karni\", className, ...props }, ref) => {\n const simple = variant === \"simple\" || (variant === \"auto\" && size <= 32);\n const labelled = title !== \"\";\n return (\n <svg\n ref={ref}\n viewBox={MARK_VIEWBOX}\n width={size}\n height={size}\n role={labelled ? \"img\" : undefined}\n aria-hidden={labelled ? undefined : true}\n aria-label={labelled ? title : undefined}\n className={cn(\"shrink-0\", className)}\n {...props}\n {...(simple ? { dangerouslySetInnerHTML: { __html: MARK_SIMPLE_BODY } } : {})}\n >\n {simple\n ? null\n : MARK_PATHS.map((path) => (\n <path key={path.fill + path.d.length} fill={path.fill} d={path.d} />\n ))}\n </svg>\n );\n },\n);\nKarniMark.displayName = \"KarniMark\";\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\nimport { KarniMark } from \"../brand/karni-mark\";\n\nregisterComponentRole(\"layout-shell\", \"Layout\");\n\ntype IconProps = React.SVGAttributes<SVGSVGElement>;\n\nfunction MenuIcon(props: IconProps): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"4\" y1=\"6\" x2=\"20\" y2=\"6\" />\n <line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\" />\n <line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\" />\n </svg>\n );\n}\n\nfunction CloseIcon(props: IconProps): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\nexport interface LayoutNavItem {\n /** Visible label of the nav entry. */\n label: React.ReactNode;\n /** Target URL (rendered as a plain <a> by default). */\n href: string;\n /** Optional icon rendered before the label. */\n icon?: React.ReactNode;\n /** Marks the current page (aria-current=\"page\" + active styling). */\n active?: boolean;\n /** React key override when `href` is not unique. */\n key?: string;\n}\n\nexport interface LayoutProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Items of the derived sidebar nav. */\n navItems?: readonly LayoutNavItem[];\n /**\n * Escape hatch for router integration: wraps/replaces the default anchor of\n * one item. `defaultNode` is the styled <a> the layout would render — return\n * it, or your own node (e.g. a TanStack Router <Link> with\n * `className={defaultClassName}`).\n */\n renderNavItem?: (\n item: LayoutNavItem,\n defaults: { defaultNode: React.ReactNode; defaultClassName: string },\n ) => React.ReactNode;\n /** Escape hatch: replaces the entire derived nav inside the sidebar. */\n sidebar?: React.ReactNode;\n /**\n * Brand/logo slot pinned to the top of the sidebar. Defaults to the Karni\n * mark (`<KarniMark />`); pass your own brand, or `null` for no header.\n */\n sidebarHeader?: React.ReactNode;\n /** Slot pinned to the bottom of the sidebar (user menu, logout, …). */\n sidebarFooter?: React.ReactNode;\n /** Header slot, rendered in the top bar next to the mobile menu button. */\n header?: React.ReactNode;\n /** Accessible name of the sidebar navigation (default \"Main\"). */\n navLabel?: string;\n sidebarClassName?: string;\n headerClassName?: string;\n contentClassName?: string;\n children?: React.ReactNode;\n}\n\nconst NAV_ITEM_CLASS =\n \"flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground [&_svg]:h-4 [&_svg]:w-4\";\nconst NAV_ITEM_ACTIVE_CLASS = \"bg-accent text-accent-foreground\";\n\nconst SIDEBAR_ID = \"karni-layout-sidebar\";\n\n/**\n * App shell: sidebar navigation + header slot + content area.\n *\n * Responsive: under the `md` breakpoint the sidebar collapses behind a menu\n * button and opens as an overlay drawer (Escape or backdrop click closes it).\n *\n * Escape hatches: `renderNavItem` wraps each derived link (router\n * integration), `sidebar` replaces the derived nav wholesale, and\n * `sidebarHeader`/`sidebarFooter`/`header` are free slots.\n */\nexport const Layout = React.forwardRef<HTMLDivElement, LayoutProps>(\n (\n {\n navItems = [],\n renderNavItem,\n sidebar,\n sidebarHeader = <KarniMark className=\"mx-3\" />,\n sidebarFooter,\n header,\n navLabel = \"Main\",\n sidebarClassName,\n headerClassName,\n contentClassName,\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const [mobileOpen, setMobileOpen] = React.useState(false);\n\n const closeMobile = React.useCallback(() => {\n setMobileOpen(false);\n }, []);\n\n React.useEffect(() => {\n if (!mobileOpen) {\n return;\n }\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n setMobileOpen(false);\n }\n };\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [mobileOpen]);\n\n const navContent = sidebar ?? (\n <nav aria-label={navLabel} className=\"grid gap-1\">\n {navItems.map((item) => {\n const defaultClassName = cn(\n NAV_ITEM_CLASS,\n item.active === true && NAV_ITEM_ACTIVE_CLASS,\n );\n const defaultNode = (\n <a\n href={item.href}\n aria-current={item.active === true ? \"page\" : undefined}\n className={defaultClassName}\n onClick={closeMobile}\n >\n {item.icon != null && <span aria-hidden=\"true\">{item.icon}</span>}\n {item.label}\n </a>\n );\n return (\n <React.Fragment key={item.key ?? item.href}>\n {renderNavItem ? renderNavItem(item, { defaultNode, defaultClassName }) : defaultNode}\n </React.Fragment>\n );\n })}\n </nav>\n );\n\n const sidebarInner = (\n <>\n {sidebarHeader != null && <div className=\"mb-4\">{sidebarHeader}</div>}\n <div className=\"flex-1 overflow-y-auto\">{navContent}</div>\n {sidebarFooter != null && <div className=\"mt-4\">{sidebarFooter}</div>}\n </>\n );\n\n return (\n <div\n ref={ref}\n className={cn(\"flex min-h-screen w-full bg-background text-foreground\", className)}\n {...props}\n >\n {/* Static sidebar (md and up). */}\n <aside\n className={cn(\n \"hidden w-64 shrink-0 flex-col border-r border-border bg-card p-4 md:flex\",\n sidebarClassName,\n )}\n >\n {sidebarInner}\n </aside>\n\n {/* Overlay drawer (below md). */}\n {mobileOpen && (\n <div className=\"fixed inset-0 z-40 md:hidden\">\n <div\n data-testid=\"karni-layout-backdrop\"\n aria-hidden=\"true\"\n className=\"absolute inset-0 bg-foreground/40\"\n onClick={closeMobile}\n />\n <aside\n id={SIDEBAR_ID}\n className={cn(\n \"absolute inset-y-0 left-0 flex w-64 flex-col border-r border-border bg-card p-4 shadow-lg\",\n sidebarClassName,\n )}\n >\n <div className=\"mb-2 flex justify-end\">\n <button\n type=\"button\"\n onClick={closeMobile}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <CloseIcon className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close navigation</span>\n </button>\n </div>\n {sidebarInner}\n </aside>\n </div>\n )}\n\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <header\n className={cn(\n \"flex h-14 shrink-0 items-center gap-3 border-b border-border px-4\",\n headerClassName,\n )}\n >\n <button\n type=\"button\"\n aria-expanded={mobileOpen}\n aria-controls={SIDEBAR_ID}\n onClick={() => {\n setMobileOpen((open) => !open);\n }}\n className=\"inline-flex h-9 w-9 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring md:hidden\"\n >\n <MenuIcon className=\"h-5 w-5\" />\n <span className=\"sr-only\">Open navigation</span>\n </button>\n {header != null && (\n <div className=\"flex min-w-0 flex-1 items-center gap-3\">{header}</div>\n )}\n </header>\n <main className={cn(\"flex-1 p-6\", contentClassName)}>{children}</main>\n </div>\n </div>\n );\n },\n);\nLayout.displayName = \"Layout\";\n","import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\n\nregisterComponentRole(\"modal\", \"Modal\");\n\ntype IconProps = React.SVGAttributes<SVGSVGElement>;\n\nfunction CloseIcon(props: IconProps): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Escape hatch for footer buttons: any element wrapped in <ModalClose asChild>\n * closes the modal on click (re-exported Radix Dialog.Close).\n */\nexport const ModalClose = DialogPrimitive.Close;\n\nexport interface ModalProps {\n /** Dialog title — always rendered (Radix requires it for accessibility). */\n title: React.ReactNode;\n /** Optional description under the title, linked via aria-describedby. */\n description?: React.ReactNode;\n /** Body content. */\n children?: React.ReactNode;\n /** Footer slot (actions row). Use <ModalClose asChild> for cancel buttons. */\n footer?: React.ReactNode;\n /**\n * Uncontrolled usage: a node (usually a Button) that opens the modal,\n * rendered through Radix `asChild`.\n */\n trigger?: React.ReactNode;\n /** Controlled open state (pair with onOpenChange). */\n open?: boolean;\n /** Initial state for uncontrolled usage. */\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Hides the top-right X button. */\n hideCloseButton?: boolean;\n /** Extra classes for the content panel. */\n className?: string;\n /**\n * Escape hatch: props spread onto Radix Dialog.Content\n * (onEscapeKeyDown, onInteractOutside, …).\n */\n contentProps?: Omit<\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,\n \"children\" | \"className\"\n >;\n}\n\n/**\n * Themed Radix Dialog. Works controlled (`open` + `onOpenChange`) or\n * uncontrolled via the `trigger` slot; `footer` is the actions row.\n *\n * Escape hatches: `contentProps` reaches the Radix content part, `className`\n * restyles the panel, `hideCloseButton` drops the X, and `ModalClose` lets any\n * footer element close the dialog.\n */\nexport function Modal({\n title,\n description,\n children,\n footer,\n trigger,\n open,\n defaultOpen,\n onOpenChange,\n hideCloseButton = false,\n className,\n contentProps,\n}: ModalProps): React.ReactElement {\n // Without a Description part, Radix warns unless aria-describedby is\n // explicitly cleared; with one (or a consumer-supplied id) leave the key\n // alone so the automatic wiring stands.\n const clearDescribedBy =\n description == null && contentProps?.[\"aria-describedby\"] === undefined\n ? { \"aria-describedby\": undefined }\n : {};\n return (\n <DialogPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\n {trigger != null && <DialogPrimitive.Trigger asChild>{trigger}</DialogPrimitive.Trigger>}\n <DialogPrimitive.Portal>\n <DialogPrimitive.Overlay className=\"fixed inset-0 z-50 bg-foreground/40\" />\n <DialogPrimitive.Content\n {...contentProps}\n {...clearDescribedBy}\n className={cn(\n \"fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg border border-border bg-background p-6 text-foreground shadow-lg\",\n className,\n )}\n >\n <div className=\"grid gap-1.5\">\n <DialogPrimitive.Title className=\"text-lg font-semibold leading-none tracking-tight\">\n {title}\n </DialogPrimitive.Title>\n {description != null && (\n <DialogPrimitive.Description className=\"text-sm text-muted-foreground\">\n {description}\n </DialogPrimitive.Description>\n )}\n </div>\n {children}\n {footer != null && (\n <div className=\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\">{footer}</div>\n )}\n {!hideCloseButton && (\n <DialogPrimitive.Close className=\"absolute right-4 top-4 rounded-sm text-muted-foreground opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none\">\n <CloseIcon className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n );\n}\n","import type * as React from \"react\";\n\n/**\n * Module-level toast store.\n *\n * `useToast()` can be called anywhere (no provider requirement beyond a\n * mounted <Toaster/>): toasts are pushed into this store and every mounted\n * Toaster/useToast subscriber re-renders via useSyncExternalStore.\n */\n\nexport type ToastVariant = \"default\" | \"success\" | \"error\" | \"info\";\n\nexport interface ToastOptions {\n /** Stable id (defaults to an auto-generated one). Re-using an id replaces. */\n id?: string;\n title?: React.ReactNode;\n description?: React.ReactNode;\n variant?: ToastVariant;\n /** Per-toast auto-dismiss override in ms (Toaster default otherwise). */\n duration?: number;\n /** Action slot (e.g. an \"Undo\" button), rendered inside the toast. */\n action?: React.ReactNode;\n}\n\nexport interface ToastInstance extends ToastOptions {\n id: string;\n variant: ToastVariant;\n}\n\nexport interface ToastHandle {\n id: string;\n dismiss: () => void;\n}\n\n/** Oldest toasts beyond this count are dropped. */\nconst TOAST_LIMIT = 5;\n\ntype Listener = () => void;\n\nlet toasts: readonly ToastInstance[] = [];\nconst listeners = new Set<Listener>();\nlet counter = 0;\n\nfunction emit(): void {\n for (const listener of listeners) {\n listener();\n }\n}\n\nexport function subscribeToToasts(listener: Listener): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\nexport function getToasts(): readonly ToastInstance[] {\n return toasts;\n}\n\nexport function dismissToast(id?: string): void {\n const next = id === undefined ? [] : toasts.filter((item) => item.id !== id);\n if (next.length !== toasts.length) {\n toasts = next;\n emit();\n }\n}\n\nexport function addToast(options: ToastOptions): ToastHandle {\n counter += 1;\n const id = options.id ?? `karni-toast-${String(counter)}`;\n const instance: ToastInstance = {\n ...options,\n id,\n variant: options.variant ?? \"default\",\n };\n toasts = [...toasts.filter((item) => item.id !== id), instance].slice(-TOAST_LIMIT);\n emit();\n return {\n id,\n dismiss: () => {\n dismissToast(id);\n },\n };\n}\n\n/** Test helper — clears all toasts and listeners' state (not in the barrel). */\nexport function resetToastStore(): void {\n toasts = [];\n counter = 0;\n emit();\n}\n","import * as React from \"react\";\nimport {\n addToast,\n dismissToast,\n getToasts,\n subscribeToToasts,\n type ToastHandle,\n type ToastInstance,\n type ToastOptions,\n} from \"./toast-store\";\n\nexport interface UseToastResult {\n /** Currently visible toasts (rendered by <Toaster/>). */\n toasts: readonly ToastInstance[];\n /** Full-control entry point: show any ToastOptions. */\n toast: (options: ToastOptions) => ToastHandle;\n /** Shorthand: success variant. */\n success: (title: React.ReactNode, options?: Omit<ToastOptions, \"variant\">) => ToastHandle;\n /** Shorthand: error variant. */\n error: (title: React.ReactNode, options?: Omit<ToastOptions, \"variant\">) => ToastHandle;\n /** Shorthand: info variant. */\n info: (title: React.ReactNode, options?: Omit<ToastOptions, \"variant\">) => ToastHandle;\n /** Dismiss one toast by id, or all when called without arguments. */\n dismiss: (id?: string) => void;\n}\n\nfunction makeShorthand(\n variant: \"success\" | \"error\" | \"info\",\n): (title: React.ReactNode, options?: Omit<ToastOptions, \"variant\">) => ToastHandle {\n return (title, options) => addToast({ ...options, title, variant });\n}\n\nconst stableApi = {\n toast: addToast,\n success: makeShorthand(\"success\"),\n error: makeShorthand(\"error\"),\n info: makeShorthand(\"info\"),\n dismiss: dismissToast,\n} as const;\n\n/**\n * Imperative toast API + the live toast list.\n *\n * Requires a mounted <Toaster/> somewhere in the tree to actually render the\n * toasts; the functions themselves are stable module-level references, safe\n * to use in effects and callbacks without dependency churn.\n */\nexport function useToast(): UseToastResult {\n const toasts = React.useSyncExternalStore(subscribeToToasts, getToasts, getToasts);\n return React.useMemo(() => ({ toasts, ...stableApi }), [toasts]);\n}\n","import * as ToastPrimitive from \"@radix-ui/react-toast\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { variants, type VariantProps } from \"../../lib/variants\";\nimport { dismissToast, type ToastVariant } from \"./toast-store\";\nimport { useToast } from \"./use-toast\";\nimport { registerComponentRole } from \"../../lib/roles\";\n\nregisterComponentRole(\"toast\", \"Toaster\");\n\ntype IconProps = React.SVGAttributes<SVGSVGElement>;\n\nfunction CloseIcon(props: IconProps): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Per-variant toast styling — colors resolve through --karni-* tokens only\n * (success leans on primary, error on destructive, info on muted).\n */\nexport const toastVariants = variants({\n base: \"pointer-events-auto relative flex w-full items-start gap-3 overflow-hidden rounded-md border p-4 pr-8 shadow-lg\",\n variants: {\n variant: {\n default: \"border-border bg-background text-foreground\",\n success: \"border-primary bg-background text-foreground\",\n error: \"border-destructive bg-destructive text-destructive-foreground\",\n info: \"border-border bg-muted text-foreground\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n});\n\nexport type ToastVariantProps = VariantProps<typeof toastVariants>;\n\nexport interface ToasterProps {\n /** Auto-dismiss duration in ms for toasts without their own (default 5000). */\n duration?: number;\n /** Swipe-to-dismiss direction (default \"right\"). */\n swipeDirection?: \"right\" | \"left\" | \"up\" | \"down\";\n /** Accessible label prefix announced with each toast (Radix Provider). */\n label?: string;\n /** Extra classes for the viewport (position/stacking escape hatch). */\n viewportClassName?: string;\n /** Extra classes for every toast root. */\n toastClassName?: string;\n}\n\n/**\n * Renders the toasts pushed through useToast(). Mount exactly one near the\n * app root. Position defaults to the bottom-right corner; override with\n * `viewportClassName` (it merges via cn(), so e.g. \"top-0 bottom-auto\" wins).\n */\nexport function Toaster({\n duration = 5000,\n swipeDirection = \"right\",\n label = \"Notification\",\n viewportClassName,\n toastClassName,\n}: ToasterProps): React.ReactElement {\n const { toasts } = useToast();\n\n return (\n <ToastPrimitive.Provider duration={duration} swipeDirection={swipeDirection} label={label}>\n {toasts.map((item) => (\n <ToastPrimitive.Root\n key={item.id}\n duration={item.duration}\n data-variant={item.variant satisfies ToastVariant}\n onOpenChange={(open) => {\n if (!open) {\n dismissToast(item.id);\n }\n }}\n className={toastVariants({ variant: item.variant, className: toastClassName })}\n >\n <div className=\"grid flex-1 gap-1\">\n {item.title != null && (\n <ToastPrimitive.Title className=\"text-sm font-semibold\">\n {item.title}\n </ToastPrimitive.Title>\n )}\n {item.description != null && (\n <ToastPrimitive.Description className=\"text-sm opacity-90\">\n {item.description}\n </ToastPrimitive.Description>\n )}\n </div>\n {item.action != null && <div className=\"flex shrink-0 items-center\">{item.action}</div>}\n <ToastPrimitive.Close\n aria-label=\"Dismiss\"\n className=\"absolute right-2 top-2 rounded-md p-1 opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <CloseIcon className=\"h-4 w-4\" />\n </ToastPrimitive.Close>\n </ToastPrimitive.Root>\n ))}\n <ToastPrimitive.Viewport\n className={cn(\n \"fixed bottom-0 right-0 z-[100] flex w-full max-w-sm flex-col gap-2 p-4 outline-none\",\n viewportClassName,\n )}\n />\n </ToastPrimitive.Provider>\n );\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\n\nregisterComponentRole(\"stat\", \"Stat\");\n\ntype ArrowProps = React.SVGAttributes<SVGSVGElement>;\n\nfunction ArrowUpIcon(props: ArrowProps): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"5\" />\n <polyline points=\"5 12 12 5 19 12\" />\n </svg>\n );\n}\n\nfunction ArrowDownIcon(props: ArrowProps): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <polyline points=\"19 12 12 19 5 12\" />\n </svg>\n );\n}\n\nexport interface StatProps extends React.HTMLAttributes<HTMLDivElement> {\n /** What the number measures (\"Active users\"). */\n label: React.ReactNode;\n /** The headline value — preformatted string or any node. */\n value: React.ReactNode;\n /**\n * Change indicator. A number renders a signed figure with an up/down arrow\n * (negative numbers use the destructive token) plus screen-reader context;\n * any other node renders verbatim in the delta slot.\n */\n delta?: number | React.ReactNode;\n /** Formats a numeric `delta` (default: signed, locale formatted). */\n formatDelta?: (delta: number) => string;\n /** Optional icon slot, top-right. */\n icon?: React.ReactNode;\n}\n\nfunction defaultFormatDelta(delta: number): string {\n const formatted = Math.abs(delta).toLocaleString();\n return delta >= 0 ? `+${formatted}` : `-${formatted}`;\n}\n\n/**\n * KPI tile: label, value, optional delta and icon.\n *\n * Escape hatches: `value`/`delta`/`icon` accept arbitrary nodes,\n * `formatDelta` overrides numeric formatting, `className` merges via cn().\n */\nexport const Stat = React.forwardRef<HTMLDivElement, StatProps>(\n ({ label, value, delta, formatDelta = defaultFormatDelta, icon, className, ...props }, ref) => {\n let deltaNode: React.ReactNode = null;\n if (typeof delta === \"number\" && Number.isFinite(delta)) {\n const down = delta < 0;\n deltaNode = (\n <p\n className={cn(\n \"flex items-center gap-1 text-sm font-medium\",\n down ? \"text-destructive\" : \"text-muted-foreground\",\n )}\n >\n {down ? (\n <ArrowDownIcon className=\"h-3.5 w-3.5\" />\n ) : (\n <ArrowUpIcon className=\"h-3.5 w-3.5\" />\n )}\n <span className=\"sr-only\">{down ? \"Decreased by\" : \"Increased by\"} </span>\n {formatDelta(delta)}\n </p>\n );\n } else if (delta != null) {\n deltaNode = <div className=\"text-sm text-muted-foreground\">{delta}</div>;\n }\n\n return (\n <div\n ref={ref}\n className={cn(\n \"flex flex-col gap-1 rounded-lg border border-border bg-card p-4 text-card-foreground\",\n className,\n )}\n {...props}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <p className=\"text-sm font-medium text-muted-foreground\">{label}</p>\n {icon != null && (\n <span aria-hidden=\"true\" className=\"text-muted-foreground [&>svg]:h-4 [&>svg]:w-4\">\n {icon}\n </span>\n )}\n </div>\n <p className=\"text-2xl font-semibold tracking-tight\">{value}</p>\n {deltaNode}\n </div>\n );\n },\n);\nStat.displayName = \"Stat\";\n","import * as VisuallyHidden from \"@radix-ui/react-visually-hidden\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\n\nregisterComponentRole(\"chart\", \"DataChart\");\n\n/**\n * In-house SVG chart (contract: no chart dependency).\n *\n * Accessibility model (contract D10): the SVG is a labelled image\n * (role=\"img\" + aria-label + <title>/<desc>); the REAL accessible data\n * surface is a visually-hidden <table> rendered next to it. The hover\n * tooltip is a visual-only affordance rendered OUTSIDE the role=\"img\"\n * element and hidden from assistive tech.\n *\n * Colors come exclusively from the --karni-chart-1..5 tokens, via the\n * Tailwind preset's chart color scale (stroke-chart-N / fill-chart-N /\n * bg-chart-N classes — whole class names, per contract D7).\n */\n\nexport type DataChartKind = \"line\" | \"bar\";\n\nexport interface DataChartPoint {\n label: string;\n value: number;\n}\n\nexport interface DataChartSeries {\n name: string;\n data: readonly DataChartPoint[];\n}\n\nexport interface DataChartTooltipContext {\n /** Category (x-axis) label under the pointer. */\n label: string;\n /** One entry per series that has a value at this category. */\n points: ReadonlyArray<{ seriesName: string; value: number; swatchClassName: string }>;\n}\n\nexport interface DataChartProps {\n kind: DataChartKind;\n /** Single-series shorthand (ignored when `series` is given). */\n data?: readonly DataChartPoint[];\n /** Multi-series data; series cycle through --karni-chart-1..5. */\n series?: readonly DataChartSeries[];\n /** Chart title: SVG <title>, aria-label and the hidden table's caption. */\n title: string;\n /** Longer description for the SVG <desc>. */\n description?: string;\n /** Formats values in the tooltip, y-axis ticks and the hidden table. */\n valueFormatter?: (value: number) => string;\n /** Formats x-axis tick labels (default: the category label itself). */\n xTickFormatter?: (label: string) => string;\n /** Escape hatch: fully custom tooltip content. */\n renderTooltip?: (context: DataChartTooltipContext) => React.ReactNode;\n /** viewBox width (default 640) — rendered size is responsive. */\n width?: number;\n /** viewBox height (default 240). */\n height?: number;\n /** Approximate number of y-axis ticks (default 4). */\n yTickCount?: number;\n /** Show the series legend (default: only for 2+ series). */\n showLegend?: boolean;\n /** Show the hover tooltip (default true). */\n showTooltip?: boolean;\n /** Column header of the hidden table's category column (default \"Label\"). */\n categoryHeader?: string;\n /** Text shown when there is no plottable data. */\n emptyLabel?: string;\n className?: string;\n}\n\nconst SERIES_STROKE = [\n \"stroke-chart-1\",\n \"stroke-chart-2\",\n \"stroke-chart-3\",\n \"stroke-chart-4\",\n \"stroke-chart-5\",\n] as const;\n\nconst SERIES_FILL = [\n \"fill-chart-1\",\n \"fill-chart-2\",\n \"fill-chart-3\",\n \"fill-chart-4\",\n \"fill-chart-5\",\n] as const;\n\nconst SERIES_SWATCH = [\n \"bg-chart-1\",\n \"bg-chart-2\",\n \"bg-chart-3\",\n \"bg-chart-4\",\n \"bg-chart-5\",\n] as const;\n\nfunction seriesClass(classes: readonly string[], index: number): string {\n const value = classes[index % classes.length];\n // The modulo keeps the index in range; the fallback only satisfies strict\n // indexing and never triggers at runtime.\n return value ?? classes[0] ?? \"\";\n}\n\nconst MARGIN = { top: 8, right: 12, bottom: 28, left: 48 } as const;\n\nfunction niceNum(range: number, round: boolean): number {\n const exponent = Math.floor(Math.log10(range));\n const fraction = range / 10 ** exponent;\n let niceFraction: number;\n if (round) {\n niceFraction = fraction < 1.5 ? 1 : fraction < 3 ? 2 : fraction < 7 ? 5 : 10;\n } else {\n niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10;\n }\n return niceFraction * 10 ** exponent;\n}\n\nfunction niceTicks(min: number, max: number, count: number): number[] {\n const span = max > min ? max - min : 1;\n const step = niceNum(niceNum(span, false) / Math.max(1, count), true);\n const start = Math.floor(min / step) * step;\n const end = Math.ceil(max / step) * step;\n const ticks: number[] = [];\n for (let value = start; value <= end + step / 2; value += step) {\n // Trim float noise (0.30000000000000004 → 0.3).\n ticks.push(Number(value.toFixed(10)));\n }\n return ticks;\n}\n\ninterface NormalizedChart {\n categories: readonly string[];\n seriesNames: readonly string[];\n /** matrix[seriesIndex][categoryIndex] — null when missing/non-finite. */\n matrix: ReadonlyArray<ReadonlyArray<number | null>>;\n}\n\nfunction normalize(\n data: readonly DataChartPoint[] | undefined,\n series: readonly DataChartSeries[] | undefined,\n): NormalizedChart {\n const resolved: readonly DataChartSeries[] =\n series ?? (data !== undefined ? [{ name: \"Value\", data }] : []);\n\n const categories: string[] = [];\n const seen = new Set<string>();\n for (const s of resolved) {\n for (const point of s.data) {\n if (!seen.has(point.label)) {\n seen.add(point.label);\n categories.push(point.label);\n }\n }\n }\n\n const matrix = resolved.map((s) => {\n const byLabel = new Map<string, number>();\n for (const point of s.data) {\n if (Number.isFinite(point.value)) {\n byLabel.set(point.label, point.value);\n }\n }\n return categories.map((label) => byLabel.get(label) ?? null);\n });\n\n return { categories, seriesNames: resolved.map((s) => s.name), matrix };\n}\n\nfunction defaultValueFormatter(value: number): string {\n return value.toLocaleString();\n}\n\n/**\n * Minimal line/bar chart driven by `{label, value}` points or named series.\n *\n * Escape hatches: `valueFormatter`/`xTickFormatter`, `renderTooltip`,\n * `width`/`height`/`yTickCount`, legend and tooltip toggles, `className`\n * (merged via cn()). Colors are only themeable through the\n * --karni-chart-1..5 CSS variables.\n */\nexport function DataChart({\n kind,\n data,\n series,\n title,\n description,\n valueFormatter = defaultValueFormatter,\n xTickFormatter,\n renderTooltip,\n width = 640,\n height = 240,\n yTickCount = 4,\n showLegend,\n showTooltip = true,\n categoryHeader = \"Label\",\n emptyLabel = \"No data\",\n className,\n}: DataChartProps): React.ReactElement {\n const titleId = React.useId();\n const descId = React.useId();\n const [hovered, setHovered] = React.useState<number | null>(null);\n\n const { categories, seriesNames, matrix } = React.useMemo(\n () => normalize(data, series),\n [data, series],\n );\n\n const values = matrix.flat().filter((value): value is number => value !== null);\n if (categories.length === 0 || values.length === 0) {\n return (\n <div\n className={cn(\n \"flex w-full items-center justify-center rounded-lg border border-dashed border-border px-6 py-10 text-sm text-muted-foreground\",\n className,\n )}\n >\n {emptyLabel}\n </div>\n );\n }\n\n // scales\n const rawMin = Math.min(0, ...values);\n const rawMax = Math.max(0, ...values);\n const ticks = niceTicks(rawMin, rawMax, yTickCount);\n const domainMin = ticks[0] ?? rawMin;\n const domainMax = ticks[ticks.length - 1] ?? rawMax;\n const domainSpan = domainMax - domainMin || 1;\n\n const plotWidth = width - MARGIN.left - MARGIN.right;\n const plotHeight = height - MARGIN.top - MARGIN.bottom;\n const yScale = (value: number): number =>\n MARGIN.top + ((domainMax - value) / domainSpan) * plotHeight;\n const bandWidth = plotWidth / categories.length;\n const bandCenter = (index: number): number => MARGIN.left + (index + 0.5) * bandWidth;\n const zeroY = yScale(Math.max(domainMin, Math.min(domainMax, 0)));\n\n // marks\n const seriesCount = Math.max(1, matrix.length);\n const groupWidth = bandWidth * 0.7;\n const barWidth = groupWidth / seriesCount;\n\n const marks = matrix.map((row, seriesIndex) => {\n if (kind === \"bar\") {\n return (\n <g key={seriesIndex} className={seriesClass(SERIES_FILL, seriesIndex)}>\n {row.map((value, categoryIndex) => {\n if (value === null) {\n return null;\n }\n const x = bandCenter(categoryIndex) - groupWidth / 2 + seriesIndex * barWidth;\n const y = Math.min(yScale(value), zeroY);\n const barHeight = Math.abs(yScale(value) - zeroY);\n return (\n <rect\n key={categoryIndex}\n x={x}\n y={y}\n width={Math.max(1, barWidth - 2)}\n height={barHeight}\n rx={2}\n />\n );\n })}\n </g>\n );\n }\n\n const points = row\n .map((value, categoryIndex) =>\n value === null ? null : ([bandCenter(categoryIndex), yScale(value)] as const),\n )\n .filter((point): point is readonly [number, number] => point !== null);\n\n return (\n <g key={seriesIndex}>\n <polyline\n className={seriesClass(SERIES_STROKE, seriesIndex)}\n fill=\"none\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n points={points.map(([x, y]) => `${String(x)},${String(y)}`).join(\" \")}\n />\n {points.map(([x, y], pointIndex) => (\n <circle\n key={pointIndex}\n className={seriesClass(SERIES_FILL, seriesIndex)}\n cx={x}\n cy={y}\n r={3}\n />\n ))}\n </g>\n );\n });\n\n // tooltip geometry (percentages of the rendered box)\n const pct = (value: number, total: number): string => `${String((value / total) * 100)}%`;\n const hoveredPoints =\n hovered === null\n ? []\n : matrix\n .map((row, seriesIndex) => ({\n seriesName: seriesNames[seriesIndex] ?? \"\",\n value: row[hovered] ?? null,\n swatchClassName: seriesClass(SERIES_SWATCH, seriesIndex),\n }))\n .filter(\n (entry): entry is { seriesName: string; value: number; swatchClassName: string } =>\n entry.value !== null,\n );\n const hoveredLabel = hovered === null ? undefined : categories[hovered];\n\n const defaultLegend = seriesNames.length > 1;\n\n return (\n <div className={cn(\"w-full\", className)}>\n <div className=\"relative w-full\">\n <svg\n role=\"img\"\n aria-label={title}\n aria-labelledby={titleId}\n aria-describedby={description !== undefined ? descId : undefined}\n viewBox={`0 0 ${String(width)} ${String(height)}`}\n className=\"block h-auto w-full text-muted-foreground\"\n >\n <title id={titleId}>{title}</title>\n {description !== undefined && <desc id={descId}>{description}</desc>}\n\n {/* y grid + tick labels */}\n {ticks.map((tick) => (\n <g key={tick}>\n <line\n x1={MARGIN.left}\n x2={width - MARGIN.right}\n y1={yScale(tick)}\n y2={yScale(tick)}\n stroke=\"currentColor\"\n strokeOpacity={tick === 0 ? 0.6 : 0.2}\n />\n <text\n x={MARGIN.left - 6}\n y={yScale(tick)}\n textAnchor=\"end\"\n dominantBaseline=\"middle\"\n fontSize={10}\n fill=\"currentColor\"\n >\n {valueFormatter(tick)}\n </text>\n </g>\n ))}\n\n {/* x tick labels */}\n {categories.map((category, index) => (\n <text\n key={category}\n x={bandCenter(index)}\n y={height - MARGIN.bottom + 14}\n textAnchor=\"middle\"\n fontSize={10}\n fill=\"currentColor\"\n >\n {xTickFormatter ? xTickFormatter(category) : category}\n </text>\n ))}\n\n {marks}\n </svg>\n\n {/* Hover affordance + tooltip: visual only, OUTSIDE the role=\"img\"\n element and hidden from assistive tech (contract D10). */}\n {showTooltip && (\n <div aria-hidden=\"true\" className=\"absolute inset-0\">\n <div\n className=\"absolute flex\"\n style={{\n left: pct(MARGIN.left, width),\n width: pct(plotWidth, width),\n top: pct(MARGIN.top, height),\n height: pct(plotHeight, height),\n }}\n onMouseLeave={() => {\n setHovered(null);\n }}\n >\n {categories.map((category, index) => (\n <div\n key={category}\n data-karni-chart-hit={index}\n className=\"h-full flex-1\"\n onMouseEnter={() => {\n setHovered(index);\n }}\n />\n ))}\n </div>\n {hovered !== null && hoveredLabel !== undefined && hoveredPoints.length > 0 && (\n <div\n data-karni-chart-tooltip=\"\"\n className=\"pointer-events-none absolute z-10 min-w-24 -translate-x-1/2 rounded-md border border-border bg-popover px-2.5 py-1.5 text-xs text-popover-foreground shadow-md\"\n style={{\n left: pct(bandCenter(hovered), width),\n top: pct(MARGIN.top, height),\n }}\n >\n {renderTooltip ? (\n renderTooltip({ label: hoveredLabel, points: hoveredPoints })\n ) : (\n <>\n <p className=\"mb-1 font-medium\">{hoveredLabel}</p>\n {hoveredPoints.map((point) => (\n <p key={point.seriesName} className=\"flex items-center gap-1.5\">\n <span\n className={cn(\"h-2 w-2 shrink-0 rounded-full\", point.swatchClassName)}\n />\n <span className=\"text-muted-foreground\">{point.seriesName}</span>\n <span className=\"ml-auto font-medium\">{valueFormatter(point.value)}</span>\n </p>\n ))}\n </>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n\n {(showLegend ?? defaultLegend) && (\n <div aria-hidden=\"true\" className=\"mt-2 flex flex-wrap items-center gap-x-4 gap-y-1\">\n {seriesNames.map((name, index) => (\n <span key={name} className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <span className={cn(\"h-2 w-2 rounded-full\", seriesClass(SERIES_SWATCH, index))} />\n {name}\n </span>\n ))}\n </div>\n )}\n\n {/* The accessible data surface (contract D10). */}\n <VisuallyHidden.Root asChild>\n <div>\n <table>\n <caption>{title}</caption>\n <thead>\n <tr>\n <th scope=\"col\">{categoryHeader}</th>\n {seriesNames.map((name) => (\n <th key={name} scope=\"col\">\n {name}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {categories.map((category, categoryIndex) => (\n <tr key={category}>\n <th scope=\"row\">{category}</th>\n {matrix.map((row, seriesIndex) => {\n const value = row[categoryIndex] ?? null;\n return (\n <td key={seriesIndex}>{value === null ? \"—\" : valueFormatter(value)}</td>\n );\n })}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </VisuallyHidden.Root>\n </div>\n );\n}\n"],"names":["cn","inputs","twMerge","clsx","registry","defaultHotDetector","meta","_a","_b","detectHot","registerComponentRole","role","component","options","reason","previous","existing","message","getRoleRegistry","variants","config","groupNames","props","className","rest","selection","chosen","classes","group","value","groupClasses","compound","compoundClassName","conditions","key","expected","buttonVariants","Button","React","variant","size","type","ref","jsx","Input","Textarea","baseProps","CheckIcon","ChevronDownIcon","ChevronUpIcon","KARNI_SELECT_EMPTY","SelectRoot","SelectPrimitive","SelectGroup","SelectValue","SelectTrigger","children","jsxs","SelectScrollUpButton","SelectScrollDownButton","SelectContent","position","SelectLabel","SelectItem","SelectSeparator","Select","onValueChange","placeholder","clearable","clearLabel","disabled","name","id","contentClassName","ariaLabel","safeOptions","filtered","option","radixValue","handleValueChange","next","Checkbox","CheckboxPrimitive","Switch","SwitchPrimitive","Label","LabelPrimitive","Tabs","TabsPrimitive","TabsList","TabsTrigger","TabsContent","DropdownMenu","DropdownMenuPrimitive","DropdownMenuTrigger","DropdownMenuGroup","DropdownMenuPortal","DropdownMenuContent","sideOffset","DropdownMenuItem","inset","DropdownMenuCheckboxItem","checked","DropdownMenuLabel","DropdownMenuSeparator","Skeleton","stringifyScalar","isScalarArray","buildListQuery","params","query","buildItemQuery","normalizeParams","out","normalized","normalizeValue","item","listPath","resource","detailPath","karniKeys","KarniClientContext","createContext","KarniProvider","client","queryClient","ownQueryClient","useState","QueryClient","QueryClientProvider","useKarniClient","useContext","useResourceList","useQuery","signal","isFileValue","isBlobValue","containsFile","values","appendFormValue","form","toFormData","encodeBody","fileFieldNames","cachedSchema","names","resources","entry","fields","field","kind","isStringOrStringArray","omitUnchangedFileUrls","fileFields","useResourceMutations","useQueryClient","invalidateKeys","invalidate","useCallback","queryKey","create","useMutation","update","prepared","remove","isRecord","humanize","spaced","REF_PREFIX","lookupRef","doc","resolveSchema","schema","seen","target","resolved","siblings","inner","normalizeType","t","relationFromExtension","ext","relationValueTypeOf","combineEnumMembers","members","nullable","description","member","CHOICE_LINE","choiceLabels","labels","line","match","text","applyChoiceLabels","info","isAnySchema","analyzeProperty","raw","relation","typeNullable","composition","combined","items","mergeField","responseInfo","requestInfo","requiredSet","hasCreateRequest","order","title","enumValues","fallback","enumLabels","maxLength","min","max","format","valueType","operationDef","path","method","op","queryParams","expandEnum","param","def","listItemSchema","response","media","_c","body","results","_d","createRequestSchema","content","METHODS","parseOpenApi","input","paths","rawAuthMode","authMode","listOps","get","listOp","itemEntry","candidate","itemPath","itemItem","operations","createOp","exportItem","exportOp","importItem","importOp","responseSchema","requestSchema","responseProps","requestProps","prop","requestProp","parsed","SCHEMA_QUERY_KEY","useParsedSchema","useSchema","known","EmptyState","icon","action","AUDIT_FIELDS","isAuditField","partitionAuditFields","domain","audit","a","b","LABEL_KEYS","displayLabel","obj","BulkActionsBar","selectedIds","bulkActions","onClear","index","sortingToOrdering","sorting","isNotFoundError","error","pageCountFor","count","pageSize","asRecord","errorMessage","data","detail","enumLabel","DEFAULT_SKIPPED_KINDS","UNSORTABLE_KINDS","EmptyValue","BooleanCell","IdCode","relationItem","label","RelationCell","Fragment","dateText","withTime","FileCell","event","JsonCell","shown","renderFieldCell","getRowLabel","headerTemplate","columnForField","override","customCell","row","ctx","deriveColumns","args","pending","column","defs","importDescribeKey","importJobKey","jobId","importPath","suffix","IN_FLIGHT","isImportInFlight","job","filenameFrom","header","downloadResourceExport","blob","filename","saveBlob","url","anchor","downloadImportTemplate","useImportDescribe","useImportJob","pollMs","useImportActions","store","upload","file","mapping","preview","commit","describe","ExportButtons","formats","busy","setBusy","setError","run","failure","useResourceItem","useDebouncedValue","delayMs","debounced","setDebounced","timer","idOf","optionDomId","listboxId","XIcon","ResourceSelect","onChange","multiple","getOptionLabel","filter","searchDebounceMs","reactId","inputId","open","setOpen","inputText","setInputText","activeIndex","setActiveIndex","cache","setCache","rootRef","contentRef","inputRef","debouncedSearch","selected","listParams","listQuery","rows","changed","unresolvedId","sel","itemQuery","resolvedItem","resolveError","labelOf","textOf","openPopover","closePopover","isSelected","optionId","toggleOption","clearSelection","singleText","inputValue","handleInputChange","handleKeyDown","handleBlur","listContent","optionSelected","PopoverPrimitive","chipText","other","toSelectValue","toRelationValue","EnumFilter","onFilterChange","BooleanFilter","FilterBar","searchEnabled","searchValue","onSearchChange","searchPlaceholder","filterFields","PaginationControls","page","pageCount","totalCount","hasPrevious","hasNext","onPageChange","DEFAULT_PAGE_SIZE","SEARCH_DEBOUNCE_MS","MAX_DERIVED_FILTERS","selectionColumn","table","DeleteRowButton","mutations","actionsColumn","rowActions","onEdit","enableDelete","TableSkeleton","_","ErrorPanel","SchemaErrorPanel","ResourceTable","columns","showAuditFields","extraColumns","columnsOverride","onRowClick","expand","initialSorting","filters","exportFormats","toolbar","empty","footer","schemaResult","setSorting","rowSelection","setRowSelection","setPage","searchInput","setSearchInput","filterValues","setFilterValues","effectivePageSize","lastSearch","handleSortingChange","updater","old","handleFilterChange","expandList","allowed","pinned","byName","declared","trimmedSearch","list","keepPreviousData","failureCount","clamping","current","hasBulkSelect","hasActions","columnDefs","leading","trailing","useReactTable","getCoreRowModel","hasActiveNarrowing","canSort","direction","flexRender","cell","_e","_f","exportList","exportEnabled","showFilterRow","REQUIRED_MESSAGE","LOCAL_DATETIME","toIsoWithOffset","date","enumSchema","literals","stringSchema","requireNonEmpty","numberSchema","integer","relationValueSchema","coerce","singleRelationSchema","fileSchema","baseSchemaFor","zodFor","mode","shape","fieldSchema","matchesAccept","accept","tokens","token","formatFileSize","bytes","fileBasename","segments","segment","UploadIcon","FileUpload","maxSize","onReject","dragging","setDragging","entries","acceptFiles","accepted","handleDrop","handleDragOver","removeEntry","remaining","i","files","humanizeValue","pad","n","toDatetimeLocal","HAS_ZONE","offsetMinutes","sign","abs","offset","isDirtyEntry","pkOf","initialFieldValue","buildFormValues","defaultValues","source","val","OMIT","emptied","coerceFieldValue","numeric","prepareSubmit","dirtyFields","jsonErrors","rawValue","result","stringInputType","DefaultFieldControl","control","describedBy","invalid","inputProps","aria","Controller","rhf","EDITABLE_KINDS","FormSkeleton","FormErrorPanel","applyServerErrors","knownNames","methods","maybe","rootMessages","messages","FormFieldRow","Component","errorId","descriptionId","part","ResourceFormInner","onSuccess","onError","fieldOverrides","extraFields","transformSubmit","actions","formFields","initialValues","resolver","base","zodResolver","omittable","context","cleaned","useForm","formState","submitting","onSubmit","jsonError","payload","rootError","fieldError","FormProvider","ResourceForm","isEdit","formatDate","formatDateTime","RelationEntry","RelationValue","DefaultValue","DetailSkeleton","DetailError","onRetry","DetailRow","muted","ResourceDetail","sections","recordHeadingId","visibleFields","section","changeHistoryKey","useChangeHistory","ACTION_LABEL","formatWhen","Value","Entry","before","after","ChangeHistory","errorText","Stats","created","updated","skipped","unchanged","errors","Problems","problem","Progress","percent","MappingTable","ResourceImport","onDone","setJobId","setMapping","remap","setRemap","templateError","setTemplateError","fileRef","jobQuery","seededFor","mutationError","handleUpload","handlePreview","handleTemplate","defaultMessage","status","KarniApiError","__publicField","splitBaseUrl","baseUrl","joinUrl","origin","basePath","appendQuery","qs","parseBody","createKarniClient","schemaUrl","fetchOption","hooks","perform","requestOptions","headers","hookHeaders","init","requestRaw","readAuthMode","record","normalizeUser","email","roles","readCookie","trimmed","separator","describeShape","keys","read2fa","AuthEngine","listener","user","document","refreshToken","access","rotated","password","twoFactor","refresh","loginPath","createLocalStorageTokenStorage","createMemoryTokenStorage","AuthContext","AuthProvider","tokenStorage","csrfCookieName","csrfHeaderName","authBasePath","storage","useMemo","engine","useEffect","snapshot","useSyncExternalStore","identity","previousIdentity","useRef","useAuth","AuthGuard","loading","LoginForm","on2FA","submitLabel","login","submit","usePermission","Page","headerClassName","MARK_VIEWBOX","MARK_PATHS","MARK_SIMPLE_BODY","KarniMark","simple","labelled","MenuIcon","CloseIcon","NAV_ITEM_CLASS","NAV_ITEM_ACTIVE_CLASS","SIDEBAR_ID","Layout","navItems","renderNavItem","sidebar","sidebarHeader","sidebarFooter","navLabel","sidebarClassName","mobileOpen","setMobileOpen","closeMobile","onKeyDown","navContent","defaultClassName","defaultNode","sidebarInner","ModalClose","DialogPrimitive","Modal","trigger","defaultOpen","onOpenChange","hideCloseButton","contentProps","clearDescribedBy","toasts","listeners","counter","emit","subscribeToToasts","getToasts","dismissToast","addToast","instance","makeShorthand","stableApi","useToast","toastVariants","Toaster","duration","swipeDirection","viewportClassName","toastClassName","ToastPrimitive","ArrowUpIcon","ArrowDownIcon","defaultFormatDelta","delta","formatted","Stat","formatDelta","deltaNode","down","SERIES_STROKE","SERIES_FILL","SERIES_SWATCH","seriesClass","MARGIN","niceNum","range","round","exponent","fraction","niceFraction","niceTicks","span","step","start","end","ticks","normalize","series","categories","point","matrix","byLabel","defaultValueFormatter","DataChart","valueFormatter","xTickFormatter","renderTooltip","width","height","yTickCount","showLegend","showTooltip","categoryHeader","emptyLabel","titleId","descId","hovered","setHovered","seriesNames","rawMin","rawMax","domainMin","domainMax","domainSpan","plotWidth","plotHeight","yScale","bandWidth","bandCenter","zeroY","seriesCount","groupWidth","barWidth","marks","seriesIndex","categoryIndex","x","y","barHeight","points","pointIndex","pct","total","hoveredPoints","hoveredLabel","defaultLegend","tick","category","VisuallyHidden"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["isRecord","capitalised","_Fragment","isRecord","capitalised","_Fragment","CloseIcon","DefaultHeader","DefaultCloseButton","_Fragment","_Fragment","_Fragment","XIcon","useDebouncedValue","useDebouncedValue","_Fragment","ResourceSelectClearIcon","DefaultIcon","DefaultTitle","DefaultDescription","DefaultActions","FIELD_SELECTOR","useIsomorphicLayoutEffect","_Fragment","textOf","capitalised","_Fragment","ViewOptionsMenu","toIsoWithOffset","fileBasename","_Fragment","FIELD_GAP","PLACEHOLDER_ROWS","shownFields","plural","FIELD_GAP","_Fragment","DefaultValue","DefaultLoading","_Fragment","DefaultLoading","DefaultEmpty","Stat","_Fragment","_Fragment","DefaultHeader","DefaultTitle","DefaultDescription","CloseIcon","_Fragment","_Fragment","_Fragment","THEME_STORAGE_KEY","React","SelectPrimitive","CheckboxPrimitive","SwitchPrimitive","LabelPrimitive","TabsPrimitive","DropdownMenuPrimitive","DialogPrimitive","PopoverPrimitive","ToastPrimitive","VisuallyHidden","cn","inputs","twMerge","clsx","registry","defaultHotDetector","meta","detectHot","registerComponentRole","options","reason","role","previous","component","existing","message","getRoleRegistry","variants","groupNames","config","rest","props","selection","chosen","classes","group","value","groupClasses","compound","compoundClassName","conditions","expected","key","className","isRecord$2","defaultMessage","data","\"detail\"","status","KarniApiError","splitBaseUrl","match","baseUrl","joinUrl","path","normalized","basePath","origin","appendQuery","query","url","params","item","qs","parseBody","response","text","createKarniClient","fetchOption","hooks","perform","headers","hookHeaders","name","requestOptions","token","body","init","requestRaw","error","next","STOCK_DETAILS","capitalised$2","serverDetail","detail","isOffline","isNetworkFailure","isTimeout","describeError","context","base","what","action","resource","errorSummary","baseProps","CheckIcon","ChevronDownIcon","ChevronUpIcon","AlertIcon","LockIcon","OfflineIcon","SearchIcon","SpinnerIcon","SunIcon","MoonIcon","MonitorIcon","PrimitivesContext","KarniPrimitivesProvider","parent","merged","useKarniPrimitives","overridable","Component","overrides","inner","Override","Default","overridableSelectPart","family","Part","part","buttonVariants","KarniButton","type","Button","SLOW_AFTER_MS","useDelayedFlag","elapsed","setElapsed","active","timer","delayMs","subscribeOnline","onChange","useOnlineStatus","PendingButton","slow","pending","Fragment","disabled","pendingLabel","ICONS","ErrorState","described","Icon","retry","onRetry","retrying","inline","variant","actions","PermissionDenied","description","ThemeContext","DARK_QUERY","readStored","systemTheme","ThemeProvider","theme","setThemeState","storageKey","defaultTheme","system","setSystem","resolvedTheme","element","target","setTheme","useTheme","NEXT","LABEL","ThemeToggle","label","KarniInput","Input","KarniTextarea","Textarea","EMPTY_VALUE_LABEL","EmptyValue","KARNI_SELECT_EMPTY","SelectRoot","SelectGroup","SelectValue","KarniSelectTrigger","children","SelectTrigger","SelectScrollUpButton","SelectScrollDownButton","KarniSelectContent","position","SelectContent","KarniSelectLabel","SelectLabel","KarniSelectItem","SelectItem","KarniSelectSeparator","SelectSeparator","Select","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","openRef","safeOptions","filtered","option","radixValue","clearable","handleValueChange","onValueChange","open","onOpenChange","event","onBlur","contentClassName","clearLabel","KarniCheckbox","Checkbox","KarniSwitch","Switch","KarniLabel","Label","Tabs","TabsList","TabsTrigger","TabsContent","DropdownMenu","DropdownMenuTrigger","DropdownMenuGroup","DropdownMenuPortal","DropdownMenuContent","DropdownMenuItem","inset","DropdownMenuCheckboxItem","DropdownMenuLabel","DropdownMenuSeparator","KarniSkeleton","Skeleton","stringifyScalar","isScalarArray","buildListQuery","buildItemQuery","normalizeParams","out","normalizeValue","listPath","detailPath","id","karniKeys","KarniClientContext","createContext","NO_PRIMITIVES","KarniProvider","ownQueryClient","useState","queryClient","QueryClient","QueryClientProvider","client","primitives","useKarniClient","useContext","readAuthMode","record","candidate","\"authMode\"","normalizeUser","email","roles","readCookie","trimmed","separator","describeShape","keys","read2fa","AuthEngine","listener","user","refreshToken","access","rotated","twoFactor","refresh","loginPath","createLocalStorageTokenStorage","createMemoryTokenStorage","AuthContext","AuthProvider","useQueryClient","storage","useMemo","tokenStorage","engine","mode","csrfCookieName","csrfHeaderName","authBasePath","snapshot","useSyncExternalStore","identity","previousIdentity","useRef","password","useAuth","useResourceList","useQuery","isFileValue","isBlobValue","containsFile","values","appendFormValue","form","toFormData","encodeBody","fileFieldNames","names","cachedSchema","resources","entry","fields","field","kind","isStringOrStringArray","omitUnchangedFileUrls","fileFields","useResourceMutations","invalidateKeys","invalidate","useCallback","useMutation","prepared","isRecord$1","humanize","spaced","REF_PREFIX","lookupRef","ref","doc","resolveSchema","schema","seen","resolved","siblings","normalizeType","t","relationFromExtension","ext","relationValueTypeOf","combineEnumMembers","nullable","member","members","CHOICE_LINE","choiceLabels","labels","line","applyChoiceLabels","isAnySchema","analyzeProperty","raw","relation","typeNullable","info","composition","combined","mergeField","requestInfo","responseInfo","title","requiredSet","hasCreateRequest","enumValues","fallback","enumLabels","maxLength","min","max","format","valueType","operationDef","queryParams","expandEnum","param","op","items","def","listItemSchema","media","results","\"results\"","createRequestSchema","content","METHODS","parseOpenApi","input","paths","rawAuthMode","authMode","listOps","get","listOp","itemEntry","itemPath","itemItem","operations","createOp","exportItem","exportOp","importItem","importOp","method","responseSchema","requestSchema","responseProps","requestProps","order","prop","requestProp","parsed","SCHEMA_QUERY_KEY","useParsedSchema","useSchema","known","AUDIT_FIELDS","isAuditField","partitionAuditFields","domain","audit","a","b","LABEL_KEYS","displayLabel","obj","\"id\"","sortingToOrdering","sorting","orderingToSorting","ordering","statusOf","isNotFoundError","listRetry","appDefault","failureCount","resourceWords","singular","plural","capitalised$1","pageCountFor","count","pageSize","asRecord","enumLabel","LOOKUP_SEPARATOR","sameId","ownedBy","row","userId","combine","unknownSeen","parts","answer","evaluateAccess","any","rule","\"public\"","\"any\"","\"all\"","\"authenticated\"","\"role\"","held","owned","\"owned\"","SELECT_COLUMN","ACTIONS_COLUMN","isStructural","columnId","selectionColumn","resourceLabel","table","checked","rowLabel","RowActions","onEdit","canEdit","buttonClassName","rowActions","onDelete","canDelete","actionsColumn","cellOf","cell","flexRender","CardList","columns","selectable","column","hasActions","dataColumns","titleColumn","sortOptions","columnLabel","sortValue","header","onOrderingChange","listRef","caption","busy","dimmed","useRowLabelAsTitle","Card","onRowClick","failures","CloseIcon$2","ModalClose","ModalTitle","ModalDescription","DefaultHeader$2","DefaultFooter","DefaultCloseButton$1","defaultModalSlots","Modal","slots","clearDescribedBy","contentProps","trigger","Header","footer","Footer","hideCloseButton","CloseButton","ConfirmDialog","failed","retryable","errorContext","onCancel","returnFocus","destructive","onConfirm","confirmLabel","DEFAULT_SKIPPED_KINDS","UNSORTABLE_KINDS","BooleanCell","IdCode","relationItem","RelationCell","index","dateText","withTime","FileCell","JsonCell","shown","renderFieldCell","getRowLabel","headerTemplate","columnForField","customCell","override","ctx","deriveColumns","args","defs","importDescribeKey","importJobKey","jobId","importPath","suffix","IN_FLIGHT","isImportInFlight","job","filenameFrom","downloadResourceExport","\"page\"","\"page_size\"","blob","filename","saveBlob","anchor","downloadImportTemplate","useImportDescribe","useImportJob","pollMs","useImportActions","store","file","mapping","describe","ExportButtons","setBusy","setError","run","failure","formats","singularOf","word","resourceNames","words","last","ResourceSelectOption","selected","XIcon$1","ResourceSelectChip","state","onRemove","removeLabel","SKELETON_WIDTHS","ResourceSelectLoading","rows","emptyText","search","loaded","ResourceSelectEmpty","ResourceSelectError","defaultResourceSelectSlots","useDebouncedValue$1","debounced","setDebounced","pageQueryOf","asPage","page","useOptionPages","filter","useInfiniteQuery","pageParam","keepPreviousData","NOTHING","useSelectedRows","ids","batched","idsFilter","batch","enabled","singles","useQueries","loading","VIRTUALIZE_AFTER","OVERSCAN","DEFAULT_ROW_HEIGHT","DEFAULT_VIEWPORT_HEIGHT","LOADING_ROWS","idOf","shortId","capitalised","ResourceSelect","slotOverrides","searchableProp","idsFilterProp","reactId","inputId","listboxId","optionDomId","listOperation","searchable","setOpen","inputText","setInputText","activeIndex","setActiveIndex","cache","setCache","scrollTop","setScrollTop","rowHeight","setRowHeight","viewportHeight","setViewportHeight","rootRef","contentRef","scrollRef","inputRef","advanceRef","setInputRef","forwardedRef","term","debouncedTerm","searchDebounceMs","pages","loadedRows","total","hasMore","changed","labelOf","getOptionLabel","labelTextOf","needle","selectedKey","cacheRef","resolution","sel","rowFor","stateOf","failedText","selectedText","isSelected","optionId","virtual","start","end","hasOptions","container","height","scrollToIndex","top","loadMore","moveTo","previousCount","resetList","openPopover","closePopover","toggleOption","multiple","removeValue","other","clearSelection","single","singleState","singleText","inputValue","handleInputChange","rowsPerPage","handleKeyDown","handleBlur","handleScroll","firstLoad","loadError","searching","totalText","emptyReason","emptyProps","announcement","activeId","invalid","Option","Chip","ListLoading","Empty","ListError","listbox","offset","optionSelected","listBody","placeholder","toSelectValue","toRelationValue","EnumFilter","onFilterChange","BooleanFilter","FilterBar","searchEnabled","searchPlaceholder","searchValue","onSearchChange","filterFields","DENSITY_CLASSES","SCROLL_BOX","TABLE","THEAD","HEAD_CELL","BODY_CELL","LAST_ROW","SELECT_CELL","FROZEN_CELL","FROZEN_AT_START","FROZEN_AFTER_SELECT","FROZEN_CONTENT","PREFIX","densityKey","hiddenColumnsKey","namespace","readStorage","writeStorage","useStoredPreference","read","parse","setState","current","serialize","parseDensity","parseColumnList","asString","serializeColumnList","BulkActionsBar","buttons","selectedIds","others","allPageRowsSelected","totalCount","pageRowCount","onClear","bulkActions","runningIndex","onAction","outcome","ChevronLeftIcon","ChevronRightIcon","FirstPageIcon","LastPageIcon","PlusIcon","SlidersIcon","FilterOffIcon","InboxIcon","NavButton","buttonRef","unavailable","spinning","onActivate","iconAfter","icon","PaginationControls","setTarget","jump","setJump","jumpId","previousRef","nextRef","refocus","setRefocus","hasPrevious","hasNext","go","clamped","pageCount","from","onPageChange","which","sizes","pageSizeOptions","onPageSizeChange","size","wanted","CARD_FIELDS","RowCard","expanded","setExpanded","listId","hiddenCount","density","onOpen","DefaultIcon$1","DefaultTitle$2","DefaultDescription$2","DefaultActions$1","defaultEmptyStateSlots","EmptyState","Title","Description","Actions","BAR_WIDTHS","barWidth","offsets","sum","TableOutline","columnCount","frozen","rowCount","CardsOutline","structural","pairs","TableSkeleton","NoRecords","onCreate","itemLabel","createLabel","NoResults","narrowing","filters","onClearFilters","TableError","RefetchError","Forbidden","OfflineNotice","defaultResourceTableSlots","CONTROL_SELECTOR","FIELD_SELECTOR$1","usable","node","controlsOf","found","stopIn","controls","stopsOf","locate","control","stop","ROW_ID_ATTRIBUTE","resolve","memory","remember","sync","setTabIndex","nextStop","stops","toRow","toGridCorner","useIsomorphicLayoutEffect$1","NAVIGATION_KEYS","useGridNavigation","tableRef","observer","onFocus","before","isCheckbox","rowKeyDown","onCell","frozenClasses","firstDataColumn","TableView","captionId","grid","keyboardNavigation","navigation","onScroll","box","scrolled","\"scrolled\"","canSort","direction","sortTarget","onSort","firstRowIndex","first","useIsomorphicLayoutEffect","useContainerWidth","width","setWidth","measure","entries","useDebouncedValue","historyListeners","createHistoryStateStore","changes","push","defaultStore","RESERVED","prefixed","encodeFilter","relationId","decodeFilter","positiveInt","snapshotOf","prefix","own","viewFromSnapshot","defaults","isCleared","compactFilters","noSubscription","useTableView","subscribe","syncUrl","getSnapshot","local","setLocal","fromUrl","view","viewRef","patch","ViewOptions","visibleCount","onDensityChange","onColumnVisibilityChange","DEFAULT_PAGE_SIZE_OPTIONS","SEARCH_DEBOUNCE_MS","MAX_DERIVED_FILTERS","SKELETON_COLUMNS","NO_COLUMNS","isPromiseLike","textOf$1","filterWords","RowDeleteDialog","mutations","deleted","quoted","onClose","onDeleted","fallbackFocus","ResourceTable","densityProp","Slots","auth","authStatus","authUser","schemaResult","one","tableName","urlNamespace","pinned","byName","declared","showAuditFields","defaultPageSize","sizesKey","defaultOrdering","initialSorting","setView","stateStore","setAnnouncement","intent","searchInput","setSearchInput","debouncedSearch","shownSearch","settledSearch","handleFilterChange","clearFilters","expandList","expand","allowed","activeSearch","listParams","appRetry","list","lastLoaded","lastData","hasError","clamping","blocking","shownData","stale","online","paused","wasOnline","refetch","transitioning","storedDensity","setStoredDensity","defaultDensity","changeDensity","hiddenColumns","setHiddenColumns","updateRule","removeRule","createRule","deleteMissing","allowEdit","allowDelete","createAllowed","canCreate","createText","deleteTarget","setDeleteTarget","requestDelete","cardListRef","hasBulkSelect","enableDelete","actionButtons","columnDefs","extraColumns","columnsOverride","leading","trailing","columnVisibility","rowSelection","setRowSelection","setSortTarget","handleSortingChange","updater","useReactTable","getCoreRowModel","selectedRef","firstSelection","quietSelection","setRunningIndex","setOutcome","setFailures","confirmTarget","setConfirmTarget","confirmError","setConfirmError","runBulk","actionLabel","returned","confirmed","onBulkAction","layout","cardBreakpoint","changePage","changePageSize","retryList","retrySchema","activeFilters","loadingNode","empty","exportList","exportFormats","exportEnabled","showFilterRow","toolbar","viewOptions","liveText","visible","hidden","BulkConfirm","custom","useResourceItem","UNSAVED_CHANGES_MESSAGE","useUnsavedChangesGuard","controlled","reported","setReported","dirty","dirtyRef","confirmRef","confirm","setDirty","beforeUnload","warn","REQUIRED_MESSAGE","LOCAL_DATETIME","toIsoWithOffset$1","date","enumSchema","z","literals","stringSchema","requireNonEmpty","numberSchema","integer","relationValueSchema","coerce","singleRelationSchema","fileSchema","baseSchemaFor","zodFor","shape","fieldSchema","matchesAccept","accept","tokens","formatFileSize","bytes","fileBasename$1","segments","segment","defaultRejectionMessage","limits","UploadIcon","XIcon","DefaultDropzone","uploading","dragging","DefaultFileRow","defaultFileUploadSlots","FileUpload","dropzoneRef","messageId","setDragging","rejections","setRejections","blocked","acceptFiles","accepted","refused","maxSize","rejectionMessage","handleDrop","handleDragOver","removeEntry","remaining","i","files","messages","describedBy","Dropzone","FileRow","humanizeValue","pad","n","toDatetimeLocal","HAS_ZONE","toIsoWithOffset","offsetMinutes","sign","abs","isDirtyEntry","pkOf","initialFieldValue","buildFormValues","source","defaultValues","val","OMIT","emptied","coerceFieldValue","numeric","prepareSubmit","jsonErrors","rawValue","dirtyFields","result","KINDS_WITHOUT_ARIA_REQUIRED","stringInputType","textValue","DefaultFieldControl","useFormContext","aria","required","Controller","rhf","renderControl","revalidateWhileInvalid","fieldState","change","inputProps","labelId","FIELD_GAP$1","SUBMIT_ROW","GhostControl","ghost","PLACEHOLDER_ROWS$1","ResourceFormSkeleton","showSubmitRow","submitLabel","ResourceFormForbidden","ResourceFormLoadError","ResourceFormErrorSummary","titleId","errors","BANNER_ICONS","ResourceFormSubmitError","reload","onReload","reloading","ROOT_KEYS","isRecord","defaultLabel","messagesOf","\"message\"","nested","isMarkup","mapServerErrors","root","toRoot","walk","isField","defaultResourceFormSlots","EDITABLE_KINDS","writableFields","shownFields$1","apiFailure","TYPE_ISSUES","isEmptyValue","hasValueAt","errorAt","plural$1","many","FormFieldRow","errorId","descriptionId","ResourceFormInner","fieldOverrides","baseId","inputIdOf","formFields","visibleFields","initialValues","resolver","zodResolver","omittable","optionalText","blank","cleaned","methods","useForm","validationMode","submitting","formState","savedRef","guard","guardUnsavedChanges","onDirtyChangeRef","onDirtyChange","submitError","setSubmitError","rootMessages","setRootMessages","summaryShown","setSummaryShown","setReloading","pendingFocus","focusTick","setFocusTick","summaryRef","bannerRef","formRef","inFlight","submitOrigin","requestFocus","tick","focusField","fieldErrors","problemCount","afterFailedValidation","failing","roots","only","failingFields","extra","applyServerFailure","shownNames","schemaNames","mapped","submit","jsonError","payload","transformSubmit","onError","onSuccess","runSubmit","saved","errorSignature","previousErrors","fresh","shouldAutoFocus","autoFocus","autoFocusTarget","reloadItem","handleKeyDownCapture","fieldError","SubmitErrorSlot","SummarySlot","summaryTitle","FormProvider","extraFields","ResourceForm","isEdit","itemQuery","ErrorSlot","ForbiddenSlot","LoadingSlot","pluralNoun","singularNoun","isClientError","useRetryUnlessClientError","configured","offlineError","useRetryWhenOnline","retryRef","network","cameBack","fileBasename","formatDate","formatDateTime","RelationEntry","RelationValue","isEmpty","DefaultValue$1","DefaultEmptyValue","PLACEHOLDER_ROWS","VALUE_WIDTHS","valueWidth","RowPlaceholder","bar","muted","DefaultLoading$2","auditFields","DefaultError","back","QUIET_PANEL","DefaultNotFound","DefaultDeleted","DefaultDeleteDialog","errorRef","defaultResourceDetailSlots","DetailRow","shownFields","ResourceDetail","recordHeadingId","schemaFetching","useIsFetching","remove","deleteOpen","setDeleteOpen","deletedRef","deletedItem","deleteButtonRef","wasOpen","closed","schemaError","itemError","blockingItemError","offline","retryAll","domainAndAudit","mayEdit","mayDelete","appended","sections","section","changeHistoryKey","useChangeHistory","ACTION_LABEL","formatWhen","Value","DefaultEntry","after","DefaultLoading$1","DefaultEmpty$1","defaultChangeHistorySlots","PLACEHOLDER_ENTRIES","ChangeHistory","refusal","VALIDATION_TITLES","ERROR_ICONS","DefaultImportError","DefaultImportLoading","Stat$1","DefaultSummary","created","updated","skipped","unchanged","DefaultProblems","problems","problem","DefaultProgress","percent","verb","quarter","DefaultConfirmCommit","defaultResourceImportSlots","MappingTable","WaitingForConnection","stepOf","remap","ResourceImport","setJobId","setMapping","setRemap","setFile","confirmOpen","setConfirmOpen","templateError","setTemplateError","fileId","hintId","uploadErrorRef","stepRef","seededFor","onDone","upload","preview","commit","step","shownStep","commitButtonRef","wasConfirming","describeLoading","describeOffline","retryDescribe","startUpload","handleUpload","handlePreview","startOver","handleTemplate","uploadError","old","done","FIELD_GAP","TwoFactorUnavailable","throttleSeconds","firstMessage","describeLoginError","seconds","DefaultLoginError","defaultLoginFormSlots","LoginForm","setFailure","emailRef","passwordRef","submitRef","attempts","attempt","login","on2FA","SignInPrompt","headingId","AccessDenied","defaultAuthGuardSlots","NO_ROLES","warned","warnImplicitNothing","AuthGuard","explain","hasFallback","anonymous","denied","usePermission","DefaultHeader$1","DefaultTitle$1","DefaultDescription$1","DefaultActions","defaultPageSlots","Page","headerClassName","MARK_VIEWBOX","MARK_PATHS","\"fill\"","\"d\"","MARK_SIMPLE_BODY","KarniMark","simple","labelled","locationKey","pathname","hash","defaultTarget","main","textOf","FIELD_SELECTOR","focusClaimed","defaultAnnouncement","heading","INTERACTIONS","useRouteFocus","latest","settled","interacted","finish","mainRef","getTarget","sameHeading","getAnnouncement","check","mutated","mark","MenuIcon","CloseIcon$1","NAV_ITEM_CLASS","NAV_ITEM_ACTIVE_CLASS","ICON_BUTTON_CLASS","SidebarColumn","nav","DefaultHeader","menuButton","DefaultSidebar","DefaultNavLink","DefaultMobileDrawer","returnFocusRef","DefaultSkipLink","defaultLayoutSlots","Layout","uncontrolledOpen","setUncontrolledOpen","defaultMobileNavOpen","mobileNavOpen","onMobileNavOpenChange","closeMobile","menuButtonRef","drawerId","mainId","skipToMain","routeFocusOn","routeFocus","routeAnnouncement","closeIfWide","button","sidebarHeader","sidebar","navLabel","navItems","defaultClassName","defaultNode","NavLink","renderNavItem","sidebarFooter","SkipLink","Sidebar","sidebarClassName","MobileDrawer","toasts","listeners","counter","emit","subscribeToToasts","getToasts","dismissToast","addToast","instance","makeShorthand","stableApi","useToast","CloseIcon","toastVariants","DefaultTitle","DefaultDescription","DefaultCloseButton","defaultToasterSlots","ANNOUNCE","Toaster","toastClassName","viewportClassName","iconProps","ArrowUpIcon","ArrowDownIcon","FlatIcon","defaultFormatDelta","formatted","delta","DefaultLabel","DefaultValue","DefaultIcon","DefaultDelta","spoken","formatDelta","defaultStatSlots","Stat","Delta","SERIES_STROKE","SERIES_FILL","SERIES_SWATCH","seriesClass","MARGIN","TICK_FONT","MIN_TICK_PX","niceNum","exponent","range","fraction","niceFraction","round","niceTicks","ticks","normalize","series","categories","s","point","matrix","byLabel","defaultValueFormatter","describeChart","chart","span","low","high","seriesNames","seriesIndex","DefaultTooltip","points","valueFormatter","DefaultLegend","swatchClassName","DefaultEmpty","DefaultLoading","defaultDataChartSlots","useRenderedWidth","measured","DataChart","descId","summaryId","hovered","setHoveredState","hoveredRef","setHovered","svgRef","plottable","renderedWidth","Loading","emptyLabel","scale","fontSize","strokeWidth","pointRadius","rawMin","rawMax","yTickCount","domainMin","domainMax","domainSpan","longestTick","margin","plotWidth","plotHeight","yScale","bandWidth","bandCenter","zeroY","seriesCount","groupWidth","marks","x","categoryIndex","y","barHeight","pointIndex","pointsAt","pct","hoveredPoints","hoveredLabel","select","onKeyDown","generatedSummary","summary","showTooltip","defaultLegend","xTickFormatter","category","renderTooltip","Tooltip","showLegend","Legend","categoryHeader","KARNI_THEME_SCRIPT"],"sources":["../src/lib/cn.ts","../src/lib/roles.ts","../src/lib/variants.ts","../src/schema/client.ts","../src/states/describe-error.ts","../src/components/primitives/icons.tsx","../src/primitives/registry.tsx","../src/components/primitives/button.tsx","../src/states/hooks.ts","../src/states/PendingButton.tsx","../src/states/ErrorState.tsx","../src/theme/theme.tsx","../src/components/primitives/input.tsx","../src/components/primitives/textarea.tsx","../src/components/resource/empty-value.tsx","../src/components/primitives/select.tsx","../src/components/primitives/checkbox.tsx","../src/components/primitives/switch.tsx","../src/components/primitives/label.tsx","../src/components/primitives/tabs.tsx","../src/components/primitives/dropdown-menu.tsx","../src/components/primitives/skeleton.tsx","../src/hooks/params.ts","../src/hooks/keys.ts","../src/schema/provider.tsx","../src/auth/engine.ts","../src/auth/storage.ts","../src/auth/provider.tsx","../src/hooks/useResourceList.ts","../src/hooks/multipart.ts","../src/hooks/useResourceMutations.ts","../src/schema/parse.ts","../src/schema/useSchema.ts","../src/components/resource/audit-fields.ts","../src/components/resource/displayLabel.ts","../src/components/resource/table/table-utils.ts","../src/components/resource/table/access.ts","../src/components/resource/table/structural-columns.tsx","../src/components/resource/table/CardList.tsx","../src/components/modal/modal.tsx","../src/components/resource/table/ConfirmDialog.tsx","../src/components/resource/table/derive-columns.tsx","../src/hooks/useResourceImport.ts","../src/components/resource/table/ExportButtons.tsx","../src/components/resource/resource-names.ts","../src/components/resource/select/select-states.tsx","../src/components/resource/select/use-debounced-value.ts","../src/components/resource/select/use-option-pages.ts","../src/components/resource/select/ResourceSelect.tsx","../src/components/resource/table/FilterBar.tsx","../src/components/resource/table/layout.ts","../src/components/resource/table/preferences.ts","../src/components/resource/table/BulkActionsBar.tsx","../src/components/resource/table/table-icons.tsx","../src/components/resource/table/PaginationControls.tsx","../src/components/resource/table/RowCard.tsx","../src/components/empty-state/empty-state.tsx","../src/components/resource/table/states.tsx","../src/components/resource/table/slots.ts","../src/components/resource/table/grid-navigation.ts","../src/components/resource/table/TableView.tsx","../src/components/resource/table/use-container-width.ts","../src/components/resource/table/use-debounced-value.ts","../src/components/resource/table/url-state.ts","../src/components/resource/table/ViewOptions.tsx","../src/components/resource/table/ResourceTable.tsx","../src/hooks/useResourceItem.ts","../src/hooks/useUnsavedChangesGuard.ts","../src/schema/zod.ts","../src/components/file-upload/FileUpload.tsx","../src/components/resource/form/prepare.ts","../src/components/resource/form/field-inputs.tsx","../src/components/resource/form/form-states.tsx","../src/components/resource/form/server-errors.ts","../src/components/resource/form/ResourceForm.tsx","../src/components/resource/nouns.ts","../src/components/resource/query-state.ts","../src/components/resource/detail/ResourceDetail.tsx","../src/hooks/useChangeHistory.ts","../src/components/resource/history/ChangeHistory.tsx","../src/components/resource/import/ResourceImport.tsx","../src/auth/LoginForm.tsx","../src/auth/AuthGuard.tsx","../src/auth/usePermission.ts","../src/components/page/page.tsx","../src/components/brand/mark-paths.ts","../src/components/brand/karni-mark.tsx","../src/components/layout/route-focus.ts","../src/components/layout/layout.tsx","../src/components/toast/toast-store.ts","../src/components/toast/use-toast.ts","../src/components/toast/toaster.tsx","../src/components/stat/stat.tsx","../src/components/chart/data-chart.tsx"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merges class names: clsx semantics for conditionals plus tailwind-merge\n * conflict resolution, so consumer-supplied `className` always wins over a\n * component's own Tailwind classes. Every @karni/ui component funnels its\n * `className` prop through this.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Component role registry (enforcement contract §4 + F11).\n *\n * Every top-level component claims a semantic role (\"data-table\",\n * \"resource-form\", …) at module scope. Two components claiming the same role\n * is a conflict: it throws at import time (so vitest and the dev server both\n * surface it) and `scripts/generate-manifest.mjs` fails the build on the same\n * duplicate via a static scan of these call sites.\n *\n * Conventions:\n * - The `role` argument MUST be a string literal. The build-time scan rejects\n * any non-literal first argument.\n * - Same role + same component name is idempotent (modules re-evaluate under\n * HMR and across test files).\n * - Replacing on purpose is explicit and must carry a reason:\n * `{ replace: true, reason: \"<why>\" }`. An empty reason throws.\n * - Under Vite HMR (`import.meta.hot`) an accidental conflict logs a\n * console.error and replaces instead of throwing, so a rename mid-edit does\n * not kill the dev server.\n * - The registry reflects imported modules only (accepted v0.1 trade-off).\n */\n\nexport interface RegisterComponentRoleOptions {\n /** Replace an existing registration on purpose. Requires `reason`. */\n replace?: boolean;\n /** Why the replacement is intentional. Required with `replace: true`. */\n reason?: string;\n}\n\nconst registry = new Map<string, string>();\n\n/**\n * `import.meta.hot` is defined by Vite's dev server and undefined in prod\n * builds. Vitest also ships an import.meta.hot stub, but tests must throw on\n * conflicts (F11), so the test environment is explicitly excluded.\n */\nfunction defaultHotDetector(): boolean {\n try {\n const meta = import.meta as ImportMeta & { hot?: unknown; env?: { MODE?: string } };\n if (!meta.hot) return false;\n if (meta.env?.MODE === \"test\") return false;\n if (typeof process !== \"undefined\" && process.env?.VITEST !== undefined) return false;\n return true;\n } catch {\n return false;\n }\n}\n\nlet detectHot: () => boolean = defaultHotDetector;\n\n/**\n * Test-only override for HMR detection. Pass `null` to restore the default.\n * Not exported from the package barrel.\n * @internal\n */\nexport function __setHotDetectorForTests(detector: (() => boolean) | null): void {\n detectHot = detector ?? defaultHotDetector;\n}\n\n/**\n * Test-only registry reset. Not exported from the package barrel.\n * @internal\n */\nexport function __resetRoleRegistryForTests(): void {\n registry.clear();\n}\n\n/**\n * Claims a UI role (such as `data-table`) for a component, so a second component with the same role fails the build. The first argument must be a string literal\n * (build-scan convention, F11).\n */\nexport function registerComponentRole(\n role: string,\n component: string,\n options?: RegisterComponentRoleOptions,\n): void {\n if (options?.replace) {\n const reason = options.reason?.trim() ?? \"\";\n if (reason === \"\") {\n throw new Error(\n `[karni] registerComponentRole: replacing role \"${role}\" requires a non-empty reason. ` +\n `Pass { replace: true, reason: \"<why>\" }.`,\n );\n }\n const previous = registry.get(role);\n if (previous !== undefined && previous !== component) {\n console.warn(\n `[karni] component role \"${role}\" replaced: \"${previous}\" -> \"${component}\" (${reason})`,\n );\n }\n registry.set(role, component);\n return;\n }\n\n const existing = registry.get(role);\n if (existing === undefined || existing === component) {\n // Idempotent: first registration, or the same component re-registering.\n registry.set(role, component);\n return;\n }\n\n const message =\n `[karni] duplicate component role \"${role}\": already registered by \"${existing}\", now ` +\n `claimed by \"${component}\". Compose or extend the existing component instead, or replace ` +\n `it on purpose with { replace: true, reason: \"<why>\" }.`;\n\n if (detectHot()) {\n // Dev HMR: a module re-evaluating mid-rename must not kill the app.\n console.error(message);\n registry.set(role, component);\n return;\n }\n throw new Error(message);\n}\n\n/** Snapshot of the current registry ({ role: component }) for tooling. */\nexport function getRoleRegistry(): Readonly<Record<string, string>> {\n return Object.freeze(Object.fromEntries(registry));\n}\n","import { cn } from \"./cn\";\n\n/**\n * Hand-rolled cva-style variant utility (no extra dependency).\n *\n * Every class string appears whole in source (contract D7): a variant map\n * value is a complete Tailwind class list, selected (never concatenated)\n * at call time and merged through cn().\n */\n\n/** A map of variant group name → allowed value → whole Tailwind class string. */\nexport type VariantShape = Record<string, Record<string, string>>;\n\n/** The props accepted for a given variant shape (each group optional). */\nexport type VariantSelection<V extends VariantShape> = {\n [K in keyof V]?: Extract<keyof V[K], string> | null;\n};\n\nexport interface VariantsConfig<V extends VariantShape> {\n /** Classes always applied, before any variant classes. */\n base?: string;\n variants: V;\n defaultVariants?: VariantSelection<V>;\n /** Extra classes applied when every listed variant value is selected. */\n compoundVariants?: ReadonlyArray<VariantSelection<V> & { className: string }>;\n}\n\nexport type VariantFn<V extends VariantShape> = (\n props?: VariantSelection<V> & { className?: string },\n) => string;\n\n/**\n * Extracts the variant props of a variant function, for typing component\n * props: `type ButtonVariantProps = VariantProps<typeof buttonVariants>`.\n */\nexport type VariantProps<F> = F extends VariantFn<infer V> ? VariantSelection<V> : never;\n\n/** Builds a typed class-name function from variant definitions, the way every themed component declares its looks. */\nexport function variants<V extends VariantShape>(config: VariantsConfig<V>): VariantFn<V> {\n const groupNames = Object.keys(config.variants) as Array<Extract<keyof V, string>>;\n\n return (props) => {\n const { className, ...rest } = props ?? {};\n const selection = rest as VariantSelection<V>;\n const chosen: Partial<Record<Extract<keyof V, string>, string>> = {};\n const classes: string[] = [];\n\n if (config.base) {\n classes.push(config.base);\n }\n\n for (const group of groupNames) {\n const value = selection[group] ?? config.defaultVariants?.[group];\n if (value == null) {\n continue;\n }\n chosen[group] = value;\n const groupClasses = config.variants[group][value];\n if (groupClasses) {\n classes.push(groupClasses);\n }\n }\n\n for (const compound of config.compoundVariants ?? []) {\n const { className: compoundClassName, ...rest } = compound;\n // TS cannot relate Omit<VariantSelection<V> & {...}, \"className\"> back to\n // the per-group selection shape, so narrow through unknown once here.\n const conditions = rest as unknown as Partial<\n Record<Extract<keyof V, string>, string | null>\n >;\n const conditionKeys = Object.keys(conditions) as Array<Extract<keyof V, string>>;\n const matches = conditionKeys.every((key) => {\n const expected = conditions[key];\n return expected != null && chosen[key] === expected;\n });\n if (matches) {\n classes.push(compoundClassName);\n }\n }\n\n return cn(...classes, className);\n };\n}\n","/**\n * createKarniClient: the typed fetch wrapper every @karni/ui layer sits on\n * (contract \"Schema client\" + D6).\n *\n * Responsibilities:\n * - URL joining + query-string serialization (arrays become repeated keys,\n * null/undefined are dropped),\n * - JSON request/response handling. A FormData body is passed through\n * untouched with NO manual Content-Type (the D2 multipart rule),\n * - DRF error passthrough: non-2xx responses throw KarniApiError carrying the\n * parsed body (field errors / detail / non_field_errors) verbatim,\n * - auth hook points per D6's client-owns-tokens design: the auth layer (not\n * React) registers token injection, extra headers (session CSRF),\n * credentials mode and a 401 handler via `setAuthHooks`. The client calls\n * `onUnauthorized` at most ONCE per request and retries at most ONCE. A\n * request that 401s again after a successful refresh is surfaced and never\n * re-triggers refresh (the single-flight refresh promise itself lives in\n * the auth layer behind this hook).\n */\n\nexport interface KarniClientOptions {\n /**\n * Origin (plus optional path prefix) requests resolve against, e.g.\n * \"https://api.example.com\" or \"\" for same-origin. Paths that already start\n * with the prefix are not double-prefixed, so operation paths taken from\n * the OpenAPI document (\"/api/events/\") work with any baseUrl.\n */\n baseUrl: string;\n /** Path of the OpenAPI document. Default \"/api/schema/\". */\n schemaUrl?: string;\n /** Initial access-token getter. `setAuthHooks` can replace it later (D6). */\n getAccessToken?: () => string | null;\n /** Custom fetch implementation (tests, SSR). Resolved per request. */\n fetch?: typeof globalThis.fetch;\n}\n\nexport type KarniQueryValue =\n string | number | boolean | ReadonlyArray<string | number | boolean> | null | undefined;\n\nexport interface KarniRequestOptions {\n method?: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n query?: Record<string, KarniQueryValue>;\n /** JSON-serialized unless it is FormData (multipart rule D2). */\n body?: unknown;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n /**\n * Skip the 401 → onUnauthorized → retry cycle for this request. The auth\n * layer sets it on its own login/refresh/logout calls so a failing refresh\n * can never recurse into another refresh (D6).\n */\n skipAuthRefresh?: boolean;\n}\n\n/**\n * Hook points the auth layer registers on the client (D6). Keys present in\n * the object passed to `setAuthHooks` override the current value (an explicit\n * `undefined` clears one). Absent keys are kept.\n */\nexport interface KarniAuthHooks {\n /** Called before every request. A non-null return is sent as Bearer. */\n getAccessToken?: () => string | null;\n /**\n * Called once when a request gets a 401 (unless `skipAuthRefresh`). Return\n * true to retry the request once with freshly-injected credentials, false\n * to surface the error. Single-flight refresh lives behind this hook.\n */\n onUnauthorized?: (error: KarniApiError) => Promise<boolean>;\n /** Extra headers merged into every request (session-mode X-CSRFToken). */\n getHeaders?: () => Record<string, string>;\n /** fetch credentials mode. Session mode sets \"include\". */\n credentials?: RequestCredentials;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction defaultMessage(status: number, data: unknown): string {\n if (isRecord(data) && typeof data[\"detail\"] === \"string\") return data[\"detail\"];\n return `Karni API request failed with status ${status}`;\n}\n\n/** Thrown for non-2xx responses, with the parsed DRF error body in `data`. */\nexport class KarniApiError extends Error {\n readonly status: number;\n /** Parsed body when JSON (field errors, detail, non_field_errors), else text. */\n readonly data: unknown;\n\n constructor(status: number, data: unknown, message?: string) {\n super(message ?? defaultMessage(status, data));\n this.name = \"KarniApiError\";\n this.status = status;\n this.data = data;\n }\n}\n\nexport interface KarniClient {\n readonly baseUrl: string;\n readonly schemaUrl: string;\n request<T>(path: string, options?: KarniRequestOptions): Promise<T>;\n /**\n * The same request (auth, query, 401 retry) returning the raw `Response`\n * instead of a parsed body, for file downloads (`GET /<resource>/export/`).\n * Non-2xx responses still throw `KarniApiError` with the parsed error body.\n */\n requestRaw(path: string, options?: KarniRequestOptions): Promise<Response>;\n /** D6 hook point: the auth layer wires tokens/CSRF/401 handling here. */\n setAuthHooks(hooks: KarniAuthHooks): void;\n}\n\n// URL handling\n\nfunction splitBaseUrl(baseUrl: string): { origin: string; basePath: string } {\n const match = /^(https?:\\/\\/[^/]+)(\\/.*)?$/.exec(baseUrl);\n if (match !== null) {\n return { origin: match[1] ?? \"\", basePath: (match[2] ?? \"\").replace(/\\/+$/, \"\") };\n }\n return { origin: \"\", basePath: baseUrl.replace(/\\/+$/, \"\") };\n}\n\nfunction joinUrl(baseUrl: string, path: string): string {\n if (/^https?:\\/\\//.test(path)) return path;\n const { origin, basePath } = splitBaseUrl(baseUrl);\n const normalized = path.startsWith(\"/\") ? path : `/${path}`;\n if (basePath !== \"\" && (normalized === basePath || normalized.startsWith(`${basePath}/`))) {\n return origin + normalized;\n }\n return origin + basePath + normalized;\n}\n\nfunction appendQuery(url: string, query: Record<string, KarniQueryValue> | undefined): string {\n if (query === undefined) return url;\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value === null || value === undefined) continue;\n if (Array.isArray(value)) {\n for (const item of value) params.append(key, String(item));\n } else {\n params.append(key, String(value));\n }\n }\n const qs = params.toString();\n if (qs === \"\") return url;\n return url.includes(\"?\") ? `${url}&${qs}` : `${url}?${qs}`;\n}\n\n// body handling\n\nasync function parseBody(response: Response): Promise<unknown> {\n if (response.status === 204 || response.status === 205) return undefined;\n const text = await response.text();\n if (text === \"\") return undefined;\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"json\")) {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }\n return text;\n}\n\n// the client\n\n/** Creates the fetch client every hook in this package uses: base URL, JSON and multipart bodies, DRF errors as `KarniApiError`, and auth hooks. */\nexport function createKarniClient(options: KarniClientOptions): KarniClient {\n const { baseUrl, schemaUrl = \"/api/schema/\", fetch: fetchOption } = options;\n\n let hooks: KarniAuthHooks = {};\n if (options.getAccessToken !== undefined) {\n hooks = { getAccessToken: options.getAccessToken };\n }\n\n async function perform(url: string, requestOptions: KarniRequestOptions): Promise<Response> {\n const headers = new Headers({ accept: \"application/json\" });\n const hookHeaders = hooks.getHeaders?.();\n if (hookHeaders !== undefined) {\n for (const [name, value] of Object.entries(hookHeaders)) headers.set(name, value);\n }\n if (requestOptions.headers !== undefined) {\n for (const [name, value] of Object.entries(requestOptions.headers)) {\n headers.set(name, value);\n }\n }\n const token = hooks.getAccessToken?.() ?? null;\n if (token !== null && token !== \"\") headers.set(\"authorization\", `Bearer ${token}`);\n\n let body: BodyInit | undefined;\n if (typeof FormData !== \"undefined\" && requestOptions.body instanceof FormData) {\n body = requestOptions.body; // the runtime sets the multipart boundary (D2)\n } else if (requestOptions.body !== undefined) {\n body = JSON.stringify(requestOptions.body);\n if (!headers.has(\"content-type\")) headers.set(\"content-type\", \"application/json\");\n }\n\n const init: RequestInit = { method: requestOptions.method ?? \"GET\", headers };\n if (body !== undefined) init.body = body;\n if (requestOptions.signal !== undefined) init.signal = requestOptions.signal;\n if (hooks.credentials !== undefined) init.credentials = hooks.credentials;\n\n const fetchImpl = fetchOption ?? globalThis.fetch;\n return fetchImpl(url, init);\n }\n\n async function requestRaw(\n path: string,\n requestOptions: KarniRequestOptions = {},\n ): Promise<Response> {\n const url = appendQuery(joinUrl(baseUrl, path), requestOptions.query);\n\n let response = await perform(url, requestOptions);\n if (response.ok) return response;\n\n const error = new KarniApiError(response.status, await parseBody(response));\n if (\n response.status === 401 &&\n hooks.onUnauthorized !== undefined &&\n requestOptions.skipAuthRefresh !== true\n ) {\n const shouldRetry = await hooks.onUnauthorized(error);\n if (shouldRetry) {\n response = await perform(url, requestOptions);\n if (response.ok) return response;\n // A 401 (or anything else) after a successful refresh is surfaced\n // as-is — it never re-triggers refresh (D6).\n throw new KarniApiError(response.status, await parseBody(response));\n }\n }\n throw error;\n }\n\n return {\n baseUrl,\n schemaUrl,\n\n async request<T>(path: string, requestOptions: KarniRequestOptions = {}): Promise<T> {\n const response = await requestRaw(path, requestOptions);\n return (await parseBody(response)) as T;\n },\n\n requestRaw,\n\n setAuthHooks(next: KarniAuthHooks): void {\n hooks = { ...hooks, ...next };\n },\n };\n}\n","/**\n * describeError: any failure in plain words, never a raw status code.\n *\n * Every Karni component that shows an error goes through this, so a 403 reads\n * \"You can't delete events\" everywhere and a dropped connection reads \"You're\n * offline\" rather than \"Failed to fetch\". Projects call it too, for their own\n * error UI. Replace a component's whole error panel through its `slots`.\n */\nimport { KarniApiError } from \"../schema/client\";\n\nexport type KarniErrorKind =\n | \"offline\"\n | \"network\"\n | \"unauthenticated\"\n | \"forbidden\"\n | \"not-found\"\n | \"validation\"\n | \"conflict\"\n | \"rate-limited\"\n | \"timeout\"\n | \"server\"\n | \"unknown\";\n\n/** What the user was doing, so the message can name it (\"You can't delete events.\"). */\nexport interface KarniErrorContext {\n /** A verb: \"view\", \"create\", \"edit\", \"delete\", \"export\", \"import\", or your own. */\n action?: string;\n /** What it was done to, as the sentence needs it: \"events\", \"this event\". */\n resource?: string;\n}\n\nexport interface KarniErrorDescription {\n kind: KarniErrorKind;\n /** A short headline in plain words. */\n title: string;\n /** What to do next. */\n description: string;\n /** Whether the same request can succeed if tried again. */\n retryable: boolean;\n /** The server's own explanation, when it gave one worth showing (never for 5xx). */\n detail?: string;\n /** The HTTP status, for logs and project code. Never shown to the user. */\n status?: number;\n}\n\n/** DRF's stock sentences add nothing to the plain-words message, so they are not repeated as `detail`. */\nconst STOCK_DETAILS = new Set([\n \"You do not have permission to perform this action.\",\n \"Authentication credentials were not provided.\",\n \"Not found.\",\n \"No Page matches the given query.\",\n]);\n\nfunction capitalised(text: string): string {\n return text.charAt(0).toUpperCase() + text.slice(1);\n}\n\nfunction serverDetail(error: KarniApiError): string | undefined {\n const data = error.data;\n if (typeof data === \"object\" && data !== null && !Array.isArray(data)) {\n const detail = (data as Record<string, unknown>)[\"detail\"];\n if (typeof detail === \"string\" && detail.trim() !== \"\" && !STOCK_DETAILS.has(detail.trim())) {\n return detail.trim();\n }\n }\n return undefined;\n}\n\nfunction isOffline(): boolean {\n return typeof navigator !== \"undefined\" && navigator.onLine === false;\n}\n\n/** fetch rejects with a TypeError when the request never got a response. */\nfunction isNetworkFailure(error: unknown): boolean {\n return error instanceof TypeError;\n}\n\nfunction isTimeout(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n [\"TimeoutError\", \"AbortError\"].includes(String((error as { name?: unknown }).name))\n );\n}\n\n/** Classifies `error` and words it for the person using the app. */\nexport function describeError(\n error: unknown,\n context: KarniErrorContext = {},\n): KarniErrorDescription {\n const { action, resource } = context;\n if (error instanceof KarniApiError) {\n const status = error.status;\n const detail = status < 500 ? serverDetail(error) : undefined;\n const base = { status, ...(detail !== undefined ? { detail } : {}) };\n if (status === 401) {\n return {\n ...base,\n kind: \"unauthenticated\",\n title: \"Your session has ended\",\n description: \"Sign in again to continue.\",\n retryable: false,\n };\n }\n if (status === 403) {\n const what = [action, resource].filter(Boolean).join(\" \");\n return {\n ...base,\n kind: \"forbidden\",\n title: what ? `You can't ${what}` : \"You don't have access to this\",\n description: \"Your role doesn't allow it. Ask an administrator if you need access.\",\n retryable: false,\n };\n }\n if (status === 404 || status === 410) {\n return {\n ...base,\n kind: \"not-found\",\n title: resource ? `Couldn't find ${resource}` : \"Not found\",\n description: \"It may have been deleted, or it isn't available to you.\",\n retryable: false,\n };\n }\n if (status === 400 || status === 422) {\n return {\n ...base,\n kind: \"validation\",\n title: \"Some details need attention\",\n description: \"Check the highlighted fields, then try again.\",\n retryable: false,\n };\n }\n if (status === 409 || status === 412) {\n return {\n ...base,\n kind: \"conflict\",\n title: \"This changed while you were working\",\n description: \"Reload to see the latest version, then try again.\",\n retryable: false,\n };\n }\n if (status === 429) {\n return {\n ...base,\n kind: \"rate-limited\",\n title: \"Too many requests\",\n description: \"Wait a moment, then try again.\",\n retryable: true,\n };\n }\n if (status === 408 || status === 504) {\n return {\n ...base,\n kind: \"timeout\",\n title: \"The server took too long to answer\",\n description: \"Try again in a moment.\",\n retryable: true,\n };\n }\n if (status >= 500) {\n return {\n ...base,\n kind: \"server\",\n title: \"Something went wrong on our side\",\n description: \"Try again. If it keeps happening, tell the site's administrator.\",\n retryable: true,\n };\n }\n }\n if (isNetworkFailure(error)) {\n return isOffline()\n ? {\n kind: \"offline\",\n title: \"You're offline\",\n description: \"Check your connection, then try again.\",\n retryable: true,\n }\n : {\n kind: \"network\",\n title: \"Couldn't reach the server\",\n description: \"Check your connection, then try again.\",\n retryable: true,\n };\n }\n if (isTimeout(error)) {\n return {\n kind: \"timeout\",\n title: \"The request took too long\",\n description: \"Try again in a moment.\",\n retryable: true,\n };\n }\n return {\n kind: \"unknown\",\n title: action ? `Couldn't ${action}${resource ? ` ${resource}` : \"\"}` : \"Something went wrong\",\n description: \"Try again.\",\n retryable: true,\n };\n}\n\n/** `describeError(...).title`, capitalised, for one-line contexts (toasts, inline text). */\nexport function errorSummary(error: unknown, context?: KarniErrorContext): string {\n return capitalised(describeError(error, context).title);\n}\n","import * as React from \"react\";\n\n/**\n * Minimal inline SVG icons used by the primitives (no icon dependency).\n * All strokes use `currentColor`, so they follow the text color tokens.\n * Internal to @karni/ui, not part of the public barrel.\n */\n\ntype IconProps = React.SVGAttributes<SVGSVGElement>;\n\nfunction baseProps(props: IconProps): IconProps {\n return {\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n \"aria-hidden\": true,\n focusable: false,\n ...props,\n };\n}\n\nexport function CheckIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n );\n}\n\nexport function ChevronDownIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n );\n}\n\nexport function ChevronUpIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <polyline points=\"18 15 12 9 6 15\" />\n </svg>\n );\n}\n\nexport function AlertIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <path d=\"M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z\" />\n <line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\" />\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\" />\n </svg>\n );\n}\n\nexport function LockIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n );\n}\n\nexport function OfflineIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\" />\n <path d=\"M16.7 11.1A10.9 10.9 0 0 1 19 12.6M5 12.6a10.9 10.9 0 0 1 5.2-2.5M10.7 5A16 16 0 0 1 22.6 9M1.4 9a15.9 15.9 0 0 1 4.7-2.9M8.5 16.1a6 6 0 0 1 7 0\" />\n <line x1=\"12\" y1=\"20\" x2=\"12.01\" y2=\"20\" />\n </svg>\n );\n}\n\nexport function SearchIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n );\n}\n\nexport function SpinnerIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <path d=\"M21 12a9 9 0 1 1-6.2-8.6\" />\n </svg>\n );\n}\n\nexport function SunIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\n <path d=\"M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4\" />\n </svg>\n );\n}\n\nexport function MoonIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <path d=\"M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z\" />\n </svg>\n );\n}\n\nexport function MonitorIcon(props: IconProps): React.ReactElement {\n return (\n <svg {...baseProps(props)}>\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" ry=\"2\" />\n <line x1=\"8\" y1=\"21\" x2=\"16\" y2=\"21\" />\n <line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\" />\n </svg>\n );\n}\n","/**\n * The primitive registry: a project renders Karni's components with its own\n * design system's primitives.\n *\n * <KarniProvider client={client} primitives={{ button: Button, input: Input }}>\n *\n * Every Karni primitive (Button, Input, Select's parts, ...) looks itself up\n * here before rendering, so ResourceTable, ResourceForm and the rest render\n * the project's button and inputs while keeping their schema-driven\n * behaviour. A role that is not registered renders Karni's own.\n *\n * Contracts: a registered component receives exactly the props Karni's\n * primitive takes (ButtonProps, InputProps, ...) and the ref. shadcn/ui's\n * components match them as they are. Any other design system registers a\n * small adapter. `select` is a family: Radix parts share a context, so its\n * parts are replaced together or not at all.\n *\n * A registered component may wrap Karni's own (`(props) => <Button\n * className=\"...\" {...props} />`): inside it, that role resolves to Karni's\n * primitive again, so the wrapper does not call itself.\n */\nimport type * as SelectPrimitive from \"@radix-ui/react-select\";\nimport * as React from \"react\";\nimport type { ButtonProps } from \"../components/primitives/button\";\nimport type { CheckboxProps } from \"../components/primitives/checkbox\";\nimport type { InputProps } from \"../components/primitives/input\";\nimport type { LabelProps } from \"../components/primitives/label\";\nimport type { SkeletonProps } from \"../components/primitives/skeleton\";\nimport type { SwitchProps } from \"../components/primitives/switch\";\nimport type { TextareaProps } from \"../components/primitives/textarea\";\n\ntype WithRef<P, T> = React.ComponentType<P & React.RefAttributes<T>>;\n\n/** The parts of a Radix-compatible select (what shadcn/ui's select.tsx exports). */\nexport interface KarniSelectParts {\n Root: React.ComponentType<SelectPrimitive.SelectProps>;\n Trigger: WithRef<SelectPrimitive.SelectTriggerProps, HTMLButtonElement>;\n Value: WithRef<SelectPrimitive.SelectValueProps, HTMLSpanElement>;\n Content: WithRef<SelectPrimitive.SelectContentProps, HTMLDivElement>;\n Item: WithRef<SelectPrimitive.SelectItemProps, HTMLDivElement>;\n Group: WithRef<SelectPrimitive.SelectGroupProps, HTMLDivElement>;\n Label: WithRef<SelectPrimitive.SelectLabelProps, HTMLDivElement>;\n Separator: WithRef<SelectPrimitive.SelectSeparatorProps, HTMLDivElement>;\n}\n\n/** Every role a project can fill with its own component. */\nexport interface KarniPrimitives {\n button: WithRef<ButtonProps, HTMLButtonElement>;\n input: WithRef<InputProps, HTMLInputElement>;\n textarea: WithRef<TextareaProps, HTMLTextAreaElement>;\n checkbox: WithRef<CheckboxProps, HTMLButtonElement>;\n switch: WithRef<SwitchProps, HTMLButtonElement>;\n label: WithRef<LabelProps, HTMLLabelElement>;\n skeleton: WithRef<SkeletonProps, HTMLDivElement>;\n select: KarniSelectParts;\n}\n\n/** A role that is one component (not a family of parts). */\nexport type KarniPrimitiveRole = Exclude<keyof KarniPrimitives, \"select\">;\n\n/** The project's replacements: any subset of the roles. */\nexport type KarniPrimitiveOverrides = Partial<KarniPrimitives>;\n\nconst PrimitivesContext = React.createContext<KarniPrimitiveOverrides>({});\n\nexport interface KarniPrimitivesProviderProps {\n /** Role -> the project's component. Merged over any registry above it. */\n value: KarniPrimitiveOverrides;\n children?: React.ReactNode;\n}\n\n/**\n * Registers the project's primitives for everything inside it. KarniProvider\n * renders one from its `primitives` prop, and you can nest another to change\n * a subtree.\n */\nexport function KarniPrimitivesProvider({\n value,\n children,\n}: KarniPrimitivesProviderProps): React.ReactElement {\n const parent = React.useContext(PrimitivesContext);\n const merged = React.useMemo(() => ({ ...parent, ...value }), [parent, value]);\n return <PrimitivesContext.Provider value={merged}>{children}</PrimitivesContext.Provider>;\n}\n\n/** The registered primitives in scope (the roles the project replaced). */\nexport function useKarniPrimitives(): KarniPrimitiveOverrides {\n return React.useContext(PrimitivesContext);\n}\n\n/**\n * Makes a Karni primitive defer to the registry.\n * @internal\n */\nexport function overridable<P extends object, T>(\n role: KarniPrimitiveRole,\n Default: React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<T>>,\n): React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<T>> {\n const Component = React.forwardRef<T, P>((props, ref) => {\n const overrides = React.useContext(PrimitivesContext);\n // Inside the project's component this role is Karni's again (no recursion).\n const inner = React.useMemo(() => ({ ...overrides, [role]: undefined }), [overrides]);\n const Override = overrides[role] as React.ComponentType<P & React.RefAttributes<T>> | undefined;\n if (Override === undefined) return React.createElement(Default, { ...props, ref });\n return (\n <PrimitivesContext.Provider value={inner}>\n {React.createElement(Override, { ...(props as P), ref })}\n </PrimitivesContext.Provider>\n );\n });\n Component.displayName = Default.displayName;\n return Component;\n}\n\n/**\n * Makes one part of Karni's select defer to a registered `select` family.\n * @internal\n */\nexport function overridableSelectPart<\n K extends keyof KarniSelectParts,\n C extends KarniSelectParts[K],\n>(part: K, Default: C): C {\n const Component = React.forwardRef<unknown, Record<string, unknown>>((props, ref) => {\n const family = React.useContext(PrimitivesContext).select;\n const Part = (family ? family[part] : Default) as React.ComponentType<Record<string, unknown>>;\n return React.createElement(Part, part === \"Root\" ? props : { ...props, ref });\n });\n Component.displayName = `Select${part === \"Root\" ? \"Root\" : part}`;\n // Same public type as Karni's own part, so `React.ElementRef<typeof SelectTrigger>` keeps working.\n return Component as unknown as C;\n}\n","import * as React from \"react\";\nimport { overridable } from \"../../primitives/registry\";\nimport { variants, type VariantProps } from \"../../lib/variants\";\n\n/**\n * Exported for composition (escape hatch): render any element as a button\n * lookalike with `className={buttonVariants({ variant: \"outline\" })}`.\n */\nexport const buttonVariants = variants({\n base: \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary-hover\",\n destructive: \"bg-destructive text-destructive-foreground hover:bg-destructive-hover\",\n outline: \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-secondary-hover\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n});\n\nexport type ButtonVariantProps = VariantProps<typeof buttonVariants>;\n\nexport type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & ButtonVariantProps;\n\nconst KarniButton = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, type, ...props }, ref) => (\n <button\n ref={ref}\n type={type ?? \"button\"}\n className={buttonVariants({ variant, size, className })}\n {...props}\n />\n ),\n);\nKarniButton.displayName = \"Button\";\n\n/**\n * Themed button. `type` defaults to \"button\" (pass type=\"submit\" in forms).\n * `className` is merged via cn(), so consumer classes win.\n * A project replaces it with its own through `primitives={{ button: ... }}` on KarniProvider.\n */\nexport const Button = overridable<ButtonProps, HTMLButtonElement>(\"button\", KarniButton);\n","import * as React from \"react\";\n\n/** How long a request may run before Karni shows progress (ms). */\nexport const SLOW_AFTER_MS = 500;\n\n/**\n * True once `active` has stayed true for `delayMs` (default 500ms), false as\n * soon as it turns false. Show progress only for slow work, so a fast request\n * never flashes a spinner.\n */\nexport function useDelayedFlag(active: boolean, delayMs: number = SLOW_AFTER_MS): boolean {\n const [elapsed, setElapsed] = React.useState(false);\n React.useEffect(() => {\n if (!active) {\n setElapsed(false);\n return undefined;\n }\n const timer = setTimeout(() => setElapsed(true), delayMs);\n return () => clearTimeout(timer);\n }, [active, delayMs]);\n return active && elapsed;\n}\n\nfunction subscribeOnline(onChange: () => void): () => void {\n window.addEventListener(\"online\", onChange);\n window.addEventListener(\"offline\", onChange);\n return () => {\n window.removeEventListener(\"online\", onChange);\n window.removeEventListener(\"offline\", onChange);\n };\n}\n\n/** Returns whether the browser reports a network connection and re-renders when it changes. */\nexport function useOnlineStatus(): boolean {\n return React.useSyncExternalStore(\n subscribeOnline,\n () => navigator.onLine,\n () => true,\n );\n}\n","import * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { Button, type ButtonProps } from \"../components/primitives/button\";\nimport { SpinnerIcon } from \"../components/primitives/icons\";\nimport { useDelayedFlag } from \"./hooks\";\n\nexport interface PendingButtonProps extends ButtonProps {\n /** True while the action runs: the button is disabled and, after ~500ms, shows progress. */\n pending?: boolean;\n /** Announced to screen readers while pending (\"Saving…\"). */\n pendingLabel?: string;\n}\n\n/**\n * A button for work that takes time. While `pending` it is disabled and\n * `aria-busy`. Once the work is slow (500ms), a spinner covers the label,\n * which stays in the layout, so the button never changes width or freezes\n * silently. Renders the registered `button` primitive, so it follows the\n * project's design system.\n */\nexport const PendingButton = React.forwardRef<HTMLButtonElement, PendingButtonProps>(\n (\n { pending = false, pendingLabel = \"Working…\", disabled, className, children, ...props },\n ref,\n ) => {\n const slow = useDelayedFlag(pending);\n return (\n <>\n <Button\n ref={ref}\n disabled={disabled === true || pending}\n aria-busy={pending || undefined}\n className={cn(\"relative\", className)}\n {...props}\n >\n <span className={cn(\"inline-flex items-center gap-2\", slow && \"text-transparent\")}>\n {children}\n </span>\n {slow && (\n <span className=\"absolute inset-0 flex items-center justify-center\" aria-hidden=\"true\">\n <SpinnerIcon className=\"h-4 w-4 animate-spin\" />\n </span>\n )}\n </Button>\n <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {pending ? pendingLabel : \"\"}\n </span>\n </>\n );\n },\n);\nPendingButton.displayName = \"PendingButton\";\n","import * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { registerComponentRole } from \"../lib/roles\";\nimport { AlertIcon, LockIcon, OfflineIcon, SearchIcon } from \"../components/primitives/icons\";\nimport { describeError, type KarniErrorContext, type KarniErrorKind } from \"./describe-error\";\nimport { PendingButton } from \"./PendingButton\";\n\nregisterComponentRole(\"error-state\", \"ErrorState\");\nregisterComponentRole(\"permission-denied\", \"PermissionDenied\");\n\nconst ICONS: Partial<Record<KarniErrorKind, React.ComponentType<{ className?: string }>>> = {\n forbidden: LockIcon,\n unauthenticated: LockIcon,\n offline: OfflineIcon,\n network: OfflineIcon,\n \"not-found\": SearchIcon,\n};\n\nexport interface ErrorStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** What failed: a KarniApiError, a fetch failure, anything. */\n error: unknown;\n /** What the user was doing, so the message names it (\"You can't delete events\"). */\n context?: KarniErrorContext;\n /** Offered when trying again can succeed. */\n onRetry?: () => void;\n /** True while the retry runs: the button shows progress after ~500ms. */\n retrying?: boolean;\n /** More actions next to Retry (a sign-in link, \"Back to the list\"). */\n actions?: React.ReactNode;\n /** \"panel\" (a bordered block, the default) or \"inline\" (one compact row). */\n variant?: \"panel\" | \"inline\";\n}\n\n/**\n * What a component's `Error` slot receives: every Karni component that loads\n * data takes `slots={{ Error: YourPanel }}` with these props.\n */\nexport type ErrorSlotProps = Pick<ErrorStateProps, \"error\" | \"context\" | \"onRetry\" | \"retrying\">;\n\n/**\n * What failed and what to do, in plain words (see describeError). Never shows\n * a raw status code, but shows the server's own explanation when it gave one.\n * Announced to screen readers when it appears.\n */\nexport const ErrorState = React.forwardRef<HTMLDivElement, ErrorStateProps>(\n (\n { error, context, onRetry, retrying = false, actions, variant = \"panel\", className, ...props },\n ref,\n ) => {\n const described = describeError(error, context);\n const Icon = ICONS[described.kind] ?? AlertIcon;\n const retry =\n described.retryable && onRetry !== undefined ? (\n <PendingButton\n variant=\"outline\"\n size=\"sm\"\n onClick={onRetry}\n pending={retrying}\n pendingLabel=\"Trying again…\"\n >\n Try again\n </PendingButton>\n ) : null;\n const inline = variant === \"inline\";\n return (\n <div\n ref={ref}\n role=\"alert\"\n data-error-kind={described.kind}\n className={cn(\n inline\n ? \"flex flex-wrap items-center gap-2 text-sm\"\n : \"flex w-full flex-col items-center gap-2 rounded-lg border border-destructive-border bg-destructive-subtle px-6 py-8 text-center\",\n className,\n )}\n {...props}\n >\n <Icon className={cn(\"shrink-0 text-destructive\", inline ? \"h-4 w-4\" : \"mb-1 h-8 w-8\")} />\n <p className={cn(\"font-semibold text-foreground\", inline ? \"text-sm\" : \"text-base\")}>\n {described.title}\n </p>\n <p className=\"max-w-128 text-sm text-muted-foreground\">{described.description}</p>\n {described.detail !== undefined && (\n <p className=\"max-w-128 text-xs text-muted-foreground\">{described.detail}</p>\n )}\n {(retry !== null || actions !== undefined) && (\n <div className={cn(\"flex flex-wrap items-center gap-2\", !inline && \"mt-2\")}>\n {retry}\n {actions}\n </div>\n )}\n </div>\n );\n },\n);\nErrorState.displayName = \"ErrorState\";\n\nexport interface PermissionDeniedProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** The action that is not allowed: \"create\", \"delete\", \"export\". */\n action?: string;\n /** What it applies to: \"events\", \"this booking\". */\n resource?: string;\n /** Replaces the default \"Ask an administrator\" sentence. */\n description?: React.ReactNode;\n /** A way forward (\"Back to the list\"). */\n actions?: React.ReactNode;\n}\n\n/**\n * Says, in plain words, which action the user's role does not allow, both\n * on screens that know before asking the server (a role check) and after\n * a 403.\n */\nexport const PermissionDenied = React.forwardRef<HTMLDivElement, PermissionDeniedProps>(\n ({ action, resource, description, actions, className, ...props }, ref) => {\n const what = [action, resource].filter(Boolean).join(\" \");\n return (\n <div\n ref={ref}\n data-error-kind=\"forbidden\"\n className={cn(\n \"flex w-full flex-col items-center gap-2 rounded-lg border border-border bg-muted-subtle px-6 py-8 text-center\",\n className,\n )}\n {...props}\n >\n <LockIcon className=\"mb-1 h-8 w-8 text-muted-foreground\" />\n <p className=\"text-base font-semibold text-foreground\">\n {what ? `You can't ${what}` : \"You don't have access to this\"}\n </p>\n <p className=\"max-w-128 text-sm text-muted-foreground\">\n {description ?? \"Your role doesn't allow it. Ask an administrator if you need access.\"}\n </p>\n {actions !== undefined && <div className=\"mt-2 flex items-center gap-2\">{actions}</div>}\n </div>\n );\n },\n);\nPermissionDenied.displayName = \"PermissionDenied\";\n","/**\n * Light, dark or the system's choice, for the whole app.\n *\n * <ThemeProvider> // follows the system until the user picks\n * <App /> // <ThemeToggle /> anywhere lets them pick\n * </ThemeProvider>\n *\n * The choice is kept per browser (localStorage) and applied as the `dark`\n * class on <html>, which is what @karni/ui's tokens switch on. Put\n * KARNI_THEME_SCRIPT in index.html's <head> (in a Vite app, `karniTheme()`\n * from `@karni/ui/vite` does) so the first paint already has the right\n * theme (no light flash before React starts).\n */\nimport * as React from \"react\";\nimport { registerComponentRole } from \"../lib/roles\";\nimport { Button } from \"../components/primitives/button\";\nimport { MonitorIcon, MoonIcon, SunIcon } from \"../components/primitives/icons\";\nimport { THEME_STORAGE_KEY } from \"./script\";\n\nregisterComponentRole(\"theme-toggle\", \"ThemeToggle\");\n\nexport type ThemePreference = \"light\" | \"dark\" | \"system\";\nexport type ResolvedTheme = \"light\" | \"dark\";\n\nexport { KARNI_THEME_SCRIPT, THEME_STORAGE_KEY } from \"./script\";\n\ninterface ThemeContextValue {\n /** What the user chose (\"system\" follows the operating system). */\n theme: ThemePreference;\n /** What is applied right now. */\n resolvedTheme: ResolvedTheme;\n setTheme: (theme: ThemePreference) => void;\n}\n\nconst ThemeContext = React.createContext<ThemeContextValue | null>(null);\n\nconst DARK_QUERY = \"(prefers-color-scheme: dark)\";\n\nfunction readStored(key: string): ThemePreference | null {\n try {\n const value = localStorage.getItem(key);\n return value === \"light\" || value === \"dark\" || value === \"system\" ? value : null;\n } catch {\n return null;\n }\n}\n\nfunction systemTheme(): ResolvedTheme {\n return typeof matchMedia === \"function\" && matchMedia(DARK_QUERY).matches ? \"dark\" : \"light\";\n}\n\nexport interface ThemeProviderProps {\n /** Used until the user chooses, \"system\" by default. */\n defaultTheme?: ThemePreference;\n /** localStorage key for the user's choice. Change it to keep apps on one origin apart. */\n storageKey?: string;\n /** The element that gets the `dark` class, <html> by default. */\n target?: () => HTMLElement;\n children?: React.ReactNode;\n}\n\n/** Rendered once around the app, it applies the user's theme choice and keeps it. */\nexport function ThemeProvider({\n defaultTheme = \"system\",\n storageKey = THEME_STORAGE_KEY,\n target,\n children,\n}: ThemeProviderProps): React.ReactElement {\n const [theme, setThemeState] = React.useState<ThemePreference>(\n () => readStored(storageKey) ?? defaultTheme,\n );\n const [system, setSystem] = React.useState<ResolvedTheme>(systemTheme);\n\n React.useEffect(() => {\n if (typeof matchMedia !== \"function\") return undefined;\n const query = matchMedia(DARK_QUERY);\n const onChange = (): void => setSystem(query.matches ? \"dark\" : \"light\");\n query.addEventListener(\"change\", onChange);\n return () => query.removeEventListener(\"change\", onChange);\n }, []);\n\n const resolvedTheme: ResolvedTheme = theme === \"system\" ? system : theme;\n\n React.useEffect(() => {\n const element = target ? target() : document.documentElement;\n element.classList.toggle(\"dark\", resolvedTheme === \"dark\");\n element.style.colorScheme = resolvedTheme;\n }, [resolvedTheme, target]);\n\n const setTheme = React.useCallback(\n (next: ThemePreference) => {\n setThemeState(next);\n try {\n localStorage.setItem(storageKey, next);\n } catch {\n // Private windows and blocked storage: the choice lasts for this page.\n }\n },\n [storageKey],\n );\n\n const value = React.useMemo(\n () => ({ theme, resolvedTheme, setTheme }),\n [theme, resolvedTheme, setTheme],\n );\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;\n}\n\n/** Returns the theme choice and a setter, and throws a descriptive error outside ThemeProvider. */\nexport function useTheme(): ThemeContextValue {\n const value = React.useContext(ThemeContext);\n if (value === null) {\n throw new Error(\n \"useTheme must be used within <ThemeProvider>. Wrap your app in <ThemeProvider> (from @karni/ui).\",\n );\n }\n return value;\n}\n\nconst NEXT: Record<ThemePreference, ThemePreference> = {\n light: \"dark\",\n dark: \"system\",\n system: \"light\",\n};\nconst LABEL: Record<ThemePreference, string> = {\n light: \"Light\",\n dark: \"Dark\",\n system: \"System\",\n};\n\nexport interface ThemeToggleProps {\n className?: string;\n}\n\n/**\n * One button that cycles Light → Dark → System. Its accessible name says the\n * current choice and the next one (\"Theme: Dark. Switch to System\").\n */\nexport function ThemeToggle({ className }: ThemeToggleProps): React.ReactElement {\n const { theme, setTheme } = useTheme();\n const Icon = theme === \"light\" ? SunIcon : theme === \"dark\" ? MoonIcon : MonitorIcon;\n const label = `Theme: ${LABEL[theme]}. Switch to ${LABEL[NEXT[theme]]}`;\n return (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={className}\n aria-label={label}\n title={label}\n onClick={() => setTheme(NEXT[theme])}\n >\n <Icon className=\"h-4 w-4\" />\n </Button>\n );\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { overridable } from \"../../primitives/registry\";\n\nexport type InputProps = React.InputHTMLAttributes<HTMLInputElement>;\n\nconst KarniInput = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, ...props }, ref) => (\n <input\n ref={ref}\n className={cn(\n \"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-visible:ring-destructive\",\n className,\n )}\n {...props}\n />\n ),\n);\nKarniInput.displayName = \"Input\";\n\n/** Themed text input that passes every native `<input>` prop through.\n *\n * A project replaces it with its own through `primitives={{ input: ... }}` on KarniProvider.\n */\nexport const Input = overridable<InputProps, HTMLInputElement>(\"input\", KarniInput);\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { overridable } from \"../../primitives/registry\";\n\nexport type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nconst KarniTextarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, ...props }, ref) => (\n <textarea\n ref={ref}\n className={cn(\n \"flex min-h-20 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-visible:ring-destructive\",\n className,\n )}\n {...props}\n />\n ),\n);\nKarniTextarea.displayName = \"Textarea\";\n\n/** Themed multi-line text input that passes every native `<textarea>` prop through.\n *\n * A project replaces it with its own through `primitives={{ textarea: ... }}` on KarniProvider.\n */\nexport const Textarea = overridable<TextareaProps, HTMLTextAreaElement>(\"textarea\", KarniTextarea);\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\n\n/** What a screen reader says for a field that has no value. */\nexport const EMPTY_VALUE_LABEL = \"empty\";\n\nexport interface EmptyValueProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Read by screen readers in place of the dash. Default \"empty\". */\n label?: string;\n}\n\n/**\n * A field that has no value (null, \"\", an empty list), the same in every\n * Karni component: ResourceTable's cells, ResourceDetail's rows and\n * ChangeHistory's before/after values. Sighted users see a muted en dash,\n * and screen readers hear \"empty\" instead of \"dash\" or nothing.\n *\n * A field the role may not read is never rendered as empty: it has no row\n * or cell at all, so an empty value never hints that a hidden one exists.\n */\nexport const EmptyValue = React.forwardRef<HTMLSpanElement, EmptyValueProps>(\n ({ label = EMPTY_VALUE_LABEL, className, ...props }, ref) => (\n <span ref={ref} className={cn(\"text-muted-foreground\", className)} {...props}>\n <span aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">{label}</span>\n </span>\n ),\n);\nEmptyValue.displayName = \"EmptyValue\";\n","import * as SelectPrimitive from \"@radix-ui/react-select\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { overridableSelectPart } from \"../../primitives/registry\";\nimport { EmptyValue } from \"../resource/empty-value\";\nimport { CheckIcon, ChevronDownIcon, ChevronUpIcon } from \"./icons\";\n\n/**\n * The value that stands for \"nothing selected\" inside Radix Select, which reserves the empty string.\n *\n * This package maps the empty state through this sentinel at the component boundary (contract D8). Consumers of\n * the composed <Select> never see it: `value`/`onValueChange` use `null`.\n */\nexport const KARNI_SELECT_EMPTY = \"__karni_empty__\";\n\n// ---------------------------------------------------------------------------\n// Low-level styled Radix parts (escape hatch for fully custom selects)\n// ---------------------------------------------------------------------------\n\n/** Radix Select root, for composing a custom select from the styled parts. */\nexport const SelectRoot = overridableSelectPart(\"Root\", SelectPrimitive.Root);\n/** Groups related options inside `SelectContent`. */\nexport const SelectGroup = overridableSelectPart(\"Group\", SelectPrimitive.Group);\n/** Shows the selected option's label inside `SelectTrigger`. */\nexport const SelectValue = overridableSelectPart(\"Value\", SelectPrimitive.Value);\n\nconst KarniSelectTrigger = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-visible:ring-destructive [&>span]:line-clamp-1\",\n className,\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <ChevronDownIcon className=\"h-4 w-4 shrink-0 opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n));\nKarniSelectTrigger.displayName = \"SelectTrigger\";\n\n/** The styled button that opens the select.\n *\n * Part of the `select` family a project can replace (`primitives={{ select: ... }}` on KarniProvider).\n */\nexport const SelectTrigger = overridableSelectPart(\"Trigger\", KarniSelectTrigger);\n\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollUpButton\n ref={ref}\n className={cn(\"flex cursor-default items-center justify-center py-1\", className)}\n {...props}\n >\n <ChevronUpIcon className=\"h-4 w-4\" />\n </SelectPrimitive.ScrollUpButton>\n));\nSelectScrollUpButton.displayName = \"SelectScrollUpButton\";\n\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollDownButton\n ref={ref}\n className={cn(\"flex cursor-default items-center justify-center py-1\", className)}\n {...props}\n >\n <ChevronDownIcon className=\"h-4 w-4\" />\n </SelectPrimitive.ScrollDownButton>\n));\nSelectScrollDownButton.displayName = \"SelectScrollDownButton\";\n\nconst KarniSelectContent = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>\n>(({ className, children, position = \"popper\", ...props }, ref) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n position={position}\n className={cn(\n \"relative z-popover max-h-96 min-w-32 overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md\",\n position === \"popper\" &&\n \"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\",\n className,\n )}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n \"p-1\",\n position === \"popper\" &&\n \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]\",\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n));\nKarniSelectContent.displayName = \"SelectContent\";\n\n/** The styled dropdown panel that lists the options.\n *\n * Part of the `select` family a project can replace (`primitives={{ select: ... }}` on KarniProvider).\n */\nexport const SelectContent = overridableSelectPart(\"Content\", KarniSelectContent);\n\nconst KarniSelectLabel = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Label\n ref={ref}\n className={cn(\"py-1.5 pl-8 pr-2 text-sm font-semibold\", className)}\n {...props}\n />\n));\nKarniSelectLabel.displayName = \"SelectLabel\";\n\n/** A heading inside a `SelectGroup`.\n *\n * Part of the `select` family a project can replace (`primitives={{ select: ... }}` on KarniProvider).\n */\nexport const SelectLabel = overridableSelectPart(\"Label\", KarniSelectLabel);\n\nconst KarniSelectItem = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <CheckIcon className=\"h-4 w-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n));\nKarniSelectItem.displayName = \"SelectItem\";\n\n/** One selectable option, whose `value` is what the select reports.\n *\n * Part of the `select` family a project can replace (`primitives={{ select: ... }}` on KarniProvider).\n */\nexport const SelectItem = overridableSelectPart(\"Item\", KarniSelectItem);\n\nconst KarniSelectSeparator = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\n {...props}\n />\n));\nKarniSelectSeparator.displayName = \"SelectSeparator\";\n\n/** A divider line between option groups.\n *\n * Part of the `select` family a project can replace (`primitives={{ select: ... }}` on KarniProvider).\n */\nexport const SelectSeparator = overridableSelectPart(\"Separator\", KarniSelectSeparator);\n\n// ---------------------------------------------------------------------------\n// Composed, options-driven Select (what ResourceForm / the filter bar use)\n// ---------------------------------------------------------------------------\n\nexport interface SelectOption {\n /** Must be non-empty and not the reserved sentinel. */\n value: string;\n label: React.ReactNode;\n disabled?: boolean;\n}\n\nexport interface SelectProps {\n /** `null`/`\"\"`/`undefined` all mean \"no selection\". */\n value: string | null | undefined;\n /** Receives `null` when the clear item is chosen, else the option value. */\n onValueChange?: (value: string | null) => void;\n options: readonly SelectOption[];\n placeholder?: React.ReactNode;\n /**\n * Renders a clear item at the top of the list (contract D8): pass it for\n * nullable fields (labelled with `EmptyValue` by default, a dash read as\n * \"empty\") and filter contexts (e.g. \"All\").\n * Choosing it emits `null`.\n */\n clearable?: boolean;\n clearLabel?: React.ReactNode;\n disabled?: boolean;\n /** Forwarded to the hidden native select for HTML form submission. */\n name?: string;\n id?: string;\n /** Merged onto the trigger. */\n className?: string;\n contentClassName?: string;\n \"aria-label\"?: string;\n /** Forwarded to the trigger, like the other `aria-*` props below. */\n \"aria-labelledby\"?: string;\n /** Ids of the help text and error message that describe the field. */\n \"aria-describedby\"?: string;\n /** Marks the field invalid: the trigger reads it and draws its destructive border. */\n \"aria-invalid\"?: React.AriaAttributes[\"aria-invalid\"];\n \"aria-required\"?: boolean | \"true\" | \"false\";\n /**\n * Called when focus leaves the select, never when it moves into the open\n * list, so react-hook-form's onBlur validation does not run while the user\n * is still choosing.\n */\n onBlur?: React.FocusEventHandler<HTMLButtonElement>;\n /** Called when the list opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /** Extra <SelectItem>/<SelectGroup> nodes appended after `options` (escape hatch). */\n children?: React.ReactNode;\n}\n\n/**\n * Styled select for a list of `options`, with `null` for no selection. Maps the\n * empty state through the KARNI_SELECT_EMPTY sentinel so `\"\"` never reaches\n * Radix (D8). For fully custom composition use SelectRoot/SelectTrigger/\n * SelectContent/SelectItem directly.\n */\nexport const Select = React.forwardRef<HTMLButtonElement, SelectProps>((props, ref) => {\n const {\n value,\n onValueChange,\n options,\n placeholder,\n clearable = false,\n clearLabel = <EmptyValue />,\n disabled,\n name,\n id,\n className,\n contentClassName,\n children,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": ariaInvalid,\n \"aria-required\": ariaRequired,\n onBlur,\n onOpenChange,\n } = props;\n const openRef = React.useRef(false);\n\n const safeOptions = React.useMemo(() => {\n const filtered = options.filter(\n (option) => option.value !== \"\" && option.value !== KARNI_SELECT_EMPTY,\n );\n if (filtered.length !== options.length) {\n console.warn(\n `[karni-ui] <Select> option values \"\" and \"${KARNI_SELECT_EMPTY}\" are reserved, so those options were dropped. Use the \\`clearable\\` prop for an empty choice.`,\n );\n }\n return filtered;\n }, [options]);\n\n const isEmpty = value == null || value === \"\";\n // With a clear item present, the sentinel is a real Radix value, so the\n // trigger shows the clear label and the item renders checked. Without one,\n // \"\" makes Radix show the placeholder.\n const radixValue = isEmpty ? (clearable ? KARNI_SELECT_EMPTY : \"\") : value;\n\n const handleValueChange = React.useCallback(\n (next: string) => {\n onValueChange?.(next === KARNI_SELECT_EMPTY ? null : next);\n },\n [onValueChange],\n );\n\n return (\n <SelectRoot\n value={radixValue}\n onValueChange={handleValueChange}\n onOpenChange={(open) => {\n openRef.current = open;\n onOpenChange?.(open);\n }}\n disabled={disabled}\n name={name}\n >\n <SelectTrigger\n ref={ref}\n id={id}\n className={className}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={ariaDescribedBy}\n aria-invalid={ariaInvalid}\n aria-required={ariaRequired}\n onBlur={(event) => {\n // Opening moves focus into the list: that is not leaving the field.\n if (openRef.current) return;\n const next = event.relatedTarget;\n if (next instanceof Element && next.closest(\"[role='listbox']\") !== null) return;\n onBlur?.(event);\n }}\n >\n <SelectValue placeholder={placeholder} />\n </SelectTrigger>\n <SelectContent className={contentClassName}>\n {clearable ? (\n <SelectItem value={KARNI_SELECT_EMPTY} className=\"text-muted-foreground\">\n {clearLabel}\n </SelectItem>\n ) : null}\n {safeOptions.map((option) => (\n <SelectItem key={option.value} value={option.value} disabled={option.disabled}>\n {option.label}\n </SelectItem>\n ))}\n {children}\n </SelectContent>\n </SelectRoot>\n );\n});\nSelect.displayName = \"Select\";\n","import * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { overridable } from \"../../primitives/registry\";\nimport { CheckIcon } from \"./icons\";\n\nexport type CheckboxProps = React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>;\n\nconst KarniCheckbox = React.forwardRef<\n React.ElementRef<typeof CheckboxPrimitive.Root>,\n CheckboxProps\n>(({ className, ...props }, ref) => (\n <CheckboxPrimitive.Root\n ref={ref}\n className={cn(\n \"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-visible:ring-destructive\",\n className,\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator className=\"flex items-center justify-center text-current\">\n <CheckIcon className=\"h-3.5 w-3.5\" />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n));\nKarniCheckbox.displayName = \"Checkbox\";\n\n/** Themed checkbox (Radix Checkbox) with a check mark indicator.\n *\n * A project replaces it with its own through `primitives={{ checkbox: ... }}` on KarniProvider.\n */\nexport const Checkbox = overridable<CheckboxProps, HTMLButtonElement>(\"checkbox\", KarniCheckbox);\n","import * as SwitchPrimitive from \"@radix-ui/react-switch\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { overridable } from \"../../primitives/registry\";\n\nexport type SwitchProps = React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root>;\n\nconst KarniSwitch = React.forwardRef<React.ElementRef<typeof SwitchPrimitive.Root>, SwitchProps>(\n ({ className, ...props }, ref) => (\n <SwitchPrimitive.Root\n ref={ref}\n className={cn(\n \"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input aria-[invalid=true]:ring-2 aria-[invalid=true]:ring-destructive aria-[invalid=true]:ring-offset-2 aria-[invalid=true]:ring-offset-background\",\n className,\n )}\n {...props}\n >\n <SwitchPrimitive.Thumb className=\"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0\" />\n </SwitchPrimitive.Root>\n ),\n);\nKarniSwitch.displayName = \"Switch\";\n\n/** Themed on/off toggle (Radix Switch).\n *\n * A project replaces it with its own through `primitives={{ switch: ... }}` on KarniProvider.\n */\nexport const Switch = overridable<SwitchProps, HTMLButtonElement>(\"switch\", KarniSwitch);\n","import * as LabelPrimitive from \"@radix-ui/react-label\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { overridable } from \"../../primitives/registry\";\n\nexport type LabelProps = React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>;\n\nconst KarniLabel = React.forwardRef<React.ElementRef<typeof LabelPrimitive.Root>, LabelProps>(\n ({ className, ...props }, ref) => (\n <LabelPrimitive.Root\n ref={ref}\n className={cn(\n \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\",\n className,\n )}\n {...props}\n />\n ),\n);\nKarniLabel.displayName = \"Label\";\n\n/** Themed form label (Radix Label) that dims when its field is disabled.\n *\n * A project replaces it with its own through `primitives={{ label: ... }}` on KarniProvider.\n */\nexport const Label = overridable<LabelProps, HTMLLabelElement>(\"label\", KarniLabel);\n","import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\n\n/** Tab set root (Radix Tabs) that holds the selected value. */\nexport const Tabs = TabsPrimitive.Root;\n\n/** The row of tab buttons. */\nexport const TabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.List\n ref={ref}\n className={cn(\n \"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground\",\n className,\n )}\n {...props}\n />\n));\nTabsList.displayName = \"TabsList\";\n\n/** One tab button, whose `value` names the panel it opens. */\nexport const TabsTrigger = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm\",\n className,\n )}\n {...props}\n />\n));\nTabsTrigger.displayName = \"TabsTrigger\";\n\n/** The panel shown while its `value` is the selected tab. */\nexport const TabsContent = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Content\n ref={ref}\n className={cn(\n \"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n className,\n )}\n {...props}\n />\n));\nTabsContent.displayName = \"TabsContent\";\n","import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { CheckIcon } from \"./icons\";\n\n/** Dropdown menu root (Radix DropdownMenu). */\nexport const DropdownMenu = DropdownMenuPrimitive.Root;\n/** The element that opens the menu. */\nexport const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n/** Groups related menu items. */\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\n/** Renders the menu into `document.body`. */\nexport const DropdownMenuPortal = DropdownMenuPrimitive.Portal;\n\n/** The styled menu panel. */\nexport const DropdownMenuContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-popover min-w-32 overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md\",\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = \"DropdownMenuContent\";\n\n/** One menu item, whose `onSelect` runs the action. */\nexport const DropdownMenuItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n inset && \"pl-8\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuItem.displayName = \"DropdownMenuItem\";\n\n/** A menu item with a check mark that toggles `checked`. */\nexport const DropdownMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n checked={checked}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon className=\"h-4 w-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName = \"DropdownMenuCheckboxItem\";\n\n/** A non-interactive heading inside the menu. */\nexport const DropdownMenuLabel = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\"px-2 py-1.5 text-sm font-semibold\", inset && \"pl-8\", className)}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = \"DropdownMenuLabel\";\n\n/** A divider line between menu items. */\nexport const DropdownMenuSeparator = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = \"DropdownMenuSeparator\";\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { overridable } from \"../../primitives/registry\";\n\nexport type SkeletonProps = React.HTMLAttributes<HTMLDivElement>;\n\nconst KarniSkeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"animate-pulse rounded-md bg-muted\", className)} {...props} />\n ),\n);\nKarniSkeleton.displayName = \"Skeleton\";\n\n/** Loading placeholder block that you size with width/height utility classes.\n *\n * A project replaces it with its own through `primitives={{ skeleton: ... }}` on KarniProvider.\n */\nexport const Skeleton = overridable<SkeletonProps, HTMLDivElement>(\"skeleton\", KarniSkeleton);\n","/**\n * Query-param construction and key normalization for the resource hooks\n * (contract \"Hooks\" + D4).\n *\n * `buildListQuery` / `buildItemQuery` turn the typed param objects into the\n * flat record that is sent to the backend (page → `page`, pageSize →\n * `page_size`, expand → comma-joined per api contract B9, filters spread\n * flat). `normalizeParams` produces the canonical representation used inside\n * query keys (D4): undefined/null dropped, keys sorted recursively, values\n * stringified exactly as they hit the query string, so two call sites that\n * describe the same request always share one cache entry.\n *\n * Internal module: not re-exported from the barrel.\n */\nimport type { FilterValue, ResourceItemParams, ResourceListParams } from \"./types\";\n\n/** Canonical param value shape stored inside query keys (D4). */\nexport type NormalizedParamValue = string | readonly string[] | NormalizedParams;\nexport type NormalizedParams = { readonly [key: string]: NormalizedParamValue };\n\nfunction stringifyScalar(value: string | number | boolean): string {\n return typeof value === \"string\" ? value : String(value);\n}\n\nfunction isScalarArray(value: FilterValue): value is ReadonlyArray<string | number | boolean> {\n return Array.isArray(value);\n}\n\n/**\n * Flattens ResourceListParams into the query record sent to the server.\n * Explicit params win over a `filters` entry of the same name. Empty\n * `search`/`ordering` strings and empty `expand` arrays are omitted (they\n * describe \"no constraint\", and sending them would fragment the cache).\n */\nexport function buildListQuery(\n params?: ResourceListParams,\n): Record<string, string | readonly string[]> {\n const query: Record<string, string | readonly string[]> = {};\n if (params === undefined) return query;\n\n if (params.filters !== undefined) {\n for (const [key, value] of Object.entries(params.filters)) {\n if (value === null || value === undefined) continue;\n if (isScalarArray(value)) {\n if (value.length > 0) query[key] = value.map(stringifyScalar);\n } else {\n query[key] = stringifyScalar(value);\n }\n }\n }\n\n if (params.page !== undefined) query.page = String(params.page);\n if (params.pageSize !== undefined) query.page_size = String(params.pageSize);\n if (params.ordering !== undefined && params.ordering !== \"\") query.ordering = params.ordering;\n if (params.search !== undefined && params.search !== \"\") query.search = params.search;\n if (params.expand !== undefined && params.expand.length > 0) {\n query.expand = params.expand.join(\",\");\n }\n return query;\n}\n\n/** Detail requests only carry `expand` (api contract B9). */\nexport function buildItemQuery(params?: ResourceItemParams): Record<string, string> {\n const query: Record<string, string> = {};\n if (params?.expand !== undefined && params.expand.length > 0) {\n query.expand = params.expand.join(\",\");\n }\n return query;\n}\n\n/**\n * D4 normalization: drop undefined/null, sort keys recursively, stringify\n * values as they hit the query string. The result is what `karniKeys` embeds\n * in list keys.\n */\nexport function normalizeParams(value: Record<string, unknown>): NormalizedParams {\n const out: Record<string, NormalizedParamValue> = {};\n for (const key of Object.keys(value).sort()) {\n const normalized = normalizeValue(value[key]);\n if (normalized !== undefined) out[key] = normalized;\n }\n return out;\n}\n\nfunction normalizeValue(value: unknown): NormalizedParamValue | undefined {\n if (value === null || value === undefined) return undefined;\n if (Array.isArray(value)) {\n return (value as readonly unknown[])\n .filter((item) => item !== null && item !== undefined)\n .map((item) =>\n typeof item === \"object\" && item !== null ? JSON.stringify(item) : String(item),\n );\n }\n if (typeof value === \"object\") {\n return normalizeParams(value as Record<string, unknown>);\n }\n return String(value);\n}\n\n/** `/events/` for resource \"events\" (the DRF router prefix, api B13). */\nexport function listPath(resource: string): string {\n const trimmed = resource.replace(/^\\/+|\\/+$/g, \"\");\n return `/${trimmed}/`;\n}\n\n/** `/events/5/`. Ids are encoded so UUIDs and slugs are safe. */\nexport function detailPath(resource: string, id: string | number): string {\n return `${listPath(resource)}${encodeURIComponent(String(id))}/`;\n}\n","/**\n * Query-key factory for every cache entry @karni/ui creates (contract D4).\n *\n * Key shapes:\n * - `[\"karni\", \"$schema\"]`: the parsed OpenAPI schema (staleTime Infinity).\n * - `[\"karni\", resource]`: the invalidation root for one resource.\n * - `[\"karni\", resource, \"list\", normalizedParams]`: one list page.\n * - `[\"karni\", resource, \"detail\", String(id)]`: one item. When the item was\n * fetched with params (e.g. `expand`), the normalized params are appended as\n * a fifth element so differently-shaped payloads never share a cache entry.\n * Prefix invalidation via `karniKeys.resource(...)` still reaches them.\n *\n * Use this factory for any manual cache work (`setQueryData`,\n * `invalidateQueries`, prefetching) so your keys and the library's keys never\n * drift.\n *\n * NEVER invalidate the bare `[\"karni\"]` root: it would also blow away the\n * schema entry (`[\"karni\", \"$schema\"]`), refetching and re-parsing the whole\n * OpenAPI document. Invalidate `karniKeys.resource(resource)` instead. The\n * `\"$\"` prefix guarantees the schema key can never collide with a real\n * resource name (DRF router prefixes cannot contain `$`).\n */\nimport { buildItemQuery, buildListQuery, normalizeParams } from \"./params\";\nimport type { ResourceItemParams, ResourceListParams } from \"./types\";\n\n/** TanStack Query keys for the schema, a resource, its lists and its items (invalidate `karniKeys.resource(name)` to refresh every view of a resource). */\nexport const karniKeys = {\n /** Cache key of the parsed OpenAPI schema document. */\n schema(): readonly unknown[] {\n return [\"karni\", \"$schema\"] as const;\n },\n\n /**\n * The invalidation root for one resource. Every list and detail key of\n * `resource` lives under this prefix.\n */\n resource(resource: string): readonly unknown[] {\n return [\"karni\", resource] as const;\n },\n\n /**\n * Key for one list page. Params are normalized (D4): undefined/null\n * dropped, keys sorted recursively, values stringified as they hit the\n * query string, so `{search: \"x\", page: 2}` and `{page: 2, search: \"x\"}`\n * share one entry.\n */\n list(resource: string, params?: ResourceListParams): readonly unknown[] {\n return [\"karni\", resource, \"list\", normalizeParams(buildListQuery(params))] as const;\n },\n\n /**\n * Key for one item. The id is always stringified, so `detail(\"events\", 5)`\n * and `detail(\"events\", \"5\")` share one entry. Params (expand) append a\n * normalized fifth element (see the module docs).\n */\n detail(resource: string, id: string | number, params?: ResourceItemParams): readonly unknown[] {\n const query = buildItemQuery(params);\n if (Object.keys(query).length > 0) {\n return [\"karni\", resource, \"detail\", String(id), normalizeParams(query)] as const;\n }\n return [\"karni\", resource, \"detail\", String(id)] as const;\n },\n};\n","/**\n * <KarniProvider> wires the Karni client into React (contract \"Schema\n * client\"). Wraps TanStack's QueryClientProvider, creating a QueryClient when\n * none is given (the `queryClient` prop is the escape hatch for apps that\n * already have one), and provides the client via context for every hook and\n * component in the package.\n */\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { createContext, useContext, useState } from \"react\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { KarniPrimitivesProvider, type KarniPrimitiveOverrides } from \"../primitives/registry\";\nimport type { KarniClient } from \"./client\";\n\nconst KarniClientContext = createContext<KarniClient | null>(null);\n\nexport interface KarniProviderProps {\n client: KarniClient;\n /** Bring your own QueryClient. One is created (once) when omitted. */\n queryClient?: QueryClient;\n /**\n * The project's own primitives, by role: `{ button: Button, input: Input }`.\n * Every Karni component then renders them in place of Karni's (see\n * KarniPrimitivesProvider for the contract).\n */\n primitives?: KarniPrimitiveOverrides;\n children?: ReactNode;\n}\n\nconst NO_PRIMITIVES: KarniPrimitiveOverrides = {};\n\n/** Rendered once at the app root, it provides the Karni client and a TanStack QueryClient to everything inside it. */\nexport function KarniProvider(props: KarniProviderProps): ReactElement {\n const { client, queryClient, primitives = NO_PRIMITIVES, children } = props;\n // Lazy initial state so the fallback QueryClient is created exactly once\n // per provider instance, never on re-renders.\n const [ownQueryClient] = useState(() => queryClient ?? new QueryClient());\n return (\n <QueryClientProvider client={queryClient ?? ownQueryClient}>\n <KarniClientContext.Provider value={client}>\n <KarniPrimitivesProvider value={primitives}>{children}</KarniPrimitivesProvider>\n </KarniClientContext.Provider>\n </QueryClientProvider>\n );\n}\n\n/** Returns the Karni client from `KarniProvider` and throws a descriptive error outside one. */\nexport function useKarniClient(): KarniClient {\n const client = useContext(KarniClientContext);\n if (client === null) {\n throw new Error(\n \"useKarniClient must be used within <KarniProvider>. \" +\n \"Wrap your app in <KarniProvider client={createKarniClient({ baseUrl })}>.\",\n );\n }\n return client;\n}\n","/**\n * The non-React auth core (contract \"Hooks + auth\" + D6). The client side\n * owns tokens and refresh. <AuthProvider> merely mirrors this engine's state\n * into React.\n *\n * The engine registers itself on the KarniClient via its D6 hook points\n * (`setAuthHooks`): access-token injection, extra headers (session CSRF),\n * credentials mode, and the 401 handler. EVERY request made through the\n * client (resource hooks, schema loading, custom calls) therefore carries\n * credentials and takes part in the refresh flow, with no per-callsite\n * wiring.\n *\n * ## JWT mode (D6)\n * - The access token lives in memory only. The refresh token lives in the\n * pluggable TokenStorage (localStorage by default).\n * - On a 401 the client calls `onUnauthorized` (at most once per request):\n * the engine runs ONE shared in-flight refresh (`POST\n * <authBasePath>/refresh/`), and every concurrent 401 awaits the same\n * promise. A rotated refresh token is persisted BEFORE that promise\n * resolves, so queued retries can never observe the stale token. The\n * client then retries each request exactly once. A request that 401s\n * AFTER a successful refresh is surfaced and never re-triggers refresh.\n * - Refresh failure clears the storage and flips the engine to \"anonymous\".\n * The original 401s surface to the queued callers.\n * - The engine's own auth calls (login/refresh/me/logout/csrf) set\n * `skipAuthRefresh`, so a 401 from them can never recurse into another\n * refresh. During a refresh the in-memory access token is nulled, so the\n * refresh request itself never carries a stale Bearer header (which would\n * trip DRF authentication/throttling before the view runs).\n * - Multi-tab: tabs do not coordinate (documented limitation). With\n * refresh-token rotation + blacklisting, a refresh in tab A can invalidate\n * the token tab B just read, logging tab B out on its next refresh.\n * Storage events are intentionally not consumed in v0.1.\n *\n * ## Session mode (A4)\n * Django's session cookie authenticates requests. The engine registers\n * `credentials: \"include\"` and a header hook that mirrors the CSRF cookie\n * (\"csrftoken\") into the CSRF header (\"X-CSRFToken\"). A4 pins both names,\n * and both are overridable. When the cookie is absent it is bootstrapped via\n * `GET <authBasePath>/csrf/` (204 + ensure_csrf_cookie) during initialization\n * and before login. Cross-origin note: `credentials: \"include\"` is only\n * registered once the mode is known. Pass `mode=\"session\"` to\n * <AuthProvider> (skipping async schema detection) so the very first\n * requests already include cookies.\n *\n * ## Mode resolution\n * `modeOverride` prop → cached parsed schema (`authMode`) → the schema\n * document's root `x-karni-auth-mode` (api B14) → \"jwt\".\n *\n * Internal module: not re-exported from the barrel.\n */\nimport type { KarniClient } from \"../schema/client\";\nimport type { TokenStorage } from \"./storage\";\nimport type { AuthStatus, KarniUser, LoginResult } from \"./types\";\n\nexport type AuthMode = \"jwt\" | \"session\";\n\nexport interface AuthEngineOptions {\n client: KarniClient;\n tokenStorage: TokenStorage;\n /** Skips schema-based mode detection entirely when set. */\n modeOverride?: AuthMode;\n /** Session-mode CSRF cookie name (A4 pin). Default \"csrftoken\". */\n csrfCookieName?: string;\n /** Session-mode CSRF header name (A4 pin). Default \"X-CSRFToken\". */\n csrfHeaderName?: string;\n /** Path prefix of the auth endpoints, relative to the client's baseUrl. */\n authBasePath?: string;\n /**\n * Reads whatever the schema loader cached under karniKeys.schema(). The\n * engine consults it (shape-guarded) for `authMode` before fetching the\n * document.\n */\n readCachedSchema?: () => unknown;\n}\n\nexport interface AuthSnapshot {\n readonly status: AuthStatus;\n readonly user: KarniUser | null;\n readonly mode: AuthMode | null;\n}\n\n/**\n * Reads the auth mode out of either a ParsedSchema (`authMode`) or a raw\n * OpenAPI document (root `x-karni-auth-mode`), shape-guarded.\n */\nexport function readAuthMode(value: unknown): AuthMode | undefined {\n if (typeof value !== \"object\" || value === null) return undefined;\n const record = value as Record<string, unknown>;\n const candidate = record[\"authMode\"] ?? record[\"x-karni-auth-mode\"];\n return candidate === \"jwt\" || candidate === \"session\" ? candidate : undefined;\n}\n\n/** Validates/normalizes a `me` payload into a KarniUser (roles default []). */\nexport function normalizeUser(value: unknown): KarniUser | null {\n if (typeof value !== \"object\" || value === null) return null;\n const record = value as Record<string, unknown>;\n const { id, email } = record;\n if (typeof id !== \"string\" && typeof id !== \"number\") return null;\n if (typeof email !== \"string\") return null;\n const roles = Array.isArray(record.roles)\n ? record.roles.filter((role): role is string => typeof role === \"string\")\n : [];\n return { ...record, id, email, roles };\n}\n\nfunction readCookie(name: string): string | null {\n if (typeof document === \"undefined\") return null;\n try {\n for (const part of document.cookie.split(\";\")) {\n const trimmed = part.trim();\n const separator = trimmed.indexOf(\"=\");\n if (separator === -1) continue;\n if (trimmed.slice(0, separator) === name) {\n return decodeURIComponent(trimmed.slice(separator + 1));\n }\n }\n } catch {\n // Cookie access can throw in sandboxed documents.\n }\n return null;\n}\n\nfunction describeShape(value: unknown): string {\n if (typeof value !== \"object\" || value === null) return `a ${typeof value}`;\n const keys = Object.keys(value);\n return keys.length === 0 ? \"an empty object\" : `an object with keys [${keys.join(\", \")}]`;\n}\n\nfunction read2fa(value: unknown): { ephemeralToken: string } | null {\n if (typeof value !== \"object\" || value === null) return null;\n const record = value as Record<string, unknown>;\n if (record.requires_2fa !== true) return null;\n return typeof record.ephemeral_token === \"string\"\n ? { ephemeralToken: record.ephemeral_token }\n : null;\n}\n\nexport class AuthEngine {\n private readonly client: KarniClient;\n private readonly tokenStorage: TokenStorage;\n private readonly modeOverride: AuthMode | undefined;\n private readonly csrfCookieName: string;\n private readonly csrfHeaderName: string;\n private readonly authBasePath: string;\n private readonly readCachedSchema: (() => unknown) | undefined;\n\n private mode: AuthMode | null;\n private accessToken: string | null = null;\n private refreshPromise: Promise<boolean> | null = null;\n private initPromise: Promise<void> | null = null;\n private readonly listeners = new Set<() => void>();\n private state: AuthSnapshot;\n\n constructor(options: AuthEngineOptions) {\n this.client = options.client;\n this.tokenStorage = options.tokenStorage;\n this.modeOverride = options.modeOverride;\n this.csrfCookieName = options.csrfCookieName ?? \"csrftoken\";\n this.csrfHeaderName = options.csrfHeaderName ?? \"X-CSRFToken\";\n this.authBasePath = (options.authBasePath ?? \"/auth\").replace(/\\/+$/, \"\");\n this.readCachedSchema = options.readCachedSchema;\n this.mode = options.modeOverride ?? null;\n this.state = { status: \"loading\", user: null, mode: this.mode };\n // Register the hook points during construction (render phase), not in an\n // effect: children of <AuthProvider> fire their first queries from\n // effects that run BEFORE the parent's own effects, and those requests\n // must already flow through the auth machinery.\n this.attach();\n }\n\n // client hook registration\n\n /** Registers the D6 hook points on the client. Idempotent. */\n attach(): void {\n this.client.setAuthHooks({\n getAccessToken: () => this.accessToken,\n onUnauthorized: () => this.handleUnauthorized(),\n getHeaders: () => this.csrfHeaders(),\n ...(this.mode === \"session\" ? { credentials: \"include\" as RequestCredentials } : {}),\n });\n }\n\n /**\n * Clears every hook this engine registered, including a `getAccessToken`\n * the app passed to createKarniClient. An unmounted AuthProvider leaves\n * the client fully unauthenticated by design.\n */\n detach(): void {\n this.client.setAuthHooks({\n getAccessToken: undefined,\n onUnauthorized: undefined,\n getHeaders: undefined,\n credentials: undefined,\n });\n }\n\n private csrfHeaders(): Record<string, string> {\n if (this.mode !== \"session\") return {};\n const token = readCookie(this.csrfCookieName);\n return token === null ? {} : { [this.csrfHeaderName]: token };\n }\n\n /**\n * The client calls this at most once per 401-ing request (D6). Returning\n * true makes the client retry that request exactly once with\n * freshly-injected credentials. The retry's outcome is always surfaced.\n */\n private async handleUnauthorized(): Promise<boolean> {\n await this.ensureInitialized();\n if (this.mode !== \"jwt\") {\n // The session evaporated server-side; mirror it.\n if (this.state.status === \"authenticated\") this.setState(\"anonymous\", null);\n return false;\n }\n if (this.tokenStorage.get() === null) return false;\n return this.ensureRefresh();\n }\n\n // --- state mirroring (consumed by <AuthProvider> via useSyncExternalStore)\n\n readonly subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n readonly getSnapshot = (): AuthSnapshot => this.state;\n\n private setState(status: AuthStatus, user: KarniUser | null): void {\n this.state = { status, user, mode: this.mode };\n for (const listener of this.listeners) listener();\n }\n\n // bootstrap\n\n /** Idempotent: the first call kicks off mode resolution + session restore. */\n ensureInitialized(): Promise<void> {\n this.initPromise ??= this.initialize();\n return this.initPromise;\n }\n\n private async initialize(): Promise<void> {\n try {\n this.mode =\n this.modeOverride ??\n readAuthMode(this.readCachedSchema?.()) ??\n (await this.fetchSchemaAuthMode()) ??\n \"jwt\";\n if (this.mode === \"session\") {\n this.client.setAuthHooks({ credentials: \"include\" });\n await this.ensureCsrfToken(); // A4: bootstrap the cookie when absent.\n await this.syncUser();\n return;\n }\n if (this.tokenStorage.get() === null) {\n this.setState(\"anonymous\", null);\n return;\n }\n const refreshed = await this.ensureRefresh();\n if (!refreshed) return; // performRefresh already cleared + emitted.\n await this.syncUser();\n } catch {\n this.setState(\"anonymous\", null);\n }\n }\n\n private async fetchSchemaAuthMode(): Promise<AuthMode | undefined> {\n try {\n // joinUrl never double-prefixes, so passing the absolute schema path is\n // safe with any baseUrl; the client's accept header selects JSON.\n const document = await this.client.request<unknown>(this.client.schemaUrl, {\n skipAuthRefresh: true,\n });\n return readAuthMode(document);\n } catch {\n return undefined;\n }\n }\n\n /** Fetches `/me/` and mirrors the result. Any failure means anonymous. */\n private async syncUser(): Promise<void> {\n try {\n const data = await this.client.request<unknown>(`${this.authBasePath}/me/`, {\n skipAuthRefresh: true,\n });\n const user = normalizeUser(data);\n if (user === null) {\n this.setState(\"anonymous\", null);\n } else {\n this.setState(\"authenticated\", user);\n }\n } catch {\n this.setState(\"anonymous\", null);\n }\n }\n\n /**\n * Reads the CSRF cookie, bootstrapping it via `GET <authBasePath>/csrf/`\n * when absent (A4). Returns null when the cookie stays unreadable (e.g.\n * CSRF_COOKIE_HTTPONLY). Requests then go out without the header and the\n * backend's 403 surfaces, which is the honest failure mode.\n */\n private async ensureCsrfToken(): Promise<string | null> {\n let token = readCookie(this.csrfCookieName);\n if (token === null) {\n try {\n await this.client.request<unknown>(`${this.authBasePath}/csrf/`, {\n method: \"GET\",\n skipAuthRefresh: true,\n });\n } catch {\n // Bootstrap is best-effort; the cookie re-read below decides.\n }\n token = readCookie(this.csrfCookieName);\n }\n return token;\n }\n\n // refresh (D6)\n\n /** ONE shared in-flight refresh. Resolves true on success. */\n private ensureRefresh(): Promise<boolean> {\n if (this.refreshPromise === null) {\n this.refreshPromise = this.performRefresh().finally(() => {\n this.refreshPromise = null;\n });\n }\n return this.refreshPromise;\n }\n\n private async performRefresh(): Promise<boolean> {\n const refreshToken = this.tokenStorage.get();\n if (refreshToken === null) {\n this.accessToken = null;\n this.setState(\"anonymous\", null);\n return false;\n }\n // Null the stale access token for the duration of the refresh so the\n // refresh request itself (and anything racing it) never carries a Bearer\n // header the backend would reject before reaching the view.\n this.accessToken = null;\n try {\n const data = await this.client.request<unknown>(`${this.authBasePath}/refresh/`, {\n method: \"POST\",\n body: { refresh: refreshToken },\n skipAuthRefresh: true, // a 401 here can never recurse (D6)\n });\n const record =\n typeof data === \"object\" && data !== null ? (data as Record<string, unknown>) : {};\n const access = record.access;\n if (typeof access !== \"string\" || access === \"\") {\n throw new Error(\n `Karni auth: ${this.authBasePath}/refresh/ returned ${describeShape(data)} ` +\n \"instead of { access, refresh? }.\",\n );\n }\n // Persist the rotated refresh token BEFORE this promise resolves, so\n // every queued 401 retry runs against the rotated token (D6).\n const rotated = record.refresh;\n if (typeof rotated === \"string\" && rotated !== \"\") {\n this.tokenStorage.set(rotated);\n }\n this.accessToken = access;\n return true;\n } catch {\n this.tokenStorage.clear();\n this.accessToken = null;\n this.setState(\"anonymous\", null);\n return false;\n }\n }\n\n // public auth actions\n\n async login(email: string, password: string): Promise<LoginResult> {\n await this.ensureInitialized();\n const path = `${this.authBasePath}/login/`;\n if (this.mode === \"session\") {\n await this.ensureCsrfToken(); // header rides in via the getHeaders hook\n const data = await this.client.request<unknown>(path, {\n method: \"POST\",\n body: { email, password },\n skipAuthRefresh: true,\n });\n const twoFactor = read2fa(data);\n if (twoFactor !== null) {\n return { requires2fa: true, ephemeralToken: twoFactor.ephemeralToken };\n }\n const user = normalizeUser(data) ?? (await this.fetchMe(path));\n this.setState(\"authenticated\", user);\n return { ok: true, user };\n }\n\n const data = await this.client.request<unknown>(path, {\n method: \"POST\",\n body: { email, password },\n skipAuthRefresh: true,\n });\n const twoFactor = read2fa(data);\n if (twoFactor !== null) {\n return { requires2fa: true, ephemeralToken: twoFactor.ephemeralToken };\n }\n const record =\n typeof data === \"object\" && data !== null ? (data as Record<string, unknown>) : {};\n const { access, refresh } = record;\n if (typeof access !== \"string\" || typeof refresh !== \"string\") {\n throw new Error(\n `Karni auth: unexpected response from POST ${path}. Expected ` +\n \"{ access, refresh } (JWT mode) or { requires_2fa, ephemeral_token }, got \" +\n `${describeShape(data)}. Check the backend's KARNI_AUTH_MODE and the ` +\n 'AuthProvider \"mode\" prop.',\n );\n }\n this.tokenStorage.set(refresh);\n this.accessToken = access;\n const user = normalizeUser(record.user) ?? (await this.fetchMe(path));\n this.setState(\"authenticated\", user);\n return { ok: true, user };\n }\n\n private async fetchMe(loginPath: string): Promise<KarniUser> {\n const data = await this.client.request<unknown>(`${this.authBasePath}/me/`, {\n skipAuthRefresh: true,\n });\n const user = normalizeUser(data);\n if (user === null) {\n throw new Error(\n `Karni auth: POST ${loginPath} succeeded but ${this.authBasePath}/me/ returned ` +\n `${describeShape(data)} instead of a user object with id and email.`,\n );\n }\n return user;\n }\n\n /** Best-effort server logout, then always clears local state (anonymous). */\n async logout(): Promise<void> {\n await this.ensureInitialized();\n try {\n if (this.mode === \"session\") {\n await this.ensureCsrfToken();\n await this.client.request<unknown>(`${this.authBasePath}/logout/`, {\n method: \"POST\",\n skipAuthRefresh: true,\n });\n } else {\n const refresh = this.tokenStorage.get();\n if (refresh !== null) {\n await this.client.request<unknown>(`${this.authBasePath}/logout/`, {\n method: \"POST\",\n body: { refresh },\n skipAuthRefresh: true,\n });\n }\n }\n } catch {\n // Server-side logout is best effort; local state clears regardless.\n }\n this.accessToken = null;\n this.tokenStorage.clear();\n this.setState(\"anonymous\", null);\n }\n\n /**\n * Adopts tokens issued out of band, which is what\n * `@karni/impersonation-ui` does when a support user starts or stops\n * impersonating (the backend answers with tokens for the other identity).\n * JWT mode only. In session mode the server-side session already changed,\n * so this just re-syncs `/me/`.\n */\n async adoptTokens(access: string | null, refresh: string | null): Promise<void> {\n await this.ensureInitialized();\n if (this.mode === \"jwt\") {\n if (typeof refresh === \"string\" && refresh !== \"\") this.tokenStorage.set(refresh);\n if (typeof access === \"string\" && access !== \"\") this.accessToken = access;\n }\n await this.syncUser();\n }\n\n /**\n * Re-syncs the session: rotates the tokens in JWT mode (A3: /refresh/ is\n * 405 in session mode, so session mode only re-fetches /me/).\n */\n async refresh(): Promise<void> {\n await this.ensureInitialized();\n if (this.mode === \"jwt\") {\n const refreshed = await this.ensureRefresh();\n if (!refreshed) return; // Already anonymous + cleared.\n }\n await this.syncUser();\n }\n}\n","/**\n * Pluggable refresh-token storage for JWT mode (contract \"Hooks + auth\").\n *\n * The default adapter is `localStorage`: it survives reloads and is the\n * simplest thing that works, but any XSS on your page can read it. Stricter\n * setups use `createMemoryTokenStorage()` (logout on reload) or implement\n * the three-method `TokenStorage` interface themselves (e.g. backed by a\n * worker, or by an HttpOnly-cookie BFF). Session mode needs no storage.\n */\n\nexport interface TokenStorage {\n get(): string | null;\n set(token: string): void;\n clear(): void;\n}\n\n/**\n * The default storage, which keeps the refresh token in localStorage. `key` defaults to \"karni.refreshToken\". Every storage\n * access is guarded: when localStorage is unavailable (SSR, private windows,\n * blocked site data) the adapter degrades to a no-op that returns `null`\n * instead of throwing.\n */\nexport function createLocalStorageTokenStorage(key = \"karni.refreshToken\"): TokenStorage {\n return {\n get(): string | null {\n try {\n return globalThis.localStorage.getItem(key);\n } catch {\n return null;\n }\n },\n set(token: string): void {\n try {\n globalThis.localStorage.setItem(key, token);\n } catch {\n // Storage unavailable — the session simply won't survive a reload.\n }\n },\n clear(): void {\n try {\n globalThis.localStorage.removeItem(key);\n } catch {\n // Nothing stored, nothing to clear.\n }\n },\n };\n}\n\n/**\n * In-memory adapter: most secure (nothing persisted anywhere), but a page\n * reload logs the user out.\n */\nexport function createMemoryTokenStorage(): TokenStorage {\n let token: string | null = null;\n return {\n get: () => token,\n set: (next: string) => {\n token = next;\n },\n clear: () => {\n token = null;\n },\n };\n}\n","/**\n * <AuthProvider> + useAuth (contract \"Hooks + auth\" + D6).\n *\n * The provider instantiates the non-React AuthEngine (which owns the tokens\n * and the single-flight refresh machinery, and registers itself on the\n * KarniClient's auth hook points, see ./engine.ts) and mirrors its state\n * into React. It must be rendered inside <KarniProvider>: it takes the\n * KarniClient from context and uses the shared QueryClient to peek at the\n * cached schema for `x-karni-auth-mode`.\n *\n * Because the engine hooks into the client itself, EVERY request made\n * through the client while an <AuthProvider> is mounted (resource hooks,\n * schema loading, custom `client.request` calls) carries credentials\n * (Bearer in JWT mode, CSRF header + `credentials: \"include\"` in session\n * mode) and takes part in the 401 → refresh → retry flow.\n *\n * Escape hatches: `mode` pins the auth mode and skips schema detection\n * (recommended for cross-origin session setups so the very first requests\n * already include cookies), `tokenStorage` swaps the refresh-token store,\n * `csrfCookieName` / `csrfHeaderName` re-pin the session CSRF names (A4),\n * and `authBasePath` moves the auth endpoints off `/auth`.\n *\n * The OpenAPI document is generated per role (`Karni.field_roles`, ADR 0002\n * P3): a field a role may not read is absent from its schema. When the\n * identity changes (login, logout, a refresh that lands on another user) the\n * provider invalidates the cached schema, so tables, forms and detail views\n * follow the new user's field set without any per-role component code.\n *\n * Known limitations (D6): browser tabs do not coordinate refreshes. With\n * refresh-token rotation, a refresh in one tab can log another tab out on\n * its next refresh. Identity changes also do not auto-invalidate resource\n * queries, so call `queryClient.invalidateQueries({ queryKey:\n * karniKeys.resource(...) })` after login/logout where it matters.\n */\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { karniKeys } from \"../hooks/keys\";\nimport { useKarniClient } from \"../schema/provider\";\nimport { AuthEngine } from \"./engine\";\nimport { createLocalStorageTokenStorage, type TokenStorage } from \"./storage\";\nimport type { AuthStatus, KarniUser, LoginResult } from \"./types\";\n\nexport interface AuthProviderProps {\n /**\n * \"jwt\" | \"session\". When omitted, the mode comes from the schema root's\n * x-karni-auth-mode (D6), falling back to \"jwt\" when the schema does not\n * declare one.\n */\n mode?: \"jwt\" | \"session\";\n /** JWT mode refresh-token storage. Defaults to the localStorage adapter. */\n tokenStorage?: TokenStorage;\n /** Session mode CSRF cookie name. Default \"csrftoken\" (D6/A4). */\n csrfCookieName?: string;\n /** Session mode CSRF header name. Default \"X-CSRFToken\" (D6/A4). */\n csrfHeaderName?: string;\n /** Path prefix of the auth endpoints relative to baseUrl. Default \"/auth\". */\n authBasePath?: string;\n children?: ReactNode;\n}\n\nexport interface AuthContextValue {\n user: KarniUser | null;\n roles: string[];\n status: AuthStatus;\n login(email: string, password: string): Promise<LoginResult>;\n logout(): Promise<void>;\n refresh(): Promise<void>;\n /**\n * Adopts tokens issued out of band (JWT mode, or a `/me/` re-sync in session\n * mode), e.g. after starting or stopping an impersonated session.\n */\n adoptTokens(access: string | null, refresh: string | null): Promise<void>;\n}\n\n/**\n * The React mirror of the auth engine's state. Exported for advanced\n * composition (stories, tests, custom providers). Application code should\n * use <AuthProvider> + useAuth().\n */\nexport const AuthContext = createContext<AuthContextValue | null>(null);\n\n/** Rendered inside `KarniProvider`, it holds the signed-in user and attaches credentials (JWT or session) to every request. */\nexport function AuthProvider({\n mode,\n tokenStorage,\n csrfCookieName,\n csrfHeaderName,\n authBasePath,\n children,\n}: AuthProviderProps): ReactElement {\n const client = useKarniClient();\n const queryClient = useQueryClient();\n const storage = useMemo(() => tokenStorage ?? createLocalStorageTokenStorage(), [tokenStorage]);\n\n // The engine registers the client auth hooks in its constructor (render\n // phase) so that children's first queries — fired from effects that run\n // BEFORE this component's own effects — already flow through it.\n const engine = useMemo(\n () =>\n new AuthEngine({\n client,\n tokenStorage: storage,\n ...(mode !== undefined ? { modeOverride: mode } : {}),\n ...(csrfCookieName !== undefined ? { csrfCookieName } : {}),\n ...(csrfHeaderName !== undefined ? { csrfHeaderName } : {}),\n ...(authBasePath !== undefined ? { authBasePath } : {}),\n readCachedSchema: () => queryClient.getQueryData(karniKeys.schema()),\n }),\n [client, queryClient, storage, mode, csrfCookieName, csrfHeaderName, authBasePath],\n );\n\n useEffect(() => {\n engine.attach(); // re-assert after StrictMode remounts / engine swaps\n void engine.ensureInitialized();\n return () => {\n engine.detach();\n };\n }, [engine]);\n\n const snapshot = useSyncExternalStore(engine.subscribe, engine.getSnapshot, engine.getSnapshot);\n\n // The schema is per role: a new identity (or none) means a new field set.\n const identity = snapshot.user?.id ?? null;\n const previousIdentity = useRef(identity);\n useEffect(() => {\n if (previousIdentity.current === identity) return;\n previousIdentity.current = identity;\n void queryClient.invalidateQueries({ queryKey: karniKeys.schema() });\n }, [identity, queryClient]);\n\n const value = useMemo<AuthContextValue>(\n () => ({\n user: snapshot.user,\n roles: snapshot.user?.roles ?? [],\n status: snapshot.status,\n login: (email, password) => engine.login(email, password),\n logout: () => engine.logout(),\n refresh: () => engine.refresh(),\n adoptTokens: (access, refresh) => engine.adoptTokens(access, refresh),\n }),\n [engine, snapshot],\n );\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n\n/** Returns the signed-in user, auth status, `login` and `logout`, and throws a descriptive error outside `AuthProvider`. */\nexport function useAuth(): AuthContextValue {\n const value = useContext(AuthContext);\n if (value === null) {\n throw new Error(\n \"useAuth must be used within an <AuthProvider> (itself inside <KarniProvider>). \" +\n \"Wrap your tree: <KarniProvider client={...}><AuthProvider>...</AuthProvider></KarniProvider>.\",\n );\n }\n return value;\n}\n","/**\n * Paginated list hook for one resource (contract \"Hooks\" + D11).\n *\n * `useResourceList<Event>(\"events\", { page: 2, search: \"conf\" })` fetches\n * `GET /<resource>/?page=2&search=conf` through the KarniClient (auth-aware\n * inside an <AuthProvider>) and caches it under\n * `karniKeys.list(resource, params)`. The response is the raw DRF page:\n * `{ count, next, previous, results }`.\n *\n * Escape hatch: `options` forwards every TanStack Query option except\n * `queryKey`/`queryFn` (e.g. `enabled`, `placeholderData`, `staleTime`,\n * `select`).\n */\nimport { useQuery, type UseQueryOptions, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useKarniClient } from \"../schema/provider\";\nimport { karniKeys } from \"./keys\";\nimport { buildListQuery, listPath } from \"./params\";\nimport type { Paginated, ResourceListParams } from \"./types\";\n\n/** Fetches one page of a resource's list (`GET /<resource>/`) with filters, search, ordering and `?expand=`. */\nexport function useResourceList<T = Record<string, unknown>>(\n resource: string,\n params?: ResourceListParams,\n options?: Omit<UseQueryOptions<Paginated<T>>, \"queryKey\" | \"queryFn\">,\n): UseQueryResult<Paginated<T>> {\n const client = useKarniClient();\n return useQuery<Paginated<T>>({\n ...options,\n queryKey: karniKeys.list(resource, params),\n queryFn: ({ signal }) =>\n client.request<Paginated<T>>(listPath(resource), { query: buildListQuery(params), signal }),\n });\n}\n","/**\n * Mutation body encoding (contract D2) + PATCH file-URL omission.\n *\n * D2: after the form's `transformSubmit` has run, a payload containing any\n * top-level `File` (or an array containing one) is encoded as `FormData`.\n * Everything else is sent as JSON. FormData rules:\n * - arrays append as repeated keys,\n * - plain objects/arrays-of-objects (json fields) are JSON-stringified,\n * - numbers/booleans are stringified,\n * - `null`/`undefined` entries are OMITTED: multipart cannot express null\n * (DRF would parse the string \"null\"). To null a field, send a JSON PATCH\n * without the file field instead,\n * - Content-Type is never set manually: fetch derives the multipart boundary.\n *\n * PATCH omission (D2): a string value on a file-kind field is the unchanged\n * display URL the backend returned (D1: response-side `format: uri`). Sending\n * it back would 400 (\"not a file\"), so it is dropped from PATCH payloads.\n * Field kinds come from the cached parsed schema when present. Without it the\n * payload passes through untouched (graceful degradation).\n *\n * Internal module: not re-exported from the barrel.\n */\n\nfunction isFileValue(value: unknown): value is File {\n return typeof File !== \"undefined\" && value instanceof File;\n}\n\nfunction isBlobValue(value: unknown): value is Blob {\n return typeof Blob !== \"undefined\" && value instanceof Blob;\n}\n\n/** True when any top-level value is a File, or an array containing one (D2). */\nexport function containsFile(values: Record<string, unknown>): boolean {\n return Object.values(values).some(\n (value) =>\n isFileValue(value) || (Array.isArray(value) && value.some((item) => isFileValue(item))),\n );\n}\n\nfunction appendFormValue(form: FormData, key: string, value: unknown): void {\n if (value === null || value === undefined) return;\n if (isFileValue(value) || isBlobValue(value)) {\n form.append(key, value);\n return;\n }\n if (typeof value === \"object\") {\n form.append(key, JSON.stringify(value));\n return;\n }\n form.append(key, String(value));\n}\n\n/** Encodes a payload as FormData per the D2 rules above. */\nexport function toFormData(values: Record<string, unknown>): FormData {\n const form = new FormData();\n for (const [key, value] of Object.entries(values)) {\n if (value === null || value === undefined) continue;\n if (Array.isArray(value)) {\n for (const item of value) appendFormValue(form, key, item);\n } else {\n appendFormValue(form, key, value);\n }\n }\n return form;\n}\n\n/**\n * D2 dispatch: FormData when a top-level File is present, the payload itself\n * (JSON-serialized by the client) otherwise. Applies to create AND PATCH.\n */\nexport function encodeBody(values: Record<string, unknown>): Record<string, unknown> | FormData {\n return containsFile(values) ? toFormData(values) : values;\n}\n\n/**\n * Extracts the file-kind field names of `resource` from the cached parsed\n * schema (`karniKeys.schema()`'s cache entry). Every access is guarded: an\n * absent cache entry or an unexpected shape yields an empty set, never a\n * throw.\n */\nexport function fileFieldNames(cachedSchema: unknown, resource: string): ReadonlySet<string> {\n const names = new Set<string>();\n if (typeof cachedSchema !== \"object\" || cachedSchema === null) return names;\n const resources = (cachedSchema as Record<string, unknown>).resources;\n if (typeof resources !== \"object\" || resources === null) return names;\n const entry = (resources as Record<string, unknown>)[resource];\n if (typeof entry !== \"object\" || entry === null) return names;\n const fields = (entry as Record<string, unknown>).fields;\n if (!Array.isArray(fields)) return names;\n for (const field of fields as readonly unknown[]) {\n if (typeof field !== \"object\" || field === null) continue;\n const { name, kind } = field as Record<string, unknown>;\n if (typeof name === \"string\" && kind === \"file\") names.add(name);\n }\n return names;\n}\n\nfunction isStringOrStringArray(value: unknown): boolean {\n if (typeof value === \"string\") return true;\n return Array.isArray(value) && value.every((item) => typeof item === \"string\");\n}\n\n/**\n * Drops unchanged file values from a PATCH payload (D2). Strings (or arrays\n * of strings) on file-kind fields are the backend's display URLs, not new\n * uploads.\n */\nexport function omitUnchangedFileUrls(\n values: Record<string, unknown>,\n fileFields: ReadonlySet<string>,\n): Record<string, unknown> {\n if (fileFields.size === 0) return values;\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(values)) {\n if (fileFields.has(key) && isStringOrStringArray(value)) continue;\n out[key] = value;\n }\n return out;\n}\n","/**\n * Create / update / remove mutations for one resource (contract \"Hooks\" +\n * D2, D3, D11).\n *\n * - `create` → `POST /<resource>/`\n * - `update` → `PATCH /<resource>/<id>/` with `{ id, values }`\n * - `remove` → `DELETE /<resource>/<id>/`\n *\n * Every successful mutation invalidates `karniKeys.resource(resource)` (all\n * list + detail entries of the resource) plus any `options.invalidateKeys`,\n * but never the bare `[\"karni\"]` root (D4), which would nuke the cached schema.\n *\n * ## Multipart (D2)\n * Payloads containing a top-level `File` (or an array containing one) are\n * encoded as FormData (on create AND PATCH), with arrays as repeated keys,\n * json values JSON-stringified, and no manual Content-Type. Unchanged file\n * values (the URL string the backend returned) are omitted from PATCH\n * payloads so they are never re-submitted as uploads.\n *\n * ## PATCH granularity: contract for the form builder (D3)\n * `update` sends EXACTLY the keys present in `values`. It never diffs or\n * drops fields itself (beyond the file-URL omission above). ResourceForm\n * must therefore build `values` at TOP-LEVEL FIELD granularity from\n * react-hook-form's `dirtyFields`: when ANY leaf inside a field's subtree is\n * dirty (nested object, array member, multi-relation), include that field's\n * ENTIRE current value, never a partial subtree, because DRF PATCH replaces\n * the whole field value. An emptied nullable field must be sent as `null`\n * (not `\"\"`/`undefined`): a key that is absent is simply left unchanged by\n * the backend, and `undefined` does not survive JSON serialization.\n */\nimport { useMutation, useQueryClient, type UseMutationResult } from \"@tanstack/react-query\";\nimport { useCallback } from \"react\";\nimport { useKarniClient } from \"../schema/provider\";\nimport { karniKeys } from \"./keys\";\nimport { encodeBody, fileFieldNames, omitUnchangedFileUrls } from \"./multipart\";\nimport { detailPath, listPath } from \"./params\";\nimport type { ResourceMutationsOptions } from \"./types\";\n\n/** Result bundle: the three mutations, each a full TanStack mutation object. */\nexport interface ResourceMutations<T> {\n create: UseMutationResult<T, unknown, Record<string, unknown>>;\n update: UseMutationResult<T, unknown, { id: string | number; values: Record<string, unknown> }>;\n remove: UseMutationResult<void, unknown, string | number>;\n}\n\n/** Create, update and remove mutations for a resource that refresh the resource's cached lists and items on each success. */\nexport function useResourceMutations<T = Record<string, unknown>>(\n resource: string,\n options?: ResourceMutationsOptions,\n): ResourceMutations<T> {\n const client = useKarniClient();\n const queryClient = useQueryClient();\n const invalidateKeys = options?.invalidateKeys;\n\n const invalidate = useCallback(async (): Promise<void> => {\n await queryClient.invalidateQueries({ queryKey: karniKeys.resource(resource) });\n if (invalidateKeys !== undefined) {\n await Promise.all(\n invalidateKeys.map((queryKey) => queryClient.invalidateQueries({ queryKey })),\n );\n }\n }, [queryClient, resource, invalidateKeys]);\n\n const create = useMutation<T, unknown, Record<string, unknown>>({\n mutationFn: (values) =>\n client.request<T>(listPath(resource), { method: \"POST\", body: encodeBody(values) }),\n onSuccess: () => invalidate(),\n });\n\n const update = useMutation<T, unknown, { id: string | number; values: Record<string, unknown> }>({\n mutationFn: ({ id, values }) => {\n const fileFields = fileFieldNames(queryClient.getQueryData(karniKeys.schema()), resource);\n const prepared = omitUnchangedFileUrls(values, fileFields);\n return client.request<T>(detailPath(resource, id), {\n method: \"PATCH\",\n body: encodeBody(prepared),\n });\n },\n onSuccess: () => invalidate(),\n });\n\n // `void` lives in the annotation, not in call-site type arguments: eslint's\n // strict no-invalid-void-type only permits it in type-reference positions.\n const remove: UseMutationResult<void, unknown, string | number> = useMutation({\n mutationFn: async (id: string | number): Promise<void> => {\n await client.request(detailPath(resource, id), { method: \"DELETE\" });\n },\n onSuccess: () => invalidate(),\n });\n\n return { create, update, remove };\n}\n","/**\n * OpenAPI → ResourceSchema parser (contract \"Schema client\" + amendment D1).\n *\n * Parses the real drf-spectacular dialect (OAS 3.0.3):\n * - resolves $ref against components.schemas (cycle-guarded),\n * - unwraps single-member allOf, merging its siblings (drf-spectacular uses\n * `allOf: [$ref] + readOnly/description` for annotated enum fields),\n * - maps oneOf [XEnum, NullEnum | BlankEnum] → kind \"enum\" (+ nullable from\n * NullEnum, with BlankEnum's \"\" excluded from enumValues),\n * - handles `nullable: true` (3.0) and `type: [T, \"null\"]` (future-proofing),\n * - split-components merge algebra (COMPONENT_SPLIT_REQUEST=True, api B14):\n * fields = union(response props, create-request props), readOnly = flagged\n * OR response-only, writeOnly = flagged OR request-only, and required = the\n * CREATE REQUEST body's required array ONLY. Resources without a create op\n * fall back to response-only, all readOnly,\n * - kind \"file\" = request-side `format: binary` (the response-side format: uri\n * is just the display URL),\n * - unknown/unsupported constructs land as kind \"unknown\" (never crash).\n *\n * This module is internal to @karni/ui (not re-exported from the barrel), but\n * sibling builders (hooks/auth/components) import it relatively.\n */\n\nimport type {\n FieldDef,\n FieldKind,\n OperationDef,\n ParsedSchema,\n RelationRef,\n ResourceSchema,\n} from \"./types\";\n\n// minimal structural OpenAPI types\n\nexport interface KarniRelationExtension {\n resource?: string;\n many?: boolean;\n}\n\nexport interface SchemaObject {\n default?: unknown;\n $ref?: string;\n type?: string | readonly string[];\n format?: string;\n title?: string;\n description?: string;\n enum?: ReadonlyArray<string | number | null>;\n nullable?: boolean;\n readOnly?: boolean;\n writeOnly?: boolean;\n required?: readonly string[];\n properties?: Record<string, SchemaObject>;\n items?: SchemaObject;\n allOf?: readonly SchemaObject[];\n oneOf?: readonly SchemaObject[];\n anyOf?: readonly SchemaObject[];\n maxLength?: number;\n minLength?: number;\n minimum?: number;\n maximum?: number;\n \"x-karni-relation\"?: KarniRelationExtension;\n [extension: string]: unknown;\n}\n\nexport interface ParameterObject {\n name?: string;\n in?: string;\n required?: boolean;\n schema?: SchemaObject;\n [extension: string]: unknown;\n}\n\nexport interface MediaTypeObject {\n schema?: SchemaObject;\n [extension: string]: unknown;\n}\n\nexport interface RequestBodyObject {\n content?: Record<string, MediaTypeObject>;\n required?: boolean;\n [extension: string]: unknown;\n}\n\nexport interface ResponseObject {\n description?: string;\n content?: Record<string, MediaTypeObject>;\n [extension: string]: unknown;\n}\n\nexport interface OperationObject {\n operationId?: string;\n parameters?: readonly ParameterObject[];\n requestBody?: RequestBodyObject;\n responses?: Record<string, ResponseObject>;\n \"x-karni-resource\"?: string;\n [extension: string]: unknown;\n}\n\nexport interface PathItemObject {\n get?: OperationObject;\n post?: OperationObject;\n put?: OperationObject;\n patch?: OperationObject;\n delete?: OperationObject;\n [extension: string]: unknown;\n}\n\nexport interface OpenApiDocument {\n openapi?: string;\n paths?: Record<string, PathItemObject>;\n components?: { schemas?: Record<string, SchemaObject>; [extension: string]: unknown };\n \"x-karni-auth-mode\"?: string;\n [extension: string]: unknown;\n}\n\n// helpers\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** \"starts_at\" → \"Starts at\", \"is_public\" → \"Is public\". */\nexport function humanize(name: string): string {\n const spaced = name.replace(/[_-]+/g, \" \").trim();\n return spaced.length === 0 ? name : spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\nconst REF_PREFIX = \"#/components/schemas/\";\n\nfunction lookupRef(doc: OpenApiDocument, ref: string): SchemaObject | undefined {\n if (!ref.startsWith(REF_PREFIX)) return undefined;\n return doc.components?.schemas?.[ref.slice(REF_PREFIX.length)];\n}\n\n/**\n * Resolves $ref chains and unwraps single-member allOf, merging siblings over\n * the resolved target (so `{allOf: [$ref StatusEnum], readOnly: true}` yields\n * the enum schema plus readOnly). Cycle-guarded: a cycle resolves to {}.\n */\nexport function resolveSchema(\n doc: OpenApiDocument,\n schema: SchemaObject | undefined,\n seen: readonly string[] = [],\n): SchemaObject | undefined {\n if (schema === undefined) return undefined;\n\n if (typeof schema.$ref === \"string\") {\n if (seen.includes(schema.$ref)) return {};\n const target = lookupRef(doc, schema.$ref);\n if (target === undefined) return {};\n const resolved = resolveSchema(doc, target, [...seen, schema.$ref]) ?? {};\n const siblings: SchemaObject = { ...schema };\n delete siblings.$ref;\n return { ...resolved, ...siblings };\n }\n\n if (Array.isArray(schema.allOf) && schema.allOf.length === 1) {\n const inner = resolveSchema(doc, schema.allOf[0], seen) ?? {};\n const siblings: SchemaObject = { ...schema };\n delete siblings.allOf;\n return { ...inner, ...siblings };\n }\n\n return schema;\n}\n\n// per-property analysis\n\ninterface PropertyInfo {\n kind: FieldKind;\n nullable: boolean;\n enumValues?: ReadonlyArray<string | number>;\n enumLabels?: Readonly<Record<string, string>>;\n maxLength?: number;\n min?: number;\n max?: number;\n format?: string;\n description?: string;\n title?: string;\n default?: unknown;\n readOnly: boolean;\n writeOnly: boolean;\n relation?: RelationRef;\n relationValueType?: \"uuid\" | \"integer\" | \"string\";\n /** True when this side emits format: binary (request side of a file field). */\n binary: boolean;\n}\n\nfunction normalizeType(schema: SchemaObject): { type: string | undefined; nullable: boolean } {\n // `type: [T, \"null\"]` is handled as future-proofing only (D1).\n if (Array.isArray(schema.type)) {\n const nonNull = schema.type.filter((t) => t !== \"null\");\n return { type: nonNull[0], nullable: schema.type.includes(\"null\") || schema.nullable === true };\n }\n return {\n type: typeof schema.type === \"string\" ? schema.type : undefined,\n nullable: schema.nullable === true,\n };\n}\n\nfunction relationFromExtension(schema: SchemaObject): RelationRef | undefined {\n const ext = schema[\"x-karni-relation\"];\n if (isRecord(ext) && typeof ext.resource === \"string\" && ext.resource.length > 0) {\n return { resource: ext.resource, many: ext.many === true };\n }\n return undefined;\n}\n\nfunction relationValueTypeOf(schema: SchemaObject): \"uuid\" | \"integer\" | \"string\" {\n const { type } = normalizeType(schema);\n if (type === \"integer\" || type === \"number\") return \"integer\";\n if (schema.format === \"uuid\") return \"uuid\";\n return \"string\";\n}\n\n/**\n * Combines oneOf/anyOf members when they follow the drf-spectacular enum\n * pattern `[XEnum, BlankEnum?, NullEnum?]`. Returns undefined for any other\n * composition (which then lands as kind \"unknown\").\n */\nfunction combineEnumMembers(\n doc: OpenApiDocument,\n members: readonly SchemaObject[],\n seen: readonly string[],\n): { values: Array<string | number>; nullable: boolean; description?: string } | undefined {\n const values: Array<string | number> = [];\n let nullable = false;\n let description: string | undefined;\n for (const member of members) {\n const resolved = resolveSchema(doc, member, seen);\n if (resolved === undefined || !Array.isArray(resolved.enum)) return undefined;\n if (description === undefined && resolved.description !== undefined && values.length === 0) {\n description = resolved.description; // the XEnum member carries the choice list\n }\n for (const value of resolved.enum) {\n if (value === null) {\n nullable = true; // NullEnum\n } else if (value !== \"\") {\n values.push(value); // BlankEnum's \"\" excluded from enumValues (D1)\n }\n }\n }\n return { values, nullable, description };\n}\n\nconst CHOICE_LINE = /^\\* `(.+?)` - (.*)$/;\n\n/**\n * Splits drf-spectacular's generated choice list (\"* `draft` - Draft\" per\n * line, appended to a ChoiceField's description) into labels by value and\n * the human help text that remains (undefined when nothing remains). The\n * raw list is markdown a form would otherwise show verbatim as help text.\n */\nexport function choiceLabels(description: string | undefined): {\n labels?: Record<string, string>;\n rest?: string;\n} {\n if (description === undefined) return {};\n const labels: Record<string, string> = {};\n const rest: string[] = [];\n for (const line of description.split(\"\\n\")) {\n const match = CHOICE_LINE.exec(line.trim());\n if (match !== null && match[1] !== undefined && match[2] !== undefined) {\n labels[match[1]] = match[2].trim();\n } else {\n rest.push(line);\n }\n }\n const text = rest.join(\"\\n\").trim();\n return {\n ...(Object.keys(labels).length > 0 ? { labels } : {}),\n ...(text !== \"\" ? { rest: text } : {}),\n };\n}\n\nfunction applyChoiceLabels(info: PropertyInfo, description: string | undefined): void {\n const { labels, rest } = choiceLabels(description);\n if (labels !== undefined) info.enumLabels = labels;\n info.description = rest;\n}\n\n/** True for drf-spectacular's JSONField output: a schema with no constraints at all. */\nfunction isAnySchema(schema: SchemaObject): boolean {\n return (\n schema.type === undefined &&\n schema.enum === undefined &&\n schema.properties === undefined &&\n schema.items === undefined &&\n schema.oneOf === undefined &&\n schema.anyOf === undefined &&\n schema.allOf === undefined &&\n schema.$ref === undefined\n );\n}\n\nfunction analyzeProperty(doc: OpenApiDocument, raw: SchemaObject): PropertyInfo {\n const resolved = resolveSchema(doc, raw) ?? {};\n const relation = relationFromExtension(resolved);\n const { type, nullable: typeNullable } = normalizeType(resolved);\n\n const info: PropertyInfo = {\n kind: \"unknown\",\n nullable: typeNullable,\n format: resolved.format,\n description: resolved.description,\n title: resolved.title,\n default: resolved.default,\n readOnly: resolved.readOnly === true,\n writeOnly: resolved.writeOnly === true,\n maxLength: resolved.maxLength,\n min: resolved.minimum,\n max: resolved.maximum,\n relation,\n binary: false,\n };\n\n // drf-spectacular nullable/blank enums: oneOf [XEnum, BlankEnum?, NullEnum?].\n const composition = resolved.oneOf ?? resolved.anyOf;\n if (Array.isArray(composition)) {\n const combined = combineEnumMembers(doc, composition, []);\n if (combined !== undefined) {\n info.kind = \"enum\";\n info.enumValues = combined.values;\n info.nullable = info.nullable || combined.nullable;\n applyChoiceLabels(info, resolved.description ?? combined.description);\n return info;\n }\n return info; // unsupported composition → kind \"unknown\"\n }\n\n if (Array.isArray(resolved.enum)) {\n info.kind = \"enum\";\n info.nullable = info.nullable || resolved.enum.includes(null);\n info.enumValues = resolved.enum.filter(\n (value): value is string | number => value !== null && value !== \"\",\n );\n applyChoiceLabels(info, resolved.description);\n return info;\n }\n\n if (relation !== undefined && !relation.many) {\n info.kind = \"relation\";\n info.relationValueType = relationValueTypeOf(resolved);\n return info;\n }\n\n switch (type) {\n case \"string\": {\n if (resolved.format === \"binary\") {\n info.kind = \"file\";\n info.binary = true;\n } else if (resolved.format === \"date\") {\n info.kind = \"date\";\n } else if (resolved.format === \"date-time\") {\n info.kind = \"datetime\";\n } else if (resolved.format === undefined && resolved.maxLength === undefined) {\n // CharField always emits maxLength; a bare string is a TextField.\n info.kind = \"text\";\n } else {\n info.kind = \"string\";\n }\n return info;\n }\n case \"integer\":\n info.kind = \"integer\";\n return info;\n case \"number\":\n info.kind = \"number\";\n return info;\n case \"boolean\":\n info.kind = \"boolean\";\n return info;\n case \"array\": {\n if (relation !== undefined) {\n info.kind = \"relation\";\n const items = resolveSchema(doc, resolved.items) ?? {};\n info.relationValueType = relationValueTypeOf(items);\n } else {\n info.kind = \"array\";\n }\n return info;\n }\n case \"object\":\n info.kind = \"json\";\n return info;\n default: {\n if (relation !== undefined) {\n // Extension present but value type undeclared — still a relation.\n info.kind = \"relation\";\n info.relationValueType = relationValueTypeOf(resolved);\n } else if (isAnySchema(resolved)) {\n // drf-spectacular emits `{}` for JSONField (\"any\" schema).\n info.kind = \"json\";\n }\n return info;\n }\n }\n}\n\n// split-components field merge (D1)\n\nfunction mergeField(\n name: string,\n responseInfo: PropertyInfo | undefined,\n requestInfo: PropertyInfo | undefined,\n requiredSet: ReadonlySet<string>,\n hasCreateRequest: boolean,\n order: number,\n): FieldDef {\n // Request side wins for write-facing facts; response side fills the gaps.\n // kind \"file\" is request-side format: binary (D1) — the response side of the\n // same field is a display URL (format: uri) and must not mask it.\n let kind: FieldKind;\n if (requestInfo?.binary === true) {\n kind = \"file\";\n } else if (requestInfo !== undefined && requestInfo.kind !== \"unknown\") {\n kind = requestInfo.kind;\n } else if (responseInfo !== undefined && responseInfo.kind !== \"unknown\") {\n kind = responseInfo.kind;\n } else {\n kind = \"unknown\";\n }\n\n const relation = requestInfo?.relation ?? responseInfo?.relation;\n const title = requestInfo?.title ?? responseInfo?.title;\n\n const field: FieldDef = {\n name,\n label: title !== undefined && title.length > 0 ? title : humanize(name),\n kind,\n required: requiredSet.has(name),\n readOnly:\n !hasCreateRequest ||\n responseInfo?.readOnly === true ||\n requestInfo?.readOnly === true ||\n (hasCreateRequest && responseInfo !== undefined && requestInfo === undefined),\n writeOnly:\n requestInfo?.writeOnly === true ||\n responseInfo?.writeOnly === true ||\n (responseInfo === undefined && requestInfo !== undefined),\n // Write-facing: a file is a nullable URL on the way out and a plain upload\n // on the way in, and only the request side says what a form may send.\n nullable: requestInfo !== undefined ? requestInfo.nullable : (responseInfo?.nullable ?? false),\n order,\n };\n\n const enumValues = requestInfo?.enumValues ?? responseInfo?.enumValues;\n const fallback = requestInfo?.default ?? responseInfo?.default;\n if (fallback !== undefined) field.default = fallback;\n if (enumValues !== undefined) field.enumValues = enumValues;\n const enumLabels = requestInfo?.enumLabels ?? responseInfo?.enumLabels;\n if (enumLabels !== undefined) field.enumLabels = enumLabels;\n const maxLength = requestInfo?.maxLength ?? responseInfo?.maxLength;\n if (maxLength !== undefined) field.maxLength = maxLength;\n const min = requestInfo?.min ?? responseInfo?.min;\n if (min !== undefined) field.min = min;\n const max = requestInfo?.max ?? responseInfo?.max;\n if (max !== undefined) field.max = max;\n const format = requestInfo?.format ?? responseInfo?.format;\n if (format !== undefined) field.format = format;\n const description = responseInfo?.description ?? requestInfo?.description;\n if (description !== undefined) field.description = description;\n if (relation !== undefined) {\n field.relation = relation;\n const valueType = requestInfo?.relationValueType ?? responseInfo?.relationValueType;\n if (valueType !== undefined) field.relationValueType = valueType;\n }\n\n return field;\n}\n\n// operation extraction\n\nfunction operationDef(\n doc: OpenApiDocument,\n path: string,\n method: OperationDef[\"method\"],\n op: OperationObject,\n): OperationDef {\n const queryParams: string[] = [];\n let expandEnum: readonly string[] | undefined;\n for (const param of op.parameters ?? []) {\n if (!isRecord(param) || param.in !== \"query\" || typeof param.name !== \"string\") continue;\n queryParams.push(param.name);\n if (param.name === \"expand\") {\n const schema = resolveSchema(doc, param.schema);\n const items = resolveSchema(doc, schema?.items);\n const values = schema?.enum ?? items?.enum;\n if (Array.isArray(values)) {\n expandEnum = values.filter((value): value is string => typeof value === \"string\");\n }\n }\n }\n const def: OperationDef = {\n path,\n method,\n queryParams,\n hasSearch: queryParams.includes(\"search\"),\n };\n if (typeof op.operationId === \"string\") def.operationId = op.operationId;\n if (expandEnum !== undefined) def.expandEnum = expandEnum;\n const access = op[\"x-karni-access\"];\n if (isRecord(access)) def.access = access;\n return def;\n}\n\n/** Unwraps a DRF paginated list response down to the item component schema. */\nfunction listItemSchema(doc: OpenApiDocument, op: OperationObject): SchemaObject | undefined {\n const response =\n op.responses?.[\"200\"] ?? op.responses?.[\"201\"] ?? Object.values(op.responses ?? {})[0];\n const media = response?.content?.[\"application/json\"];\n const body = resolveSchema(doc, media?.schema);\n if (body === undefined) return undefined;\n const results = resolveSchema(doc, body.properties?.[\"results\"]);\n if (results !== undefined && results.type === \"array\") {\n return resolveSchema(doc, results.items);\n }\n if (body.type === \"array\") return resolveSchema(doc, body.items);\n return body;\n}\n\nfunction createRequestSchema(doc: OpenApiDocument, op: OperationObject): SchemaObject | undefined {\n const content = op.requestBody?.content;\n if (!isRecord(content)) return undefined;\n const media =\n content[\"application/json\"] ?? content[\"multipart/form-data\"] ?? Object.values(content)[0];\n return resolveSchema(doc, media?.schema);\n}\n\n// the parser\n\nconst METHODS = [\"get\", \"post\", \"put\", \"patch\", \"delete\"] as const;\n\n/**\n * Parses an OpenAPI document (fetched from the backend's schemaUrl) into the\n * normalized registry. Tolerates anything it does not understand: unknown\n * constructs become kind \"unknown\" fields, paths without x-karni-resource are\n * ignored, and a malformed document yields an empty registry.\n */\nexport function parseOpenApi(input: unknown): ParsedSchema {\n const doc: OpenApiDocument = isRecord(input) ? (input as OpenApiDocument) : {};\n const paths = isRecord(doc.paths) ? doc.paths : {};\n\n const resources: Record<string, ResourceSchema> = {};\n const rawAuthMode = doc[\"x-karni-auth-mode\"];\n const authMode = rawAuthMode === \"jwt\" || rawAuthMode === \"session\" ? rawAuthMode : undefined;\n\n // Pass 1: find every list operation via its x-karni-resource marker.\n const listOps: Array<{ resource: string; path: string; item: PathItemObject }> = [];\n for (const [path, item] of Object.entries(paths)) {\n if (!isRecord(item)) continue;\n const get = item.get;\n if (isRecord(get) && typeof get[\"x-karni-resource\"] === \"string\") {\n listOps.push({ resource: get[\"x-karni-resource\"], path, item });\n }\n }\n\n for (const { resource, path, item } of listOps) {\n const listOp = item.get;\n if (!isRecord(listOp)) continue;\n\n // The item path is the collection path plus a single `{param}/` segment.\n const itemEntry = Object.entries(paths).find(([candidate]) => {\n if (!candidate.startsWith(path)) return false;\n const rest = candidate.slice(path.length);\n return /^\\{[^/{}]+\\}\\/?$/.test(rest);\n });\n const itemPath = itemEntry?.[0];\n const itemItem = itemEntry !== undefined && isRecord(itemEntry[1]) ? itemEntry[1] : undefined;\n\n const operations: ResourceSchema[\"operations\"] = {\n list: operationDef(doc, path, \"get\", listOp),\n };\n const createOp = isRecord(item.post) ? item.post : undefined;\n if (createOp !== undefined) operations.create = operationDef(doc, path, \"post\", createOp);\n // karni.transfer (P6): the export and import actions live under the list path.\n const exportItem = paths[`${path}export/`];\n const exportOp = isRecord(exportItem) && isRecord(exportItem.get) ? exportItem.get : undefined;\n if (exportOp !== undefined) {\n operations.export = operationDef(doc, `${path}export/`, \"get\", exportOp);\n }\n const importItem = paths[`${path}import/`];\n const importOp =\n isRecord(importItem) && isRecord(importItem.post) ? importItem.post : undefined;\n if (importOp !== undefined) {\n operations.import = operationDef(doc, `${path}import/`, \"post\", importOp);\n }\n if (itemPath !== undefined && itemItem !== undefined) {\n for (const method of METHODS) {\n const op = itemItem[method];\n if (!isRecord(op)) continue;\n if (method === \"get\") operations.detail = operationDef(doc, itemPath, \"get\", op);\n else if (method === \"patch\") operations.update = operationDef(doc, itemPath, \"patch\", op);\n else if (method === \"put\" && operations.update === undefined)\n operations.update = operationDef(doc, itemPath, \"put\", op);\n else if (method === \"delete\") operations.remove = operationDef(doc, itemPath, \"delete\", op);\n }\n }\n\n // Field derivation: response component of the list op + create request body.\n const responseSchema = listItemSchema(doc, listOp);\n const requestSchema = createOp !== undefined ? createRequestSchema(doc, createOp) : undefined;\n const hasCreateRequest = requestSchema !== undefined;\n\n const responseProps = isRecord(responseSchema?.properties) ? responseSchema.properties : {};\n const requestProps = isRecord(requestSchema?.properties) ? requestSchema.properties : {};\n // required comes from the CREATE REQUEST body only — never the response (D1).\n const requiredSet = new Set<string>(\n Array.isArray(requestSchema?.required) ? requestSchema.required : [],\n );\n\n const fields: FieldDef[] = [];\n let order = 0;\n for (const [name, prop] of Object.entries(responseProps)) {\n const responseInfo = analyzeProperty(doc, prop);\n const requestProp = requestProps[name];\n const requestInfo = requestProp !== undefined ? analyzeProperty(doc, requestProp) : undefined;\n fields.push(\n mergeField(name, responseInfo, requestInfo, requiredSet, hasCreateRequest, order),\n );\n order += 1;\n }\n for (const [name, prop] of Object.entries(requestProps)) {\n if (name in responseProps) continue;\n const requestInfo = analyzeProperty(doc, prop);\n fields.push(mergeField(name, undefined, requestInfo, requiredSet, hasCreateRequest, order));\n order += 1;\n }\n\n resources[resource] = { resource, operations, fields };\n }\n\n const parsed: ParsedSchema = { resources };\n if (authMode !== undefined) parsed.authMode = authMode;\n return parsed;\n}\n","/**\n * useSchema: the schema registry hook (contract \"Schema client\").\n *\n * The OpenAPI document is fetched under the pinned [\"karni\", \"$schema\"] key\n * with staleTime Infinity and parsed ONCE inside the query function, so every\n * consumer shares a single ParsedSchema instance per fetch. The key literal\n * is duplicated from karniKeys.schema() (hooks/keys.ts) by design: both\n * modules are bound to the same D4-pinned shape and neither imports the\n * other at runtime.\n *\n * Asking for a resource the backend does not expose (after the schema has\n * loaded) throws during render (error-boundary friendly) with the list of\n * known resources, which catches typos immediately instead of rendering an\n * empty table.\n */\nimport { useQuery } from \"@tanstack/react-query\";\nimport type { UseQueryResult } from \"@tanstack/react-query\";\nimport { parseOpenApi } from \"./parse\";\nimport { useKarniClient } from \"./provider\";\nimport type { ParsedSchema, ResourceSchema } from \"./types\";\n\n/** D4-pinned query key for the parsed schema document. */\nexport const SCHEMA_QUERY_KEY = [\"karni\", \"$schema\"] as const;\n\n/**\n * The whole parsed registry (resources + root x-karni-auth-mode). Internal to\n * the package: the auth layer reads `data.authMode` from here. Apps use\n * useSchema(resource).\n */\nexport function useParsedSchema(): UseQueryResult<ParsedSchema> {\n const client = useKarniClient();\n return useQuery<ParsedSchema>({\n queryKey: SCHEMA_QUERY_KEY,\n staleTime: Infinity,\n queryFn: async () => parseOpenApi(await client.request<unknown>(client.schemaUrl)),\n });\n}\n\nexport interface UseSchemaResult {\n data: ResourceSchema | undefined;\n isLoading: boolean;\n error: unknown;\n /** Fetches the schema document again: what a \"Try again\" after a failed load calls. */\n refetch?: () => void;\n /** True while the schema document is being fetched (the first load or a retry). */\n isFetching?: boolean;\n}\n\n/** Returns one resource's parsed schema (fields, types, relations, operations) from the backend's OpenAPI document, fetched once per app. */\nexport function useSchema(resource: string): UseSchemaResult {\n const query = useParsedSchema();\n\n if (query.data !== undefined) {\n const schema = query.data.resources[resource];\n if (schema === undefined) {\n const known = Object.keys(query.data.resources).sort();\n throw new Error(\n `Unknown resource \"${resource}\". Known resources: ` +\n `${known.length > 0 ? known.join(\", \") : \"none (does the schema expose x-karni-resource?)\"}.`,\n );\n }\n return { data: schema, isLoading: false, error: query.error };\n }\n\n return {\n data: undefined,\n isLoading: query.isPending,\n error: query.error,\n refetch: () => void query.refetch(),\n isFetching: query.isFetching,\n };\n}\n","/**\n * Audit fields: the columns every Karni resource carries because every model\n * inherits BaseModel (`deleted_at` is never exposed by the API). They are\n * record bookkeeping, not domain data, so the generic resource components\n * de-emphasise them: ResourceTable hides them by default (escape hatches:\n * `columns` entries and `showAuditFields`), ResourceDetail renders them last\n * in a muted \"Record\" group.\n *\n * This list is the single source of truth. Edit it here and every generic\n * component follows. Its order is also the display order whenever audit\n * fields are shown, whatever order the schema declares them in.\n */\nimport type { FieldDef } from \"../../schema/types\";\n\n/** The audit field names (`created_at`, `created_by`, …) that tables hide and detail views group last. */\nexport const AUDIT_FIELDS: readonly string[] = Object.freeze([\n \"id\",\n \"created_at\",\n \"updated_at\",\n \"created_by\",\n \"updated_by\",\n]);\n\n/**\n * True for a schema field that is one of AUDIT_FIELDS. The backend always\n * emits these readOnly. A writable field that merely shares a name (a natural\n * `id` key, say) is domain data and is never treated as audit.\n */\nexport function isAuditField(field: Pick<FieldDef, \"name\" | \"readOnly\">): boolean {\n return field.readOnly && AUDIT_FIELDS.includes(field.name);\n}\n\n/**\n * Splits fields into domain fields (schema order kept) and audit fields\n * (AUDIT_FIELDS order).\n */\nexport function partitionAuditFields<F extends Pick<FieldDef, \"name\" | \"readOnly\">>(\n fields: readonly F[],\n): { domain: F[]; audit: F[] } {\n const domain: F[] = [];\n const audit: F[] = [];\n for (const field of fields) {\n (isAuditField(field) ? audit : domain).push(field);\n }\n audit.sort((a, b) => AUDIT_FIELDS.indexOf(a.name) - AUDIT_FIELDS.indexOf(b.name));\n return { domain, audit };\n}\n","/**\n * Human label heuristic for resource objects (contract \"ResourceTable\").\n *\n * Used by ResourceTable's relation cells, ResourceSelect's options and\n * ResourceDetail's relation values. Overridable everywhere it is used:\n * ResourceTable takes `getRowLabel`, ResourceSelect takes `getOptionLabel`.\n */\n\nconst LABEL_KEYS = [\"name\", \"title\", \"label\", \"email\", \"str\"] as const;\n\n/**\n * Returns the first non-empty string among the `name` → `title` → `label` →\n * `email` → `str` keys, falling back to `String(id)` and finally \"\".\n */\nexport function displayLabel(obj: Record<string, unknown>): string {\n for (const key of LABEL_KEYS) {\n const value = obj[key];\n if (typeof value === \"string\" && value.trim().length > 0) return value;\n }\n const id = obj[\"id\"];\n if (id !== null && id !== undefined) return String(id);\n return \"\";\n}\n","/**\n * Internal helpers for ResourceTable (contract \"ResourceTable\" + D5).\n * Pure functions, unit-tested directly. Not part of the public barrel.\n */\nimport type { DefaultError, DefaultOptions } from \"@tanstack/react-query\";\nimport type { SortingState } from \"@tanstack/react-table\";\n\n/**\n * Maps TanStack sorting state to the DRF `ordering` query parameter.\n * Column ids equal schema field names verbatim (that IS the ordering\n * contract, D5), so `[{id: \"title\", desc: true}]` becomes `-title`.\n */\nexport function sortingToOrdering(sorting: SortingState): string | undefined {\n if (sorting.length === 0) return undefined;\n return sorting.map((entry) => (entry.desc ? `-${entry.id}` : entry.id)).join(\",\");\n}\n\n/** `\"-title,starts_at\"` → TanStack sorting state (the inverse of sortingToOrdering). */\nexport function orderingToSorting(ordering: string): SortingState {\n return ordering\n .split(\",\")\n .map((part) => part.trim())\n .filter((part) => part.length > 0 && part !== \"-\")\n .map((part) =>\n part.startsWith(\"-\") ? { id: part.slice(1), desc: true } : { id: part, desc: false },\n );\n}\n\n/** The HTTP status of a KarniApiError-shaped error, if it has one. */\nexport function statusOf(error: unknown): number | undefined {\n if (typeof error !== \"object\" || error === null || !(\"status\" in error)) return undefined;\n const status = (error as { status: unknown }).status;\n return typeof status === \"number\" ? status : undefined;\n}\n\n/**\n * Duck-typed 404 check (works with KarniApiError or any error exposing a\n * numeric `status`), used for the D5 page-clamp: a list 404 with page > 1\n * decrements the page and refetches as loading, never as an error.\n */\nexport function isNotFoundError(error: unknown): boolean {\n return statusOf(error) === 404;\n}\n\n/** The `retry` default of the app's QueryClient (`undefined`: TanStack's own). */\nexport type RetryDefault = NonNullable<DefaultOptions[\"queries\"]>[\"retry\"];\n\n/**\n * The list query's retry rule, under the app's own. A request the server\n * refused (4xx) fails the same way again, so it is never retried, except a\n * timeout (408) or a rate limit (429). Anything else (5xx, the network)\n * retries as the app's QueryClient `retry` default says: three tries when it\n * sets none, and none at all with `retry: false`, which shows the error at once.\n */\nexport function listRetry(\n appDefault: RetryDefault,\n): (failureCount: number, error: DefaultError) => boolean {\n return (failureCount, error) => {\n const status = statusOf(error);\n if (status !== undefined && status >= 400 && status < 500 && status !== 408 && status !== 429) {\n return false;\n }\n if (appDefault === undefined) return failureCount < 3;\n if (typeof appDefault === \"boolean\") return appDefault;\n if (typeof appDefault === \"number\") return failureCount < appDefault;\n return appDefault(failureCount, error);\n };\n}\n\n/** \"loose-slots\" → \"loose slots\": the resource as a sentence names it. */\nexport function resourceWords(resource: string): string {\n return resource.replace(/[_-]+/g, \" \").trim().toLowerCase();\n}\n\n/**\n * A conservative English singular (\"events\" → \"event\", \"categories\" →\n * \"category\", \"addresses\" → \"address\"). ResourceTable's `itemLabel` prop\n * replaces it where it guesses wrong.\n */\nexport function singular(plural: string): string {\n if (/[^aeiou]ies$/.test(plural)) return `${plural.slice(0, -3)}y`;\n if (/(?:ss|x|z|ch|sh)es$/.test(plural)) return plural.slice(0, -2);\n if (/[^s]s$/.test(plural)) return plural.slice(0, -1);\n return plural;\n}\n\nexport function capitalised(text: string): string {\n return text.charAt(0).toUpperCase() + text.slice(1);\n}\n\nexport function pageCountFor(count: number | undefined, pageSize: number): number {\n if (count === undefined || count <= 0 || pageSize <= 0) return 1;\n return Math.max(1, Math.ceil(count / pageSize));\n}\n\n/** Safe record view of an unknown row (rows are plain JSON objects). */\nexport function asRecord(value: unknown): Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\n/** Best-effort human message from a KarniApiError-shaped or plain Error. */\nexport function errorMessage(error: unknown): string {\n if (typeof error === \"object\" && error !== null) {\n const data = (error as { data?: unknown }).data;\n if (typeof data === \"object\" && data !== null) {\n const detail = (data as { detail?: unknown }).detail;\n if (typeof detail === \"string\" && detail.length > 0) return detail;\n }\n const message = (error as { message?: unknown }).message;\n if (typeof message === \"string\" && message.length > 0) return message;\n }\n return \"Something went wrong while loading this table.\";\n}\n\n/**\n * Display label for an enum member: ALL_CAPS and lower_snake constants are\n * prettified (\"DRAFT\" → \"Draft\", \"in_progress\" → \"In progress\"). Mixed-case\n * values (\"iOS\") pass through untouched.\n */\nexport function enumLabel(\n value: string | number,\n labels?: Readonly<Record<string, string>>,\n): string {\n const known = labels?.[String(value)];\n if (known !== undefined) return known;\n if (typeof value === \"number\") return String(value);\n const simple = /^[A-Za-z0-9_ ]+$/.test(value);\n if (simple && (value === value.toUpperCase() || value === value.toLowerCase())) {\n const spaced = value.toLowerCase().replace(/_+/g, \" \").trim();\n if (spaced.length === 0) return value;\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n }\n return value;\n}\n","/**\n * Reads an operation's `x-karni-access` rule against the signed-in user, so\n * ResourceTable leaves out the actions a role cannot perform (create, edit,\n * delete) instead of offering a button that ends in \"You can't\".\n *\n * The rule is the backend's own predicate, published per operation:\n * `{\"public\": true}`, `{\"authenticated\": true}`, `{\"role\": [...]}`,\n * `{\"owned\": \"organizer\"}`, `{\"any\": [...]}`, `{\"all\": [...]}`, `{\"deny\": ...}`\n * and predicates only the server can answer (`can`, `granted`, `where`,\n * `unscoped`). The answer is three-valued. It is `false` only when the rule\n * certainly refuses, and `undefined` when the client cannot tell (no\n * AuthProvider, a grant, a custom function). `undefined` keeps the action:\n * the server still enforces, and a refusal is then reported in plain words.\n *\n * Internal to @karni/ui. Escape hatch: ResourceTable's `canCreate`,\n * `canEdit` and `canDelete` props replace this evaluation.\n */\nimport type { KarniUser } from \"../../../auth/types\";\nimport type { KarniAccessRule } from \"../../../schema/types\";\nimport { asRecord } from \"./table-utils\";\n\n/** Who is asking. `null` when the table renders outside an AuthProvider. */\nexport interface AccessIdentity {\n status: \"loading\" | \"authenticated\" | \"anonymous\";\n user: KarniUser | null;\n}\n\nconst LOOKUP_SEPARATOR = \"__\";\n\nfunction sameId(value: unknown, id: string | number): boolean {\n if (value === null || value === undefined) return false;\n if (typeof value === \"object\" && !Array.isArray(value)) {\n return sameId(asRecord(value)[\"id\"], id);\n }\n return String(value) === String(id);\n}\n\n/** `Owned(\"organizer\")` on one row: is the row's owner field the user? */\nfunction ownedBy(path: string, identity: AccessIdentity, row: unknown): boolean | undefined {\n if (identity.status !== \"authenticated\" || identity.user === null) {\n return identity.status === \"anonymous\" ? false : undefined;\n }\n // A traversal (\"event__organizer\") is not in the row: only the server knows.\n if (row === undefined || path.includes(LOOKUP_SEPARATOR)) return undefined;\n const record = asRecord(row);\n const key = path === \"pk\" ? \"id\" : path;\n if (!(key in record)) return undefined;\n const value = record[key];\n const userId = identity.user.id;\n return Array.isArray(value) ? value.some((item) => sameId(item, userId)) : sameId(value, userId);\n}\n\nfunction combine(\n parts: readonly unknown[],\n identity: AccessIdentity | null,\n row: unknown,\n any: boolean,\n): boolean | undefined {\n let unknownSeen = false;\n for (const part of parts) {\n const answer = evaluateAccess(asRecord(part), identity, row);\n if (answer === any) return any;\n if (answer === undefined) unknownSeen = true;\n }\n return unknownSeen ? undefined : !any;\n}\n\n/**\n * `true` when the rule allows the operation for this identity (and row),\n * `false` when it refuses, `undefined` when only the server can tell.\n */\nexport function evaluateAccess(\n rule: KarniAccessRule | undefined,\n identity: AccessIdentity | null,\n row?: unknown,\n): boolean | undefined {\n if (rule === undefined) return undefined;\n if (rule[\"public\"] === true) return true;\n if (\"deny\" in rule) return false;\n if (Array.isArray(rule[\"any\"])) return combine(rule[\"any\"], identity, row, true);\n if (Array.isArray(rule[\"all\"])) return combine(rule[\"all\"], identity, row, false);\n if (identity === null || identity.status === \"loading\") return undefined;\n if (rule[\"authenticated\"] === true) return identity.status === \"authenticated\";\n const roles = rule[\"role\"];\n if (Array.isArray(roles)) {\n if (identity.status !== \"authenticated\" || identity.user === null) return false;\n const held = new Set(identity.user.roles);\n return roles.some((name) => typeof name === \"string\" && held.has(name));\n }\n const owned = rule[\"owned\"];\n if (typeof owned === \"string\") return ownedBy(owned, identity, row);\n return undefined;\n}\n","/**\n * ResourceTable's structural columns: the selection checkboxes (bulk select)\n * and the row actions (edit, `rowActions`, delete). Their ids start with\n * \"__\", so they are never sortable, never in the column menu and never URL\n * state. Internal to @karni/ui.\n */\nimport type { ColumnDef } from \"@tanstack/react-table\";\nimport * as React from \"react\";\nimport { cn } from \"../../../lib/cn\";\nimport { Button } from \"../../primitives/button\";\nimport { Checkbox } from \"../../primitives/checkbox\";\n\nexport const SELECT_COLUMN = \"__select__\";\nexport const ACTIONS_COLUMN = \"__actions__\";\n\nexport function isStructural(columnId: string): boolean {\n return columnId === SELECT_COLUMN || columnId === ACTIONS_COLUMN;\n}\n\nexport function selectionColumn<T>(options: {\n rowLabel: (row: T) => string;\n resourceLabel: string;\n}): ColumnDef<T> {\n const { rowLabel, resourceLabel } = options;\n return {\n id: SELECT_COLUMN,\n enableSorting: false,\n enableHiding: false,\n header: ({ table }) => (\n <Checkbox\n aria-label={`Select all ${resourceLabel} on this page`}\n checked={\n table.getIsAllPageRowsSelected()\n ? true\n : table.getIsSomePageRowsSelected()\n ? \"indeterminate\"\n : false\n }\n onCheckedChange={(checked) => table.toggleAllPageRowsSelected(checked === true)}\n />\n ),\n cell: ({ row }) => (\n <div className=\"flex items-center\" onClick={(event) => event.stopPropagation()}>\n <Checkbox\n aria-label={`Select ${rowLabel(row.original)}`}\n checked={row.getIsSelected()}\n onCheckedChange={(checked) => row.toggleSelected(checked === true)}\n />\n </div>\n ),\n };\n}\n\nexport interface RowActionsOptions<T> {\n rowActions?: (row: T) => React.ReactNode;\n onEdit?: (row: T) => void;\n /** Whether this row's edit action is offered (the role may change it). */\n canEdit: (row: T) => boolean;\n /** Present when deletes are enabled. Asks to confirm, then deletes. */\n onDelete?: (row: T, trigger: HTMLButtonElement) => void;\n canDelete: (row: T) => boolean;\n /** Button geometry for the current density. */\n buttonClassName: string;\n}\n\n/** The actions of one row, in the order a row reads: edit, custom, delete. */\nexport function RowActions<T>(props: RowActionsOptions<T> & { row: T }): React.ReactElement {\n const { row, rowActions, onEdit, canEdit, onDelete, canDelete, buttonClassName } = props;\n return (\n <>\n {onEdit !== undefined && canEdit(row) && (\n <Button variant=\"ghost\" size=\"sm\" className={buttonClassName} onClick={() => onEdit(row)}>\n Edit\n </Button>\n )}\n {rowActions?.(row)}\n {onDelete !== undefined && canDelete(row) && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className={cn(\"text-destructive hover:text-destructive\", buttonClassName)}\n onClick={(event) => onDelete(row, event.currentTarget)}\n >\n Delete\n </Button>\n )}\n </>\n );\n}\n\nexport function actionsColumn<T>(options: RowActionsOptions<T>): ColumnDef<T> {\n return {\n id: ACTIONS_COLUMN,\n enableSorting: false,\n enableHiding: false,\n header: () => <span className=\"sr-only\">Actions</span>,\n cell: ({ row }) => (\n <div\n className=\"flex items-center justify-end gap-1\"\n onClick={(event) => event.stopPropagation()}\n >\n <RowActions {...options} row={row.original} />\n </div>\n ),\n };\n}\n","/**\n * ResourceTable's narrow layout: each row a card (the RowCard slot), with a\n * \"select all on this page\" checkbox and a sort choice above them, since the\n * column headers are gone. Internal to @karni/ui.\n */\nimport { flexRender, type Row, type Table } from \"@tanstack/react-table\";\nimport * as React from \"react\";\nimport { cn } from \"../../../lib/cn\";\nimport { Checkbox } from \"../../primitives/checkbox\";\nimport { Select } from \"../../primitives/select\";\nimport type { ResourceTableDensity } from \"./preferences\";\nimport type { ResourceTableRowCardProps } from \"./RowCard\";\nimport { ACTIONS_COLUMN, SELECT_COLUMN } from \"./structural-columns\";\n\nexport interface CardListProps<T> {\n table: Table<T>;\n caption: string;\n resourceLabel: string;\n density: ResourceTableDensity;\n Card: React.ComponentType<ResourceTableRowCardProps<unknown>>;\n rowLabel: (row: T) => string;\n /** Overrides the first column as each card's title. */\n useRowLabelAsTitle: boolean;\n onRowClick?: (row: T) => void;\n failures: Readonly<Record<string, string>>;\n /** Plain-text column names, for the sort choice. */\n columnLabel: (columnId: string) => string;\n /** The current ordering and a way to change it (\"\" is the default order). */\n ordering: string;\n onOrderingChange: (ordering: string) => void;\n /** A sort or page change is loading: the list announces busy. */\n busy: boolean;\n dimmed: boolean;\n /**\n * The list element. Focusable by script only (tabIndex -1): where focus\n * lands when the control that had it is gone (a deleted row, the bulk\n * toolbar after its action), as the table layout's scroll region is.\n */\n listRef?: React.Ref<HTMLUListElement>;\n}\n\nfunction cellOf<T>(row: Row<T>, columnId: string): React.ReactNode {\n const cell = row.getVisibleCells().find((candidate) => candidate.column.id === columnId);\n return cell === undefined ? null : flexRender(cell.column.columnDef.cell, cell.getContext());\n}\n\nexport function CardList<T>(props: CardListProps<T>): React.ReactElement {\n const {\n table,\n caption,\n resourceLabel,\n density,\n Card,\n rowLabel,\n useRowLabelAsTitle,\n onRowClick,\n failures,\n columnLabel,\n ordering,\n onOrderingChange,\n busy,\n dimmed,\n listRef,\n } = props;\n const columns = table.getVisibleLeafColumns();\n const selectable = columns.some((column) => column.id === SELECT_COLUMN);\n const hasActions = columns.some((column) => column.id === ACTIONS_COLUMN);\n const dataColumns = columns.filter(\n (column) => column.id !== SELECT_COLUMN && column.id !== ACTIONS_COLUMN,\n );\n const [titleColumn, ...rest] = dataColumns;\n const sortable = dataColumns.filter((column) => column.getCanSort());\n const sortOptions = sortable.flatMap((column) => [\n { value: column.id, label: `${columnLabel(column.id)}, ascending` },\n { value: `-${column.id}`, label: `${columnLabel(column.id)}, descending` },\n ]);\n const sortValue = sortOptions.some((option) => option.value === ordering) ? ordering : null;\n const labels = new Map<string, React.ReactNode>(\n table\n .getFlatHeaders()\n .map((header) => [\n header.column.id,\n flexRender(header.column.columnDef.header, header.getContext()),\n ]),\n );\n\n return (\n <div className=\"flex flex-col gap-3\">\n {(selectable || sortOptions.length > 0) && (\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n {selectable ? (\n <label className=\"flex items-center gap-2 text-sm text-foreground\">\n <Checkbox\n checked={\n table.getIsAllPageRowsSelected()\n ? true\n : table.getIsSomePageRowsSelected()\n ? \"indeterminate\"\n : false\n }\n onCheckedChange={(checked) => table.toggleAllPageRowsSelected(checked === true)}\n />\n Select all {resourceLabel} on this page\n </label>\n ) : (\n <span />\n )}\n {sortOptions.length > 0 && (\n // Never disabled while a page loads: a disabled trigger cannot hold\n // focus, so the keyboard would drop to <body> right after choosing.\n // A choice is an absolute ordering, so applying it twice is harmless.\n <Select\n aria-label=\"Sort by\"\n className=\"h-9 w-auto min-w-40\"\n value={sortValue}\n placeholder=\"Sort by\"\n clearable\n clearLabel=\"Sort: default order\"\n options={sortOptions}\n onValueChange={(next) => onOrderingChange(next ?? \"\")}\n />\n )}\n </div>\n )}\n <ul\n ref={listRef}\n aria-label={caption}\n aria-busy={busy || undefined}\n tabIndex={-1}\n className={cn(\n \"flex flex-col gap-3 rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n dimmed && \"cursor-progress\",\n )}\n >\n {table.getRowModel().rows.map((row) => {\n const title =\n useRowLabelAsTitle || titleColumn === undefined\n ? rowLabel(row.original)\n : cellOf(row, titleColumn.id);\n return (\n <Card\n key={row.id}\n row={row.original}\n title={title}\n fields={rest.map((column) => ({\n id: column.id,\n label: labels.get(column.id) ?? columnLabel(column.id),\n value: cellOf(row, column.id),\n }))}\n selection={\n selectable ? (\n <Checkbox\n aria-label={`Select ${rowLabel(row.original)}`}\n checked={row.getIsSelected()}\n onCheckedChange={(checked) => row.toggleSelected(checked === true)}\n />\n ) : undefined\n }\n actions={hasActions ? cellOf(row, ACTIONS_COLUMN) : undefined}\n onOpen={onRowClick !== undefined ? () => onRowClick(row.original) : undefined}\n selected={row.getIsSelected()}\n failure={failures[row.id]}\n density={density}\n />\n );\n })}\n </ul>\n </div>\n );\n}\n","import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\n\nregisterComponentRole(\"modal\", \"Modal\");\n\ntype IconProps = React.SVGAttributes<SVGSVGElement>;\n\nfunction CloseIcon(props: IconProps): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Escape hatch for footer buttons: any element wrapped in\n * `<ModalClose asChild>` closes the modal on click (re-exported Radix\n * Dialog.Close).\n */\nexport const ModalClose = DialogPrimitive.Close;\n\n/**\n * The modal's title: names the dialog (aria-labelledby). A custom `Header`\n * slot renders it so the dialog stays labelled.\n */\nexport const ModalTitle = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold leading-none tracking-tight\", className)}\n {...props}\n />\n));\nModalTitle.displayName = \"ModalTitle\";\n\n/** The modal's description: describes the dialog (aria-describedby). */\nexport const ModalDescription = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nModalDescription.displayName = \"ModalDescription\";\n\n/** What the `Header` slot receives. Render ModalTitle (and ModalDescription) inside it. */\nexport interface ModalHeaderProps {\n title: React.ReactNode;\n /** The `description` prop, or undefined. */\n description?: React.ReactNode;\n}\n\n/** What the `Footer` slot receives: the `footer` prop. */\nexport interface ModalFooterProps {\n children: React.ReactNode;\n}\n\n/** What the `CloseButton` slot receives. Wrap your button in <ModalClose asChild>. */\nexport interface ModalCloseButtonProps {\n /** Its accessible name (\"Close\"). */\n label: string;\n}\n\n/** The parts of the dialog a project can replace (`slots={{ Footer: StickyFooter }}`). */\nexport interface ModalSlots {\n /** Title and description. It must render ModalTitle. */\n Header: React.ComponentType<ModalHeaderProps>;\n /** The actions row. */\n Footer: React.ComponentType<ModalFooterProps>;\n /** The top-right close button. It must close through ModalClose. */\n CloseButton: React.ComponentType<ModalCloseButtonProps>;\n}\n\nfunction DefaultHeader({ title, description }: ModalHeaderProps): React.ReactElement {\n return (\n <div className=\"grid gap-1.5\">\n <ModalTitle>{title}</ModalTitle>\n {description != null && <ModalDescription>{description}</ModalDescription>}\n </div>\n );\n}\n\nfunction DefaultFooter({ children }: ModalFooterProps): React.ReactElement {\n return <div className=\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\">{children}</div>;\n}\n\nfunction DefaultCloseButton({ label }: ModalCloseButtonProps): React.ReactElement {\n return (\n <DialogPrimitive.Close className=\"absolute right-4 top-4 rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none\">\n <CloseIcon className=\"h-4 w-4\" />\n <span className=\"sr-only\">{label}</span>\n </DialogPrimitive.Close>\n );\n}\n\n/** The default pieces of the dialog, for wrapping one. */\nexport const defaultModalSlots: ModalSlots = {\n Header: DefaultHeader,\n Footer: DefaultFooter,\n CloseButton: DefaultCloseButton,\n};\n\nexport interface ModalProps {\n /** Dialog title, always rendered (Radix requires it for accessibility). */\n title: React.ReactNode;\n /** Optional description under the title, linked via aria-describedby. */\n description?: React.ReactNode;\n /** Body content. */\n children?: React.ReactNode;\n /** Footer slot (actions row). Use <ModalClose asChild> for cancel buttons. */\n footer?: React.ReactNode;\n /**\n * Uncontrolled usage: a node (usually a Button) that opens the modal,\n * rendered through Radix `asChild`.\n */\n trigger?: React.ReactNode;\n /** Controlled open state (pair with onOpenChange). */\n open?: boolean;\n /** Initial state for uncontrolled usage. */\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Hides the top-right X button. */\n hideCloseButton?: boolean;\n /** Replaces the Header, Footer or CloseButton. See ModalSlots. */\n slots?: Partial<ModalSlots>;\n /** Extra classes for the content panel. */\n className?: string;\n /**\n * Escape hatch: props spread onto Radix Dialog.Content\n * (onEscapeKeyDown, onInteractOutside, …).\n */\n contentProps?: Omit<\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,\n \"children\" | \"className\"\n >;\n}\n\n/**\n * Themed Radix Dialog. Works controlled (`open` + `onOpenChange`) or\n * uncontrolled via the `trigger` slot, and `footer` is the actions row.\n *\n * Keyboard and screen readers: the dialog is named by its title and\n * described by its description. Focus moves into it on open, Tab stays\n * inside, Escape closes, and focus returns to what opened it.\n *\n * Escape hatches: `slots` replaces the Header, Footer or CloseButton,\n * `contentProps` reaches the Radix content part, `className` restyles the\n * panel, `hideCloseButton` drops the X, and `ModalClose` lets any footer\n * element close the dialog.\n */\nexport function Modal({\n title,\n description,\n children,\n footer,\n trigger,\n open,\n defaultOpen,\n onOpenChange,\n hideCloseButton = false,\n slots,\n className,\n contentProps,\n}: ModalProps): React.ReactElement {\n const { Header, Footer, CloseButton } = { ...defaultModalSlots, ...slots };\n // Without a Description part, Radix warns unless aria-describedby is\n // explicitly cleared; with one (or a consumer-supplied id) leave the key\n // alone so the automatic wiring stands.\n const clearDescribedBy =\n description == null && contentProps?.[\"aria-describedby\"] === undefined\n ? { \"aria-describedby\": undefined }\n : {};\n return (\n <DialogPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\n {trigger != null && <DialogPrimitive.Trigger asChild>{trigger}</DialogPrimitive.Trigger>}\n <DialogPrimitive.Portal>\n <DialogPrimitive.Overlay className=\"fixed inset-0 z-modal bg-overlay\" />\n <DialogPrimitive.Content\n {...contentProps}\n {...clearDescribedBy}\n className={cn(\n // Centred, with a gutter on phones: inset-x-4 + mx-auto under max-w-128.\n // Never taller than the viewport (a phone on its side, an open\n // keyboard): it scrolls inside, since the page behind is locked.\n \"fixed inset-x-4 top-1/2 z-modal mx-auto grid max-h-full max-w-128 -translate-y-1/2 gap-4 overflow-y-auto rounded-lg border border-border bg-background p-6 text-foreground shadow-lg\",\n className,\n )}\n >\n <Header title={title} description={description ?? undefined} />\n {children}\n {footer != null && <Footer>{footer}</Footer>}\n {!hideCloseButton && <CloseButton label=\"Close\" />}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n );\n}\n","/**\n * The question ResourceTable asks before destructive work (a row delete, a\n * destructive bulk action): a Modal (Radix dialog, so focus is trapped and\n * Escape cancels) naming the action and how many rows it touches. While the\n * work runs the confirm button shows progress. A failure is reported inside\n * the dialog in plain words, with the button kept for another try when\n * trying again can help. Focus returns to the control that opened it.\n * Internal to @karni/ui.\n */\nimport * as React from \"react\";\nimport { describeError, type KarniErrorContext } from \"../../../states/describe-error\";\nimport { ErrorState } from \"../../../states/ErrorState\";\nimport { PendingButton } from \"../../../states/PendingButton\";\nimport { Modal, ModalClose } from \"../../modal/modal\";\nimport { Button } from \"../../primitives/button\";\n\nexport interface ConfirmDialogProps {\n open: boolean;\n title: React.ReactNode;\n description?: React.ReactNode;\n confirmLabel: string;\n pendingLabel?: string;\n destructive?: boolean;\n pending: boolean;\n /** The last attempt's failure, shown in the dialog. */\n error?: unknown;\n errorContext?: KarniErrorContext;\n onConfirm: () => void;\n onCancel: () => void;\n /** Where focus goes when the dialog closes (the control that opened it, or a fallback). */\n returnFocus: () => HTMLElement | null;\n}\n\nexport function ConfirmDialog(props: ConfirmDialogProps): React.ReactElement {\n const {\n open,\n title,\n description,\n confirmLabel,\n pendingLabel,\n destructive = false,\n pending,\n error,\n errorContext,\n onConfirm,\n onCancel,\n returnFocus,\n } = props;\n const failed = error !== undefined && error !== null;\n const retryable = !failed || describeError(error, errorContext).retryable;\n return (\n <Modal\n open={open}\n onOpenChange={(next) => {\n if (!next && !pending) onCancel();\n }}\n title={title}\n description={description}\n contentProps={{\n onCloseAutoFocus: (event) => {\n event.preventDefault();\n returnFocus()?.focus();\n },\n }}\n footer={\n <>\n <ModalClose asChild>\n <Button variant=\"outline\" disabled={pending}>\n Cancel\n </Button>\n </ModalClose>\n {retryable && (\n <PendingButton\n variant={destructive ? \"destructive\" : \"default\"}\n pending={pending}\n pendingLabel={pendingLabel}\n onClick={onConfirm}\n >\n {failed ? \"Try again\" : confirmLabel}\n </PendingButton>\n )}\n </>\n }\n >\n {failed && <ErrorState variant=\"inline\" error={error} context={errorContext} />}\n </Modal>\n );\n}\n","/**\n * Schema → TanStack column derivation (contract \"ResourceTable\" + D5).\n *\n * - Domain fields first, in declaration order. writeOnly / json / file /\n * unknown fields are skipped unless the consumer explicitly names them in\n * the `columns` prop.\n * - Audit fields (AUDIT_FIELDS: id, created_at, updated_at, created_by,\n * updated_by) are hidden by default. A `columns` entry naming one (without\n * `hidden: true`) or `showAuditFields` brings it back, after the domain\n * columns, in AUDIT_FIELDS order.\n * - Column ids equal schema field names verbatim: that IS the DRF `ordering`\n * contract (D5).\n * - relation / json / file / array / unknown columns are unsortable by\n * default. The per-field `sortable` override wins both ways.\n * - Cells: booleans → check icon, dates localized, enum labels prettified,\n * relations → displayLabel of the expanded object else the raw id in\n * <code>. The label heuristic is overridable via `getRowLabel`.\n */\nimport type { ColumnDef } from \"@tanstack/react-table\";\nimport * as React from \"react\";\nimport { humanize } from \"../../../schema/parse\";\nimport type { FieldDef, FieldKind } from \"../../../schema/types\";\nimport { CheckIcon } from \"../../primitives/icons\";\nimport { isAuditField, partitionAuditFields } from \"../audit-fields\";\nimport { displayLabel } from \"../displayLabel\";\nimport { EmptyValue } from \"../empty-value\";\nimport { asRecord, enumLabel } from \"./table-utils\";\n\n/** Per-field override merged over the schema-derived column. */\nexport interface ResourceColumn<T = Record<string, unknown>> {\n field: string;\n header?: React.ReactNode;\n cell?: (row: T) => React.ReactNode;\n hidden?: boolean;\n sortable?: boolean;\n}\n\ntype RowLabeler = (row: Record<string, unknown>) => string;\n\nconst DEFAULT_SKIPPED_KINDS: ReadonlySet<FieldKind> = new Set([\"json\", \"file\", \"unknown\"]);\nconst UNSORTABLE_KINDS: ReadonlySet<FieldKind> = new Set([\n \"relation\",\n \"json\",\n \"file\",\n \"array\",\n \"unknown\",\n]);\n\nfunction BooleanCell({ value }: { value: boolean }): React.ReactElement {\n return value ? (\n <span className=\"inline-flex items-center text-foreground\">\n <CheckIcon className=\"h-4 w-4\" />\n <span className=\"sr-only\">Yes</span>\n </span>\n ) : (\n <span className=\"inline-flex items-center text-muted-foreground\">\n <span aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">No</span>\n </span>\n );\n}\n\nfunction IdCode({ value }: { value: unknown }): React.ReactElement {\n return <code className=\"rounded bg-muted px-1 py-0.5 text-xs\">{String(value)}</code>;\n}\n\nfunction relationItem(item: unknown, label: RowLabeler): React.ReactNode {\n if (item === null || item === undefined) return <EmptyValue />;\n if (typeof item === \"object\" && !Array.isArray(item)) return label(asRecord(item));\n return <IdCode value={item} />;\n}\n\nfunction RelationCell({ value, label }: { value: unknown; label: RowLabeler }): React.ReactElement {\n if (value === null || value === undefined) return <EmptyValue />;\n if (Array.isArray(value)) {\n if (value.length === 0) return <EmptyValue />;\n return (\n <span className=\"inline-flex flex-wrap items-center gap-x-2 gap-y-1\">\n {value.map((item, index) => (\n <React.Fragment key={index}>{relationItem(item, label)}</React.Fragment>\n ))}\n </span>\n );\n }\n return <>{relationItem(value, label)}</>;\n}\n\nfunction dateText(value: unknown, withTime: boolean): string {\n const parsed = new Date(String(value));\n if (Number.isNaN(parsed.getTime())) return String(value);\n return withTime ? parsed.toLocaleString() : parsed.toLocaleDateString();\n}\n\nfunction FileCell({ value }: { value: unknown }): React.ReactElement {\n if (typeof value === \"string\" && value.length > 0) {\n const name = value.split(\"/\").filter(Boolean).pop() ?? value;\n return (\n <a\n href={value}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-primary underline underline-offset-4\"\n onClick={(event) => event.stopPropagation()}\n >\n {name}\n </a>\n );\n }\n if (typeof File !== \"undefined\" && value instanceof File) return <>{value.name}</>;\n return <EmptyValue />;\n}\n\nfunction JsonCell({ value }: { value: unknown }): React.ReactElement {\n let text: string;\n try {\n text = JSON.stringify(value) ?? String(value);\n } catch {\n text = String(value);\n }\n const shown = text.length > 80 ? `${text.slice(0, 80)}…` : text;\n return (\n <code className=\"rounded bg-muted px-1 py-0.5 text-xs\" title={text}>\n {shown}\n </code>\n );\n}\n\n/**\n * Default cell renderer for a schema field's value. Exported for reuse by\n * custom cells that want the stock formatting for other fields.\n */\nexport function renderFieldCell(\n field: FieldDef,\n value: unknown,\n getRowLabel?: RowLabeler,\n): React.ReactNode {\n // The same empty rendering as ResourceDetail: a dash, read as \"empty\".\n if (value === null || value === undefined || value === \"\") return <EmptyValue />;\n switch (field.kind) {\n case \"boolean\":\n return <BooleanCell value={value === true} />;\n case \"date\":\n return dateText(value, false);\n case \"datetime\":\n return dateText(value, true);\n case \"enum\":\n return typeof value === \"string\" || typeof value === \"number\"\n ? enumLabel(value, field.enumLabels)\n : String(value);\n case \"relation\":\n return <RelationCell value={value} label={getRowLabel ?? displayLabel} />;\n case \"number\":\n case \"integer\":\n return (\n <span className=\"tabular-nums\">\n {typeof value === \"number\" ? value.toLocaleString() : String(value)}\n </span>\n );\n case \"file\":\n return <FileCell value={value} />;\n case \"json\":\n return <JsonCell value={value} />;\n case \"array\":\n return Array.isArray(value) ? value.map((item) => String(item)).join(\", \") : String(value);\n case \"text\":\n return (\n <span className=\"block max-w-80 truncate\" title={String(value)}>\n {String(value)}\n </span>\n );\n default:\n return String(value);\n }\n}\n\n/** ColumnDef.header only takes a string or a render function, so nodes get wrapped. */\nfunction headerTemplate<T>(content: React.ReactNode): ColumnDef<T>[\"header\"] {\n return typeof content === \"string\" ? content : () => content;\n}\n\nexport interface DeriveColumnsArgs<T> {\n fields: readonly FieldDef[];\n columns?: ReadonlyArray<ResourceColumn<T>>;\n getRowLabel?: RowLabeler;\n /** Show every audit field (AUDIT_FIELDS) without naming each in `columns`. */\n showAuditFields?: boolean;\n}\n\nfunction columnForField<T>(\n field: FieldDef,\n override: ResourceColumn<T> | undefined,\n getRowLabel: RowLabeler | undefined,\n): ColumnDef<T> {\n const customCell = override?.cell;\n return {\n id: field.name,\n accessorFn: (row) => asRecord(row)[field.name],\n header: headerTemplate(override?.header ?? field.label),\n cell:\n customCell !== undefined\n ? (ctx) => customCell(ctx.row.original)\n : (ctx) => renderFieldCell(field, ctx.getValue(), getRowLabel),\n enableSorting: override?.sortable ?? !UNSORTABLE_KINDS.has(field.kind),\n };\n}\n\n/**\n * Builds the derived column set: domain columns (schema order), then any\n * shown audit columns (AUDIT_FIELDS order), then `columns` entries naming\n * fields the schema does not declare, as plain accessor columns (escape hatch\n * for computed or server-extra keys). `columns` overrides merge onto their\n * fields, and naming a default-skipped field (json, audit, ...) shows it.\n */\nexport function deriveColumns<T>(args: DeriveColumnsArgs<T>): Array<ColumnDef<T>> {\n const pending = new Map<string, ResourceColumn<T>>(\n (args.columns ?? []).map((column) => [column.field, column]),\n );\n const defs: Array<ColumnDef<T>> = [];\n const { domain, audit } = partitionAuditFields(args.fields);\n\n for (const field of [...domain, ...audit]) {\n const override = pending.get(field.name);\n pending.delete(field.name);\n if (override?.hidden === true) continue;\n if (override === undefined) {\n if (field.writeOnly || DEFAULT_SKIPPED_KINDS.has(field.kind)) continue;\n if (args.showAuditFields !== true && isAuditField(field)) continue;\n }\n defs.push(columnForField(field, override, args.getRowLabel));\n }\n\n for (const [name, override] of pending) {\n if (override.hidden === true) continue;\n const customCell = override.cell;\n defs.push({\n id: name,\n accessorFn: (row) => asRecord(row)[name],\n header: headerTemplate(override.header ?? humanize(name)),\n cell:\n customCell !== undefined\n ? (ctx) => customCell(ctx.row.original)\n : (ctx) => {\n const value = ctx.getValue();\n return value === null || value === undefined ? <EmptyValue /> : String(value);\n },\n enableSorting: override.sortable ?? false,\n });\n }\n\n return defs;\n}\n","/**\n * Import and export hooks (karni.transfer, ADR 0002 P6).\n *\n * - `downloadResourceExport(client, resource, params, format)` fetches\n * `GET /<resource>/export/` with the list's own query (filters, search,\n * ordering) and hands the file to the browser. ResourceTable's export\n * buttons call it.\n * - `useImportDescribe(resource)` reads `GET /<resource>/import/`: the\n * importable fields and the user's remembered mapping.\n * - `useImportJob(resource, jobId)` reads one job's state and polls while the\n * backend is previewing or committing it in Celery.\n * - `useImportActions(resource)` holds the three mutations: upload (creates\n * the job), preview (the mandatory dry run, with the mapping) and commit.\n *\n * The backend decides everything that matters: which fields the role may\n * write, which rows are in scope, what a row's errors are. The hooks render\n * its answers without filtering.\n */\nimport {\n useMutation,\n useQuery,\n useQueryClient,\n type UseMutationResult,\n type UseQueryOptions,\n type UseQueryResult,\n} from \"@tanstack/react-query\";\nimport type { KarniClient, KarniQueryValue } from \"../schema/client\";\nimport { useKarniClient } from \"../schema/provider\";\nimport { karniKeys } from \"./keys\";\nimport { buildListQuery, listPath } from \"./params\";\nimport type { ResourceListParams } from \"./types\";\n\nexport type ExportFormat = \"csv\" | \"xlsx\";\n\nexport type ImportColumnKind =\n | \"text\"\n | \"integer\"\n | \"decimal\"\n | \"boolean\"\n | \"date\"\n | \"datetime\"\n | \"choice\"\n | \"relation\"\n | \"relations\"\n | \"json\"\n | \"file\"\n | \"other\";\n\nexport interface ImportColumn {\n name: string;\n label: string;\n kind: ImportColumnKind;\n required: boolean;\n readable: boolean;\n writable: boolean;\n choices: ReadonlyArray<{ value: string; label: string }>;\n /** `app_label.model` of a relation's target. */\n target: string | null;\n /** The target field a relation column carries (its natural key), else the id. */\n lookup: string | null;\n help: string;\n /** The column an import matches existing rows on. */\n key: boolean;\n}\n\nexport interface ImportDescription {\n fields: ImportColumn[];\n /** The mapping the user last confirmed for this resource (header → field). */\n mapping: Record<string, string>;\n /** Files with more rows than this run in Celery. Poll the job. */\n inline_rows: number;\n max_rows: number;\n key: string | null;\n}\n\nexport type ImportStatus =\n \"uploaded\" | \"previewing\" | \"previewed\" | \"committing\" | \"done\" | \"failed\";\n\nexport interface ImportResult {\n rows_total: number;\n created: number;\n updated: number;\n unchanged: number;\n errors: number;\n skipped: number;\n}\n\nexport interface ImportProblem {\n /** The line in the file (the header is line 1). */\n row: number;\n field: string;\n message: string;\n}\n\nexport interface ImportJob {\n id: string;\n model: string | null;\n status: ImportStatus;\n file_name: string;\n format: string;\n columns: string[];\n mapping: Record<string, string>;\n rows_total: number;\n rows_done: number;\n async: boolean;\n result: ImportResult | null;\n problems: ImportProblem[];\n error: string | null;\n batch: number | null;\n created_at: string | null;\n fields?: ImportColumn[];\n}\n\n/** The query key of a resource's import description. */\nexport function importDescribeKey(resource: string): readonly unknown[] {\n return [...karniKeys.resource(resource), \"import\", \"describe\"] as const;\n}\n\n/** The query key of one import job. */\nexport function importJobKey(resource: string, jobId: string): readonly unknown[] {\n return [...karniKeys.resource(resource), \"import\", \"job\", jobId] as const;\n}\n\nfunction importPath(resource: string, suffix = \"\"): string {\n return `${listPath(resource)}import/${suffix}`;\n}\n\nconst IN_FLIGHT: ReadonlySet<ImportStatus> = new Set<ImportStatus>([\"previewing\", \"committing\"]);\n\n/** True while an import job is previewing or committing (the states worth polling). */\nexport function isImportInFlight(job: ImportJob | undefined): boolean {\n return job !== undefined && IN_FLIGHT.has(job.status);\n}\n\n/** The name the backend suggested, else \"<resource>.<format>\". */\nfunction filenameFrom(response: Response, fallback: string): string {\n const header = response.headers.get(\"content-disposition\") ?? \"\";\n const match = /filename=\"?([^\";]+)\"?/i.exec(header);\n return match?.[1] ?? fallback;\n}\n\n/**\n * Fetches `GET /<resource>/export/?format=…` with the list's query and saves\n * it through a temporary object URL. Resolves with the file name. Throws the\n * `KarniApiError` the backend answered (a 400 with code E803 when the export\n * is larger than `KARNI_EXPORT_MAX_ROWS`).\n */\nexport async function downloadResourceExport(\n client: KarniClient,\n resource: string,\n params: ResourceListParams | undefined,\n format: ExportFormat = \"csv\",\n): Promise<string> {\n const query: Record<string, KarniQueryValue> = { ...buildListQuery(params), format };\n delete query[\"page\"];\n delete query[\"page_size\"];\n const response = await client.requestRaw(`${listPath(resource)}export/`, { query });\n const blob = await response.blob();\n const filename = filenameFrom(response, `${resource}.${format}`);\n saveBlob(blob, filename);\n return filename;\n}\n\n/** Hands a blob to the browser as a download (a no-op outside a DOM, e.g. SSR). */\nexport function saveBlob(blob: Blob, filename: string): void {\n if (typeof document === \"undefined\" || typeof URL.createObjectURL !== \"function\") return;\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = filename;\n document.body.appendChild(anchor);\n anchor.click();\n anchor.remove();\n URL.revokeObjectURL(url);\n}\n\n/** Fetches `GET /<resource>/import/template/?format=…` and saves it (the headers, an example, allowed values). */\nexport async function downloadImportTemplate(\n client: KarniClient,\n resource: string,\n format: ExportFormat = \"xlsx\",\n): Promise<string> {\n const response = await client.requestRaw(importPath(resource, \"template/\"), {\n query: { format },\n });\n const blob = await response.blob();\n const filename = filenameFrom(response, `${resource}-template.${format}`);\n saveBlob(blob, filename);\n return filename;\n}\n\n/** Fetches what a resource's import accepts: its columns, required fields and allowed values. */\nexport function useImportDescribe(\n resource: string,\n options?: Omit<UseQueryOptions<ImportDescription>, \"queryKey\" | \"queryFn\">,\n): UseQueryResult<ImportDescription> {\n const client = useKarniClient();\n return useQuery<ImportDescription>({\n ...options,\n queryKey: importDescribeKey(resource),\n queryFn: ({ signal }) => client.request<ImportDescription>(importPath(resource), { signal }),\n });\n}\n\nexport interface UseImportJobOptions {\n /** Polling interval while the job is previewing/committing. Default 1500 ms. */\n pollMs?: number;\n}\n\n/** Fetches one import job and polls it while it runs. */\nexport function useImportJob(\n resource: string,\n jobId: string | undefined,\n options?: UseImportJobOptions,\n): UseQueryResult<ImportJob> {\n const client = useKarniClient();\n const pollMs = options?.pollMs ?? 1500;\n return useQuery<ImportJob>({\n queryKey: importJobKey(resource, jobId ?? \"\"),\n enabled: jobId !== undefined,\n queryFn: ({ signal }) =>\n client.request<ImportJob>(importPath(resource, `${encodeURIComponent(jobId ?? \"\")}/`), {\n signal,\n }),\n refetchInterval: (query) => (isImportInFlight(query.state.data) ? pollMs : false),\n });\n}\n\nexport interface UploadImportInput {\n file: File;\n /** An explicit mapping. Otherwise the backend suggests or remembers one. */\n mapping?: Record<string, string>;\n}\n\nexport interface PreviewImportInput {\n jobId: string;\n mapping: Record<string, string>;\n}\n\nexport interface ImportActions {\n upload: UseMutationResult<ImportJob, unknown, UploadImportInput>;\n preview: UseMutationResult<ImportJob, unknown, PreviewImportInput>;\n commit: UseMutationResult<ImportJob, unknown, string>;\n}\n\n/** Upload, preview and commit mutations for a resource's import jobs. */\nexport function useImportActions(resource: string): ImportActions {\n const client = useKarniClient();\n const queryClient = useQueryClient();\n\n const store = (job: ImportJob): ImportJob => {\n queryClient.setQueryData(importJobKey(resource, job.id), job);\n return job;\n };\n\n const upload = useMutation<ImportJob, unknown, UploadImportInput>({\n mutationFn: async ({ file, mapping }) => {\n const form = new FormData();\n form.append(\"file\", file);\n if (mapping !== undefined) form.append(\"mapping\", JSON.stringify(mapping));\n return store(\n await client.request<ImportJob>(importPath(resource), { method: \"POST\", body: form }),\n );\n },\n });\n\n const preview = useMutation<ImportJob, unknown, PreviewImportInput>({\n mutationFn: async ({ jobId, mapping }) =>\n store(\n await client.request<ImportJob>(\n importPath(resource, `${encodeURIComponent(jobId)}/preview/`),\n {\n method: \"POST\",\n body: { mapping },\n },\n ),\n ),\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: importDescribeKey(resource) });\n },\n });\n\n const commit = useMutation<ImportJob, unknown, string>({\n mutationFn: async (jobId) =>\n store(\n await client.request<ImportJob>(\n importPath(resource, `${encodeURIComponent(jobId)}/commit/`),\n {\n method: \"POST\",\n body: {},\n },\n ),\n ),\n onSuccess: (job) => {\n if (job.status === \"done\") {\n void queryClient.invalidateQueries({ queryKey: karniKeys.resource(resource) });\n }\n },\n });\n\n return { upload, preview, commit };\n}\n","/**\n * ResourceTable's export buttons (karni.transfer, ADR 0002 P6): one per\n * format, each downloading `GET /<resource>/export/` with the table's current\n * filters, search and ordering. The backend applies the row scope and the\n * role's field visibility, so the file is exactly what the table may show.\n *\n * Internal to @karni/ui. The public surface is ResourceTable's `exportFormats`.\n */\nimport * as React from \"react\";\nimport type { ResourceListParams } from \"../../../hooks/types\";\nimport { downloadResourceExport, type ExportFormat } from \"../../../hooks/useResourceImport\";\nimport { useKarniClient } from \"../../../schema/provider\";\nimport { Button } from \"../../primitives/button\";\n\nexport interface ExportButtonsProps {\n resource: string;\n params: ResourceListParams;\n formats: readonly ExportFormat[];\n}\n\nfunction describe(error: unknown): string {\n if (error instanceof Error) {\n const data = (error as { data?: unknown }).data;\n if (typeof data === \"object\" && data !== null && \"detail\" in data) {\n const detail = (data as { detail?: unknown }).detail;\n if (typeof detail === \"string\") return detail;\n }\n return error.message;\n }\n return \"The export failed.\";\n}\n\nexport function ExportButtons({\n resource,\n params,\n formats,\n}: ExportButtonsProps): React.ReactElement {\n const client = useKarniClient();\n const [busy, setBusy] = React.useState<ExportFormat | null>(null);\n const [error, setError] = React.useState<string | null>(null);\n\n const run = (format: ExportFormat): void => {\n setBusy(format);\n setError(null);\n downloadResourceExport(client, resource, params, format)\n .catch((failure: unknown) => setError(describe(failure)))\n .finally(() => setBusy(null));\n };\n\n return (\n <div className=\"flex items-center gap-2\" data-testid=\"resource-table-export\">\n {formats.map((format) => (\n <Button\n key={format}\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={busy !== null}\n onClick={() => run(format)}\n aria-label={`Export as ${format.toUpperCase()}`}\n >\n {busy === format ? \"Exporting…\" : `Export ${format.toUpperCase()}`}\n </Button>\n ))}\n {error !== null && (\n <span role=\"alert\" className=\"text-sm text-destructive\">\n {error}\n </span>\n )}\n </div>\n );\n}\n","/**\n * How a resource is named in a sentence: \"No venues yet\", \"You can't edit\n * this event\". The router prefix is plural (\"events\", \"loose-slots\"). The\n * singular is derived with English rules that cover the common cases, and a\n * component's `resourceLabel` prop is the escape hatch for the rest\n * (\"people\" / \"person\").\n *\n * Internal to @karni/ui.\n */\n\n/** The words a resource takes in a sentence, both lower case. */\nexport interface ResourceNames {\n /** \"event\", \"loose slot\". */\n singular: string;\n /** \"events\", \"loose slots\". */\n plural: string;\n}\n\n/** What a component's `resourceLabel` prop accepts: either word, or both. */\nexport interface ResourceLabel {\n singular?: string;\n plural?: string;\n}\n\nfunction singularOf(word: string): string {\n if (/ies$/i.test(word) && word.length > 3) return `${word.slice(0, -3)}y`;\n if (/(?:ss|sh|ch|x|z)es$/i.test(word)) return word.slice(0, -2);\n if (/ss$/i.test(word)) return word;\n if (/s$/i.test(word)) return word.slice(0, -1);\n return word;\n}\n\n/** \"loose-slots\" → { singular: \"loose slot\", plural: \"loose slots\" }, unless `label` says otherwise. */\nexport function resourceNames(resource: string, label?: ResourceLabel): ResourceNames {\n const plural = (label?.plural ?? resource.replace(/[_-]+/g, \" \").trim()).toLowerCase();\n const words = plural.split(\" \");\n const last = words.pop() ?? plural;\n const singular = label?.singular ?? [...words, singularOf(last)].join(\" \");\n return { singular, plural };\n}\n","/**\n * ResourceSelect's replaceable parts (`slots`) and their defaults, exported\n * as `defaultResourceSelectSlots` so a project can wrap them.\n */\nimport * as React from \"react\";\nimport { cn } from \"../../../lib/cn\";\nimport { ErrorState, type ErrorSlotProps } from \"../../../states/ErrorState\";\nimport { AlertIcon, CheckIcon } from \"../../primitives/icons\";\nimport { Skeleton } from \"../../primitives/skeleton\";\nimport type { ResourceNames } from \"../resource-names\";\n\nexport interface ResourceSelectOptionProps {\n /** The row behind the option. */\n item: Record<string, unknown>;\n /** Its label (`getOptionLabel`, else displayLabel). */\n label: React.ReactNode;\n selected: boolean;\n /** Highlighted by the keyboard or the pointer. */\n active: boolean;\n}\n\nexport interface ResourceSelectChipProps {\n /** The selected row's label, or what to say when it could not be loaded. */\n label: React.ReactNode;\n /** \"loading\" while the row behind a preselected id loads, \"failed\" when it could not. */\n state: \"loaded\" | \"loading\" | \"failed\";\n /** Removes the value. Absent when the select is disabled. */\n onRemove?: () => void;\n /** The accessible name of the remove button: \"Remove Aurora Hall\". */\n removeLabel: string;\n}\n\nexport interface ResourceSelectEmptyProps {\n /**\n * \"none\": the resource has no rows yet. \"no-match\": the search found\n * nothing. \"no-loaded-match\": search is not available and none of the\n * loaded rows match the typed text.\n */\n reason: \"none\" | \"no-match\" | \"no-loaded-match\";\n /** The typed text. */\n search: string;\n /** How the resource is named (\"venue\" / \"venues\"). */\n names: ResourceNames;\n /** How many rows are loaded (for \"no-loaded-match\"). */\n loaded: number;\n}\n\nexport interface ResourceSelectLoadingProps {\n /** How many placeholder rows to show. */\n rows: number;\n}\n\n/** The replaceable parts of ResourceSelect (`slots`). */\nexport interface ResourceSelectSlots {\n /** One option's content (the row around it carries the listbox semantics). */\n Option: React.ComponentType<ResourceSelectOptionProps>;\n /** One selected value in `multiple` mode. */\n Chip: React.ComponentType<ResourceSelectChipProps>;\n /** While the first page of options loads. */\n Loading: React.ComponentType<ResourceSelectLoadingProps>;\n /** No options to show, and why. */\n Empty: React.ComponentType<ResourceSelectEmptyProps>;\n /** The options could not be loaded (forbidden, offline, server), with retry when it can help. */\n Error: React.ComponentType<ErrorSlotProps>;\n}\n\nexport function ResourceSelectOption({\n label,\n selected,\n}: ResourceSelectOptionProps): React.ReactElement {\n return (\n <>\n <span className=\"truncate\">{label}</span>\n {selected ? <CheckIcon className=\"h-4 w-4 shrink-0\" /> : null}\n </>\n );\n}\n\nfunction XIcon(props: React.SVGAttributes<SVGSVGElement>): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\nexport { XIcon as ResourceSelectClearIcon };\n\nexport function ResourceSelectChip({\n label,\n state,\n onRemove,\n removeLabel,\n}: ResourceSelectChipProps): React.ReactElement {\n if (state === \"loading\") {\n return <Skeleton className=\"h-5 w-20 rounded-sm\" />;\n }\n return (\n <span\n className={cn(\n \"inline-flex max-w-full items-center gap-1 rounded-sm px-1.5 py-0.5 text-xs\",\n state === \"failed\"\n ? \"border border-destructive-border bg-destructive-subtle text-foreground\"\n : \"bg-secondary text-secondary-foreground\",\n )}\n >\n {state === \"failed\" ? <AlertIcon className=\"h-3 w-3 shrink-0 text-destructive\" /> : null}\n <span className=\"truncate\">{label}</span>\n {onRemove !== undefined ? (\n <button\n type=\"button\"\n aria-label={removeLabel}\n className=\"rounded-sm opacity-70 hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n onClick={(event) => {\n event.stopPropagation();\n onRemove();\n }}\n onKeyDown={(event) => {\n if (event.key === \"Backspace\" || event.key === \"Delete\") {\n event.preventDefault();\n event.stopPropagation();\n onRemove();\n }\n }}\n >\n <XIcon className=\"h-3 w-3\" />\n </button>\n ) : null}\n </span>\n );\n}\n\nconst SKELETON_WIDTHS = [\"w-3/4\", \"w-1/2\", \"w-2/3\", \"w-3/5\", \"w-1/2\"];\n\nexport function ResourceSelectLoading({ rows }: ResourceSelectLoadingProps): React.ReactElement {\n return (\n <div aria-hidden=\"true\">\n {Array.from({ length: rows }, (_, index) => (\n <div key={index} className=\"flex h-8 items-center px-2\">\n <Skeleton className={cn(\"h-3.5\", SKELETON_WIDTHS[index % SKELETON_WIDTHS.length])} />\n </div>\n ))}\n </div>\n );\n}\n\n/** \"No venues yet\" and \"No venues match “ber”\" are different situations, said differently. */\nexport function emptyText({ reason, search, names, loaded }: ResourceSelectEmptyProps): string {\n if (reason === \"no-match\") return `No ${names.plural} match “${search}”`;\n if (reason === \"no-loaded-match\") {\n return `None of the ${loaded.toLocaleString()} loaded ${names.plural} match “${search}”`;\n }\n return `No ${names.plural} yet`;\n}\n\nexport function ResourceSelectEmpty(props: ResourceSelectEmptyProps): React.ReactElement {\n return <p className=\"px-2 py-6 text-center text-sm text-muted-foreground\">{emptyText(props)}</p>;\n}\n\nexport function ResourceSelectError(props: ErrorSlotProps): React.ReactElement {\n return <ErrorState variant=\"inline\" className=\"px-2 py-3\" {...props} />;\n}\n\n/** ResourceSelect's own slot components, for wrapping rather than rewriting. */\nexport const defaultResourceSelectSlots: ResourceSelectSlots = {\n Option: ResourceSelectOption,\n Chip: ResourceSelectChip,\n Loading: ResourceSelectLoading,\n Empty: ResourceSelectEmpty,\n Error: ResourceSelectError,\n};\n","import * as React from \"react\";\n\n/** Returns `value` after it has been stable for `delayMs` (D8: search debounce). */\nexport function useDebouncedValue<T>(value: T, delayMs: number): T {\n const [debounced, setDebounced] = React.useState(value);\n\n React.useEffect(() => {\n if (delayMs <= 0) {\n setDebounced(value);\n return undefined;\n }\n const timer = setTimeout(() => setDebounced(value), delayMs);\n return () => clearTimeout(timer);\n }, [value, delayMs]);\n\n return debounced;\n}\n","/**\n * ResourceSelect's data: option pages and the rows behind preselected ids.\n *\n * Options come a page at a time from the related resource's list endpoint,\n * following the API's own `next` link (page-number and cursor pagination\n * alike). Only its query string is used, so a proxy-rewritten host never\n * matters. Nothing ever fetches every row.\n *\n * Preselected ids resolve in ONE list request when the list documents an\n * id-list filter (`?id__in=1,2,3`, django-filter's `in` lookup, which a project\n * adds with `filterset_fields = {\"id\": [\"exact\", \"in\"]}`), otherwise\n * through each id's detail endpoint, in parallel.\n *\n * Internal to @karni/ui.\n */\nimport {\n keepPreviousData,\n useInfiniteQuery,\n useQueries,\n type UseInfiniteQueryResult,\n type InfiniteData,\n} from \"@tanstack/react-query\";\nimport { karniKeys } from \"../../../hooks/keys\";\nimport { buildListQuery, detailPath, listPath } from \"../../../hooks/params\";\nimport type { Paginated, ResourceListParams } from \"../../../hooks/types\";\nimport { useResourceList } from \"../../../hooks/useResourceList\";\nimport { useKarniClient } from \"../../../schema/provider\";\n\nexport type OptionRow = Record<string, unknown>;\n\n/** The query string of one page request. */\ntype PageQuery = Record<string, string | readonly string[]>;\n\nexport interface OptionPage {\n /** Undefined when the API does not count (cursor pagination). */\n count?: number;\n next: string | null;\n results: OptionRow[];\n}\n\n/** `next` → its query string (`?page=2&search=x`, `?cursor=...`). */\nexport function pageQueryOf(next: string): PageQuery {\n const url = new URL(next, \"http://karni.invalid\");\n const query: Record<string, string | string[]> = {};\n for (const key of new Set(url.searchParams.keys())) {\n const values = url.searchParams.getAll(key);\n query[key] = values.length === 1 ? (values[0] ?? \"\") : values;\n }\n return query;\n}\n\n/** A DRF page, or a plain list (an `Unpaginated` viewset), as one page. */\nfunction asPage(body: unknown): OptionPage {\n if (Array.isArray(body)) return { count: body.length, next: null, results: body as OptionRow[] };\n const page = (body ?? {}) as Partial<Paginated<OptionRow>> & { count?: unknown };\n return {\n count: typeof page.count === \"number\" ? page.count : undefined,\n next: typeof page.next === \"string\" && page.next !== \"\" ? page.next : null,\n results: Array.isArray(page.results) ? page.results : [],\n };\n}\n\nexport interface OptionPagesInput {\n resource: string;\n /** The (debounced) search term, \"\" for none. */\n search: string;\n filter?: Record<string, string | number | boolean>;\n pageSize?: number;\n enabled: boolean;\n}\n\nexport type OptionPagesResult = UseInfiniteQueryResult<InfiniteData<OptionPage, PageQuery | null>>;\n\n/** Option pages, each fetched on demand. The previous term's rows stay while a new search loads. */\nexport function useOptionPages({\n resource,\n search,\n filter,\n pageSize,\n enabled,\n}: OptionPagesInput): OptionPagesResult {\n const client = useKarniClient();\n const params: ResourceListParams = { page: 1 };\n if (pageSize !== undefined) params.pageSize = pageSize;\n if (search !== \"\") params.search = search;\n if (filter !== undefined) params.filters = filter;\n return useInfiniteQuery({\n queryKey: [...karniKeys.list(resource, params), \"options\"],\n queryFn: async ({ pageParam, signal }) =>\n asPage(\n await client.request<unknown>(listPath(resource), {\n query: pageParam ?? buildListQuery(params),\n signal,\n }),\n ),\n initialPageParam: null as PageQuery | null,\n getNextPageParam: (last) => (last.next !== null ? pageQueryOf(last.next) : undefined),\n enabled,\n placeholderData: keepPreviousData,\n });\n}\n\nexport interface SelectedRows {\n /** Rows found for the requested ids, by String(id). */\n rows: Record<string, OptionRow>;\n /** Ids that could not be loaded (deleted, hidden from the role, or the request failed). */\n failed: ReadonlySet<string>;\n /** Ids still loading. */\n loading: ReadonlySet<string>;\n}\n\nconst NOTHING: ReadonlySet<string> = new Set();\n\n/** Loads the rows behind ids the options have not shown yet. */\nexport function useSelectedRows(\n resource: string,\n ids: ReadonlyArray<string | number>,\n options: { idsFilter?: string; enabled: boolean },\n): SelectedRows {\n const client = useKarniClient();\n const { idsFilter, enabled } = options;\n const keys = ids.map(String);\n const batched = idsFilter !== undefined;\n\n const batch = useResourceList<OptionRow>(\n resource,\n {\n filters: { [idsFilter ?? \"id__in\"]: keys.join(\",\") },\n pageSize: Math.max(keys.length, 1),\n },\n { enabled: enabled && batched && keys.length > 0, retry: false },\n );\n\n const singles = useQueries({\n queries: (batched ? [] : keys).map((key) => ({\n queryKey: karniKeys.detail(resource, key),\n queryFn: ({ signal }: { signal: AbortSignal }) =>\n client.request<OptionRow>(detailPath(resource, key), { signal }),\n enabled,\n retry: false,\n })),\n });\n\n const rows: Record<string, OptionRow> = {};\n if (keys.length === 0) return { rows, failed: NOTHING, loading: NOTHING };\n const failed = new Set<string>();\n const loading = new Set<string>();\n if (batched) {\n const results = batch.data?.results;\n if (results !== undefined) {\n for (const row of results) rows[String(row[\"id\"])] = row;\n for (const key of keys) if (!(key in rows)) failed.add(key);\n } else if (batch.error != null) {\n for (const key of keys) failed.add(key);\n } else {\n for (const key of keys) loading.add(key);\n }\n } else {\n keys.forEach((key, index) => {\n const query = singles[index];\n if (query?.data !== undefined) rows[key] = query.data;\n else if (query?.error != null) failed.add(key);\n else loading.add(key);\n });\n }\n return { rows, failed, loading };\n}\n","import * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { cn } from \"../../../lib/cn\";\nimport { registerComponentRole } from \"../../../lib/roles\";\nimport { useParsedSchema } from \"../../../schema/useSchema\";\nimport { describeError } from \"../../../states/describe-error\";\nimport { AlertIcon, ChevronDownIcon, SpinnerIcon } from \"../../primitives/icons\";\nimport { displayLabel } from \"../displayLabel\";\nimport { resourceNames, type ResourceLabel } from \"../resource-names\";\nimport {\n defaultResourceSelectSlots,\n emptyText,\n ResourceSelectClearIcon,\n type ResourceSelectEmptyProps,\n type ResourceSelectSlots,\n} from \"./select-states\";\nimport { useDebouncedValue } from \"./use-debounced-value\";\nimport { useOptionPages, useSelectedRows, type OptionRow } from \"./use-option-pages\";\n\nregisterComponentRole(\"async-select\", \"ResourceSelect\");\n\nexport interface ResourceSelectProps {\n resource: string;\n value: string | number | ReadonlyArray<string | number> | null;\n onChange: (value: string | number | Array<string | number> | null) => void;\n multiple?: boolean;\n disabled?: boolean;\n placeholder?: string;\n /** Defaults to displayLabel(). */\n getOptionLabel?: (item: Record<string, unknown>) => React.ReactNode;\n /** Extra filter params sent with the search request. */\n filter?: Record<string, string | number | boolean>;\n id?: string;\n className?: string;\n /** Rows per options request. Default: the API's own page size. More load as the list scrolls. */\n pageSize?: number;\n /** Set false to hide the clear affordance (which emits null). Default true. */\n clearable?: boolean;\n /** Debounce for the ?search= request in ms. Default 300 (D8). */\n searchDebounceMs?: number;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n /** Ids of the help text and error message that describe the field. */\n \"aria-describedby\"?: string;\n /** Marks the field invalid (destructive border). */\n \"aria-invalid\"?: boolean | \"true\" | \"false\";\n \"aria-required\"?: boolean | \"true\" | \"false\";\n /** Called when focus leaves the select (not when it moves into its own list). */\n onBlur?: () => void;\n /** Replaces parts of the picker: Option, Chip, Loading, Empty, Error. */\n slots?: Partial<ResourceSelectSlots>;\n /**\n * Whether typing searches the server (`?search=`). Default: what the\n * schema says (a list without `search_fields` documents no `search`\n * parameter). Without search, typing narrows the rows already loaded and\n * the list says so.\n */\n searchable?: boolean;\n /**\n * The list filter that takes several ids at once, used to label\n * preselected values in one request. Default `\"id__in\"` when the schema\n * documents it. Otherwise (or with `false`) each id loads from its detail\n * endpoint.\n */\n idsFilter?: string | false;\n /** How the related resource is named in messages. Default: derived from `resource`. */\n resourceLabel?: ResourceLabel;\n}\n\n/** Lists longer than this render only the rows in view (plus a margin). */\nconst VIRTUALIZE_AFTER = 100;\nconst OVERSCAN = 6;\n/** h-8 at the default root font size, measured from the first option once rendered. */\nconst DEFAULT_ROW_HEIGHT = 32;\n/** max-h-64 at the default root font size, measured once the list is open. */\nconst DEFAULT_VIEWPORT_HEIGHT = 256;\nconst LOADING_ROWS = 5;\n\nfunction idOf(item: OptionRow): string | number {\n const value = item[\"id\"];\n if (typeof value === \"string\" || typeof value === \"number\") return value;\n return String(value);\n}\n\nfunction shortId(id: string | number): string {\n const text = String(id);\n return text.length > 12 ? `${text.slice(0, 8)}…` : text;\n}\n\nfunction capitalised(text: string): string {\n return text.charAt(0).toUpperCase() + text.slice(1);\n}\n\n/**\n * Searchable picker for a related row, querying the related resource as you type.\n *\n * Contract D8.\n *\n * A text input drives a debounced `?search=` request (or, when the API cannot\n * search, narrows the loaded rows and says so). Options render in a\n * NON-MODAL Radix Popover that never takes focus from the input. Options load\n * a page at a time as the list scrolls or the keyboard reaches its end, never\n * all at once, and long lists render only the rows in view. The input\n * implements the ARIA 1.2 combobox pattern (aria-expanded, aria-controls,\n * aria-activedescendant). Arrows, Home/End and PageUp/PageDown move through\n * every loaded page. Preselected ids are labelled in one request where the\n * API has an id-list filter, else per id. An id that cannot be loaded says\n * so instead of showing a bare id. The clear affordance emits `null`.\n */\nexport const ResourceSelect = React.forwardRef<HTMLInputElement, ResourceSelectProps>(\n function ResourceSelect(props, forwardedRef): React.ReactElement {\n const {\n resource,\n value,\n onChange,\n multiple = false,\n disabled = false,\n placeholder,\n getOptionLabel,\n filter,\n id,\n className,\n pageSize,\n clearable = true,\n searchDebounceMs = 300,\n onBlur,\n slots: slotOverrides,\n searchable: searchableProp,\n idsFilter: idsFilterProp,\n resourceLabel,\n } = props;\n const slots = { ...defaultResourceSelectSlots, ...slotOverrides };\n const names = resourceNames(resource, resourceLabel);\n\n const reactId = React.useId();\n const inputId = id ?? reactId;\n const listboxId = `${inputId}-listbox`;\n const optionDomId = (index: number): string => `${listboxId}-option-${index}`;\n\n // What the related resource's list can do, from the schema.\n const parsed = useParsedSchema();\n const listOperation = parsed.data?.resources[resource]?.operations.list;\n const searchable =\n searchableProp ?? (listOperation === undefined || listOperation.hasSearch === true);\n const idsFilter =\n idsFilterProp === false\n ? undefined\n : (idsFilterProp ??\n (listOperation?.queryParams.includes(\"id__in\") === true ? \"id__in\" : undefined));\n\n const [open, setOpen] = React.useState(false);\n const [inputText, setInputText] = React.useState(\"\");\n const [activeIndex, setActiveIndex] = React.useState(0);\n const [cache, setCache] = React.useState<Record<string, OptionRow>>({});\n const [scrollTop, setScrollTop] = React.useState(0);\n const [rowHeight, setRowHeight] = React.useState(DEFAULT_ROW_HEIGHT);\n const [viewportHeight, setViewportHeight] = React.useState(DEFAULT_VIEWPORT_HEIGHT);\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const contentRef = React.useRef<HTMLDivElement>(null);\n const scrollRef = React.useRef<HTMLDivElement>(null);\n const inputRef = React.useRef<HTMLInputElement | null>(null);\n /** ArrowDown at the last loaded option: move on once the next page arrives. */\n const advanceRef = React.useRef(false);\n\n const setInputRef = React.useCallback(\n (element: HTMLInputElement | null) => {\n inputRef.current = element;\n if (typeof forwardedRef === \"function\") forwardedRef(element);\n else if (forwardedRef !== null) forwardedRef.current = element;\n },\n [forwardedRef],\n );\n\n const term = inputText.trim();\n const debouncedTerm = useDebouncedValue(term, searchDebounceMs);\n const search = searchable ? debouncedTerm : \"\";\n\n const pages = useOptionPages({\n resource,\n search,\n filter,\n pageSize,\n enabled: open && !disabled,\n });\n\n const loadedRows = React.useMemo(() => {\n const seen = new Set<string>();\n const rows: OptionRow[] = [];\n for (const page of pages.data?.pages ?? []) {\n for (const row of page.results) {\n const key = String(idOf(row));\n if (seen.has(key)) continue;\n seen.add(key);\n rows.push(row);\n }\n }\n return rows;\n }, [pages.data]);\n const total = pages.data?.pages[0]?.count;\n const hasMore = pages.hasNextPage;\n\n // Remember every row seen, so selected values can always be labelled.\n React.useEffect(() => {\n if (loadedRows.length === 0) return;\n setCache((previous) => {\n let changed = false;\n const next = { ...previous };\n for (const row of loadedRows) {\n const key = String(idOf(row));\n if (!(key in next)) {\n next[key] = row;\n changed = true;\n }\n }\n return changed ? next : previous;\n });\n }, [loadedRows]);\n\n const labelOf = React.useCallback(\n (item: OptionRow): React.ReactNode =>\n getOptionLabel !== undefined ? getOptionLabel(item) : displayLabel(item),\n [getOptionLabel],\n );\n const labelTextOf = React.useCallback(\n (item: OptionRow): string => {\n const label = labelOf(item);\n if (typeof label === \"string\") return label;\n if (typeof label === \"number\") return String(label);\n return displayLabel(item);\n },\n [labelOf],\n );\n\n // Without server search, typing narrows the loaded rows.\n const options = React.useMemo(() => {\n if (searchable || term === \"\") return loadedRows;\n const needle = term.toLowerCase();\n return loadedRows.filter((row) => labelTextOf(row).toLowerCase().includes(needle));\n }, [searchable, term, loadedRows, labelTextOf]);\n const count = options.length;\n\n // --- selected values -------------------------------------------------\n const selected: ReadonlyArray<string | number> = React.useMemo(() => {\n if (value == null) return [];\n return Array.isArray(value) ? value : [value as string | number];\n }, [value]);\n const selectedKey = selected.map(String).join(\"\\u0000\");\n const cacheRef = React.useRef(cache);\n cacheRef.current = cache;\n // The ids to load are fixed when the value changes, so rows arriving in\n // option pages later never re-key (and repeat) the request.\n const toResolve = React.useMemo(\n () => selected.filter((sel) => !(String(sel) in cacheRef.current)),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- keyed on the value, read from the cache at that moment\n [selectedKey],\n );\n // Wait for the schema (or its failure): it decides between one batched\n // request and one request per id.\n const schemaSettled = parsed.data !== undefined || parsed.isError;\n const resolution = useSelectedRows(resource, toResolve, {\n idsFilter,\n enabled: schemaSettled,\n });\n\n const rowFor = (sel: string | number): OptionRow | undefined =>\n cache[String(sel)] ?? resolution.rows[String(sel)];\n const stateOf = (sel: string | number): \"loaded\" | \"loading\" | \"failed\" => {\n if (rowFor(sel) !== undefined) return \"loaded\";\n return resolution.failed.has(String(sel)) ? \"failed\" : \"loading\";\n };\n const failedText = (sel: string | number): string =>\n `Couldn't load ${names.singular} ${shortId(sel)}`;\n const selectedText = (sel: string | number): string => {\n const row = rowFor(sel);\n if (row !== undefined) return labelTextOf(row);\n return resolution.failed.has(String(sel)) ? failedText(sel) : \"\";\n };\n\n const isSelected = (optionId: string | number): boolean =>\n selected.some((sel) => String(sel) === String(optionId));\n\n // --- list geometry (virtual window) ------------------------------------\n const virtual = count > VIRTUALIZE_AFTER;\n const start = virtual ? Math.max(0, Math.floor(scrollTop / rowHeight) - OVERSCAN) : 0;\n const end = virtual\n ? Math.min(count, Math.ceil((scrollTop + viewportHeight) / rowHeight) + OVERSCAN)\n : count;\n\n const hasOptions = count > 0;\n React.useLayoutEffect(() => {\n if (!open) return;\n const container = scrollRef.current;\n if (container === null) return;\n if (container.clientHeight > 0) setViewportHeight(container.clientHeight);\n const first = container.querySelector(\"[role='option']\");\n const height = first?.getBoundingClientRect().height ?? 0;\n if (height > 0) setRowHeight(height);\n }, [open, hasOptions]);\n\n const scrollToIndex = (index: number): void => {\n const top = index * rowHeight;\n let next = scrollTop;\n if (top < next) next = top;\n else if (top + rowHeight > next + viewportHeight) next = top + rowHeight - viewportHeight;\n if (next === scrollTop) return;\n if (scrollRef.current !== null) scrollRef.current.scrollTop = next;\n setScrollTop(next);\n };\n\n const loadMore = (): void => {\n if (pages.hasNextPage && !pages.isFetchingNextPage && !pages.isFetchNextPageError) {\n void pages.fetchNextPage();\n }\n };\n\n const moveTo = (index: number): void => {\n setActiveIndex(index);\n scrollToIndex(index);\n };\n\n // Keep the highlight inside the list, and move on into a page that just arrived.\n const previousCount = React.useRef(count);\n React.useEffect(() => {\n if (advanceRef.current && count > previousCount.current) {\n advanceRef.current = false;\n moveTo(Math.min(activeIndex + 1, count - 1));\n } else if (activeIndex >= count && count > 0) {\n setActiveIndex(count - 1);\n }\n previousCount.current = count;\n // eslint-disable-next-line react-hooks/exhaustive-deps -- reacts to the option count only\n }, [count]);\n\n const resetList = (): void => {\n setActiveIndex(0);\n setScrollTop(0);\n if (scrollRef.current !== null) scrollRef.current.scrollTop = 0;\n };\n\n // A new search starts at the top of its results.\n React.useEffect(() => {\n setActiveIndex(0);\n setScrollTop(0);\n if (scrollRef.current !== null) scrollRef.current.scrollTop = 0;\n }, [search]);\n\n const openPopover = (): void => {\n if (disabled) return;\n setInputText(\"\");\n resetList();\n setOpen(true);\n };\n\n const closePopover = (): void => {\n setOpen(false);\n setInputText(\"\");\n advanceRef.current = false;\n };\n\n const toggleOption = (item: OptionRow): void => {\n const optionId = idOf(item);\n setCache((previous) =>\n String(optionId) in previous ? previous : { ...previous, [String(optionId)]: item },\n );\n if (multiple) {\n const next = isSelected(optionId)\n ? selected.filter((sel) => String(sel) !== String(optionId))\n : [...selected, optionId];\n onChange([...next]);\n } else {\n onChange(optionId);\n closePopover();\n }\n };\n\n const removeValue = (sel: string | number): void => {\n onChange([...selected.filter((other) => String(other) !== String(sel))]);\n inputRef.current?.focus();\n };\n\n const clearSelection = (): void => {\n onChange(null);\n setInputText(\"\");\n inputRef.current?.focus();\n };\n\n const single = !multiple && selected.length > 0 ? selected[0] : undefined;\n const singleState = single !== undefined ? stateOf(single) : undefined;\n const singleText = single !== undefined ? selectedText(single) : \"\";\n const inputValue = open ? inputText : multiple ? \"\" : singleText;\n\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>): void => {\n const next = event.target.value;\n resetList();\n if (!open) {\n if (disabled) return;\n setOpen(true);\n // While closed the input showed the selected label; typing appends to\n // it, so strip the label prefix and keep only the fresh keystrokes.\n setInputText(\n singleText !== \"\" && next.startsWith(singleText) ? next.slice(singleText.length) : next,\n );\n return;\n }\n setInputText(next);\n };\n\n const rowsPerPage = Math.max(1, Math.floor(viewportHeight / rowHeight) - 1);\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {\n if (disabled) return;\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n if (!open) openPopover();\n else if (count > 0) {\n if (activeIndex < count - 1) moveTo(activeIndex + 1);\n else if (hasMore) {\n advanceRef.current = true;\n loadMore();\n } else moveTo(0);\n }\n break;\n case \"ArrowUp\":\n event.preventDefault();\n if (!open) openPopover();\n else if (count > 0) {\n if (activeIndex > 0) moveTo(activeIndex - 1);\n else if (!hasMore) moveTo(count - 1);\n }\n break;\n case \"Home\":\n if (open && count > 0) {\n event.preventDefault();\n moveTo(0);\n }\n break;\n case \"End\":\n if (open && count > 0) {\n event.preventDefault();\n moveTo(count - 1);\n loadMore();\n }\n break;\n case \"PageDown\":\n if (open && count > 0) {\n event.preventDefault();\n const target = Math.min(count - 1, activeIndex + rowsPerPage);\n moveTo(target);\n if (target === count - 1) loadMore();\n }\n break;\n case \"PageUp\":\n if (open && count > 0) {\n event.preventDefault();\n moveTo(Math.max(0, activeIndex - rowsPerPage));\n }\n break;\n case \"Enter\":\n if (open) {\n // Inside an open list Enter chooses; it never submits the form.\n event.preventDefault();\n const item = options[activeIndex];\n if (item !== undefined) toggleOption(item);\n }\n break;\n case \"Escape\":\n if (open) {\n event.preventDefault();\n event.stopPropagation();\n closePopover();\n }\n break;\n case \"Backspace\":\n if (multiple && inputText === \"\" && selected.length > 0) {\n onChange([...selected.slice(0, -1)]);\n }\n break;\n case \"Tab\":\n if (open) closePopover();\n break;\n default:\n break;\n }\n };\n\n const handleBlur = (event: React.FocusEvent<HTMLDivElement>): void => {\n const next = event.relatedTarget as Node | null;\n if (\n next !== null &&\n (rootRef.current?.contains(next) === true || contentRef.current?.contains(next) === true)\n ) {\n return;\n }\n if (open) closePopover();\n onBlur?.();\n };\n\n const handleScroll = (event: React.UIEvent<HTMLDivElement>): void => {\n const container = event.currentTarget;\n setScrollTop(container.scrollTop);\n const height = container.clientHeight > 0 ? container.clientHeight : viewportHeight;\n if (container.scrollTop + height >= count * rowHeight - rowHeight * 5) loadMore();\n };\n\n // --- what the list says ------------------------------------------------\n const firstLoad = pages.data === undefined && pages.error == null;\n const loadError = pages.data === undefined ? pages.error : null;\n const searching =\n searchable && (term !== debouncedTerm || (pages.isPlaceholderData && pages.isFetching));\n const loaded = loadedRows.length;\n const totalText = total !== undefined ? total.toLocaleString() : undefined;\n\n const emptyReason: ResourceSelectEmptyProps[\"reason\"] | null =\n count > 0 || firstLoad || loadError != null || searching\n ? null\n : term !== \"\"\n ? searchable\n ? \"no-match\"\n : \"no-loaded-match\"\n : \"none\";\n const emptyProps: ResourceSelectEmptyProps | null =\n emptyReason !== null ? { reason: emptyReason, search: term, names, loaded } : null;\n\n const status = ((): string => {\n if (searching) return \"Searching…\";\n if (pages.isFetchingNextPage) return `Loading more ${names.plural}…`;\n if (!searchable) {\n if (term !== \"\") {\n return `Search isn't available for ${names.plural}: ${count.toLocaleString()} of the ${loaded.toLocaleString()} loaded match`;\n }\n if (hasMore) {\n return `Showing ${loaded.toLocaleString()}${totalText !== undefined ? ` of ${totalText}` : \"\"}. Search isn't available, so scroll for more.`;\n }\n return `${loaded.toLocaleString()} ${loaded === 1 ? names.singular : names.plural}`;\n }\n if (hasMore) {\n return `Showing ${loaded.toLocaleString()}${totalText !== undefined ? ` of ${totalText}` : \"\"}. Type to narrow.`;\n }\n if (term !== \"\") {\n return `${count.toLocaleString()} ${count === 1 ? `${names.singular} matches` : `${names.plural} match`} “${term}”`;\n }\n return `${count.toLocaleString()} ${count === 1 ? names.singular : names.plural}`;\n })();\n\n const announcement = ((): string => {\n if (!open) return \"\";\n if (loadError != null) {\n return describeError(loadError, { action: \"view\", resource: names.plural }).title;\n }\n if (firstLoad) return `Loading ${names.plural}…`;\n if (emptyProps !== null) return emptyText(emptyProps);\n return status;\n })();\n\n const activeId =\n open && count > 0 && activeIndex < count && !firstLoad ? optionDomId(activeIndex) : undefined;\n const invalid = props[\"aria-invalid\"] === true || props[\"aria-invalid\"] === \"true\";\n\n const Option = slots.Option;\n const Chip = slots.Chip;\n const ListLoading = slots.Loading;\n const Empty = slots.Empty;\n const ListError = slots.Error;\n\n const listbox = (\n <div\n role=\"listbox\"\n id={listboxId}\n aria-label={\n props[\"aria-labelledby\"] === undefined\n ? (props[\"aria-label\"] ?? capitalised(names.plural))\n : undefined\n }\n aria-labelledby={props[\"aria-labelledby\"]}\n aria-multiselectable={multiple || undefined}\n aria-busy={firstLoad || searching || undefined}\n className={cn(\"p-1\", searching && \"cursor-progress\")}\n style={\n virtual\n ? { paddingTop: start * rowHeight, paddingBottom: (count - end) * rowHeight }\n : undefined\n }\n >\n {options.slice(start, end).map((item, offset) => {\n const index = start + offset;\n const optionId = idOf(item);\n const optionSelected = isSelected(optionId);\n const active = index === activeIndex;\n return (\n <div\n key={String(optionId)}\n id={optionDomId(index)}\n role=\"option\"\n aria-selected={optionSelected}\n aria-setsize={hasMore ? (total ?? -1) : count}\n aria-posinset={index + 1}\n data-highlighted={active ? \"true\" : undefined}\n className=\"flex h-8 cursor-default select-none items-center justify-between gap-2 rounded-sm px-2 text-sm outline-none data-[highlighted=true]:bg-accent data-[highlighted=true]:text-accent-foreground\"\n onMouseDown={(event) => event.preventDefault()}\n onMouseMove={() => {\n if (!active) setActiveIndex(index);\n }}\n onClick={() => toggleOption(item)}\n >\n <Option item={item} label={labelOf(item)} selected={optionSelected} active={active} />\n </div>\n );\n })}\n </div>\n );\n\n const listBody = ((): React.ReactNode => {\n if (loadError != null) {\n return (\n <>\n <div className=\"p-1\">\n <ListError\n error={loadError}\n context={{ action: \"view\", resource: names.plural }}\n onRetry={() => void pages.refetch()}\n retrying={pages.isFetching}\n />\n </div>\n {listbox}\n </>\n );\n }\n if (firstLoad) {\n return (\n <>\n <p\n className=\"border-b border-border px-3 py-1.5 text-xs text-muted-foreground\"\n aria-hidden=\"true\"\n >\n Loading {names.plural}…\n </p>\n <div className=\"p-1\">\n <ListLoading rows={LOADING_ROWS} />\n </div>\n {listbox}\n </>\n );\n }\n return (\n <>\n {emptyProps === null ? (\n <p\n className=\"flex items-start gap-2 border-b border-border px-3 py-1.5 text-xs text-muted-foreground\"\n aria-hidden=\"true\"\n >\n {searching || pages.isFetchingNextPage ? (\n <SpinnerIcon className=\"mt-0.5 h-3 w-3 shrink-0 animate-spin\" />\n ) : null}\n <span className=\"min-w-0\">{status}</span>\n </p>\n ) : null}\n <div ref={scrollRef} className=\"max-h-64 overflow-y-auto\" onScroll={handleScroll}>\n {emptyProps !== null ? <Empty {...emptyProps} /> : null}\n {listbox}\n {hasMore ? (\n <div className=\"px-1 pb-1\">\n {pages.isFetchNextPageError ? (\n <p className=\"flex h-8 items-center gap-2 px-2 text-xs text-muted-foreground\">\n <AlertIcon className=\"h-3 w-3 shrink-0 text-destructive\" />\n <span className=\"truncate\">Couldn't load more {names.plural}.</span>\n <button\n type=\"button\"\n tabIndex={-1}\n className=\"font-medium text-foreground underline underline-offset-4\"\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => void pages.fetchNextPage()}\n >\n Try again\n </button>\n </p>\n ) : (\n <button\n type=\"button\"\n tabIndex={-1}\n disabled={pages.isFetchingNextPage}\n className=\"flex h-8 w-full items-center justify-center gap-2 rounded-sm text-xs text-muted-foreground hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none\"\n onMouseDown={(event) => event.preventDefault()}\n onClick={loadMore}\n >\n {pages.isFetchingNextPage ? (\n <>\n <SpinnerIcon className=\"h-3 w-3 animate-spin\" />\n Loading more…\n </>\n ) : (\n `Load more ${names.plural}`\n )}\n </button>\n )}\n </div>\n ) : null}\n </div>\n </>\n );\n })();\n\n return (\n <PopoverPrimitive.Root\n open={open}\n onOpenChange={(next) => {\n if (!next) closePopover();\n }}\n modal={false}\n >\n <PopoverPrimitive.Anchor asChild>\n <div\n ref={rootRef}\n onClick={() => {\n if (disabled) return;\n inputRef.current?.focus();\n if (!open) openPopover();\n }}\n onBlur={handleBlur}\n data-invalid={invalid ? \"true\" : undefined}\n className={cn(\n \"relative flex min-h-10 w-full flex-wrap items-center gap-1.5 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 data-[invalid=true]:border-destructive data-[invalid=true]:focus-within:ring-destructive\",\n disabled && \"cursor-not-allowed opacity-50\",\n className,\n )}\n >\n {multiple\n ? selected.map((sel) => {\n const state = stateOf(sel);\n const text = state === \"loaded\" ? selectedText(sel) : failedText(sel);\n return (\n <Chip\n key={String(sel)}\n label={state === \"loaded\" ? labelOf(rowFor(sel) ?? {}) : text}\n state={state}\n removeLabel={`Remove ${text}`}\n onRemove={disabled ? undefined : () => removeValue(sel)}\n />\n );\n })\n : null}\n {singleState === \"failed\" && !open ? (\n <AlertIcon className=\"h-4 w-4 shrink-0 text-destructive\" />\n ) : null}\n <input\n ref={setInputRef}\n id={inputId}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={listboxId}\n aria-autocomplete=\"list\"\n aria-activedescendant={activeId}\n aria-label={props[\"aria-label\"]}\n aria-labelledby={props[\"aria-labelledby\"]}\n aria-describedby={props[\"aria-describedby\"]}\n aria-invalid={props[\"aria-invalid\"]}\n aria-required={props[\"aria-required\"]}\n autoComplete=\"off\"\n disabled={disabled}\n placeholder={\n singleState === \"loading\"\n ? `Loading ${names.singular}…`\n : selected.length === 0\n ? placeholder\n : undefined\n }\n value={inputValue}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onClick={() => {\n if (!open) openPopover();\n }}\n className={cn(\n \"min-w-16 flex-1 bg-transparent outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed\",\n singleState === \"failed\" && !open && \"text-muted-foreground\",\n )}\n />\n {clearable && selected.length > 0 && !disabled ? (\n <button\n type=\"button\"\n aria-label=\"Clear selection\"\n className=\"rounded-sm p-0.5 text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n onMouseDown={(event) => event.preventDefault()}\n onClick={(event) => {\n event.stopPropagation();\n clearSelection();\n }}\n >\n <ResourceSelectClearIcon className=\"h-4 w-4\" />\n </button>\n ) : null}\n <ChevronDownIcon className=\"h-4 w-4 shrink-0 opacity-50\" />\n <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {announcement}\n </span>\n </div>\n </PopoverPrimitive.Anchor>\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={contentRef}\n side=\"bottom\"\n align=\"start\"\n sideOffset={4}\n onOpenAutoFocus={(event) => event.preventDefault()}\n onCloseAutoFocus={(event) => event.preventDefault()}\n onInteractOutside={(event) => {\n const target = event.target;\n if (\n rootRef.current !== null &&\n target instanceof Node &&\n rootRef.current.contains(target)\n ) {\n event.preventDefault();\n }\n }}\n className=\"z-popover w-[var(--radix-popover-trigger-width)] min-w-48 overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md\"\n >\n {listBody}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n );\n },\n);\nResourceSelect.displayName = \"ResourceSelect\";\n","/**\n * ResourceTable's search box + declared-params-derived filter bar (D5).\n *\n * The parent decides WHICH fields filter (enum/boolean/relation fields ∩ the\n * list operation's declared query params, cap 4, `filters` prop overrides).\n * This component only renders the controls:\n * - enum → clearable <Select> (\"All\" clears),\n * - boolean → clearable Yes/No <Select>,\n * - relation → <ResourceSelect> (multiple for many-relations).\n *\n * Internal to @karni/ui. The public surface is ResourceTable's props.\n */\nimport * as React from \"react\";\nimport type { FilterValue } from \"../../../hooks/types\";\nimport type { FieldDef } from \"../../../schema/types\";\nimport { cn } from \"../../../lib/cn\";\nimport { Input } from \"../../primitives/input\";\nimport { Select } from \"../../primitives/select\";\nimport { ResourceSelect } from \"../ResourceSelect\";\nimport { enumLabel } from \"./table-utils\";\n\nexport interface FilterBarProps {\n /** Whether the list operation declares a `search` query param. */\n searchEnabled: boolean;\n searchValue: string;\n onSearchChange: (value: string) => void;\n searchPlaceholder?: string;\n /** Already-derived filter fields, in render order. */\n filterFields: readonly FieldDef[];\n values: Readonly<Record<string, FilterValue>>;\n onFilterChange: (field: FieldDef, value: FilterValue) => void;\n className?: string;\n}\n\nfunction toSelectValue(value: FilterValue): string | null {\n if (value === null || value === undefined || typeof value === \"object\") return null;\n return String(value);\n}\n\nfunction toRelationValue(\n value: FilterValue,\n): string | number | ReadonlyArray<string | number> | null {\n if (value === null || value === undefined || typeof value === \"boolean\") return null;\n if (Array.isArray(value)) {\n return value.filter(\n (item): item is string | number => typeof item === \"string\" || typeof item === \"number\",\n );\n }\n return value as string | number;\n}\n\nfunction EnumFilter({\n field,\n value,\n onFilterChange,\n}: {\n field: FieldDef;\n value: FilterValue;\n onFilterChange: FilterBarProps[\"onFilterChange\"];\n}): React.ReactElement {\n const options = (field.enumValues ?? []).map((member) => ({\n value: String(member),\n label: enumLabel(member, field.enumLabels),\n }));\n return (\n <Select\n aria-label={field.label}\n className=\"h-9 w-auto min-w-36\"\n value={toSelectValue(value)}\n options={options}\n placeholder={field.label}\n clearable\n clearLabel={`${field.label}: All`}\n onValueChange={(next) => {\n if (next === null) {\n onFilterChange(field, null);\n return;\n }\n // Preserve the member's original type (numeric enums stay numbers).\n const member = (field.enumValues ?? []).find((candidate) => String(candidate) === next);\n onFilterChange(field, member ?? next);\n }}\n />\n );\n}\n\nfunction BooleanFilter({\n field,\n value,\n onFilterChange,\n}: {\n field: FieldDef;\n value: FilterValue;\n onFilterChange: FilterBarProps[\"onFilterChange\"];\n}): React.ReactElement {\n return (\n <Select\n aria-label={field.label}\n className=\"h-9 w-auto min-w-36\"\n value={typeof value === \"boolean\" ? String(value) : null}\n options={[\n { value: \"true\", label: \"Yes\" },\n { value: \"false\", label: \"No\" },\n ]}\n placeholder={field.label}\n clearable\n clearLabel={`${field.label}: All`}\n onValueChange={(next) => onFilterChange(field, next === null ? null : next === \"true\")}\n />\n );\n}\n\n/** Search box + up to four filter controls in one wrapping row. */\nexport function FilterBar(props: FilterBarProps): React.ReactElement {\n const {\n searchEnabled,\n searchValue,\n onSearchChange,\n searchPlaceholder = \"Search…\",\n filterFields,\n values,\n onFilterChange,\n className,\n } = props;\n\n return (\n <div className={cn(\"flex flex-wrap items-center gap-2\", className)}>\n {searchEnabled && (\n <Input\n type=\"search\"\n aria-label=\"Search\"\n placeholder={searchPlaceholder}\n value={searchValue}\n onChange={(event) => onSearchChange(event.target.value)}\n className=\"h-9 w-full max-w-80\"\n />\n )}\n {filterFields.map((field) => {\n const value = values[field.name];\n if (field.kind === \"enum\") {\n return (\n <EnumFilter\n key={field.name}\n field={field}\n value={value}\n onFilterChange={onFilterChange}\n />\n );\n }\n if (field.kind === \"boolean\") {\n return (\n <BooleanFilter\n key={field.name}\n field={field}\n value={value}\n onFilterChange={onFilterChange}\n />\n );\n }\n if (field.kind === \"relation\" && field.relation !== undefined) {\n return (\n <div key={field.name} className=\"min-w-36\">\n <ResourceSelect\n resource={field.relation.resource}\n multiple={field.relation.many}\n value={toRelationValue(value)}\n placeholder={field.label}\n // A placeholder is not a label: it disappears once a value is chosen.\n aria-label={field.label}\n onChange={(next) => onFilterChange(field, next)}\n />\n </div>\n );\n }\n return null;\n })}\n </div>\n );\n}\n","/**\n * The class lists ResourceTable's table and its loading skeleton share, so\n * the skeleton occupies exactly the box the data will: same container, same\n * header height, same row height per density. Internal to @karni/ui.\n */\nimport type { ResourceTableDensity } from \"./preferences\";\n\n/** Row and header geometry per density. Every value is a spacing token. */\nexport const DENSITY_CLASSES: Record<\n ResourceTableDensity,\n { head: string; cell: string; action: string; card: string }\n> = {\n comfortable: {\n head: \"h-10 px-3\",\n cell: \"h-12 px-3 py-2\",\n action: \"h-8 px-3\",\n card: \"gap-3 p-4\",\n },\n compact: {\n head: \"h-9 px-2\",\n cell: \"h-9 px-2 py-1\",\n action: \"h-7 px-2\",\n card: \"gap-2 p-3\",\n },\n};\n\n/**\n * The scrolling box: both directions scroll inside it, so 50 columns never\n * push the page sideways and the header can stick. Its height is capped by\n * the `--karni-table-max-height` token (70vh). Set it to `none` to let the\n * page scroll instead.\n */\nexport const SCROLL_BOX =\n \"group/scroll relative w-full max-h-[var(--karni-table-max-height)] overflow-auto rounded-md border border-border bg-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\";\n\n/**\n * The scroll box of a grid: a cell or control the keyboard focuses scrolls\n * into view below the sticky header, not under it.\n */\nexport const GRID_SCROLL_BOX = \"scroll-pt-10\";\n\n/** A grid cell without a control takes focus itself, and shows it inside its edges. */\nexport const GRID_CELL =\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring\";\n\nexport const TABLE = \"w-full border-separate border-spacing-0 text-sm\";\n\n/** Sticky on vertical scroll, above the frozen body cells. */\nexport const THEAD = \"sticky top-0 z-raised\";\n\nexport const HEAD_CELL =\n \"whitespace-nowrap border-b border-border bg-muted text-left align-middle text-xs font-medium text-muted-foreground\";\n\n/** Opaque backgrounds on every cell, so frozen cells hide what scrolls beneath them. */\nexport const BODY_CELL =\n \"whitespace-nowrap border-b border-border bg-background align-middle group-hover/row:bg-muted group-data-[state=selected]/row:bg-muted\";\n\nexport const LAST_ROW = \"[&>tr:last-child>td]:border-b-0\";\n\n/** The checkbox column: a fixed width, so the frozen first column can sit after it. */\nexport const SELECT_CELL = \"sticky left-0 w-10 min-w-10 px-3\";\n\n/** The frozen first data column, with an edge once the table scrolls sideways. */\nexport const FROZEN_CELL =\n \"sticky border-r border-r-transparent group-data-[scrolled=true]/scroll:border-r-border\";\n\nexport const FROZEN_AT_START = \"left-0\";\nexport const FROZEN_AFTER_SELECT = \"left-10\";\n\n/** The frozen column's content is capped, so it never takes the whole width. */\nexport const FROZEN_CONTENT = \"max-w-72 truncate\";\n","/**\n * Per-user table preferences kept in localStorage: row density (one choice\n * per user, for every table) and the columns a user hid (per table). The key\n * carries the signed-in user's id when an AuthProvider knows it, so people\n * sharing a browser keep their own. Without one it is \"anonymous\".\n *\n * Storage failures (private mode, quota, a server render) fall back to the\n * defaults silently: a preference is a convenience, never a requirement.\n * Internal to @karni/ui. ResourceTable's `density` / `onDensityChange` props\n * are the escape hatch.\n */\nimport * as React from \"react\";\n\nexport type ResourceTableDensity = \"comfortable\" | \"compact\";\n\nconst PREFIX = \"karni:table\";\n\nexport function densityKey(userId: string | number | undefined): string {\n return `${PREFIX}:density:${userId === undefined ? \"anonymous\" : String(userId)}`;\n}\n\nexport function hiddenColumnsKey(namespace: string, userId: string | number | undefined): string {\n return `${PREFIX}:columns:${namespace}:${userId === undefined ? \"anonymous\" : String(userId)}`;\n}\n\nfunction readStorage(key: string): string | null {\n try {\n return typeof window === \"undefined\" ? null : window.localStorage.getItem(key);\n } catch {\n return null;\n }\n}\n\nfunction writeStorage(key: string, value: string): void {\n try {\n window.localStorage.setItem(key, value);\n } catch {\n // A full or blocked storage only loses the preference.\n }\n}\n\n/**\n * A value remembered under `key`, re-read when the key changes (another user\n * signs in). `parse` returns undefined for anything it does not recognise.\n */\nexport function useStoredPreference<V>(\n key: string,\n fallback: V,\n parse: (raw: string) => V | undefined,\n serialize: (value: V) => string,\n): [V, (value: V) => void] {\n const read = React.useCallback((): V => {\n const raw = readStorage(key);\n return raw === null ? fallback : (parse(raw) ?? fallback);\n }, [key, fallback, parse]);\n const [state, setState] = React.useState<{ key: string; value: V }>(() => ({\n key,\n value: read(),\n }));\n // Another identity (or table) means another remembered value.\n const current = state.key === key ? state.value : read();\n if (state.key !== key) setState({ key, value: current });\n const set = React.useCallback(\n (value: V) => {\n setState({ key, value });\n writeStorage(key, serialize(value));\n },\n [key, serialize],\n );\n return [current, set];\n}\n\nexport function parseDensity(raw: string): ResourceTableDensity | undefined {\n return raw === \"compact\" || raw === \"comfortable\" ? raw : undefined;\n}\n\nexport function parseColumnList(raw: string): readonly string[] | undefined {\n try {\n const parsed: unknown = JSON.parse(raw);\n return Array.isArray(parsed) && parsed.every((item) => typeof item === \"string\")\n ? (parsed as string[])\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport const asString = (value: string): string => value;\nexport const serializeColumnList = (value: readonly string[]): string => JSON.stringify(value);\n","/**\n * Selected-count toolbar for ResourceTable's bulk select (D5): how many rows\n * are selected (selection persists across pages) and what \"all\" covers, a\n * clear affordance, one button per bulk action, and what happened last time\n * (a failure in plain words, or which rows failed). The table runs the\n * actions (confirming destructive ones first). This bar only presents them.\n * The default of ResourceTable's `BulkActions` slot.\n */\nimport * as React from \"react\";\nimport { cn } from \"../../../lib/cn\";\nimport { ErrorState } from \"../../../states/ErrorState\";\nimport { PendingButton } from \"../../../states/PendingButton\";\nimport { Button } from \"../../primitives/button\";\nimport { AlertIcon } from \"../../primitives/icons\";\n\n/** What a bulk action may report back: the rows it could not handle, and why. */\nexport interface BulkResult {\n /** Each failed row's id (String(row.id)) and the reason to show on that row. */\n failed?: ReadonlyArray<{ id: string; reason: string }>;\n}\n\n/**\n * What `BulkAction.onClick` returns: nothing (the 0.3 contract, kept), or a\n * promise of nothing or a `BulkResult`.\n */\n// eslint-disable-next-line @typescript-eslint/no-invalid-void-type -- a callback may return nothing or a promise; void is the precise contract\nexport type BulkActionReturn = void | Promise<void | BulkResult>;\n\nexport interface BulkAction {\n label: React.ReactNode;\n /**\n * Runs the action on the selected ids. Return a promise to have the table\n * show progress, report failures and deselect the rows that succeeded.\n * Resolve a `BulkResult` to mark the rows that failed. A plain `void`\n * return leaves the selection as it is.\n */\n onClick: (selectedIds: string[]) => BulkActionReturn;\n destructive?: boolean;\n /**\n * Ask before running. Default: true for destructive actions. An object\n * words the question (\"Archive 3 events?\" by default).\n */\n confirm?:\n boolean | { title?: React.ReactNode; description?: React.ReactNode; confirmLabel?: string };\n /** Announced while the action runs (\"Archiving…\"). */\n pendingLabel?: string;\n}\n\n/** What the last bulk action came to, for the bar to report. */\nexport type BulkOutcome =\n | { kind: \"failed\"; actionLabel: string; error: unknown; count: number }\n | { kind: \"partial\"; actionLabel: string; failed: number; total: number };\n\nexport interface BulkActionsBarProps {\n /** Row ids (String(row.id), D5) currently selected, across all pages. */\n selectedIds: readonly string[];\n bulkActions: ReadonlyArray<BulkAction>;\n onClear: () => void;\n /** Runs (or asks to confirm) the action at `index`. `trigger` gets focus back after a dialog. */\n onAction?: (index: number, trigger: HTMLButtonElement | null) => void;\n /** The action running now, by index. */\n runningIndex?: number | null;\n /** The last action's failure or partial failure, reported until the next one. */\n outcome?: BulkOutcome | null;\n /** Rows on the current page, and whether all of them are selected. */\n pageRowCount?: number;\n allPageRowsSelected?: boolean;\n /** Everything matching the current search and filters (DRF `count`). */\n totalCount?: number;\n /** The resource, plural (\"events\"). */\n resourceLabel?: string;\n className?: string;\n}\n\nexport function BulkActionsBar(props: BulkActionsBarProps): React.ReactElement {\n const {\n selectedIds,\n bulkActions,\n onClear,\n onAction,\n runningIndex = null,\n outcome = null,\n pageRowCount,\n allPageRowsSelected = false,\n totalCount,\n resourceLabel = \"rows\",\n className,\n } = props;\n const buttons = React.useRef<Array<HTMLButtonElement | null>>([]);\n const count = selectedIds.length;\n const others =\n allPageRowsSelected && totalCount !== undefined && pageRowCount !== undefined\n ? totalCount - count\n : 0;\n\n return (\n <div\n role=\"toolbar\"\n aria-label=\"Bulk actions\"\n className={cn(\n \"flex flex-col gap-2 rounded-md border border-border bg-muted px-3 py-2\",\n className,\n )}\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"text-sm font-medium text-foreground\">{count} selected</p>\n <Button variant=\"ghost\" size=\"sm\" onClick={onClear}>\n Clear\n </Button>\n <div className=\"ml-auto flex flex-wrap items-center gap-2\">\n {bulkActions.map((action, index) => (\n <PendingButton\n key={index}\n ref={(element) => {\n buttons.current[index] = element;\n }}\n variant={action.destructive === true ? \"destructive\" : \"outline\"}\n size=\"sm\"\n pending={runningIndex === index}\n pendingLabel={action.pendingLabel ?? \"Working…\"}\n disabled={runningIndex !== null && runningIndex !== index}\n onClick={() => {\n if (onAction !== undefined) onAction(index, buttons.current[index] ?? null);\n else void action.onClick([...selectedIds]);\n }}\n >\n {action.label}\n </PendingButton>\n ))}\n </div>\n </div>\n {others > 0 && (\n <p className=\"text-xs text-muted-foreground\">\n All {count} {resourceLabel} on this page are selected. The other {others.toLocaleString()}{\" \"}\n matching {resourceLabel} are not.\n </p>\n )}\n {outcome?.kind === \"partial\" && (\n <p role=\"alert\" className=\"flex items-center gap-2 text-sm text-foreground\">\n <AlertIcon className=\"h-4 w-4 shrink-0 text-destructive\" />\n {outcome.actionLabel} failed for {outcome.failed} of {outcome.total} {resourceLabel}. The\n rows that failed say why and stay selected. The others are done.\n </p>\n )}\n {outcome?.kind === \"failed\" && (\n <ErrorState\n variant=\"inline\"\n error={outcome.error}\n context={{\n action: outcome.actionLabel.toLowerCase(),\n resource: `${outcome.count} ${resourceLabel}`,\n }}\n />\n )}\n </div>\n );\n}\n","/**\n * ResourceTable's own icons (pagination arrows, create, view options). Inline\n * SVG with `currentColor` strokes, like the primitives' icons.\n * Internal to @karni/ui.\n */\nimport * as React from \"react\";\n\ntype IconProps = React.SVGAttributes<SVGSVGElement>;\n\nfunction Icon({\n children,\n ...props\n}: IconProps & { children: React.ReactNode }): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n {children}\n </svg>\n );\n}\n\nexport function ChevronLeftIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <polyline points=\"15 18 9 12 15 6\" />\n </Icon>\n );\n}\n\nexport function ChevronRightIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <polyline points=\"9 18 15 12 9 6\" />\n </Icon>\n );\n}\n\nexport function FirstPageIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <polyline points=\"17 18 11 12 17 6\" />\n <line x1=\"7\" y1=\"6\" x2=\"7\" y2=\"18\" />\n </Icon>\n );\n}\n\nexport function LastPageIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <polyline points=\"7 18 13 12 7 6\" />\n <line x1=\"17\" y1=\"6\" x2=\"17\" y2=\"18\" />\n </Icon>\n );\n}\n\nexport function PlusIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </Icon>\n );\n}\n\nexport function SlidersIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <line x1=\"4\" y1=\"6\" x2=\"20\" y2=\"6\" />\n <line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\" />\n <line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\" />\n <circle cx=\"9\" cy=\"6\" r=\"2\" />\n <circle cx=\"15\" cy=\"12\" r=\"2\" />\n <circle cx=\"8\" cy=\"18\" r=\"2\" />\n </Icon>\n );\n}\n\nexport function FilterOffIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <polygon points=\"22 3 2 3 10 12.5 10 19 14 21 14 12.5 22 3\" />\n </Icon>\n );\n}\n\nexport function InboxIcon(props: IconProps): React.ReactElement {\n return (\n <Icon {...props}>\n <polyline points=\"22 12 16 12 14 15 10 15 8 12 2 12\" />\n <path d=\"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z\" />\n </Icon>\n );\n}\n","/**\n * ResourceTable's server-mode pagination row (DRF PageNumberPagination:\n * `{count, next, previous, results}` with `page` / `page_size` params):\n * \"Page X of Y · N items\", a page size choice, first / previous / next /\n * last, and a page number to jump to. Only one page is ever fetched.\n *\n * While a page is on its way (`busy`) the buttons stay focusable but ignore\n * clicks (`aria-disabled`), so a double click never skips a page and a\n * keyboard user's focus stays put. After 500ms the clicked button shows\n * progress. The default of ResourceTable's `Pagination` slot.\n */\nimport * as React from \"react\";\nimport { cn } from \"../../../lib/cn\";\nimport { useDelayedFlag } from \"../../../states/hooks\";\nimport { Button } from \"../../primitives/button\";\nimport { SpinnerIcon } from \"../../primitives/icons\";\nimport { Input } from \"../../primitives/input\";\nimport { Select } from \"../../primitives/select\";\nimport { ChevronLeftIcon, ChevronRightIcon, FirstPageIcon, LastPageIcon } from \"./table-icons\";\n\nexport interface PaginationControlsProps {\n /** 1-based current page. */\n page: number;\n pageCount: number;\n /** Total item count across all pages (DRF `count`). */\n totalCount: number;\n /** From DRF `previous` / `next`. The server is the authority. */\n hasPrevious: boolean;\n hasNext: boolean;\n onPageChange: (page: number) => void;\n /** Rows per page. With `onPageSizeChange` and `pageSizeOptions` it renders the size choice. */\n pageSize?: number;\n pageSizeOptions?: readonly number[];\n onPageSizeChange?: (pageSize: number) => void;\n /** A page is loading: controls announce busy and ignore clicks. */\n busy?: boolean;\n className?: string;\n}\n\ntype Target = \"first\" | \"previous\" | \"next\" | \"last\" | \"jump\";\n\ninterface NavButtonProps {\n label: string;\n /** Shown as text. Icon-only buttons pass `null` and keep `label` as their name. */\n text: React.ReactNode;\n icon?: React.ReactNode;\n iconAfter?: boolean;\n unavailable: boolean;\n busy: boolean;\n spinning: boolean;\n onActivate: () => void;\n buttonRef?: React.Ref<HTMLButtonElement>;\n}\n\nfunction NavButton(props: NavButtonProps): React.ReactElement {\n const { label, text, icon, iconAfter, unavailable, busy, spinning, onActivate, buttonRef } =\n props;\n return (\n <Button\n ref={buttonRef}\n variant=\"outline\"\n size=\"sm\"\n disabled={unavailable}\n aria-label={text === null ? label : undefined}\n title={text === null ? label : undefined}\n aria-disabled={busy || undefined}\n aria-busy={spinning || undefined}\n className={cn(\n \"relative aria-disabled:cursor-wait [&[aria-disabled]:not([aria-busy])]:opacity-50\",\n text === null && \"w-9 px-0\",\n )}\n onClick={() => {\n if (!busy) onActivate();\n }}\n >\n <span className={cn(\"inline-flex items-center gap-1\", spinning && \"text-transparent\")}>\n {!iconAfter && icon}\n {text}\n {iconAfter === true && icon}\n </span>\n {spinning && (\n <span className=\"absolute inset-0 flex items-center justify-center\" aria-hidden=\"true\">\n <SpinnerIcon className=\"h-4 w-4 animate-spin\" />\n </span>\n )}\n </Button>\n );\n}\n\nexport function PaginationControls(props: PaginationControlsProps): React.ReactElement {\n const {\n page,\n pageCount,\n totalCount,\n hasPrevious,\n hasNext,\n onPageChange,\n pageSize,\n pageSizeOptions,\n onPageSizeChange,\n busy = false,\n className,\n } = props;\n const [target, setTarget] = React.useState<Target | null>(null);\n const slow = useDelayedFlag(busy);\n const [jump, setJump] = React.useState(\"\");\n const jumpId = React.useId();\n const previousRef = React.useRef<HTMLButtonElement>(null);\n const nextRef = React.useRef<HTMLButtonElement>(null);\n const [refocus, setRefocus] = React.useState<\"previous\" | \"next\" | null>(null);\n\n // A button that just went unavailable would drop keyboard focus to <body>:\n // hand it to the button pointing the other way.\n React.useEffect(() => {\n if (refocus === \"next\" && !hasPrevious) nextRef.current?.focus();\n if (refocus === \"previous\" && !hasNext) previousRef.current?.focus();\n if (refocus !== null) setRefocus(null);\n }, [refocus, hasPrevious, hasNext]);\n\n const go = (next: number, from: Target): void => {\n const clamped = Math.min(Math.max(1, next), Math.max(1, pageCount));\n if (clamped === page) return;\n setTarget(from);\n if (clamped === 1 && (from === \"first\" || from === \"previous\")) setRefocus(\"next\");\n if (clamped === pageCount && (from === \"last\" || from === \"next\")) setRefocus(\"previous\");\n onPageChange(clamped);\n };\n\n const spinning = (which: Target): boolean => slow && target === which;\n const sizes =\n pageSize !== undefined && pageSizeOptions !== undefined\n ? [...new Set([...pageSizeOptions, pageSize])].sort((a, b) => a - b)\n : [];\n\n return (\n <nav\n aria-label=\"Pagination\"\n aria-busy={busy || undefined}\n className={cn(\"flex flex-wrap items-center justify-between gap-x-3 gap-y-2\", className)}\n >\n <p className=\"text-sm text-muted-foreground\">\n Page {page.toLocaleString()} of {pageCount.toLocaleString()} · {totalCount.toLocaleString()}{\" \"}\n {totalCount === 1 ? \"item\" : \"items\"}\n </p>\n <div className=\"flex flex-wrap items-center gap-2\">\n {sizes.length > 1 && onPageSizeChange !== undefined && pageSize !== undefined && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\" aria-hidden=\"true\">\n Rows per page\n </span>\n <Select\n aria-label=\"Rows per page\"\n className=\"h-9 w-20\"\n value={String(pageSize)}\n options={sizes.map((size) => ({ value: String(size), label: String(size) }))}\n onValueChange={(next) => {\n if (next !== null && !busy) onPageSizeChange(Number(next));\n }}\n />\n </div>\n )}\n <div className=\"flex items-center gap-1\">\n <NavButton\n label=\"First page\"\n text={null}\n icon={<FirstPageIcon className=\"h-4 w-4\" />}\n unavailable={!hasPrevious}\n busy={busy}\n spinning={spinning(\"first\")}\n onActivate={() => go(1, \"first\")}\n />\n <NavButton\n buttonRef={previousRef}\n label=\"Previous\"\n text=\"Previous\"\n icon={<ChevronLeftIcon className=\"h-4 w-4\" />}\n unavailable={!hasPrevious}\n busy={busy}\n spinning={spinning(\"previous\")}\n onActivate={() => go(page - 1, \"previous\")}\n />\n <NavButton\n buttonRef={nextRef}\n label=\"Next\"\n text=\"Next\"\n icon={<ChevronRightIcon className=\"h-4 w-4\" />}\n iconAfter\n unavailable={!hasNext}\n busy={busy}\n spinning={spinning(\"next\")}\n onActivate={() => go(page + 1, \"next\")}\n />\n <NavButton\n label=\"Last page\"\n text={null}\n icon={<LastPageIcon className=\"h-4 w-4\" />}\n unavailable={!hasNext || page >= pageCount}\n busy={busy}\n spinning={spinning(\"last\")}\n onActivate={() => go(pageCount, \"last\")}\n />\n </div>\n {pageCount > 2 && (\n <form\n className=\"flex items-center gap-1\"\n onSubmit={(event) => {\n event.preventDefault();\n const wanted = Number(jump);\n if (busy || !Number.isInteger(wanted) || jump.trim() === \"\") return;\n go(wanted, \"jump\");\n setJump(\"\");\n }}\n >\n <label htmlFor={jumpId} className=\"sr-only\">\n Go to page (1 to {pageCount})\n </label>\n <Input\n id={jumpId}\n type=\"number\"\n inputMode=\"numeric\"\n min={1}\n max={pageCount}\n placeholder=\"Page\"\n value={jump}\n onChange={(event) => setJump(event.target.value)}\n className=\"h-9 w-20\"\n />\n <Button\n type=\"submit\"\n variant=\"outline\"\n size=\"sm\"\n aria-disabled={busy || undefined}\n className=\"aria-disabled:cursor-wait aria-disabled:opacity-50\"\n >\n Go\n </Button>\n </form>\n )}\n </div>\n </nav>\n );\n}\n","/**\n * One row as a card, for containers narrower than ResourceTable's\n * `cardBreakpoint`: the title (the first column, or `getRowLabel`), then a\n * label: value pair per visible column, with the row's checkbox and actions.\n * The default of ResourceTable's `RowCard` slot.\n */\nimport * as React from \"react\";\nimport { cn } from \"../../../lib/cn\";\nimport { AlertIcon } from \"../../primitives/icons\";\nimport { DENSITY_CLASSES } from \"./layout\";\nimport type { ResourceTableDensity } from \"./preferences\";\n\n/** Fields a card shows before \"Show N more details\" (hide columns in the View menu to choose them). */\nconst CARD_FIELDS = 8;\n\nexport interface ResourceTableCardField {\n id: string;\n label: React.ReactNode;\n value: React.ReactNode;\n}\n\nexport interface ResourceTableRowCardProps<T = Record<string, unknown>> {\n row: T;\n /** The card's heading: the first column's cell, or `getRowLabel(row)`. */\n title: React.ReactNode;\n /** The other visible columns, as label: value pairs. */\n fields: readonly ResourceTableCardField[];\n /** The row's checkbox, when the table has bulk actions. */\n selection?: React.ReactNode;\n /** The row's actions (edit, delete, `rowActions`). */\n actions?: React.ReactNode;\n /** Opens the row (`onRowClick`). The title becomes a button. */\n onOpen?: () => void;\n selected: boolean;\n /** Why the last bulk action failed for this row. */\n failure?: string;\n density: ResourceTableDensity;\n}\n\nexport function RowCard<T>(props: ResourceTableRowCardProps<T>): React.ReactElement {\n const { title, fields, selection, actions, onOpen, selected, failure, density } = props;\n const [expanded, setExpanded] = React.useState(false);\n const listId = React.useId();\n // A card is a summary: past CARD_FIELDS fields the rest sit behind a toggle.\n const shown = expanded ? fields : fields.slice(0, CARD_FIELDS);\n const hiddenCount = fields.length - CARD_FIELDS;\n return (\n <li\n data-state={selected ? \"selected\" : undefined}\n className={cn(\n \"flex flex-col rounded-lg border border-border bg-card text-card-foreground data-[state=selected]:border-primary\",\n DENSITY_CLASSES[density].card,\n )}\n >\n <div className=\"flex items-start gap-3\">\n {selection !== undefined && <div className=\"flex h-6 items-center\">{selection}</div>}\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-base font-semibold leading-none\">\n {onOpen !== undefined ? (\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"max-w-full truncate rounded-sm text-left hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {title}\n </button>\n ) : (\n <span className=\"block truncate\">{title}</span>\n )}\n </h3>\n {failure !== undefined && (\n <p className=\"mt-1 flex items-center gap-1 text-xs text-destructive\">\n <AlertIcon className=\"h-3.5 w-3.5 shrink-0\" />\n {failure}\n </p>\n )}\n </div>\n </div>\n {fields.length > 0 && (\n <dl id={listId} className=\"grid grid-cols-2 gap-x-3 gap-y-1 text-sm\">\n {shown.map((field) => (\n <React.Fragment key={field.id}>\n <dt className=\"truncate text-muted-foreground\">{field.label}</dt>\n <dd className=\"min-w-0 break-words text-foreground\">{field.value}</dd>\n </React.Fragment>\n ))}\n </dl>\n )}\n {hiddenCount > 0 && (\n <button\n type=\"button\"\n aria-expanded={expanded}\n aria-controls={listId}\n onClick={() => setExpanded((open) => !open)}\n className=\"self-start rounded-sm text-sm font-medium text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {expanded ? \"Show fewer details\" : `Show ${hiddenCount} more details`}\n </button>\n )}\n {actions !== undefined && (\n // Hidden when the role may do nothing to this row (the actions render empty).\n <div className=\"hidden flex-wrap items-center justify-end gap-1 border-t border-border pt-2 has-[a]:flex has-[button]:flex\">\n {actions}\n </div>\n )}\n </li>\n );\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\n\nregisterComponentRole(\"empty-state\", \"EmptyState\");\n\n/** What each EmptyState slot receives: the matching prop. */\nexport interface EmptyStateSlotProps {\n children: React.ReactNode;\n}\n\n/** The parts of the placeholder a project can replace (`slots={{ Title: MyHeading }}`). */\nexport interface EmptyStateSlots {\n /** Wraps `icon`. It is decorative and hidden from assistive tech. */\n Icon: React.ComponentType<EmptyStateSlotProps>;\n /** The headline. The default is an <h3>. */\n Title: React.ComponentType<EmptyStateSlotProps>;\n /** The supporting copy. */\n Description: React.ComponentType<EmptyStateSlotProps>;\n /** Wraps `action`. */\n Actions: React.ComponentType<EmptyStateSlotProps>;\n}\n\nexport interface EmptyStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Optional illustration/icon slot, rendered above the title. */\n icon?: React.ReactNode;\n /** Short headline (\"No events yet\"). */\n title: React.ReactNode;\n /** Optional supporting copy under the title. */\n description?: React.ReactNode;\n /** Slot for a call to action (e.g. a \"Create\" button). */\n action?: React.ReactNode;\n /** Replaces the Icon, Title, Description or Actions. See EmptyStateSlots. */\n slots?: Partial<EmptyStateSlots>;\n children?: React.ReactNode;\n}\n\nfunction DefaultIcon({ children }: EmptyStateSlotProps): React.ReactElement {\n return (\n <div aria-hidden=\"true\" className=\"mb-2 text-muted-foreground [&>svg]:h-10 [&>svg]:w-10\">\n {children}\n </div>\n );\n}\n\nfunction DefaultTitle({ children }: EmptyStateSlotProps): React.ReactElement {\n return <h3 className=\"text-base font-semibold text-foreground\">{children}</h3>;\n}\n\nfunction DefaultDescription({ children }: EmptyStateSlotProps): React.ReactElement {\n return <p className=\"max-w-96 text-sm text-muted-foreground\">{children}</p>;\n}\n\nfunction DefaultActions({ children }: EmptyStateSlotProps): React.ReactElement {\n return <div className=\"mt-3 flex items-center gap-2\">{children}</div>;\n}\n\n/** The default pieces of the placeholder, for wrapping one. */\nexport const defaultEmptyStateSlots: EmptyStateSlots = {\n Icon: DefaultIcon,\n Title: DefaultTitle,\n Description: DefaultDescription,\n Actions: DefaultActions,\n};\n\n/**\n * Centered placeholder for empty collections: icon, title, description and\n * an action slot. Used by ResourceTable's `empty` slot and reusable anywhere.\n *\n * Escape hatches: `slots` replaces the Icon, Title (an <h3> by default: swap\n * it for the heading level your page needs), Description or Actions.\n * `className` merges via cn(), and extra children render under the action.\n */\nexport const EmptyState = React.forwardRef<HTMLDivElement, EmptyStateProps>(\n ({ icon, title, description, action, slots, className, children, ...props }, ref) => {\n const { Icon, Title, Description, Actions } = { ...defaultEmptyStateSlots, ...slots };\n return (\n <div\n ref={ref}\n className={cn(\n \"flex w-full flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-border bg-background px-6 py-12 text-center\",\n className,\n )}\n {...props}\n >\n {icon != null && <Icon>{icon}</Icon>}\n <Title>{title}</Title>\n {description != null && <Description>{description}</Description>}\n {action != null && <Actions>{action}</Actions>}\n {children}\n </div>\n );\n },\n);\nEmptyState.displayName = \"EmptyState\";\n","/**\n * ResourceTable's state screens, each the default of one slot: the loading\n * skeleton, the two empty screens (nothing yet / nothing matches), the error\n * panels, the permission screen and the offline notice. A project replaces\n * any of them with `slots={{ NoRecords: OurEmpty }}`, and each receives the\n * props documented here.\n */\nimport * as React from \"react\";\nimport { cn } from \"../../../lib/cn\";\nimport { ErrorState, PermissionDenied, type ErrorSlotProps } from \"../../../states/ErrorState\";\nimport { EmptyState } from \"../../empty-state/empty-state\";\nimport { Button } from \"../../primitives/button\";\nimport { OfflineIcon } from \"../../primitives/icons\";\nimport { Skeleton } from \"../../primitives/skeleton\";\nimport {\n BODY_CELL,\n DENSITY_CLASSES,\n FROZEN_AFTER_SELECT,\n FROZEN_AT_START,\n FROZEN_CELL,\n HEAD_CELL,\n LAST_ROW,\n SCROLL_BOX,\n SELECT_CELL,\n TABLE,\n THEAD,\n} from \"./layout\";\nimport type { ResourceTableDensity } from \"./preferences\";\nimport { FilterOffIcon, InboxIcon, PlusIcon } from \"./table-icons\";\n\n// loading\n\n/** What the Loading slot receives: enough to draw the real layout's outline. */\nexport interface ResourceTableLoadingProps {\n /** Columns of the real table, the checkbox and actions columns included (a guess until the schema loads). */\n columnCount: number;\n /** Rows of a full page: the page size. */\n rowCount: number;\n density: ResourceTableDensity;\n /** Draw the toolbar's outline too (until the schema says what the toolbar holds). */\n toolbar: boolean;\n /** \"cards\" below the container breakpoint, else \"table\". */\n layout: \"table\" | \"cards\";\n /** A checkbox column leads (the table has bulk actions). */\n selectable: boolean;\n /** An actions column ends each row (edit, delete, `rowActions`). */\n actions: boolean;\n}\n\n/** Bars of uneven width read as text. The pattern repeats so rows differ. */\nconst BAR_WIDTHS = [\"w-3/4\", \"w-1/2\", \"w-2/3\", \"w-5/6\", \"w-1/3\"] as const;\n\nfunction barWidth(...offsets: number[]): string {\n const index = offsets.reduce((sum, offset) => sum + offset, 0);\n return BAR_WIDTHS[index % BAR_WIDTHS.length] ?? \"w-1/2\";\n}\n\nfunction TableOutline(props: ResourceTableLoadingProps): React.ReactElement {\n const { columnCount, rowCount, density, selectable } = props;\n const sizes = DENSITY_CLASSES[density];\n const columns = Array.from({ length: Math.max(1, columnCount) }, (_, index) => index);\n const frozen = (index: number): string | false => {\n if (selectable && index === 0) return SELECT_CELL;\n if (index === (selectable ? 1 : 0)) {\n return cn(FROZEN_CELL, selectable ? FROZEN_AFTER_SELECT : FROZEN_AT_START);\n }\n return false;\n };\n return (\n <div className={cn(SCROLL_BOX, \"overflow-hidden\")}>\n <table className={TABLE}>\n <thead className={THEAD}>\n <tr>\n {columns.map((index) => (\n <th key={index} scope=\"col\" className={cn(HEAD_CELL, sizes.head, frozen(index))}>\n {selectable && index === 0 ? (\n <Skeleton className=\"h-4 w-4 rounded-sm bg-background\" />\n ) : (\n <Skeleton className=\"h-3 w-16 bg-background\" />\n )}\n </th>\n ))}\n </tr>\n </thead>\n <tbody className={LAST_ROW}>\n {Array.from({ length: rowCount }, (_, row) => (\n <tr key={row} className=\"group/row\">\n {columns.map((index) => (\n <td key={index} className={cn(BODY_CELL, sizes.cell, frozen(index))}>\n {selectable && index === 0 ? (\n <Skeleton className=\"h-4 w-4 rounded-sm\" />\n ) : (\n <Skeleton className={cn(\"h-4 min-w-12\", barWidth(row, index))} />\n )}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\nfunction CardsOutline(props: ResourceTableLoadingProps): React.ReactElement {\n const { density, selectable, actions } = props;\n const sizes = DENSITY_CLASSES[density];\n // The card's fields: the data columns after the title, as RowCard shows them (8 at most).\n const structural = (selectable ? 1 : 0) + (actions ? 1 : 0);\n const pairs = Math.min(8, Math.max(1, props.columnCount - structural - 1));\n return (\n <ul className=\"flex flex-col gap-3\">\n {Array.from({ length: props.rowCount }, (_, row) => (\n <li\n key={row}\n className={cn(\"flex flex-col rounded-lg border border-border bg-card\", sizes.card)}\n >\n <div className=\"flex h-6 items-center gap-3\">\n {selectable && <Skeleton className=\"h-4 w-4 rounded-sm\" />}\n <Skeleton className={cn(\"h-4\", barWidth(row, 0))} />\n </div>\n <div className=\"grid grid-cols-2 gap-x-3 gap-y-1\">\n {Array.from({ length: pairs * 2 }, (_, index) => (\n <div key={index} className=\"flex h-5 items-center\">\n <Skeleton className={cn(\"h-3.5\", barWidth(row, index, 1))} />\n </div>\n ))}\n </div>\n {actions && (\n <div className=\"flex justify-end border-t border-border pt-2\">\n <Skeleton className={cn(\"w-16\", sizes.action)} />\n </div>\n )}\n </li>\n ))}\n </ul>\n );\n}\n\n/**\n * The default Loading slot: the real layout in outline (toolbar, header row\n * with the real column count, a full page of rows at the current density,\n * the pagination row), so nothing moves when the data arrives. Hidden from\n * screen readers: the table's live region says \"Loading…\" instead.\n */\nexport function TableSkeleton(props: ResourceTableLoadingProps): React.ReactElement {\n return (\n <div aria-hidden=\"true\" data-testid=\"resource-table-skeleton\" className=\"flex flex-col gap-3\">\n {props.toolbar && (\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <Skeleton className=\"h-9 w-full max-w-80\" />\n <Skeleton className=\"h-9 w-40\" />\n </div>\n )}\n {props.layout === \"cards\" ? <CardsOutline {...props} /> : <TableOutline {...props} />}\n <div className=\"flex min-h-9 flex-wrap items-center justify-between gap-3\">\n <Skeleton className=\"h-4 w-40\" />\n <Skeleton className=\"h-9 w-64\" />\n </div>\n </div>\n );\n}\n\n// empty: nothing yet\n\n/** What the NoRecords slot receives: the resource has no rows at all yet. */\nexport interface ResourceTableNoRecordsProps {\n /** The resource as a sentence names it, plural (\"events\"). */\n resourceLabel: string;\n /** One of them (\"event\"). */\n itemLabel: string;\n /** Set when the table knows how to create one and the role may: offer it. */\n onCreate?: () => void;\n createLabel: string;\n}\n\n/** \"No events yet\": explains, and offers the create action when there is one. */\nexport function NoRecords(props: ResourceTableNoRecordsProps): React.ReactElement {\n const { resourceLabel, itemLabel, onCreate, createLabel } = props;\n return (\n <EmptyState\n data-empty-reason=\"no-records\"\n icon={<InboxIcon />}\n title={`No ${resourceLabel} yet`}\n description={\n onCreate !== undefined\n ? `Create the first ${itemLabel} and it will appear here.`\n : `When ${resourceLabel} are added, they will appear here.`\n }\n action={\n onCreate !== undefined ? (\n <Button size=\"sm\" onClick={onCreate}>\n <PlusIcon className=\"h-4 w-4\" />\n {createLabel}\n </Button>\n ) : undefined\n }\n />\n );\n}\n\n// empty: nothing matches\n\n/** One active filter, in words (\"Status: Draft\"). */\nexport interface ResourceTableActiveFilter {\n field: string;\n label: string;\n value: string;\n}\n\n/** What the NoResults slot receives: rows exist, but none match the search or filters. */\nexport interface ResourceTableNoResultsProps {\n resourceLabel: string;\n /** The search term, or \"\" when the search box is empty. */\n search: string;\n /** The filters narrowing the list, in words. */\n filters: readonly ResourceTableActiveFilter[];\n /** Resets the search and every filter (pinned `params` stay). */\n onClearFilters: () => void;\n}\n\n/** \"No events match\": says what is narrowing the list and offers to clear it. */\nexport function NoResults(props: ResourceTableNoResultsProps): React.ReactElement {\n const { resourceLabel, search, filters, onClearFilters } = props;\n const narrowing = [\n ...(search !== \"\" ? [`the search “${search}”`] : []),\n ...filters.map((filter) => `${filter.label}: ${filter.value}`),\n ];\n return (\n <EmptyState\n data-empty-reason=\"no-results\"\n icon={<FilterOffIcon />}\n title={`No ${resourceLabel} match`}\n description={`Nothing matches ${narrowing.join(\" and \")}. Try a different search, or clear the filters.`}\n action={\n <Button variant=\"outline\" size=\"sm\" onClick={onClearFilters}>\n Clear filters\n </Button>\n }\n >\n {narrowing.length > 0 && (\n <ul aria-label=\"Active filters\" className=\"mt-3 flex flex-wrap justify-center gap-2\">\n {search !== \"\" && (\n <li className=\"rounded-md border border-border bg-muted px-2 py-0.5 text-xs text-foreground\">\n Search: {search}\n </li>\n )}\n {filters.map((filter) => (\n <li\n key={filter.field}\n className=\"rounded-md border border-border bg-muted px-2 py-0.5 text-xs text-foreground\"\n >\n {filter.label}: {filter.value}\n </li>\n ))}\n </ul>\n )}\n </EmptyState>\n );\n}\n\n// errors\n\n/** The default Error slot: what failed, in plain words, with \"Try again\" when it can help. */\nexport function TableError(props: ErrorSlotProps): React.ReactElement {\n return <ErrorState {...props} />;\n}\n\n/**\n * The default RefetchError slot: a failed refresh over rows already shown.\n * The rows stay, and this one line says the list may be out of date.\n */\nexport function RefetchError(props: ErrorSlotProps): React.ReactElement {\n return (\n <ErrorState\n {...props}\n variant=\"inline\"\n className=\"rounded-md border border-destructive-border bg-destructive-subtle px-3 py-2\"\n />\n );\n}\n\n/** What the Forbidden slot receives: the list itself answered 403. */\nexport interface ResourceTableForbiddenProps {\n resourceLabel: string;\n /** The server's refusal (its own explanation, when it gave one, is in `data.detail`). */\n error: unknown;\n}\n\n/** \"You can't view events\": no retry, since asking again changes nothing. */\nexport function Forbidden(props: ResourceTableForbiddenProps): React.ReactElement {\n return <PermissionDenied action=\"view\" resource={props.resourceLabel} />;\n}\n\n/** What the Offline slot receives while the browser has no connection. */\nexport interface ResourceTableOfflineProps {\n resourceLabel: string;\n /** Rows loaded before the connection dropped are still on screen. */\n hasRows: boolean;\n onRetry: () => void;\n}\n\n/**\n * The default Offline slot. With rows on screen it is one line above them.\n * Without rows it is the offline error panel. The table reloads by itself\n * once the connection is back.\n */\nexport function OfflineNotice(props: ResourceTableOfflineProps): React.ReactElement {\n if (!props.hasRows) {\n return (\n <ErrorState\n error={new TypeError(\"offline\")}\n onRetry={props.onRetry}\n actions={\n <span className=\"text-sm text-muted-foreground\">\n The list loads by itself when you are back online.\n </span>\n }\n />\n );\n }\n return (\n <div\n role=\"status\"\n className={cn(\n \"flex items-center gap-2 rounded-md border border-border bg-muted px-3 py-2 text-sm text-foreground\",\n )}\n >\n <OfflineIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span>\n You're offline. These {props.resourceLabel} may be out of date. The list refreshes by\n itself when you're back online.\n </span>\n </div>\n );\n}\n","/**\n * ResourceTable's slots: every state screen and structural part a project\n * can replace with its own component, `slots={{ NoRecords: OurEmpty }}`.\n * Each slot receives the props type exported next to it. The defaults are\n * exported as `defaultResourceTableSlots`, so a replacement can wrap one\n * (`(props) => <defaultResourceTableSlots.Error {...props} />`).\n */\nimport type * as React from \"react\";\nimport type { ErrorSlotProps } from \"../../../states/ErrorState\";\nimport { BulkActionsBar, type BulkActionsBarProps } from \"./BulkActionsBar\";\nimport { PaginationControls, type PaginationControlsProps } from \"./PaginationControls\";\nimport { RowCard, type ResourceTableRowCardProps } from \"./RowCard\";\nimport {\n Forbidden,\n NoRecords,\n NoResults,\n OfflineNotice,\n RefetchError,\n TableError,\n TableSkeleton,\n type ResourceTableForbiddenProps,\n type ResourceTableLoadingProps,\n type ResourceTableNoRecordsProps,\n type ResourceTableNoResultsProps,\n type ResourceTableOfflineProps,\n} from \"./states\";\n\n/** The pagination row's props (the `Pagination` slot). */\nexport type ResourceTablePaginationProps = PaginationControlsProps;\n\n/** The bulk actions bar's props (the `BulkActions` slot). */\nexport type ResourceTableBulkActionsProps = BulkActionsBarProps;\n\nexport interface ResourceTableSlots {\n /** The first load: the layout in outline. */\n Loading: React.ComponentType<ResourceTableLoadingProps>;\n /** The resource has no rows at all yet. */\n NoRecords: React.ComponentType<ResourceTableNoRecordsProps>;\n /** Rows exist, but none match the search and filters. */\n NoResults: React.ComponentType<ResourceTableNoResultsProps>;\n /** The list (or the schema) failed to load and there is nothing to show. */\n Error: React.ComponentType<ErrorSlotProps>;\n /** A refresh failed while rows were already on screen: the rows stay. */\n RefetchError: React.ComponentType<ErrorSlotProps>;\n /** The role may not view this resource (the list answered 403). */\n Forbidden: React.ComponentType<ResourceTableForbiddenProps>;\n /** The browser is offline. */\n Offline: React.ComponentType<ResourceTableOfflineProps>;\n /** The pagination row. */\n Pagination: React.ComponentType<ResourceTablePaginationProps>;\n /** The selected-rows bar. */\n BulkActions: React.ComponentType<ResourceTableBulkActionsProps>;\n /** One row as a card, below `cardBreakpoint`. */\n RowCard: React.ComponentType<ResourceTableRowCardProps<unknown>>;\n}\n\nexport const defaultResourceTableSlots: ResourceTableSlots = {\n Loading: TableSkeleton,\n NoRecords,\n NoResults,\n Error: TableError,\n RefetchError,\n Forbidden,\n Offline: OfflineNotice,\n Pagination: PaginationControls,\n BulkActions: BulkActionsBar,\n RowCard,\n};\n\nexport type {\n ResourceTableForbiddenProps,\n ResourceTableLoadingProps,\n ResourceTableNoRecordsProps,\n ResourceTableNoResultsProps,\n ResourceTableOfflineProps,\n ResourceTableRowCardProps,\n};\n","/**\n * ResourceTable's keyboard model in the table layout: the WAI-ARIA grid\n * pattern with a roving tabindex. The whole table is one Tab stop. The arrow\n * keys move between rows and cells, Home and End to the ends of a row, and\n * Ctrl+Home and Ctrl+End to the first and last cell of the grid.\n *\n * The stops are read from the DOM, so any cell content works: a cell that\n * holds controls (a checkbox, the row's button, links, the row actions, a\n * menu trigger) puts each control in the row's arrow order, and a cell\n * without one is a stop itself. Exactly one stop has tabindex 0 (the last\n * one focused). Every other stop has -1, and a MutationObserver keeps it so\n * when rows, pages or cell content change. Internal to @karni/ui.\n */\nimport * as React from \"react\";\n\n/** What can take focus inside a cell. */\nconst CONTROL_SELECTOR = [\n \"a[href]\",\n \"button\",\n \"input\",\n \"select\",\n \"textarea\",\n \"summary\",\n \"iframe\",\n \"audio[controls]\",\n \"video[controls]\",\n '[contenteditable=\"\"]',\n '[contenteditable=\"true\"]',\n \"[tabindex]\",\n].join(\", \");\n\n/** Controls that use the arrow keys themselves, so the grid leaves them alone. */\nconst FIELD_SELECTOR =\n 'input:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"button\"]):not([type=\"submit\"]):not([type=\"reset\"]), textarea, select, [contenteditable=\"\"], [contenteditable=\"true\"]';\n\n/** Whether a control can take focus: not disabled, and not hidden inside its cell. */\nfunction usable(element: HTMLElement, cell: HTMLTableCellElement): boolean {\n if (element.matches(\":disabled\")) return false;\n if (element instanceof HTMLInputElement && element.type === \"hidden\") return false;\n // Up to the cell only: a dialog hides the page around it with aria-hidden for a while.\n for (let node: HTMLElement | null = element; node !== null && node !== cell;) {\n if (node.hidden || node.hasAttribute(\"inert\") || node.getAttribute(\"aria-hidden\") === \"true\") {\n return false;\n }\n node = node.parentElement;\n }\n return true;\n}\n\n/** The controls of one cell, outermost only (a button's inner focusable is not a second stop). */\nfunction controlsOf(cell: HTMLTableCellElement): HTMLElement[] {\n const found = Array.from(cell.querySelectorAll<HTMLElement>(CONTROL_SELECTOR)).filter((element) =>\n usable(element, cell),\n );\n return found.filter(\n (element) => !found.some((other) => other !== element && other.contains(element)),\n );\n}\n\n/** A cell's stop number `index`: its control at that position (clamped), or the cell itself. */\nfunction stopIn(cell: HTMLTableCellElement, index: number): HTMLElement {\n const controls = controlsOf(cell);\n if (controls.length === 0) return cell;\n return controls[Math.min(index, controls.length - 1)] ?? cell;\n}\n\n/** Every stop of a row, left to right. */\nfunction stopsOf(row: HTMLTableRowElement): HTMLElement[] {\n return Array.from(row.cells).flatMap((cell) => {\n const controls = controlsOf(cell);\n return controls.length === 0 ? [cell] : controls;\n });\n}\n\ninterface Position {\n row: HTMLTableRowElement;\n rowIndex: number;\n cell: HTMLTableCellElement;\n cellIndex: number;\n /** Which control of the cell (0 for a cell without controls). */\n control: number;\n stop: HTMLElement;\n}\n\n/** Where an element sits in the grid, or null when it is not in one of its cells. */\nfunction locate(table: HTMLTableElement, element: Element): Position | null {\n const cell = element.closest(\"td, th\");\n if (!(cell instanceof HTMLTableCellElement)) return null;\n const row = cell.parentElement;\n if (!(row instanceof HTMLTableRowElement) || row.closest(\"table\") !== table) return null;\n const controls = controlsOf(cell);\n const control = controls.findIndex((candidate) => candidate.contains(element));\n const stop = controls[control] ?? cell;\n return {\n row,\n rowIndex: row.rowIndex,\n cell,\n cellIndex: cell.cellIndex,\n control: Math.max(control, 0),\n stop,\n };\n}\n\n/** The remembered stop, by row id, then by the same place when its row is gone. */\ninterface Memory {\n stop: HTMLElement | null;\n rowId: string | null;\n rowIndex: number;\n cellIndex: number;\n control: number;\n}\n\n/** The row attribute that names a row across renders (TableView sets it to the row id). */\nconst ROW_ID_ATTRIBUTE = \"data-row-id\";\n\nfunction resolve(table: HTMLTableElement, memory: Memory): HTMLElement | null {\n if (memory.stop !== null && memory.stop.isConnected && table.contains(memory.stop)) {\n const position = locate(table, memory.stop);\n if (position !== null && position.stop === memory.stop) return memory.stop;\n }\n const rows = Array.from(table.rows);\n if (rows.length === 0) return null;\n const byId =\n memory.rowId === null\n ? undefined\n : rows.find((row) => row.getAttribute(ROW_ID_ATTRIBUTE) === memory.rowId);\n const row = byId ?? rows[Math.min(memory.rowIndex, rows.length - 1)];\n if (row === undefined || row.cells.length === 0) return null;\n const cell = row.cells[Math.min(memory.cellIndex, row.cells.length - 1)];\n return cell === undefined ? null : stopIn(cell, memory.control);\n}\n\nfunction remember(table: HTMLTableElement, memory: Memory, element: Element): HTMLElement | null {\n const position = locate(table, element);\n if (position === null) return null;\n memory.stop = position.stop;\n memory.rowId = position.row.getAttribute(ROW_ID_ATTRIBUTE);\n memory.rowIndex = position.rowIndex;\n memory.cellIndex = position.cellIndex;\n memory.control = position.control;\n return position.stop;\n}\n\n/** Gives the active stop tabindex 0 and every other stop -1. */\nfunction sync(table: HTMLTableElement, memory: Memory): void {\n const active = resolve(table, memory);\n // Its row may have moved (a sort): remember where it is now.\n if (active !== null) remember(table, memory, active);\n for (const row of Array.from(table.rows)) {\n for (const cell of Array.from(row.cells)) {\n const controls = controlsOf(cell);\n if (controls.length === 0) {\n setTabIndex(cell, cell === active ? 0 : -1);\n } else {\n // A cell with controls is not a stop of its own.\n if (cell.hasAttribute(\"tabindex\")) cell.removeAttribute(\"tabindex\");\n for (const control of controls) setTabIndex(control, control === active ? 0 : -1);\n }\n }\n }\n}\n\nfunction setTabIndex(element: HTMLElement, value: 0 | -1): void {\n const text = String(value);\n if (element.getAttribute(\"tabindex\") !== text) element.setAttribute(\"tabindex\", text);\n}\n\n/** Where a navigation key goes from `from`, or null at the edge of the grid. */\nfunction nextStop(\n table: HTMLTableElement,\n from: Position,\n event: React.KeyboardEvent,\n): HTMLElement | null {\n const rows = Array.from(table.rows);\n const stops = stopsOf(from.row);\n const index = stops.indexOf(from.stop);\n const toRow = (row: HTMLTableRowElement | undefined): HTMLElement | null => {\n if (row === undefined || row.cells.length === 0) return null;\n const cell = row.cells[Math.min(from.cellIndex, row.cells.length - 1)];\n return cell === undefined ? null : stopIn(cell, from.control);\n };\n const toGridCorner = event.ctrlKey || event.metaKey;\n switch (event.key) {\n case \"ArrowRight\":\n return stops[index + 1] ?? null;\n case \"ArrowLeft\":\n return index > 0 ? (stops[index - 1] ?? null) : null;\n case \"ArrowDown\":\n return toRow(rows[from.rowIndex + 1]);\n case \"ArrowUp\":\n return from.rowIndex > 0 ? toRow(rows[from.rowIndex - 1]) : null;\n case \"Home\": {\n const row = toGridCorner ? rows[0] : from.row;\n return row === undefined ? null : (stopsOf(row)[0] ?? null);\n }\n case \"End\": {\n const row = toGridCorner ? rows[rows.length - 1] : from.row;\n return row === undefined ? null : (stopsOf(row).at(-1) ?? null);\n }\n default:\n return null;\n }\n}\n\n/** useLayoutEffect warns during server rendering, where there is no DOM to sync. */\nconst useIsomorphicLayoutEffect =\n typeof window === \"undefined\" ? React.useEffect : React.useLayoutEffect;\n\nconst NAVIGATION_KEYS = new Set([\"ArrowRight\", \"ArrowLeft\", \"ArrowDown\", \"ArrowUp\", \"Home\", \"End\"]);\n\nexport interface GridNavigation {\n onKeyDown: (event: React.KeyboardEvent<HTMLTableElement>) => void;\n onFocus: (event: React.FocusEvent<HTMLTableElement>) => void;\n}\n\n/**\n * The roving tabindex of a table. Returns the handlers for the <table>. When\n * `enabled` is false they do nothing and the table is left as rendered.\n */\nexport function useGridNavigation(\n tableRef: React.RefObject<HTMLTableElement>,\n enabled: boolean,\n): GridNavigation {\n // Enter the grid at its first body row (the header row when there is none).\n const memory = React.useRef<Memory>({\n stop: null,\n rowId: null,\n rowIndex: 1,\n cellIndex: 0,\n control: 0,\n });\n\n useIsomorphicLayoutEffect(() => {\n const table = tableRef.current;\n if (!enabled || table === null) return undefined;\n sync(table, memory.current);\n // Rows, pages and cell content change without this hook's knowledge.\n const observer = new MutationObserver(() => sync(table, memory.current));\n observer.observe(table, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"disabled\", \"hidden\", \"inert\", \"aria-hidden\", \"href\"],\n });\n return () => observer.disconnect();\n }, [enabled, tableRef]);\n\n const onFocus = React.useCallback(\n (event: React.FocusEvent<HTMLTableElement>) => {\n if (!enabled) return;\n const table = event.currentTarget;\n if (!(event.target instanceof Element) || !table.contains(event.target)) return;\n // A click, a script or a closing dialog put focus here: Tab comes back to it.\n const before = memory.current.stop;\n const stop = remember(table, memory.current, event.target);\n if (stop !== null && (stop !== before || stop.getAttribute(\"tabindex\") !== \"0\")) {\n sync(table, memory.current);\n }\n },\n [enabled],\n );\n\n const onKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLTableElement>) => {\n if (!enabled || event.defaultPrevented || event.altKey) return;\n if (!NAVIGATION_KEYS.has(event.key)) return;\n const table = event.currentTarget;\n const element = event.target;\n // Keys from a menu portalled out of a cell reach here through React: not ours.\n if (!(element instanceof HTMLElement) || !table.contains(element)) return;\n // A text field inside a cell keeps its arrows (Tab leaves it).\n if (element.matches(FIELD_SELECTOR)) return;\n const from = locate(table, element);\n if (from === null) return;\n event.preventDefault();\n const next = nextStop(table, from, event);\n if (next === null) return;\n remember(table, memory.current, next);\n sync(table, memory.current);\n next.focus();\n },\n [enabled],\n );\n\n return { onKeyDown, onFocus };\n}\n","/**\n * ResourceTable's table layout: one scrolling box (both axes), a header that\n * sticks on vertical scroll, a frozen first column (after the checkboxes)\n * that shows an edge once the table scrolls sideways, and rows a keyboard\n * can open (the first cell holds a button when `onRowClick` is set).\n *\n * With `keyboardNavigation=\"grid\"` (the default) the table is a WAI-ARIA\n * grid: one Tab stop for the whole table, arrows between rows and cells\n * (./grid-navigation), Enter opens the row and Space selects it.\n * Internal to @karni/ui.\n */\nimport { flexRender, type Header, type Row, type Table } from \"@tanstack/react-table\";\nimport * as React from \"react\";\nimport { cn } from \"../../../lib/cn\";\nimport { AlertIcon, ChevronDownIcon, ChevronUpIcon, SpinnerIcon } from \"../../primitives/icons\";\nimport {\n BODY_CELL,\n DENSITY_CLASSES,\n FROZEN_AFTER_SELECT,\n FROZEN_AT_START,\n FROZEN_CELL,\n FROZEN_CONTENT,\n GRID_CELL,\n GRID_SCROLL_BOX,\n HEAD_CELL,\n LAST_ROW,\n SCROLL_BOX,\n SELECT_CELL,\n TABLE,\n THEAD,\n} from \"./layout\";\nimport { useGridNavigation } from \"./grid-navigation\";\nimport type { ResourceTableDensity } from \"./preferences\";\nimport { ACTIONS_COLUMN, SELECT_COLUMN } from \"./structural-columns\";\n\n/** How the keyboard moves through the table's rows (ResourceTable's `keyboardNavigation`). */\nexport type ResourceTableKeyboardNavigation = \"grid\" | \"native\";\n\nexport interface TableViewProps<T> {\n table: Table<T>;\n /** Names the table for assistive technology (\"Events\"). */\n caption: string;\n density: ResourceTableDensity;\n /** A sort or page change is loading: sort buttons ignore clicks. */\n busy: boolean;\n /** The column whose header was clicked last, for its progress spinner. */\n sortTarget: string | null;\n /** Work has run for 500ms: show progress. */\n slow: boolean;\n onSort: (header: Header<T, unknown>, event: React.MouseEvent) => void;\n onRowClick?: (row: T) => void;\n /** Why the last bulk action failed, by row id. */\n failures: Readonly<Record<string, string>>;\n /** 1-based position of the first row in the whole list, for aria-rowindex. */\n firstRowIndex: number;\n totalCount?: number;\n /** The rows are stale (a later request failed or is slow): dim them. */\n dimmed: boolean;\n scrollRef: React.RefObject<HTMLDivElement>;\n keyboardNavigation: ResourceTableKeyboardNavigation;\n}\n\nfunction isCheckbox(element: HTMLElement): boolean {\n return (\n element.getAttribute(\"role\") === \"checkbox\" ||\n (element instanceof HTMLInputElement && element.type === \"checkbox\")\n );\n}\n\n/**\n * Enter and Space on a row of the grid. Controls keep their own keys: a\n * button activates, a link follows, and Ctrl or Cmd+Enter opens it in a new\n * tab. On a cell, Enter opens the row and Space selects it. A checkbox does\n * not use Enter, so there Enter opens the row too.\n */\nfunction rowKeyDown<T>(\n event: React.KeyboardEvent<HTMLTableRowElement>,\n row: Row<T>,\n onRowClick: ((row: T) => void) | undefined,\n): void {\n if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;\n if (event.key !== \"Enter\" && event.key !== \" \") return;\n const element = event.target;\n if (!(element instanceof HTMLElement)) return;\n const cell = element.closest(\"td\");\n if (cell === null || cell.parentElement !== event.currentTarget) return;\n const onCell = element === cell;\n if (event.key === \"Enter\") {\n // A checkbox cancels Enter itself (it must not submit a form), so that is not checked here.\n if ((onCell || isCheckbox(element)) && onRowClick !== undefined) {\n event.preventDefault();\n onRowClick(row.original);\n }\n return;\n }\n // Space: links do not use it, buttons and checkboxes do.\n if (event.defaultPrevented || !(onCell || element instanceof HTMLAnchorElement)) return;\n if (row.getCanSelect()) {\n event.preventDefault();\n row.toggleSelected();\n }\n}\n\nfunction frozenClasses(\n columnId: string,\n firstDataColumn: string | undefined,\n selectable: boolean,\n): string | false {\n if (columnId === SELECT_COLUMN) return SELECT_CELL;\n if (columnId === firstDataColumn) {\n return cn(FROZEN_CELL, selectable ? FROZEN_AFTER_SELECT : FROZEN_AT_START);\n }\n return false;\n}\n\nexport function TableView<T>(props: TableViewProps<T>): React.ReactElement {\n const {\n table,\n caption,\n density,\n busy,\n sortTarget,\n slow,\n onSort,\n onRowClick,\n failures,\n firstRowIndex,\n totalCount,\n dimmed,\n scrollRef,\n keyboardNavigation,\n } = props;\n const sizes = DENSITY_CLASSES[density];\n const captionId = React.useId();\n const grid = keyboardNavigation === \"grid\";\n const tableRef = React.useRef<HTMLTableElement>(null);\n const navigation = useGridNavigation(tableRef, grid);\n const columns = table.getVisibleLeafColumns();\n const selectable = columns.some((column) => column.id === SELECT_COLUMN);\n const firstDataColumn = columns.find(\n (column) => column.id !== SELECT_COLUMN && column.id !== ACTIONS_COLUMN,\n )?.id;\n\n // Mark the box once it scrolls sideways, so the frozen column shows its edge.\n const onScroll = React.useCallback((event: React.UIEvent<HTMLDivElement>) => {\n const box = event.currentTarget;\n const scrolled = box.scrollLeft > 0;\n if ((box.dataset[\"scrolled\"] === \"true\") !== scrolled) {\n box.dataset[\"scrolled\"] = String(scrolled);\n }\n }, []);\n\n return (\n <div className=\"relative\">\n {slow && (\n <div\n aria-hidden=\"true\"\n data-testid=\"resource-table-progress\"\n className=\"absolute inset-x-0 top-0 z-drawer h-1 animate-pulse rounded-t-md bg-primary\"\n />\n )}\n <div\n ref={scrollRef}\n role=\"region\"\n aria-labelledby={captionId}\n // A grid is the Tab stop and scrolls each cell it focuses into view. The\n // box still takes focus by script (where focus lands after a delete).\n tabIndex={grid ? -1 : 0}\n onScroll={onScroll}\n className={cn(SCROLL_BOX, grid && GRID_SCROLL_BOX, dimmed && \"cursor-progress\")}\n >\n <table\n ref={tableRef}\n role={grid ? \"grid\" : undefined}\n aria-labelledby={grid ? captionId : undefined}\n aria-multiselectable={grid && selectable ? true : undefined}\n className={TABLE}\n aria-busy={busy || undefined}\n aria-rowcount={totalCount !== undefined ? totalCount + 1 : undefined}\n onKeyDown={grid ? navigation.onKeyDown : undefined}\n onFocus={grid ? navigation.onFocus : undefined}\n >\n <caption id={captionId} className=\"sr-only\">\n {caption}\n </caption>\n <thead className={THEAD}>\n {table.getHeaderGroups().map((group) => (\n <tr key={group.id} aria-rowindex={1}>\n {group.headers.map((header) => {\n const canSort = header.column.getCanSort();\n const direction = header.column.getIsSorted();\n const spinning = slow && busy && sortTarget === header.column.id;\n return (\n <th\n key={header.id}\n scope=\"col\"\n aria-sort={\n direction === \"asc\"\n ? \"ascending\"\n : direction === \"desc\"\n ? \"descending\"\n : undefined\n }\n className={cn(\n HEAD_CELL,\n grid && GRID_CELL,\n sizes.head,\n frozenClasses(header.column.id, firstDataColumn, selectable),\n header.column.id === ACTIONS_COLUMN && \"text-right\",\n )}\n >\n {header.isPlaceholder ? null : canSort ? (\n <button\n type=\"button\"\n aria-disabled={busy || undefined}\n aria-busy={spinning || undefined}\n className=\"inline-flex items-center gap-1 rounded-sm hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring aria-disabled:cursor-wait\"\n onClick={(event) => onSort(header, event)}\n >\n {flexRender(header.column.columnDef.header, header.getContext())}\n {spinning ? (\n <SpinnerIcon className=\"h-3.5 w-3.5 animate-spin\" />\n ) : direction === \"asc\" ? (\n <ChevronUpIcon className=\"h-3.5 w-3.5\" />\n ) : direction === \"desc\" ? (\n <ChevronDownIcon className=\"h-3.5 w-3.5\" />\n ) : null}\n </button>\n ) : (\n flexRender(header.column.columnDef.header, header.getContext())\n )}\n </th>\n );\n })}\n </tr>\n ))}\n </thead>\n <tbody className={LAST_ROW}>\n {table.getRowModel().rows.map((row, index) => {\n const failure = failures[row.id];\n return (\n <tr\n key={row.id}\n data-row-id={row.id}\n aria-rowindex={firstRowIndex + index + 1}\n aria-selected={grid && selectable ? row.getIsSelected() : undefined}\n data-state={row.getIsSelected() ? \"selected\" : undefined}\n data-failed={failure !== undefined ? \"true\" : undefined}\n onClick={onRowClick !== undefined ? () => onRowClick(row.original) : undefined}\n onKeyDown={grid ? (event) => rowKeyDown(event, row, onRowClick) : undefined}\n className={cn(\"group/row\", onRowClick !== undefined && \"cursor-pointer\")}\n >\n {row.getVisibleCells().map((cell) => {\n const first = cell.column.id === firstDataColumn;\n const content = flexRender(cell.column.columnDef.cell, cell.getContext());\n return (\n <td\n key={cell.id}\n className={cn(\n BODY_CELL,\n grid && GRID_CELL,\n sizes.cell,\n frozenClasses(cell.column.id, firstDataColumn, selectable),\n )}\n >\n {first ? (\n <div className=\"flex flex-col\">\n {onRowClick !== undefined ? (\n <button\n type=\"button\"\n className={cn(\n FROZEN_CONTENT,\n \"rounded-sm text-left font-medium hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n )}\n onClick={(event) => {\n event.stopPropagation();\n onRowClick(row.original);\n }}\n >\n {content}\n </button>\n ) : (\n <div className={FROZEN_CONTENT}>{content}</div>\n )}\n {failure !== undefined && (\n <span className=\"flex items-center gap-1 text-xs text-destructive\">\n <AlertIcon className=\"h-3.5 w-3.5 shrink-0\" />\n {failure}\n </span>\n )}\n </div>\n ) : (\n content\n )}\n </td>\n );\n })}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n","/**\n * The width of an element, kept current with a ResizeObserver. ResourceTable\n * switches to cards from its own container's width, not the viewport's, so a\n * table in a narrow sidebar or a split view lays out for the room it has.\n * `undefined` until measured (and where there is no layout, as in jsdom), so\n * the table keeps its default layout rather than guessing.\n * Internal to @karni/ui.\n */\nimport * as React from \"react\";\n\nconst useIsomorphicLayoutEffect =\n typeof window === \"undefined\" ? React.useEffect : React.useLayoutEffect;\n\nexport function useContainerWidth(ref: React.RefObject<HTMLElement | null>): number | undefined {\n const [width, setWidth] = React.useState<number | undefined>(undefined);\n useIsomorphicLayoutEffect(() => {\n const element = ref.current;\n if (element === null) return undefined;\n const measure = (next: number): void => setWidth(next > 0 ? next : undefined);\n measure(element.getBoundingClientRect().width);\n if (typeof ResizeObserver === \"undefined\") return undefined;\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) measure(entry.contentRect.width);\n });\n observer.observe(element);\n return () => observer.disconnect();\n }, [ref]);\n return width;\n}\n","/**\n * Tiny debounce hook for ResourceTable's search box, so a keystroke burst\n * becomes one list query. Internal to @karni/ui.\n */\nimport * as React from \"react\";\n\nexport function useDebouncedValue<T>(value: T, delayMs: number): T {\n const [debounced, setDebounced] = React.useState(value);\n React.useEffect(() => {\n const timer = setTimeout(() => setDebounced(value), delayMs);\n return () => clearTimeout(timer);\n }, [value, delayMs]);\n return debounced;\n}\n","/**\n * ResourceTable's view state (page, page size, ordering, search, filters) in\n * the URL, so a view can be shared and Back returns to the previous one.\n *\n * The table reads and writes its own query keys through a\n * `ResourceTableStateStore`. The default store uses `window.history` and\n * listens to `popstate`, so it needs no router. A project on a router plugs\n * its search params in with its own store (see the README). Keys are\n * namespaced (`events.page=2`), and the reserved names are DRF's own\n * (`page`, `page_size`, `ordering`, `search`), so a filter field can never\n * collide with them. A value equal to the table's default is left out of the\n * URL. Pinned `params` are never URL state.\n */\nimport * as React from \"react\";\nimport type { FilterValue } from \"../../../hooks/types\";\nimport type { FieldDef } from \"../../../schema/types\";\n\n/**\n * Where a table keeps its view state. The table only touches its own\n * (namespaced) keys.\n *\n * An adapter for a router reads the router's current search params in\n * `read`, navigates in `write`, and either calls the `subscribe` listener\n * when the params change or simply passes a new store object on each change\n * (the table re-reads whenever the store changes).\n */\nexport interface ResourceTableStateStore {\n /** Every current query value by key. */\n read(): Readonly<Record<string, string>>;\n /**\n * Merge `changes` into the URL (`null` removes a key). `push` adds a\n * history entry (page, sort, filter changes). Otherwise the current entry\n * is replaced (a search refined while typing, a page clamped).\n */\n write(changes: Readonly<Record<string, string | null>>, options: { push: boolean }): void;\n /** Call `onChange` when the values change outside the table. Returns an unsubscribe. */\n subscribe(onChange: () => void): () => void;\n}\n\nconst historyListeners = new Set<() => void>();\n\n/**\n * The default store: the browser's URL through `window.history`\n * (`pushState` / `replaceState`, `popstate` for Back and Forward). Other\n * query parameters and the hash are kept.\n */\nexport function createHistoryStateStore(): ResourceTableStateStore {\n return {\n read() {\n if (typeof window === \"undefined\") return {};\n return Object.fromEntries(new URLSearchParams(window.location.search));\n },\n write(changes, { push }) {\n if (typeof window === \"undefined\") return;\n const url = new URL(window.location.href);\n for (const [key, value] of Object.entries(changes)) {\n if (value === null) url.searchParams.delete(key);\n else url.searchParams.set(key, value);\n }\n if (url.href === window.location.href) return;\n if (push) window.history.pushState(window.history.state, \"\", url);\n else window.history.replaceState(window.history.state, \"\", url);\n // Other tables on the page re-read their own keys (pushState fires no event).\n for (const listener of [...historyListeners]) listener();\n },\n subscribe(onChange) {\n historyListeners.add(onChange);\n window.addEventListener(\"popstate\", onChange);\n return () => {\n historyListeners.delete(onChange);\n window.removeEventListener(\"popstate\", onChange);\n };\n },\n };\n}\n\nconst defaultStore = createHistoryStateStore();\n\n/** The view a table shows: what the URL holds for it. */\nexport interface TableView {\n page: number;\n pageSize: number;\n /** DRF ordering (\"-starts_at,title\"), where \"\" is \"no ordering\". */\n ordering: string;\n search: string;\n filters: Readonly<Record<string, FilterValue>>;\n}\n\nexport interface TableViewDefaults {\n pageSize: number;\n ordering: string;\n /** Page sizes a URL may ask for. Anything else falls back to the default. */\n pageSizes: readonly number[];\n}\n\nconst RESERVED = new Set([\"page\", \"page_size\", \"ordering\", \"search\"]);\n\nfunction prefixed(namespace: string, key: string): string {\n return namespace === \"\" ? key : `${namespace}.${key}`;\n}\n\n/** Encodes one filter value for the URL (arrays comma-joined). */\nexport function encodeFilter(value: FilterValue): string | null {\n if (value === null || value === undefined) return null;\n if (Array.isArray(value)) return value.length === 0 ? null : value.map(String).join(\",\");\n return String(value);\n}\n\nfunction relationId(raw: string, field: FieldDef): string | number {\n return field.relationValueType === \"integer\" && /^-?\\d+$/.test(raw) ? Number(raw) : raw;\n}\n\n/** Decodes a URL value back to the type the filter control and the API expect. */\nexport function decodeFilter(raw: string, field: FieldDef): FilterValue {\n if (field.kind === \"boolean\") return raw === \"true\" ? true : raw === \"false\" ? false : undefined;\n if (field.kind === \"enum\") {\n return (field.enumValues ?? []).find((member) => String(member) === raw);\n }\n if (field.kind === \"relation\" && field.relation !== undefined) {\n if (field.relation.many) {\n const ids = raw\n .split(\",\")\n .filter((part) => part.length > 0)\n .map((part) => relationId(part, field));\n return ids.length > 0 ? ids : undefined;\n }\n return relationId(raw, field);\n }\n return raw;\n}\n\nfunction positiveInt(raw: string | undefined): number | undefined {\n if (raw === undefined || !/^\\d+$/.test(raw)) return undefined;\n const value = Number(raw);\n return value >= 1 ? value : undefined;\n}\n\n/** The table's own entries of the store, as a stable string (a snapshot). */\nfunction snapshotOf(store: ResourceTableStateStore, namespace: string): string {\n const prefix = namespace === \"\" ? \"\" : `${namespace}.`;\n const own = Object.entries(store.read())\n .filter(([key]) => (prefix === \"\" ? true : key.startsWith(prefix)))\n .map(([key, value]) => [key.slice(prefix.length), value] as const)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));\n return JSON.stringify(own);\n}\n\nfunction viewFromSnapshot(\n snapshot: string,\n defaults: TableViewDefaults,\n filterFields: readonly FieldDef[],\n): TableView {\n const entries = new Map(JSON.parse(snapshot) as Array<[string, string]>);\n const size = positiveInt(entries.get(\"page_size\"));\n const filters: Record<string, FilterValue> = {};\n for (const field of filterFields) {\n const raw = entries.get(field.name);\n if (raw === undefined || RESERVED.has(field.name)) continue;\n const value = decodeFilter(raw, field);\n if (value !== undefined) filters[field.name] = value;\n }\n return {\n page: positiveInt(entries.get(\"page\")) ?? 1,\n pageSize: size !== undefined && defaults.pageSizes.includes(size) ? size : defaults.pageSize,\n ordering: entries.get(\"ordering\") ?? defaults.ordering,\n search: entries.get(\"search\") ?? \"\",\n filters,\n };\n}\n\nfunction isCleared(value: FilterValue): boolean {\n return (\n value === null ||\n value === undefined ||\n value === \"\" ||\n (Array.isArray(value) && value.length === 0)\n );\n}\n\n/** Drops cleared filters so \"no filter\" has one representation. */\nexport function compactFilters(\n filters: Readonly<Record<string, FilterValue>>,\n): Record<string, FilterValue> {\n return Object.fromEntries(Object.entries(filters).filter(([, value]) => !isCleared(value)));\n}\n\nexport type SetTableView = (patch: Partial<TableView>, options: { push: boolean }) => void;\n\nexport interface UseTableViewOptions {\n /** False keeps the view in component state only (the URL is untouched). */\n syncUrl: boolean;\n /** Where the URL state lives. Default: `window.history`. */\n store?: ResourceTableStateStore;\n namespace: string;\n defaults: TableViewDefaults;\n /** The fields the filter bar offers: only these are read from the URL. */\n filterFields: readonly FieldDef[];\n}\n\nconst noSubscription = (): (() => void) => () => undefined;\n\n/** The table's view state, from the URL (or component state) with a setter. */\nexport function useTableView(options: UseTableViewOptions): [TableView, SetTableView] {\n const { syncUrl, namespace, defaults, filterFields } = options;\n const store = options.store ?? defaultStore;\n\n const subscribe = React.useCallback(\n (onChange: () => void) => (syncUrl ? store.subscribe(onChange) : noSubscription()),\n [store, syncUrl],\n );\n const getSnapshot = React.useCallback(\n () => (syncUrl ? snapshotOf(store, namespace) : \"[]\"),\n [store, namespace, syncUrl],\n );\n const snapshot = React.useSyncExternalStore(subscribe, getSnapshot, () => \"[]\");\n\n const [local, setLocal] = React.useState<TableView>(() => ({\n page: 1,\n pageSize: defaults.pageSize,\n ordering: defaults.ordering,\n search: \"\",\n filters: {},\n }));\n\n const fromUrl = React.useMemo(\n () => viewFromSnapshot(snapshot, defaults, filterFields),\n [snapshot, defaults, filterFields],\n );\n const view = syncUrl ? fromUrl : local;\n\n const viewRef = React.useRef(view);\n viewRef.current = view;\n\n const setView = React.useCallback<SetTableView>(\n (patch, { push }) => {\n const next: TableView = {\n ...viewRef.current,\n ...patch,\n filters: compactFilters(patch.filters ?? viewRef.current.filters),\n };\n // Two updates in one event (search settles while a filter changes) compose.\n viewRef.current = next;\n if (!syncUrl) {\n setLocal(next);\n return;\n }\n const changes: Record<string, string | null> = {\n [prefixed(namespace, \"page\")]: next.page === 1 ? null : String(next.page),\n [prefixed(namespace, \"page_size\")]:\n next.pageSize === defaults.pageSize ? null : String(next.pageSize),\n [prefixed(namespace, \"ordering\")]:\n next.ordering === defaults.ordering ? null : next.ordering,\n [prefixed(namespace, \"search\")]: next.search === \"\" ? null : next.search,\n };\n for (const field of filterFields) {\n if (RESERVED.has(field.name)) continue;\n changes[prefixed(namespace, field.name)] = encodeFilter(next.filters[field.name]);\n }\n store.write(changes, { push });\n },\n [store, syncUrl, namespace, defaults, filterFields],\n );\n\n return [view, setView];\n}\n","/**\n * ResourceTable's \"View\" menu: compact rows on or off, and which columns\n * show. Both are remembered per user (see ./preferences). A Radix dropdown,\n * so it is operable by keyboard (arrows, Space to toggle, Escape to close).\n * Internal to @karni/ui. ResourceTable's `viewOptions={false}` hides it.\n */\nimport * as React from \"react\";\nimport { Button } from \"../../primitives/button\";\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"../../primitives/dropdown-menu\";\nimport type { ResourceTableDensity } from \"./preferences\";\nimport { SlidersIcon } from \"./table-icons\";\n\nexport interface ViewOptionsProps {\n density: ResourceTableDensity;\n onDensityChange: (density: ResourceTableDensity) => void;\n columns: ReadonlyArray<{ id: string; label: string; visible: boolean }>;\n onColumnVisibilityChange: (id: string, visible: boolean) => void;\n}\n\nexport function ViewOptions(props: ViewOptionsProps): React.ReactElement {\n const { density, onDensityChange, columns, onColumnVisibilityChange } = props;\n const visibleCount = columns.filter((column) => column.visible).length;\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" size=\"sm\" aria-label=\"View options\">\n <SlidersIcon className=\"h-4 w-4\" />\n View\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"max-h-96 overflow-y-auto\">\n <DropdownMenuCheckboxItem\n checked={density === \"compact\"}\n onCheckedChange={(checked) => onDensityChange(checked ? \"compact\" : \"comfortable\")}\n >\n Compact rows\n </DropdownMenuCheckboxItem>\n {columns.length > 1 && (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Columns</DropdownMenuLabel>\n {columns.map((column) => (\n <DropdownMenuCheckboxItem\n key={column.id}\n checked={column.visible}\n // The last visible column stays: a table with no columns says nothing.\n disabled={column.visible && visibleCount === 1}\n onCheckedChange={(checked) => onColumnVisibilityChange(column.id, checked)}\n onSelect={(event) => event.preventDefault()}\n >\n {column.label}\n </DropdownMenuCheckboxItem>\n ))}\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n","/**\n * ResourceTable: the schema-driven data table (contract \"ResourceTable\" + D5).\n *\n * `<Page title=\"Events\"><ResourceTable resource=\"events\" /></Page>` is a\n * complete screen: columns derive from the parsed OpenAPI schema, sorting maps\n * to DRF `ordering`, the search box renders only when the list operation\n * declares `search`, the filter bar derives from the declared query params,\n * and pagination speaks `page` / `page_size` (one page is fetched, never\n * everything).\n *\n * Every state is its own screen, each a replaceable slot: the loading outline\n * (the real layout, so nothing moves when data arrives), \"no records yet\"\n * (with the create action when there is one) apart from \"nothing matches\"\n * (with \"Clear filters\"), errors in plain words with a retry, a failed\n * refresh that keeps the rows, \"You can't view events\" for a 403, offline,\n * and progress once work runs for 500ms.\n *\n * Page, page size, ordering, search and filters live in the URL (namespaced,\n * Back works). `syncUrl={false}` opts out and `stateStore` plugs in a router.\n * Below `cardBreakpoint` (its container's width, not the viewport's) rows\n * render as cards. Wide tables scroll inside their box with a sticky header\n * and a frozen first column. Density and hidden columns are remembered per\n * user. In the table layout the rows are a WAI-ARIA grid: the whole table\n * is one Tab stop and the arrow keys move between rows and cells\n * (`keyboardNavigation=\"native\"` makes every control a Tab stop again).\n *\n * Audit fields (AUDIT_FIELDS: id, created_at, updated_at, created_by,\n * updated_by, carried by every BaseModel resource) are hidden by default so\n * domain fields lead. Rows stay keyed by `id` regardless (getRowId, row\n * actions, onRowClick, bulk selection). Show one with a `columns` entry\n * (`{ field: \"created_at\" }`), or all of them with `showAuditFields`.\n *\n * Escape hatches: `columns` (per-field overrides), `extraColumns` (ColumnDef\n * passthrough), `columnsOverride` (applied last over the derived + merged\n * domain columns, but the selection and actions columns are structural and\n * follow `bulkActions` / `rowActions` / `onEdit` / `enableDelete`),\n * `rowActions`, `bulkActions`, `filters`, `slots` (every state screen and\n * part), `toolbar` / `empty` / `footer`, `canCreate` / `canEdit` /\n * `canDelete` (over the schema's access rules), `stateStore`, `getRowLabel`,\n * and `className`.\n */\nimport { keepPreviousData, useQueryClient } from \"@tanstack/react-query\";\nimport {\n getCoreRowModel,\n useReactTable,\n type ColumnDef,\n type Header,\n type RowSelectionState,\n type SortingState,\n type Updater,\n type VisibilityState,\n} from \"@tanstack/react-table\";\nimport * as React from \"react\";\nimport { AuthContext } from \"../../../auth/provider\";\nimport { karniKeys } from \"../../../hooks/keys\";\nimport type { FilterValue, Paginated, ResourceListParams } from \"../../../hooks/types\";\nimport type { ExportFormat } from \"../../../hooks/useResourceImport\";\nimport { useResourceList } from \"../../../hooks/useResourceList\";\nimport { useResourceMutations } from \"../../../hooks/useResourceMutations\";\nimport { cn } from \"../../../lib/cn\";\nimport { registerComponentRole } from \"../../../lib/roles\";\nimport type { KarniQueryValue } from \"../../../schema/client\";\nimport { humanize } from \"../../../schema/parse\";\nimport type { FieldDef } from \"../../../schema/types\";\nimport { useSchema } from \"../../../schema/useSchema\";\nimport { useDelayedFlag, useOnlineStatus } from \"../../../states/hooks\";\nimport { Button } from \"../../primitives/button\";\nimport { isAuditField, partitionAuditFields } from \"../audit-fields\";\nimport { displayLabel } from \"../displayLabel\";\nimport { evaluateAccess, type AccessIdentity } from \"./access\";\nimport type { BulkAction, BulkOutcome, BulkResult } from \"./BulkActionsBar\";\nimport { CardList } from \"./CardList\";\nimport { ConfirmDialog } from \"./ConfirmDialog\";\nimport { deriveColumns, type ResourceColumn } from \"./derive-columns\";\nimport { ExportButtons } from \"./ExportButtons\";\nimport { FilterBar } from \"./FilterBar\";\nimport { DENSITY_CLASSES } from \"./layout\";\nimport {\n asString,\n densityKey,\n hiddenColumnsKey,\n parseColumnList,\n parseDensity,\n serializeColumnList,\n useStoredPreference,\n type ResourceTableDensity,\n} from \"./preferences\";\nimport { defaultResourceTableSlots, type ResourceTableSlots } from \"./slots\";\nimport type { ResourceTableActiveFilter } from \"./states\";\nimport { actionsColumn, isStructural, selectionColumn } from \"./structural-columns\";\nimport { PlusIcon } from \"./table-icons\";\nimport {\n asRecord,\n capitalised,\n enumLabel,\n isNotFoundError,\n orderingToSorting,\n pageCountFor,\n resourceWords,\n listRetry,\n singular,\n sortingToOrdering,\n statusOf,\n} from \"./table-utils\";\nimport { TableView, type ResourceTableKeyboardNavigation } from \"./TableView\";\nimport { useContainerWidth } from \"./use-container-width\";\nimport { useDebouncedValue } from \"./use-debounced-value\";\nimport { useTableView, type ResourceTableStateStore } from \"./url-state\";\nimport { ViewOptions as ViewOptionsMenu } from \"./ViewOptions\";\n\nregisterComponentRole(\"data-table\", \"ResourceTable\");\n\nexport type {\n BulkAction,\n BulkResult,\n ResourceColumn,\n ResourceTableDensity,\n ResourceTableKeyboardNavigation,\n};\n\nexport const DEFAULT_PAGE_SIZE = 25;\n/** The page sizes offered by default (`pageSizeOptions`). */\nexport const DEFAULT_PAGE_SIZE_OPTIONS: readonly number[] = [10, 25, 50, 100];\n/** Below this container width (px) rows render as cards (`cardBreakpoint`). */\nexport const DEFAULT_CARD_BREAKPOINT = 640;\nconst SEARCH_DEBOUNCE_MS = 300;\nconst MAX_DERIVED_FILTERS = 4;\n/** Columns the loading outline draws before the schema says how many there are. */\nconst SKELETON_COLUMNS = 5;\nconst NO_COLUMNS: readonly string[] = [];\n\nexport interface ResourceTableProps<T = Record<string, unknown>> {\n resource: string;\n /**\n * Per-field overrides. Naming a default-hidden field (an audit field such\n * as `created_at`, or a json/file field) shows it. `hidden: true` hides one.\n */\n columns?: ReadonlyArray<ResourceColumn<T>>;\n /**\n * Show the audit columns (AUDIT_FIELDS: id, created_at, updated_at,\n * created_by, updated_by) after the domain columns, and let audit fields\n * into the derived filter bar. Default false: they are hidden.\n */\n showAuditFields?: boolean;\n /** TanStack ColumnDef pass-through, appended after derived columns. */\n extraColumns?: ReadonlyArray<ColumnDef<T>>;\n /** Full escape hatch, applied last over the derived + merged columns. */\n columnsOverride?: (derived: Array<ColumnDef<T>>) => Array<ColumnDef<T>>;\n rowActions?: (row: T) => React.ReactNode;\n /** Passing this enables the default edit row action. */\n onEdit?: (row: T) => void;\n /** Enables the default delete row action (confirms in a dialog, uses useResourceMutations). */\n enableDelete?: boolean;\n bulkActions?: ReadonlyArray<BulkAction>;\n /**\n * Opens a row. The whole row is clickable, and its first cell is a button,\n * so the row opens from the keyboard too (Enter on any cell of the grid).\n */\n onRowClick?: (row: T) => void;\n /**\n * `expand` query values. Default: single-relation field names ∩ the list\n * operation's expand enum, never guessed beyond the schema (D5).\n */\n expand?: readonly string[];\n /** The ordering when the URL names none. */\n initialSorting?: SortingState;\n /** Sent as `page_size`. Default 25. */\n pageSize?: number;\n /** The page sizes a user can choose. Default `[10, 25, 50, 100]`. `pageSize` is always offered. */\n pageSizeOptions?: readonly number[];\n /**\n * Field names to build the filter bar from. `false` disables it. Default:\n * (enum/boolean/relation fields) ∩ declared list query params, domain\n * fields first, audit fields only with `showAuditFields`, cap 4 (D5).\n * Only enum, boolean and relation fields get controls.\n */\n filters?: readonly string[] | false;\n /**\n * Fixed filters sent with every request and hidden from the filter bar,\n * e.g. `{ event: eventId }` for \"the bookings of this event\". A user filter\n * on the same field never overrides them. Never written to the URL.\n */\n params?: Readonly<Record<string, KarniQueryValue>>;\n /**\n * Export buttons (one per format) when the resource serves\n * `GET /<resource>/export/`, as every Karni BaseViewSet does. The file\n * carries the table's current filters, search and ordering. The backend\n * applies the row scope and field visibility. Default `[\"csv\", \"xlsx\"]`.\n * `false` hides them.\n */\n exportFormats?: readonly ExportFormat[] | false;\n /** Extra toolbar content, rendered to the right of the search/filter row. */\n toolbar?: React.ReactNode;\n /**\n * Replaces both empty screens. Prefer `slots.NoRecords` and\n * `slots.NoResults`, which tell \"nothing yet\" from \"nothing matches\".\n */\n empty?: React.ReactNode;\n /** Rendered under the pagination row. */\n footer?: React.ReactNode;\n /** Overrides displayLabel() for relation cells, row names (checkboxes, cards, the delete question). */\n getRowLabel?: (row: Record<string, unknown>) => string;\n /** Replace any state screen or part (see ResourceTableSlots). */\n slots?: Partial<ResourceTableSlots>;\n /** The resource in sentences, plural (\"events\"). Default: from the resource name. */\n resourceLabel?: string;\n /** One of them (\"event\"). Default: a singular of `resourceLabel`. */\n itemLabel?: string;\n /** Names the table for assistive technology. Default: `resourceLabel`, capitalised. */\n caption?: string;\n /** Offers a create button (toolbar and the \"no records yet\" screen). */\n onCreate?: () => void;\n /** Default \"New <itemLabel>\". */\n createLabel?: string;\n /**\n * Whether the role may create. Default: the schema documents a create\n * operation and its access rule does not refuse this user.\n */\n canCreate?: boolean;\n /** Whether a row's edit action shows. Default: the update operation's access rule for this user and row. */\n canEdit?: boolean | ((row: T) => boolean);\n /** Whether a row's delete action shows. Default: the delete operation's access rule for this user and row. */\n canDelete?: boolean | ((row: T) => boolean);\n /** Keep page, page size, sort, search and filters in the URL. Default true. */\n syncUrl?: boolean;\n /** Prefix of this table's URL keys (`events.page=2`). Default: the resource name, `\"\"` for none. */\n urlNamespace?: string;\n /** Where URL state lives. Default `window.history`. Plug a router in here. */\n stateStore?: ResourceTableStateStore;\n /** Row density, controlled. Uncontrolled, the user's choice is remembered per user. */\n density?: ResourceTableDensity;\n /** The density before the user chooses. Default \"comfortable\". */\n defaultDensity?: ResourceTableDensity;\n onDensityChange?: (density: ResourceTableDensity) => void;\n /** The \"View\" menu (density, column visibility). Default true. */\n viewOptions?: boolean;\n /** Below this container width (px) rows render as cards. Default 640, and 0 means never. */\n cardBreakpoint?: number;\n /**\n * How the keyboard moves through the table layout. Default `\"grid\"`, the\n * WAI-ARIA grid pattern: the whole table is one Tab stop, the arrow keys\n * move between rows and cells (each control of a cell is a stop of its\n * own), Home and End go to the ends of a row, Ctrl+Home and Ctrl+End to\n * the first and last cell, Enter on a cell opens the row (`onRowClick`) and\n * Space on a cell selects it (`bulkActions`). `\"native\"` is a plain table\n * where every checkbox, button and link is its own Tab stop, as before.\n */\n keyboardNavigation?: ResourceTableKeyboardNavigation;\n className?: string;\n}\n\ninterface DeleteTarget<T> {\n row: T;\n trigger: HTMLButtonElement;\n}\n\ninterface ConfirmTarget {\n index: number;\n trigger: HTMLButtonElement | null;\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\nfunction textOf(node: React.ReactNode): string | undefined {\n return typeof node === \"string\" || typeof node === \"number\" ? String(node) : undefined;\n}\n\nfunction filterWords(field: FieldDef, value: FilterValue): string {\n if (field.kind === \"boolean\") return value === true ? \"Yes\" : \"No\";\n if (field.kind === \"enum\" && (typeof value === \"string\" || typeof value === \"number\")) {\n return enumLabel(value, field.enumLabels);\n }\n if (Array.isArray(value)) return `${value.length} chosen`;\n if (field.kind === \"relation\") return \"1 chosen\";\n return String(value);\n}\n\n/** The delete question for one row. Its mutation lives here so tables without deletes never create it. */\nfunction RowDeleteDialog<T>(props: {\n resource: string;\n target: DeleteTarget<T> | null;\n rowLabel: (row: T) => string;\n onClose: () => void;\n onDeleted: (label: string) => void;\n fallbackFocus: () => HTMLElement | null;\n}): React.ReactElement {\n const { resource, target, rowLabel, onClose, onDeleted, fallbackFocus } = props;\n const mutations = useResourceMutations(resource);\n const [error, setError] = React.useState<unknown>(null);\n const deleted = React.useRef(false);\n // The dialog closes after `target` is cleared: keep wording and focus on the last one.\n const last = React.useRef(target);\n if (target !== null) last.current = target;\n React.useEffect(() => {\n setError(null);\n if (target !== null) deleted.current = false;\n }, [target]);\n const label = last.current === null ? \"\" : rowLabel(last.current.row);\n const quoted = `“${label}”`;\n return (\n <ConfirmDialog\n open={target !== null}\n title={`Delete ${quoted}?`}\n description=\"This can't be undone.\"\n confirmLabel=\"Delete\"\n pendingLabel=\"Deleting…\"\n destructive\n pending={mutations.remove.isPending}\n error={error}\n errorContext={{ action: \"delete\", resource: quoted }}\n onCancel={onClose}\n onConfirm={() => {\n const id = target === null ? undefined : asRecord(target.row)[\"id\"];\n if (typeof id !== \"string\" && typeof id !== \"number\") return;\n setError(null);\n mutations.remove.mutate(id, {\n onSuccess: () => {\n deleted.current = true;\n onDeleted(label);\n },\n onError: (failure) => setError(failure),\n });\n }}\n returnFocus={() => {\n const trigger = last.current?.trigger;\n return !deleted.current && trigger !== undefined && trigger.isConnected\n ? trigger\n : fallbackFocus();\n }}\n />\n );\n}\n\n/** Schema-driven data table for one resource: columns, sorting, filters, search, pagination, row actions and bulk select, all derived from the OpenAPI schema. */\nexport function ResourceTable<T = Record<string, unknown>>(\n props: ResourceTableProps<T>,\n): React.ReactElement {\n const {\n resource,\n columns,\n showAuditFields,\n extraColumns,\n columnsOverride,\n rowActions,\n onEdit,\n enableDelete,\n bulkActions,\n onRowClick,\n expand,\n initialSorting,\n pageSize,\n pageSizeOptions,\n filters,\n params,\n exportFormats,\n toolbar,\n empty,\n footer,\n getRowLabel,\n slots: slotOverrides,\n resourceLabel,\n itemLabel,\n caption,\n onCreate,\n createLabel,\n canCreate,\n canEdit,\n canDelete,\n syncUrl = true,\n urlNamespace,\n stateStore,\n density: densityProp,\n defaultDensity = \"comfortable\",\n onDensityChange,\n viewOptions = true,\n cardBreakpoint = DEFAULT_CARD_BREAKPOINT,\n keyboardNavigation = \"grid\",\n className,\n } = props;\n\n const Slots = React.useMemo<ResourceTableSlots>(\n () => ({ ...defaultResourceTableSlots, ...slotOverrides }),\n [slotOverrides],\n );\n const queryClient = useQueryClient();\n const auth = React.useContext(AuthContext);\n const authStatus = auth?.status;\n const authUser = auth?.user ?? null;\n const identity = React.useMemo<AccessIdentity | null>(\n () => (authStatus === undefined ? null : { status: authStatus, user: authUser }),\n [authStatus, authUser],\n );\n const userId = authStatus === \"authenticated\" ? authUser?.id : undefined;\n\n const schemaResult = useSchema(resource);\n const schema = schemaResult.data;\n\n const plural = resourceLabel ?? resourceWords(resource);\n const one = itemLabel ?? singular(plural);\n const tableName = caption ?? capitalised(plural);\n const namespace = urlNamespace ?? resource;\n\n // filters the bar offers (D5)\n const pinned = React.useMemo(() => new Set(Object.keys(params ?? {})), [params]);\n const filterFields = React.useMemo<readonly FieldDef[]>(() => {\n if (filters === false || schema === undefined) return [];\n if (filters !== undefined) {\n const byName = new Map(schema.fields.map((field) => [field.name, field]));\n return filters\n .filter((name) => !pinned.has(name))\n .map((name) => byName.get(name))\n .filter((field): field is FieldDef => field !== undefined);\n }\n const declared = new Set(schema.operations.list?.queryParams ?? []);\n const { domain, audit } = partitionAuditFields(schema.fields);\n return [...domain, ...audit]\n .filter(\n (field) =>\n !field.writeOnly &&\n !pinned.has(field.name) &&\n (showAuditFields === true || !isAuditField(field)) &&\n declared.has(field.name) &&\n (field.kind === \"enum\" ||\n field.kind === \"boolean\" ||\n (field.kind === \"relation\" && field.relation !== undefined)),\n )\n .slice(0, MAX_DERIVED_FILTERS);\n }, [filters, pinned, schema, showAuditFields]);\n\n // view state: the URL (or component state with syncUrl={false})\n const defaultPageSize = pageSize ?? DEFAULT_PAGE_SIZE;\n const sizesKey = (pageSizeOptions ?? DEFAULT_PAGE_SIZE_OPTIONS).join(\",\");\n const defaultOrdering = sortingToOrdering(initialSorting ?? []) ?? \"\";\n const defaults = React.useMemo(\n () => ({\n pageSize: defaultPageSize,\n ordering: defaultOrdering,\n pageSizes: [\n ...new Set([...sizesKey.split(\",\").map(Number).filter(Number.isFinite), defaultPageSize]),\n ].sort((a, b) => a - b),\n }),\n [defaultPageSize, defaultOrdering, sizesKey],\n );\n const [view, setView] = useTableView({\n syncUrl,\n store: stateStore,\n namespace,\n defaults,\n filterFields,\n });\n const viewRef = React.useRef(view);\n viewRef.current = view;\n const sorting = React.useMemo(() => orderingToSorting(view.ordering), [view.ordering]);\n\n // announcements for screen readers\n const [announcement, setAnnouncement] = React.useState(\"\");\n const intent = React.useRef<\"page\" | \"results\" | null>(null);\n\n // search: the box is local while typing, the settled term is URL state\n const [searchInput, setSearchInput] = React.useState(view.search);\n const debouncedSearch = useDebouncedValue(searchInput, SEARCH_DEBOUNCE_MS);\n const shownSearch = React.useRef(view.search);\n React.useEffect(() => {\n // Back, Forward, a shared link or \"Clear filters\" changed the search.\n if (view.search !== shownSearch.current) {\n shownSearch.current = view.search;\n setSearchInput(view.search);\n }\n }, [view.search]);\n const settledSearch = React.useRef(debouncedSearch);\n React.useEffect(() => {\n if (debouncedSearch === settledSearch.current) return;\n settledSearch.current = debouncedSearch;\n const term = debouncedSearch.trim();\n const current = viewRef.current;\n if (term === current.search) return;\n shownSearch.current = term;\n intent.current = \"results\";\n // The first keystrokes add a history entry; refining the term replaces it.\n setView({ search: term, page: 1 }, { push: current.search === \"\" });\n }, [debouncedSearch, setView]);\n\n const handleFilterChange = React.useCallback(\n (field: FieldDef, value: FilterValue) => {\n intent.current = \"results\";\n setView(\n { filters: { ...viewRef.current.filters, [field.name]: value }, page: 1 },\n { push: true },\n );\n },\n [setView],\n );\n\n const clearFilters = React.useCallback(() => {\n intent.current = \"results\";\n setSearchInput(\"\");\n setView({ search: \"\", filters: {}, page: 1 }, { push: true });\n }, [setView]);\n\n // schema-derived behaviour (D5)\n const expandList = React.useMemo<readonly string[]>(() => {\n if (expand !== undefined) return expand;\n const allowed = schema?.operations.list?.expandEnum;\n if (schema === undefined || allowed === undefined) return [];\n return schema.fields\n .filter(\n (field) =>\n field.kind === \"relation\" &&\n field.relation !== undefined &&\n !field.relation.many &&\n allowed.includes(field.name),\n )\n .map((field) => field.name);\n }, [expand, schema]);\n\n const searchEnabled = schema?.operations.list?.hasSearch === true;\n const activeSearch = searchEnabled ? view.search : \"\";\n\n // the list query: one page, never everything\n const listParams = React.useMemo<ResourceListParams>(\n () => ({\n page: view.page,\n pageSize: view.pageSize,\n ordering: view.ordering === \"\" ? undefined : view.ordering,\n search: activeSearch.length > 0 ? activeSearch : undefined,\n filters:\n Object.keys(view.filters).length > 0 || params !== undefined\n ? { ...view.filters, ...params }\n : undefined,\n expand: expandList.length > 0 ? expandList : undefined,\n }),\n [view, activeSearch, params, expandList],\n );\n\n const appRetry = queryClient.getDefaultOptions().queries?.retry;\n const retry = React.useMemo(() => listRetry(appRetry), [appRetry]);\n const list = useResourceList<T>(resource, listParams, {\n enabled: schema !== undefined,\n placeholderData: keepPreviousData,\n // A 4xx answers the same way again (a 404 is the page-clamp signal, D5);\n // the rest follows the app's QueryClient.\n retry,\n });\n\n // The last page that loaded, kept so a failed refresh never wipes the table.\n const lastLoaded = React.useRef<{ resource: string; data: Paginated<T> } | null>(null);\n if (list.data !== undefined) lastLoaded.current = { resource, data: list.data };\n const lastData = lastLoaded.current?.resource === resource ? lastLoaded.current.data : undefined;\n\n const status = statusOf(list.error);\n const hasError = list.error !== null && list.error !== undefined;\n // D5 page clamp: a 404 past page 1 means the page is gone (fewer rows now).\n const clamping = isNotFoundError(list.error) && view.page > 1;\n React.useEffect(() => {\n if (!clamping) return;\n const known = lastData !== undefined ? pageCountFor(lastData.count, view.pageSize) : 1;\n const target = view.page > known ? known : view.page - 1;\n setView({ page: Math.max(1, target) }, { push: false });\n }, [clamping, lastData, view.page, view.pageSize, setView]);\n\n const blocking = status === 401 || status === 403;\n const shownData = list.data ?? (hasError && !blocking && !clamping ? lastData : undefined);\n const stale = list.data === undefined && shownData !== undefined;\n\n // connection\n const online = useOnlineStatus();\n const paused = list.fetchStatus === \"paused\";\n const wasOnline = React.useRef(online);\n const refetch = list.refetch;\n React.useEffect(() => {\n // Back online: reload what failed (TanStack resumes paused queries itself).\n if (online && !wasOnline.current && hasError) void refetch();\n wasOnline.current = online;\n }, [online, hasError, refetch]);\n\n const transitioning = list.isFetching && list.isPlaceholderData === true;\n const slow = useDelayedFlag(list.isFetching);\n\n // preferences, per user\n const [storedDensity, setStoredDensity] = useStoredPreference(\n densityKey(userId),\n defaultDensity,\n parseDensity,\n asString,\n );\n const density = densityProp ?? storedDensity;\n const changeDensity = React.useCallback(\n (next: ResourceTableDensity) => {\n if (densityProp === undefined) setStoredDensity(next);\n onDensityChange?.(next);\n },\n [densityProp, setStoredDensity, onDensityChange],\n );\n const [hiddenColumns, setHiddenColumns] = useStoredPreference<readonly string[]>(\n hiddenColumnsKey(namespace, userId),\n NO_COLUMNS,\n parseColumnList,\n serializeColumnList,\n );\n\n // permissions: explicit props win over the schema's access rules\n const rowLabel = React.useCallback(\n (row: T) => (getRowLabel ?? displayLabel)(asRecord(row)),\n [getRowLabel],\n );\n const updateRule = schema?.operations.update?.access;\n const removeRule = schema?.operations.remove?.access;\n const createRule = schema?.operations.create?.access;\n // The item path is documented but has no DELETE: nobody can delete.\n const deleteMissing =\n schema !== undefined &&\n schema.operations.detail !== undefined &&\n schema.operations.remove === undefined;\n const allowEdit = React.useCallback(\n (row: T): boolean => {\n if (typeof canEdit === \"function\") return canEdit(row);\n if (canEdit !== undefined) return canEdit;\n return evaluateAccess(updateRule, identity, row) !== false;\n },\n [canEdit, updateRule, identity],\n );\n const allowDelete = React.useCallback(\n (row: T): boolean => {\n if (typeof canDelete === \"function\") return canDelete(row);\n if (canDelete !== undefined) return canDelete;\n return !deleteMissing && evaluateAccess(removeRule, identity, row) !== false;\n },\n [canDelete, deleteMissing, removeRule, identity],\n );\n const createAllowed =\n onCreate !== undefined &&\n (canCreate ??\n (schema?.operations.create !== undefined && evaluateAccess(createRule, identity) !== false));\n const createText = createLabel ?? `New ${one}`;\n\n // row delete\n const [deleteTarget, setDeleteTarget] = React.useState<DeleteTarget<T> | null>(null);\n const requestDelete = React.useCallback((row: T, trigger: HTMLButtonElement) => {\n setDeleteTarget({ row, trigger });\n }, []);\n const scrollRef = React.useRef<HTMLDivElement>(null);\n const cardListRef = React.useRef<HTMLUListElement>(null);\n const rootRef = React.useRef<HTMLDivElement>(null);\n // Where focus lands when the control that had it is gone (a deleted row, the\n // bulk toolbar once its action ran): the table's scroll region, or the card\n // list below the card breakpoint. Both take focus by script.\n const fallbackFocus = React.useCallback(\n (): HTMLElement | null => scrollRef.current ?? cardListRef.current ?? rootRef.current,\n [],\n );\n\n // columns\n const hasBulkSelect = bulkActions !== undefined && bulkActions.length > 0;\n const hasActions = rowActions !== undefined || onEdit !== undefined || enableDelete === true;\n const actionButtons = DENSITY_CLASSES[density].action;\n\n const columnDefs = React.useMemo<Array<ColumnDef<T>>>(() => {\n if (schema === undefined) return [];\n let defs = deriveColumns<T>({ fields: schema.fields, columns, getRowLabel, showAuditFields });\n if (extraColumns !== undefined) defs = [...defs, ...extraColumns];\n if (columnsOverride !== undefined) defs = columnsOverride(defs);\n const leading: Array<ColumnDef<T>> = hasBulkSelect\n ? [selectionColumn<T>({ rowLabel, resourceLabel: plural })]\n : [];\n const trailing: Array<ColumnDef<T>> = hasActions\n ? [\n actionsColumn<T>({\n rowActions,\n onEdit,\n canEdit: allowEdit,\n onDelete: enableDelete === true ? requestDelete : undefined,\n canDelete: allowDelete,\n buttonClassName: actionButtons,\n }),\n ]\n : [];\n return [...leading, ...defs, ...trailing];\n }, [\n schema,\n columns,\n getRowLabel,\n showAuditFields,\n extraColumns,\n columnsOverride,\n hasBulkSelect,\n hasActions,\n rowLabel,\n plural,\n rowActions,\n onEdit,\n allowEdit,\n enableDelete,\n requestDelete,\n allowDelete,\n actionButtons,\n ]);\n\n const columnLabel = React.useCallback(\n (id: string): string => {\n const def = columnDefs.find((candidate) => candidate.id === id);\n if (typeof def?.header === \"string\") return def.header;\n return schema?.fields.find((field) => field.name === id)?.label ?? humanize(id);\n },\n [columnDefs, schema],\n );\n\n const columnVisibility = React.useMemo<VisibilityState>(\n () => Object.fromEntries(hiddenColumns.map((id) => [id, false])),\n [hiddenColumns],\n );\n\n const rows = React.useMemo<T[]>(() => shownData?.results ?? [], [shownData]);\n const count = shownData?.count;\n const pageCount = pageCountFor(count, view.pageSize);\n\n const [rowSelection, setRowSelection] = React.useState<RowSelectionState>({});\n const [sortTarget, setSortTarget] = React.useState<string | null>(null);\n\n const handleSortingChange = React.useCallback(\n (updater: Updater<SortingState>) => {\n const current = orderingToSorting(viewRef.current.ordering);\n const next = typeof updater === \"function\" ? updater(current) : updater;\n const first = next[0];\n setAnnouncement(\n first === undefined\n ? \"Sorting cleared.\"\n : `Sorted by ${columnLabel(first.id)}, ${first.desc ? \"descending\" : \"ascending\"}.`,\n );\n setView({ ordering: sortingToOrdering(next) ?? \"\", page: 1 }, { push: true });\n },\n [columnLabel, setView],\n );\n\n const table = useReactTable<T>({\n data: rows,\n columns: columnDefs,\n state: { sorting, rowSelection, columnVisibility },\n manualSorting: true,\n manualPagination: true,\n manualFiltering: true,\n pageCount,\n enableRowSelection: hasBulkSelect,\n onSortingChange: handleSortingChange,\n onRowSelectionChange: setRowSelection,\n // D5: selection is keyed by String(row.id) and persists across pages —\n // rows always carry `id`, even while its column is hidden.\n getRowId: (row) => String(asRecord(row).id),\n getCoreRowModel: getCoreRowModel(),\n });\n\n const selectedIds = React.useMemo(\n () => Object.keys(rowSelection).filter((id) => rowSelection[id]),\n [rowSelection],\n );\n const selectedRef = React.useRef(selectedIds);\n selectedRef.current = selectedIds;\n\n // Say what changed once the new rows are in.\n React.useEffect(() => {\n if (intent.current === null || list.isFetching || list.data === undefined) return;\n const kind = intent.current;\n intent.current = null;\n const total = list.data.count;\n if (kind === \"page\") {\n setAnnouncement(\n `Showing page ${view.page.toLocaleString()} of ${pageCountFor(total, view.pageSize).toLocaleString()}.`,\n );\n } else {\n setAnnouncement(\n total === 0\n ? `No ${plural} match.`\n : `${total.toLocaleString()} ${total === 1 ? one : plural} match.`,\n );\n }\n }, [list.isFetching, list.data, view.page, view.pageSize, plural, one]);\n\n const firstSelection = React.useRef(true);\n // A finished bulk action says what it did; its deselection needs no second word.\n const quietSelection = React.useRef(false);\n React.useEffect(() => {\n if (firstSelection.current || quietSelection.current) {\n firstSelection.current = false;\n quietSelection.current = false;\n return;\n }\n setAnnouncement(\n selectedIds.length === 0 ? \"Selection cleared.\" : `${selectedIds.length} selected.`,\n );\n }, [selectedIds.length]);\n\n // bulk actions\n const [runningIndex, setRunningIndex] = React.useState<number | null>(null);\n const [outcome, setOutcome] = React.useState<BulkOutcome | null>(null);\n const [failures, setFailures] = React.useState<Record<string, string>>({});\n const [confirmTarget, setConfirmTarget] = React.useState<ConfirmTarget | null>(null);\n const [confirmError, setConfirmError] = React.useState<unknown>(null);\n\n const runBulk = React.useCallback(\n async (index: number, confirmed: boolean): Promise<void> => {\n const action = bulkActions?.[index];\n if (action === undefined) return;\n const ids = [...selectedRef.current];\n const actionLabel = textOf(action.label) ?? \"The action\";\n setOutcome(null);\n setFailures({});\n setConfirmError(null);\n let returned: unknown;\n try {\n returned = action.onClick(ids);\n } catch (error) {\n if (confirmed) setConfirmError(error);\n else setOutcome({ kind: \"failed\", actionLabel, error, count: ids.length });\n return;\n }\n if (!isPromiseLike(returned)) {\n // A plain `void` action: the selection stays, as it always has.\n setConfirmTarget(null);\n return;\n }\n setRunningIndex(index);\n try {\n const result = (await returned) as BulkResult | undefined;\n const failed = result?.failed ?? [];\n setConfirmTarget(null);\n if (failed.length > 0) {\n setFailures(Object.fromEntries(failed.map((entry) => [entry.id, entry.reason])));\n setRowSelection(Object.fromEntries(failed.map((entry) => [entry.id, true])));\n setOutcome({ kind: \"partial\", actionLabel, failed: failed.length, total: ids.length });\n } else {\n quietSelection.current = true;\n setRowSelection({});\n setAnnouncement(\n `${actionLabel}: done for ${ids.length} ${ids.length === 1 ? one : plural}.`,\n );\n }\n void queryClient.invalidateQueries({ queryKey: karniKeys.resource(resource) });\n } catch (error) {\n if (confirmed) setConfirmError(error);\n else setOutcome({ kind: \"failed\", actionLabel, error, count: ids.length });\n } finally {\n setRunningIndex(null);\n }\n },\n [bulkActions, queryClient, resource, one, plural],\n );\n\n const onBulkAction = React.useCallback(\n (index: number, trigger: HTMLButtonElement | null) => {\n const action = bulkActions?.[index];\n if (action === undefined) return;\n const confirm = action.confirm ?? action.destructive === true;\n if (confirm === false) {\n void runBulk(index, false);\n return;\n }\n setConfirmError(null);\n setConfirmTarget({ index, trigger });\n },\n [bulkActions, runBulk],\n );\n\n const clearSelection = React.useCallback(() => {\n setRowSelection({});\n setFailures({});\n setOutcome(null);\n }, []);\n\n // layout from the container's own width\n const width = useContainerWidth(rootRef);\n const layout =\n cardBreakpoint > 0 && width !== undefined && width < cardBreakpoint ? \"cards\" : \"table\";\n\n const changePage = React.useCallback(\n (page: number) => {\n intent.current = \"page\";\n setView({ page }, { push: true });\n },\n [setView],\n );\n const changePageSize = React.useCallback(\n (size: number) => {\n intent.current = \"page\";\n setView({ pageSize: size, page: 1 }, { push: true });\n },\n [setView],\n );\n const onSort = React.useCallback(\n (header: Header<T, unknown>, event: React.MouseEvent) => {\n if (transitioning) return;\n setSortTarget(header.column.id);\n header.column.getToggleSortingHandler()?.(event);\n },\n [transitioning],\n );\n\n const retryList = React.useCallback(() => {\n void refetch();\n }, [refetch]);\n const retrySchema = React.useCallback(() => {\n void queryClient.invalidateQueries({ queryKey: karniKeys.schema() });\n }, [queryClient]);\n\n const activeFilters = React.useMemo<ResourceTableActiveFilter[]>(\n () =>\n Object.entries(view.filters).flatMap(([name, value]) => {\n const field = filterFields.find((candidate) => candidate.name === name);\n return field === undefined\n ? []\n : [{ field: name, label: field.label, value: filterWords(field, value) }];\n }),\n [view.filters, filterFields],\n );\n\n // render\n const loadingNode = (\n <Slots.Loading\n columnCount={\n schema === undefined\n ? SKELETON_COLUMNS + (hasBulkSelect ? 1 : 0) + (hasActions ? 1 : 0)\n : table.getVisibleLeafColumns().length\n }\n rowCount={view.pageSize}\n density={density}\n toolbar={schema === undefined}\n layout={layout}\n selectable={hasBulkSelect}\n actions={hasActions}\n />\n );\n\n let body: React.ReactNode;\n if (schemaResult.error !== null && schemaResult.error !== undefined) {\n body = (\n <Slots.Error\n error={schemaResult.error}\n context={{ action: \"load\", resource: plural }}\n onRetry={retrySchema}\n />\n );\n } else if (blocking) {\n body =\n status === 403 ? (\n <Slots.Forbidden resourceLabel={plural} error={list.error} />\n ) : (\n <Slots.Error error={list.error} context={{ action: \"view\", resource: plural }} />\n );\n } else if (shownData === undefined && (paused || (!online && hasError))) {\n body = <Slots.Offline resourceLabel={plural} hasRows={false} onRetry={retryList} />;\n } else if (schema === undefined || clamping || shownData === undefined) {\n body =\n hasError && !clamping && schema !== undefined ? (\n <Slots.Error\n error={list.error}\n context={{ action: \"load\", resource: plural }}\n onRetry={retryList}\n retrying={list.isFetching}\n />\n ) : (\n loadingNode\n );\n } else if (rows.length === 0 && !stale) {\n body =\n empty ??\n (activeSearch !== \"\" || activeFilters.length > 0 ? (\n <Slots.NoResults\n resourceLabel={plural}\n search={activeSearch}\n filters={activeFilters}\n onClearFilters={clearFilters}\n />\n ) : (\n <Slots.NoRecords\n resourceLabel={plural}\n itemLabel={one}\n onCreate={createAllowed ? onCreate : undefined}\n createLabel={createText}\n />\n ));\n } else {\n const dimmed = stale || (slow && transitioning);\n body = (\n <>\n {layout === \"cards\" ? (\n <CardList\n table={table}\n caption={tableName}\n resourceLabel={plural}\n density={density}\n Card={Slots.RowCard}\n rowLabel={rowLabel}\n useRowLabelAsTitle={getRowLabel !== undefined}\n onRowClick={onRowClick}\n failures={failures}\n columnLabel={columnLabel}\n ordering={view.ordering}\n onOrderingChange={(ordering) => handleSortingChange(orderingToSorting(ordering))}\n busy={transitioning}\n dimmed={dimmed}\n listRef={cardListRef}\n />\n ) : (\n <TableView\n table={table}\n caption={tableName}\n density={density}\n busy={transitioning}\n sortTarget={sortTarget}\n slow={slow}\n onSort={onSort}\n onRowClick={onRowClick}\n failures={failures}\n firstRowIndex={(view.page - 1) * view.pageSize + 1}\n totalCount={count}\n dimmed={dimmed}\n scrollRef={scrollRef}\n keyboardNavigation={keyboardNavigation}\n />\n )}\n {count !== undefined && count > 0 && (\n <Slots.Pagination\n page={view.page}\n pageCount={pageCount}\n totalCount={count}\n hasPrevious={\n transitioning\n ? view.page > 1\n : shownData.previous !== null && shownData.previous !== undefined\n }\n hasNext={\n transitioning\n ? view.page < pageCount\n : shownData.next !== null && shownData.next !== undefined\n }\n onPageChange={changePage}\n pageSize={view.pageSize}\n pageSizeOptions={defaults.pageSizes}\n onPageSizeChange={changePageSize}\n busy={transitioning}\n />\n )}\n </>\n );\n }\n\n const exportList: readonly ExportFormat[] =\n exportFormats === undefined ? [\"csv\", \"xlsx\"] : exportFormats === false ? [] : exportFormats;\n const exportEnabled = exportList.length > 0 && schema?.operations.export !== undefined;\n const dataColumns = table\n .getAllLeafColumns()\n .filter((column) => !isStructural(column.id))\n .map((column) => ({\n id: column.id,\n label: columnLabel(column.id),\n visible: column.getIsVisible(),\n }));\n\n const showFilterRow =\n schema !== undefined &&\n !blocking &&\n (searchEnabled ||\n filterFields.length > 0 ||\n toolbar !== undefined ||\n exportEnabled ||\n viewOptions ||\n createAllowed);\n\n const liveText = slow ? `Loading ${plural}…` : announcement;\n\n return (\n <div ref={rootRef} className={cn(\"flex w-full min-w-0 flex-col gap-3\", className)}>\n <div role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {liveText}\n </div>\n {showFilterRow && (\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <FilterBar\n searchEnabled={searchEnabled}\n searchValue={searchInput}\n onSearchChange={setSearchInput}\n filterFields={filterFields}\n values={view.filters}\n onFilterChange={handleFilterChange}\n className=\"min-w-64 flex-1\"\n />\n <div className=\"flex shrink-0 flex-wrap items-center gap-2\">\n {viewOptions && (\n <ViewOptionsMenu\n density={density}\n onDensityChange={changeDensity}\n columns={dataColumns}\n onColumnVisibilityChange={(id, visible) =>\n setHiddenColumns(\n visible\n ? hiddenColumns.filter((hidden) => hidden !== id)\n : [...hiddenColumns.filter((hidden) => hidden !== id), id],\n )\n }\n />\n )}\n {exportEnabled && (\n <ExportButtons resource={resource} params={listParams} formats={exportList} />\n )}\n {toolbar}\n {createAllowed && (\n <Button size=\"sm\" onClick={onCreate}>\n <PlusIcon className=\"h-4 w-4\" />\n {createText}\n </Button>\n )}\n </div>\n </div>\n )}\n {!online && shownData !== undefined && (\n <Slots.Offline resourceLabel={plural} hasRows onRetry={retryList} />\n )}\n {hasError && !blocking && !clamping && shownData !== undefined && online && (\n <Slots.RefetchError\n error={list.error}\n context={{ action: \"load\", resource: plural }}\n onRetry={retryList}\n retrying={list.isFetching}\n />\n )}\n {hasBulkSelect && selectedIds.length > 0 && (\n <Slots.BulkActions\n selectedIds={selectedIds}\n bulkActions={bulkActions}\n onClear={clearSelection}\n onAction={onBulkAction}\n runningIndex={runningIndex}\n outcome={outcome}\n pageRowCount={rows.length}\n allPageRowsSelected={rows.length > 0 && table.getIsAllPageRowsSelected()}\n totalCount={count}\n resourceLabel={plural}\n />\n )}\n {body}\n {footer}\n {hasBulkSelect && (\n <BulkConfirm\n target={confirmTarget}\n actions={bulkActions}\n count={selectedIds.length}\n one={one}\n plural={plural}\n pending={confirmTarget !== null && runningIndex === confirmTarget.index}\n error={confirmError}\n onConfirm={(index) => void runBulk(index, true)}\n onCancel={() => {\n setConfirmTarget(null);\n setConfirmError(null);\n }}\n fallbackFocus={fallbackFocus}\n />\n )}\n {enableDelete === true && (\n <RowDeleteDialog\n resource={resource}\n target={deleteTarget}\n rowLabel={rowLabel}\n onClose={() => setDeleteTarget(null)}\n onDeleted={(label) => {\n setAnnouncement(`Deleted “${label}”.`);\n setDeleteTarget(null);\n }}\n fallbackFocus={fallbackFocus}\n />\n )}\n </div>\n );\n}\n\n/** The confirm question for a bulk action, worded from its label and the count. */\nfunction BulkConfirm(props: {\n target: ConfirmTarget | null;\n actions: ReadonlyArray<BulkAction>;\n count: number;\n one: string;\n plural: string;\n pending: boolean;\n error: unknown;\n onConfirm: (index: number) => void;\n onCancel: () => void;\n fallbackFocus: () => HTMLElement | null;\n}): React.ReactElement {\n const { target, actions, one, plural, pending, error, onConfirm, onCancel } = props;\n // The dialog closes after `target` is cleared (and the selection with it):\n // keep the wording and the focus target of the last question.\n const last = React.useRef({ target, count: props.count });\n if (target !== null) last.current = { target, count: props.count };\n const shown = last.current.target;\n const count = last.current.count;\n const action = shown === null ? undefined : actions[shown.index];\n const label = action === undefined ? undefined : textOf(action.label);\n const custom = typeof action?.confirm === \"object\" ? action.confirm : undefined;\n const what = `${count} ${count === 1 ? one : plural}`;\n return (\n <ConfirmDialog\n open={target !== null}\n title={custom?.title ?? (label !== undefined ? `${label} ${what}?` : `Apply to ${what}?`)}\n description={\n custom?.description ??\n (action?.destructive === true\n ? `This applies to all ${what} you selected, and can't be undone.`\n : `This applies to all ${what} you selected.`)\n }\n confirmLabel={custom?.confirmLabel ?? (label !== undefined ? `${label} ${what}` : \"Continue\")}\n pendingLabel={action?.pendingLabel}\n destructive={action?.destructive === true}\n pending={pending}\n error={error === null ? undefined : error}\n errorContext={{ action: (label ?? \"change\").toLowerCase(), resource: what }}\n onConfirm={() => {\n if (target !== null) onConfirm(target.index);\n }}\n onCancel={onCancel}\n returnFocus={() => {\n const trigger = last.current.target?.trigger;\n return trigger !== null && trigger !== undefined && trigger.isConnected\n ? trigger\n : props.fallbackFocus();\n }}\n />\n );\n}\n","/**\n * Single-item hook for one resource (contract \"Hooks\" + D11).\n *\n * `useResourceItem<Event>(\"events\", id, { expand: [\"venue\"] })` fetches\n * `GET /<resource>/<id>/?expand=venue` and caches it under\n * `karniKeys.detail(resource, id, params)`. Params participate in the key,\n * so an expanded detail view and an unexpanded edit form never clobber each\n * other's cache entry, while `karniKeys.resource(resource)` invalidation\n * still reaches both.\n *\n * Escape hatch: `options` forwards every TanStack Query option except\n * `queryKey`/`queryFn` (e.g. `enabled` for \"fetch only when an id exists\").\n */\nimport { useQuery, type UseQueryOptions, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useKarniClient } from \"../schema/provider\";\nimport { karniKeys } from \"./keys\";\nimport { buildItemQuery, detailPath } from \"./params\";\nimport type { ResourceItemParams } from \"./types\";\n\n/** Fetches one row of a resource (`GET /<resource>/<id>/`), optionally expanded. */\nexport function useResourceItem<T = Record<string, unknown>>(\n resource: string,\n id: string | number,\n params?: ResourceItemParams,\n options?: Omit<UseQueryOptions<T>, \"queryKey\" | \"queryFn\">,\n): UseQueryResult<T> {\n const client = useKarniClient();\n return useQuery<T>({\n ...options,\n queryKey: karniKeys.detail(resource, id, params),\n queryFn: ({ signal }) =>\n client.request<T>(detailPath(resource, id), { query: buildItemQuery(params), signal }),\n });\n}\n","/**\n * useUnsavedChangesGuard: warn before leaving a form with unsaved changes.\n *\n * Router-agnostic: the hook owns the \"is anything unsaved?\" state and the\n * browser's own leave warning (`beforeunload`, for reloads, closed tabs and\n * links out of the app). In-app navigation belongs to the router, so the app\n * hands the guard to its router's blocker:\n *\n * const guard = useUnsavedChangesGuard();\n * useBlocker({ shouldBlockFn: guard.shouldBlock, enableBeforeUnload: false }); // TanStack Router\n * <ResourceForm resource=\"events\" onDirtyChange={guard.setDirty} onSuccess={...} />\n *\n * `isDirty()` and `shouldBlock()` read the latest value synchronously, so a\n * navigation made inside `onSuccess` (after ResourceForm has reported the form\n * clean) is never blocked by a state update that has not rendered yet.\n *\n * Escape hatches: `confirm` replaces `window.confirm` (your own dialog),\n * `beforeUnload: false` leaves reloads alone, and `dirty` makes the hook\n * controlled by your own form state.\n */\nimport * as React from \"react\";\n\n/** What the leave warning says. Browsers show their own text for reloads and closed tabs. */\nexport const UNSAVED_CHANGES_MESSAGE = \"You have unsaved changes. Leave without saving them?\";\n\nexport interface UseUnsavedChangesGuardOptions {\n /** Controlled mode: whether something is unsaved. Omit it and call `setDirty` instead. */\n dirty?: boolean;\n /** Turns the guard off without unmounting it (an opt-out). Default true. */\n enabled?: boolean;\n /** Warn on reload, tab close and links out of the app (`beforeunload`). Default true. */\n beforeUnload?: boolean;\n /** The question `shouldBlock` asks. Default UNSAVED_CHANGES_MESSAGE. */\n message?: string;\n /** Asks the user whether to leave and returns true to leave. Default `window.confirm`. */\n confirm?: (message: string) => boolean;\n}\n\nexport interface UnsavedChangesGuard {\n /** Whether something is unsaved (re-renders when it changes). */\n dirty: boolean;\n /** Reports the form's state. Pass it as ResourceForm's `onDirtyChange`. */\n setDirty: (dirty: boolean) => void;\n /** The latest state, read synchronously (for a router blocker's callback). */\n isDirty: () => boolean;\n /**\n * For a router's blocker: true when there are unsaved changes and the user\n * chose to stay, false (let the navigation happen) otherwise.\n */\n shouldBlock: () => boolean;\n /** The question asked before leaving. */\n message: string;\n}\n\n/** Tracks unsaved changes, warns on reload or close, and gives a router blocker what it needs. */\nexport function useUnsavedChangesGuard(\n options: UseUnsavedChangesGuardOptions = {},\n): UnsavedChangesGuard {\n const {\n dirty: controlled,\n enabled = true,\n beforeUnload = true,\n message = UNSAVED_CHANGES_MESSAGE,\n confirm,\n } = options;\n const [reported, setReported] = React.useState(false);\n const dirty = enabled && (controlled ?? reported);\n\n const dirtyRef = React.useRef(dirty);\n dirtyRef.current = dirty;\n const confirmRef = React.useRef(confirm);\n confirmRef.current = confirm;\n\n const setDirty = React.useCallback(\n (next: boolean) => {\n dirtyRef.current = enabled && next;\n setReported(next);\n },\n [enabled],\n );\n\n React.useEffect(() => {\n if (!dirty || !beforeUnload) return undefined;\n const warn = (event: BeforeUnloadEvent): void => {\n // Re-read: a successful save may have cleared it after this render.\n if (!dirtyRef.current) return;\n event.preventDefault();\n // Older browsers show the prompt only when returnValue is set.\n event.returnValue = \"\";\n };\n window.addEventListener(\"beforeunload\", warn);\n return () => window.removeEventListener(\"beforeunload\", warn);\n }, [dirty, beforeUnload]);\n\n const isDirty = React.useCallback(() => dirtyRef.current, []);\n const shouldBlock = React.useCallback((): boolean => {\n if (!dirtyRef.current) return false;\n const ask = confirmRef.current ?? ((text: string) => window.confirm(text));\n return !ask(message);\n }, [message]);\n\n return { dirty, setDirty, isDirty, shouldBlock, message };\n}\n","/**\n * zodFor: runtime Zod schema generation from a ResourceSchema (contract\n * \"Schema client\" + D3).\n *\n * Rules:\n * - mode \"create\": the create request's required fields are required, the\n * rest are `.optional()`. Mode \"update\": ALL fields are optional, with\n * `.nullable()` nested INSIDE `.optional()` so `undefined` means \"not\n * touched\" and `null` means \"clear this nullable field\".\n * - readOnly fields are excluded, writeOnly fields are included.\n * - nullable / maxLength / min / max and the email / url / uuid string\n * formats map onto the obvious Zod validators.\n * - enum → z.enum when every member is a string, otherwise a union of\n * z.literal. \"\" (BlankEnum) and null (NullEnum) are never members: the\n * parser already stripped them, and nullability travels on the field.\n * - relation values take their schema from the property's own emitted\n * type/format (integer pk vs uuid pk), arrays of it when `many`.\n * - file → File-or-string. When `File` does not exist (SSR) it degrades to\n * z.string() so imports never crash.\n * - json → z.unknown(), number/integer coerce (form inputs produce strings).\n * - datetime accepts datetime-local input (\"YYYY-MM-DDTHH:mm[:ss]\") and\n * transforms it to full ISO-8601 with offset on submit (D3).\n */\nimport { z } from \"zod\";\nimport type { ZodObject, ZodRawShape, ZodTypeAny } from \"zod\";\nimport type { FieldDef, ResourceSchema } from \"./types\";\n\nconst REQUIRED_MESSAGE = \"This field is required.\";\n\n/** datetime-local output: no timezone designator at the end. */\nconst LOCAL_DATETIME = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d{1,6})?)?$/;\n\nfunction toIsoWithOffset(value: string): string {\n if (!LOCAL_DATETIME.test(value)) return value; // already zoned (or server-side format)\n const date = new Date(value); // datetime-local strings parse as local time\n if (Number.isNaN(date.getTime())) return value;\n return date.toISOString();\n}\n\nfunction enumSchema(values: ReadonlyArray<string | number>): ZodTypeAny {\n if (values.length === 0) return z.never();\n if (values.every((value): value is string => typeof value === \"string\")) {\n return z.enum(values as [string, ...string[]]);\n }\n const literals = values.map((value) => z.literal(value));\n if (literals.length === 1) return literals[0];\n return z.union(literals as unknown as [ZodTypeAny, ZodTypeAny, ...ZodTypeAny[]]);\n}\n\nfunction stringSchema(field: FieldDef, requireNonEmpty: boolean): ZodTypeAny {\n let schema = z.string();\n // DRF's own wording, so a value reads the same whether the browser or the\n // server rejects it.\n if (field.format === \"email\") schema = schema.email(\"Enter a valid email address.\");\n else if (field.format === \"uri\" || field.format === \"url\")\n schema = schema.url(\"Enter a valid URL.\");\n else if (field.format === \"uuid\") schema = schema.uuid(\"Must be a valid UUID.\");\n if (field.maxLength !== undefined) {\n schema = schema.max(\n field.maxLength,\n `Ensure this field has no more than ${field.maxLength} characters.`,\n );\n }\n if (requireNonEmpty) schema = schema.min(1, REQUIRED_MESSAGE);\n return schema;\n}\n\nfunction numberSchema(field: FieldDef, integer: boolean): ZodTypeAny {\n let schema = z.coerce.number();\n if (integer) schema = schema.int();\n if (field.min !== undefined) schema = schema.min(field.min);\n if (field.max !== undefined) schema = schema.max(field.max);\n return schema;\n}\n\nfunction relationValueSchema(field: FieldDef, coerce: boolean): ZodTypeAny {\n switch (field.relationValueType) {\n case \"uuid\":\n return z.string({ required_error: REQUIRED_MESSAGE }).uuid();\n case \"integer\":\n return coerce\n ? z.coerce.number().int()\n : z.number({ required_error: REQUIRED_MESSAGE }).int();\n default:\n return z.string({ required_error: REQUIRED_MESSAGE }).min(1, REQUIRED_MESSAGE);\n }\n}\n\n/**\n * A single relation input left empty arrives as \"\" (an untouched select) or\n * null (a cleared one). A nullable relation then carries null (DRF's\n * allow_null). A required non-nullable one fails with REQUIRED_MESSAGE\n * instead of \"Invalid uuid\" / \"Expected string, received null\". An optional\n * non-nullable one is omitted. Integer ids typed as strings are coerced.\n */\nfunction singleRelationSchema(field: FieldDef, requireNonEmpty: boolean): ZodTypeAny {\n const value = relationValueSchema(field, false);\n let target: ZodTypeAny = field.nullable ? value.nullable() : value;\n if (!requireNonEmpty) target = target.optional();\n return z.preprocess((raw) => {\n if (raw === \"\" || raw === null || raw === undefined) return field.nullable ? null : undefined;\n if (field.relationValueType === \"integer\" && typeof raw === \"string\" && raw.trim() !== \"\") {\n const parsed = Number(raw);\n return Number.isNaN(parsed) ? raw : parsed;\n }\n return raw;\n }, target);\n}\n\nfunction fileSchema(): ZodTypeAny {\n if (typeof File === \"undefined\") return z.string();\n return z.union([z.instanceof(File), z.string()]);\n}\n\nfunction baseSchemaFor(field: FieldDef, requireNonEmpty: boolean): ZodTypeAny {\n switch (field.kind) {\n case \"string\":\n case \"text\":\n return stringSchema(field, requireNonEmpty);\n case \"integer\":\n return numberSchema(field, true);\n case \"number\":\n return numberSchema(field, false);\n case \"boolean\":\n return z.boolean();\n case \"date\": {\n const schema = z.string();\n return requireNonEmpty ? schema.min(1, REQUIRED_MESSAGE) : schema;\n }\n case \"datetime\": {\n const schema = requireNonEmpty ? z.string().min(1, REQUIRED_MESSAGE) : z.string();\n return schema.transform(toIsoWithOffset);\n }\n case \"enum\":\n return enumSchema(field.enumValues ?? []);\n case \"relation\": {\n if (field.relation?.many === true) return z.array(relationValueSchema(field, true));\n return singleRelationSchema(field, requireNonEmpty);\n }\n case \"file\":\n return fileSchema();\n case \"json\":\n return z.unknown();\n case \"array\":\n return z.array(z.unknown());\n case \"unknown\":\n return z.unknown();\n }\n}\n\n/** Builds a Zod validator for a resource's create or update payload from its schema. */\nexport function zodFor(schema: ResourceSchema, mode: \"create\" | \"update\"): ZodObject<ZodRawShape> {\n const shape: ZodRawShape = {};\n\n for (const field of schema.fields) {\n if (field.readOnly) continue; // writeOnly stays in (D3)\n\n // A required string provided as \"\" must fail in BOTH modes: DRF rejects\n // blank values on required CharFields; in update mode the field may be\n // omitted entirely instead.\n const requireNonEmpty = field.required;\n let fieldSchema = baseSchemaFor(field, requireNonEmpty);\n\n if (field.nullable) fieldSchema = fieldSchema.nullable();\n // D3: in update mode .nullable() sits INSIDE .optional() — undefined\n // means untouched, null clears.\n if (mode === \"update\" || !field.required) fieldSchema = fieldSchema.optional();\n\n shape[field.name] = fieldSchema;\n }\n\n return z.object(shape);\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\nimport { SpinnerIcon } from \"../primitives/icons\";\n\nregisterComponentRole(\"file-upload\", \"FileUpload\");\n\n/** Why a file was refused by <FileUpload> (surfaced through `onReject`). */\nexport type FileUploadRejectReason = \"accept\" | \"size\";\n\n/** What the `Dropzone` slot receives: the props of the button it replaces, plus its state. */\nexport interface FileUploadDropzoneProps extends Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n \"children\"\n> {\n /** Attach to the button: focus returns to it after a file is removed. */\n buttonRef: React.Ref<HTMLButtonElement>;\n /** A file is being dragged over the dropzone. */\n dragging: boolean;\n multiple: boolean;\n /** The `uploading` prop. */\n uploading: boolean;\n /** The `children` prop (custom content), or undefined for the default text. */\n children?: React.ReactNode;\n}\n\n/** What the `FileRow` slot receives: one current file. Render an <li>. */\nexport interface FileUploadFileRowProps {\n /** A pending `File`, or the URL string of a file already uploaded. */\n file: File | string;\n /** The file name (a URL's last path segment). */\n name: string;\n /** A pending file's size (\"12 KB\"), undefined for a URL. */\n size?: string;\n /** Removes the file. Undefined when it cannot be removed (clearable=false, disabled, uploading). */\n onRemove?: () => void;\n}\n\n/** The parts of the picker a project can replace (`slots={{ FileRow: Thumbnail }}`). */\nexport interface FileUploadSlots {\n /** The drop target: a button that opens the file picker. */\n Dropzone: React.ComponentType<FileUploadDropzoneProps>;\n /** One row of the current-files list. */\n FileRow: React.ComponentType<FileUploadFileRowProps>;\n}\n\nexport interface FileUploadProps {\n /**\n * Current value. A `string` is an existing uploaded file (the display URL a\n * karni backend returns), and a `File` is a pending upload. Arrays are for\n * `multiple` mode and may mix both.\n */\n value?: File | string | ReadonlyArray<File | string> | null;\n /**\n * Emits the newly chosen `File` (or `File[]` when `multiple`), and `null`\n * when the value is cleared. Existing URL strings are display-only: they\n * can be removed (emitting `null` / the remaining files) but never re-emitted.\n */\n onChange?: (value: File | File[] | null) => void;\n /** Same grammar as the native `accept` attribute (\".png,image/*,application/pdf\"). */\n accept?: string;\n multiple?: boolean;\n disabled?: boolean;\n /** Maximum size per file, in bytes. Larger files are rejected via `onReject`. */\n maxSize?: number;\n /** Called once per refused file with the reason (\"accept\" | \"size\"). */\n onReject?: (file: File, reason: FileUploadRejectReason) => void;\n /**\n * The sentence shown (and announced) for a refused file. Default: \"notes.txt\n * isn't an accepted file type.\" / \"big.png is larger than 1.0 MB.\". Return\n * null to show nothing (when `onReject` reports it elsewhere).\n */\n rejectionMessage?: (\n file: File,\n reason: FileUploadRejectReason,\n limits: { accept?: string; maxSize?: number },\n ) => React.ReactNode;\n /** An error to show under the dropzone (announced). It marks the field invalid. */\n error?: React.ReactNode;\n /** True while the file uploads: the dropzone shows progress and takes no new files. */\n uploading?: boolean;\n id?: string;\n /** Forwarded to the hidden native file input. */\n name?: string;\n className?: string;\n /** Replaces the default dropzone content (escape hatch). */\n children?: React.ReactNode;\n /** Set false to hide the per-file remove affordance. Default true. */\n clearable?: boolean;\n /** Replaces the Dropzone or FileRow (see FileUploadSlots). */\n slots?: Partial<FileUploadSlots>;\n \"aria-label\"?: string;\n /** Ids of elements that label the dropzone (or point a <label htmlFor> at `id`). */\n \"aria-labelledby\"?: string;\n /** Ids of elements that describe the dropzone (help text, a form's error message). */\n \"aria-describedby\"?: string;\n /** Marks the dropzone invalid (a destructive border). `error` sets it too. */\n \"aria-invalid\"?: React.AriaAttributes[\"aria-invalid\"];\n /** Called when focus leaves the dropzone (react-hook-form's onBlur). */\n onBlur?: React.FocusEventHandler<HTMLButtonElement>;\n}\n\nfunction matchesAccept(file: File, accept: string | undefined): boolean {\n if (accept === undefined || accept.trim() === \"\") return true;\n const tokens = accept\n .split(\",\")\n .map((token) => token.trim().toLowerCase())\n .filter((token) => token !== \"\");\n if (tokens.length === 0) return true;\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return tokens.some((token) => {\n if (token.startsWith(\".\")) return name.endsWith(token);\n if (token.endsWith(\"/*\")) return type.startsWith(token.slice(0, -1));\n return type === token;\n });\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction fileBasename(url: string): string {\n const withoutQuery = url.split(/[?#]/, 1)[0] ?? url;\n const segments = withoutQuery.split(\"/\").filter((segment) => segment !== \"\");\n return segments[segments.length - 1] ?? url;\n}\n\nfunction defaultRejectionMessage(\n file: File,\n reason: FileUploadRejectReason,\n limits: { maxSize?: number },\n): React.ReactNode {\n if (reason === \"size\" && limits.maxSize !== undefined) {\n return `${file.name} is larger than ${formatFileSize(limits.maxSize)}.`;\n }\n return `${file.name} isn't an accepted file type.`;\n}\n\nfunction UploadIcon(props: React.SVGAttributes<SVGSVGElement>): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <path d=\"M21 15v3a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3v-3\" />\n <polyline points=\"7 8 12 3 17 8\" />\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" />\n </svg>\n );\n}\n\nfunction XIcon(props: React.SVGAttributes<SVGSVGElement>): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\nfunction DefaultDropzone({\n buttonRef,\n dragging,\n multiple,\n uploading,\n children,\n className,\n ...props\n}: FileUploadDropzoneProps): React.ReactElement {\n let content = children;\n if (uploading) {\n content = (\n <>\n <SpinnerIcon className=\"h-5 w-5 animate-spin\" />\n <span>Uploading…</span>\n </>\n );\n } else if (content === undefined) {\n content = (\n <>\n <UploadIcon className=\"h-5 w-5\" />\n <span>\n {multiple\n ? \"Drag and drop files here, or click to browse\"\n : \"Drag and drop a file here, or click to browse\"}\n </span>\n </>\n );\n }\n return (\n <button\n ref={buttonRef}\n type=\"button\"\n data-dragging={dragging ? \"true\" : undefined}\n className={cn(\n \"flex w-full flex-col items-center justify-center gap-1 rounded-md border border-dashed border-input bg-background px-4 py-6 text-sm text-muted-foreground ring-offset-background transition-colors hover:border-ring hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive data-[dragging=true]:border-ring data-[dragging=true]:bg-accent data-[dragging=true]:text-accent-foreground\",\n // Busy, not unavailable: the progress message stays fully legible.\n uploading && \"disabled:cursor-progress disabled:opacity-100\",\n className,\n )}\n {...props}\n >\n {content}\n </button>\n );\n}\n\nfunction DefaultFileRow({\n file,\n name,\n size,\n onRemove,\n}: FileUploadFileRowProps): React.ReactElement {\n return (\n <li className=\"flex items-center justify-between gap-2 rounded-md border border-border bg-muted-subtle px-3 py-1.5 text-sm\">\n {typeof file === \"string\" ? (\n <a\n href={file}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"truncate font-medium text-primary underline underline-offset-4 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {name}\n </a>\n ) : (\n <span className=\"truncate\">\n {name}\n <span className=\"ml-2 text-xs text-muted-foreground\">{size}</span>\n </span>\n )}\n {onRemove !== undefined ? (\n <button\n type=\"button\"\n aria-label={`Remove ${name}`}\n onClick={onRemove}\n className=\"rounded-sm p-1 text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <XIcon className=\"h-4 w-4\" />\n </button>\n ) : null}\n </li>\n );\n}\n\n/** The default pieces of the picker, for wrapping one. */\nexport const defaultFileUploadSlots: FileUploadSlots = {\n Dropzone: DefaultDropzone,\n FileRow: DefaultFileRow,\n};\n\n/**\n * Drag-and-drop or click-to-browse file picker that shows the current file and the pending ones.\n *\n * Contract \"FileUpload\".\n *\n * Shows an existing uploaded value (URL string) as a link, pending `File`\n * values with name and size, and emits `File` objects. The hooks layer turns\n * them into multipart bodies per amendment D2.\n *\n * Keyboard and screen readers: the dropzone is a button (Enter or Space opens\n * the picker), labelled by its text, `aria-label`, `aria-labelledby` or a\n * <label htmlFor={id}>. A refused file and the `error` prop are announced and\n * linked through aria-describedby. `aria-invalid` (or `error`) marks it\n * invalid. Removing a file returns focus to the dropzone.\n *\n * Escape hatches: `slots` replaces the Dropzone or FileRow, `children`\n * replaces the dropzone's content, `rejectionMessage` rewords refusals.\n */\nexport const FileUpload = React.forwardRef<HTMLButtonElement, FileUploadProps>(\n function FileUpload(props, ref): React.ReactElement {\n const {\n value = null,\n onChange,\n accept,\n multiple = false,\n disabled = false,\n maxSize,\n onReject,\n rejectionMessage = defaultRejectionMessage,\n error,\n uploading = false,\n id,\n name,\n className,\n children,\n clearable = true,\n slots,\n } = props;\n const { Dropzone, FileRow } = { ...defaultFileUploadSlots, ...slots };\n\n const inputRef = React.useRef<HTMLInputElement>(null);\n const dropzoneRef = React.useRef<HTMLButtonElement>(null);\n // The forwarded ref is the dropzone button: what a label, aria-describedby and form focus point at.\n React.useImperativeHandle(ref, () => dropzoneRef.current as HTMLButtonElement, []);\n const messageId = React.useId();\n const [dragging, setDragging] = React.useState(false);\n const [rejections, setRejections] = React.useState<readonly React.ReactNode[]>([]);\n\n const blocked = disabled || uploading;\n const entries: ReadonlyArray<File | string> =\n value == null ? [] : Array.isArray(value) ? value : [value as File | string];\n\n const acceptFiles = (list: ArrayLike<File>): void => {\n if (blocked) return;\n const accepted: File[] = [];\n const refused: React.ReactNode[] = [];\n for (const file of Array.from(list)) {\n let reason: FileUploadRejectReason | null = null;\n if (!matchesAccept(file, accept)) reason = \"accept\";\n else if (maxSize !== undefined && file.size > maxSize) reason = \"size\";\n if (reason === null) {\n accepted.push(file);\n continue;\n }\n onReject?.(file, reason);\n const message = rejectionMessage(file, reason, { accept, maxSize });\n if (message != null && message !== false) refused.push(message);\n }\n setRejections(refused);\n if (accepted.length === 0) return;\n onChange?.(multiple ? accepted : accepted[0]);\n };\n\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>): void => {\n if (event.target.files !== null) acceptFiles(event.target.files);\n // Reset so selecting the same file again re-fires the change event.\n event.target.value = \"\";\n };\n\n const handleDrop = (event: React.DragEvent<HTMLButtonElement>): void => {\n event.preventDefault();\n setDragging(false);\n if (blocked) return;\n acceptFiles(event.dataTransfer.files);\n };\n\n const handleDragOver = (event: React.DragEvent<HTMLButtonElement>): void => {\n event.preventDefault();\n if (!blocked) setDragging(true);\n };\n\n const removeEntry = (index: number): void => {\n if (onChange === undefined) return;\n // The row (and its button) is about to go: keep the keyboard on the field.\n dropzoneRef.current?.focus();\n const remaining = entries.filter((_, i) => i !== index);\n if (remaining.length === 0) {\n onChange(null);\n return;\n }\n // Existing URL strings cannot be re-emitted (onChange carries File values\n // only); the remaining pending files are kept.\n const files = remaining.filter((entry): entry is File => typeof entry !== \"string\");\n if (multiple) {\n onChange(files);\n } else {\n onChange(files[0] ?? null);\n }\n };\n\n const messages: React.ReactNode[] = error != null && error !== false ? [error] : [];\n messages.push(...rejections);\n const describedBy =\n [props[\"aria-describedby\"], messages.length > 0 ? messageId : undefined]\n .filter(Boolean)\n .join(\" \") || undefined;\n const invalid = props[\"aria-invalid\"] ?? (error != null && error !== false ? true : undefined);\n\n return (\n <div className={cn(\"space-y-2\", className)}>\n <Dropzone\n buttonRef={dropzoneRef}\n id={id}\n disabled={blocked}\n aria-label={props[\"aria-label\"]}\n aria-labelledby={props[\"aria-labelledby\"]}\n aria-describedby={describedBy}\n aria-invalid={invalid}\n aria-busy={uploading || undefined}\n onBlur={props.onBlur}\n onClick={() => inputRef.current?.click()}\n onDragOver={handleDragOver}\n onDragEnter={handleDragOver}\n onDragLeave={() => setDragging(false)}\n onDrop={handleDrop}\n dragging={dragging}\n multiple={multiple}\n uploading={uploading}\n >\n {children}\n </Dropzone>\n <input\n ref={inputRef}\n type=\"file\"\n name={name}\n accept={accept}\n multiple={multiple}\n disabled={blocked}\n onChange={handleInputChange}\n tabIndex={-1}\n aria-hidden=\"true\"\n className=\"sr-only\"\n />\n <span className=\"sr-only\" role=\"status\">\n {uploading ? \"Uploading…\" : \"\"}\n </span>\n {messages.length > 0 ? (\n <div id={messageId} className=\"space-y-1\">\n {messages.map((message, index) => (\n <p key={index} role=\"alert\" className=\"text-sm text-destructive\">\n {message}\n </p>\n ))}\n </div>\n ) : null}\n {entries.length > 0 ? (\n <ul className=\"space-y-1\">\n {entries.map((entry, index) => {\n const label = typeof entry === \"string\" ? fileBasename(entry) : entry.name;\n return (\n <FileRow\n key={typeof entry === \"string\" ? `url-${entry}` : `file-${entry.name}-${index}`}\n file={entry}\n name={label}\n size={typeof entry === \"string\" ? undefined : formatFileSize(entry.size)}\n onRemove={clearable && !blocked ? () => removeEntry(index) : undefined}\n />\n );\n })}\n </ul>\n ) : null}\n </div>\n );\n },\n);\n","/**\n * Pure helpers behind <ResourceForm>: initial-value construction, the D3\n * submit pipeline (dirty-field PATCH granularity, null-clearing, input\n * coercions) and small formatting utilities shared with <ResourceDetail>.\n */\nimport type { FieldDef } from \"../../../schema/types\";\n\nexport type FormValues = Record<string, unknown>;\n\n/** \"published_on\" / \"draft-mode\" → \"Published on\" / \"Draft mode\". */\nexport function humanizeValue(value: string): string {\n const spaced = value.replace(/[_-]+/g, \" \").trim();\n if (spaced === \"\") return value;\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\nfunction pad(n: number): string {\n return String(n).padStart(2, \"0\");\n}\n\n/** ISO-8601 (any offset) → the local \"YYYY-MM-DDTHH:mm\" a datetime-local input needs. */\nexport function toDatetimeLocal(value: string): string {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return value;\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(\n date.getHours(),\n )}:${pad(date.getMinutes())}`;\n}\n\nconst HAS_ZONE = /(?:Z|[+-]\\d{2}:?\\d{2})$/i;\n\n/**\n * datetime-local value (\"YYYY-MM-DDTHH:mm[:ss]\", implicitly local) →\n * ISO-8601 with an explicit UTC offset, per the submit rule in the contract.\n * Values that already carry a zone pass through untouched.\n */\nexport function toIsoWithOffset(value: string): string {\n if (HAS_ZONE.test(value)) return value;\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return value;\n const offsetMinutes = -date.getTimezoneOffset();\n const sign = offsetMinutes >= 0 ? \"+\" : \"-\";\n const abs = Math.abs(offsetMinutes);\n const offset = `${sign}${pad(Math.floor(abs / 60))}:${pad(abs % 60)}`;\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(\n date.getHours(),\n )}:${pad(date.getMinutes())}:${pad(date.getSeconds())}${offset}`;\n}\n\n/**\n * D3 dirtiness at TOP-LEVEL field granularity: a react-hook-form dirtyFields\n * entry counts as dirty when anything in its subtree is truthy, and the whole\n * field value is then sent (DRF PATCH replaces whole field values).\n */\nexport function isDirtyEntry(entry: unknown): boolean {\n if (entry === true) return true;\n if (Array.isArray(entry)) return entry.some(isDirtyEntry);\n if (entry !== null && typeof entry === \"object\") {\n return Object.values(entry).some(isDirtyEntry);\n }\n return false;\n}\n\n/** Unwraps an (accidentally expanded) relation object to its pk. */\nfunction pkOf(value: unknown): unknown {\n if (value !== null && typeof value === \"object\" && !Array.isArray(value) && \"id\" in value) {\n return (value as { id: unknown }).id;\n }\n return value;\n}\n\nexport interface BuildFormValuesInput {\n fields: readonly FieldDef[];\n /** Edit mode: the UNEXPANDED detail record (D10). Wins over defaultValues. */\n item?: Record<string, unknown>;\n defaultValues?: Record<string, unknown>;\n}\n\nfunction initialFieldValue(field: FieldDef, value: unknown): unknown {\n switch (field.kind) {\n case \"string\":\n case \"text\":\n return value == null ? \"\" : String(value);\n case \"number\":\n case \"integer\":\n return value == null ? \"\" : value;\n case \"boolean\":\n return Boolean(value);\n case \"date\":\n return value == null || value === \"\" ? \"\" : String(value).slice(0, 10);\n case \"datetime\":\n return value == null || value === \"\" ? \"\" : toDatetimeLocal(String(value));\n case \"enum\":\n return value == null ? null : value;\n case \"relation\":\n if (field.relation?.many === true) {\n return Array.isArray(value) ? value.map(pkOf) : [];\n }\n return value == null ? null : pkOf(value);\n case \"file\":\n return value == null ? null : value;\n case \"json\":\n return value == null ? \"\" : JSON.stringify(value, null, 2);\n default:\n return value;\n }\n}\n\n/**\n * Builds the react-hook-form value map: every form field gets a defined,\n * controlled-input-safe initial value. Unmatched `defaultValues` keys are kept\n * verbatim (they seed `extraFields`).\n */\nexport function buildFormValues({ fields, item, defaultValues }: BuildFormValuesInput): FormValues {\n const out: FormValues = {};\n for (const field of fields) {\n let source: unknown = defaultValues?.[field.name];\n if (source === undefined) source = field.default; // the model default, on create\n if (item !== undefined && field.name in item) source = item[field.name];\n out[field.name] = initialFieldValue(field, source);\n }\n if (defaultValues !== undefined) {\n for (const [key, value] of Object.entries(defaultValues)) {\n if (!(key in out)) out[key] = value;\n }\n }\n return out;\n}\n\ntype CoercionResult =\n { kind: \"value\"; value: unknown } | { kind: \"omit\" } | { kind: \"error\"; message: string };\n\nfunction val(value: unknown): CoercionResult {\n return { kind: \"value\", value };\n}\n\nconst OMIT: CoercionResult = { kind: \"omit\" };\n\n/** D3: an emptied nullable field is sent as null, and a non-nullable one is omitted. */\nfunction emptied(field: FieldDef): CoercionResult {\n return field.nullable ? val(null) : OMIT;\n}\n\nfunction coerceFieldValue(field: FieldDef, value: unknown): CoercionResult {\n switch (field.kind) {\n case \"string\":\n case \"text\": {\n if (value == null) return emptied(field);\n const text = String(value);\n if (text === \"\" && field.nullable) return val(null);\n return val(text);\n }\n case \"number\":\n case \"integer\": {\n if (value == null || value === \"\") return emptied(field);\n const numeric = typeof value === \"number\" ? value : Number(value);\n if (!Number.isFinite(numeric)) return emptied(field);\n return val(numeric);\n }\n case \"boolean\":\n if (value == null) return emptied(field);\n return val(Boolean(value));\n case \"date\":\n if (value == null || value === \"\") return emptied(field);\n return val(String(value).slice(0, 10));\n case \"datetime\":\n if (value == null || value === \"\") return emptied(field);\n return val(toIsoWithOffset(String(value)));\n case \"enum\": {\n if (value == null || value === \"\") return emptied(field);\n const member = (field.enumValues ?? []).find(\n (candidate) => String(candidate) === String(value),\n );\n return val(member ?? value);\n }\n case \"relation\": {\n if (field.relation?.many === true) {\n // M2M fields are cleared with [] — null is not a valid DRF value here.\n if (value == null) return val([]);\n return val(Array.isArray(value) ? value.map(pkOf) : [pkOf(value)]);\n }\n if (value == null || value === \"\") return emptied(field);\n return val(pkOf(value));\n }\n case \"file\": {\n if (value == null) return emptied(field);\n // An unchanged string value is the existing file's URL — never resent (D2).\n if (typeof value === \"string\") return OMIT;\n return val(value);\n }\n case \"json\": {\n if (typeof value !== \"string\") {\n return value == null ? emptied(field) : val(value);\n }\n if (value.trim() === \"\") return emptied(field);\n try {\n return val(JSON.parse(value));\n } catch {\n return { kind: \"error\", message: \"Enter valid JSON.\" };\n }\n }\n default:\n return val(value);\n }\n}\n\nexport interface JsonFieldError {\n name: string;\n message: string;\n}\n\nexport interface PrepareSubmitInput {\n /** The writable schema fields rendered by the form. */\n fields: readonly FieldDef[];\n /** Resolver output from handleSubmit. */\n raw: FormValues;\n mode: \"create\" | \"update\";\n /** react-hook-form dirtyFields, only consulted in \"update\" mode (D3). */\n dirtyFields?: Record<string, unknown>;\n}\n\nexport interface PreparedSubmit {\n values: Record<string, unknown>;\n /** Per-field validation failures (invalid JSON) that must block the submit. */\n jsonErrors: JsonFieldError[];\n}\n\n/**\n * The D3 submit pipeline. Create mode sends every defined value. Update mode\n * sends only fields whose dirtyFields subtree is truthy, and always the WHOLE\n * field value. Keys without a schema field (extraFields) pass through as-is.\n */\nexport function prepareSubmit({\n fields,\n raw,\n mode,\n dirtyFields,\n}: PrepareSubmitInput): PreparedSubmit {\n const byName = new Map(fields.map((field) => [field.name, field]));\n const values: Record<string, unknown> = {};\n const jsonErrors: JsonFieldError[] = [];\n\n for (const [name, rawValue] of Object.entries(raw)) {\n if (mode === \"update\" && !isDirtyEntry(dirtyFields?.[name])) continue;\n const field = byName.get(name);\n if (field === undefined) {\n if (rawValue !== undefined) values[name] = rawValue;\n continue;\n }\n const result = coerceFieldValue(field, rawValue);\n if (result.kind === \"error\") {\n jsonErrors.push({ name, message: result.message });\n } else if (result.kind === \"value\" && result.value !== undefined) {\n values[name] = result.value;\n }\n }\n\n return { values, jsonErrors };\n}\n","/**\n * Default per-kind inputs for <ResourceForm> (contract: string → Input,\n * text → Textarea, number/integer → Input[type=number], boolean → Switch,\n * date/datetime → native inputs, enum → Select, relation → ResourceSelect\n * (multiple for many), file → FileUpload, json → Textarea with validation).\n *\n * Every control receives react-hook-form's ref (so a failed submit can move\n * focus to it), `aria-invalid`, `aria-describedby` (help text and error) and,\n * where its role supports it, `aria-required`. A field that shows an error\n * re-validates on every change, so the error goes away as soon as the value\n * is fixed. A field without one validates when it loses focus.\n */\nimport * as React from \"react\";\nimport { Controller, useFormContext } from \"react-hook-form\";\nimport type { Control, ControllerRenderProps, FieldValues } from \"react-hook-form\";\nimport type { FieldDef } from \"../../../schema/types\";\nimport { FileUpload } from \"../../file-upload/FileUpload\";\nimport { Input } from \"../../primitives/input\";\nimport { Select } from \"../../primitives/select\";\nimport { Switch } from \"../../primitives/switch\";\nimport { Textarea } from \"../../primitives/textarea\";\nimport { ResourceSelect } from \"../select/ResourceSelect\";\nimport { humanizeValue } from \"./prepare\";\n\nexport interface DefaultFieldControlProps {\n field: FieldDef;\n control: Control<FieldValues>;\n inputId: string;\n /** The label's id, for controls whose popup needs naming too (ResourceSelect's list). */\n labelId?: string;\n describedBy?: string;\n invalid: boolean;\n /** Sets `aria-required` on controls whose role supports it. */\n required?: boolean;\n disabled?: boolean;\n /** Re-validate on every change while the field shows an error. Default true. */\n revalidateWhileInvalid?: boolean;\n /** FieldOverride.props pass-through, spread onto the rendered input. */\n inputProps?: Record<string, unknown>;\n}\n\n/** Kinds whose control role cannot carry aria-required (their label says \"required\" instead). */\nexport const KINDS_WITHOUT_ARIA_REQUIRED: ReadonlySet<string> = new Set([\"boolean\", \"file\"]);\n\nfunction stringInputType(field: FieldDef): string {\n switch (field.format) {\n case \"email\":\n return \"email\";\n case \"uri\":\n case \"url\":\n return \"url\";\n case \"password\":\n return \"password\";\n default:\n return \"text\";\n }\n}\n\nfunction textValue(value: unknown): string {\n return value == null ? \"\" : String(value);\n}\n\nexport function DefaultFieldControl({\n field,\n control,\n inputId,\n labelId,\n describedBy,\n invalid,\n required = false,\n disabled,\n revalidateWhileInvalid = true,\n inputProps,\n}: DefaultFieldControlProps): React.ReactElement {\n const { trigger } = useFormContext();\n const aria = {\n \"aria-invalid\": invalid || undefined,\n \"aria-describedby\": describedBy,\n } as const;\n const ariaRequired = required && !KINDS_WITHOUT_ARIA_REQUIRED.has(field.kind) ? true : undefined;\n\n return (\n <Controller\n control={control}\n name={field.name}\n render={({ field: rhf, fieldState }) => {\n const change = (next: unknown): void => {\n rhf.onChange(next);\n if (revalidateWhileInvalid && fieldState.invalid) void trigger(field.name);\n };\n return renderControl({\n field,\n rhf,\n change,\n inputId,\n labelId,\n aria,\n ariaRequired,\n disabled,\n inputProps,\n });\n }}\n />\n );\n}\n\ninterface RenderControlInput {\n field: FieldDef;\n rhf: ControllerRenderProps<FieldValues, string>;\n change: (next: unknown) => void;\n inputId: string;\n labelId?: string;\n aria: { \"aria-invalid\": true | undefined; \"aria-describedby\": string | undefined };\n ariaRequired: true | undefined;\n disabled?: boolean;\n inputProps?: Record<string, unknown>;\n}\n\nfunction renderControl({\n field,\n rhf,\n change,\n inputId,\n labelId,\n aria,\n ariaRequired,\n disabled,\n inputProps,\n}: RenderControlInput): React.ReactElement {\n switch (field.kind) {\n case \"text\":\n return (\n <Textarea\n ref={rhf.ref}\n id={inputId}\n name={rhf.name}\n rows={4}\n maxLength={field.maxLength}\n disabled={disabled}\n value={textValue(rhf.value)}\n onChange={(event) => change(event.target.value)}\n onBlur={rhf.onBlur}\n aria-required={ariaRequired}\n {...aria}\n {...inputProps}\n />\n );\n case \"number\":\n case \"integer\":\n return (\n <Input\n ref={rhf.ref}\n id={inputId}\n name={rhf.name}\n type=\"number\"\n inputMode={field.kind === \"integer\" ? \"numeric\" : \"decimal\"}\n step={field.kind === \"integer\" ? 1 : \"any\"}\n min={field.min}\n max={field.max}\n disabled={disabled}\n value={rhf.value == null ? \"\" : (rhf.value as number | string)}\n onChange={(event) => change(event.target.value)}\n onBlur={rhf.onBlur}\n aria-required={ariaRequired}\n {...aria}\n {...inputProps}\n />\n );\n case \"boolean\":\n // A block of its own, so the switch sits under its label like every\n // other control (an inline switch ran into the label's text).\n return (\n <div>\n <Switch\n ref={rhf.ref}\n id={inputId}\n disabled={disabled}\n checked={Boolean(rhf.value)}\n onCheckedChange={(checked) => change(checked)}\n onBlur={rhf.onBlur}\n {...aria}\n {...inputProps}\n />\n </div>\n );\n case \"date\":\n case \"datetime\":\n return (\n <Input\n ref={rhf.ref}\n id={inputId}\n name={rhf.name}\n type={field.kind === \"date\" ? \"date\" : \"datetime-local\"}\n disabled={disabled}\n value={textValue(rhf.value)}\n onChange={(event) => change(event.target.value)}\n onBlur={rhf.onBlur}\n aria-required={ariaRequired}\n {...aria}\n {...inputProps}\n />\n );\n case \"enum\": {\n const members = field.enumValues ?? [];\n const options = members.map((member) => ({\n value: String(member),\n label: field.enumLabels?.[String(member)] ?? humanizeValue(String(member)),\n }));\n return (\n <Select\n ref={rhf.ref}\n id={inputId}\n disabled={disabled}\n value={rhf.value == null ? null : String(rhf.value)}\n options={options}\n clearable={field.nullable}\n placeholder=\"Select…\"\n onValueChange={(next) => {\n if (next === null) {\n change(null);\n return;\n }\n const member = members.find((candidate) => String(candidate) === next);\n change(member ?? next);\n }}\n onBlur={rhf.onBlur}\n aria-required={ariaRequired}\n {...aria}\n {...inputProps}\n />\n );\n }\n case \"relation\": {\n const relation = field.relation;\n if (relation === undefined) {\n // Degraded mode: no x-karni-relation extension, edit the raw pk.\n return (\n <Input\n ref={rhf.ref}\n id={inputId}\n name={rhf.name}\n type=\"text\"\n disabled={disabled}\n value={textValue(rhf.value)}\n onChange={(event) => change(event.target.value)}\n onBlur={rhf.onBlur}\n aria-required={ariaRequired}\n {...aria}\n {...inputProps}\n />\n );\n }\n return (\n <ResourceSelect\n ref={rhf.ref}\n id={inputId}\n resource={relation.resource}\n multiple={relation.many}\n disabled={disabled}\n value={(rhf.value ?? null) as string | number | ReadonlyArray<string | number> | null}\n onChange={(next) => change(next)}\n onBlur={rhf.onBlur}\n aria-labelledby={labelId}\n aria-required={ariaRequired}\n {...aria}\n {...inputProps}\n />\n );\n }\n case \"file\":\n return (\n <FileUpload\n ref={rhf.ref}\n id={inputId}\n name={rhf.name}\n disabled={disabled}\n value={(rhf.value ?? null) as File | string | null}\n onChange={(next) => change(next)}\n onBlur={rhf.onBlur}\n {...aria}\n {...inputProps}\n />\n );\n case \"json\":\n return (\n <Textarea\n ref={rhf.ref}\n id={inputId}\n name={rhf.name}\n rows={5}\n disabled={disabled}\n className=\"font-mono\"\n value={\n typeof rhf.value === \"string\"\n ? rhf.value\n : rhf.value == null\n ? \"\"\n : JSON.stringify(rhf.value, null, 2)\n }\n onChange={(event) => change(event.target.value)}\n onBlur={rhf.onBlur}\n aria-required={ariaRequired}\n {...aria}\n {...inputProps}\n />\n );\n default:\n return (\n <Input\n ref={rhf.ref}\n id={inputId}\n name={rhf.name}\n type={stringInputType(field)}\n maxLength={field.maxLength}\n disabled={disabled}\n value={textValue(rhf.value)}\n onChange={(event) => change(event.target.value)}\n onBlur={rhf.onBlur}\n aria-required={ariaRequired}\n {...aria}\n {...inputProps}\n />\n );\n }\n}\n","/**\n * The states <ResourceForm> shows around its fields, as replaceable slots:\n * the loading skeleton, the permission panel, the error summary after a\n * failed submit and the banner for a submit that failed for another reason.\n * Their defaults are exported (`defaultResourceFormSlots`) so a project can\n * wrap them rather than rewrite them.\n */\nimport * as React from \"react\";\nimport { cn } from \"../../../lib/cn\";\nimport type { FieldDef } from \"../../../schema/types\";\nimport { ErrorState, PermissionDenied, type ErrorSlotProps } from \"../../../states/ErrorState\";\nimport { describeError, type KarniErrorKind } from \"../../../states/describe-error\";\nimport { PendingButton } from \"../../../states/PendingButton\";\nimport { FileUpload } from \"../../file-upload/FileUpload\";\nimport { AlertIcon, LockIcon, OfflineIcon } from \"../../primitives/icons\";\nimport { Button } from \"../../primitives/button\";\nimport { Input } from \"../../primitives/input\";\nimport { Label } from \"../../primitives/label\";\nimport { Skeleton } from \"../../primitives/skeleton\";\nimport { Switch } from \"../../primitives/switch\";\nimport { Textarea } from \"../../primitives/textarea\";\n\n/**\n * A field's label-to-control gap as Tailwind 3's `space-y` draws it: a top\n * margin on every child after the first. Tailwind 4's `space-y` puts a bottom\n * margin on the inline <label> instead, which an inline element ignores, so\n * the gap is spelled out to render the same under both.\n */\nexport const FIELD_GAP = \"[&>:not([hidden])~:not([hidden])]:mt-2\";\n\n/** The submit row, shared by the form and its skeleton so nothing moves when the form arrives. */\nexport const SUBMIT_ROW = \"flex items-center justify-end gap-3 pt-2\";\n\nexport interface ResourceFormLoadingProps {\n /**\n * The fields the form will render, labels already overridden, once the\n * schema is known (edit mode while the row loads). Undefined while the\n * schema itself loads.\n */\n fields?: readonly FieldDef[];\n /** \"create\" or \"update\". */\n mode: \"create\" | \"update\";\n /** The submit button's label, so the skeleton's button has the real one's width. */\n submitLabel: React.ReactNode;\n /** False when the form's `actions` prop replaces the submit row. */\n showSubmitRow: boolean;\n}\n\nexport interface ResourceFormForbiddenProps {\n /** The verb the role lacks: \"edit\". */\n action: string;\n /** What it applies to: \"this event\". */\n resource: string;\n}\n\n/** One entry of the error summary. */\nexport interface ResourceFormFieldError {\n /** The field's name. Absent for a message that belongs to no field. */\n name?: string;\n /** The field's label, as the form shows it. */\n label?: string;\n message: string;\n /** Moves focus to the field's input. Absent for a message that belongs to no field. */\n focus?: () => void;\n /** `#<the input's id>`, for a link to the field. */\n href?: string;\n}\n\nexport interface ResourceFormErrorSummaryProps {\n /** \"2 fields need attention\", or what failed when no field did. */\n title: string;\n errors: readonly ResourceFormFieldError[];\n}\n\nexport interface ResourceFormSubmitErrorProps extends ErrorSlotProps {\n /** Edit mode, after a conflict: loads the latest version of the row (typed values are kept). */\n onReload?: () => void;\n /** True while that reload runs. */\n reloading?: boolean;\n}\n\n/**\n * Each default control as an invisible stand-in under a shimmer, so the\n * skeleton takes exactly the space the real control will, whatever\n * primitives the project registered.\n */\nfunction GhostControl({ field }: { field?: FieldDef }): React.ReactElement {\n const kind = field?.kind ?? \"string\";\n let ghost: React.ReactElement;\n switch (kind) {\n case \"text\":\n ghost = <Textarea rows={4} disabled tabIndex={-1} />;\n break;\n case \"json\":\n ghost = <Textarea rows={5} disabled tabIndex={-1} className=\"font-mono\" />;\n break;\n case \"boolean\":\n ghost = <Switch disabled tabIndex={-1} />;\n break;\n case \"file\":\n ghost = <FileUpload disabled />;\n break;\n default:\n ghost = <Input disabled tabIndex={-1} />;\n }\n return (\n <div className={cn(\"relative\", kind === \"boolean\" ? \"w-fit\" : \"w-full\")}>\n <div className=\"invisible\">{ghost}</div>\n <Skeleton\n className={cn(\"absolute inset-0\", kind === \"boolean\" ? \"rounded-full\" : \"rounded-md\")}\n />\n </div>\n );\n}\n\nconst PLACEHOLDER_ROWS = [0, 1, 2, 3];\n\n/**\n * The loading state: the form's own layout with shimmering controls. Once the\n * schema is known it has the real field count, kinds, labels and help text,\n * and the submit row sits where the real one will, so nothing shifts when the\n * values arrive.\n */\nexport function ResourceFormSkeleton({\n fields,\n submitLabel,\n showSubmitRow,\n}: ResourceFormLoadingProps): React.ReactElement {\n return (\n <div role=\"status\" aria-label=\"Loading form\" aria-busy=\"true\" className=\"space-y-5\">\n <div className=\"space-y-5\" aria-hidden=\"true\">\n {fields !== undefined\n ? fields.map((field) => (\n <div key={field.name} className={FIELD_GAP}>\n <Label>\n {field.label}\n {field.required && field.kind !== \"boolean\" ? (\n <span className=\"text-destructive\">{\" *\"}</span>\n ) : null}\n </Label>\n <GhostControl field={field} />\n {field.description !== undefined ? (\n <p className=\"text-sm text-muted-foreground\">{field.description}</p>\n ) : null}\n </div>\n ))\n : PLACEHOLDER_ROWS.map((row) => (\n <div key={row} className={FIELD_GAP}>\n <Skeleton className={cn(\"h-3.5\", row % 2 === 0 ? \"w-24\" : \"w-32\")} />\n <GhostControl />\n </div>\n ))}\n </div>\n {showSubmitRow ? (\n <div className={SUBMIT_ROW} aria-hidden=\"true\">\n <div className=\"relative\">\n <Button type=\"button\" disabled tabIndex={-1} className=\"invisible\">\n {submitLabel}\n </Button>\n <Skeleton className=\"absolute inset-0 rounded-md\" />\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\n/** The 403-on-load state: the role cannot edit this row, said plainly. */\nexport function ResourceFormForbidden({\n action,\n resource,\n}: ResourceFormForbiddenProps): React.ReactElement {\n return <PermissionDenied action={action} resource={resource} />;\n}\n\n/** A failed load, with \"Try again\" when it can help. */\nexport function ResourceFormLoadError(props: ErrorSlotProps): React.ReactElement {\n return <ErrorState {...props} />;\n}\n\n/**\n * Every problem after a failed submit, at the top of the form, each field a\n * link that moves focus to it (links wrap like text, so a long message keeps\n * its bullet on its first line). Announced when it appears.\n */\nexport function ResourceFormErrorSummary({\n title,\n errors,\n}: ResourceFormErrorSummaryProps): React.ReactElement {\n const titleId = React.useId();\n return (\n <div\n role=\"alert\"\n aria-labelledby={titleId}\n className=\"rounded-md border border-destructive-border bg-destructive-subtle px-4 py-3 text-sm\"\n >\n <p id={titleId} className=\"flex items-center gap-2 font-semibold text-foreground\">\n <AlertIcon className=\"h-4 w-4 shrink-0 text-destructive\" />\n {title}\n </p>\n <ul className=\"mt-2 list-disc space-y-1 pl-10 text-foreground marker:text-destructive\">\n {errors.map((entry, index) => (\n <li key={entry.name ?? `form-${index}`}>\n {entry.focus !== undefined ? (\n <a\n href={entry.href ?? \"#\"}\n onClick={(event) => {\n event.preventDefault();\n entry.focus?.();\n }}\n className=\"rounded-sm underline decoration-destructive underline-offset-4 hover:no-underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {entry.label}: {entry.message}\n </a>\n ) : (\n <span>{entry.message}</span>\n )}\n </li>\n ))}\n </ul>\n </div>\n );\n}\n\nconst BANNER_ICONS: Partial<Record<KarniErrorKind, React.ComponentType<{ className?: string }>>> = {\n offline: OfflineIcon,\n network: OfflineIcon,\n forbidden: LockIcon,\n unauthenticated: LockIcon,\n};\n\n/**\n * A submit that failed for a reason other than the values (offline, the\n * server, permission, a conflict): a compact banner above the fields, in\n * describeError's plain words, with \"Try again\" when it can help and \"Load\n * the latest version\" after a conflict. The values the user typed stay in\n * the fields.\n */\nexport function ResourceFormSubmitError({\n error,\n context,\n onRetry,\n retrying = false,\n onReload,\n reloading = false,\n}: ResourceFormSubmitErrorProps): React.ReactElement {\n const described = describeError(error, context);\n const Icon = BANNER_ICONS[described.kind] ?? AlertIcon;\n const retry = described.retryable && onRetry !== undefined;\n const reload = described.kind === \"conflict\" && onReload !== undefined;\n return (\n <div\n role=\"alert\"\n data-error-kind={described.kind}\n className=\"flex gap-3 rounded-md border border-destructive-border bg-destructive-subtle px-4 py-3 text-sm\"\n >\n <Icon className=\"mt-0.5 h-4 w-4 shrink-0 text-destructive\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-semibold text-foreground\">{described.title}</p>\n <p className=\"mt-1 text-muted-foreground\">{described.description}</p>\n {described.detail !== undefined ? (\n <p className=\"mt-1 text-xs text-muted-foreground\">{described.detail}</p>\n ) : null}\n {retry || reload ? (\n <div className=\"mt-3 flex flex-wrap items-center gap-2\">\n {retry ? (\n <PendingButton\n variant=\"outline\"\n size=\"sm\"\n onClick={onRetry}\n pending={retrying}\n pendingLabel=\"Trying again…\"\n >\n Try again\n </PendingButton>\n ) : null}\n {reload ? (\n <PendingButton\n variant=\"outline\"\n size=\"sm\"\n onClick={onReload}\n pending={reloading}\n pendingLabel=\"Loading the latest version…\"\n >\n Load the latest version\n </PendingButton>\n ) : null}\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n","/**\n * DRF validation bodies → the fields they belong to.\n *\n * DRF answers a failed save with many shapes, and ResourceForm must put every\n * message where the user can act on it:\n *\n * {\"title\": [\"Required.\"]} a field\n * {\"title\": \"Required.\"} a field, one message\n * {\"address\": {\"city\": [\"Required.\"]}} a nested serializer\n * {\"items\": [{}, {\"name\": [\"Required.\"]}]} a list serializer\n * {\"tags\": {\"1\": [\"Invalid pk.\"]}} errors keyed by position\n * {\"non_field_errors\": [\"...\"]}, {\"detail\": \"...\"}, [\"...\"], \"...\"\n * {\"secret_field\": [\"...\"]} a key the form does not show\n *\n * A message lands on the deepest path the form renders (`address.city` when\n * that is a field, else `address` with the nested part named in the\n * message). Everything else is a form-level message that names what it\n * is about. Internal to @karni/ui.\n */\nimport { humanizeValue } from \"./prepare\";\n\nexport interface MappedServerErrors {\n /** Field path → its messages, joined into one sentence run. */\n fields: Record<string, string>;\n /** Messages that belong to no field the form shows. */\n root: string[];\n}\n\nexport interface MapServerErrorsOptions {\n /** Whether the form renders an input for `path` (\"title\", \"address.city\"). */\n isField: (path: string) => boolean;\n /** How a path is named in a form-level message. The default humanizes it. */\n labelOf?: (path: string) => string;\n}\n\nconst ROOT_KEYS = new Set([\"non_field_errors\", \"detail\", \"__all__\"]);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction defaultLabel(path: string): string {\n const segments = path.split(\".\");\n const named = segments.map((segment) =>\n /^\\d+$/.test(segment) ? `item ${Number(segment) + 1}` : segment,\n );\n return humanizeValue(named.join(\" \"));\n}\n\n/** Every message inside `value`, nested parts prefixed with what they are about. */\nfunction messagesOf(value: unknown): string[] {\n if (value === null || value === undefined) return [];\n if (typeof value === \"string\") return value.trim() === \"\" ? [] : [value];\n if (typeof value === \"number\" || typeof value === \"boolean\") return [String(value)];\n if (Array.isArray(value)) {\n return value.flatMap((entry, index) =>\n isRecord(entry) && !(\"message\" in entry)\n ? messagesOf(entry).map((message) => `Item ${index + 1}: ${message}`)\n : messagesOf(entry),\n );\n }\n if (isRecord(value)) {\n // {\"message\": \"...\", \"code\": \"...\"} (DRF's get_full_details shape).\n if (typeof value[\"message\"] === \"string\") return [value[\"message\"]];\n return Object.entries(value).flatMap(([key, nested]) =>\n messagesOf(nested).map((message) =>\n ROOT_KEYS.has(key) ? message : `${defaultLabel(key)}: ${message}`,\n ),\n );\n }\n return [];\n}\n\n/** True for HTML error pages and other bodies that are not a message for people. */\nfunction isMarkup(text: string): boolean {\n return /^\\s*</.test(text);\n}\n\n/** Splits a DRF error body into field messages and form-level messages. */\nexport function mapServerErrors(\n data: unknown,\n { isField, labelOf = defaultLabel }: MapServerErrorsOptions,\n): MappedServerErrors {\n const fields: Record<string, string[]> = {};\n const root: string[] = [];\n\n const toRoot = (path: string, value: unknown): void => {\n for (const message of messagesOf(value)) root.push(`${labelOf(path)}: ${message}`);\n };\n\n const walk = (path: string, value: unknown): void => {\n if (isField(path)) {\n const messages = messagesOf(value);\n if (messages.length > 0) (fields[path] ??= []).push(...messages);\n return;\n }\n if (isRecord(value) && typeof value[\"message\"] !== \"string\") {\n for (const [key, nested] of Object.entries(value)) {\n if (ROOT_KEYS.has(key)) root.push(...messagesOf(nested));\n else walk(`${path}.${key}`, nested);\n }\n return;\n }\n if (Array.isArray(value) && value.some(isRecord)) {\n value.forEach((entry, index) => {\n if (isRecord(entry)) walk(`${path}.${index}`, entry);\n else toRoot(path, entry);\n });\n return;\n }\n toRoot(path, value);\n };\n\n if (typeof data === \"string\") {\n if (data.trim() !== \"\" && !isMarkup(data)) root.push(data.trim());\n } else if (Array.isArray(data)) {\n root.push(...messagesOf(data));\n } else if (isRecord(data)) {\n for (const [key, value] of Object.entries(data)) {\n if (ROOT_KEYS.has(key)) {\n root.push(...messagesOf(value));\n } else if (key === \"code\" && typeof value === \"string\" && \"detail\" in data) {\n // {\"detail\": \"...\", \"code\": \"...\"}: the code is for programs, not people.\n continue;\n } else {\n walk(key, value);\n }\n }\n }\n\n return {\n fields: Object.fromEntries(\n Object.entries(fields).map(([path, messages]) => [path, messages.join(\" \")]),\n ),\n root,\n };\n}\n","import { zodResolver } from \"@hookform/resolvers/zod\";\nimport * as React from \"react\";\nimport { FormProvider, useForm } from \"react-hook-form\";\nimport type {\n Control,\n FieldError,\n FieldErrors,\n FieldValues,\n Mode,\n Resolver,\n UseFormReturn,\n} from \"react-hook-form\";\nimport { useResourceItem } from \"../../../hooks/useResourceItem\";\nimport { useResourceMutations } from \"../../../hooks/useResourceMutations\";\nimport { useUnsavedChangesGuard } from \"../../../hooks/useUnsavedChangesGuard\";\nimport { cn } from \"../../../lib/cn\";\nimport { registerComponentRole } from \"../../../lib/roles\";\nimport type { FieldDef, ResourceSchema } from \"../../../schema/types\";\nimport { useSchema } from \"../../../schema/useSchema\";\nimport { zodFor } from \"../../../schema/zod\";\nimport { describeError, type KarniErrorContext } from \"../../../states/describe-error\";\nimport type { ErrorSlotProps } from \"../../../states/ErrorState\";\nimport { PendingButton } from \"../../../states/PendingButton\";\nimport { AlertIcon } from \"../../primitives/icons\";\nimport { Label } from \"../../primitives/label\";\nimport { resourceNames, type ResourceLabel, type ResourceNames } from \"../resource-names\";\nimport { DefaultFieldControl, KINDS_WITHOUT_ARIA_REQUIRED } from \"./field-inputs\";\nimport {\n FIELD_GAP,\n ResourceFormErrorSummary,\n ResourceFormForbidden,\n ResourceFormLoadError,\n ResourceFormSkeleton,\n ResourceFormSubmitError,\n SUBMIT_ROW,\n type ResourceFormErrorSummaryProps,\n type ResourceFormFieldError,\n type ResourceFormForbiddenProps,\n type ResourceFormLoadingProps,\n type ResourceFormSubmitErrorProps,\n} from \"./form-states\";\nimport { buildFormValues, humanizeValue, prepareSubmit } from \"./prepare\";\nimport { mapServerErrors } from \"./server-errors\";\n\nregisterComponentRole(\"resource-form\", \"ResourceForm\");\n\n/** Props passed to a custom field component (the `fields` escape hatch). */\nexport interface KarniFieldProps {\n field: FieldDef;\n name: string;\n label: string;\n required: boolean;\n control: Control<FieldValues>;\n error?: string;\n disabled?: boolean;\n /** Pass-through from FieldOverride.props. */\n props?: Record<string, unknown>;\n}\n\nexport interface FieldOverride {\n component?: React.ComponentType<KarniFieldProps>;\n label?: string;\n hidden?: boolean;\n props?: Record<string, unknown>;\n}\n\n/**\n * The replaceable parts of ResourceForm (`slots`). Each default is in\n * `defaultResourceFormSlots`.\n */\nexport interface ResourceFormSlots {\n /** While the schema or the edited row loads. */\n Loading: React.ComponentType<ResourceFormLoadingProps>;\n /** A failed load of the schema or the row, with retry when it can help. */\n Error: React.ComponentType<ErrorSlotProps>;\n /** A 403 while loading the row: the role cannot edit it. */\n Forbidden: React.ComponentType<ResourceFormForbiddenProps>;\n /** After a failed submit with more than one problem: every one, each field focusable. */\n ErrorSummary: React.ComponentType<ResourceFormErrorSummaryProps>;\n /** A submit that failed for a reason other than the values (offline, 403, 409, 5xx). */\n SubmitError: React.ComponentType<ResourceFormSubmitErrorProps>;\n}\n\n/** ResourceForm's own slot components, for wrapping rather than rewriting. */\nexport const defaultResourceFormSlots: ResourceFormSlots = {\n Loading: ResourceFormSkeleton,\n Error: ResourceFormLoadError,\n Forbidden: ResourceFormForbidden,\n ErrorSummary: ResourceFormErrorSummary,\n SubmitError: ResourceFormSubmitError,\n};\n\nexport interface ResourceFormProps {\n resource: string;\n /** Present → edit mode: loads the UNEXPANDED item, PATCHes dirty fields only (D10). */\n id?: string | number;\n defaultValues?: Record<string, unknown>;\n onSuccess?: (result: Record<string, unknown>) => void;\n /** Called with every failed submit's error (the form shows it as well). */\n onError?: (error: unknown) => void;\n fields?: Record<string, FieldOverride>;\n /** Custom RHF-registered nodes appended after the derived fields. */\n extraFields?: React.ReactNode;\n transformSubmit?: (values: Record<string, unknown>) => Record<string, unknown>;\n /** Replaces the submit row. */\n actions?: React.ReactNode;\n /** The submit button's text. Default \"Create\" or \"Save changes\". */\n submitLabel?: React.ReactNode;\n className?: string;\n /** Replaces parts of the form: loading, load error, permission, error summary, submit error. */\n slots?: Partial<ResourceFormSlots>;\n /**\n * When a field first validates (react-hook-form's `mode`). Default \"onBlur\":\n * a field is checked when the user leaves it, never on every keystroke.\n */\n validationMode?: Mode;\n /**\n * When a field validates again after a submit (react-hook-form's\n * `reValidateMode`). Default \"onBlur\". Independently of both, a field that\n * shows an error re-validates on every change, so the error clears as soon\n * as the value is fixed.\n */\n reValidateMode?: Exclude<Mode, \"onTouched\" | \"all\">;\n /** Focus the first field when the form appears. Default: true to create, false to edit. */\n autoFocus?: boolean;\n /**\n * Warn before the page unloads with unsaved changes (`beforeunload`).\n * Default true. Pass false to opt out. In-app navigation: see `onDirtyChange`.\n */\n guardUnsavedChanges?: boolean;\n /**\n * Called when the form gains or loses unsaved changes, and with false just\n * before `onSuccess`. Feed it to `useUnsavedChangesGuard().setDirty` and\n * the router's blocker to stop in-app navigation away from a dirty form.\n */\n onDirtyChange?: (dirty: boolean) => void;\n /**\n * How the resource is named in messages. The default is derived from\n * `resource` (\"events\" → \"event\").\n */\n resourceLabel?: ResourceLabel;\n}\n\n/** Field kinds the generic form knows how to render (others need an override). */\nconst EDITABLE_KINDS: ReadonlySet<string> = new Set([\n \"string\",\n \"text\",\n \"number\",\n \"integer\",\n \"boolean\",\n \"date\",\n \"datetime\",\n \"enum\",\n \"relation\",\n \"file\",\n \"json\",\n]);\n\n/**\n * The fields the form submits: writable, of a kind it can render (or with a\n * custom component). Fields the role cannot see are absent from its schema\n * and fields it cannot write are read-only there, so neither is ever here.\n */\nfunction writableFields(\n schema: ResourceSchema,\n overrides: Record<string, FieldOverride> | undefined,\n): FieldDef[] {\n return schema.fields.filter(\n (field) =>\n !field.readOnly &&\n (EDITABLE_KINDS.has(field.kind) || overrides?.[field.name]?.component !== undefined),\n );\n}\n\n/** The fields the form shows: writable and not hidden, labels overridden. */\nfunction shownFields(\n fields: readonly FieldDef[],\n overrides: Record<string, FieldOverride> | undefined,\n): FieldDef[] {\n return fields\n .filter((field) => overrides?.[field.name]?.hidden !== true)\n .map((field) => {\n const label = overrides?.[field.name]?.label;\n return label !== undefined ? { ...field, label } : field;\n });\n}\n\n/** A rejected request as DRF answered it: the status and the parsed body. */\nfunction apiFailure(error: unknown): { status: number; data: unknown } | null {\n if (typeof error !== \"object\" || error === null) return null;\n const candidate = error as { status?: unknown; data?: unknown };\n return typeof candidate.status === \"number\"\n ? { status: candidate.status, data: candidate.data }\n : null;\n}\n\n/** zod issue codes that, on an empty value, only mean \"nothing was entered\". */\nconst TYPE_ISSUES: ReadonlySet<string> = new Set([\n \"invalid_type\",\n \"invalid_enum_value\",\n \"invalid_union\",\n \"invalid_literal\",\n]);\n\nfunction isEmptyValue(value: unknown): boolean {\n return (\n value === null ||\n value === undefined ||\n value === \"\" ||\n (Array.isArray(value) && value.length === 0)\n );\n}\n\nfunction hasValueAt(values: FieldValues, path: string): boolean {\n let current: unknown = values;\n for (const segment of path.split(\".\")) {\n if (typeof current !== \"object\" || current === null) return false;\n current = (current as Record<string, unknown>)[segment];\n }\n return current !== undefined;\n}\n\nfunction errorAt(errors: FieldErrors<FieldValues>, path: string): FieldError | undefined {\n let current: unknown = errors;\n for (const segment of path.split(\".\")) {\n if (typeof current !== \"object\" || current === null) return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n const entry = current as FieldError | undefined;\n return typeof entry?.message === \"string\" ? entry : undefined;\n}\n\nfunction plural(count: number, one: string, many: string): string {\n return count === 1 ? one : many;\n}\n\ninterface FormFieldRowProps {\n field: FieldDef;\n inputId: string;\n override?: FieldOverride;\n control: Control<FieldValues>;\n error?: string;\n disabled?: boolean;\n}\n\nfunction FormFieldRow({\n field,\n inputId,\n override,\n control,\n error,\n disabled,\n}: FormFieldRowProps): React.ReactElement {\n if (override?.component !== undefined) {\n const Component = override.component;\n return (\n <Component\n field={field}\n name={field.name}\n label={field.label}\n required={field.required}\n control={control}\n error={error}\n disabled={disabled}\n props={override.props}\n />\n );\n }\n\n const labelId = `${inputId}-label`;\n const errorId = `${inputId}-error`;\n const descriptionId = `${inputId}-description`;\n const describedBy =\n [field.description !== undefined ? descriptionId : null, error !== undefined ? errorId : null]\n .filter((part): part is string => part !== null)\n .join(\" \") || undefined;\n // A switch is never empty, so \"required\" would only mislead.\n const required = field.required && field.kind !== \"boolean\";\n\n return (\n <div className={FIELD_GAP} data-karni-field={field.name}>\n <Label htmlFor={inputId} id={labelId}>\n {field.label}\n {required ? (\n <span aria-hidden=\"true\" className=\"text-destructive\">\n {\" *\"}\n </span>\n ) : null}\n {required && KINDS_WITHOUT_ARIA_REQUIRED.has(field.kind) ? (\n <span className=\"sr-only\"> (required)</span>\n ) : null}\n </Label>\n <DefaultFieldControl\n field={field}\n control={control}\n inputId={inputId}\n labelId={labelId}\n describedBy={describedBy}\n invalid={error !== undefined}\n required={required}\n disabled={disabled}\n inputProps={override?.props}\n />\n {field.description !== undefined ? (\n <p id={descriptionId} className=\"text-sm text-muted-foreground\">\n {field.description}\n </p>\n ) : null}\n {error !== undefined ? (\n <p id={errorId} className=\"flex items-start gap-1.5 text-sm font-medium text-foreground\">\n <AlertIcon className=\"mt-0.5 h-4 w-4 shrink-0 text-destructive\" />\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n\ntype PendingFocus =\n | { kind: \"field\"; name: string }\n | { kind: \"summary\" }\n | { kind: \"banner\" }\n | { kind: \"restore\"; element: HTMLElement | null };\n\ninterface ResourceFormInnerProps extends ResourceFormProps {\n schema: ResourceSchema;\n item?: Record<string, unknown>;\n names: ResourceNames;\n slotsResolved: ResourceFormSlots;\n reloadItem?: () => Promise<unknown>;\n}\n\nfunction ResourceFormInner(props: ResourceFormInnerProps): React.ReactElement {\n const {\n resource,\n id,\n defaultValues,\n onSuccess,\n onError,\n fields: fieldOverrides,\n extraFields,\n transformSubmit,\n actions,\n submitLabel,\n className,\n schema,\n item,\n names,\n slotsResolved: slots,\n validationMode = \"onBlur\",\n reValidateMode = \"onBlur\",\n autoFocus,\n guardUnsavedChanges = true,\n onDirtyChange,\n reloadItem,\n } = props;\n const mode = id === undefined ? \"create\" : \"update\";\n const mutations = useResourceMutations(resource);\n const baseId = React.useId();\n const inputIdOf = React.useCallback((name: string) => `${baseId}-${name}`, [baseId]);\n\n const formFields = React.useMemo(\n () => writableFields(schema, fieldOverrides),\n [schema, fieldOverrides],\n );\n const visibleFields = React.useMemo(\n () => shownFields(formFields, fieldOverrides),\n [formFields, fieldOverrides],\n );\n\n const initialValues = React.useMemo(\n () => buildFormValues({ fields: formFields, item, defaultValues }),\n [formFields, item, defaultValues],\n );\n\n const resolver = React.useMemo<Resolver<FieldValues>>(() => {\n const base = zodResolver(zodFor(schema, mode)) as unknown as Resolver<FieldValues>;\n // A cleared optional, non-nullable field (a select's \"no selection\") is\n // omitted from the request (D3), so it must not fail validation as null.\n // Many relations are cleared with [] and stay.\n const omittable = new Set(\n schema.fields\n .filter(\n (field) =>\n !field.required &&\n !field.nullable &&\n !(field.kind === \"relation\" && field.relation?.many === true),\n )\n .map((field) => field.name),\n );\n const required = new Set(\n schema.fields.filter((field) => field.required).map((field) => field.name),\n );\n // An optional text field left empty is not an invalid email or URL: its\n // format is checked only when something was typed. The \"\" itself is kept\n // in the submitted values (clearing a field in edit mode must save).\n const optionalText = new Set(\n schema.fields\n .filter((field) => !field.required && (field.kind === \"string\" || field.kind === \"text\"))\n .map((field) => field.name),\n );\n return async (values, context, options) => {\n const blank = Object.keys(values).filter(\n (name) => values[name] === \"\" && optionalText.has(name),\n );\n const cleaned: FieldValues = Object.fromEntries(\n Object.entries(values).filter(\n ([name, value]) =>\n !(value === null && omittable.has(name)) && !(value === \"\" && optionalText.has(name)),\n ),\n );\n const result = await base(cleaned, context, options);\n if (Object.keys(result.errors).length === 0) {\n for (const name of blank) (result.values as FieldValues)[name] = \"\";\n }\n // An empty required field reads \"This field is required.\", not zod's\n // \"Expected 'draft' | 'published', received null\" (its own messages stay).\n for (const [name, entry] of Object.entries(result.errors)) {\n const error = entry as FieldError | undefined;\n if (\n error !== undefined &&\n required.has(name) &&\n isEmptyValue(values[name]) &&\n TYPE_ISSUES.has(String(error.type))\n ) {\n error.message = \"This field is required.\";\n }\n }\n return result;\n };\n }, [schema, mode]);\n\n const methods: UseFormReturn<FieldValues> = useForm<FieldValues>({\n resolver,\n values: initialValues,\n resetOptions: { keepDirtyValues: true },\n mode: validationMode,\n reValidateMode,\n shouldFocusError: false,\n });\n\n const { formState } = methods;\n const submitting =\n formState.isSubmitting || mutations.create.isPending || mutations.update.isPending;\n\n // --- unsaved changes ---------------------------------------------------\n /**\n * Set by a successful save until the form has been reset (which happens\n * once the submit has settled): saved values are never \"unsaved\".\n */\n const savedRef = React.useRef<\"create\" | \"update\" | null>(null);\n const dirty = formState.isDirty && savedRef.current === null;\n const guard = useUnsavedChangesGuard({ dirty, enabled: guardUnsavedChanges });\n const onDirtyChangeRef = React.useRef(onDirtyChange);\n onDirtyChangeRef.current = onDirtyChange;\n React.useEffect(() => {\n onDirtyChangeRef.current?.(dirty);\n }, [dirty]);\n\n // --- submit outcome state ----------------------------------------------\n const [submitError, setSubmitError] = React.useState<unknown>(null);\n const [rootMessages, setRootMessages] = React.useState<readonly string[]>([]);\n const [summaryShown, setSummaryShown] = React.useState(false);\n const [reloading, setReloading] = React.useState(false);\n const [announcement, setAnnouncement] = React.useState(\"\");\n const pendingFocus = React.useRef<PendingFocus | null>(null);\n const [focusTick, setFocusTick] = React.useState(0);\n const summaryRef = React.useRef<HTMLDivElement>(null);\n const bannerRef = React.useRef<HTMLDivElement>(null);\n const formRef = React.useRef<HTMLFormElement>(null);\n const inFlight = React.useRef(false);\n /** What had focus when the submit started, to give it back after a save. */\n const submitOrigin = React.useRef<HTMLElement | null>(null);\n\n const requestFocus = (target: PendingFocus): void => {\n pendingFocus.current = target;\n setFocusTick((tick) => tick + 1);\n };\n\n const labelOf = React.useCallback(\n (path: string): string =>\n visibleFields.find((field) => field.name === path)?.label ??\n humanizeValue(path.replace(/\\./g, \" \")),\n [visibleFields],\n );\n\n const focusField = React.useCallback(\n (name: string): void => {\n methods.setFocus(name);\n const element = document.getElementById(inputIdOf(name));\n if (element !== null && document.activeElement !== element) element.focus();\n },\n [methods, inputIdOf],\n );\n\n // Field errors in the order the fields appear, then extra fields.\n const fieldErrors: ResourceFormFieldError[] = [];\n for (const field of visibleFields) {\n const entry = errorAt(formState.errors, field.name);\n if (entry?.message !== undefined) {\n fieldErrors.push({\n name: field.name,\n label: field.label,\n message: entry.message,\n focus: () => focusField(field.name),\n href: `#${inputIdOf(field.name)}`,\n });\n }\n }\n for (const [name, entry] of Object.entries(formState.errors)) {\n if (name === \"root\" || visibleFields.some((field) => field.name === name)) continue;\n const message = (entry as FieldError | undefined)?.message;\n if (typeof message === \"string\") {\n fieldErrors.push({\n name,\n label: labelOf(name),\n message,\n focus: () => focusField(name),\n href: `#${inputIdOf(name)}`,\n });\n }\n }\n const problemCount = fieldErrors.length + rootMessages.length;\n\n const action = mode === \"create\" ? \"create\" : \"save\";\n const errorContext: KarniErrorContext =\n mode === \"create\"\n ? { action: \"create\", resource: names.plural }\n : { action: \"save\", resource: `this ${names.singular}` };\n\n /** After a submit the values failed: the summary when more than one thing is wrong, else the field. */\n const afterFailedValidation = (\n failing: ReadonlyArray<{ name: string; message: string }>,\n roots: readonly string[],\n ): void => {\n setSubmitError(null);\n if (failing.length + roots.length > 1 || roots.length > 0) {\n setSummaryShown(true);\n setAnnouncement(\"\");\n requestFocus({ kind: \"summary\" });\n return;\n }\n const only = failing[0];\n if (only === undefined) return;\n setSummaryShown(false);\n setAnnouncement(`${labelOf(only.name)}: ${only.message}`);\n requestFocus({ kind: \"field\", name: only.name });\n };\n\n /** The failing fields in the order the form shows them, extra fields last. */\n const failingFields = (\n errors: FieldErrors<FieldValues>,\n ): Array<{ name: string; message: string }> => {\n const shown = visibleFields.map((field) => field.name);\n const extra = Object.keys(errors).filter((name) => name !== \"root\" && !shown.includes(name));\n return [...shown, ...extra].flatMap((name) => {\n const message = errorAt(errors, name)?.message;\n return message !== undefined ? [{ name, message }] : [];\n });\n };\n\n const applyServerFailure = (error: unknown, raw: FieldValues): boolean => {\n const failure = apiFailure(error);\n if (failure === null || (failure.status !== 400 && failure.status !== 422)) return false;\n const shownNames = new Set(visibleFields.map((field) => field.name));\n const schemaNames = new Set(schema.fields.map((field) => field.name));\n const mapped = mapServerErrors(failure.data, {\n isField: (path) =>\n shownNames.has(path) || (!schemaNames.has(path.split(\".\")[0]) && hasValueAt(raw, path)),\n labelOf,\n });\n const names = Object.keys(mapped.fields);\n if (names.length === 0 && mapped.root.length === 0) return false;\n for (const [name, message] of Object.entries(mapped.fields)) {\n methods.setError(name, { type: \"server\", message });\n }\n if (mapped.root.length > 0) {\n // Kept on `root.server` too, for extraFields that read formState.\n methods.setError(\"root.server\", { type: \"server\", message: mapped.root.join(\" \") });\n }\n setRootMessages(mapped.root);\n const failing = [\n ...visibleFields.map((field) => field.name).filter((name) => names.includes(name)),\n ...names.filter((name) => !shownNames.has(name)),\n ].map((name) => ({ name, message: mapped.fields[name] ?? \"\" }));\n afterFailedValidation(failing, mapped.root);\n return true;\n };\n\n const submit = methods.handleSubmit(\n async (raw) => {\n setRootMessages([]);\n methods.clearErrors(\"root.server\");\n const { values, jsonErrors } = prepareSubmit({\n fields: formFields,\n raw,\n mode,\n dirtyFields: methods.formState.dirtyFields,\n });\n if (jsonErrors.length > 0) {\n for (const jsonError of jsonErrors) {\n methods.setError(jsonError.name, { type: \"validate\", message: jsonError.message });\n }\n afterFailedValidation(jsonErrors, []);\n return;\n }\n const payload = transformSubmit !== undefined ? transformSubmit(values) : values;\n let result: Record<string, unknown>;\n try {\n result =\n id === undefined\n ? await mutations.create.mutateAsync(payload)\n : await mutations.update.mutateAsync({ id, values: payload });\n } catch (error) {\n // The typed values stay: nothing below resets the form.\n if (!applyServerFailure(error, raw)) {\n setSummaryShown(false);\n setSubmitError(error);\n requestFocus({ kind: \"banner\" });\n }\n onError?.(error);\n return;\n }\n setSummaryShown(false);\n setSubmitError(null);\n // Clean before onSuccess, so a navigation made there is not blocked.\n // The form itself resets once the submit has settled (below):\n // react-hook-form's Controllers re-register stale values when reset\n // runs inside the submit handler.\n savedRef.current = mode;\n guard.setDirty(false);\n onDirtyChangeRef.current?.(false);\n setAnnouncement(mode === \"create\" ? `${humanizeValue(names.singular)} created.` : \"Saved.\");\n requestFocus({ kind: \"restore\", element: submitOrigin.current });\n onSuccess?.(result);\n },\n (errors) => {\n setRootMessages([]);\n methods.clearErrors(\"root.server\");\n afterFailedValidation(failingFields(errors), []);\n },\n );\n\n // One submit at a time, whatever starts it (button, Enter, Ctrl+Enter, \"Try again\").\n const runSubmit = (): void => {\n if (inFlight.current) return;\n inFlight.current = true;\n submitOrigin.current =\n document.activeElement instanceof HTMLElement ? document.activeElement : null;\n void submit().finally(() => {\n inFlight.current = false;\n });\n };\n\n // After a save, once the submit has settled: create starts over from the\n // initial values; edit makes the saved values the new baseline, so it is\n // clean at once (the refetched row then replaces them). keepDirtyValues is\n // switched off explicitly: reset() otherwise inherits the form's\n // resetOptions and would keep every typed value.\n React.useEffect(() => {\n const saved = savedRef.current;\n if (saved === null || submitting) return;\n if (saved === \"create\") methods.reset(initialValues, { keepDirtyValues: false });\n else methods.reset(methods.getValues(), { keepDirtyValues: false });\n savedRef.current = null;\n }, [focusTick, submitting, methods, initialValues]);\n\n // Focus moves once the submit has settled and the fields are enabled again.\n React.useEffect(() => {\n const target = pendingFocus.current;\n if (target === null || submitting) return;\n pendingFocus.current = null;\n switch (target.kind) {\n case \"field\":\n focusField(target.name);\n break;\n case \"summary\":\n summaryRef.current?.focus();\n break;\n case \"banner\":\n bannerRef.current?.focus();\n break;\n case \"restore\":\n if (\n target.element !== null &&\n target.element.isConnected &&\n (document.activeElement === null || document.activeElement === document.body)\n ) {\n target.element.focus();\n }\n break;\n }\n }, [focusTick, submitting, focusField]);\n\n // The summary goes once every problem is fixed.\n React.useEffect(() => {\n if (summaryShown && problemCount === 0) setSummaryShown(false);\n }, [summaryShown, problemCount]);\n\n // A field that gains an error when it loses focus is announced (the summary announces itself).\n const errorSignature = fieldErrors.map((entry) => `${entry.name}:${entry.message}`).join(\"|\");\n const previousErrors = React.useRef<ReadonlySet<string>>(new Set());\n React.useEffect(() => {\n const current = new Set(fieldErrors.map((entry) => entry.name ?? \"\"));\n const fresh = fieldErrors.find((entry) => !previousErrors.current.has(entry.name ?? \"\"));\n previousErrors.current = current;\n if (fresh !== undefined && !summaryShown) {\n setAnnouncement(`${fresh.label}: ${fresh.message}`);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- keyed on the error text, not the array identity\n }, [errorSignature]);\n\n // Autofocus: the first field, on create (or when asked).\n const shouldAutoFocus = autoFocus ?? mode === \"create\";\n const autoFocusTarget = visibleFields[0]?.name;\n React.useEffect(() => {\n if (shouldAutoFocus && autoFocusTarget !== undefined) focusField(autoFocusTarget);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- once, when the form appears\n }, []);\n\n const reload =\n reloadItem !== undefined\n ? () => {\n setReloading(true);\n void reloadItem().finally(() => {\n setReloading(false);\n setSubmitError(null);\n });\n }\n : undefined;\n\n const handleKeyDownCapture = (event: React.KeyboardEvent<HTMLFormElement>): void => {\n // Ctrl/Cmd+Enter submits from any control, a textarea or an open list included.\n if (\n event.key === \"Enter\" &&\n (event.metaKey || event.ctrlKey) &&\n !event.nativeEvent.isComposing\n ) {\n event.preventDefault();\n event.stopPropagation();\n runSubmit();\n }\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLFormElement>): void => {\n // Plain Enter in a one-line input submits natively through the submit\n // button; with `actions` that have none, submit here instead.\n if (event.key !== \"Enter\" || event.defaultPrevented || event.nativeEvent.isComposing) return;\n const target = event.target;\n if (!(target instanceof HTMLInputElement)) return;\n if ([\"checkbox\", \"radio\", \"file\", \"button\", \"submit\", \"reset\"].includes(target.type)) return;\n if (formRef.current?.querySelector(\"[type='submit']:not(:disabled)\") != null) return;\n event.preventDefault();\n runSubmit();\n };\n\n const fieldError = (name: string): string | undefined => errorAt(formState.errors, name)?.message;\n\n const SubmitErrorSlot = slots.SubmitError;\n const SummarySlot = slots.ErrorSummary;\n const summaryTitle =\n fieldErrors.length > 0\n ? `${fieldErrors.length} ${plural(fieldErrors.length, \"field needs\", \"fields need\")} attention`\n : `Couldn't ${action} ${mode === \"create\" ? names.singular : `this ${names.singular}`}`;\n\n return (\n <FormProvider {...methods}>\n <form\n ref={formRef}\n onSubmit={(event) => {\n event.preventDefault();\n runSubmit();\n }}\n onKeyDownCapture={handleKeyDownCapture}\n onKeyDown={handleKeyDown}\n noValidate\n aria-busy={submitting || undefined}\n className={cn(\"space-y-5\", className)}\n >\n {submitError !== null ? (\n <div ref={bannerRef} tabIndex={-1} className=\"rounded-md outline-none\">\n <SubmitErrorSlot\n error={submitError}\n context={errorContext}\n onRetry={runSubmit}\n retrying={submitting}\n onReload={reload}\n reloading={reloading}\n />\n </div>\n ) : null}\n {summaryShown && problemCount > 0 ? (\n <div ref={summaryRef} tabIndex={-1} className=\"rounded-md outline-none\">\n <SummarySlot\n title={summaryTitle}\n errors={[...fieldErrors, ...rootMessages.map((message) => ({ message }))]}\n />\n </div>\n ) : null}\n <fieldset disabled={submitting} className=\"m-0 min-w-0 space-y-5 border-0 p-0\">\n {formFields.map((field) => {\n const override = fieldOverrides?.[field.name];\n if (override?.hidden === true) return null;\n const shown = visibleFields.find((candidate) => candidate.name === field.name) ?? field;\n return (\n <FormFieldRow\n key={field.name}\n field={shown}\n inputId={inputIdOf(field.name)}\n override={override}\n control={methods.control}\n error={fieldError(field.name)}\n disabled={submitting}\n />\n );\n })}\n {extraFields}\n </fieldset>\n {actions !== undefined ? (\n actions\n ) : (\n <div className={SUBMIT_ROW}>\n <PendingButton\n type=\"submit\"\n pending={submitting}\n pendingLabel={mode === \"create\" ? \"Creating…\" : \"Saving…\"}\n >\n {submitLabel ?? (mode === \"create\" ? \"Create\" : \"Save changes\")}\n </PendingButton>\n </div>\n )}\n <p className=\"sr-only\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n {announcement}\n </p>\n </form>\n </FormProvider>\n );\n}\n\n/**\n * Schema-driven create and edit form for one resource: inputs, validation and\n * server errors derived from the OpenAPI schema.\n *\n * Contract \"ResourceForm\" + D2/D3/D10.\n *\n * Create mode POSTs every prepared value. Edit mode loads the UNEXPANDED\n * detail record and PATCHes only dirty fields at top-level granularity, with\n * emptied nullable fields sent as null (D3). Fields validate when they lose\n * focus. A failed submit keeps every typed value, puts DRF's messages on their\n * fields (a summary lists them when more than one fails) and moves focus there.\n * Any other failure (offline, 403, 409, 5xx) is a banner with \"Try again\" when\n * it can help. Escape hatches: per-field overrides (`fields`), `extraFields`,\n * `transformSubmit`, `actions`, `slots`, `validationMode` / `reValidateMode`\n * and `guardUnsavedChanges` / `onDirtyChange`.\n */\nexport function ResourceForm(props: ResourceFormProps): React.ReactElement {\n const { resource, id, slots: slotOverrides, resourceLabel, className } = props;\n const slots = React.useMemo(\n () => ({ ...defaultResourceFormSlots, ...slotOverrides }),\n [slotOverrides],\n );\n const names = resourceNames(resource, resourceLabel);\n const schemaResult = useSchema(resource);\n const isEdit = id !== undefined;\n const itemQuery = useResourceItem(resource, id ?? \"\", undefined, { enabled: isEdit });\n const mode = isEdit ? \"update\" : \"create\";\n\n if (schemaResult.error != null && schemaResult.data === undefined) {\n const ErrorSlot = slots.Error;\n return (\n <div className={className}>\n <ErrorSlot\n error={schemaResult.error}\n context={{ action: \"load\", resource: \"this form\" }}\n onRetry={schemaResult.refetch}\n retrying={schemaResult.isFetching}\n />\n </div>\n );\n }\n if (isEdit && itemQuery.error != null && itemQuery.data === undefined) {\n const forbidden =\n describeError(itemQuery.error).kind === \"forbidden\" ||\n apiFailure(itemQuery.error)?.status === 403;\n if (forbidden) {\n const ForbiddenSlot = slots.Forbidden;\n return (\n <div className={className}>\n <ForbiddenSlot action=\"edit\" resource={`this ${names.singular}`} />\n </div>\n );\n }\n const ErrorSlot = slots.Error;\n return (\n <div className={className}>\n <ErrorSlot\n error={itemQuery.error}\n context={{ action: \"load\", resource: `this ${names.singular}` }}\n onRetry={() => void itemQuery.refetch()}\n retrying={itemQuery.isFetching}\n />\n </div>\n );\n }\n if (schemaResult.data === undefined || (isEdit && itemQuery.data === undefined)) {\n const LoadingSlot = slots.Loading;\n const fields =\n schemaResult.data !== undefined\n ? shownFields(writableFields(schemaResult.data, props.fields), props.fields)\n : undefined;\n return (\n <div className={className}>\n <LoadingSlot\n fields={fields}\n mode={mode}\n submitLabel={props.submitLabel ?? (isEdit ? \"Save changes\" : \"Create\")}\n showSubmitRow={props.actions === undefined}\n />\n </div>\n );\n }\n return (\n <ResourceFormInner\n {...props}\n schema={schemaResult.data}\n item={isEdit ? itemQuery.data : undefined}\n names={names}\n slotsResolved={slots}\n reloadItem={isEdit ? () => itemQuery.refetch() : undefined}\n />\n );\n}\n","/**\n * The words a resource's messages use: \"events\" → \"event\" (\"Couldn't find\n * this event\"), \"loose-slots\" → \"loose slots\" (\"You can't import loose\n * slots\"). English rules only. Every component that words a message takes\n * a `resourceLabel` prop to name the resource in the project's own words.\n *\n * Internal to @karni/ui.\n */\n\n/** The router prefix as words: \"loose-slots\" → \"loose slots\". */\nexport function pluralNoun(resource: string): string {\n const spaced = resource.replace(/[_-]+/g, \" \").trim().toLowerCase();\n return spaced === \"\" ? resource : spaced;\n}\n\n/** One of the resource: \"events\" → \"event\", \"categories\" → \"category\", \"addresses\" → \"address\". */\nexport function singularNoun(resource: string): string {\n const plural = pluralNoun(resource);\n const words = plural.split(\" \");\n const last = words.pop() ?? plural;\n let single = last;\n if (/[^aeiou]ies$/.test(last)) single = `${last.slice(0, -3)}y`;\n else if (/(?:ss|sh|ch|x|z)es$/.test(last)) single = last.slice(0, -2);\n else if (/[^s]s$/.test(last)) single = last.slice(0, -1);\n return [...words, single].join(\" \");\n}\n","/**\n * Shared plumbing for the unhappy states of the resource components that\n * load one thing (ResourceDetail, ChangeHistory, ResourceImport).\n *\n * Internal to @karni/ui.\n */\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport * as React from \"react\";\nimport { KarniApiError } from \"../../schema/client\";\nimport { describeError } from \"../../states/describe-error\";\nimport { useOnlineStatus } from \"../../states/hooks\";\n\ntype RetryValue = boolean | number | ((failureCount: number, error: unknown) => boolean);\n\n/** A 4xx answer is the server's decision (not found, forbidden, invalid): asking again gives the same answer. */\nexport function isClientError(error: unknown): boolean {\n return error instanceof KarniApiError && error.status >= 400 && error.status < 500;\n}\n\n/**\n * The query client's own retry policy, except that a 4xx is never retried:\n * TanStack's default (three retries with backoff) would hold a \"Couldn't\n * find this event\" back for seven seconds.\n */\nexport function useRetryUnlessClientError(): (failureCount: number, error: unknown) => boolean {\n const configured = useQueryClient().getDefaultOptions().queries?.retry as RetryValue | undefined;\n return React.useCallback(\n (failureCount: number, error: unknown): boolean => {\n if (isClientError(error)) return false;\n if (typeof configured === \"function\") return configured(failureCount, error);\n if (typeof configured === \"number\") return failureCount < configured;\n if (typeof configured === \"boolean\") return configured;\n return failureCount < 3;\n },\n [configured],\n );\n}\n\n/**\n * Stands for \"the request is waiting for a connection\": TanStack Query\n * pauses queries while the browser is offline instead of failing them, and\n * this is what the Error slot receives then (describeError words it as\n * \"You're offline\").\n */\nexport function offlineError(): TypeError {\n return new TypeError(\"The browser is offline.\");\n}\n\n/**\n * Calls `retry` when the connection comes back while `error` is a network\n * failure, so an offline error clears itself without a click.\n */\nexport function useRetryWhenOnline(error: unknown, retry: () => void): void {\n const online = useOnlineStatus();\n const wasOnline = React.useRef(online);\n const retryRef = React.useRef(retry);\n retryRef.current = retry;\n const network =\n error !== null &&\n error !== undefined &&\n [\"offline\", \"network\"].includes(describeError(error).kind);\n React.useEffect(() => {\n const cameBack = online && !wasOnline.current;\n wasOnline.current = online;\n if (cameBack && network) retryRef.current();\n }, [online, network]);\n}\n","import { useIsFetching, useQueryClient } from \"@tanstack/react-query\";\nimport * as React from \"react\";\nimport { karniKeys } from \"../../../hooks/keys\";\nimport type { ResourceItemParams } from \"../../../hooks/types\";\nimport { useResourceItem } from \"../../../hooks/useResourceItem\";\nimport { useResourceMutations } from \"../../../hooks/useResourceMutations\";\nimport { cn } from \"../../../lib/cn\";\nimport { registerComponentRole } from \"../../../lib/roles\";\nimport type { FieldDef } from \"../../../schema/types\";\nimport { useSchema } from \"../../../schema/useSchema\";\nimport { describeError } from \"../../../states/describe-error\";\nimport { ErrorState, type ErrorSlotProps } from \"../../../states/ErrorState\";\nimport { useDelayedFlag, useOnlineStatus } from \"../../../states/hooks\";\nimport { PendingButton } from \"../../../states/PendingButton\";\nimport { Modal, ModalClose } from \"../../modal/modal\";\nimport { Button } from \"../../primitives/button\";\nimport { CheckIcon, SearchIcon } from \"../../primitives/icons\";\nimport { Skeleton } from \"../../primitives/skeleton\";\nimport { partitionAuditFields } from \"../audit-fields\";\nimport { displayLabel } from \"../displayLabel\";\nimport { EmptyValue } from \"../empty-value\";\nimport { humanizeValue } from \"../form/prepare\";\nimport { singularNoun } from \"../nouns\";\nimport { offlineError, useRetryUnlessClientError, useRetryWhenOnline } from \"../query-state\";\n\nregisterComponentRole(\"detail-view\", \"ResourceDetail\");\n\ntype Item = Record<string, unknown>;\n\nexport interface ResourceDetailFieldOverride {\n label?: string;\n hidden?: boolean;\n render?: (value: unknown, item: Record<string, unknown>) => React.ReactNode;\n}\n\n/** What the `Loading` slot receives. */\nexport interface ResourceDetailLoadingProps {\n /** The domain fields the record will show, in order. Undefined while the schema loads. */\n fields: readonly FieldDef[] | undefined;\n /** The audit fields of the \"Record\" group. Undefined while the schema loads. */\n auditFields: readonly FieldDef[] | undefined;\n /** True once loading has taken longer than SLOW_AFTER_MS (500ms): show the placeholder now. */\n slow: boolean;\n}\n\n/** What the `Error` slot receives: ErrorSlotProps plus the `back` prop. */\nexport interface ResourceDetailErrorProps extends ErrorSlotProps {\n /** The way out of the screen (the `back` prop). */\n back?: React.ReactNode;\n}\n\n/** What the `NotFound` slot receives (the backend answered 404). */\nexport interface ResourceDetailNotFoundProps {\n error: unknown;\n /** The resource in words, singular: \"event\". */\n resourceLabel: string;\n back?: React.ReactNode;\n}\n\n/** What the `Deleted` slot receives, after a delete from this view succeeded. */\nexport interface ResourceDetailDeletedProps {\n item: Item;\n resourceLabel: string;\n back?: React.ReactNode;\n}\n\n/** What the `EmptyValue` slot receives: a visible field with no value. */\nexport interface ResourceDetailEmptyValueProps {\n field: FieldDef;\n}\n\n/** What the `DeleteDialog` slot receives: the confirmation before a delete. */\nexport interface ResourceDetailDeleteDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n item: Item;\n /** displayLabel(item): \"Launch party\". */\n itemLabel: string;\n resourceLabel: string;\n onConfirm: () => void;\n /** True while the delete request runs. */\n pending: boolean;\n /** The failed attempt's error (null before an attempt and while one runs). */\n error: unknown;\n}\n\n/**\n * The replaceable parts of ResourceDetail. Pass any subset as `slots`.\n * `defaultResourceDetailSlots` holds Karni's own, to wrap them.\n */\nexport interface ResourceDetailSlots {\n /** The field placeholders while the record loads (the header is ResourceDetail's own). */\n Loading: React.ComponentType<ResourceDetailLoadingProps>;\n /** Any failure but a 404: offline, server error, 403, ... */\n Error: React.ComponentType<ResourceDetailErrorProps>;\n /** The backend answered 404: the record does not exist or is outside the user's scope. */\n NotFound: React.ComponentType<ResourceDetailNotFoundProps>;\n /** A visible field whose value is empty. */\n EmptyValue: React.ComponentType<ResourceDetailEmptyValueProps>;\n /** The delete confirmation. */\n DeleteDialog: React.ComponentType<ResourceDetailDeleteDialogProps>;\n /** Shown in place of the record once it is deleted from this view. */\n Deleted: React.ComponentType<ResourceDetailDeletedProps>;\n}\n\nexport interface ResourceDetailProps {\n resource: string;\n id: string | number;\n fields?: Record<string, ResourceDetailFieldOverride>;\n /** Appended below the field list (e.g. a child <ResourceTable>), even while the record loads. */\n sections?: ReadonlyArray<React.ReactNode>;\n expand?: readonly string[];\n /** The heading. A function receives the loaded record. A placeholder stands in until then. */\n title?: React.ReactNode | ((item: Item) => React.ReactNode);\n /** Shown in the header next to Edit and Delete. A function receives the loaded record. */\n actions?: React.ReactNode | ((item: Item) => React.ReactNode);\n /** The resource in words, singular, for messages (\"Couldn't find this event\"). Default: from `resource`. */\n resourceLabel?: string;\n /** A way back (a link or button to the list), shown when the record is missing, fails or is deleted. */\n back?: React.ReactNode;\n /** Shows an Edit button that calls this with the record. */\n onEdit?: (item: Item) => void;\n /** Whether the user may edit this record (the role, the record's state). Default true. */\n canEdit?: boolean | ((item: Item) => boolean);\n /** Shows a Delete button, which asks for confirmation first. */\n enableDelete?: boolean;\n /** Whether the user may delete this record. Default true. */\n canDelete?: boolean | ((item: Item) => boolean);\n /** Called after a confirmed delete succeeded (navigate away from here). */\n onDeleted?: (item: Item) => void;\n /** Replace parts of the view: Loading, Error, NotFound, EmptyValue, DeleteDialog, Deleted. */\n slots?: Partial<ResourceDetailSlots>;\n className?: string;\n}\n\nfunction fileBasename(url: string): string {\n const withoutQuery = url.split(/[?#]/, 1)[0] ?? url;\n const segments = withoutQuery.split(\"/\").filter((segment) => segment !== \"\");\n return segments[segments.length - 1] ?? url;\n}\n\nfunction formatDate(value: string): string {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(value);\n if (match !== null) {\n const date = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]));\n return date.toLocaleDateString();\n }\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? value : date.toLocaleDateString();\n}\n\nfunction formatDateTime(value: string): string {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? value : date.toLocaleString();\n}\n\nfunction RelationEntry({ value }: { value: unknown }): React.ReactElement {\n if (value !== null && typeof value === \"object\") {\n return <>{displayLabel(value as Record<string, unknown>)}</>;\n }\n return <code className=\"rounded bg-muted px-1 py-0.5 font-mono text-xs\">{String(value)}</code>;\n}\n\nfunction RelationValue({ value }: { value: unknown }): React.ReactElement {\n if (Array.isArray(value)) {\n return (\n <span className=\"flex flex-wrap gap-1.5\">\n {value.map((entry, index) => (\n <span\n key={index}\n className=\"inline-flex items-center rounded-sm bg-secondary px-1.5 py-0.5 text-xs text-secondary-foreground\"\n >\n <RelationEntry value={entry} />\n </span>\n ))}\n </span>\n );\n }\n return <RelationEntry value={value} />;\n}\n\nfunction isEmpty(value: unknown): boolean {\n return (\n value === undefined ||\n value === null ||\n value === \"\" ||\n (Array.isArray(value) && value.length === 0)\n );\n}\n\n/** Default value renderer per field kind, overridable per field via `fields`. */\nfunction DefaultValue(props: {\n field: FieldDef;\n value: unknown;\n Empty: React.ComponentType<ResourceDetailEmptyValueProps>;\n}): React.ReactElement {\n const { field, value, Empty } = props;\n if (isEmpty(value)) return <Empty field={field} />;\n switch (field.kind) {\n case \"boolean\":\n return <>{value ? \"Yes\" : \"No\"}</>;\n case \"date\":\n return <>{formatDate(String(value))}</>;\n case \"datetime\":\n return <>{formatDateTime(String(value))}</>;\n case \"enum\":\n return <>{field.enumLabels?.[String(value)] ?? humanizeValue(String(value))}</>;\n case \"relation\":\n return <RelationValue value={value} />;\n case \"file\":\n return (\n <a\n href={String(value)}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"rounded-sm font-medium text-primary underline underline-offset-4 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n >\n {fileBasename(String(value))}\n </a>\n );\n case \"json\":\n return (\n <pre className=\"overflow-x-auto rounded-md bg-muted p-3 text-xs\">\n {JSON.stringify(value, null, 2)}\n </pre>\n );\n case \"number\":\n case \"integer\":\n return <>{typeof value === \"number\" ? value.toLocaleString() : String(value)}</>;\n case \"array\":\n return <>{Array.isArray(value) ? value.map(String).join(\", \") : String(value)}</>;\n default:\n return <>{String(value)}</>;\n }\n}\n\nfunction DefaultEmptyValue(): React.ReactElement {\n return <EmptyValue />;\n}\n\n// loading\n\n/** Rows drawn before the schema has loaded (it usually is: the schema is fetched once per app). */\nconst PLACEHOLDER_ROWS = 5;\nconst VALUE_WIDTHS = [\"w-48\", \"w-64\", \"w-32\", \"w-56\", \"w-40\"] as const;\n\nfunction valueWidth(field: FieldDef | undefined, index: number): string {\n switch (field?.kind) {\n case \"boolean\":\n return \"w-10\";\n case \"number\":\n case \"integer\":\n return \"w-16\";\n case \"date\":\n return \"w-24\";\n case \"datetime\":\n return \"w-40\";\n default:\n return VALUE_WIDTHS[index % VALUE_WIDTHS.length] ?? \"w-48\";\n }\n}\n\n/** One placeholder row, the same height as a DetailRow with one line of text. */\nfunction RowPlaceholder(props: {\n field: FieldDef | undefined;\n index: number;\n muted: boolean;\n}): React.ReactElement {\n const { field, index, muted } = props;\n const bar = muted ? \"my-0.5 h-3\" : \"my-0.5 h-4\";\n return (\n <div className={cn(\"grid grid-cols-1 gap-1 sm:grid-cols-3 sm:gap-4\", muted ? \"py-2\" : \"py-3\")}>\n <div>\n <Skeleton className={cn(bar, muted ? \"w-20\" : \"w-24\")} />\n </div>\n <div className=\"sm:col-span-2\">\n {field?.kind === \"json\" && !muted ? (\n <Skeleton className=\"h-16 w-full\" />\n ) : (\n <Skeleton className={cn(bar, valueWidth(field, index))} />\n )}\n </div>\n </div>\n );\n}\n\n/**\n * The default `Loading` slot: the record's own layout (one row per field the\n * schema declares, then the \"Record\" group), drawn only once loading is\n * slow so a fast load never flashes it. The space is held from the start.\n */\nfunction DefaultLoading({\n fields,\n auditFields,\n slow,\n}: ResourceDetailLoadingProps): React.ReactElement {\n const domain: ReadonlyArray<FieldDef | undefined> =\n fields ?? Array.from({ length: PLACEHOLDER_ROWS }, () => undefined);\n return (\n <div\n className={cn(\"space-y-6\", !slow && \"invisible\")}\n aria-hidden=\"true\"\n data-testid=\"resource-detail-skeleton\"\n >\n <div className=\"[&>*+*]:border-t [&>*+*]:border-border\">\n {domain.map((field, index) => (\n <RowPlaceholder key={field?.name ?? index} field={field} index={index} muted={false} />\n ))}\n </div>\n {auditFields !== undefined && auditFields.length > 0 ? (\n <div className=\"rounded-md border border-border bg-muted-subtle px-4 py-2\">\n <div className=\"py-1\">\n <Skeleton className=\"my-0.5 h-3 w-14\" />\n </div>\n <div className=\"[&>*+*]:border-t [&>*+*]:border-border\">\n {auditFields.map((field, index) => (\n <RowPlaceholder key={field.name} field={field} index={index} muted />\n ))}\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\n// unhappy states\n\nfunction DefaultError({ back, ...props }: ResourceDetailErrorProps): React.ReactElement {\n return <ErrorState {...props} actions={back} />;\n}\n\nconst QUIET_PANEL =\n \"flex w-full flex-col items-center gap-2 rounded-lg border border-border bg-muted-subtle px-6 py-8 text-center\";\n\n/**\n * A 404. Karni answers 404 both for a record that does not exist and for one\n * outside the user's scope, so the words never say it exists.\n */\nfunction DefaultNotFound({ resourceLabel, back }: ResourceDetailNotFoundProps): React.ReactElement {\n return (\n <div role=\"alert\" data-error-kind=\"not-found\" className={QUIET_PANEL}>\n <SearchIcon className=\"mb-1 h-8 w-8 text-muted-foreground\" />\n <p className=\"text-base font-semibold text-foreground\">\n Couldn't find this {resourceLabel}\n </p>\n <p className=\"max-w-128 text-sm text-muted-foreground\">\n The link may be wrong, or the {resourceLabel} may have been deleted or not shared with you.\n </p>\n {back !== undefined && back !== null ? (\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">{back}</div>\n ) : null}\n </div>\n );\n}\n\nfunction DefaultDeleted({ resourceLabel, back }: ResourceDetailDeletedProps): React.ReactElement {\n return (\n <div className={QUIET_PANEL}>\n <CheckIcon className=\"mb-1 h-8 w-8 text-muted-foreground\" />\n <p className=\"text-base font-semibold text-foreground\">The {resourceLabel} was deleted</p>\n {back !== undefined && back !== null ? (\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">{back}</div>\n ) : null}\n </div>\n );\n}\n\nfunction DefaultDeleteDialog(props: ResourceDetailDeleteDialogProps): React.ReactElement {\n const { open, onOpenChange, itemLabel, resourceLabel, onConfirm, pending, error } = props;\n const errorRef = React.useRef<HTMLDivElement>(null);\n const failed = error !== null && error !== undefined;\n // A failed delete moves focus to what went wrong (the button it was on is disabled meanwhile).\n React.useEffect(() => {\n if (failed) errorRef.current?.focus();\n }, [failed, error]);\n return (\n <Modal\n open={open}\n onOpenChange={onOpenChange}\n title={`Delete this ${resourceLabel}?`}\n description={\n <>\n <span className=\"font-medium text-foreground\">{itemLabel}</span> will be deleted. This\n can't be undone.\n </>\n }\n footer={\n <>\n <ModalClose asChild>\n <Button variant=\"outline\" disabled={pending}>\n Cancel\n </Button>\n </ModalClose>\n <PendingButton\n variant=\"destructive\"\n pending={pending}\n pendingLabel=\"Deleting…\"\n onClick={onConfirm}\n >\n Delete\n </PendingButton>\n </>\n }\n >\n {failed ? (\n <ErrorState\n ref={errorRef}\n tabIndex={-1}\n variant=\"inline\"\n className=\"rounded-md border border-destructive-border bg-destructive-subtle p-3 focus:outline-none\"\n error={error}\n context={{ action: \"delete\", resource: `this ${resourceLabel}` }}\n />\n ) : null}\n </Modal>\n );\n}\n\n/** Karni's own slots, exported so a project can wrap one instead of rewriting it. */\nexport const defaultResourceDetailSlots: ResourceDetailSlots = {\n Loading: DefaultLoading,\n Error: DefaultError,\n NotFound: DefaultNotFound,\n EmptyValue: DefaultEmptyValue,\n DeleteDialog: DefaultDeleteDialog,\n Deleted: DefaultDeleted,\n};\n\nfunction DetailRow(props: {\n field: FieldDef;\n item: Record<string, unknown>;\n override: ResourceDetailFieldOverride | undefined;\n muted: boolean;\n Empty: React.ComponentType<ResourceDetailEmptyValueProps>;\n}): React.ReactElement {\n const { field, item, override, muted, Empty } = props;\n const value = item[field.name];\n return (\n <div\n className={cn(\n \"grid grid-cols-1 gap-1 sm:grid-cols-3 sm:gap-4\",\n muted ? \"py-2 text-xs\" : \"py-3 text-sm\",\n )}\n >\n <dt className=\"font-medium text-muted-foreground\">{override?.label ?? field.label}</dt>\n <dd className={cn(\"sm:col-span-2\", muted ? \"text-muted-foreground\" : \"text-foreground\")}>\n {override?.render !== undefined ? (\n override.render(value, item)\n ) : (\n <DefaultValue field={field} value={value} Empty={Empty} />\n )}\n </dd>\n </div>\n );\n}\n\nfunction allowed(rule: boolean | ((item: Item) => boolean) | undefined, item: Item): boolean {\n if (rule === undefined) return true;\n return typeof rule === \"function\" ? rule(item) : rule;\n}\n\n/** The fields a row shows: readable, known, not hidden by an override, and present in the payload. */\nfunction shownFields(\n fields: readonly FieldDef[],\n overrides: Record<string, ResourceDetailFieldOverride> | undefined,\n item: Item | undefined,\n): readonly FieldDef[] {\n return fields.filter(\n (field) =>\n !field.writeOnly &&\n field.kind !== \"unknown\" &&\n overrides?.[field.name]?.hidden !== true &&\n // A field the role may not read is absent from the payload: no row, no dash, no hint.\n (item === undefined || field.name in item),\n );\n}\n\n/**\n * Schema-driven read view of one row: every readable field, labelled and formatted.\n *\n * Contract \"ResourceDetail\": a definition list of every non-writeOnly field\n * the payload carries, with domain fields first (schema order), then the audit\n * fields (AUDIT_FIELDS: id, created_at, updated_at, created_by, updated_by)\n * in a visually muted \"Record\" group. A field the role may not read\n * (`Karni.field_roles`) is absent from the per-role schema and the payload,\n * so it has no row at all. A visible field with no value shows EmptyValue\n * (a dash, read as \"empty\"). Relations render through displayLabel when the\n * object is expanded (the field is in `expand`), else as the raw id in <code>.\n *\n * States: a placeholder in the record's own layout while it loads (drawn\n * after 500ms, the header in place from the start). A 404 shows \"Couldn't\n * find this <resource>\", and Karni also answers 404 for a record outside the\n * user's scope. Everything else shows describeError's words, with \"Try again\"\n * when it can help (it refetches the schema too when that failed). Offline\n * says so and reloads when the connection returns.\n *\n * Escape hatches: per-field `fields` overrides (label/hidden/render, audit\n * fields included), appended `sections`, the title/actions header, the\n * `canEdit`/`canDelete` predicates, and `slots` for every state.\n */\nexport function ResourceDetail(props: ResourceDetailProps): React.ReactElement {\n const {\n resource,\n id,\n fields,\n sections,\n expand,\n title,\n actions,\n resourceLabel,\n back,\n onEdit,\n canEdit,\n enableDelete = false,\n canDelete,\n onDeleted,\n slots,\n className,\n } = props;\n const Slots: ResourceDetailSlots = { ...defaultResourceDetailSlots, ...slots };\n const label = resourceLabel ?? singularNoun(resource);\n const recordHeadingId = React.useId();\n const queryClient = useQueryClient();\n const online = useOnlineStatus();\n const retry = useRetryUnlessClientError();\n\n const schemaResult = useSchema(resource);\n const schemaFetching = useIsFetching({ queryKey: karniKeys.schema() }) > 0;\n const { remove } = useResourceMutations(resource);\n const params: ResourceItemParams | undefined = React.useMemo(\n () => (expand !== undefined && expand.length > 0 ? { expand } : undefined),\n [expand],\n );\n const itemQuery = useResourceItem(resource, id, params, {\n retry,\n // Once deleted here, the record is gone: do not ask for it again.\n enabled: !remove.isSuccess,\n });\n\n const [deleteOpen, setDeleteOpen] = React.useState(false);\n const deletedRef = React.useRef<HTMLDivElement>(null);\n const deletedItem = remove.isSuccess ? itemQuery.data : undefined;\n const deleted = deletedItem !== undefined;\n React.useEffect(() => {\n if (deleted) deletedRef.current?.focus();\n }, [deleted]);\n // Closing the confirmation without deleting returns focus to the Delete\n // button (the dialog has no Radix trigger of its own to return it to).\n const deleteButtonRef = React.useRef<HTMLButtonElement>(null);\n const wasOpen = React.useRef(false);\n React.useEffect(() => {\n const closed = wasOpen.current && !deleteOpen;\n wasOpen.current = deleteOpen;\n if (!closed || remove.isSuccess) return undefined;\n const timer = setTimeout(() => deleteButtonRef.current?.focus(), 0);\n return () => clearTimeout(timer);\n }, [deleteOpen, remove.isSuccess]);\n\n const schema = schemaResult.data;\n const item = itemQuery.data;\n const schemaError = schema === undefined ? schemaResult.error : undefined;\n const itemError = itemQuery.error;\n // While a delete runs, the resource is refetched and this record 404s: that is the delete, not an error.\n const deleting = remove.isPending || remove.isSuccess;\n const blockingItemError =\n !deleting &&\n itemError !== null &&\n itemError !== undefined &&\n (item === undefined || !describeError(itemError).retryable);\n const error = schemaError != null ? schemaError : blockingItemError ? itemError : undefined;\n const loading = schema === undefined || item === undefined;\n const offline = error === undefined && loading && (!online || itemQuery.fetchStatus === \"paused\");\n const slow = useDelayedFlag(loading && error === undefined && !offline);\n\n const retryAll = React.useCallback((): void => {\n if (schemaResult.error != null && schemaResult.data === undefined) {\n void queryClient.refetchQueries({ queryKey: karniKeys.schema() });\n }\n if (itemQuery.error != null || itemQuery.data === undefined) void itemQuery.refetch();\n }, [queryClient, schemaResult.error, schemaResult.data, itemQuery]);\n useRetryWhenOnline(error, retryAll);\n const retrying = itemQuery.isFetching || schemaFetching;\n\n if (deletedItem !== undefined) {\n return (\n <div\n ref={deletedRef}\n tabIndex={-1}\n role=\"status\"\n className={cn(\"focus:outline-none\", className)}\n >\n <Slots.Deleted item={deletedItem} resourceLabel={label} back={back} />\n </div>\n );\n }\n\n if (error !== undefined) {\n if (error === itemError && describeError(error).kind === \"not-found\") {\n return (\n <div className={className}>\n <Slots.NotFound error={error} resourceLabel={label} back={back} />\n </div>\n );\n }\n return (\n <div className={className}>\n <Slots.Error\n error={error}\n context={{ action: \"view\", resource: `this ${label}` }}\n onRetry={retryAll}\n retrying={retrying}\n back={back}\n />\n </div>\n );\n }\n\n if (offline) {\n return (\n <div className={className}>\n <Slots.Error\n error={offlineError()}\n context={{ action: \"view\", resource: `this ${label}` }}\n onRetry={retryAll}\n retrying={false}\n back={back}\n />\n </div>\n );\n }\n\n const domainAndAudit =\n schema !== undefined\n ? partitionAuditFields(shownFields(schema.fields, fields, item))\n : undefined;\n const mayEdit = onEdit !== undefined && canEdit !== false;\n const mayDelete = enableDelete && canDelete !== false;\n const hasHeader = title !== undefined || actions !== undefined || mayEdit || mayDelete;\n\n const header = hasHeader ? (\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n {title === undefined ? (\n <div />\n ) : typeof title === \"function\" ? (\n item === undefined ? (\n <div className=\"py-1\">\n {/* Narrow enough on a phone to share the line with the buttons, as a short title does. */}\n <Skeleton className={cn(\"h-5 w-32 sm:w-48\", !slow && \"invisible\")} />\n </div>\n ) : (\n <h2 className=\"text-lg font-semibold tracking-tight\">{title(item)}</h2>\n )\n ) : (\n <h2 className=\"text-lg font-semibold tracking-tight\">{title}</h2>\n )}\n {actions !== undefined || mayEdit || mayDelete ? (\n <div className=\"flex flex-wrap items-center gap-2\">\n {item === undefined ? (\n <>\n {typeof actions === \"function\" ? (\n <Skeleton className={cn(\"h-10 w-24\", !slow && \"invisible\")} />\n ) : (\n actions\n )}\n {mayEdit ? <Skeleton className={cn(\"h-10 w-16\", !slow && \"invisible\")} /> : null}\n {mayDelete ? <Skeleton className={cn(\"h-10 w-20\", !slow && \"invisible\")} /> : null}\n </>\n ) : (\n <>\n {typeof actions === \"function\" ? actions(item) : actions}\n {onEdit !== undefined && mayEdit && allowed(canEdit, item) ? (\n <Button variant=\"outline\" onClick={() => onEdit(item)}>\n Edit\n </Button>\n ) : null}\n {mayDelete && allowed(canDelete, item) ? (\n <Button\n ref={deleteButtonRef}\n variant=\"outline\"\n onClick={() => {\n remove.reset();\n setDeleteOpen(true);\n }}\n >\n Delete\n </Button>\n ) : null}\n </>\n )}\n </div>\n ) : null}\n </div>\n ) : null;\n\n const appended =\n sections !== undefined && sections.length > 0 ? (\n <div className=\"space-y-6\">\n {sections.map((section, index) => (\n <div key={index}>{section}</div>\n ))}\n </div>\n ) : null;\n\n if (item === undefined || domainAndAudit === undefined) {\n const placeholder =\n schema !== undefined\n ? partitionAuditFields(shownFields(schema.fields, fields, undefined))\n : undefined;\n return (\n <div className={cn(\"space-y-6\", className)} aria-busy=\"true\">\n <span role=\"status\" aria-label=\"Loading details\" className=\"sr-only\">\n {slow ? `Loading this ${label}…` : \"\"}\n </span>\n {header}\n <Slots.Loading fields={placeholder?.domain} auditFields={placeholder?.audit} slow={slow} />\n {appended}\n </div>\n );\n }\n\n const { domain, audit } = domainAndAudit;\n return (\n <div className={cn(\"space-y-6\", className)}>\n {header}\n <dl className=\"[&>*+*]:border-t [&>*+*]:border-border\">\n {domain.map((field) => (\n <DetailRow\n key={field.name}\n field={field}\n item={item}\n override={fields?.[field.name]}\n muted={false}\n Empty={Slots.EmptyValue}\n />\n ))}\n </dl>\n {audit.length > 0 ? (\n <section\n aria-labelledby={recordHeadingId}\n className=\"rounded-md border border-border bg-muted-subtle px-4 py-2\"\n >\n <h3\n id={recordHeadingId}\n className=\"py-1 text-xs font-medium uppercase tracking-wide text-muted-foreground\"\n >\n Record\n </h3>\n <dl className=\"[&>*+*]:border-t [&>*+*]:border-border\">\n {audit.map((field) => (\n <DetailRow\n key={field.name}\n field={field}\n item={item}\n override={fields?.[field.name]}\n muted\n Empty={Slots.EmptyValue}\n />\n ))}\n </dl>\n </section>\n ) : null}\n {appended}\n {mayDelete ? (\n <Slots.DeleteDialog\n open={deleteOpen}\n onOpenChange={(open) => {\n if (!remove.isPending) setDeleteOpen(open);\n }}\n item={item}\n itemLabel={displayLabel(item)}\n resourceLabel={label}\n pending={remove.isPending}\n error={remove.error}\n onConfirm={() =>\n remove.mutate(id, {\n onSuccess: () => {\n setDeleteOpen(false);\n onDeleted?.(item);\n },\n })\n }\n />\n ) : null}\n </div>\n );\n}\n","/**\n * useChangeHistory: one row's field-level change history (karni.audit, ADR 0002 P4).\n *\n * `useChangeHistory(\"prices\", id)` fetches `GET /<resource>/<id>/history/`,\n * the paginated list a `BaseViewSet` serves for models that opt in with\n * `class Karni: audit = True`. The backend answers 404 for the rest, and\n * hides from each entry's `diff` the fields the requesting role may not see,\n * so the hook renders whatever it is given without filtering.\n */\nimport { useQuery, type UseQueryOptions, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useKarniClient } from \"../schema/provider\";\nimport { karniKeys } from \"./keys\";\nimport { detailPath } from \"./params\";\n\n/** `transition`: a StateField moved along a declared transition (`diff` holds `[from, to]`). */\nexport type ChangeAction = \"create\" | \"update\" | \"delete\" | \"restore\" | \"transition\";\n\nexport interface ChangeLogEntry {\n id: number;\n timestamp: string;\n actor: { id: string | number; email?: string } | null;\n action: ChangeAction;\n /** `{ field: [old, new] }`. A redacted field carries `\"[redacted]\"` on both sides. */\n diff: Record<string, [unknown, unknown]>;\n fields_changed: string[];\n}\n\nexport interface ChangeHistoryPage {\n count: number;\n next: string | null;\n previous: string | null;\n results: ChangeLogEntry[];\n}\n\nexport interface ChangeHistoryParams {\n /** Entries per page (the backend caps it). Default: the API's page size. */\n pageSize?: number;\n page?: number;\n}\n\n/** The query key of one row's change history. */\nexport function changeHistoryKey(\n resource: string,\n id: string | number,\n params?: ChangeHistoryParams,\n): readonly unknown[] {\n return [...karniKeys.resource(resource), \"history\", String(id), params ?? {}] as const;\n}\n\n/** Fetches one row's field-level change history (`GET /<resource>/<id>/history/`) for models with `audit = True`. */\nexport function useChangeHistory(\n resource: string,\n id: string | number,\n params?: ChangeHistoryParams,\n options?: Omit<UseQueryOptions<ChangeHistoryPage>, \"queryKey\" | \"queryFn\">,\n): UseQueryResult<ChangeHistoryPage> {\n const client = useKarniClient();\n return useQuery<ChangeHistoryPage>({\n ...options,\n queryKey: changeHistoryKey(resource, id, params),\n queryFn: ({ signal }) =>\n client.request<ChangeHistoryPage>(`${detailPath(resource, id)}history/`, {\n query: { page_size: params?.pageSize, page: params?.page },\n signal,\n }),\n });\n}\n","import * as React from \"react\";\nimport { useChangeHistory, type ChangeLogEntry } from \"../../../hooks/useChangeHistory\";\nimport { cn } from \"../../../lib/cn\";\nimport { registerComponentRole } from \"../../../lib/roles\";\nimport { ErrorState, type ErrorSlotProps } from \"../../../states/ErrorState\";\nimport { useDelayedFlag, useOnlineStatus } from \"../../../states/hooks\";\nimport { Skeleton } from \"../../primitives/skeleton\";\nimport { EmptyValue } from \"../empty-value\";\nimport { singularNoun } from \"../nouns\";\nimport { offlineError, useRetryUnlessClientError, useRetryWhenOnline } from \"../query-state\";\n\nregisterComponentRole(\"change-history\", \"ChangeHistory\");\n\n/** What the `Loading` slot receives. */\nexport interface ChangeHistoryLoadingProps {\n /** How many entry placeholders to draw. */\n rows: number;\n /** True once loading has taken longer than SLOW_AFTER_MS (500ms): show the placeholder now. */\n slow: boolean;\n}\n\n/** What the `Empty` slot receives: the row has no recorded change. */\nexport interface ChangeHistoryEmptyProps {\n /** The `empty` prop (\"No changes recorded.\" by default). */\n children: React.ReactNode;\n}\n\n/** What the `Entry` slot receives: one recorded change. */\nexport interface ChangeHistoryEntryProps {\n entry: ChangeLogEntry;\n}\n\n/**\n * The replaceable parts of ChangeHistory. Pass any subset as `slots`.\n * `defaultChangeHistorySlots` holds Karni's own, to wrap them.\n */\nexport interface ChangeHistorySlots {\n Loading: React.ComponentType<ChangeHistoryLoadingProps>;\n /** Any failure: offline, server error, 403, a model that keeps no history (404). */\n Error: React.ComponentType<ErrorSlotProps>;\n Empty: React.ComponentType<ChangeHistoryEmptyProps>;\n /** One entry of the list (rendered inside its <li>). */\n Entry: React.ComponentType<ChangeHistoryEntryProps>;\n}\n\nexport interface ChangeHistoryProps {\n resource: string;\n id: string | number;\n /** Entries to show (the backend paginates). Default: the API's page size. */\n pageSize?: number;\n title?: React.ReactNode;\n /** Shown when the row has no recorded changes. */\n empty?: React.ReactNode;\n /** The resource in words, singular, for messages (\"the history of this event\"). Default: from `resource`. */\n resourceLabel?: string;\n /** Replace parts of the list: Loading, Error, Empty, Entry. */\n slots?: Partial<ChangeHistorySlots>;\n className?: string;\n}\n\nconst ACTION_LABEL: Record<ChangeLogEntry[\"action\"], string> = {\n create: \"Created\",\n update: \"Updated\",\n delete: \"Deleted\",\n restore: \"Restored\",\n transition: \"Transitioned\",\n};\n\nfunction formatWhen(value: string): string {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? value : date.toLocaleString();\n}\n\nfunction Value({ value }: { value: unknown }): React.ReactElement {\n if (value === null || value === undefined || value === \"\") {\n return <EmptyValue />;\n }\n if (value === \"[redacted]\") {\n return <span className=\"italic text-muted-foreground\">redacted</span>;\n }\n const text = typeof value === \"object\" ? JSON.stringify(value) : String(value);\n return <span className=\"break-words\">{text}</span>;\n}\n\nfunction DefaultEntry({ entry }: ChangeHistoryEntryProps): React.ReactElement {\n const fields = Object.entries(entry.diff);\n return (\n <>\n <div className=\"flex flex-wrap items-baseline gap-x-3 gap-y-1\">\n <span className=\"font-medium\">{ACTION_LABEL[entry.action] ?? entry.action}</span>\n <time dateTime={entry.timestamp} className=\"text-muted-foreground\">\n {formatWhen(entry.timestamp)}\n </time>\n <span className=\"text-muted-foreground\">\n {entry.actor?.email ?? <EmptyValue label=\"no user recorded\" />}\n </span>\n </div>\n {fields.length > 0 ? (\n <dl className=\"mt-2 grid grid-cols-[max-content_1fr] items-baseline gap-x-3 gap-y-1\">\n {fields.map(([name, [before, after]]) => (\n <React.Fragment key={name}>\n <dt className=\"font-mono text-xs text-muted-foreground\">{name}</dt>\n <dd className=\"flex flex-wrap items-center gap-2\">\n <Value value={before} />\n <span aria-hidden=\"true\" className=\"text-muted-foreground\">\n →\n </span>\n <span className=\"sr-only\">changed to</span>\n <Value value={after} />\n </dd>\n </React.Fragment>\n ))}\n </dl>\n ) : (\n <p className=\"mt-2 text-muted-foreground\">No visible field changed.</p>\n )}\n </>\n );\n}\n\n/** Entry cards in the list's own layout, drawn only once loading is slow (the space is held). */\nfunction DefaultLoading({ rows, slow }: ChangeHistoryLoadingProps): React.ReactElement {\n return (\n <div\n className={cn(\"space-y-2\", !slow && \"invisible\")}\n aria-hidden=\"true\"\n data-testid=\"change-history-loading\"\n >\n {Array.from({ length: rows }, (_, index) => (\n <div key={index} className=\"rounded-md border bg-card p-3 text-sm\">\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1\">\n <Skeleton className=\"my-0.5 h-4 w-16\" />\n <Skeleton className=\"my-0.5 h-4 w-36\" />\n <Skeleton className=\"my-0.5 h-4 w-28\" />\n </div>\n <div className=\"mt-2 grid grid-cols-[max-content_1fr] items-center gap-x-3 gap-y-1\">\n <Skeleton className=\"h-3 w-16\" />\n <Skeleton className={cn(\"my-0.5 h-4\", index % 2 === 0 ? \"w-40\" : \"w-32\")} />\n <Skeleton className=\"h-3 w-12\" />\n <Skeleton className={cn(\"my-0.5 h-4\", index % 2 === 0 ? \"w-32\" : \"w-48\")} />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction DefaultEmpty({ children }: ChangeHistoryEmptyProps): React.ReactElement {\n return <p className=\"text-sm text-muted-foreground\">{children}</p>;\n}\n\n/** Karni's own slots, exported so a project can wrap one instead of rewriting it. */\nexport const defaultChangeHistorySlots: ChangeHistorySlots = {\n Loading: DefaultLoading,\n Error: ErrorState,\n Empty: DefaultEmpty,\n Entry: DefaultEntry,\n};\n\n/** Placeholder entries while the history loads (a page rarely starts with more on screen). */\nconst PLACEHOLDER_ENTRIES = 3;\n\n/**\n * The field-level change history of one row: when, by whom, what changed\n * from what to what. Reads `GET /<resource>/<id>/history/` (models that opt\n * in with `class Karni: audit = True`). Fields the role may not see are\n * already absent from each diff, redacted ones say so, and an empty value\n * is the shared EmptyValue (a dash, read as \"empty\").\n *\n * States: entry placeholders while it loads (drawn after 500ms), failures\n * in describeError's words with \"Try again\" when it can help. A 403 reads\n * \"You can't view the history of this <resource>\". Offline says so and\n * reloads when the connection returns. Escape hatch: `slots`.\n */\nexport function ChangeHistory({\n resource,\n id,\n pageSize,\n title = \"History\",\n empty = \"No changes recorded.\",\n resourceLabel,\n slots,\n className,\n}: ChangeHistoryProps): React.ReactElement {\n const Slots: ChangeHistorySlots = { ...defaultChangeHistorySlots, ...slots };\n const label = resourceLabel ?? singularNoun(resource);\n const retry = useRetryUnlessClientError();\n const online = useOnlineStatus();\n const query = useChangeHistory(resource, id, pageSize !== undefined ? { pageSize } : undefined, {\n retry,\n });\n const error = query.data === undefined ? query.error : null;\n const offline =\n query.data === undefined && error == null && (!online || query.fetchStatus === \"paused\");\n const loading = query.data === undefined && error == null && !offline;\n const slow = useDelayedFlag(loading);\n const refetch = React.useCallback((): void => {\n void query.refetch();\n }, [query]);\n useRetryWhenOnline(error, refetch);\n const context = { action: \"view\", resource: `the history of this ${label}` };\n\n let body: React.ReactNode;\n if (error !== null && error !== undefined) {\n body = (\n <Slots.Error error={error} context={context} onRetry={refetch} retrying={query.isFetching} />\n );\n } else if (offline) {\n body = (\n <Slots.Error error={offlineError()} context={context} onRetry={refetch} retrying={false} />\n );\n } else if (query.data === undefined) {\n body = (\n <>\n <span role=\"status\" className=\"sr-only\">\n {slow ? \"Loading the history…\" : \"\"}\n </span>\n <Slots.Loading\n rows={Math.min(pageSize ?? PLACEHOLDER_ENTRIES, PLACEHOLDER_ENTRIES)}\n slow={slow}\n />\n </>\n );\n } else if (query.data.results.length === 0) {\n body = <Slots.Empty>{empty}</Slots.Empty>;\n } else {\n body = (\n <ol className=\"space-y-2\">\n {query.data.results.map((entry) => (\n <li\n key={entry.id}\n className=\"rounded-md border bg-card p-3 text-sm\"\n data-action={entry.action}\n >\n <Slots.Entry entry={entry} />\n </li>\n ))}\n </ol>\n );\n }\n\n return (\n <section\n className={cn(\"space-y-3\", className)}\n aria-label=\"Change history\"\n aria-busy={loading || undefined}\n >\n {title !== null ? <h3 className=\"text-base font-semibold\">{title}</h3> : null}\n {body}\n </section>\n );\n}\n","import * as React from \"react\";\nimport {\n downloadImportTemplate,\n isImportInFlight,\n useImportActions,\n useImportDescribe,\n useImportJob,\n type ImportColumn,\n type ImportJob,\n type ImportProblem,\n type ImportResult,\n} from \"../../../hooks/useResourceImport\";\nimport { cn } from \"../../../lib/cn\";\nimport { registerComponentRole } from \"../../../lib/roles\";\nimport { KarniApiError } from \"../../../schema/client\";\nimport { useKarniClient } from \"../../../schema/provider\";\nimport { describeError } from \"../../../states/describe-error\";\nimport { ErrorState, type ErrorSlotProps } from \"../../../states/ErrorState\";\nimport { useDelayedFlag, useOnlineStatus } from \"../../../states/hooks\";\nimport { PendingButton } from \"../../../states/PendingButton\";\nimport { Modal, ModalClose } from \"../../modal/modal\";\nimport { Button } from \"../../primitives/button\";\nimport { AlertIcon, LockIcon, OfflineIcon } from \"../../primitives/icons\";\nimport { Input } from \"../../primitives/input\";\nimport { Label } from \"../../primitives/label\";\nimport { Select } from \"../../primitives/select\";\nimport { Skeleton } from \"../../primitives/skeleton\";\nimport { EmptyValue } from \"../empty-value\";\nimport { pluralNoun } from \"../nouns\";\nimport { offlineError, useRetryUnlessClientError, useRetryWhenOnline } from \"../query-state\";\n\nregisterComponentRole(\"resource-import\", \"ResourceImport\");\n\n/** What the `Loading` slot receives while the import description loads. */\nexport interface ResourceImportLoadingProps {\n /** True once loading has taken longer than SLOW_AFTER_MS (500ms): show the placeholder now. */\n slow: boolean;\n}\n\n/** What the `Progress` slot receives while the backend previews or commits a job. */\nexport interface ImportProgressProps {\n job: ImportJob;\n}\n\n/** What the `Summary` slot receives: a preview's or a commit's counts. */\nexport interface ImportSummaryProps {\n job: ImportJob;\n result: ImportResult;\n}\n\n/** What the `Problems` slot receives: the rows the backend refused, with why. */\nexport interface ImportProblemsProps {\n job: ImportJob;\n problems: readonly ImportProblem[];\n}\n\n/** What the `ConfirmCommit` slot receives: the step between a preview and its commit. */\nexport interface ImportConfirmProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n job: ImportJob;\n /** The preview's counts: what the commit will do. */\n result: ImportResult;\n /** The resource in words, plural: \"events\". */\n resourceLabel: string;\n onConfirm: () => void;\n /** True while the commit request runs. */\n pending: boolean;\n /** Why the last commit attempt failed (null before an attempt and while one runs). */\n error: unknown;\n}\n\n/**\n * The replaceable parts of ResourceImport. Pass any subset as `slots`.\n * `defaultResourceImportSlots` holds Karni's own, to wrap them.\n */\nexport interface ResourceImportSlots {\n /** The upload form's placeholder while the import description loads. */\n Loading: React.ComponentType<ResourceImportLoadingProps>;\n /** A failure: loading what the import accepts, an upload, a preview. */\n Error: React.ComponentType<ErrorSlotProps>;\n /** A running preview or commit. */\n Progress: React.ComponentType<ImportProgressProps>;\n /** Created / updated / skipped counts. */\n Summary: React.ComponentType<ImportSummaryProps>;\n /** The table of rows with errors. */\n Problems: React.ComponentType<ImportProblemsProps>;\n /** The confirmation before a commit. */\n ConfirmCommit: React.ComponentType<ImportConfirmProps>;\n}\n\nexport interface ResourceImportProps {\n resource: string;\n title?: React.ReactNode;\n /** Called when a commit finishes (the job is `done`). */\n onDone?: (job: ImportJob) => void;\n /** The resource in words, plural, for messages (\"You can't import events\"). Default: from `resource`. */\n resourceLabel?: string;\n /** Replace parts of the flow: Loading, Error, Progress, Summary, Problems, ConfirmCommit. */\n slots?: Partial<ResourceImportSlots>;\n className?: string;\n}\n\nfunction plural(count: number, one: string, many: string): string {\n return `${count.toLocaleString()} ${count === 1 ? one : many}`;\n}\n\n/** The backend's own explanation of a refused file or mapping (a KarniValueError or a field error). */\nfunction refusal(error: unknown): string | undefined {\n if (!(error instanceof KarniApiError) || typeof error.data !== \"object\" || error.data === null) {\n return undefined;\n }\n const data = error.data as Record<string, unknown>;\n if (typeof data[\"detail\"] === \"string\") return data[\"detail\"];\n for (const value of Object.values(data)) {\n if (typeof value === \"string\") return value;\n if (Array.isArray(value) && typeof value[0] === \"string\") return value[0];\n }\n return undefined;\n}\n\nconst VALIDATION_TITLES: Record<string, string> = {\n upload: \"This file can't be imported\",\n preview: \"This mapping can't be previewed\",\n commit: \"This import can't be committed\",\n};\n\nconst ERROR_ICONS: Partial<Record<string, React.ComponentType<{ className?: string }>>> = {\n forbidden: LockIcon,\n offline: OfflineIcon,\n network: OfflineIcon,\n};\n\n/**\n * The default `Error` slot. When loading what the import accepts fails, the\n * whole step is ErrorState's panel. A failed upload or preview is a compact\n * alert under the form it came from, and a refused file or mapping (a 400)\n * says what the backend objected to.\n */\nfunction DefaultImportError(props: ErrorSlotProps): React.ReactElement {\n const { error, context, onRetry, retrying = false } = props;\n if (context?.action === \"import\") return <ErrorState {...props} />;\n const described = describeError(error, context);\n const refused = described.kind === \"validation\";\n const Icon = ERROR_ICONS[described.kind] ?? AlertIcon;\n return (\n <div\n role=\"alert\"\n data-error-kind={described.kind}\n className=\"flex items-start gap-2 rounded-md border border-destructive-border bg-destructive-subtle p-3 text-sm\"\n >\n <Icon className=\"mt-0.5 h-4 w-4 shrink-0 text-destructive\" />\n <div className=\"min-w-0 flex-1 space-y-1\">\n <p className=\"font-medium text-foreground\">\n {refused\n ? (VALIDATION_TITLES[context?.action ?? \"\"] ?? \"This can't be imported\")\n : described.title}\n </p>\n <p className=\"text-muted-foreground\">\n {refused\n ? (refusal(error) ?? \"Check the file against the template, then try again.\")\n : described.description}\n </p>\n {!refused && described.detail !== undefined ? (\n <p className=\"text-xs text-muted-foreground\">{described.detail}</p>\n ) : null}\n {described.retryable && onRetry !== undefined ? (\n <div className=\"pt-2\">\n <PendingButton\n variant=\"outline\"\n size=\"sm\"\n onClick={onRetry}\n pending={retrying}\n pendingLabel=\"Trying again…\"\n >\n Try again\n </PendingButton>\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n\nfunction DefaultImportLoading({ slow }: ResourceImportLoadingProps): React.ReactElement {\n return (\n <div\n className={cn(\"space-y-3\", !slow && \"invisible\")}\n aria-hidden=\"true\"\n data-testid=\"resource-import-loading\"\n >\n <div className=\"flex flex-wrap items-end gap-3\">\n <div className=\"grid w-full max-w-96 gap-1.5\">\n <Skeleton className=\"h-3.5 w-24\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n <Skeleton className=\"h-10 w-20\" />\n </div>\n {/* The hint: one line, two on a phone. */}\n <div className=\"space-y-1\">\n <Skeleton className=\"my-0.5 h-3 w-96 max-w-full\" />\n <Skeleton className=\"my-0.5 h-3 w-40 sm:hidden\" />\n </div>\n </div>\n );\n}\n\nfunction Stat({ label, value }: { label: string; value: React.ReactNode }): React.ReactElement {\n return (\n <div>\n <dt className=\"text-xs uppercase text-muted-foreground\">{label}</dt>\n <dd className=\"text-2xl font-semibold tabular-nums\">{value}</dd>\n </div>\n );\n}\n\nfunction DefaultSummary({ result }: ImportSummaryProps): React.ReactElement {\n const { created, updated, skipped, unchanged, errors } = result;\n return (\n <dl className=\"flex flex-wrap gap-6\" data-testid=\"import-stats\">\n <Stat label=\"Created\" value={created} />\n <Stat label=\"Updated\" value={updated} />\n <Stat\n label=\"Skipped\"\n value={\n <>\n {skipped}{\" \"}\n <span className=\"text-sm font-normal text-muted-foreground\">\n ({unchanged} unchanged, {errors} with errors)\n </span>\n </>\n }\n />\n </dl>\n );\n}\n\nfunction DefaultProblems({ problems }: ImportProblemsProps): React.ReactElement {\n return (\n <div className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full text-sm\">\n <caption className=\"px-3 py-2 text-left text-sm font-medium text-foreground\">\n Rows with errors\n </caption>\n <thead className=\"bg-muted text-left text-xs uppercase text-muted-foreground\">\n <tr>\n <th scope=\"col\" className=\"px-3 py-2 font-medium\">\n Row\n </th>\n <th scope=\"col\" className=\"px-3 py-2 font-medium\">\n Field\n </th>\n <th scope=\"col\" className=\"px-3 py-2 font-medium\">\n Problem\n </th>\n </tr>\n </thead>\n <tbody>\n {problems.map((problem, index) => (\n <tr key={`${problem.row}-${problem.field}-${index}`} className=\"border-t border-border\">\n <th scope=\"row\" className=\"px-3 py-2 text-left font-normal tabular-nums\">\n {problem.row}\n </th>\n <td className=\"px-3 py-2 font-mono text-xs\">\n {problem.field || <EmptyValue label=\"the whole row\" />}\n </td>\n <td className=\"px-3 py-2\">{problem.message}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\n/**\n * A running preview or commit. The bar is a `progressbar`. The polite\n * announcement changes only at each quarter, so a screen reader is not\n * read every poll (1.5s).\n */\nfunction DefaultProgress({ job }: ImportProgressProps): React.ReactElement {\n const percent = job.rows_total > 0 ? Math.round((job.rows_done * 100) / job.rows_total) : 0;\n const verb = job.status === \"previewing\" ? \"Previewing\" : \"Committing\";\n const quarter = Math.min(100, Math.floor(percent / 25) * 25);\n return (\n <div className=\"space-y-2\">\n <p className=\"text-sm tabular-nums\">\n {verb}… {job.rows_done.toLocaleString()} / {job.rows_total.toLocaleString()} rows\n </p>\n <div\n role=\"progressbar\"\n aria-label={`${verb} ${job.file_name}`}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={percent}\n aria-valuetext={`${job.rows_done} of ${job.rows_total} rows`}\n className=\"h-2 w-full overflow-hidden rounded-full bg-muted\"\n >\n <div className=\"h-full bg-primary transition-all\" style={{ width: `${percent}%` }} />\n </div>\n <span role=\"status\" className=\"sr-only\">\n {`${verb} ${plural(job.rows_total, \"row\", \"rows\")}: ${quarter}% done.`}\n </span>\n </div>\n );\n}\n\nfunction DefaultConfirmCommit(props: ImportConfirmProps): React.ReactElement {\n const { open, onOpenChange, job, result, resourceLabel, onConfirm, pending, error } = props;\n const errorRef = React.useRef<HTMLDivElement>(null);\n const failed = error !== null && error !== undefined;\n React.useEffect(() => {\n if (failed) errorRef.current?.focus();\n }, [failed, error]);\n const saved = result.created + result.updated;\n return (\n <Modal\n open={open}\n onOpenChange={onOpenChange}\n title=\"Commit this import?\"\n description={`${job.file_name}: ${plural(saved, \"row\", \"rows\")} will be saved to ${resourceLabel}.`}\n footer={\n <>\n <ModalClose asChild>\n <Button variant=\"outline\" disabled={pending}>\n Cancel\n </Button>\n </ModalClose>\n <PendingButton pending={pending} pendingLabel=\"Committing…\" onClick={onConfirm}>\n Commit import\n </PendingButton>\n </>\n }\n >\n <dl className=\"grid grid-cols-2 gap-4 sm:grid-cols-4\" data-testid=\"import-confirm-counts\">\n <Stat label=\"Created\" value={result.created} />\n <Stat label=\"Updated\" value={result.updated} />\n <Stat label=\"Unchanged\" value={result.unchanged} />\n <Stat label=\"Failed\" value={result.errors} />\n </dl>\n {result.errors > 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {plural(result.errors, \"row has\", \"rows have\")} errors and will not be imported. Fix them\n in the file and import it again.\n </p>\n ) : null}\n {failed ? (\n <div ref={errorRef} tabIndex={-1} className=\"focus:outline-none\">\n <ErrorState\n variant=\"inline\"\n className=\"rounded-md border border-destructive-border bg-destructive-subtle p-3\"\n error={error}\n context={{ action: \"import\", resource: resourceLabel }}\n />\n </div>\n ) : null}\n </Modal>\n );\n}\n\n/** Karni's own slots, exported so a project can wrap one instead of rewriting it. */\nexport const defaultResourceImportSlots: ResourceImportSlots = {\n Loading: DefaultImportLoading,\n Error: DefaultImportError,\n Progress: DefaultProgress,\n Summary: DefaultSummary,\n Problems: DefaultProblems,\n ConfirmCommit: DefaultConfirmCommit,\n};\n\nfunction MappingTable(props: {\n job: ImportJob;\n fields: readonly ImportColumn[];\n mapping: Record<string, string>;\n onChange: (header: string, field: string) => void;\n}): React.ReactElement {\n const { job, fields, mapping, onChange } = props;\n const options = fields.map((field) => ({\n value: field.name,\n label: `${field.name}${field.required ? \" *\" : \"\"}${field.key ? \" (key)\" : \"\"}`,\n }));\n return (\n <div className=\"overflow-x-auto rounded-md border border-border\">\n <table className=\"w-full text-sm\">\n <caption className=\"sr-only\">Column mapping</caption>\n <thead className=\"bg-muted text-left text-xs uppercase text-muted-foreground\">\n <tr>\n <th scope=\"col\" className=\"px-3 py-2 font-medium\">\n Column in the file\n </th>\n <th scope=\"col\" className=\"px-3 py-2 font-medium\">\n Field\n </th>\n </tr>\n </thead>\n <tbody>\n {job.columns.map((header) => (\n <tr key={header} className=\"border-t border-border\">\n <th scope=\"row\" className=\"px-3 py-2 text-left font-normal\">\n {header}\n </th>\n <td className=\"px-3 py-2\">\n <Select\n aria-label={`Field for ${header}`}\n className=\"h-9 w-auto min-w-48\"\n value={mapping[header] ?? \"\"}\n options={options}\n clearable\n clearLabel=\"Ignore this column\"\n onValueChange={(next) => onChange(header, next ?? \"\")}\n />\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\n/** A request TanStack holds back while the browser is offline: it is sent when the connection returns. */\nfunction WaitingForConnection({ what }: { what: string }): React.ReactElement {\n return (\n <p role=\"status\" className=\"text-sm text-muted-foreground\">\n You're offline. The {what} will be sent when you're back online.\n </p>\n );\n}\n\ntype Step = \"upload\" | \"map\" | \"progress\" | \"previewed\" | \"done\";\n\nfunction stepOf(job: ImportJob | undefined, remap: boolean): Step {\n if (job === undefined) return \"upload\";\n if (isImportInFlight(job)) return \"progress\";\n if (job.status === \"uploaded\" || job.status === \"failed\" || remap) return \"map\";\n return job.status === \"done\" ? \"done\" : \"previewed\";\n}\n\n/**\n * Import a CSV or XLSX file into a resource: upload, map columns to fields,\n * preview (the mandatory dry run, which shows N created / updated / skipped\n * with every row's errors), confirm, then commit. Drives\n * `/<resource>/import/…`. The backend validates every row through the same\n * serializer the API uses, keeps rows inside the user's scope and refuses\n * fields the role may not write. Large files run in the background with\n * progress.\n *\n * States: a placeholder in the form's layout while the import description\n * loads (drawn after 500ms). When that fails the form is not shown: a 403\n * reads \"You can't import <resource>\". A failed upload keeps the chosen file,\n * offers \"Try again\" when it can help and moves focus to the error. Offline\n * requests wait for the connection and say so. Escape hatch: `slots`.\n */\nexport function ResourceImport({\n resource,\n title = \"Import\",\n onDone,\n resourceLabel,\n slots,\n className,\n}: ResourceImportProps): React.ReactElement {\n const Slots: ResourceImportSlots = { ...defaultResourceImportSlots, ...slots };\n const label = resourceLabel ?? pluralNoun(resource);\n const client = useKarniClient();\n const retry = useRetryUnlessClientError();\n const online = useOnlineStatus();\n const describe = useImportDescribe(resource, { retry });\n const actions = useImportActions(resource);\n const [jobId, setJobId] = React.useState<string | undefined>(undefined);\n const [mapping, setMapping] = React.useState<Record<string, string>>({});\n const [remap, setRemap] = React.useState(false);\n const [file, setFile] = React.useState<File | null>(null);\n const [confirmOpen, setConfirmOpen] = React.useState(false);\n const [templateError, setTemplateError] = React.useState<unknown>(null);\n const fileId = React.useId();\n const hintId = React.useId();\n const uploadErrorRef = React.useRef<HTMLDivElement>(null);\n const stepRef = React.useRef<HTMLDivElement>(null);\n const jobQuery = useImportJob(resource, jobId);\n const job = jobQuery.data;\n\n // The job's mapping (suggested or remembered) seeds the editable one.\n const seededFor = React.useRef<string | undefined>(undefined);\n React.useEffect(() => {\n if (job !== undefined && seededFor.current !== job.id) {\n seededFor.current = job.id;\n setMapping(job.mapping);\n }\n }, [job]);\n\n React.useEffect(() => {\n if (job?.status === \"done\") onDone?.(job);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- fire once per completion\n }, [job?.status, job?.id]);\n\n const { upload, preview, commit } = actions;\n const busy = upload.isPending || preview.isPending || commit.isPending;\n const step = stepOf(job, remap);\n\n // Each step that replaces the one the user acted on takes the focus, so\n // keyboard and screen reader users land on what happened. The timer runs\n // after a closing dialog has restored focus to its (now gone) trigger.\n const shownStep = React.useRef(step);\n React.useEffect(() => {\n if (shownStep.current === step) return undefined;\n shownStep.current = step;\n const timer = setTimeout(() => stepRef.current?.focus(), 0);\n return () => clearTimeout(timer);\n }, [step]);\n\n // Cancelling the confirmation returns focus to Commit (the dialog has no\n // Radix trigger of its own to return it to); a commit moves on to its step.\n const commitButtonRef = React.useRef<HTMLButtonElement>(null);\n const wasConfirming = React.useRef(false);\n React.useEffect(() => {\n const closed = wasConfirming.current && !confirmOpen;\n wasConfirming.current = confirmOpen;\n if (!closed) return undefined;\n const timer = setTimeout(() => commitButtonRef.current?.focus(), 0);\n return () => clearTimeout(timer);\n }, [confirmOpen]);\n\n // A failed upload moves focus to what went wrong; the chosen file stays.\n React.useEffect(() => {\n if (upload.error !== null && upload.error !== undefined) uploadErrorRef.current?.focus();\n }, [upload.error]);\n\n const describeLoading = describe.data === undefined && describe.isPending;\n const describeOffline =\n describe.data === undefined &&\n describe.error == null &&\n (!online || describe.fetchStatus === \"paused\");\n const loadError = describe.data === undefined ? describe.error : null;\n const slow = useDelayedFlag(describeLoading && !describeOffline);\n const retryDescribe = React.useCallback((): void => {\n void describe.refetch();\n }, [describe]);\n useRetryWhenOnline(loadError, retryDescribe);\n\n const startUpload = (chosen: File): void => {\n setRemap(false);\n upload.mutate({ file: chosen }, { onSuccess: (created) => setJobId(created.id) });\n };\n\n const handleUpload = (event: React.FormEvent<HTMLFormElement>): void => {\n event.preventDefault();\n if (file === null) return;\n startUpload(file);\n };\n\n const handlePreview = (): void => {\n if (job === undefined) return;\n setRemap(false);\n preview.mutate({ jobId: job.id, mapping });\n };\n\n const startOver = (): void => {\n setJobId(undefined);\n setFile(null);\n setRemap(false);\n upload.reset();\n preview.reset();\n commit.reset();\n };\n\n const handleTemplate = (format: \"xlsx\" | \"csv\"): void => {\n setTemplateError(null);\n downloadImportTemplate(client, resource, format).catch((error: unknown) =>\n setTemplateError(error),\n );\n };\n\n const header = (\n <div className=\"flex flex-wrap items-baseline justify-between gap-2\">\n {title !== null ? <h3 className=\"text-base font-semibold\">{title}</h3> : null}\n {describe.data !== undefined ? (\n <div className=\"flex items-baseline gap-3 text-sm\">\n <Button\n variant=\"link\"\n size=\"sm\"\n className=\"h-auto px-0 underline\"\n onClick={() => handleTemplate(\"xlsx\")}\n >\n Download template (XLSX)\n </Button>\n <Button\n variant=\"link\"\n size=\"sm\"\n className=\"h-auto px-0 underline\"\n aria-label=\"CSV template\"\n onClick={() => handleTemplate(\"csv\")}\n >\n CSV\n </Button>\n </div>\n ) : describeLoading ? (\n // Where the template links will be, so they do not push the form down on a phone.\n <Skeleton className={cn(\"h-5 w-56\", !slow && \"invisible\")} aria-hidden=\"true\" />\n ) : null}\n </div>\n );\n\n let body: React.ReactNode;\n if (loadError !== null && loadError !== undefined) {\n // Without the description there is nothing to upload against: no form.\n body = (\n <Slots.Error\n error={loadError}\n context={{ action: \"import\", resource: label }}\n onRetry={retryDescribe}\n retrying={describe.isFetching}\n />\n );\n } else if (describeOffline) {\n body = (\n <Slots.Error\n error={offlineError()}\n context={{ action: \"import\", resource: label }}\n onRetry={retryDescribe}\n retrying={false}\n />\n );\n } else if (describe.data === undefined) {\n body = (\n <>\n <span role=\"status\" className=\"sr-only\">\n {slow ? \"Loading the import form…\" : \"\"}\n </span>\n <Slots.Loading slow={slow} />\n </>\n );\n } else if (step === \"upload\") {\n const uploadError = upload.error;\n body = (\n <div className=\"space-y-3\">\n <form onSubmit={handleUpload} className=\"space-y-2\">\n <div className=\"flex flex-wrap items-end gap-3\">\n <div className=\"grid w-full max-w-96 gap-1.5\">\n <Label htmlFor={fileId}>File to import</Label>\n <Input\n id={fileId}\n type=\"file\"\n name=\"file\"\n accept=\".csv,.xlsx\"\n required\n className=\"cursor-pointer\"\n aria-describedby={hintId}\n aria-invalid={\n uploadError != null && describeError(uploadError).kind === \"validation\"\n ? true\n : undefined\n }\n onChange={(event) => setFile(event.target.files?.[0] ?? null)}\n />\n </div>\n <PendingButton type=\"submit\" pending={upload.isPending} pendingLabel=\"Uploading…\">\n Upload\n </PendingButton>\n </div>\n <p id={hintId} className=\"text-xs text-muted-foreground\">\n CSV or XLSX with a header row, up to {describe.data.max_rows.toLocaleString()} rows. The\n template lists the columns.\n </p>\n </form>\n {upload.isPaused ? <WaitingForConnection what=\"file\" /> : null}\n {uploadError !== null && uploadError !== undefined ? (\n <div ref={uploadErrorRef} tabIndex={-1} className=\"focus:outline-none\">\n <Slots.Error\n error={uploadError}\n context={{ action: \"upload\", resource: label }}\n onRetry={file !== null ? () => startUpload(file) : undefined}\n retrying={upload.isPending}\n />\n </div>\n ) : null}\n </div>\n );\n } else if (job === undefined) {\n body = null; // unreachable: step \"upload\" covers a missing job\n } else if (step === \"progress\") {\n body = <Slots.Progress job={job} />;\n } else if (step === \"map\") {\n const fields = job.fields ?? describe.data.fields;\n body = (\n <div className=\"space-y-3\">\n {job.error !== null ? (\n <div\n role=\"alert\"\n className=\"flex items-start gap-2 rounded-md border border-destructive-border bg-destructive-subtle p-3 text-sm\"\n >\n <AlertIcon className=\"mt-0.5 h-4 w-4 shrink-0 text-destructive\" />\n <div className=\"space-y-1\">\n <p className=\"font-medium text-foreground\">The import failed</p>\n <p className=\"text-muted-foreground\">{job.error}</p>\n </div>\n </div>\n ) : null}\n <p className=\"text-sm text-muted-foreground\">\n {job.file_name} has {job.rows_total} rows. Map each column to a field. Blank cells leave a\n field unchanged.\n </p>\n <MappingTable\n job={job}\n fields={fields}\n mapping={mapping}\n onChange={(header, field) => setMapping((old) => ({ ...old, [header]: field }))}\n />\n {preview.isPaused ? <WaitingForConnection what=\"preview\" /> : null}\n {preview.error !== null && preview.error !== undefined ? (\n <Slots.Error\n error={preview.error}\n context={{ action: \"preview\", resource: label }}\n onRetry={handlePreview}\n retrying={preview.isPending}\n />\n ) : null}\n <div className=\"flex flex-wrap gap-2\">\n <PendingButton\n onClick={handlePreview}\n pending={preview.isPending}\n pendingLabel=\"Previewing…\"\n >\n Preview\n </PendingButton>\n <Button variant=\"outline\" onClick={startOver} disabled={busy}>\n Upload another file\n </Button>\n </div>\n </div>\n );\n } else {\n const result = job.result;\n const done = step === \"done\";\n body = (\n <div className=\"space-y-3\">\n <p role=\"status\" className=\"text-sm text-muted-foreground\">\n {done ? \"Imported\" : \"Previewed\"} {job.file_name} ({job.rows_total} rows).\n {done ? null : \" Nothing is saved yet.\"}\n </p>\n {result !== null ? <Slots.Summary job={job} result={result} /> : null}\n {job.problems.length > 0 ? <Slots.Problems job={job} problems={job.problems} /> : null}\n <div className=\"flex flex-wrap gap-2\">\n {done ? (\n <Button variant=\"outline\" onClick={startOver}>\n Import another file\n </Button>\n ) : (\n <>\n <Button\n ref={commitButtonRef}\n onClick={() => {\n commit.reset();\n setConfirmOpen(true);\n }}\n disabled={busy || result === null}\n >\n Commit\n </Button>\n <Button variant=\"outline\" onClick={() => setRemap(true)} disabled={busy}>\n Change the mapping\n </Button>\n </>\n )}\n </div>\n {!done && result !== null ? (\n <Slots.ConfirmCommit\n open={confirmOpen}\n onOpenChange={(open) => {\n if (!commit.isPending) setConfirmOpen(open);\n }}\n job={job}\n result={result}\n resourceLabel={label}\n pending={commit.isPending}\n error={commit.isPaused ? offlineError() : commit.error}\n onConfirm={() =>\n commit.mutate(job.id, {\n onSuccess: () => setConfirmOpen(false),\n })\n }\n />\n ) : null}\n </div>\n );\n }\n\n return (\n <section\n className={cn(\"space-y-3\", className)}\n aria-label=\"Import\"\n aria-busy={describeLoading || undefined}\n >\n {header}\n {templateError !== null ? (\n <ErrorState\n variant=\"inline\"\n error={templateError}\n context={{ action: \"download the template for\", resource: label }}\n />\n ) : null}\n <div ref={stepRef} tabIndex={-1} className=\"focus:outline-none\" data-step={step}>\n {body}\n </div>\n </section>\n );\n}\n","/**\n * LoginForm is the sign-in form every app needs (contract: auth).\n *\n * Email + password against `useAuth().login`, with the error inline. On\n * success it calls `onSuccess(user)` (navigate there). When the backend's\n * 2FA gate fires, `on2FA` receives the ephemeral token so the app can render\n * its code step (`POST <authBasePath>/2fa/login/`). Without a handler the\n * form explains that a code is required. Render it inside `AuthProvider`,\n * e.g. as `AuthGuard`'s `fallback`.\n */\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { registerComponentRole } from \"../lib/roles\";\nimport { AlertIcon, OfflineIcon } from \"../components/primitives/icons\";\nimport { Input } from \"../components/primitives/input\";\nimport { Label } from \"../components/primitives/label\";\nimport { KarniApiError } from \"../schema/client\";\nimport { describeError, type KarniErrorDescription } from \"../states/describe-error\";\nimport type { ErrorSlotProps } from \"../states/ErrorState\";\nimport { PendingButton } from \"../states/PendingButton\";\nimport { useAuth } from \"./provider\";\nimport type { KarniUser } from \"./types\";\n\nregisterComponentRole(\"login-form\", \"LoginForm\");\n\n/** What the `Error` slot receives: ErrorSlotProps plus the message, already worded for sign-in. */\nexport interface LoginFormErrorProps extends ErrorSlotProps {\n /** Put this id on the message's root: the inputs' `aria-describedby` points at it. */\n id: string;\n /**\n * The failure in plain words: wrong credentials (\"That email and password\n * do not match\"), throttling (\"Wait 42 seconds\"), offline, a server error.\n */\n described: KarniErrorDescription;\n}\n\n/**\n * The replaceable parts of LoginForm. Pass any subset as `slots`.\n * `defaultLoginFormSlots` holds Karni's own, to wrap them.\n */\nexport interface LoginFormSlots {\n /** The message under the fields when signing in fails (announced as an alert). */\n Error: React.ComponentType<LoginFormErrorProps>;\n}\n\nexport interface LoginFormProps {\n /** Called with the signed-in user. Navigate from here. */\n onSuccess?: (user: KarniUser) => void;\n /** Called when the account needs a second factor (the token completes it). */\n on2FA?: (ephemeralToken: string) => void;\n /** Heading above the fields. `null` renders none. Default \"Sign in\". */\n title?: React.ReactNode;\n /** Text under the heading (demo logins, a signup link, ...). */\n description?: React.ReactNode;\n /** The submit button's label. Default \"Sign in\". */\n submitLabel?: React.ReactNode;\n /** Disables the form (e.g. while the auth status is still \"loading\"). */\n disabled?: boolean;\n /** Focus the email field when the form appears. Default true: signing in is the page's purpose. */\n autoFocus?: boolean;\n /** Replace parts of the form: Error. */\n slots?: Partial<LoginFormSlots>;\n className?: string;\n}\n\n/**\n * A field's label-to-control gap as Tailwind 3's `space-y` draws it: a top\n * margin on every child after the first. Tailwind 4's `space-y` puts a bottom\n * margin on the inline <label> instead, which an inline element ignores, so\n * the gap is spelled out to render the same under both.\n */\nconst FIELD_GAP = \"[&>:not([hidden])~:not([hidden])]:mt-1\";\n\n/** Thrown inside the form when the account needs a code and the app has no `on2FA`. */\nclass TwoFactorUnavailable extends Error {\n constructor() {\n super(\"This account needs a two-factor code, but the app has not enabled that step.\");\n this.name = \"TwoFactorUnavailable\";\n }\n}\n\n/** DRF's throttle message: \"Request was throttled. Expected available in 42 seconds.\" */\nfunction throttleSeconds(error: KarniApiError): number | undefined {\n const data = error.data;\n const detail =\n typeof data === \"object\" && data !== null ? (data as Record<string, unknown>)[\"detail\"] : data;\n const match = typeof detail === \"string\" ? /available in (\\d+) seconds?/i.exec(detail) : null;\n return match?.[1] !== undefined ? Number(match[1]) : undefined;\n}\n\n/** The first message of a DRF 400 body (`{\"email\": [\"Enter a valid email address.\"]}`). */\nfunction firstMessage(data: unknown): string | undefined {\n if (typeof data !== \"object\" || data === null) return undefined;\n for (const value of Object.values(data as Record<string, unknown>)) {\n if (typeof value === \"string\") return value;\n if (Array.isArray(value) && typeof value[0] === \"string\") return value[0];\n }\n return undefined;\n}\n\n/**\n * A sign-in failure in plain words. A 401 is the credentials (the backend\n * does not say which one is wrong, so neither does this). A 429 says how long\n * to wait. Everything else is describeError's (\"You're offline\", \"Something\n * went wrong on our side\"), never a status code.\n */\nfunction describeLoginError(error: unknown): KarniErrorDescription {\n if (error instanceof TwoFactorUnavailable) {\n return {\n kind: \"unauthenticated\",\n title: \"This account needs a two-factor code\",\n description: \"The app has not enabled that step. Ask the site's administrator.\",\n retryable: false,\n };\n }\n if (error instanceof KarniApiError) {\n if (error.status === 401) {\n return {\n kind: \"unauthenticated\",\n title: \"That email and password do not match\",\n description: \"Check both and try again.\",\n retryable: false,\n status: 401,\n };\n }\n if (error.status === 400) {\n return {\n kind: \"validation\",\n title: \"Check your email and password\",\n description: firstMessage(error.data) ?? \"Fill in both fields, then try again.\",\n retryable: false,\n status: 400,\n };\n }\n if (error.status === 429) {\n const seconds = throttleSeconds(error);\n return {\n kind: \"rate-limited\",\n title: \"Too many sign-in attempts\",\n description:\n seconds !== undefined\n ? `Wait ${seconds} ${seconds === 1 ? \"second\" : \"seconds\"}, then try again.`\n : \"Wait a few minutes, then try again.\",\n retryable: true,\n status: 429,\n };\n }\n }\n return describeError(error, { action: \"sign in\" });\n}\n\nfunction DefaultLoginError({ id, described }: LoginFormErrorProps): React.ReactElement {\n const Icon =\n described.kind === \"offline\" || described.kind === \"network\" ? OfflineIcon : AlertIcon;\n return (\n <div\n id={id}\n role=\"alert\"\n data-error-kind={described.kind}\n className=\"flex items-start gap-2 rounded-md border border-destructive-border bg-destructive-subtle p-3 text-sm\"\n >\n <Icon className=\"mt-0.5 h-4 w-4 shrink-0 text-destructive\" />\n <div className=\"space-y-1\">\n <p className=\"font-medium text-foreground\">{described.title}</p>\n <p className=\"text-muted-foreground\">{described.description}</p>\n {described.detail !== undefined && described.kind !== \"rate-limited\" ? (\n <p className=\"text-xs text-muted-foreground\">{described.detail}</p>\n ) : null}\n </div>\n </div>\n );\n}\n\n/** Karni's own slots, exported so a project can wrap one instead of rewriting it. */\nexport const defaultLoginFormSlots: LoginFormSlots = { Error: DefaultLoginError };\n\n/**\n * Email and password sign-in form with inline errors and a callback for the two-factor step.\n *\n * Wrong credentials, throttling, a dropped connection and a server error each\n * read differently. The message is announced, both fields point at it\n * (`aria-describedby`) and are marked invalid when they are the problem.\n * After a failure the email stays. Wrong credentials clear the password and\n * focus it. Escape hatch: `slots.Error`.\n */\nexport function LoginForm({\n onSuccess,\n on2FA,\n title = \"Sign in\",\n description,\n submitLabel = \"Sign in\",\n disabled = false,\n autoFocus = true,\n slots,\n className,\n}: LoginFormProps) {\n const Slots: LoginFormSlots = { ...defaultLoginFormSlots, ...slots };\n const { login } = useAuth();\n const id = React.useId();\n const errorId = `${id}-error`;\n const [busy, setBusy] = React.useState(false);\n const [failure, setFailure] = React.useState<{ error: unknown; attempt: number } | null>(null);\n const emailRef = React.useRef<HTMLInputElement>(null);\n const passwordRef = React.useRef<HTMLInputElement>(null);\n const submitRef = React.useRef<HTMLButtonElement>(null);\n const attempts = React.useRef(0);\n\n const described = failure !== null ? describeLoginError(failure.error) : null;\n // The fields are the problem only when the backend refused them (401, 400) —\n // not when it throttled, failed or asked for a second factor.\n const invalid =\n failure !== null &&\n failure.error instanceof KarniApiError &&\n (failure.error.status === 401 || failure.error.status === 400);\n\n // Focus follows the failure once the fields are enabled again: wrong\n // credentials → the (cleared) password, a refused field → the email, the\n // rest (offline, throttled, server) → the button that tries again.\n React.useEffect(() => {\n if (failure === null || busy) return;\n const kind = describeLoginError(failure.error);\n if (failure.error instanceof KarniApiError && failure.error.status === 401) {\n passwordRef.current?.focus();\n } else if (kind.kind === \"validation\") {\n emailRef.current?.focus();\n } else {\n submitRef.current?.focus();\n }\n }, [failure, busy]);\n\n async function submit(event: React.FormEvent<HTMLFormElement>) {\n event.preventDefault();\n const data = new FormData(event.currentTarget);\n attempts.current += 1;\n const attempt = attempts.current;\n setBusy(true);\n setFailure(null);\n try {\n const result = await login(\n String(data.get(\"email\") ?? \"\"),\n String(data.get(\"password\") ?? \"\"),\n );\n if (\"ok\" in result) {\n onSuccess?.(result.user);\n } else if (on2FA !== undefined) {\n on2FA(result.ephemeralToken);\n } else {\n setFailure({ error: new TwoFactorUnavailable(), attempt });\n }\n } catch (error) {\n if (error instanceof KarniApiError && error.status === 401 && passwordRef.current !== null) {\n passwordRef.current.value = \"\";\n }\n setFailure({ error, attempt });\n } finally {\n setBusy(false);\n }\n }\n\n return (\n <form\n className={cn(\"space-y-4\", className)}\n onSubmit={(event) => void submit(event)}\n aria-busy={busy}\n noValidate={false}\n >\n {title !== null ? <h2 className=\"text-lg font-semibold\">{title}</h2> : null}\n {description !== undefined ? (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n ) : null}\n <div className={FIELD_GAP}>\n <Label htmlFor={`${id}-email`}>Email</Label>\n <Input\n ref={emailRef}\n id={`${id}-email`}\n name=\"email\"\n type=\"email\"\n autoComplete=\"email\"\n // Signing in is what the page is for; a form placed elsewhere passes autoFocus={false}.\n autoFocus={autoFocus}\n required\n disabled={disabled || busy}\n className={cn(invalid && \"border-destructive\")}\n aria-invalid={invalid || undefined}\n aria-describedby={failure !== null ? errorId : undefined}\n />\n </div>\n <div className={FIELD_GAP}>\n <Label htmlFor={`${id}-password`}>Password</Label>\n <Input\n ref={passwordRef}\n id={`${id}-password`}\n name=\"password\"\n type=\"password\"\n autoComplete=\"current-password\"\n required\n disabled={disabled || busy}\n className={cn(invalid && \"border-destructive\")}\n aria-invalid={invalid || undefined}\n aria-describedby={failure !== null ? errorId : undefined}\n />\n </div>\n {failure !== null && described !== null ? (\n // Keyed by attempt: the same message after a second failed attempt is announced again.\n <React.Fragment key={failure.attempt}>\n <Slots.Error\n id={errorId}\n error={failure.error}\n context={{ action: \"sign in\" }}\n described={described}\n />\n </React.Fragment>\n ) : null}\n <PendingButton\n ref={submitRef}\n type=\"submit\"\n disabled={disabled}\n pending={busy}\n pendingLabel=\"Signing in…\"\n >\n {submitLabel}\n </PendingButton>\n </form>\n );\n}\n","/**\n * <AuthGuard> renders children only for authenticated users (optionally\n * holding one of the given roles). Otherwise it renders a fallback or says\n * why, in plain words (contract \"Hooks + auth\").\n *\n * Two different refusals: with `explain`, a visitor who is not signed in sees\n * a sign-in prompt (the `Anonymous` slot: a LoginForm, so signing in reveals\n * the content in place) and a signed-in user whose role lacks access sees\n * PermissionDenied (the `Denied` slot). `anonymous` / `denied` render your own\n * node for one of them, and `fallback` (one node for both) keeps working.\n *\n * Deprecation (0.4 → 1.0): a guard with none of `explain`, `fallback`,\n * `anonymous`, `denied` or `slots` renders nothing when it refuses, as in\n * 0.3, and warns once in development. 1.0 makes `explain` the default. A\n * guard that hides a piece of UI passes `fallback={null}`.\n *\n * While the initial auth state resolves, the `loading` slot renders\n * (default: nothing) so protected content never flashes a login screen\n * during session restore.\n */\nimport * as React from \"react\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { LockIcon } from \"../components/primitives/icons\";\nimport { cn } from \"../lib/cn\";\nimport { registerComponentRole } from \"../lib/roles\";\nimport { PermissionDenied } from \"../states/ErrorState\";\nimport { LoginForm } from \"./LoginForm\";\nimport { useAuth } from \"./provider\";\nimport type { KarniUser } from \"./types\";\n\nregisterComponentRole(\"auth-guard\", \"AuthGuard\");\n\n/** What the `Anonymous` slot receives: nobody is signed in. */\nexport interface AuthGuardAnonymousProps {\n /** The roles the content needs, when the guard names some. */\n roles: readonly string[];\n className?: string;\n}\n\n/** What the `Denied` slot receives: someone is signed in, and no role of theirs is in `roles`. */\nexport interface AuthGuardDeniedProps {\n user: KarniUser;\n /** The roles the content needs. */\n roles: readonly string[];\n className?: string;\n}\n\n/**\n * The replaceable refusals of AuthGuard. Pass any subset as `slots`.\n * `defaultAuthGuardSlots` holds Karni's own, to wrap them.\n */\nexport interface AuthGuardSlots {\n /** Not signed in: a sign-in prompt. */\n Anonymous: React.ComponentType<AuthGuardAnonymousProps>;\n /** Signed in without the role: PermissionDenied. */\n Denied: React.ComponentType<AuthGuardDeniedProps>;\n}\n\nexport interface AuthGuardProps {\n /** Grant access when the user holds AT LEAST ONE of these role names. */\n roles?: string[];\n /**\n * Rendered for anonymous users and role mismatches alike. `anonymous` and\n * `denied` (or `slots`) are preferred: they say which of the two it is.\n * `null` renders nothing.\n */\n fallback?: ReactNode;\n /** Rendered for a visitor who is not signed in (wins over `fallback`). */\n anonymous?: ReactNode;\n /** Rendered for a signed-in user whose role lacks access (wins over `fallback`). */\n denied?: ReactNode;\n /** Rendered while the auth status is still \"loading\". Default: nothing. */\n loading?: ReactNode;\n /** Replace the default refusals: Anonymous (sign-in prompt), Denied (PermissionDenied). */\n slots?: Partial<AuthGuardSlots>;\n /**\n * Say why instead of rendering nothing: the sign-in prompt for a visitor,\n * PermissionDenied for a role mismatch. It is the default from 1.0. Until\n * then a guard with no fallback and no `explain` renders nothing (and warns).\n */\n explain?: boolean;\n /** Merged onto the default refusal's root. */\n className?: string;\n children?: ReactNode;\n}\n\n/** The default `Anonymous` slot: says the content needs a signed-in user, with the form to do it. */\nfunction SignInPrompt({ className }: AuthGuardAnonymousProps): ReactElement {\n const headingId = React.useId();\n return (\n <section\n aria-labelledby={headingId}\n className={cn(\n \"mx-auto w-full max-w-96 space-y-4 rounded-lg border border-border bg-card p-6 text-card-foreground\",\n className,\n )}\n >\n <div className=\"flex items-start gap-3\">\n <LockIcon className=\"mt-0.5 h-5 w-5 shrink-0 text-muted-foreground\" />\n <div className=\"space-y-1\">\n <h2 id={headingId} className=\"text-lg font-semibold\">\n Sign in to continue\n </h2>\n <p className=\"text-sm text-muted-foreground\">You need to be signed in to see this.</p>\n </div>\n </div>\n <LoginForm title={null} />\n </section>\n );\n}\n\n/** The default `Denied` slot: who is signed in, and that their role does not reach this. */\nfunction AccessDenied({ user, className }: AuthGuardDeniedProps): ReactElement {\n return (\n <PermissionDenied\n className={className}\n description={\n <>\n You're signed in as <span className=\"font-medium text-foreground\">{user.email}</span>\n , and your role doesn't include this. Ask an administrator if you need access.\n </>\n }\n />\n );\n}\n\n/** Karni's own slots, exported so a project can wrap one instead of rewriting it. */\nexport const defaultAuthGuardSlots: AuthGuardSlots = {\n Anonymous: SignInPrompt,\n Denied: AccessDenied,\n};\n\nconst NO_ROLES: readonly string[] = [];\n\nlet warned = false;\n\n/** One development warning per page load for a guard relying on the 0.3 default. */\nfunction warnImplicitNothing(): void {\n if (warned) return;\n const env = typeof process === \"undefined\" ? undefined : process.env?.NODE_ENV;\n if (env === \"production\") return;\n warned = true;\n console.warn(\n \"[karni-ui] An <AuthGuard> refused and rendered nothing because it has no fallback. \" +\n \"From @karni/ui 1.0 a guard explains a refusal by default (a sign-in prompt, or \" +\n \"PermissionDenied). Pass `explain` to opt in now, or `fallback={null}` to keep \" +\n \"rendering nothing. See https://cbsshekhawat18-lab.github.io/karni/migrations/0.4/\",\n );\n}\n\n/** Renders its children only for a signed-in user, optionally with one of the given roles, and otherwise says why. */\nexport function AuthGuard(props: AuthGuardProps): ReactElement | null {\n const { roles, fallback, anonymous, denied, loading = null, slots, className, children } = props;\n const Slots: AuthGuardSlots = { ...defaultAuthGuardSlots, ...slots };\n // Passing slots asks for them to be used, which is opting in too.\n const explain = props.explain === true || slots !== undefined;\n const { status, user } = useAuth();\n const required = roles ?? NO_ROLES;\n // `fallback={null}` is a choice (render nothing); only an absent fallback means the defaults.\n const hasFallback = fallback !== undefined;\n if (status === \"loading\") return <>{loading}</>;\n if (status !== \"authenticated\" || user === null) {\n if (anonymous !== undefined) return <>{anonymous}</>;\n if (hasFallback) return <>{fallback}</>;\n if (!explain) {\n warnImplicitNothing();\n return null;\n }\n return <Slots.Anonymous roles={required} className={className} />;\n }\n if (required.length > 0 && !required.some((role) => user.roles.includes(role))) {\n if (denied !== undefined) return <>{denied}</>;\n if (hasFallback) return <>{fallback}</>;\n if (!explain) {\n warnImplicitNothing();\n return null;\n }\n return <Slots.Denied user={user} roles={required} className={className} />;\n }\n return <>{children}</>;\n}\n","/**\n * Role helpers over the authenticated user (contract \"Hooks + auth\",\n * accounts A15: the me endpoint returns `roles: string[]`).\n */\nimport { useMemo } from \"react\";\nimport { useAuth } from \"./provider\";\n\nexport interface PermissionHelpers {\n /** True when the user has at least one of the given role names. */\n hasRole(...names: string[]): boolean;\n isAuthenticated: boolean;\n}\n\n/** `isAuthenticated` and `hasRole(...names)` for the signed-in user. */\nexport function usePermission(): PermissionHelpers {\n const { roles, status } = useAuth();\n return useMemo<PermissionHelpers>(\n () => ({\n isAuthenticated: status === \"authenticated\",\n hasRole: (...names: string[]) =>\n status === \"authenticated\" && names.some((name) => roles.includes(name)),\n }),\n [roles, status],\n );\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\n\nregisterComponentRole(\"page-shell\", \"Page\");\n\n/** What the `Header` slot receives: the title row's pieces, already rendered by their slots. */\nexport interface PageHeaderProps {\n /** The Title slot holding `title`. */\n title: React.ReactNode;\n /** The Description slot holding `description`, or null. */\n description: React.ReactNode;\n /** The Actions slot holding `actions`, or null. */\n actions: React.ReactNode;\n /** `headerClassName`. */\n className?: string;\n}\n\n/** What the `Title`, `Description` and `Actions` slots receive. */\nexport interface PageSlotContentProps {\n children: React.ReactNode;\n}\n\n/** The parts of the page chrome a project can replace (`slots={{ Title: MyHeading }}`). */\nexport interface PageSlots {\n /** The row holding the title, description and actions. */\n Header: React.ComponentType<PageHeaderProps>;\n /** The page heading. The default is the page's <h1>. */\n Title: React.ComponentType<PageSlotContentProps>;\n /** The line under the title. */\n Description: React.ComponentType<PageSlotContentProps>;\n /** The container of the actions, right of the title. */\n Actions: React.ComponentType<PageSlotContentProps>;\n}\n\nexport interface PageProps extends Omit<React.HTMLAttributes<HTMLElement>, \"title\"> {\n /** Page heading, rendered as an <h1>. */\n title: React.ReactNode;\n /** Optional sub-heading under the title. */\n description?: React.ReactNode;\n /** Slot rendered to the right of the title (buttons, menus, …). */\n actions?: React.ReactNode;\n /**\n * Replaces the entire derived header (title/description/actions are\n * ignored when given). Prefer the `Header` slot, which still receives them.\n */\n header?: React.ReactNode;\n /** Replaces pieces of the chrome. See PageSlots. */\n slots?: Partial<PageSlots>;\n /** Extra classes for the derived header row. */\n headerClassName?: string;\n /** Extra classes for the content area under the header. */\n contentClassName?: string;\n children?: React.ReactNode;\n}\n\nfunction DefaultHeader({\n title,\n description,\n actions,\n className,\n}: PageHeaderProps): React.ReactElement {\n return (\n <header className={cn(\"flex flex-wrap items-start justify-between gap-4\", className)}>\n <div className=\"grid gap-1\">\n {title}\n {description}\n </div>\n {actions}\n </header>\n );\n}\n\nfunction DefaultTitle({ children }: PageSlotContentProps): React.ReactElement {\n return <h1 className=\"text-2xl font-semibold tracking-tight text-foreground\">{children}</h1>;\n}\n\nfunction DefaultDescription({ children }: PageSlotContentProps): React.ReactElement {\n return <p className=\"text-sm text-muted-foreground\">{children}</p>;\n}\n\nfunction DefaultActions({ children }: PageSlotContentProps): React.ReactElement {\n return <div className=\"flex shrink-0 items-center gap-2\">{children}</div>;\n}\n\n/** The default pieces of the page chrome, for wrapping one. */\nexport const defaultPageSlots: PageSlots = {\n Header: DefaultHeader,\n Title: DefaultTitle,\n Description: DefaultDescription,\n Actions: DefaultActions,\n};\n\n/**\n * Standard page chrome: an `<h1>` title row with an actions slot, then the\n * content. The target usage `<Page title=\"Events\"><ResourceTable … /></Page>`\n * is a complete screen.\n *\n * Escape hatches: `slots` replaces the Header, Title, Description or\n * Actions. `header` replaces the whole derived header. `className`,\n * `headerClassName` and `contentClassName` merge through cn(). Every other\n * prop passes through to the root <section>.\n */\nexport const Page = React.forwardRef<HTMLElement, PageProps>(\n (\n {\n title,\n description,\n actions,\n header,\n slots,\n headerClassName,\n contentClassName,\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const { Header, Title, Description, Actions } = { ...defaultPageSlots, ...slots };\n return (\n <section ref={ref} className={cn(\"flex w-full flex-col gap-6\", className)} {...props}>\n {header ?? (\n <Header\n className={headerClassName}\n title={<Title>{title}</Title>}\n description={description != null ? <Description>{description}</Description> : null}\n actions={actions != null ? <Actions>{actions}</Actions> : null}\n />\n )}\n <div className={cn(\"flex flex-col gap-4\", contentClassName)}>{children}</div>\n </section>\n );\n },\n);\nPage.displayName = \"Page\";\n","// Generated by scripts/brand/render.mjs from assets/brand/ — do not edit.\nexport const MARK_VIEWBOX = \"0 0 1000 1000\";\n/** The full mark: ground, rings, strokes. */\nexport const MARK_PATHS: ReadonlyArray<{ readonly fill: string; readonly d: string }> = [\n {\n \"fill\": \"#000000\",\n \"d\": \"M495.8 884.4C366.3 877.9 255.3 816.3 182.4 710.5C128.6 632.2 103.2 521.3 115 415.5C128.3 296.3 188.2 205.8 290.9 150.2C389.1 97 470.1 78.3 564.8 87C689.6 98.4 790.1 167.2 844.3 278.1C896.3 384.6 901.7 498.4 860.4 619.6C833.4 698.7 806.7 746.3 766.3 787.1C699.4 854.6 601.9 889.7 495.8 884.4Z\"\n },\n {\n \"fill\": \"#FB5D08\",\n \"d\": \"M355.6 514.1C355.6 509.2 355.7 507.3 355.8 509.8C355.9 512.3 355.9 516.3 355.8 518.7C355.7 521 355.6 519 355.6 514.1ZM677.1 423C637.3 415.7 624.1 366.4 654.9 340.2C672.8 325 696 324.3 713.7 338.5C741 360.3 735.8 403.2 704.1 418.6C696.1 422.4 684.6 424.3 677.1 423ZM330.5 421.6C299.1 415 283.8 379.9 300.6 352.7C317.1 325.8 352.4 320.7 373.7 342.2C398.9 367.6 387.2 410.3 352.3 420.8C347.4 422.3 335.7 422.7 330.5 421.6ZM504.5 399.6C466.4 392.2 453.2 345.4 481.5 318.2C509.6 291.1 556 308.2 560.5 347.3C564.1 377.9 534.5 405.5 504.5 399.6ZM349.4 395.9C367.2 387.1 367.7 363.1 350.2 354.5C329.3 344.3 308.5 369.4 321.8 388.6C327.9 397.5 339.8 400.7 349.4 395.9ZM694 395.9C716 385.1 709 352 684.8 352C665.4 352 654.8 375.3 667.3 390.4C673.5 397.8 685.2 400.2 694 395.9ZM522.4 373.7C534.6 368 539.9 353.6 534.2 341.9C525.3 323.9 501.3 323.8 492.5 341.8C482.8 361.3 503 382.8 522.4 373.7Z\"\n },\n {\n \"fill\": \"#FFFFFF\",\n \"d\": \"M363 677.8C348.7 675.4 341.3 657.2 334.1 606.9C326.6 554.4 325.7 485.2 332.2 459.2C336.3 442.9 349.3 435.9 362.9 442.6C374.7 448.4 394.4 475.1 427.1 529.5C428.9 532.4 430.5 534.9 430.8 534.9C431 534.9 433.5 530.7 436.3 525.6C486 435.8 497.3 419.9 512.2 419.2C523.9 418.6 531.9 426.3 550 455.6C555.3 464.3 582.5 513.2 591.4 530.3C592.7 532.8 594 534.9 594.2 534.9C594.4 534.9 595.9 532.7 597.5 530C621.8 490.2 643.6 458.3 652.7 449.5C668.6 434.2 686.9 437.8 692.6 457.4C703.9 496.4 693.7 637.6 677.5 666.3C673 674.5 663.4 679.5 655.8 677.8C642.6 674.9 633.9 663.4 598.7 602.7C592.7 592.3 593.3 593.1 592.3 594.4C590.8 596.2 572.8 626.4 560.2 648.2C546.9 671 546 672.4 541.7 674.3C531.2 679.1 519.1 669.5 522.1 658.7C523.4 654.4 551 607 571.8 573.6C575 568.5 577.6 564.2 577.6 564C577.6 563.7 560.8 532.5 547.2 507.4C527.8 471.7 514.9 450.1 513.1 450.1C512.4 450.1 510.6 452.9 504.3 463.4C492.7 482.5 447.9 562.5 447.9 564C447.9 564.3 449.8 567.6 452.1 571.4C475.2 609.2 501.1 653.4 502.6 657.5C506.1 667.6 496.6 677.8 485.8 675.3C479.8 673.9 479.1 673.1 468.6 655.1C464.9 648.8 456 633.6 448.7 621.3C441.5 608.9 434.9 597.8 434.2 596.5C432.8 594 431.8 593 431.5 593.9C431.3 594.5 427.1 601.6 414 623.8C386.6 670 377.1 680.1 363 677.8ZM373.8 636.7C376.1 632.9 382.1 622.9 387.1 614.4C408.9 577.2 413.5 569.4 414.6 567.2L415.7 564.9L411.3 557.5C374 495.9 359.9 473.9 357.6 473.9C355.5 473.9 355.1 527.7 357.1 556.7C359.2 587.2 364.9 630.4 368.5 642.5C369 644.1 369.4 643.7 373.8 636.7ZM658.1 639.2C666.8 598 672.3 509 668.1 476.6C667.7 473.1 667.4 473.2 663.8 478C657.6 486.3 651.5 495.7 631.2 529C626.9 536.1 622.1 543.9 620.5 546.5C618.9 549.1 615.7 554.3 613.4 558.1L609.1 565L610.6 567.5C611.4 568.9 616.6 577.6 622.1 586.9C627.5 596.2 634.1 607.5 636.7 611.9C649.4 633.6 655.7 643.4 656.8 643.4C657 643.4 657.6 641.5 658.1 639.2Z\"\n }\n];\n/** The small-size variant's SVG body (use at 32px and below). */\nexport const MARK_SIMPLE_BODY = \"<path fill=\\\"#000000\\\" d=\\\"M495.8 884.4C291.9 874.2 135.4 724 114.7 518.5C97.9 351.3 160.2 221 290.9 150.2C372.3 106.1 439.7 86.4 513.6 85.2C686 82.3 812.9 171.5 867 333.5C903.9 444 890.2 573.8 828.6 698.6C766.8 823.4 644.3 891.8 495.8 884.4Z\\\"/>\\n<circle cx=\\\"340\\\" cy=\\\"300\\\" r=\\\"44\\\" fill=\\\"#FB5D08\\\"/>\\n<circle cx=\\\"500\\\" cy=\\\"276\\\" r=\\\"44\\\" fill=\\\"#FB5D08\\\"/>\\n<circle cx=\\\"660\\\" cy=\\\"300\\\" r=\\\"44\\\" fill=\\\"#FB5D08\\\"/>\\n<path fill=\\\"none\\\" stroke=\\\"#FFFFFF\\\" stroke-width=\\\"58\\\" stroke-linecap=\\\"round\\\" stroke-linejoin=\\\"round\\\"\\n d=\\\"M318 420v280l182-250 182 250V420M500 450 410 700M500 450l90 250\\\"/>\";\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { MARK_PATHS, MARK_SIMPLE_BODY, MARK_VIEWBOX } from \"./mark-paths\";\n\nexport interface KarniMarkProps extends Omit<React.SVGAttributes<SVGSVGElement>, \"children\"> {\n /** Rendered size in px (width and height). Default 28. */\n size?: number;\n /**\n * Which drawing: the full mark, the small-size variant, or `auto` (the\n * default): the small variant at 32px and below, the full mark above.\n */\n variant?: \"auto\" | \"full\" | \"simple\";\n /** Accessible name. Pass an empty string to hide a purely decorative mark. */\n title?: string;\n}\n\n/**\n * The Karni mark as inline SVG, so there is no asset to load or bundle.\n *\n * It is the default content of `<Layout>`'s `sidebarHeader` slot so a bare\n * shell is never nameless. A project replaces it by passing its own\n * `sidebarHeader` (the scaffold already does). Do not recolour or restyle it:\n * the mark is Karni's, see assets/brand/README.md in the repository.\n */\nexport const KarniMark = React.forwardRef<SVGSVGElement, KarniMarkProps>(\n ({ size = 28, variant = \"auto\", title = \"Karni\", className, ...props }, ref) => {\n const simple = variant === \"simple\" || (variant === \"auto\" && size <= 32);\n const labelled = title !== \"\";\n return (\n <svg\n ref={ref}\n viewBox={MARK_VIEWBOX}\n width={size}\n height={size}\n role={labelled ? \"img\" : undefined}\n aria-hidden={labelled ? undefined : true}\n aria-label={labelled ? title : undefined}\n className={cn(\"shrink-0\", className)}\n {...props}\n {...(simple ? { dangerouslySetInnerHTML: { __html: MARK_SIMPLE_BODY } } : {})}\n >\n {simple\n ? null\n : MARK_PATHS.map((path) => (\n <path key={path.fill + path.d.length} fill={path.fill} d={path.d} />\n ))}\n </svg>\n );\n },\n);\nKarniMark.displayName = \"KarniMark\";\n","/**\n * Layout's focus management after a client-side navigation, the way\n * accessible SPA routers do it: once the new page is in, focus moves to its\n * main heading (else <main>) and a polite live region says its title.\n *\n * It needs no router. The route is the URL's path (a hash route such as\n * `#/events` included, search params left out), or the `routeKey` option. A\n * change is noticed when the Layout renders and when anything in <main>\n * changes, so a router that re-renders only its outlet is covered too.\n * Internal to @karni/ui. Layout's `routeFocus` prop is the public surface.\n */\nimport * as React from \"react\";\n\n/** What Layout's `routeFocus` prop takes when it is an object. */\nexport interface LayoutRouteFocusOptions {\n /**\n * The current route: focus moves when it changes. Default: the URL's path\n * (`location.pathname`, plus a hash route such as `#/events`), so a change\n * of search params only (filters, pagination, sorting) never moves focus.\n * Pass your router's pathname or route id when the URL does not say which\n * page is showing (a memory router).\n */\n routeKey?: string;\n /**\n * The element that takes focus after a navigation. Default: the first\n * `<h1>` in `<main>`, else `<main>` itself. An element that cannot take\n * focus gets `tabindex=\"-1\"`.\n */\n getTarget?: (main: HTMLElement) => HTMLElement | null;\n /**\n * What the live region says after a navigation. Default: the document\n * title when the new page changed it, else the heading's text. Return \"\"\n * to say nothing.\n */\n getAnnouncement?: (target: HTMLElement) => string;\n}\n\ninterface Settled {\n key: string;\n heading: HTMLElement | null;\n text: string;\n title: string;\n}\n\nfunction locationKey(): string {\n const { pathname, hash } = window.location;\n // A hash router keeps its route in the hash: its path counts, its query does not.\n const hashRoute = hash.startsWith(\"#/\") || hash.startsWith(\"#!/\") ? hash.split(\"?\")[0] : \"\";\n return `${pathname}${hashRoute}`;\n}\n\nfunction defaultTarget(main: HTMLElement): HTMLElement | null {\n return main.querySelector<HTMLElement>(\"h1\");\n}\n\nfunction textOf(element: HTMLElement | null): string {\n return element?.textContent?.trim() ?? \"\";\n}\n\nconst FIELD_SELECTOR = 'input, textarea, select, [contenteditable=\"\"], [contenteditable=\"true\"]';\n\n/**\n * Whether something already took focus for the new page, which the Layout\n * then leaves alone: a control inside <main> (an autofocused field, a link\n * of the page that is still there), an open dialog, or a form field anywhere\n * (a search box in the header that navigates as you type).\n */\nfunction focusClaimed(main: HTMLElement, target: HTMLElement): boolean {\n const active = document.activeElement;\n if (!(active instanceof HTMLElement)) return false;\n if (active === document.body || active === main || active === target) return false;\n if (active.closest('[role=\"dialog\"], [role=\"alertdialog\"], dialog') !== null) return true;\n if (active.closest(FIELD_SELECTOR) !== null) return true;\n return main.contains(active);\n}\n\nfunction defaultAnnouncement(target: HTMLElement, main: HTMLElement, before: Settled): string {\n const title = document.title.trim();\n if (title !== \"\" && title !== before.title) return title;\n const heading = target === main ? \"\" : textOf(target);\n return heading !== \"\" ? heading : title;\n}\n\nexport interface RouteFocusOptions extends LayoutRouteFocusOptions {\n enabled: boolean;\n}\n\n/** What counts as the user acting: a key, a pointer, or Back and Forward. */\nconst INTERACTIONS = [\"keydown\", \"pointerdown\", \"popstate\"] as const;\n\n/**\n * Watches the route and, after a navigation, moves focus into the new page.\n * Returns the live region's text.\n */\nexport function useRouteFocus(\n mainRef: React.RefObject<HTMLElement | null>,\n options: RouteFocusOptions,\n): string {\n const { enabled } = options;\n const [announcement, setAnnouncement] = React.useState(\"\");\n // The callbacks are read when they run, so inline functions do not re-subscribe.\n const latest = React.useRef(options);\n latest.current = options;\n const settled = React.useRef<Settled | null>(null);\n const pending = React.useRef<{ key: string; mutated: boolean } | null>(null);\n const timer = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n // Redirects before the user does anything (\"/\" to \"/dashboard\") are part of the first load.\n const interacted = React.useRef(false);\n\n const snapshot = React.useCallback((key: string, main: HTMLElement): Settled => {\n const heading = (latest.current.getTarget ?? defaultTarget)(main);\n return { key, heading, text: textOf(heading), title: document.title.trim() };\n }, []);\n\n const finish = React.useCallback((): void => {\n timer.current = null;\n const main = mainRef.current;\n const navigation = pending.current;\n const before = settled.current;\n if (main === null || navigation === null || before === null) return;\n const { getTarget, getAnnouncement } = latest.current;\n const target = (getTarget ?? defaultTarget)(main) ?? main;\n // The old page is still up (the router waits for data): the next change in <main> ends the wait.\n const sameHeading = target === before.heading && textOf(target) === before.text;\n if (!navigation.mutated && sameHeading) return;\n pending.current = null;\n if (!focusClaimed(main, target)) {\n if (target.tabIndex < 0 && !target.hasAttribute(\"tabindex\")) {\n target.setAttribute(\"tabindex\", \"-1\");\n }\n // The router owns scrolling (top of the page, or where Back left it).\n target.focus({ preventScroll: true });\n }\n setAnnouncement(\n getAnnouncement !== undefined\n ? getAnnouncement(target)\n : defaultAnnouncement(target, main, before),\n );\n settled.current = snapshot(navigation.key, main);\n }, [mainRef, snapshot]);\n\n const check = React.useCallback(\n (mutated: boolean): void => {\n const main = mainRef.current;\n if (main === null) return;\n const key = latest.current.routeKey ?? locationKey();\n const before = settled.current;\n if (before === null || !interacted.current) {\n // The first load: the browser already put focus where it belongs.\n settled.current = snapshot(key, main);\n return;\n }\n if (key === before.key) {\n // The same page (a search-param change, new data): only keep up with it.\n if (pending.current !== null) {\n pending.current = null;\n if (timer.current !== null) clearTimeout(timer.current);\n timer.current = null;\n }\n settled.current = snapshot(key, main);\n return;\n }\n if (pending.current?.key !== key) {\n pending.current = { key, mutated: false };\n setAnnouncement(\"\");\n }\n if (mutated) pending.current.mutated = true;\n // After the page's own effects: an autofocused field wins, and the title is set.\n if (timer.current !== null) clearTimeout(timer.current);\n timer.current = setTimeout(finish, 0);\n },\n [mainRef, snapshot, finish],\n );\n\n React.useEffect(() => {\n if (!enabled || interacted.current) return undefined;\n const stop = (): void => {\n for (const name of INTERACTIONS) window.removeEventListener(name, mark, true);\n };\n const mark = (): void => {\n interacted.current = true;\n stop();\n };\n for (const name of INTERACTIONS) window.addEventListener(name, mark, true);\n return stop;\n }, [enabled]);\n\n React.useEffect(() => {\n const main = mainRef.current;\n if (!enabled || main === null) return undefined;\n const observer = new MutationObserver(() => check(true));\n observer.observe(main, { childList: true, subtree: true, characterData: true });\n return () => {\n observer.disconnect();\n if (timer.current !== null) clearTimeout(timer.current);\n timer.current = null;\n };\n }, [enabled, mainRef, check]);\n\n // Every render: the Layout re-renders when its router's location changes.\n React.useEffect(() => {\n if (enabled) check(false);\n });\n\n React.useEffect(() => {\n if (enabled) return;\n // Switched off: the next time it is on starts from that page, as on a first load.\n settled.current = null;\n pending.current = null;\n }, [enabled]);\n\n return enabled ? announcement : \"\";\n}\n","import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\nimport { KarniMark } from \"../brand/karni-mark\";\nimport { useRouteFocus, type LayoutRouteFocusOptions } from \"./route-focus\";\n\nexport type { LayoutRouteFocusOptions } from \"./route-focus\";\n\nregisterComponentRole(\"layout-shell\", \"Layout\");\n\ntype IconProps = React.SVGAttributes<SVGSVGElement>;\n\nfunction MenuIcon(props: IconProps): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"4\" y1=\"6\" x2=\"20\" y2=\"6\" />\n <line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\" />\n <line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\" />\n </svg>\n );\n}\n\nfunction CloseIcon(props: IconProps): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\nexport interface LayoutNavItem {\n /** Visible label of the nav entry. */\n label: React.ReactNode;\n /** Target URL (rendered as a plain <a> by default). */\n href: string;\n /** Optional icon rendered before the label. */\n icon?: React.ReactNode;\n /** Marks the current page (aria-current=\"page\" + active styling). */\n active?: boolean;\n /** React key override when `href` is not unique. */\n key?: string;\n}\n\n/** What the `NavLink` slot receives: the props of the <a> it replaces, plus the item. */\nexport interface LayoutNavLinkProps {\n item: LayoutNavItem;\n href: string;\n /** The styled class, focus indicator and active state included. */\n className: string;\n \"aria-current\"?: \"page\";\n /** Closes the mobile drawer. Call it when the link navigates. */\n onClick: () => void;\n /** The icon and the label. */\n children: React.ReactNode;\n}\n\n/** What the `Sidebar` slot (the static sidebar, md and up) receives. */\nexport interface LayoutSidebarProps {\n /** The `sidebarHeader` (the Karni mark by default), or null. */\n header: React.ReactNode;\n /** The derived nav, or the `sidebar` prop. */\n nav: React.ReactNode;\n /** The `sidebarFooter`, or null. */\n footer: React.ReactNode;\n /** `sidebarClassName`. */\n className?: string;\n}\n\n/** What the `MobileDrawer` slot (the sidebar below md) receives. */\nexport interface LayoutMobileDrawerProps extends LayoutSidebarProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** The id the menu button's aria-controls names while the drawer is open. */\n id: string;\n /** The menu button: where focus returns when the drawer closes. */\n returnFocusRef: React.RefObject<HTMLButtonElement | null>;\n}\n\n/** What the `Header` slot (the top bar) receives. */\nexport interface LayoutHeaderProps {\n /** The button that opens the drawer below md. Render it, or the drawer cannot open. */\n menuButton: React.ReactNode;\n /** The `header` prop's content. */\n children?: React.ReactNode;\n /** `headerClassName`. */\n className?: string;\n}\n\n/** What the `SkipLink` slot receives: the first focusable element of the page. */\nexport interface LayoutSkipLinkProps {\n /** `#` + the id of <main>. */\n href: string;\n /** Moves focus to <main> without changing the URL (hash routers keep their route). */\n onClick: (event: React.MouseEvent<HTMLAnchorElement>) => void;\n children: React.ReactNode;\n}\n\n/** The parts of the shell a project can replace (`slots={{ NavLink: RouterLink }}`). */\nexport interface LayoutSlots {\n /** The top bar with the menu button and the `header` content. */\n Header: React.ComponentType<LayoutHeaderProps>;\n /** The static sidebar (md and up). The default hides itself below md. */\n Sidebar: React.ComponentType<LayoutSidebarProps>;\n /** Each derived nav link. Replace it with your router's link. */\n NavLink: React.ComponentType<LayoutNavLinkProps>;\n /** The sidebar below md: a modal drawer (focus trapped, Escape closes). */\n MobileDrawer: React.ComponentType<LayoutMobileDrawerProps>;\n /** \"Skip to content\", visible only while focused. `() => null` removes it. */\n SkipLink: React.ComponentType<LayoutSkipLinkProps>;\n}\n\nexport interface LayoutProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Items of the derived sidebar nav. */\n navItems?: readonly LayoutNavItem[];\n /**\n * Wraps or replaces the default link of one item. `defaultNode` is the\n * link the layout would render. Return it, or your own node (e.g. a\n * TanStack Router <Link> with `className={defaultClassName}`).\n * Prefer the `NavLink` slot, which also closes the mobile drawer.\n */\n renderNavItem?: (\n item: LayoutNavItem,\n defaults: { defaultNode: React.ReactNode; defaultClassName: string },\n ) => React.ReactNode;\n /** Escape hatch: replaces the entire derived nav inside the sidebar. */\n sidebar?: React.ReactNode;\n /**\n * Brand/logo slot pinned to the top of the sidebar. Defaults to the Karni\n * mark (`<KarniMark />`). Pass your own brand, or `null` for no header.\n */\n sidebarHeader?: React.ReactNode;\n /** Slot pinned to the bottom of the sidebar (user menu, logout, …). */\n sidebarFooter?: React.ReactNode;\n /** Header slot, rendered in the top bar next to the mobile menu button. */\n header?: React.ReactNode;\n /** Accessible name of the sidebar navigation (default \"Main\"). */\n navLabel?: string;\n /** Controlled open state of the mobile drawer (pair with onMobileNavOpenChange). */\n mobileNavOpen?: boolean;\n /** Initial open state of the mobile drawer when uncontrolled. */\n defaultMobileNavOpen?: boolean;\n /** Called when the drawer opens or closes (menu button, Escape, backdrop, a link). */\n onMobileNavOpenChange?: (open: boolean) => void;\n /** Replaces internal pieces of the shell. See LayoutSlots. */\n slots?: Partial<LayoutSlots>;\n /**\n * Focus after a client-side navigation. Default `true`: once the new page\n * is in, focus moves to its `<h1>` (else `<main>`) and a polite live region\n * says the page title. Nothing moves on the first load (a redirect before\n * the user acts included), when only search params change (filters,\n * pagination, sorting), or when something took focus for the page itself\n * (an autofocused field, a control inside `<main>`, a dialog). `false`\n * turns it off. An object keeps it on and sets the route key, the target\n * or the announcement (see LayoutRouteFocusOptions).\n */\n routeFocus?: boolean | LayoutRouteFocusOptions;\n sidebarClassName?: string;\n headerClassName?: string;\n contentClassName?: string;\n children?: React.ReactNode;\n}\n\nconst NAV_ITEM_CLASS =\n \"flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring [&_svg]:h-4 [&_svg]:w-4\";\nconst NAV_ITEM_ACTIVE_CLASS = \"bg-accent text-accent-foreground\";\n\nconst ICON_BUTTON_CLASS =\n \"inline-flex items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\";\n\n/** The sidebar's inner column, shared by the static sidebar and the drawer. */\nfunction SidebarColumn({ header, nav, footer }: LayoutSidebarProps): React.ReactElement {\n return (\n <>\n {header != null && <div className=\"mb-4\">{header}</div>}\n <div className=\"flex-1 overflow-y-auto\">{nav}</div>\n {footer != null && <div className=\"mt-4\">{footer}</div>}\n </>\n );\n}\n\nfunction DefaultHeader({ menuButton, children, className }: LayoutHeaderProps): React.ReactElement {\n return (\n <header\n className={cn(\"flex h-14 shrink-0 items-center gap-3 border-b border-border px-4\", className)}\n >\n {menuButton}\n {children != null && <div className=\"flex min-w-0 flex-1 items-center gap-3\">{children}</div>}\n </header>\n );\n}\n\nfunction DefaultSidebar(props: LayoutSidebarProps): React.ReactElement {\n return (\n <aside\n className={cn(\n \"hidden w-64 shrink-0 flex-col border-r border-border bg-card p-4 md:flex\",\n props.className,\n )}\n >\n <SidebarColumn {...props} />\n </aside>\n );\n}\n\nfunction DefaultNavLink(props: LayoutNavLinkProps): React.ReactElement {\n return (\n <a\n href={props.href}\n className={props.className}\n aria-current={props[\"aria-current\"]}\n onClick={props.onClick}\n >\n {props.children}\n </a>\n );\n}\n\nfunction DefaultMobileDrawer({\n open,\n onOpenChange,\n id,\n returnFocusRef,\n className,\n ...column\n}: LayoutMobileDrawerProps): React.ReactElement {\n return (\n <DialogPrimitive.Root open={open} onOpenChange={onOpenChange}>\n <DialogPrimitive.Portal>\n <DialogPrimitive.Overlay\n data-testid=\"karni-layout-backdrop\"\n className=\"fixed inset-0 z-drawer bg-overlay md:hidden\"\n />\n <DialogPrimitive.Content\n id={id}\n aria-describedby={undefined}\n onCloseAutoFocus={(event) => {\n // Back to the menu button, even where a click does not focus it (Safari).\n const target = returnFocusRef.current;\n if (target !== null) {\n event.preventDefault();\n target.focus();\n }\n }}\n className={cn(\n \"fixed inset-y-0 left-0 z-drawer flex w-64 flex-col border-r border-border bg-card p-4 shadow-lg focus:outline-none md:hidden\",\n className,\n )}\n >\n <DialogPrimitive.Title className=\"sr-only\">Navigation</DialogPrimitive.Title>\n <div className=\"mb-2 flex justify-end\">\n <DialogPrimitive.Close className={cn(ICON_BUTTON_CLASS, \"h-8 w-8\")}>\n <CloseIcon className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close navigation</span>\n </DialogPrimitive.Close>\n </div>\n <SidebarColumn {...column} />\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n );\n}\n\nfunction DefaultSkipLink({ href, onClick, children }: LayoutSkipLinkProps): React.ReactElement {\n return (\n <a\n href={href}\n onClick={onClick}\n className=\"sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-4 focus:z-popover focus:rounded-md focus:bg-background focus:px-4 focus:py-2 focus:text-sm focus:font-medium focus:text-foreground focus:shadow-md focus:outline-none focus:ring-2 focus:ring-ring\"\n >\n {children}\n </a>\n );\n}\n\n/** The default pieces of the shell, which you spread to wrap one (`{ ...defaultLayoutSlots }`). */\nexport const defaultLayoutSlots: LayoutSlots = {\n Header: DefaultHeader,\n Sidebar: DefaultSidebar,\n NavLink: DefaultNavLink,\n MobileDrawer: DefaultMobileDrawer,\n SkipLink: DefaultSkipLink,\n};\n\n/**\n * App shell: sidebar navigation + header slot + content area.\n *\n * Responsive: under the `md` breakpoint the sidebar collapses behind a menu\n * button and opens as a modal drawer: focus moves into it and stays there,\n * Escape, the backdrop, the close button or a link close it, and focus\n * returns to the menu button. A \"Skip to content\" link is the first stop of\n * the keyboard.\n *\n * After a client-side navigation, focus moves to the new page's `<h1>` and\n * a live region says its title (`routeFocus`). Render the Layout once,\n * around your router's outlet, so it sees the route change.\n *\n * Escape hatches: `slots` replaces the Header, Sidebar, NavLink,\n * MobileDrawer or SkipLink. `renderNavItem` wraps each derived link.\n * `sidebar` replaces the derived nav wholesale. `sidebarHeader`,\n * `sidebarFooter` and `header` are free slots. `mobileNavOpen` controls\n * the drawer. `routeFocus={false}` turns the focus move off, and an object\n * sets its route key, target or announcement.\n */\nexport const Layout = React.forwardRef<HTMLDivElement, LayoutProps>(\n (\n {\n navItems = [],\n renderNavItem,\n sidebar,\n sidebarHeader = <KarniMark className=\"mx-3\" />,\n sidebarFooter,\n header,\n navLabel = \"Main\",\n mobileNavOpen,\n defaultMobileNavOpen = false,\n onMobileNavOpenChange,\n slots,\n routeFocus = true,\n sidebarClassName,\n headerClassName,\n contentClassName,\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const { Header, Sidebar, NavLink, MobileDrawer, SkipLink } = {\n ...defaultLayoutSlots,\n ...slots,\n };\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultMobileNavOpen);\n const open = mobileNavOpen ?? uncontrolledOpen;\n const setOpen = React.useCallback(\n (next: boolean) => {\n if (mobileNavOpen === undefined) setUncontrolledOpen(next);\n onMobileNavOpenChange?.(next);\n },\n [mobileNavOpen, onMobileNavOpenChange],\n );\n const closeMobile = React.useCallback(() => setOpen(false), [setOpen]);\n\n const menuButtonRef = React.useRef<HTMLButtonElement>(null);\n const drawerId = React.useId();\n const mainId = React.useId();\n const mainRef = React.useRef<HTMLElement>(null);\n const skipToMain = React.useCallback((event: React.MouseEvent<HTMLAnchorElement>) => {\n const main = mainRef.current;\n if (main === null) return;\n event.preventDefault();\n main.focus();\n }, []);\n const routeFocusOn = routeFocus !== false;\n const routeAnnouncement = useRouteFocus(mainRef, {\n ...(typeof routeFocus === \"object\" ? routeFocus : {}),\n enabled: routeFocusOn,\n });\n\n // The drawer is for narrow screens only: once the menu button is hidden\n // (the window grew past md), a still-open modal drawer would trap focus\n // in an invisible panel, so it closes.\n React.useEffect(() => {\n if (!open) return undefined;\n const closeIfWide = (): void => {\n const button = menuButtonRef.current;\n if (button !== null && window.getComputedStyle(button).display === \"none\") {\n setOpen(false);\n }\n };\n closeIfWide();\n window.addEventListener(\"resize\", closeIfWide);\n return () => window.removeEventListener(\"resize\", closeIfWide);\n }, [open, setOpen]);\n\n const nav = sidebar ?? (\n <nav aria-label={navLabel} className=\"grid gap-1\">\n {navItems.map((item) => {\n const defaultClassName = cn(\n NAV_ITEM_CLASS,\n item.active === true && NAV_ITEM_ACTIVE_CLASS,\n );\n const defaultNode = (\n <NavLink\n item={item}\n href={item.href}\n aria-current={item.active === true ? \"page\" : undefined}\n className={defaultClassName}\n onClick={closeMobile}\n >\n {item.icon != null && <span aria-hidden=\"true\">{item.icon}</span>}\n {item.label}\n </NavLink>\n );\n return (\n <React.Fragment key={item.key ?? item.href}>\n {renderNavItem ? renderNavItem(item, { defaultNode, defaultClassName }) : defaultNode}\n </React.Fragment>\n );\n })}\n </nav>\n );\n const column = { header: sidebarHeader, nav, footer: sidebarFooter };\n\n const menuButton = (\n <button\n ref={menuButtonRef}\n type=\"button\"\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n // Names the drawer only while it exists.\n aria-controls={open ? drawerId : undefined}\n onClick={() => setOpen(!open)}\n className={cn(ICON_BUTTON_CLASS, \"h-9 w-9 md:hidden\")}\n >\n <MenuIcon className=\"h-5 w-5\" />\n <span className=\"sr-only\">Open navigation</span>\n </button>\n );\n\n return (\n <div\n ref={ref}\n className={cn(\"flex min-h-screen w-full bg-background text-foreground\", className)}\n {...props}\n >\n <SkipLink href={`#${mainId}`} onClick={skipToMain}>\n Skip to content\n </SkipLink>\n <Sidebar {...column} className={sidebarClassName} />\n <MobileDrawer\n {...column}\n className={sidebarClassName}\n open={open}\n onOpenChange={setOpen}\n id={drawerId}\n returnFocusRef={menuButtonRef}\n />\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <Header menuButton={menuButton} className={headerClassName}>\n {header}\n </Header>\n <main\n ref={mainRef}\n id={mainId}\n // Focusable from the skip link, not part of the tab order.\n tabIndex={-1}\n className={cn(\"flex-1 p-6 focus:outline-none\", contentClassName)}\n >\n {children}\n </main>\n </div>\n {routeFocusOn && (\n <div role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {routeAnnouncement}\n </div>\n )}\n </div>\n );\n },\n);\nLayout.displayName = \"Layout\";\n","import type * as React from \"react\";\n\n/**\n * Module-level toast store.\n *\n * `useToast()` can be called anywhere (no provider requirement beyond a\n * mounted <Toaster/>): toasts are pushed into this store and every mounted\n * Toaster/useToast subscriber re-renders via useSyncExternalStore.\n */\n\nexport type ToastVariant = \"default\" | \"success\" | \"error\" | \"info\";\n\nexport interface ToastOptions {\n /** Stable id (defaults to an auto-generated one). Re-using an id replaces. */\n id?: string;\n title?: React.ReactNode;\n description?: React.ReactNode;\n variant?: ToastVariant;\n /** Per-toast auto-dismiss override in ms (Toaster default otherwise). */\n duration?: number;\n /** Action slot (e.g. an \"Undo\" button), rendered inside the toast. */\n action?: React.ReactNode;\n}\n\nexport interface ToastInstance extends ToastOptions {\n id: string;\n variant: ToastVariant;\n}\n\nexport interface ToastHandle {\n id: string;\n dismiss: () => void;\n}\n\n/** Oldest toasts beyond this count are dropped. */\nconst TOAST_LIMIT = 5;\n\ntype Listener = () => void;\n\nlet toasts: readonly ToastInstance[] = [];\nconst listeners = new Set<Listener>();\nlet counter = 0;\n\nfunction emit(): void {\n for (const listener of listeners) {\n listener();\n }\n}\n\nexport function subscribeToToasts(listener: Listener): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\nexport function getToasts(): readonly ToastInstance[] {\n return toasts;\n}\n\nexport function dismissToast(id?: string): void {\n const next = id === undefined ? [] : toasts.filter((item) => item.id !== id);\n if (next.length !== toasts.length) {\n toasts = next;\n emit();\n }\n}\n\nexport function addToast(options: ToastOptions): ToastHandle {\n counter += 1;\n const id = options.id ?? `karni-toast-${String(counter)}`;\n const instance: ToastInstance = {\n ...options,\n id,\n variant: options.variant ?? \"default\",\n };\n toasts = [...toasts.filter((item) => item.id !== id), instance].slice(-TOAST_LIMIT);\n emit();\n return {\n id,\n dismiss: () => {\n dismissToast(id);\n },\n };\n}\n\n/** Test helper: clears all toasts and listeners' state (not in the barrel). */\nexport function resetToastStore(): void {\n toasts = [];\n counter = 0;\n emit();\n}\n","import * as React from \"react\";\nimport {\n addToast,\n dismissToast,\n getToasts,\n subscribeToToasts,\n type ToastHandle,\n type ToastInstance,\n type ToastOptions,\n} from \"./toast-store\";\n\nexport interface UseToastResult {\n /** Currently visible toasts (rendered by <Toaster/>). */\n toasts: readonly ToastInstance[];\n /** Full-control entry point: show any ToastOptions. */\n toast: (options: ToastOptions) => ToastHandle;\n /** Shorthand: success variant. */\n success: (title: React.ReactNode, options?: Omit<ToastOptions, \"variant\">) => ToastHandle;\n /** Shorthand: error variant. */\n error: (title: React.ReactNode, options?: Omit<ToastOptions, \"variant\">) => ToastHandle;\n /** Shorthand: info variant. */\n info: (title: React.ReactNode, options?: Omit<ToastOptions, \"variant\">) => ToastHandle;\n /** Dismiss one toast by id, or all when called without arguments. */\n dismiss: (id?: string) => void;\n}\n\nfunction makeShorthand(\n variant: \"success\" | \"error\" | \"info\",\n): (title: React.ReactNode, options?: Omit<ToastOptions, \"variant\">) => ToastHandle {\n return (title, options) => addToast({ ...options, title, variant });\n}\n\nconst stableApi = {\n toast: addToast,\n success: makeShorthand(\"success\"),\n error: makeShorthand(\"error\"),\n info: makeShorthand(\"info\"),\n dismiss: dismissToast,\n} as const;\n\n/**\n * Imperative toast API + the live toast list.\n *\n * Requires a mounted <Toaster/> somewhere in the tree to actually render the\n * toasts. The functions themselves are stable module-level references, safe\n * to use in effects and callbacks without dependency churn.\n */\nexport function useToast(): UseToastResult {\n const toasts = React.useSyncExternalStore(subscribeToToasts, getToasts, getToasts);\n return React.useMemo(() => ({ toasts, ...stableApi }), [toasts]);\n}\n","import * as ToastPrimitive from \"@radix-ui/react-toast\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { variants, type VariantProps } from \"../../lib/variants\";\nimport { dismissToast, type ToastVariant } from \"./toast-store\";\nimport { useToast } from \"./use-toast\";\nimport { registerComponentRole } from \"../../lib/roles\";\n\nregisterComponentRole(\"toast\", \"Toaster\");\n\ntype IconProps = React.SVGAttributes<SVGSVGElement>;\n\nfunction CloseIcon(props: IconProps): React.ReactElement {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable={false}\n {...props}\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Per-variant toast styling, with colors that resolve through --karni-* tokens\n * only (success leans on primary, error on destructive, info on muted).\n */\nexport const toastVariants = variants({\n base: \"pointer-events-auto relative flex w-full items-start gap-3 overflow-hidden rounded-md border p-4 pr-8 shadow-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n variants: {\n variant: {\n default: \"border-border bg-background text-foreground\",\n success: \"border-primary bg-background text-foreground\",\n error: \"border-destructive bg-destructive text-destructive-foreground\",\n info: \"border-border bg-muted text-foreground\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n});\n\nexport type ToastVariantProps = VariantProps<typeof toastVariants>;\n\n/** What the `Title` and `Description` slots receive. */\nexport interface ToasterSlotProps {\n children: React.ReactNode;\n variant: ToastVariant;\n}\n\n/** What the `CloseButton` slot receives. */\nexport interface ToasterCloseButtonProps {\n /** Its accessible name (\"Dismiss\"). */\n label: string;\n variant: ToastVariant;\n /** Removes the toast. */\n dismiss: () => void;\n}\n\n/** The parts of each toast a project can replace (`slots={{ CloseButton: MyClose }}`). */\nexport interface ToasterSlots {\n Title: React.ComponentType<ToasterSlotProps>;\n Description: React.ComponentType<ToasterSlotProps>;\n /** The top-right dismiss button. */\n CloseButton: React.ComponentType<ToasterCloseButtonProps>;\n}\n\nfunction DefaultTitle({ children }: ToasterSlotProps): React.ReactElement {\n return <ToastPrimitive.Title className=\"text-sm font-semibold\">{children}</ToastPrimitive.Title>;\n}\n\nfunction DefaultDescription({ children }: ToasterSlotProps): React.ReactElement {\n return (\n <ToastPrimitive.Description className=\"text-sm opacity-90\">\n {children}\n </ToastPrimitive.Description>\n );\n}\n\nfunction DefaultCloseButton({ label }: ToasterCloseButtonProps): React.ReactElement {\n // The focus indicator takes the toast's text colour, so it shows on every variant.\n return (\n <ToastPrimitive.Close\n aria-label={label}\n className=\"absolute right-2 top-2 rounded-md p-1 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-current\"\n >\n <CloseIcon className=\"h-4 w-4\" />\n </ToastPrimitive.Close>\n );\n}\n\n/** The default pieces of a toast, for wrapping one. */\nexport const defaultToasterSlots: ToasterSlots = {\n Title: DefaultTitle,\n Description: DefaultDescription,\n CloseButton: DefaultCloseButton,\n};\n\n/**\n * How urgently screen readers announce each variant: an error interrupts\n * (assertive), everything else waits for a pause (polite).\n */\nconst ANNOUNCE: Record<ToastVariant, \"foreground\" | \"background\"> = {\n default: \"background\",\n success: \"background\",\n info: \"background\",\n error: \"foreground\",\n};\n\nexport interface ToasterProps {\n /** Auto-dismiss duration in ms for toasts without their own (default 5000). */\n duration?: number;\n /** Swipe-to-dismiss direction (default \"right\"). */\n swipeDirection?: \"right\" | \"left\" | \"up\" | \"down\";\n /** Accessible label prefix announced with each toast (Radix Provider). */\n label?: string;\n /** Extra classes for the viewport, the list the toasts render in. */\n className?: string;\n /** Same as `className` (kept for compatibility). */\n viewportClassName?: string;\n /** Extra classes for every toast root. */\n toastClassName?: string;\n /** Replaces the Title, Description or CloseButton of every toast (see ToasterSlots). */\n slots?: Partial<ToasterSlots>;\n}\n\n/**\n * Renders the toasts pushed through useToast(). Mount exactly one near the\n * app root. Position defaults to the bottom-right corner. Override it with\n * `className` (it merges via cn(), so e.g. \"top-0 bottom-auto\" wins).\n *\n * Keyboard and screen readers: an error is announced at once (assertive),\n * other toasts politely. F8 moves focus to the toasts. Tab reaches each one\n * and its buttons, and Escape dismisses the focused toast. A toast's timer\n * pauses while the pointer is over the toasts or focus is inside them, and\n * while the window is in the background.\n */\nexport function Toaster({\n duration = 5000,\n swipeDirection = \"right\",\n label = \"Notification\",\n className,\n viewportClassName,\n toastClassName,\n slots,\n}: ToasterProps): React.ReactElement {\n const { toasts } = useToast();\n const { Title, Description, CloseButton } = { ...defaultToasterSlots, ...slots };\n\n return (\n <ToastPrimitive.Provider duration={duration} swipeDirection={swipeDirection} label={label}>\n {toasts.map((item) => (\n <ToastPrimitive.Root\n key={item.id}\n duration={item.duration}\n type={ANNOUNCE[item.variant]}\n data-variant={item.variant satisfies ToastVariant}\n onOpenChange={(open) => {\n if (!open) {\n dismissToast(item.id);\n }\n }}\n className={toastVariants({ variant: item.variant, className: toastClassName })}\n >\n <div className=\"grid flex-1 gap-1\">\n {item.title != null && <Title variant={item.variant}>{item.title}</Title>}\n {item.description != null && (\n <Description variant={item.variant}>{item.description}</Description>\n )}\n </div>\n {item.action != null && <div className=\"flex shrink-0 items-center\">{item.action}</div>}\n <CloseButton\n label=\"Dismiss\"\n variant={item.variant}\n dismiss={() => dismissToast(item.id)}\n />\n </ToastPrimitive.Root>\n ))}\n <ToastPrimitive.Viewport\n className={cn(\n \"fixed bottom-0 right-0 z-toast flex w-full max-w-96 flex-col gap-2 p-4 outline-none\",\n viewportClassName,\n className,\n )}\n />\n </ToastPrimitive.Provider>\n );\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\nimport { Skeleton } from \"../primitives/skeleton\";\n\nregisterComponentRole(\"stat\", \"Stat\");\n\ntype ArrowProps = React.SVGAttributes<SVGSVGElement>;\n\nfunction iconProps(props: ArrowProps): ArrowProps {\n return {\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n \"aria-hidden\": true,\n focusable: false,\n ...props,\n };\n}\n\nfunction ArrowUpIcon(props: ArrowProps): React.ReactElement {\n return (\n <svg {...iconProps(props)}>\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"5\" />\n <polyline points=\"5 12 12 5 19 12\" />\n </svg>\n );\n}\n\nfunction ArrowDownIcon(props: ArrowProps): React.ReactElement {\n return (\n <svg {...iconProps(props)}>\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <polyline points=\"19 12 12 19 5 12\" />\n </svg>\n );\n}\n\nfunction FlatIcon(props: ArrowProps): React.ReactElement {\n return (\n <svg {...iconProps(props)}>\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n );\n}\n\n/** What the `Label`, `Value` and `Icon` slots receive. */\nexport interface StatSlotProps {\n children: React.ReactNode;\n}\n\n/** What the `Delta` slot receives. */\nexport interface StatDeltaProps {\n /** The `delta` prop: a number, or any node. */\n delta: number | React.ReactNode;\n /** The `formatDelta` prop (or the default signed format). */\n formatDelta: (delta: number) => string;\n}\n\n/** The parts of the tile a project can replace (`slots={{ Delta: GoodWhenDown }}`). */\nexport interface StatSlots {\n /** What the number measures. */\n Label: React.ComponentType<StatSlotProps>;\n /** The headline value. */\n Value: React.ComponentType<StatSlotProps>;\n /** The change indicator. The default treats a rise as neutral and a fall as destructive. */\n Delta: React.ComponentType<StatDeltaProps>;\n /** Wraps `icon`. Decorative, hidden from assistive tech. */\n Icon: React.ComponentType<StatSlotProps>;\n}\n\nexport interface StatProps extends React.HTMLAttributes<HTMLDivElement> {\n /** What the number measures (\"Active users\"). */\n label: React.ReactNode;\n /** The headline value: a preformatted string or any node. */\n value: React.ReactNode;\n /**\n * Change indicator. A number renders a signed figure with an up, down or\n * flat marker (negative numbers use the destructive token) plus\n * screen-reader context. Any other node renders verbatim in the delta slot.\n */\n delta?: number | React.ReactNode;\n /** Formats a numeric `delta` (default: signed, locale formatted). */\n formatDelta?: (delta: number) => string;\n /** Optional icon slot, top-right. */\n icon?: React.ReactNode;\n /** True while the value loads: a placeholder replaces the value and the delta. */\n loading?: boolean;\n /** Replaces the Label, Value, Delta or Icon. See StatSlots. */\n slots?: Partial<StatSlots>;\n}\n\nfunction defaultFormatDelta(delta: number): string {\n const formatted = Math.abs(delta).toLocaleString();\n if (delta === 0) return formatted;\n return delta > 0 ? `+${formatted}` : `-${formatted}`;\n}\n\nfunction DefaultLabel({ children }: StatSlotProps): React.ReactElement {\n return <p className=\"text-sm font-medium text-muted-foreground\">{children}</p>;\n}\n\nfunction DefaultValue({ children }: StatSlotProps): React.ReactElement {\n return <p className=\"text-2xl font-semibold tracking-tight\">{children}</p>;\n}\n\nfunction DefaultIcon({ children }: StatSlotProps): React.ReactElement {\n return (\n <span aria-hidden=\"true\" className=\"text-muted-foreground [&>svg]:h-4 [&>svg]:w-4\">\n {children}\n </span>\n );\n}\n\nfunction DefaultDelta({ delta, formatDelta }: StatDeltaProps): React.ReactElement | null {\n if (typeof delta === \"number\") {\n if (!Number.isFinite(delta)) return null;\n const direction = delta < 0 ? \"down\" : delta > 0 ? \"up\" : \"flat\";\n const Icon = direction === \"down\" ? ArrowDownIcon : direction === \"up\" ? ArrowUpIcon : FlatIcon;\n const spoken =\n direction === \"down\" ? \"Decreased by\" : direction === \"up\" ? \"Increased by\" : \"Unchanged:\";\n return (\n <p\n data-trend={direction}\n className={cn(\n \"flex items-center gap-1 text-sm font-medium\",\n direction === \"down\" ? \"text-destructive\" : \"text-muted-foreground\",\n )}\n >\n <Icon className=\"h-3.5 w-3.5\" />\n <span className=\"sr-only\">{spoken} </span>\n {formatDelta(delta)}\n </p>\n );\n }\n if (delta == null) return null;\n return <div className=\"text-sm text-muted-foreground\">{delta}</div>;\n}\n\n/** The default pieces of the tile, for wrapping one. */\nexport const defaultStatSlots: StatSlots = {\n Label: DefaultLabel,\n Value: DefaultValue,\n Delta: DefaultDelta,\n Icon: DefaultIcon,\n};\n\n/**\n * KPI tile: label, value, optional delta and icon.\n *\n * Escape hatches: `slots` replaces the Label, Value, Delta or Icon (a Delta\n * for metrics where down is good, say), `value`/`delta`/`icon` accept\n * arbitrary nodes, `formatDelta` overrides numeric formatting, and `className`\n * merges via cn().\n */\nexport const Stat = React.forwardRef<HTMLDivElement, StatProps>(\n (\n {\n label,\n value,\n delta,\n formatDelta = defaultFormatDelta,\n icon,\n loading = false,\n slots,\n className,\n ...props\n },\n ref,\n ) => {\n const { Label, Value, Delta, Icon } = { ...defaultStatSlots, ...slots };\n return (\n <div\n ref={ref}\n aria-busy={loading || undefined}\n className={cn(\n \"flex flex-col gap-1 rounded-lg border border-border bg-card p-4 text-card-foreground\",\n className,\n )}\n {...props}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <Label>{label}</Label>\n {icon != null && <Icon>{icon}</Icon>}\n </div>\n {loading ? (\n <>\n <Skeleton className=\"h-8 w-24\" />\n <span className=\"sr-only\">Loading</span>\n </>\n ) : (\n <>\n <Value>{value}</Value>\n {delta != null && <Delta delta={delta} formatDelta={formatDelta} />}\n </>\n )}\n </div>\n );\n },\n);\nStat.displayName = \"Stat\";\n","import * as VisuallyHidden from \"@radix-ui/react-visually-hidden\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { registerComponentRole } from \"../../lib/roles\";\nimport { Skeleton } from \"../primitives/skeleton\";\nimport { EmptyValue } from \"../resource/empty-value\";\n\nregisterComponentRole(\"chart\", \"DataChart\");\n\n/**\n * In-house SVG chart (contract: no chart dependency).\n *\n * Accessibility model (contract D10): the SVG is a labelled image\n * (role=\"img\" + aria-label + <title>/<desc>) described by a generated\n * summary (the range of each series). The REAL accessible data surface is a\n * visually-hidden <table> rendered next to it. The tooltip is rendered\n * OUTSIDE the role=\"img\" element and hidden from assistive tech. The SVG is\n * focusable, the arrow keys move the tooltip from point to point, and each\n * point is announced through a polite live region.\n *\n * Colors come exclusively from the --karni-chart-1..5 tokens, via the\n * Tailwind preset's chart color scale (stroke-chart-N / fill-chart-N /\n * bg-chart-N classes, whole class names per contract D7).\n */\n\nexport type DataChartKind = \"line\" | \"bar\";\n\nexport interface DataChartPoint {\n label: string;\n value: number;\n}\n\nexport interface DataChartSeries {\n name: string;\n data: readonly DataChartPoint[];\n}\n\nexport interface DataChartTooltipContext {\n /** Category (x-axis) label under the pointer. */\n label: string;\n /** One entry per series that has a value at this category. */\n points: ReadonlyArray<{ seriesName: string; value: number; swatchClassName: string }>;\n}\n\n/** What the `Tooltip` slot receives: the hovered (or keyboard-selected) category. */\nexport interface DataChartTooltipProps extends DataChartTooltipContext {\n valueFormatter: (value: number) => string;\n}\n\n/** What the `Legend` slot receives. */\nexport interface DataChartLegendProps {\n series: ReadonlyArray<{ name: string; swatchClassName: string }>;\n}\n\n/** What the `Empty` slot receives (no plottable data). */\nexport interface DataChartEmptyProps {\n /** The chart's title, for screen readers. */\n title: string;\n /** The `emptyLabel` prop. */\n label: React.ReactNode;\n}\n\n/** What the `Loading` slot receives (`loading` is true). */\nexport interface DataChartLoadingProps {\n title: string;\n /** The viewBox size, for a placeholder of the chart's proportions. */\n width: number;\n height: number;\n}\n\n/** The parts of the chart a project can replace (`slots={{ Tooltip: MyTooltip }}`). */\nexport interface DataChartSlots {\n /** The tooltip's content (the positioned box around it stays the chart's). */\n Tooltip: React.ComponentType<DataChartTooltipProps>;\n /** The series legend, decorative (the hidden table carries the names). */\n Legend: React.ComponentType<DataChartLegendProps>;\n /** Shown instead of the chart when there is nothing to plot. */\n Empty: React.ComponentType<DataChartEmptyProps>;\n /** Shown instead of the chart while `loading`. */\n Loading: React.ComponentType<DataChartLoadingProps>;\n}\n\nexport interface DataChartProps {\n kind: DataChartKind;\n /** Single-series shorthand (ignored when `series` is given). */\n data?: readonly DataChartPoint[];\n /** Multi-series data. Series cycle through --karni-chart-1..5. */\n series?: readonly DataChartSeries[];\n /** Chart title: SVG <title>, aria-label and the hidden table's caption. */\n title: string;\n /** Longer description for the SVG <desc>. */\n description?: string;\n /**\n * What screen readers hear after the title and description. Default: a\n * generated summary (each series' lowest and highest value). \"\" omits it.\n */\n summary?: string;\n /** Formats values in the tooltip, y-axis ticks and the hidden table. */\n valueFormatter?: (value: number) => string;\n /** Formats x-axis tick labels (default: the category label itself). */\n xTickFormatter?: (label: string) => string;\n /** Fully custom tooltip content. Prefer the `Tooltip` slot. */\n renderTooltip?: (context: DataChartTooltipContext) => React.ReactNode;\n /** viewBox width (default 640). The rendered size is responsive. */\n width?: number;\n /** viewBox height (default 240). */\n height?: number;\n /** Approximate number of y-axis ticks (default 4). */\n yTickCount?: number;\n /** Show the series legend (default: only for 2+ series). */\n showLegend?: boolean;\n /** Show the tooltip on hover and keyboard focus (default true). */\n showTooltip?: boolean;\n /** Column header of the hidden table's category column (default \"Label\"). */\n categoryHeader?: string;\n /** Text shown when there is no plottable data. */\n emptyLabel?: string;\n /** True while the data loads: a placeholder of the chart's size replaces it. */\n loading?: boolean;\n /** Replaces the Tooltip, Legend, Empty or Loading. See DataChartSlots. */\n slots?: Partial<DataChartSlots>;\n className?: string;\n}\n\nconst SERIES_STROKE = [\n \"stroke-chart-1\",\n \"stroke-chart-2\",\n \"stroke-chart-3\",\n \"stroke-chart-4\",\n \"stroke-chart-5\",\n] as const;\n\nconst SERIES_FILL = [\n \"fill-chart-1\",\n \"fill-chart-2\",\n \"fill-chart-3\",\n \"fill-chart-4\",\n \"fill-chart-5\",\n] as const;\n\nconst SERIES_SWATCH = [\n \"bg-chart-1\",\n \"bg-chart-2\",\n \"bg-chart-3\",\n \"bg-chart-4\",\n \"bg-chart-5\",\n] as const;\n\nfunction seriesClass(classes: readonly string[], index: number): string {\n const value = classes[index % classes.length];\n // The modulo keeps the index in range; the fallback only satisfies strict\n // indexing and never triggers at runtime.\n return value ?? classes[0] ?? \"\";\n}\n\nconst MARGIN = { top: 8, right: 12, bottom: 28, left: 48 } as const;\n/** Tick label size in viewBox units, as drawn when the chart renders at its viewBox size or larger. */\nconst TICK_FONT = 10;\n/** The smallest tick label, in CSS pixels, a narrow chart scales its labels up to. */\nconst MIN_TICK_PX = 11;\n\nfunction niceNum(range: number, round: boolean): number {\n const exponent = Math.floor(Math.log10(range));\n const fraction = range / 10 ** exponent;\n let niceFraction: number;\n if (round) {\n niceFraction = fraction < 1.5 ? 1 : fraction < 3 ? 2 : fraction < 7 ? 5 : 10;\n } else {\n niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10;\n }\n return niceFraction * 10 ** exponent;\n}\n\nfunction niceTicks(min: number, max: number, count: number): number[] {\n const span = max > min ? max - min : 1;\n const step = niceNum(niceNum(span, false) / Math.max(1, count), true);\n const start = Math.floor(min / step) * step;\n const end = Math.ceil(max / step) * step;\n const ticks: number[] = [];\n for (let value = start; value <= end + step / 2; value += step) {\n // Trim float noise (0.30000000000000004 → 0.3).\n ticks.push(Number(value.toFixed(10)));\n }\n return ticks;\n}\n\ninterface NormalizedChart {\n categories: readonly string[];\n seriesNames: readonly string[];\n /** matrix[seriesIndex][categoryIndex], null when missing/non-finite. */\n matrix: ReadonlyArray<ReadonlyArray<number | null>>;\n}\n\nfunction normalize(\n data: readonly DataChartPoint[] | undefined,\n series: readonly DataChartSeries[] | undefined,\n): NormalizedChart {\n const resolved: readonly DataChartSeries[] =\n series ?? (data !== undefined ? [{ name: \"Value\", data }] : []);\n\n const categories: string[] = [];\n const seen = new Set<string>();\n for (const s of resolved) {\n for (const point of s.data) {\n if (!seen.has(point.label)) {\n seen.add(point.label);\n categories.push(point.label);\n }\n }\n }\n\n const matrix = resolved.map((s) => {\n const byLabel = new Map<string, number>();\n for (const point of s.data) {\n if (Number.isFinite(point.value)) {\n byLabel.set(point.label, point.value);\n }\n }\n return categories.map((label) => byLabel.get(label) ?? null);\n });\n\n return { categories, seriesNames: resolved.map((s) => s.name), matrix };\n}\n\nfunction defaultValueFormatter(value: number): string {\n return value.toLocaleString();\n}\n\n/** \"Line chart, Jan to Jun. Signups: lowest 120 (Jan), highest 300 (May).\" */\nfunction describeChart(\n kind: DataChartKind,\n chart: NormalizedChart,\n format: (value: number) => string,\n): string {\n const { categories, seriesNames, matrix } = chart;\n const span =\n categories.length > 1\n ? `${categories[0] ?? \"\"} to ${categories[categories.length - 1] ?? \"\"}`\n : (categories[0] ?? \"\");\n const parts = [`${kind === \"line\" ? \"Line\" : \"Bar\"} chart, ${span}.`];\n matrix.forEach((row, seriesIndex) => {\n let low = -1;\n let high = -1;\n for (let index = 0; index < row.length; index += 1) {\n const value = row[index] ?? null;\n if (value === null) continue;\n if (low === -1 || value < (row[low] ?? value)) low = index;\n if (high === -1 || value > (row[high] ?? value)) high = index;\n }\n if (low === -1 || high === -1) return;\n const prefix = matrix.length > 1 ? `${seriesNames[seriesIndex] ?? \"\"}: lowest` : \"Lowest\";\n parts.push(\n `${prefix} ${format(row[low] ?? 0)} (${categories[low] ?? \"\"}), highest ${format(row[high] ?? 0)} (${categories[high] ?? \"\"}).`,\n );\n });\n return parts.join(\" \");\n}\n\nfunction DefaultTooltip({\n label,\n points,\n valueFormatter,\n}: DataChartTooltipProps): React.ReactElement {\n return (\n <>\n <p className=\"mb-1 font-medium\">{label}</p>\n {points.map((point) => (\n <p key={point.seriesName} className=\"flex items-center gap-1.5\">\n <span className={cn(\"h-2 w-2 shrink-0 rounded-full\", point.swatchClassName)} />\n <span className=\"text-muted-foreground\">{point.seriesName}</span>\n <span className=\"ml-auto font-medium\">{valueFormatter(point.value)}</span>\n </p>\n ))}\n </>\n );\n}\n\nfunction DefaultLegend({ series }: DataChartLegendProps): React.ReactElement {\n return (\n <div aria-hidden=\"true\" className=\"mt-2 flex flex-wrap items-center gap-x-4 gap-y-1\">\n {series.map(({ name, swatchClassName }) => (\n <span key={name} className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <span className={cn(\"h-2 w-2 rounded-full\", swatchClassName)} />\n {name}\n </span>\n ))}\n </div>\n );\n}\n\nfunction DefaultEmpty({ title, label }: DataChartEmptyProps): React.ReactElement {\n return (\n <div className=\"flex w-full items-center justify-center rounded-lg border border-dashed border-border px-6 py-10 text-sm text-muted-foreground\">\n <span className=\"sr-only\">{title}: </span>\n {label}\n </div>\n );\n}\n\nfunction DefaultLoading({ title, width, height }: DataChartLoadingProps): React.ReactElement {\n return (\n <>\n <Skeleton\n className=\"w-full\"\n style={{ aspectRatio: `${String(width)} / ${String(height)}` }}\n />\n <span className=\"sr-only\">Loading {title}</span>\n </>\n );\n}\n\n/** The default pieces of the chart, for wrapping one. */\nexport const defaultDataChartSlots: DataChartSlots = {\n Tooltip: DefaultTooltip,\n Legend: DefaultLegend,\n Empty: DefaultEmpty,\n Loading: DefaultLoading,\n};\n\n/** The rendered width of an element, tracked as it resizes (null before the first measure). */\nfunction useRenderedWidth(ref: React.RefObject<Element | null>, active: boolean): number | null {\n const [width, setWidth] = React.useState<number | null>(null);\n React.useEffect(() => {\n const element = ref.current;\n if (!active || element === null || typeof ResizeObserver === \"undefined\") return undefined;\n const observer = new ResizeObserver((entries) => {\n const measured = entries[0]?.contentRect.width;\n if (measured !== undefined && measured > 0) setWidth(measured);\n });\n observer.observe(element);\n return () => observer.disconnect();\n }, [ref, active]);\n return width;\n}\n\n/**\n * Minimal line/bar chart driven by `{label, value}` points or named series.\n *\n * Keyboard and screen readers: the chart is an image named by `title`,\n * described by `description` and a generated summary, with every value in a\n * visually-hidden table. Tab focuses it. The arrow keys (Home, End) move the\n * tooltip from category to category and announce each one. Escape hides it.\n *\n * Escape hatches: `slots` (replaces the Tooltip, Legend, Empty or Loading\n * pieces), `valueFormatter`/`xTickFormatter`, `summary`, `renderTooltip`,\n * `width`/`height`/`yTickCount`, legend and tooltip toggles, `className`\n * (merged via cn()). Colors are only themeable through the\n * --karni-chart-1..5 CSS variables.\n */\nexport function DataChart({\n kind,\n data,\n series,\n title,\n description,\n summary,\n valueFormatter = defaultValueFormatter,\n xTickFormatter,\n renderTooltip,\n width = 640,\n height = 240,\n yTickCount = 4,\n showLegend,\n showTooltip = true,\n categoryHeader = \"Label\",\n emptyLabel = \"No data\",\n loading = false,\n slots,\n className,\n}: DataChartProps): React.ReactElement {\n const { Tooltip, Legend, Empty, Loading } = { ...defaultDataChartSlots, ...slots };\n const titleId = React.useId();\n const descId = React.useId();\n const summaryId = React.useId();\n const [hovered, setHoveredState] = React.useState<number | null>(null);\n // The latest index, for key presses that arrive before a re-render.\n const hoveredRef = React.useRef<number | null>(null);\n const setHovered = React.useCallback((index: number | null) => {\n hoveredRef.current = index;\n setHoveredState(index);\n }, []);\n // What the live region says: set by the keyboard only, so hovering stays quiet.\n const [announcement, setAnnouncement] = React.useState(\"\");\n const svgRef = React.useRef<SVGSVGElement>(null);\n\n const chart = React.useMemo(() => normalize(data, series), [data, series]);\n const { categories, seriesNames, matrix } = chart;\n\n const values = matrix.flat().filter((value): value is number => value !== null);\n const plottable = !loading && categories.length > 0 && values.length > 0;\n const renderedWidth = useRenderedWidth(svgRef, plottable);\n\n if (loading) {\n return (\n <div aria-busy=\"true\" className={cn(\"w-full\", className)}>\n <Loading title={title} width={width} height={height} />\n </div>\n );\n }\n\n if (!plottable) {\n return (\n <div className={cn(\"w-full\", className)}>\n <Empty title={title} label={emptyLabel} />\n </div>\n );\n }\n\n // A chart drawn narrower than its viewBox would shrink its labels below\n // legibility: keep them at MIN_TICK_PX, and the lines visible, on phones.\n const scale = renderedWidth === null ? 1 : renderedWidth / width;\n const fontSize = renderedWidth === null ? TICK_FONT : Math.max(TICK_FONT, MIN_TICK_PX / scale);\n const strokeWidth = Math.max(2, 1.5 / scale);\n const pointRadius = Math.max(3, 2.5 / scale);\n\n // scales\n const rawMin = Math.min(0, ...values);\n const rawMax = Math.max(0, ...values);\n const ticks = niceTicks(rawMin, rawMax, yTickCount);\n const domainMin = ticks[0] ?? rawMin;\n const domainMax = ticks[ticks.length - 1] ?? rawMax;\n const domainSpan = domainMax - domainMin || 1;\n\n const longestTick = Math.max(...ticks.map((tick) => valueFormatter(tick).length));\n const margin = {\n top: Math.max(MARGIN.top, fontSize * 0.6),\n right: MARGIN.right,\n // Room for the y labels (about 0.6em a character) and the x labels.\n left: Math.max(MARGIN.left, Math.ceil(longestTick * fontSize * 0.6) + 6),\n bottom: Math.max(MARGIN.bottom, Math.ceil(fontSize * 2)),\n };\n const plotWidth = width - margin.left - margin.right;\n const plotHeight = height - margin.top - margin.bottom;\n const yScale = (value: number): number =>\n margin.top + ((domainMax - value) / domainSpan) * plotHeight;\n const bandWidth = plotWidth / categories.length;\n const bandCenter = (index: number): number => margin.left + (index + 0.5) * bandWidth;\n const zeroY = yScale(Math.max(domainMin, Math.min(domainMax, 0)));\n\n // marks\n const seriesCount = Math.max(1, matrix.length);\n const groupWidth = bandWidth * 0.7;\n const barWidth = groupWidth / seriesCount;\n\n const marks = matrix.map((row, seriesIndex) => {\n if (kind === \"bar\") {\n return (\n <g key={seriesIndex} className={seriesClass(SERIES_FILL, seriesIndex)}>\n {row.map((value, categoryIndex) => {\n if (value === null) {\n return null;\n }\n const x = bandCenter(categoryIndex) - groupWidth / 2 + seriesIndex * barWidth;\n const y = Math.min(yScale(value), zeroY);\n const barHeight = Math.abs(yScale(value) - zeroY);\n return (\n <rect\n key={categoryIndex}\n x={x}\n y={y}\n width={Math.max(1, barWidth - 2)}\n height={barHeight}\n rx={2}\n />\n );\n })}\n </g>\n );\n }\n\n const points = row\n .map((value, categoryIndex) =>\n value === null ? null : ([bandCenter(categoryIndex), yScale(value)] as const),\n )\n .filter((point): point is readonly [number, number] => point !== null);\n\n return (\n <g key={seriesIndex}>\n <polyline\n className={seriesClass(SERIES_STROKE, seriesIndex)}\n fill=\"none\"\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n points={points.map(([x, y]) => `${String(x)},${String(y)}`).join(\" \")}\n />\n {points.map(([x, y], pointIndex) => (\n <circle\n key={pointIndex}\n className={seriesClass(SERIES_FILL, seriesIndex)}\n cx={x}\n cy={y}\n r={pointRadius}\n />\n ))}\n </g>\n );\n });\n\n const pointsAt = (index: number): DataChartTooltipContext[\"points\"] =>\n matrix\n .map((row, seriesIndex) => ({\n seriesName: seriesNames[seriesIndex] ?? \"\",\n value: row[index] ?? null,\n swatchClassName: seriesClass(SERIES_SWATCH, seriesIndex),\n }))\n .filter(\n (entry): entry is { seriesName: string; value: number; swatchClassName: string } =>\n entry.value !== null,\n );\n\n // tooltip geometry (percentages of the rendered box)\n const pct = (value: number, total: number): string => `${String((value / total) * 100)}%`;\n const hoveredPoints = hovered === null ? [] : pointsAt(hovered);\n const hoveredLabel = hovered === null ? undefined : categories[hovered];\n\n const select = (index: number | null): void => {\n setHovered(index);\n if (index === null) {\n setAnnouncement(\"\");\n return;\n }\n const spoken = pointsAt(index)\n .map((point) =>\n matrix.length > 1\n ? `${point.seriesName} ${valueFormatter(point.value)}`\n : valueFormatter(point.value),\n )\n .join(\", \");\n setAnnouncement(`${categories[index] ?? \"\"}: ${spoken}`);\n };\n\n const onKeyDown = (event: React.KeyboardEvent<SVGSVGElement>): void => {\n const last = categories.length - 1;\n const current = hoveredRef.current;\n let next: number | null | undefined;\n switch (event.key) {\n case \"ArrowRight\":\n case \"ArrowDown\":\n next = current === null ? 0 : Math.min(last, current + 1);\n break;\n case \"ArrowLeft\":\n case \"ArrowUp\":\n next = current === null ? last : Math.max(0, current - 1);\n break;\n case \"Home\":\n next = 0;\n break;\n case \"End\":\n next = last;\n break;\n case \"Escape\":\n next = null;\n break;\n default:\n return;\n }\n event.preventDefault();\n select(next);\n };\n\n const generatedSummary =\n summary ??\n `${describeChart(kind, chart, valueFormatter)}${\n showTooltip ? \" Use the arrow keys to read each value.\" : \"\"\n }`;\n const describedBy =\n [description !== undefined ? descId : null, generatedSummary !== \"\" ? summaryId : null]\n .filter(Boolean)\n .join(\" \") || undefined;\n\n const defaultLegend = seriesNames.length > 1;\n\n return (\n <div className={cn(\"w-full\", className)}>\n <div className=\"relative w-full rounded-md ring-offset-background has-[svg:focus-visible]:ring-2 has-[svg:focus-visible]:ring-ring has-[svg:focus-visible]:ring-offset-2\">\n <svg\n ref={svgRef}\n role=\"img\"\n aria-label={title}\n aria-labelledby={titleId}\n aria-describedby={describedBy}\n tabIndex={showTooltip ? 0 : undefined}\n onKeyDown={showTooltip ? onKeyDown : undefined}\n onBlur={showTooltip ? () => select(null) : undefined}\n viewBox={`0 0 ${String(width)} ${String(height)}`}\n className=\"block h-auto w-full text-muted-foreground focus-visible:outline-none\"\n >\n <title id={titleId}>{title}</title>\n {description !== undefined && <desc id={descId}>{description}</desc>}\n\n {/* y grid + tick labels */}\n {ticks.map((tick) => (\n <g key={tick}>\n <line\n x1={margin.left}\n x2={width - margin.right}\n y1={yScale(tick)}\n y2={yScale(tick)}\n stroke=\"currentColor\"\n strokeOpacity={tick === 0 ? 0.6 : 0.2}\n />\n <text\n x={margin.left - 6}\n y={yScale(tick)}\n textAnchor=\"end\"\n dominantBaseline=\"middle\"\n fontSize={fontSize}\n fill=\"currentColor\"\n >\n {valueFormatter(tick)}\n </text>\n </g>\n ))}\n\n {/* x tick labels */}\n {categories.map((category, index) => (\n <text\n key={category}\n x={bandCenter(index)}\n y={height - margin.bottom + fontSize * 1.4}\n textAnchor=\"middle\"\n fontSize={fontSize}\n fill=\"currentColor\"\n >\n {xTickFormatter ? xTickFormatter(category) : category}\n </text>\n ))}\n\n {marks}\n </svg>\n\n {/* Hover affordance + tooltip: visual only, OUTSIDE the role=\"img\"\n element and hidden from assistive tech (contract D10). */}\n {showTooltip && (\n <div aria-hidden=\"true\" className=\"absolute inset-0\">\n <div\n className=\"absolute flex\"\n style={{\n left: pct(margin.left, width),\n width: pct(plotWidth, width),\n top: pct(margin.top, height),\n height: pct(plotHeight, height),\n }}\n onMouseLeave={() => {\n setHovered(null);\n }}\n >\n {categories.map((category, index) => (\n <div\n key={category}\n data-karni-chart-hit={index}\n className=\"h-full flex-1\"\n onMouseEnter={() => {\n setHovered(index);\n }}\n />\n ))}\n </div>\n {hovered !== null && hoveredLabel !== undefined && hoveredPoints.length > 0 && (\n <div\n data-karni-chart-tooltip=\"\"\n className=\"pointer-events-none absolute z-raised min-w-24 -translate-x-1/2 rounded-md border border-border bg-popover px-2.5 py-1.5 text-xs text-popover-foreground shadow-md\"\n style={{\n left: pct(bandCenter(hovered), width),\n top: pct(margin.top, height),\n }}\n >\n {renderTooltip ? (\n renderTooltip({ label: hoveredLabel, points: hoveredPoints })\n ) : (\n <Tooltip\n label={hoveredLabel}\n points={hoveredPoints}\n valueFormatter={valueFormatter}\n />\n )}\n </div>\n )}\n </div>\n )}\n </div>\n\n {(showLegend ?? defaultLegend) && (\n <Legend\n series={seriesNames.map((name, index) => ({\n name,\n swatchClassName: seriesClass(SERIES_SWATCH, index),\n }))}\n />\n )}\n\n {/* The accessible data surface (contract D10). */}\n <VisuallyHidden.Root asChild>\n <div>\n {generatedSummary !== \"\" && <p id={summaryId}>{generatedSummary}</p>}\n <p role=\"status\">{announcement}</p>\n <table>\n <caption>{title}</caption>\n <thead>\n <tr>\n <th scope=\"col\">{categoryHeader}</th>\n {seriesNames.map((name) => (\n <th key={name} scope=\"col\">\n {name}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {categories.map((category, categoryIndex) => (\n <tr key={category}>\n <th scope=\"row\">{category}</th>\n {matrix.map((row, seriesIndex) => {\n const value = row[categoryIndex] ?? null;\n return (\n <td key={seriesIndex}>\n {value === null ? <EmptyValue /> : valueFormatter(value)}\n </td>\n );\n })}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </VisuallyHidden.Root>\n </div>\n );\n}\n"],"mappings":"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"}
|