@karni/ui 0.0.0-stage → 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.
Files changed (142) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +928 -2
  3. package/dist/index.cjs +9 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.js +8699 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/manifest.json +102 -0
  8. package/dist/mockServiceWorker.js +361 -0
  9. package/dist/script-BVJ9BbPm.cjs +2 -0
  10. package/dist/script-BVJ9BbPm.cjs.map +1 -0
  11. package/dist/script-D1fn4Dm4.js +6 -0
  12. package/dist/script-D1fn4Dm4.js.map +1 -0
  13. package/dist/src/auth/AuthGuard.d.ts +77 -0
  14. package/dist/src/auth/LoginForm.d.ts +63 -0
  15. package/dist/src/auth/engine.d.ts +101 -0
  16. package/dist/src/auth/provider.d.ts +43 -0
  17. package/dist/src/auth/storage.d.ts +26 -0
  18. package/dist/src/auth/types.d.ts +32 -0
  19. package/dist/src/auth/usePermission.d.ts +7 -0
  20. package/dist/src/components/brand/karni-mark.d.ts +21 -0
  21. package/dist/src/components/brand/mark-paths.d.ts +8 -0
  22. package/dist/src/components/chart/data-chart.d.ts +129 -0
  23. package/dist/src/components/empty-state/empty-state.d.ts +40 -0
  24. package/dist/src/components/file-upload/FileUpload.d.ts +108 -0
  25. package/dist/src/components/layout/layout.d.ts +150 -0
  26. package/dist/src/components/layout/route-focus.d.ts +43 -0
  27. package/dist/src/components/modal/modal.d.ts +86 -0
  28. package/dist/src/components/page/page.d.ts +60 -0
  29. package/dist/src/components/primitives/button.d.ts +45 -0
  30. package/dist/src/components/primitives/checkbox.d.ts +8 -0
  31. package/dist/src/components/primitives/dropdown-menu.d.ts +24 -0
  32. package/dist/src/components/primitives/icons.d.ts +19 -0
  33. package/dist/src/components/primitives/input.d.ts +7 -0
  34. package/dist/src/components/primitives/label.d.ts +8 -0
  35. package/dist/src/components/primitives/select.d.ts +94 -0
  36. package/dist/src/components/primitives/skeleton.d.ts +7 -0
  37. package/dist/src/components/primitives/switch.d.ts +8 -0
  38. package/dist/src/components/primitives/tabs.d.ts +10 -0
  39. package/dist/src/components/primitives/textarea.d.ts +7 -0
  40. package/dist/src/components/resource/ResourceDetail.d.ts +7 -0
  41. package/dist/src/components/resource/ResourceForm.d.ts +8 -0
  42. package/dist/src/components/resource/ResourceSelect.d.ts +9 -0
  43. package/dist/src/components/resource/ResourceTable.d.ts +17 -0
  44. package/dist/src/components/resource/audit-fields.d.ts +17 -0
  45. package/dist/src/components/resource/detail/ResourceDetail.d.ts +128 -0
  46. package/dist/src/components/resource/displayLabel.d.ts +12 -0
  47. package/dist/src/components/resource/empty-value.d.ts +17 -0
  48. package/dist/src/components/resource/form/ResourceForm.d.ts +109 -0
  49. package/dist/src/components/resource/form/field-inputs.d.ts +34 -0
  50. package/dist/src/components/resource/form/fixtures.d.ts +24 -0
  51. package/dist/src/components/resource/form/form-states.d.ts +87 -0
  52. package/dist/src/components/resource/form/prepare.d.ts +54 -0
  53. package/dist/src/components/resource/form/server-errors.d.ts +14 -0
  54. package/dist/src/components/resource/history/ChangeHistory.d.ts +60 -0
  55. package/dist/src/components/resource/import/ResourceImport.d.ts +84 -0
  56. package/dist/src/components/resource/nouns.d.ts +12 -0
  57. package/dist/src/components/resource/query-state.d.ts +20 -0
  58. package/dist/src/components/resource/resource-names.d.ts +23 -0
  59. package/dist/src/components/resource/select/ResourceSelect.d.ts +67 -0
  60. package/dist/src/components/resource/select/select-states.d.ts +68 -0
  61. package/dist/src/components/resource/select/use-debounced-value.d.ts +2 -0
  62. package/dist/src/components/resource/select/use-option-pages.d.ts +37 -0
  63. package/dist/src/components/resource/select/venue-backend.d.ts +144 -0
  64. package/dist/src/components/resource/table/BulkActionsBar.d.ts +77 -0
  65. package/dist/src/components/resource/table/CardList.d.ts +31 -0
  66. package/dist/src/components/resource/table/ConfirmDialog.d.ts +28 -0
  67. package/dist/src/components/resource/table/ExportButtons.d.ts +17 -0
  68. package/dist/src/components/resource/table/FilterBar.d.ts +29 -0
  69. package/dist/src/components/resource/table/PaginationControls.d.ts +31 -0
  70. package/dist/src/components/resource/table/ResourceTable.d.ts +137 -0
  71. package/dist/src/components/resource/table/RowCard.d.ts +31 -0
  72. package/dist/src/components/resource/table/TableView.d.ts +29 -0
  73. package/dist/src/components/resource/table/ViewOptions.d.ts +19 -0
  74. package/dist/src/components/resource/table/access.d.ts +12 -0
  75. package/dist/src/components/resource/table/demo-fixtures.d.ts +25 -0
  76. package/dist/src/components/resource/table/derive-columns.d.ts +33 -0
  77. package/dist/src/components/resource/table/grid-navigation.d.ts +23 -0
  78. package/dist/src/components/resource/table/layout.d.ts +37 -0
  79. package/dist/src/components/resource/table/preferences.d.ts +12 -0
  80. package/dist/src/components/resource/table/slots.d.ts +41 -0
  81. package/dist/src/components/resource/table/states.d.ts +91 -0
  82. package/dist/src/components/resource/table/story-fixtures.d.ts +25 -0
  83. package/dist/src/components/resource/table/structural-columns.d.ts +25 -0
  84. package/dist/src/components/resource/table/table-icons.d.ts +16 -0
  85. package/dist/src/components/resource/table/table-utils.d.ts +48 -0
  86. package/dist/src/components/resource/table/url-state.d.ts +67 -0
  87. package/dist/src/components/resource/table/use-container-width.d.ts +10 -0
  88. package/dist/src/components/resource/table/use-debounced-value.d.ts +1 -0
  89. package/dist/src/components/resource/testapp-fixtures.d.ts +78 -0
  90. package/dist/src/components/stat/stat.d.ts +54 -0
  91. package/dist/src/components/toast/toast-store.d.ts +36 -0
  92. package/dist/src/components/toast/toaster.d.ts +66 -0
  93. package/dist/src/components/toast/use-toast.d.ts +24 -0
  94. package/dist/src/hooks/keys.d.ts +24 -0
  95. package/dist/src/hooks/multipart.d.ts +44 -0
  96. package/dist/src/hooks/params.d.ts +25 -0
  97. package/dist/src/hooks/types.d.ts +41 -0
  98. package/dist/src/hooks/useChangeHistory.d.ts +30 -0
  99. package/dist/src/hooks/useResourceImport.d.ts +107 -0
  100. package/dist/src/hooks/useResourceItem.d.ts +4 -0
  101. package/dist/src/hooks/useResourceList.d.ts +4 -0
  102. package/dist/src/hooks/useResourceMutations.d.ts +13 -0
  103. package/dist/src/hooks/useUnsavedChangesGuard.d.ts +31 -0
  104. package/dist/src/index.d.ts +113 -0
  105. package/dist/src/lib/cn.d.ts +8 -0
  106. package/dist/src/lib/roles.d.ts +45 -0
  107. package/dist/src/lib/variants.d.ts +33 -0
  108. package/dist/src/primitives/registry.d.ts +81 -0
  109. package/dist/src/schema/client.d.ts +90 -0
  110. package/dist/src/schema/parse.d.ts +101 -0
  111. package/dist/src/schema/provider.d.ts +20 -0
  112. package/dist/src/schema/types.d.ts +93 -0
  113. package/dist/src/schema/useSchema.d.ts +21 -0
  114. package/dist/src/schema/zod.d.ts +4 -0
  115. package/dist/src/states/ErrorState.d.ts +43 -0
  116. package/dist/src/states/PendingButton.d.ts +16 -0
  117. package/dist/src/states/describe-error.d.ts +25 -0
  118. package/dist/src/states/hooks.d.ts +10 -0
  119. package/dist/src/theme/script.d.ts +12 -0
  120. package/dist/src/theme/theme.d.ts +45 -0
  121. package/dist/styles.css +248 -0
  122. package/dist/tailwind-preset.cjs +2 -0
  123. package/dist/tailwind-preset.cjs.map +1 -0
  124. package/dist/tailwind-preset.d.ts +140 -0
  125. package/dist/tailwind-preset.js +183 -0
  126. package/dist/tailwind-preset.js.map +1 -0
  127. package/dist/tailwind-v4.css +31 -0
  128. package/dist/vite-plugin.cjs +2 -0
  129. package/dist/vite-plugin.cjs.map +1 -0
  130. package/dist/vite-plugin.d.ts +19 -0
  131. package/dist/vite-plugin.js +16 -0
  132. package/dist/vite-plugin.js.map +1 -0
  133. package/eslint-plugin/index.js +76 -0
  134. package/eslint-plugin/lib/docs.js +11 -0
  135. package/eslint-plugin/lib/glob.js +51 -0
  136. package/eslint-plugin/rules/max-page-lines.js +65 -0
  137. package/eslint-plugin/rules/no-deep-imports.js +61 -0
  138. package/eslint-plugin/rules/no-direct-http.js +128 -0
  139. package/eslint-plugin/rules/no-raw-elements.js +65 -0
  140. package/eslint-plugin/rules/no-style-literals.js +222 -0
  141. package/eslint-plugin/rules.json +32 -0
  142. package/package.json +156 -4
@@ -0,0 +1,31 @@
1
+ /** What the leave warning says. Browsers show their own text for reloads and closed tabs. */
2
+ export declare const UNSAVED_CHANGES_MESSAGE = "You have unsaved changes. Leave without saving them?";
3
+ export interface UseUnsavedChangesGuardOptions {
4
+ /** Controlled mode: whether something is unsaved. Omit it and call `setDirty` instead. */
5
+ dirty?: boolean;
6
+ /** Turns the guard off without unmounting it (an opt-out). Default true. */
7
+ enabled?: boolean;
8
+ /** Warn on reload, tab close and links out of the app (`beforeunload`). Default true. */
9
+ beforeUnload?: boolean;
10
+ /** The question `shouldBlock` asks. Default UNSAVED_CHANGES_MESSAGE. */
11
+ message?: string;
12
+ /** Asks the user whether to leave and returns true to leave. Default `window.confirm`. */
13
+ confirm?: (message: string) => boolean;
14
+ }
15
+ export interface UnsavedChangesGuard {
16
+ /** Whether something is unsaved (re-renders when it changes). */
17
+ dirty: boolean;
18
+ /** Reports the form's state. Pass it as ResourceForm's `onDirtyChange`. */
19
+ setDirty: (dirty: boolean) => void;
20
+ /** The latest state, read synchronously (for a router blocker's callback). */
21
+ isDirty: () => boolean;
22
+ /**
23
+ * For a router's blocker: true when there are unsaved changes and the user
24
+ * chose to stay, false (let the navigation happen) otherwise.
25
+ */
26
+ shouldBlock: () => boolean;
27
+ /** The question asked before leaving. */
28
+ message: string;
29
+ }
30
+ /** Tracks unsaved changes, warns on reload or close, and gives a router blocker what it needs. */
31
+ export declare function useUnsavedChangesGuard(options?: UseUnsavedChangesGuardOptions): UnsavedChangesGuard;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @karni/ui public barrel.
3
+ *
4
+ * Every public name of the package is re-exported here, explicitly, so that
5
+ * scripts/generate-manifest.mjs can parse this file and emit dist/manifest.json
6
+ * (contract D7). Keep exports in the explicit `export { ... } from` /
7
+ * `export type { ... } from` form, never `export *`.
8
+ */
9
+ export { cn } from './lib/cn';
10
+ export { registerComponentRole, getRoleRegistry } from './lib/roles';
11
+ export type { RegisterComponentRoleOptions } from './lib/roles';
12
+ export { variants } from './lib/variants';
13
+ export type { VariantShape, VariantSelection, VariantsConfig, VariantFn, VariantProps, } from './lib/variants';
14
+ export { describeError, errorSummary } from './states/describe-error';
15
+ export type { KarniErrorContext, KarniErrorDescription, KarniErrorKind, } from './states/describe-error';
16
+ export { ErrorState, PermissionDenied } from './states/ErrorState';
17
+ export type { ErrorSlotProps, ErrorStateProps, PermissionDeniedProps } from './states/ErrorState';
18
+ export { PendingButton } from './states/PendingButton';
19
+ export type { PendingButtonProps } from './states/PendingButton';
20
+ export { SLOW_AFTER_MS, useDelayedFlag, useOnlineStatus } from './states/hooks';
21
+ export { KARNI_THEME_SCRIPT, THEME_STORAGE_KEY, ThemeProvider, ThemeToggle, useTheme, } from './theme/theme';
22
+ export type { ResolvedTheme, ThemePreference, ThemeProviderProps, ThemeToggleProps, } from './theme/theme';
23
+ export { KarniPrimitivesProvider, useKarniPrimitives } from './primitives/registry';
24
+ export type { KarniPrimitiveOverrides, KarniPrimitiveRole, KarniPrimitives, KarniPrimitivesProviderProps, KarniSelectParts, } from './primitives/registry';
25
+ export { Button, buttonVariants } from './components/primitives/button';
26
+ export type { ButtonProps, ButtonVariantProps } from './components/primitives/button';
27
+ export { Input } from './components/primitives/input';
28
+ export type { InputProps } from './components/primitives/input';
29
+ export { Textarea } from './components/primitives/textarea';
30
+ export type { TextareaProps } from './components/primitives/textarea';
31
+ export { Select, SelectRoot, SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator, KARNI_SELECT_EMPTY, } from './components/primitives/select';
32
+ export type { SelectOption, SelectProps } from './components/primitives/select';
33
+ export { Checkbox } from './components/primitives/checkbox';
34
+ export type { CheckboxProps } from './components/primitives/checkbox';
35
+ export { Switch } from './components/primitives/switch';
36
+ export type { SwitchProps } from './components/primitives/switch';
37
+ export { Label } from './components/primitives/label';
38
+ export type { LabelProps } from './components/primitives/label';
39
+ export { Tabs, TabsList, TabsTrigger, TabsContent } from './components/primitives/tabs';
40
+ export { DropdownMenu, DropdownMenuTrigger, DropdownMenuGroup, DropdownMenuPortal, DropdownMenuContent, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuLabel, DropdownMenuSeparator, } from './components/primitives/dropdown-menu';
41
+ export { Skeleton } from './components/primitives/skeleton';
42
+ export type { SkeletonProps } from './components/primitives/skeleton';
43
+ export { ResourceTable } from './components/resource/ResourceTable';
44
+ export type { ResourceTableProps, ResourceColumn, BulkAction, } from './components/resource/ResourceTable';
45
+ export { createHistoryStateStore, defaultResourceTableSlots, } from './components/resource/ResourceTable';
46
+ export type { BulkActionReturn, BulkOutcome, BulkResult, ResourceTableActiveFilter, ResourceTableBulkActionsProps, ResourceTableCardField, ResourceTableDensity, ResourceTableForbiddenProps, ResourceTableKeyboardNavigation, ResourceTableLoadingProps, ResourceTableNoRecordsProps, ResourceTableNoResultsProps, ResourceTableOfflineProps, ResourceTablePaginationProps, ResourceTableRowCardProps, ResourceTableSlots, ResourceTableStateStore, } from './components/resource/ResourceTable';
47
+ export type { KarniAccessRule } from './schema/types';
48
+ export { ResourceForm, defaultResourceFormSlots } from './components/resource/ResourceForm';
49
+ export type { ResourceFormProps, ResourceFormSlots, ResourceFormErrorSummaryProps, ResourceFormFieldError, ResourceFormForbiddenProps, ResourceFormLoadingProps, ResourceFormSubmitErrorProps, FieldOverride, KarniFieldProps, } from './components/resource/ResourceForm';
50
+ export { UNSAVED_CHANGES_MESSAGE, useUnsavedChangesGuard } from './hooks/useUnsavedChangesGuard';
51
+ export type { UnsavedChangesGuard, UseUnsavedChangesGuardOptions, } from './hooks/useUnsavedChangesGuard';
52
+ export { ResourceDetail, defaultResourceDetailSlots } from './components/resource/ResourceDetail';
53
+ export type { ResourceDetailProps, ResourceDetailFieldOverride, ResourceDetailSlots, ResourceDetailLoadingProps, ResourceDetailErrorProps, ResourceDetailNotFoundProps, ResourceDetailDeletedProps, ResourceDetailEmptyValueProps, ResourceDetailDeleteDialogProps, } from './components/resource/ResourceDetail';
54
+ export { ResourceSelect, defaultResourceSelectSlots } from './components/resource/ResourceSelect';
55
+ export type { ResourceSelectProps, ResourceSelectSlots, ResourceSelectChipProps, ResourceSelectEmptyProps, ResourceSelectLoadingProps, ResourceSelectOptionProps, } from './components/resource/ResourceSelect';
56
+ export { ChangeHistory, defaultChangeHistorySlots, } from './components/resource/history/ChangeHistory';
57
+ export type { ChangeHistoryProps, ChangeHistorySlots, ChangeHistoryLoadingProps, ChangeHistoryEmptyProps, ChangeHistoryEntryProps, } from './components/resource/history/ChangeHistory';
58
+ export { useChangeHistory, changeHistoryKey } from './hooks/useChangeHistory';
59
+ export type { ChangeAction, ChangeLogEntry, ChangeHistoryPage, ChangeHistoryParams, } from './hooks/useChangeHistory';
60
+ export { ResourceImport, defaultResourceImportSlots, } from './components/resource/import/ResourceImport';
61
+ export type { ResourceImportProps, ResourceImportSlots, ResourceImportLoadingProps, ImportProgressProps, ImportSummaryProps, ImportProblemsProps, ImportConfirmProps, } from './components/resource/import/ResourceImport';
62
+ export { useImportDescribe, useImportJob, useImportActions, downloadResourceExport, downloadImportTemplate, importDescribeKey, importJobKey, isImportInFlight, } from './hooks/useResourceImport';
63
+ export type { ExportFormat, ImportActions, ImportColumn, ImportColumnKind, ImportDescription, ImportJob, ImportProblem, ImportResult, ImportStatus, PreviewImportInput, UploadImportInput, UseImportJobOptions, } from './hooks/useResourceImport';
64
+ export { displayLabel } from './components/resource/displayLabel';
65
+ export { EmptyValue, EMPTY_VALUE_LABEL } from './components/resource/empty-value';
66
+ export type { EmptyValueProps } from './components/resource/empty-value';
67
+ export { AUDIT_FIELDS } from './components/resource/audit-fields';
68
+ export { karniKeys } from './hooks/keys';
69
+ export { useResourceList } from './hooks/useResourceList';
70
+ export { useResourceItem } from './hooks/useResourceItem';
71
+ export { useResourceMutations } from './hooks/useResourceMutations';
72
+ export type { ResourceMutations } from './hooks/useResourceMutations';
73
+ export type { Paginated, FilterValue, ResourceListParams, ResourceItemParams, ResourceMutationsOptions, } from './hooks/types';
74
+ export { createKarniClient, KarniApiError } from './schema/client';
75
+ export type { KarniClient, KarniClientOptions, KarniQueryValue, KarniRequestOptions, } from './schema/client';
76
+ export { KarniProvider, useKarniClient } from './schema/provider';
77
+ export type { KarniProviderProps } from './schema/provider';
78
+ export { useSchema } from './schema/useSchema';
79
+ export type { UseSchemaResult } from './schema/useSchema';
80
+ export { zodFor } from './schema/zod';
81
+ export type { FieldKind, RelationRef, FieldDef, OperationDef, ResourceSchema, } from './schema/types';
82
+ export { AuthProvider, useAuth } from './auth/provider';
83
+ export type { AuthProviderProps, AuthContextValue } from './auth/provider';
84
+ export { AuthGuard, defaultAuthGuardSlots } from './auth/AuthGuard';
85
+ export type { AuthGuardProps, AuthGuardSlots, AuthGuardAnonymousProps, AuthGuardDeniedProps, } from './auth/AuthGuard';
86
+ export { LoginForm, defaultLoginFormSlots } from './auth/LoginForm';
87
+ export type { LoginFormProps, LoginFormSlots, LoginFormErrorProps } from './auth/LoginForm';
88
+ export { usePermission } from './auth/usePermission';
89
+ export type { PermissionHelpers } from './auth/usePermission';
90
+ export { createLocalStorageTokenStorage, createMemoryTokenStorage } from './auth/storage';
91
+ export type { TokenStorage } from './auth/storage';
92
+ export type { KarniUser, AuthStatus, LoginResult } from './auth/types';
93
+ export { Page, defaultPageSlots } from './components/page/page';
94
+ export type { PageProps, PageSlots, PageHeaderProps, PageSlotContentProps, } from './components/page/page';
95
+ export { Layout, defaultLayoutSlots } from './components/layout/layout';
96
+ export type { LayoutProps, LayoutNavItem, LayoutSlots, LayoutHeaderProps, LayoutSidebarProps, LayoutNavLinkProps, LayoutMobileDrawerProps, LayoutSkipLinkProps, LayoutRouteFocusOptions, } from './components/layout/layout';
97
+ export { KarniMark } from './components/brand/karni-mark';
98
+ export type { KarniMarkProps } from './components/brand/karni-mark';
99
+ export { Modal, ModalClose, ModalTitle, ModalDescription, defaultModalSlots, } from './components/modal/modal';
100
+ export type { ModalProps, ModalSlots, ModalHeaderProps, ModalFooterProps, ModalCloseButtonProps, } from './components/modal/modal';
101
+ export { Toaster, toastVariants, defaultToasterSlots } from './components/toast/toaster';
102
+ export type { ToasterProps, ToastVariantProps, ToasterSlots, ToasterSlotProps, ToasterCloseButtonProps, } from './components/toast/toaster';
103
+ export { useToast } from './components/toast/use-toast';
104
+ export type { UseToastResult } from './components/toast/use-toast';
105
+ export type { ToastHandle, ToastInstance, ToastOptions, ToastVariant, } from './components/toast/toast-store';
106
+ export { EmptyState, defaultEmptyStateSlots } from './components/empty-state/empty-state';
107
+ export type { EmptyStateProps, EmptyStateSlots, EmptyStateSlotProps, } from './components/empty-state/empty-state';
108
+ export { FileUpload, defaultFileUploadSlots } from './components/file-upload/FileUpload';
109
+ export type { FileUploadProps, FileUploadRejectReason, FileUploadSlots, FileUploadDropzoneProps, FileUploadFileRowProps, } from './components/file-upload/FileUpload';
110
+ export { Stat, defaultStatSlots } from './components/stat/stat';
111
+ export type { StatProps, StatSlots, StatSlotProps, StatDeltaProps } from './components/stat/stat';
112
+ export { DataChart, defaultDataChartSlots } from './components/chart/data-chart';
113
+ export type { DataChartProps, DataChartKind, DataChartPoint, DataChartSeries, DataChartTooltipContext, DataChartSlots, DataChartTooltipProps, DataChartLegendProps, DataChartEmptyProps, DataChartLoadingProps, } from './components/chart/data-chart';
@@ -0,0 +1,8 @@
1
+ import { ClassValue } from 'clsx';
2
+ /**
3
+ * Merges class names: clsx semantics for conditionals plus tailwind-merge
4
+ * conflict resolution, so consumer-supplied `className` always wins over a
5
+ * component's own Tailwind classes. Every @karni/ui component funnels its
6
+ * `className` prop through this.
7
+ */
8
+ export declare function cn(...inputs: ClassValue[]): string;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Component role registry (enforcement contract §4 + F11).
3
+ *
4
+ * Every top-level component claims a semantic role ("data-table",
5
+ * "resource-form", …) at module scope. Two components claiming the same role
6
+ * is a conflict: it throws at import time (so vitest and the dev server both
7
+ * surface it) and `scripts/generate-manifest.mjs` fails the build on the same
8
+ * duplicate via a static scan of these call sites.
9
+ *
10
+ * Conventions:
11
+ * - The `role` argument MUST be a string literal. The build-time scan rejects
12
+ * any non-literal first argument.
13
+ * - Same role + same component name is idempotent (modules re-evaluate under
14
+ * HMR and across test files).
15
+ * - Replacing on purpose is explicit and must carry a reason:
16
+ * `{ replace: true, reason: "<why>" }`. An empty reason throws.
17
+ * - Under Vite HMR (`import.meta.hot`) an accidental conflict logs a
18
+ * console.error and replaces instead of throwing, so a rename mid-edit does
19
+ * not kill the dev server.
20
+ * - The registry reflects imported modules only (accepted v0.1 trade-off).
21
+ */
22
+ export interface RegisterComponentRoleOptions {
23
+ /** Replace an existing registration on purpose. Requires `reason`. */
24
+ replace?: boolean;
25
+ /** Why the replacement is intentional. Required with `replace: true`. */
26
+ reason?: string;
27
+ }
28
+ /**
29
+ * Test-only override for HMR detection. Pass `null` to restore the default.
30
+ * Not exported from the package barrel.
31
+ * @internal
32
+ */
33
+ export declare function __setHotDetectorForTests(detector: (() => boolean) | null): void;
34
+ /**
35
+ * Test-only registry reset. Not exported from the package barrel.
36
+ * @internal
37
+ */
38
+ export declare function __resetRoleRegistryForTests(): void;
39
+ /**
40
+ * 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
41
+ * (build-scan convention, F11).
42
+ */
43
+ export declare function registerComponentRole(role: string, component: string, options?: RegisterComponentRoleOptions): void;
44
+ /** Snapshot of the current registry ({ role: component }) for tooling. */
45
+ export declare function getRoleRegistry(): Readonly<Record<string, string>>;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Hand-rolled cva-style variant utility (no extra dependency).
3
+ *
4
+ * Every class string appears whole in source (contract D7): a variant map
5
+ * value is a complete Tailwind class list, selected (never concatenated)
6
+ * at call time and merged through cn().
7
+ */
8
+ /** A map of variant group name → allowed value → whole Tailwind class string. */
9
+ export type VariantShape = Record<string, Record<string, string>>;
10
+ /** The props accepted for a given variant shape (each group optional). */
11
+ export type VariantSelection<V extends VariantShape> = {
12
+ [K in keyof V]?: Extract<keyof V[K], string> | null;
13
+ };
14
+ export interface VariantsConfig<V extends VariantShape> {
15
+ /** Classes always applied, before any variant classes. */
16
+ base?: string;
17
+ variants: V;
18
+ defaultVariants?: VariantSelection<V>;
19
+ /** Extra classes applied when every listed variant value is selected. */
20
+ compoundVariants?: ReadonlyArray<VariantSelection<V> & {
21
+ className: string;
22
+ }>;
23
+ }
24
+ export type VariantFn<V extends VariantShape> = (props?: VariantSelection<V> & {
25
+ className?: string;
26
+ }) => string;
27
+ /**
28
+ * Extracts the variant props of a variant function, for typing component
29
+ * props: `type ButtonVariantProps = VariantProps<typeof buttonVariants>`.
30
+ */
31
+ export type VariantProps<F> = F extends VariantFn<infer V> ? VariantSelection<V> : never;
32
+ /** Builds a typed class-name function from variant definitions, the way every themed component declares its looks. */
33
+ export declare function variants<V extends VariantShape>(config: VariantsConfig<V>): VariantFn<V>;
@@ -0,0 +1,81 @@
1
+ import { ButtonProps } from '../components/primitives/button';
2
+ import { CheckboxProps } from '../components/primitives/checkbox';
3
+ import { InputProps } from '../components/primitives/input';
4
+ import { LabelProps } from '../components/primitives/label';
5
+ import { SkeletonProps } from '../components/primitives/skeleton';
6
+ import { SwitchProps } from '../components/primitives/switch';
7
+ import { TextareaProps } from '../components/primitives/textarea';
8
+ /**
9
+ * The primitive registry: a project renders Karni's components with its own
10
+ * design system's primitives.
11
+ *
12
+ * <KarniProvider client={client} primitives={{ button: Button, input: Input }}>
13
+ *
14
+ * Every Karni primitive (Button, Input, Select's parts, ...) looks itself up
15
+ * here before rendering, so ResourceTable, ResourceForm and the rest render
16
+ * the project's button and inputs while keeping their schema-driven
17
+ * behaviour. A role that is not registered renders Karni's own.
18
+ *
19
+ * Contracts: a registered component receives exactly the props Karni's
20
+ * primitive takes (ButtonProps, InputProps, ...) and the ref. shadcn/ui's
21
+ * components match them as they are. Any other design system registers a
22
+ * small adapter. `select` is a family: Radix parts share a context, so its
23
+ * parts are replaced together or not at all.
24
+ *
25
+ * A registered component may wrap Karni's own (`(props) => <Button
26
+ * className="..." {...props} />`): inside it, that role resolves to Karni's
27
+ * primitive again, so the wrapper does not call itself.
28
+ */
29
+ import type * as SelectPrimitive from "@radix-ui/react-select";
30
+ import * as React from "react";
31
+ type WithRef<P, T> = React.ComponentType<P & React.RefAttributes<T>>;
32
+ /** The parts of a Radix-compatible select (what shadcn/ui's select.tsx exports). */
33
+ export interface KarniSelectParts {
34
+ Root: React.ComponentType<SelectPrimitive.SelectProps>;
35
+ Trigger: WithRef<SelectPrimitive.SelectTriggerProps, HTMLButtonElement>;
36
+ Value: WithRef<SelectPrimitive.SelectValueProps, HTMLSpanElement>;
37
+ Content: WithRef<SelectPrimitive.SelectContentProps, HTMLDivElement>;
38
+ Item: WithRef<SelectPrimitive.SelectItemProps, HTMLDivElement>;
39
+ Group: WithRef<SelectPrimitive.SelectGroupProps, HTMLDivElement>;
40
+ Label: WithRef<SelectPrimitive.SelectLabelProps, HTMLDivElement>;
41
+ Separator: WithRef<SelectPrimitive.SelectSeparatorProps, HTMLDivElement>;
42
+ }
43
+ /** Every role a project can fill with its own component. */
44
+ export interface KarniPrimitives {
45
+ button: WithRef<ButtonProps, HTMLButtonElement>;
46
+ input: WithRef<InputProps, HTMLInputElement>;
47
+ textarea: WithRef<TextareaProps, HTMLTextAreaElement>;
48
+ checkbox: WithRef<CheckboxProps, HTMLButtonElement>;
49
+ switch: WithRef<SwitchProps, HTMLButtonElement>;
50
+ label: WithRef<LabelProps, HTMLLabelElement>;
51
+ skeleton: WithRef<SkeletonProps, HTMLDivElement>;
52
+ select: KarniSelectParts;
53
+ }
54
+ /** A role that is one component (not a family of parts). */
55
+ export type KarniPrimitiveRole = Exclude<keyof KarniPrimitives, "select">;
56
+ /** The project's replacements: any subset of the roles. */
57
+ export type KarniPrimitiveOverrides = Partial<KarniPrimitives>;
58
+ export interface KarniPrimitivesProviderProps {
59
+ /** Role -> the project's component. Merged over any registry above it. */
60
+ value: KarniPrimitiveOverrides;
61
+ children?: React.ReactNode;
62
+ }
63
+ /**
64
+ * Registers the project's primitives for everything inside it. KarniProvider
65
+ * renders one from its `primitives` prop, and you can nest another to change
66
+ * a subtree.
67
+ */
68
+ export declare function KarniPrimitivesProvider({ value, children, }: KarniPrimitivesProviderProps): React.ReactElement;
69
+ /** The registered primitives in scope (the roles the project replaced). */
70
+ export declare function useKarniPrimitives(): KarniPrimitiveOverrides;
71
+ /**
72
+ * Makes a Karni primitive defer to the registry.
73
+ * @internal
74
+ */
75
+ export declare function overridable<P extends object, T>(role: KarniPrimitiveRole, Default: React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<T>>): React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<T>>;
76
+ /**
77
+ * Makes one part of Karni's select defer to a registered `select` family.
78
+ * @internal
79
+ */
80
+ export declare function overridableSelectPart<K extends keyof KarniSelectParts, C extends KarniSelectParts[K]>(part: K, Default: C): C;
81
+ export {};
@@ -0,0 +1,90 @@
1
+ /**
2
+ * createKarniClient: the typed fetch wrapper every @karni/ui layer sits on
3
+ * (contract "Schema client" + D6).
4
+ *
5
+ * Responsibilities:
6
+ * - URL joining + query-string serialization (arrays become repeated keys,
7
+ * null/undefined are dropped),
8
+ * - JSON request/response handling. A FormData body is passed through
9
+ * untouched with NO manual Content-Type (the D2 multipart rule),
10
+ * - DRF error passthrough: non-2xx responses throw KarniApiError carrying the
11
+ * parsed body (field errors / detail / non_field_errors) verbatim,
12
+ * - auth hook points per D6's client-owns-tokens design: the auth layer (not
13
+ * React) registers token injection, extra headers (session CSRF),
14
+ * credentials mode and a 401 handler via `setAuthHooks`. The client calls
15
+ * `onUnauthorized` at most ONCE per request and retries at most ONCE. A
16
+ * request that 401s again after a successful refresh is surfaced and never
17
+ * re-triggers refresh (the single-flight refresh promise itself lives in
18
+ * the auth layer behind this hook).
19
+ */
20
+ export interface KarniClientOptions {
21
+ /**
22
+ * Origin (plus optional path prefix) requests resolve against, e.g.
23
+ * "https://api.example.com" or "" for same-origin. Paths that already start
24
+ * with the prefix are not double-prefixed, so operation paths taken from
25
+ * the OpenAPI document ("/api/events/") work with any baseUrl.
26
+ */
27
+ baseUrl: string;
28
+ /** Path of the OpenAPI document. Default "/api/schema/". */
29
+ schemaUrl?: string;
30
+ /** Initial access-token getter. `setAuthHooks` can replace it later (D6). */
31
+ getAccessToken?: () => string | null;
32
+ /** Custom fetch implementation (tests, SSR). Resolved per request. */
33
+ fetch?: typeof globalThis.fetch;
34
+ }
35
+ export type KarniQueryValue = string | number | boolean | ReadonlyArray<string | number | boolean> | null | undefined;
36
+ export interface KarniRequestOptions {
37
+ method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
38
+ query?: Record<string, KarniQueryValue>;
39
+ /** JSON-serialized unless it is FormData (multipart rule D2). */
40
+ body?: unknown;
41
+ headers?: Record<string, string>;
42
+ signal?: AbortSignal;
43
+ /**
44
+ * Skip the 401 → onUnauthorized → retry cycle for this request. The auth
45
+ * layer sets it on its own login/refresh/logout calls so a failing refresh
46
+ * can never recurse into another refresh (D6).
47
+ */
48
+ skipAuthRefresh?: boolean;
49
+ }
50
+ /**
51
+ * Hook points the auth layer registers on the client (D6). Keys present in
52
+ * the object passed to `setAuthHooks` override the current value (an explicit
53
+ * `undefined` clears one). Absent keys are kept.
54
+ */
55
+ export interface KarniAuthHooks {
56
+ /** Called before every request. A non-null return is sent as Bearer. */
57
+ getAccessToken?: () => string | null;
58
+ /**
59
+ * Called once when a request gets a 401 (unless `skipAuthRefresh`). Return
60
+ * true to retry the request once with freshly-injected credentials, false
61
+ * to surface the error. Single-flight refresh lives behind this hook.
62
+ */
63
+ onUnauthorized?: (error: KarniApiError) => Promise<boolean>;
64
+ /** Extra headers merged into every request (session-mode X-CSRFToken). */
65
+ getHeaders?: () => Record<string, string>;
66
+ /** fetch credentials mode. Session mode sets "include". */
67
+ credentials?: RequestCredentials;
68
+ }
69
+ /** Thrown for non-2xx responses, with the parsed DRF error body in `data`. */
70
+ export declare class KarniApiError extends Error {
71
+ readonly status: number;
72
+ /** Parsed body when JSON (field errors, detail, non_field_errors), else text. */
73
+ readonly data: unknown;
74
+ constructor(status: number, data: unknown, message?: string);
75
+ }
76
+ export interface KarniClient {
77
+ readonly baseUrl: string;
78
+ readonly schemaUrl: string;
79
+ request<T>(path: string, options?: KarniRequestOptions): Promise<T>;
80
+ /**
81
+ * The same request (auth, query, 401 retry) returning the raw `Response`
82
+ * instead of a parsed body, for file downloads (`GET /<resource>/export/`).
83
+ * Non-2xx responses still throw `KarniApiError` with the parsed error body.
84
+ */
85
+ requestRaw(path: string, options?: KarniRequestOptions): Promise<Response>;
86
+ /** D6 hook point: the auth layer wires tokens/CSRF/401 handling here. */
87
+ setAuthHooks(hooks: KarniAuthHooks): void;
88
+ }
89
+ /** Creates the fetch client every hook in this package uses: base URL, JSON and multipart bodies, DRF errors as `KarniApiError`, and auth hooks. */
90
+ export declare function createKarniClient(options: KarniClientOptions): KarniClient;
@@ -0,0 +1,101 @@
1
+ import { ParsedSchema } from './types';
2
+ export interface KarniRelationExtension {
3
+ resource?: string;
4
+ many?: boolean;
5
+ }
6
+ export interface SchemaObject {
7
+ default?: unknown;
8
+ $ref?: string;
9
+ type?: string | readonly string[];
10
+ format?: string;
11
+ title?: string;
12
+ description?: string;
13
+ enum?: ReadonlyArray<string | number | null>;
14
+ nullable?: boolean;
15
+ readOnly?: boolean;
16
+ writeOnly?: boolean;
17
+ required?: readonly string[];
18
+ properties?: Record<string, SchemaObject>;
19
+ items?: SchemaObject;
20
+ allOf?: readonly SchemaObject[];
21
+ oneOf?: readonly SchemaObject[];
22
+ anyOf?: readonly SchemaObject[];
23
+ maxLength?: number;
24
+ minLength?: number;
25
+ minimum?: number;
26
+ maximum?: number;
27
+ "x-karni-relation"?: KarniRelationExtension;
28
+ [extension: string]: unknown;
29
+ }
30
+ export interface ParameterObject {
31
+ name?: string;
32
+ in?: string;
33
+ required?: boolean;
34
+ schema?: SchemaObject;
35
+ [extension: string]: unknown;
36
+ }
37
+ export interface MediaTypeObject {
38
+ schema?: SchemaObject;
39
+ [extension: string]: unknown;
40
+ }
41
+ export interface RequestBodyObject {
42
+ content?: Record<string, MediaTypeObject>;
43
+ required?: boolean;
44
+ [extension: string]: unknown;
45
+ }
46
+ export interface ResponseObject {
47
+ description?: string;
48
+ content?: Record<string, MediaTypeObject>;
49
+ [extension: string]: unknown;
50
+ }
51
+ export interface OperationObject {
52
+ operationId?: string;
53
+ parameters?: readonly ParameterObject[];
54
+ requestBody?: RequestBodyObject;
55
+ responses?: Record<string, ResponseObject>;
56
+ "x-karni-resource"?: string;
57
+ [extension: string]: unknown;
58
+ }
59
+ export interface PathItemObject {
60
+ get?: OperationObject;
61
+ post?: OperationObject;
62
+ put?: OperationObject;
63
+ patch?: OperationObject;
64
+ delete?: OperationObject;
65
+ [extension: string]: unknown;
66
+ }
67
+ export interface OpenApiDocument {
68
+ openapi?: string;
69
+ paths?: Record<string, PathItemObject>;
70
+ components?: {
71
+ schemas?: Record<string, SchemaObject>;
72
+ [extension: string]: unknown;
73
+ };
74
+ "x-karni-auth-mode"?: string;
75
+ [extension: string]: unknown;
76
+ }
77
+ /** "starts_at" → "Starts at", "is_public" → "Is public". */
78
+ export declare function humanize(name: string): string;
79
+ /**
80
+ * Resolves $ref chains and unwraps single-member allOf, merging siblings over
81
+ * the resolved target (so `{allOf: [$ref StatusEnum], readOnly: true}` yields
82
+ * the enum schema plus readOnly). Cycle-guarded: a cycle resolves to {}.
83
+ */
84
+ export declare function resolveSchema(doc: OpenApiDocument, schema: SchemaObject | undefined, seen?: readonly string[]): SchemaObject | undefined;
85
+ /**
86
+ * Splits drf-spectacular's generated choice list ("* `draft` - Draft" per
87
+ * line, appended to a ChoiceField's description) into labels by value and
88
+ * the human help text that remains (undefined when nothing remains). The
89
+ * raw list is markdown a form would otherwise show verbatim as help text.
90
+ */
91
+ export declare function choiceLabels(description: string | undefined): {
92
+ labels?: Record<string, string>;
93
+ rest?: string;
94
+ };
95
+ /**
96
+ * Parses an OpenAPI document (fetched from the backend's schemaUrl) into the
97
+ * normalized registry. Tolerates anything it does not understand: unknown
98
+ * constructs become kind "unknown" fields, paths without x-karni-resource are
99
+ * ignored, and a malformed document yields an empty registry.
100
+ */
101
+ export declare function parseOpenApi(input: unknown): ParsedSchema;
@@ -0,0 +1,20 @@
1
+ import { QueryClient } from '@tanstack/react-query';
2
+ import { ReactElement, ReactNode } from 'react';
3
+ import { KarniPrimitiveOverrides } from '../primitives/registry';
4
+ import { KarniClient } from './client';
5
+ export interface KarniProviderProps {
6
+ client: KarniClient;
7
+ /** Bring your own QueryClient. One is created (once) when omitted. */
8
+ queryClient?: QueryClient;
9
+ /**
10
+ * The project's own primitives, by role: `{ button: Button, input: Input }`.
11
+ * Every Karni component then renders them in place of Karni's (see
12
+ * KarniPrimitivesProvider for the contract).
13
+ */
14
+ primitives?: KarniPrimitiveOverrides;
15
+ children?: ReactNode;
16
+ }
17
+ /** Rendered once at the app root, it provides the Karni client and a TanStack QueryClient to everything inside it. */
18
+ export declare function KarniProvider(props: KarniProviderProps): ReactElement;
19
+ /** Returns the Karni client from `KarniProvider` and throws a descriptive error outside one. */
20
+ export declare function useKarniClient(): KarniClient;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Normalized schema registry types (karni-ui-contract.md "Schema client" + D1).
3
+ *
4
+ * The OpenAPI document served by the karni backend (drf-spectacular, OAS 3.0.3,
5
+ * COMPONENT_SPLIT_REQUEST=True per api contract B14) is parsed ONCE into these
6
+ * shapes. Every generic component consumes FieldDef/ResourceSchema, never raw
7
+ * OpenAPI.
8
+ */
9
+ export type FieldKind = "string" | "text" | "number" | "integer" | "boolean" | "date" | "datetime" | "enum" | "relation" | "file" | "json" | "array" | "unknown";
10
+ /** Derived from the x-karni-relation vendor extension (api contract B13). */
11
+ export interface RelationRef {
12
+ resource: string;
13
+ many: boolean;
14
+ }
15
+ export interface FieldDef {
16
+ name: string;
17
+ /** Humanized from the property name (or the schema `title` when present). */
18
+ label: string;
19
+ kind: FieldKind;
20
+ /** From the CREATE request body's required array only (D1). */
21
+ required: boolean;
22
+ /** Flagged readOnly OR present only in the response component (D1). */
23
+ readOnly: boolean;
24
+ /** Flagged writeOnly OR present only in the request component (D1). */
25
+ writeOnly: boolean;
26
+ nullable: boolean;
27
+ /** Enum members. BlankEnum's "" and NullEnum's null are never members (D1/D3). */
28
+ enumValues?: ReadonlyArray<string | number>;
29
+ /** Choice labels by value, from drf-spectacular's "* `value` - Label" description lines. */
30
+ enumLabels?: Readonly<Record<string, string>>;
31
+ /** The schema's `default` (a model default): forms start from it on create. */
32
+ default?: unknown;
33
+ maxLength?: number;
34
+ min?: number;
35
+ max?: number;
36
+ format?: string;
37
+ /** Schema `description`, surfaced as field help text. */
38
+ description?: string;
39
+ /** Present only when x-karni-relation was emitted (degrades gracefully). */
40
+ relation?: RelationRef;
41
+ /**
42
+ * Underlying pk value type of a relation field, derived from the property's
43
+ * own emitted type/format, never assumed (D3). Drives zodFor's relation
44
+ * value schema (uuid string vs integer).
45
+ */
46
+ relationValueType?: "uuid" | "integer" | "string";
47
+ /** Declaration order in the schema (response props first, request-only appended). */
48
+ order: number;
49
+ }
50
+ /**
51
+ * An operation's `x-karni-access` rule as the backend publishes it: the access
52
+ * predicate governing the operation, e.g. `{"role": ["staff"]}`,
53
+ * `{"owned": "organizer"}`, `{"any": [...]}`. A display hint only: the server
54
+ * enforces it.
55
+ */
56
+ export type KarniAccessRule = Readonly<Record<string, unknown>>;
57
+ export interface OperationDef {
58
+ path: string;
59
+ method: "get" | "post" | "put" | "patch" | "delete";
60
+ operationId?: string;
61
+ /** Declared query parameter names. The filter bar derives from these (D5). */
62
+ queryParams: readonly string[];
63
+ /** Allowed expand keys when the expand param declares an enum (D5). */
64
+ expandEnum?: readonly string[];
65
+ /** True when the operation declares a `search` query parameter (api B14). */
66
+ hasSearch?: boolean;
67
+ /** The operation's `x-karni-access` rule, when the backend published one. */
68
+ access?: KarniAccessRule;
69
+ }
70
+ export interface ResourceSchema {
71
+ /** Router prefix, e.g. "events" (from x-karni-resource). */
72
+ resource: string;
73
+ operations: {
74
+ list?: OperationDef;
75
+ detail?: OperationDef;
76
+ create?: OperationDef;
77
+ update?: OperationDef;
78
+ remove?: OperationDef;
79
+ /** `GET /<resource>/export/`: the list as a CSV/XLSX file (karni.transfer, P6). */
80
+ export?: OperationDef;
81
+ /** `POST /<resource>/import/`: the import flow (upload, preview, commit). */
82
+ import?: OperationDef;
83
+ };
84
+ /** Ordered by declaration. Unknown constructs land as kind "unknown". */
85
+ fields: readonly FieldDef[];
86
+ }
87
+ /** The whole parsed registry, produced once per schema fetch by parseOpenApi. */
88
+ export interface ParsedSchema {
89
+ /** Keyed by router prefix (x-karni-resource). */
90
+ resources: Record<string, ResourceSchema>;
91
+ /** From the schema root's x-karni-auth-mode (api B14). Undefined when absent. */
92
+ authMode?: "jwt" | "session";
93
+ }
@@ -0,0 +1,21 @@
1
+ import { UseQueryResult } from '@tanstack/react-query';
2
+ import { ParsedSchema, ResourceSchema } from './types';
3
+ /** D4-pinned query key for the parsed schema document. */
4
+ export declare const SCHEMA_QUERY_KEY: readonly ["karni", "$schema"];
5
+ /**
6
+ * The whole parsed registry (resources + root x-karni-auth-mode). Internal to
7
+ * the package: the auth layer reads `data.authMode` from here. Apps use
8
+ * useSchema(resource).
9
+ */
10
+ export declare function useParsedSchema(): UseQueryResult<ParsedSchema>;
11
+ export interface UseSchemaResult {
12
+ data: ResourceSchema | undefined;
13
+ isLoading: boolean;
14
+ error: unknown;
15
+ /** Fetches the schema document again: what a "Try again" after a failed load calls. */
16
+ refetch?: () => void;
17
+ /** True while the schema document is being fetched (the first load or a retry). */
18
+ isFetching?: boolean;
19
+ }
20
+ /** Returns one resource's parsed schema (fields, types, relations, operations) from the backend's OpenAPI document, fetched once per app. */
21
+ export declare function useSchema(resource: string): UseSchemaResult;