@modern-admin/react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/dist/action-guard.d.ts +13 -0
  2. package/dist/action-guard.d.ts.map +1 -0
  3. package/dist/action-guard.js +15 -0
  4. package/dist/action-guard.js.map +1 -0
  5. package/dist/action-menu.d.ts +17 -0
  6. package/dist/action-menu.d.ts.map +1 -0
  7. package/dist/action-menu.jsx +80 -0
  8. package/dist/action-menu.jsx.map +1 -0
  9. package/dist/admin-app.d.ts +23 -0
  10. package/dist/admin-app.d.ts.map +1 -0
  11. package/dist/admin-app.jsx +407 -0
  12. package/dist/admin-app.jsx.map +1 -0
  13. package/dist/admin-router.d.ts +29 -0
  14. package/dist/admin-router.d.ts.map +1 -0
  15. package/dist/admin-router.jsx +215 -0
  16. package/dist/admin-router.jsx.map +1 -0
  17. package/dist/breadcrumbs.d.ts +17 -0
  18. package/dist/breadcrumbs.d.ts.map +1 -0
  19. package/dist/breadcrumbs.jsx +40 -0
  20. package/dist/breadcrumbs.jsx.map +1 -0
  21. package/dist/client.d.ts +526 -0
  22. package/dist/client.d.ts.map +1 -0
  23. package/dist/client.js +582 -0
  24. package/dist/client.js.map +1 -0
  25. package/dist/component-loader.d.ts +10 -0
  26. package/dist/component-loader.d.ts.map +1 -0
  27. package/dist/component-loader.js +23 -0
  28. package/dist/component-loader.js.map +1 -0
  29. package/dist/components/ai-assistant-widget.d.ts +3 -0
  30. package/dist/components/ai-assistant-widget.d.ts.map +1 -0
  31. package/dist/components/ai-assistant-widget.jsx +390 -0
  32. package/dist/components/ai-assistant-widget.jsx.map +1 -0
  33. package/dist/components/ai-fill-dialog.d.ts +9 -0
  34. package/dist/components/ai-fill-dialog.d.ts.map +1 -0
  35. package/dist/components/ai-fill-dialog.jsx +105 -0
  36. package/dist/components/ai-fill-dialog.jsx.map +1 -0
  37. package/dist/components/chart-builder-dialog.d.ts +10 -0
  38. package/dist/components/chart-builder-dialog.d.ts.map +1 -0
  39. package/dist/components/chart-builder-dialog.jsx +433 -0
  40. package/dist/components/chart-builder-dialog.jsx.map +1 -0
  41. package/dist/components/chart-widget.d.ts +12 -0
  42. package/dist/components/chart-widget.d.ts.map +1 -0
  43. package/dist/components/chart-widget.jsx +365 -0
  44. package/dist/components/chart-widget.jsx.map +1 -0
  45. package/dist/components/global-search-dialog.d.ts +7 -0
  46. package/dist/components/global-search-dialog.d.ts.map +1 -0
  47. package/dist/components/global-search-dialog.jsx +187 -0
  48. package/dist/components/global-search-dialog.jsx.map +1 -0
  49. package/dist/components/group-settings-dialog.d.ts +13 -0
  50. package/dist/components/group-settings-dialog.d.ts.map +1 -0
  51. package/dist/components/group-settings-dialog.jsx +53 -0
  52. package/dist/components/group-settings-dialog.jsx.map +1 -0
  53. package/dist/components/move-chart-dialog.d.ts +18 -0
  54. package/dist/components/move-chart-dialog.d.ts.map +1 -0
  55. package/dist/components/move-chart-dialog.jsx +68 -0
  56. package/dist/components/move-chart-dialog.jsx.map +1 -0
  57. package/dist/components/reference-multi-table-dialog.d.ts +12 -0
  58. package/dist/components/reference-multi-table-dialog.d.ts.map +1 -0
  59. package/dist/components/reference-multi-table-dialog.jsx +126 -0
  60. package/dist/components/reference-multi-table-dialog.jsx.map +1 -0
  61. package/dist/components/related-records-tabs.d.ts +8 -0
  62. package/dist/components/related-records-tabs.d.ts.map +1 -0
  63. package/dist/components/related-records-tabs.jsx +75 -0
  64. package/dist/components/related-records-tabs.jsx.map +1 -0
  65. package/dist/components/revisions-button.d.ts +7 -0
  66. package/dist/components/revisions-button.d.ts.map +1 -0
  67. package/dist/components/revisions-button.jsx +152 -0
  68. package/dist/components/revisions-button.jsx.map +1 -0
  69. package/dist/components/wizard-form.d.ts +43 -0
  70. package/dist/components/wizard-form.d.ts.map +1 -0
  71. package/dist/components/wizard-form.jsx +136 -0
  72. package/dist/components/wizard-form.jsx.map +1 -0
  73. package/dist/dashboard/time-series.d.ts +20 -0
  74. package/dist/dashboard/time-series.d.ts.map +1 -0
  75. package/dist/dashboard/time-series.js +108 -0
  76. package/dist/dashboard/time-series.js.map +1 -0
  77. package/dist/dialogs.d.ts +35 -0
  78. package/dist/dialogs.d.ts.map +1 -0
  79. package/dist/dialogs.jsx +152 -0
  80. package/dist/dialogs.jsx.map +1 -0
  81. package/dist/export.d.ts +39 -0
  82. package/dist/export.d.ts.map +1 -0
  83. package/dist/export.js +114 -0
  84. package/dist/export.js.map +1 -0
  85. package/dist/extension-registry.d.ts +122 -0
  86. package/dist/extension-registry.d.ts.map +1 -0
  87. package/dist/extension-registry.js +93 -0
  88. package/dist/extension-registry.js.map +1 -0
  89. package/dist/header-controls.d.ts +4 -0
  90. package/dist/header-controls.d.ts.map +1 -0
  91. package/dist/header-controls.jsx +70 -0
  92. package/dist/header-controls.jsx.map +1 -0
  93. package/dist/hooks.d.ts +104 -0
  94. package/dist/hooks.d.ts.map +1 -0
  95. package/dist/hooks.js +374 -0
  96. package/dist/hooks.js.map +1 -0
  97. package/dist/hotkey-help.d.ts +3 -0
  98. package/dist/hotkey-help.d.ts.map +1 -0
  99. package/dist/hotkey-help.jsx +32 -0
  100. package/dist/hotkey-help.jsx.map +1 -0
  101. package/dist/hotkey-registry.d.ts +18 -0
  102. package/dist/hotkey-registry.d.ts.map +1 -0
  103. package/dist/hotkey-registry.jsx +34 -0
  104. package/dist/hotkey-registry.jsx.map +1 -0
  105. package/dist/i18n.d.ts +74 -0
  106. package/dist/i18n.d.ts.map +1 -0
  107. package/dist/i18n.jsx +127 -0
  108. package/dist/i18n.jsx.map +1 -0
  109. package/dist/index.d.ts +35 -0
  110. package/dist/index.d.ts.map +1 -0
  111. package/dist/index.js +36 -0
  112. package/dist/index.js.map +1 -0
  113. package/dist/notify.d.ts +41 -0
  114. package/dist/notify.d.ts.map +1 -0
  115. package/dist/notify.jsx +58 -0
  116. package/dist/notify.jsx.map +1 -0
  117. package/dist/pages/ai-assistant-settings-section.d.ts +3 -0
  118. package/dist/pages/ai-assistant-settings-section.d.ts.map +1 -0
  119. package/dist/pages/ai-assistant-settings-section.jsx +126 -0
  120. package/dist/pages/ai-assistant-settings-section.jsx.map +1 -0
  121. package/dist/pages/audit-log-page.d.ts +3 -0
  122. package/dist/pages/audit-log-page.d.ts.map +1 -0
  123. package/dist/pages/audit-log-page.jsx +354 -0
  124. package/dist/pages/audit-log-page.jsx.map +1 -0
  125. package/dist/pages/edit-page.d.ts +7 -0
  126. package/dist/pages/edit-page.d.ts.map +1 -0
  127. package/dist/pages/edit-page.jsx +614 -0
  128. package/dist/pages/edit-page.jsx.map +1 -0
  129. package/dist/pages/export-dialog.d.ts +11 -0
  130. package/dist/pages/export-dialog.d.ts.map +1 -0
  131. package/dist/pages/export-dialog.jsx +102 -0
  132. package/dist/pages/export-dialog.jsx.map +1 -0
  133. package/dist/pages/home-page.d.ts +3 -0
  134. package/dist/pages/home-page.d.ts.map +1 -0
  135. package/dist/pages/home-page.jsx +211 -0
  136. package/dist/pages/home-page.jsx.map +1 -0
  137. package/dist/pages/list-page.d.ts +42 -0
  138. package/dist/pages/list-page.d.ts.map +1 -0
  139. package/dist/pages/list-page.jsx +1596 -0
  140. package/dist/pages/list-page.jsx.map +1 -0
  141. package/dist/pages/login-page.d.ts +11 -0
  142. package/dist/pages/login-page.d.ts.map +1 -0
  143. package/dist/pages/login-page.jsx +157 -0
  144. package/dist/pages/login-page.jsx.map +1 -0
  145. package/dist/pages/settings-page.d.ts +5 -0
  146. package/dist/pages/settings-page.d.ts.map +1 -0
  147. package/dist/pages/settings-page.jsx +787 -0
  148. package/dist/pages/settings-page.jsx.map +1 -0
  149. package/dist/pages/settings-shared.d.ts +51 -0
  150. package/dist/pages/settings-shared.d.ts.map +1 -0
  151. package/dist/pages/settings-shared.jsx +66 -0
  152. package/dist/pages/settings-shared.jsx.map +1 -0
  153. package/dist/pages/show-page.d.ts +7 -0
  154. package/dist/pages/show-page.d.ts.map +1 -0
  155. package/dist/pages/show-page.jsx +147 -0
  156. package/dist/pages/show-page.jsx.map +1 -0
  157. package/dist/pages/wizard-create-page.d.ts +14 -0
  158. package/dist/pages/wizard-create-page.d.ts.map +1 -0
  159. package/dist/pages/wizard-create-page.jsx +106 -0
  160. package/dist/pages/wizard-create-page.jsx.map +1 -0
  161. package/dist/property-renderer.d.ts +8 -0
  162. package/dist/property-renderer.d.ts.map +1 -0
  163. package/dist/property-renderer.jsx +690 -0
  164. package/dist/property-renderer.jsx.map +1 -0
  165. package/dist/provider.d.ts +20 -0
  166. package/dist/provider.d.ts.map +1 -0
  167. package/dist/provider.jsx +32 -0
  168. package/dist/provider.jsx.map +1 -0
  169. package/dist/realtime.d.ts +22 -0
  170. package/dist/realtime.d.ts.map +1 -0
  171. package/dist/realtime.js +38 -0
  172. package/dist/realtime.js.map +1 -0
  173. package/dist/reference.d.ts +52 -0
  174. package/dist/reference.d.ts.map +1 -0
  175. package/dist/reference.jsx +224 -0
  176. package/dist/reference.jsx.map +1 -0
  177. package/dist/relations.d.ts +11 -0
  178. package/dist/relations.d.ts.map +1 -0
  179. package/dist/relations.js +36 -0
  180. package/dist/relations.js.map +1 -0
  181. package/dist/router.d.ts +82 -0
  182. package/dist/router.d.ts.map +1 -0
  183. package/dist/router.jsx +187 -0
  184. package/dist/router.jsx.map +1 -0
  185. package/dist/show-when.d.ts +7 -0
  186. package/dist/show-when.d.ts.map +1 -0
  187. package/dist/show-when.js +77 -0
  188. package/dist/show-when.js.map +1 -0
  189. package/dist/types.d.ts +194 -0
  190. package/dist/types.d.ts.map +1 -0
  191. package/dist/types.js +18 -0
  192. package/dist/types.js.map +1 -0
  193. package/dist/use-dashboard-charts.d.ts +93 -0
  194. package/dist/use-dashboard-charts.d.ts.map +1 -0
  195. package/dist/use-dashboard-charts.js +263 -0
  196. package/dist/use-dashboard-charts.js.map +1 -0
  197. package/dist/use-hotkey.d.ts +17 -0
  198. package/dist/use-hotkey.d.ts.map +1 -0
  199. package/dist/use-hotkey.js +103 -0
  200. package/dist/use-hotkey.js.map +1 -0
  201. package/dist/user-directory.d.ts +18 -0
  202. package/dist/user-directory.d.ts.map +1 -0
  203. package/dist/user-directory.js +51 -0
  204. package/dist/user-directory.js.map +1 -0
  205. package/dist/validation.d.ts +22 -0
  206. package/dist/validation.d.ts.map +1 -0
  207. package/dist/validation.js +338 -0
  208. package/dist/validation.js.map +1 -0
  209. package/package.json +59 -0
  210. package/src/action-guard.ts +20 -0
  211. package/src/action-menu.tsx +161 -0
  212. package/src/admin-app.tsx +630 -0
  213. package/src/admin-router.tsx +273 -0
  214. package/src/breadcrumbs.tsx +75 -0
  215. package/src/client.ts +1093 -0
  216. package/src/component-loader.ts +33 -0
  217. package/src/components/ai-assistant-widget.tsx +565 -0
  218. package/src/components/ai-fill-dialog.tsx +143 -0
  219. package/src/components/chart-builder-dialog.tsx +618 -0
  220. package/src/components/chart-widget.tsx +654 -0
  221. package/src/components/global-search-dialog.tsx +272 -0
  222. package/src/components/group-settings-dialog.tsx +93 -0
  223. package/src/components/move-chart-dialog.tsx +130 -0
  224. package/src/components/reference-multi-table-dialog.tsx +196 -0
  225. package/src/components/related-records-tabs.tsx +130 -0
  226. package/src/components/revisions-button.tsx +237 -0
  227. package/src/components/wizard-form.tsx +302 -0
  228. package/src/dashboard/time-series.ts +125 -0
  229. package/src/dialogs.tsx +265 -0
  230. package/src/export.ts +140 -0
  231. package/src/extension-registry.ts +195 -0
  232. package/src/header-controls.tsx +125 -0
  233. package/src/hooks.ts +509 -0
  234. package/src/hotkey-help.tsx +56 -0
  235. package/src/hotkey-registry.tsx +60 -0
  236. package/src/i18n.tsx +267 -0
  237. package/src/index.ts +192 -0
  238. package/src/notify.tsx +94 -0
  239. package/src/pages/ai-assistant-settings-section.tsx +167 -0
  240. package/src/pages/audit-log-page.tsx +580 -0
  241. package/src/pages/edit-page.tsx +743 -0
  242. package/src/pages/export-dialog.tsx +154 -0
  243. package/src/pages/home-page.tsx +318 -0
  244. package/src/pages/list-page.tsx +2645 -0
  245. package/src/pages/login-page.tsx +242 -0
  246. package/src/pages/settings-page.tsx +1143 -0
  247. package/src/pages/settings-shared.tsx +134 -0
  248. package/src/pages/show-page.tsx +223 -0
  249. package/src/pages/wizard-create-page.tsx +164 -0
  250. package/src/property-renderer.tsx +1143 -0
  251. package/src/provider.tsx +70 -0
  252. package/src/realtime.ts +55 -0
  253. package/src/reference.tsx +386 -0
  254. package/src/relations.ts +55 -0
  255. package/src/router.tsx +211 -0
  256. package/src/show-when.ts +76 -0
  257. package/src/types.ts +198 -0
  258. package/src/use-dashboard-charts.ts +362 -0
  259. package/src/use-hotkey.ts +128 -0
  260. package/src/user-directory.ts +56 -0
  261. package/src/validation.ts +361 -0
@@ -0,0 +1,93 @@
1
+ import { type ChartDef, type ChartDefInput, type ChartGroup, type DashboardBlob, type IDashboardStore, type TimeRange } from '@modern-admin/core';
2
+ import type { AdminClient, TimeSeriesMetric, TimeSeriesStep } from './client.js';
3
+ /**
4
+ * localStorage-backed `IDashboardStore`. Persists one blob per user under
5
+ * `modern-admin:dashboard:v1:<userId>` so multiple admins on the same
6
+ * browser do not see each other's charts.
7
+ *
8
+ * SSR-safe: `typeof window` checks gate every access; on the server load()
9
+ * returns `EMPTY_DASHBOARD` and save() is a no-op.
10
+ */
11
+ export declare class LocalStorageDashboardStore implements IDashboardStore {
12
+ load(userId: string): DashboardBlob;
13
+ save(userId: string, blob: DashboardBlob): void;
14
+ }
15
+ /**
16
+ * Server-backed `IDashboardStore` that persists per-user dashboard layouts
17
+ * via `GET/PUT /admin/api/dashboard`. Requires `configStore` to be wired in
18
+ * `ModernAdminModule.forRoot()`. Falls back gracefully when the endpoint
19
+ * returns an empty dashboard (e.g. first load or missing configStore).
20
+ */
21
+ export declare class ServerDashboardStore implements IDashboardStore {
22
+ private readonly client;
23
+ constructor(client: AdminClient);
24
+ load(_userId: string): Promise<DashboardBlob>;
25
+ save(_userId: string, blob: DashboardBlob): Promise<void>;
26
+ }
27
+ /**
28
+ * Resolve a `TimeRange` (preset or explicit custom) into concrete
29
+ * inclusive `from`/`to` `YYYY-MM-DD` strings. Presets are anchored to
30
+ * `now` so cards always reflect "the last N days" without re-saving.
31
+ *
32
+ * `'all'` resolves to a 10-year window ending at `now`, which is wide
33
+ * enough for any realistic admin dataset while keeping the server's
34
+ * date-range constraint satisfied.
35
+ */
36
+ export declare function resolveRange(range: TimeRange, now?: Date): {
37
+ from: string;
38
+ to: string;
39
+ };
40
+ /**
41
+ * Equal-length window immediately preceding `[from, to]`.
42
+ */
43
+ export declare function previousRangeOf(range: {
44
+ from: string;
45
+ to: string;
46
+ }): {
47
+ from: string;
48
+ to: string;
49
+ } | null;
50
+ /** Signal every mounted `useDashboardCharts` hook to reload from its store. */
51
+ export declare function emitDashboardReload(): void;
52
+ export interface UseDashboardChartsOptions {
53
+ /** Used to scope the storage key. `null`/`undefined` defers loading. */
54
+ userId: string | null | undefined;
55
+ /** Override the default localStorage store (e.g. server-backed in future). */
56
+ store?: IDashboardStore;
57
+ }
58
+ export interface UseDashboardChartsResult {
59
+ charts: ChartDef[];
60
+ /** Groups defined on the dashboard, sorted by `order` ascending. */
61
+ groups: ChartGroup[];
62
+ /** True until the initial load has resolved (relevant for async stores). */
63
+ isLoading: boolean;
64
+ /** Append a new chart. Auto-assigns to the first group when groups exist and no `groupId` is provided. */
65
+ addChart(input: ChartDefInput): void;
66
+ updateChart(id: string, input: ChartDefInput): void;
67
+ removeChart(id: string): void;
68
+ /**
69
+ * Create a new group. When this is the very first group, every existing
70
+ * (ungrouped) chart is moved into it so the user keeps the same view.
71
+ * Returns the new group id so callers can switch to it.
72
+ */
73
+ addGroup(input: {
74
+ name: string;
75
+ order?: number;
76
+ }): string;
77
+ updateGroup(id: string, patch: {
78
+ name?: string;
79
+ order?: number;
80
+ }): void;
81
+ /** Remove a group AND every chart assigned to it. */
82
+ removeGroup(id: string): void;
83
+ }
84
+ /**
85
+ * Per-user dashboard chart registry backed by `IDashboardStore` (default:
86
+ * `LocalStorageDashboardStore`). When `userId` is null/undefined the hook
87
+ * returns an empty list and ignores writes — used while
88
+ * `useCurrentUser()` is still loading.
89
+ */
90
+ export declare function useDashboardCharts(options: UseDashboardChartsOptions): UseDashboardChartsResult;
91
+ export type { TimeSeriesMetric, TimeSeriesStep };
92
+ export type { ChartDef, ChartDefInput, ChartGroup } from '@modern-admin/core';
93
+ //# sourceMappingURL=use-dashboard-charts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-dashboard-charts.d.ts","sourceRoot":"","sources":["../src/use-dashboard-charts.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,SAAS,EACf,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAKhF;;;;;;;GAOG;AACH,qBAAa,0BAA2B,YAAW,eAAe;IAChE,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa;IAenC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI;CAWhD;AAID;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,eAAe;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,WAAW;IAE1C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAS7C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;CAOhE;AAID;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,SAAS,EAChB,GAAG,GAAE,IAAiB,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAY9B;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAQrC;AAaD,+EAA+E;AAC/E,wBAAgB,mBAAmB,IAAI,IAAI,CAQ1C;AAID,MAAM,WAAW,yBAAyB;IACxC,wEAAwE;IACxE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IACjC,8EAA8E;IAC9E,KAAK,CAAC,EAAE,eAAe,CAAA;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,QAAQ,EAAE,CAAA;IAClB,oEAAoE;IACpE,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,4EAA4E;IAC5E,SAAS,EAAE,OAAO,CAAA;IAClB,0GAA0G;IAC1G,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAA;IACpC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAAA;IACnD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAA;IACzD,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACvE,qDAAqD;IACrD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,yBAAyB,GACjC,wBAAwB,CAqK1B;AASD,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,CAAA;AAChD,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,263 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { EMPTY_DASHBOARD, dashboardBlobZ, uuidv7, } from '@modern-admin/core';
3
+ const STORAGE_PREFIX = 'modern-admin:dashboard:v1:';
4
+ const ANON_USER = '__anon__';
5
+ /**
6
+ * localStorage-backed `IDashboardStore`. Persists one blob per user under
7
+ * `modern-admin:dashboard:v1:<userId>` so multiple admins on the same
8
+ * browser do not see each other's charts.
9
+ *
10
+ * SSR-safe: `typeof window` checks gate every access; on the server load()
11
+ * returns `EMPTY_DASHBOARD` and save() is a no-op.
12
+ */
13
+ export class LocalStorageDashboardStore {
14
+ load(userId) {
15
+ if (typeof window === 'undefined')
16
+ return EMPTY_DASHBOARD;
17
+ try {
18
+ const raw = window.localStorage.getItem(STORAGE_PREFIX + (userId || ANON_USER));
19
+ if (!raw)
20
+ return EMPTY_DASHBOARD;
21
+ const parsed = JSON.parse(raw);
22
+ const result = dashboardBlobZ.safeParse(parsed);
23
+ // Legacy bare-array shapes and other malformed blobs reset to empty
24
+ // rather than crashing the dashboard.
25
+ return result.success ? result.data : EMPTY_DASHBOARD;
26
+ }
27
+ catch {
28
+ return EMPTY_DASHBOARD;
29
+ }
30
+ }
31
+ save(userId, blob) {
32
+ if (typeof window === 'undefined')
33
+ return;
34
+ try {
35
+ window.localStorage.setItem(STORAGE_PREFIX + (userId || ANON_USER), JSON.stringify(blob));
36
+ }
37
+ catch {
38
+ // Quota exceeded / private mode — silently drop.
39
+ }
40
+ }
41
+ }
42
+ const defaultStore = new LocalStorageDashboardStore();
43
+ /**
44
+ * Server-backed `IDashboardStore` that persists per-user dashboard layouts
45
+ * via `GET/PUT /admin/api/dashboard`. Requires `configStore` to be wired in
46
+ * `ModernAdminModule.forRoot()`. Falls back gracefully when the endpoint
47
+ * returns an empty dashboard (e.g. first load or missing configStore).
48
+ */
49
+ export class ServerDashboardStore {
50
+ constructor(client) {
51
+ this.client = client;
52
+ }
53
+ async load(_userId) {
54
+ try {
55
+ const res = await this.client.loadDashboard();
56
+ return res.dashboard;
57
+ }
58
+ catch {
59
+ return EMPTY_DASHBOARD;
60
+ }
61
+ }
62
+ async save(_userId, blob) {
63
+ try {
64
+ await this.client.saveDashboard(blob);
65
+ }
66
+ catch {
67
+ // Server unavailable — silently drop. The next save attempt will retry.
68
+ }
69
+ }
70
+ }
71
+ // ─── Time-range helpers ──────────────────────────────────────────────────
72
+ /**
73
+ * Resolve a `TimeRange` (preset or explicit custom) into concrete
74
+ * inclusive `from`/`to` `YYYY-MM-DD` strings. Presets are anchored to
75
+ * `now` so cards always reflect "the last N days" without re-saving.
76
+ *
77
+ * `'all'` resolves to a 10-year window ending at `now`, which is wide
78
+ * enough for any realistic admin dataset while keeping the server's
79
+ * date-range constraint satisfied.
80
+ */
81
+ export function resolveRange(range, now = new Date()) {
82
+ if (range.preset === 'custom')
83
+ return { from: range.from, to: range.to };
84
+ const days = range.preset === '7d' ? 7
85
+ : range.preset === '30d' ? 30
86
+ : range.preset === '90d' ? 90
87
+ : range.preset === '1y' ? 365
88
+ : 3650; // 'all' → 10 years
89
+ const to = new Date(now);
90
+ const from = new Date(now);
91
+ from.setDate(from.getDate() - days);
92
+ return { from: ymd(from), to: ymd(to) };
93
+ }
94
+ /**
95
+ * Equal-length window immediately preceding `[from, to]`.
96
+ */
97
+ export function previousRangeOf(range) {
98
+ const f = new Date(range.from).getTime();
99
+ const t = new Date(range.to).getTime();
100
+ if (isNaN(f) || isNaN(t) || t < f)
101
+ return null;
102
+ const span = t - f;
103
+ const prevTo = new Date(f - 86_400_000);
104
+ const prevFrom = new Date(prevTo.getTime() - span);
105
+ return { from: ymd(prevFrom), to: ymd(prevTo) };
106
+ }
107
+ const ymd = (d) => d.toISOString().slice(0, 10);
108
+ // ─── Reload signal ───────────────────────────────────────────────────────
109
+ /**
110
+ * Module-scoped pub/sub so external code (e.g. AI assistant widget after a
111
+ * chart mutation) can force the dashboard to reload its blob from the store
112
+ * without lifting state up. Subscribers are notified asynchronously.
113
+ */
114
+ const dashboardReloadListeners = new Set();
115
+ /** Signal every mounted `useDashboardCharts` hook to reload from its store. */
116
+ export function emitDashboardReload() {
117
+ for (const listener of dashboardReloadListeners) {
118
+ try {
119
+ listener();
120
+ }
121
+ catch {
122
+ // Listener errors must not block sibling listeners.
123
+ }
124
+ }
125
+ }
126
+ /**
127
+ * Per-user dashboard chart registry backed by `IDashboardStore` (default:
128
+ * `LocalStorageDashboardStore`). When `userId` is null/undefined the hook
129
+ * returns an empty list and ignores writes — used while
130
+ * `useCurrentUser()` is still loading.
131
+ */
132
+ export function useDashboardCharts(options) {
133
+ const { userId, store = defaultStore } = options;
134
+ const [charts, setCharts] = useState([]);
135
+ const [groups, setGroups] = useState([]);
136
+ const [isLoading, setIsLoading] = useState(true);
137
+ // Bumping this counter re-runs the load effect; used by external
138
+ // `emitDashboardReload()` callers (e.g. AI assistant widget) so the hook
139
+ // can pick up changes other actors made to the underlying store.
140
+ const [reloadTick, setReloadTick] = useState(0);
141
+ // Reload whenever `userId` flips (login / logout / switch) or an external
142
+ // reload is signalled.
143
+ useEffect(() => {
144
+ if (!userId) {
145
+ setCharts([]);
146
+ setIsLoading(false);
147
+ return;
148
+ }
149
+ let cancelled = false;
150
+ setIsLoading(true);
151
+ Promise.resolve(store.load(userId)).then((blob) => {
152
+ if (cancelled)
153
+ return;
154
+ setCharts(blob.charts);
155
+ setGroups([...blob.groups].sort(byOrderThenCreated));
156
+ setIsLoading(false);
157
+ });
158
+ return () => {
159
+ cancelled = true;
160
+ };
161
+ }, [userId, store, reloadTick]);
162
+ // Subscribe to module-scoped reload signal.
163
+ useEffect(() => {
164
+ const listener = () => setReloadTick((tick) => tick + 1);
165
+ dashboardReloadListeners.add(listener);
166
+ return () => {
167
+ dashboardReloadListeners.delete(listener);
168
+ };
169
+ }, []);
170
+ // Single persist that writes BOTH charts and groups so a partial update
171
+ // never strands one in localStorage while overwriting the other.
172
+ const persist = useCallback((nextCharts, nextGroups) => {
173
+ setCharts(nextCharts);
174
+ setGroups([...nextGroups].sort(byOrderThenCreated));
175
+ if (!userId)
176
+ return;
177
+ void Promise.resolve(store.save(userId, { version: 1, charts: nextCharts, groups: nextGroups }));
178
+ }, [userId, store]);
179
+ const addChart = useCallback((input) => {
180
+ const now = new Date().toISOString();
181
+ // When groups exist and the caller didn't pick one, fall back to the
182
+ // first-ordered group so the new chart is visible somewhere.
183
+ const fallbackGroupId = input.groupId ?? groups[0]?.id;
184
+ const def = {
185
+ ...input,
186
+ id: uuidv7(),
187
+ title: input.title ?? '',
188
+ filters: input.filters ?? {},
189
+ ...(fallbackGroupId ? { groupId: fallbackGroupId } : {}),
190
+ createdAt: now,
191
+ updatedAt: now,
192
+ };
193
+ persist([...charts, def], groups);
194
+ }, [charts, groups, persist]);
195
+ const updateChart = useCallback((id, input) => {
196
+ persist(charts.map((c) => c.id === id
197
+ ? {
198
+ ...c,
199
+ ...input,
200
+ id,
201
+ title: input.title ?? '',
202
+ filters: input.filters ?? {},
203
+ createdAt: c.createdAt,
204
+ updatedAt: new Date().toISOString(),
205
+ }
206
+ : c), groups);
207
+ }, [charts, groups, persist]);
208
+ const removeChart = useCallback((id) => {
209
+ persist(charts.filter((c) => c.id !== id), groups);
210
+ }, [charts, groups, persist]);
211
+ const addGroup = useCallback((input) => {
212
+ const now = new Date().toISOString();
213
+ const id = uuidv7();
214
+ const next = {
215
+ id,
216
+ name: input.name,
217
+ order: input.order ?? groups.length,
218
+ createdAt: now,
219
+ updatedAt: now,
220
+ };
221
+ // First-group rule: existing ungrouped charts join this group so the
222
+ // user does not lose their current dashboard view.
223
+ const isFirstGroup = groups.length === 0;
224
+ const nextCharts = isFirstGroup
225
+ ? charts.map((c) => (c.groupId ? c : { ...c, groupId: id, updatedAt: now }))
226
+ : charts;
227
+ persist(nextCharts, [...groups, next]);
228
+ return id;
229
+ }, [charts, groups, persist]);
230
+ const updateGroup = useCallback((id, patch) => {
231
+ const now = new Date().toISOString();
232
+ persist(charts, groups.map((g) => g.id === id
233
+ ? {
234
+ ...g,
235
+ ...(patch.name !== undefined ? { name: patch.name } : {}),
236
+ ...(patch.order !== undefined ? { order: patch.order } : {}),
237
+ updatedAt: now,
238
+ }
239
+ : g));
240
+ }, [charts, groups, persist]);
241
+ const removeGroup = useCallback((id) => {
242
+ // Cascading delete: every chart assigned to the group disappears with it.
243
+ persist(charts.filter((c) => c.groupId !== id), groups.filter((g) => g.id !== id));
244
+ }, [charts, groups, persist]);
245
+ return {
246
+ charts,
247
+ groups,
248
+ isLoading,
249
+ addChart,
250
+ updateChart,
251
+ removeChart,
252
+ addGroup,
253
+ updateGroup,
254
+ removeGroup,
255
+ };
256
+ }
257
+ /** Stable sort: by `order` ascending, then by `createdAt` for tie-breaking. */
258
+ function byOrderThenCreated(a, b) {
259
+ if (a.order !== b.order)
260
+ return a.order - b.order;
261
+ return a.createdAt.localeCompare(b.createdAt);
262
+ }
263
+ //# sourceMappingURL=use-dashboard-charts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-dashboard-charts.js","sourceRoot":"","sources":["../src/use-dashboard-charts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface HotkeyOptions {
2
+ enabled?: boolean;
3
+ /** Override input-suppression. `true` always fires, `false` never. */
4
+ allowInInput?: boolean;
5
+ /** Call `preventDefault()` on match. Default `true`. */
6
+ preventDefault?: boolean;
7
+ /**
8
+ * Human-readable label shown in <KeyboardShortcutsHelp>. When set, the
9
+ * hotkey registers itself with the surrounding HotkeyRegistryProvider
10
+ * for the duration it's mounted (and `enabled`).
11
+ */
12
+ description?: string;
13
+ /** Optional group label used to bucket entries in the help dialog. */
14
+ group?: string;
15
+ }
16
+ export declare function useHotkey(combo: string | string[], handler: (e: KeyboardEvent) => void, options?: HotkeyOptions): void;
17
+ //# sourceMappingURL=use-hotkey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-hotkey.d.ts","sourceRoot":"","sources":["../src/use-hotkey.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,sEAAsE;IACtE,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,wDAAwD;IACxD,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAoED,wBAAgB,SAAS,CACvB,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,EACxB,OAAO,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,EACnC,OAAO,GAAE,aAAkB,GAC1B,IAAI,CA6BN"}
@@ -0,0 +1,103 @@
1
+ // Tiny keyboard-shortcut hook. Each combo is a `+`-separated string,
2
+ // e.g. `mod+s`, `ctrl+shift+k`, `esc`. `mod` matches Ctrl on
3
+ // Windows/Linux and Cmd on macOS so Ctrl+S / ⌘S map to the same handler.
4
+ //
5
+ // By default a chord with a modifier (mod / alt) fires anywhere; a
6
+ // modifier-less chord is suppressed when focus is inside an input,
7
+ // textarea, select, or contenteditable element so plain `n`/`r` keys
8
+ // don't hijack typing. Override per-call with `allowInInput`.
9
+ import * as React from 'react';
10
+ import { useHotkeyRegister } from './hotkey-registry.js';
11
+ const KEY_ALIASES = {
12
+ esc: 'escape',
13
+ space: ' ',
14
+ spacebar: ' ',
15
+ return: 'enter',
16
+ del: 'delete',
17
+ };
18
+ function keyToCode(key) {
19
+ if (/^[a-z]$/.test(key))
20
+ return `Key${key.toUpperCase()}`;
21
+ if (/^[0-9]$/.test(key))
22
+ return `Digit${key}`;
23
+ return null;
24
+ }
25
+ function parseCombo(s) {
26
+ const parts = s.toLowerCase().split('+').map((p) => p.trim()).filter(Boolean);
27
+ const last = parts[parts.length - 1] ?? '';
28
+ const key = KEY_ALIASES[last] ?? last;
29
+ const code = keyToCode(key);
30
+ const mod = parts.some((p) => p === 'mod' || p === 'ctrl' || p === 'meta' || p === 'cmd');
31
+ const shift = parts.includes('shift');
32
+ const alt = parts.includes('alt') || parts.includes('option');
33
+ return { key, code, mod, shift, alt, hasModifier: mod || alt };
34
+ }
35
+ function normalizeEventKey(e) {
36
+ return typeof e.key === 'string' ? e.key.toLowerCase() : null;
37
+ }
38
+ function normalizeEventCode(e) {
39
+ return typeof e.code === 'string' && e.code.length > 0 ? e.code : null;
40
+ }
41
+ function matches(c, e) {
42
+ if (c.code) {
43
+ const code = normalizeEventCode(e);
44
+ if (!code || code !== c.code)
45
+ return false;
46
+ }
47
+ else {
48
+ const k = normalizeEventKey(e);
49
+ if (!k || k !== c.key)
50
+ return false;
51
+ }
52
+ const hasMod = e.ctrlKey || e.metaKey;
53
+ if (c.mod !== hasMod)
54
+ return false;
55
+ if (c.alt !== e.altKey)
56
+ return false;
57
+ // Require shift only when explicitly asked. Letter keys may have shift
58
+ // accidentally engaged (caps lock, etc.) — allow that case.
59
+ if (c.shift && !e.shiftKey)
60
+ return false;
61
+ return true;
62
+ }
63
+ function isEditableTarget(target) {
64
+ if (!(target instanceof HTMLElement))
65
+ return false;
66
+ const tag = target.tagName;
67
+ if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT')
68
+ return true;
69
+ return target.isContentEditable;
70
+ }
71
+ export function useHotkey(combo, handler, options = {}) {
72
+ const { enabled = true, allowInInput, preventDefault = true, description, group } = options;
73
+ const handlerRef = React.useRef(handler);
74
+ React.useEffect(() => {
75
+ handlerRef.current = handler;
76
+ }, [handler]);
77
+ const comboKey = Array.isArray(combo) ? combo.join('|') : combo;
78
+ const register = useHotkeyRegister();
79
+ React.useEffect(() => {
80
+ if (!enabled)
81
+ return;
82
+ const parsed = comboKey.split('|').map(parseCombo);
83
+ const onKeyDown = (e) => {
84
+ const hit = parsed.find((c) => matches(c, e));
85
+ if (!hit)
86
+ return;
87
+ const allow = allowInInput ?? hit.hasModifier;
88
+ if (!allow && isEditableTarget(e.target))
89
+ return;
90
+ if (preventDefault)
91
+ e.preventDefault();
92
+ handlerRef.current(e);
93
+ };
94
+ document.addEventListener('keydown', onKeyDown);
95
+ return () => document.removeEventListener('keydown', onKeyDown);
96
+ }, [comboKey, enabled, allowInInput, preventDefault]);
97
+ React.useEffect(() => {
98
+ if (!enabled || !description)
99
+ return;
100
+ return register({ keys: comboKey, description, group });
101
+ }, [enabled, description, group, comboKey, register]);
102
+ }
103
+ //# sourceMappingURL=use-hotkey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-hotkey.js","sourceRoot":"","sources":["../src/use-hotkey.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { RecordJSON } from './types.js';
2
+ /** Convention: the host app exposes panel administrators under the
3
+ * `admins` resource id (backed by Better Auth's `ma_user` table). When
4
+ * absent or the lookup fails we fall back to the raw id string. */
5
+ export declare const USERS_RESOURCE_ID = "admins";
6
+ /** Resolve admin user records by id via the conventional `users` resource.
7
+ * Failed lookups (404 / no users resource) cache as `null` so we don't keep
8
+ * retrying them on every re-render.
9
+ *
10
+ * NOTE: uses the `'user-dir'` segment (not `'show'`) so the cached value
11
+ * (`RecordJSON | null`) doesn't collide with `useRecord`'s cache which stores
12
+ * the full `RecordResponse` shape under `['modern-admin', id, 'show', ...]`. */
13
+ export declare function useUserDirectory(userIds: ReadonlyArray<string>): Map<string, RecordJSON | null>;
14
+ /** Pick a human-readable label for an admin record. Checks explicit name
15
+ * fields first — `record.title` may be the id fallback when the resource
16
+ * has no matching TITLE_COLUMN_NAMES property. */
17
+ export declare function userLabelOf(record: RecordJSON | null | undefined, fallback: string): string;
18
+ //# sourceMappingURL=user-directory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-directory.d.ts","sourceRoot":"","sources":["../src/user-directory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C;;oEAEoE;AACpE,eAAO,MAAM,iBAAiB,WAAW,CAAA;AAEzC;;;;;;iFAMiF;AACjF,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,GAC7B,GAAG,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC,CAoBhC;AAED;;mDAEmD;AACnD,wBAAgB,WAAW,CACzB,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EACrC,QAAQ,EAAE,MAAM,GACf,MAAM,CASR"}
@@ -0,0 +1,51 @@
1
+ import { useQueries } from '@tanstack/react-query';
2
+ import { useAdminClient } from './provider.js';
3
+ /** Convention: the host app exposes panel administrators under the
4
+ * `admins` resource id (backed by Better Auth's `ma_user` table). When
5
+ * absent or the lookup fails we fall back to the raw id string. */
6
+ export const USERS_RESOURCE_ID = 'admins';
7
+ /** Resolve admin user records by id via the conventional `users` resource.
8
+ * Failed lookups (404 / no users resource) cache as `null` so we don't keep
9
+ * retrying them on every re-render.
10
+ *
11
+ * NOTE: uses the `'user-dir'` segment (not `'show'`) so the cached value
12
+ * (`RecordJSON | null`) doesn't collide with `useRecord`'s cache which stores
13
+ * the full `RecordResponse` shape under `['modern-admin', id, 'show', ...]`. */
14
+ export function useUserDirectory(userIds) {
15
+ const client = useAdminClient();
16
+ const queries = useQueries({
17
+ queries: userIds.map((id) => ({
18
+ queryKey: ['modern-admin', 'user-dir', USERS_RESOURCE_ID, id],
19
+ queryFn: async () => {
20
+ try {
21
+ const res = await client.show(USERS_RESOURCE_ID, id);
22
+ return res.record;
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ },
28
+ staleTime: 60_000,
29
+ retry: false,
30
+ })),
31
+ });
32
+ const map = new Map();
33
+ userIds.forEach((id, i) => map.set(id, queries[i]?.data ?? null));
34
+ return map;
35
+ }
36
+ /** Pick a human-readable label for an admin record. Checks explicit name
37
+ * fields first — `record.title` may be the id fallback when the resource
38
+ * has no matching TITLE_COLUMN_NAMES property. */
39
+ export function userLabelOf(record, fallback) {
40
+ if (!record)
41
+ return fallback;
42
+ const params = record.params ?? {};
43
+ const candidates = [params.name, params.fullName, params.email, record.title];
44
+ for (const candidate of candidates) {
45
+ const s = typeof candidate === 'string' ? candidate.trim() : '';
46
+ if (s && s !== record.id)
47
+ return s;
48
+ }
49
+ return fallback;
50
+ }
51
+ //# sourceMappingURL=user-directory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-directory.js","sourceRoot":"","sources":["../src/user-directory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAG9C;;oEAEoE;AACpE,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAA;AAEzC;;;;;;iFAMiF;AACjF,MAAM,UAAU,gBAAgB,CAC9B,OAA8B;IAE9B,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;IAC/B,MAAM,OAAO,GAAG,UAAU,CAAC;QACzB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAC5B,QAAQ,EAAE,CAAC,cAAc,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,CAAU;YACtE,OAAO,EAAE,KAAK,IAAgC,EAAE;gBAC9C,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAA;oBACpD,OAAO,GAAG,CAAC,MAAM,CAAA;gBACnB,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,IAAI,CAAA;gBACb,CAAC;YACH,CAAC;YACD,SAAS,EAAE,MAAM;YACjB,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;KACJ,CAAC,CAAA;IACF,MAAM,GAAG,GAAG,IAAI,GAAG,EAA6B,CAAA;IAChD,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC,CAAA;IACjE,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;mDAEmD;AACnD,MAAM,UAAU,WAAW,CACzB,MAAqC,EACrC,QAAgB;IAEhB,IAAI,CAAC,MAAM;QAAE,OAAO,QAAQ,CAAA;IAC5B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAA;IAClC,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IAC7E,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,CAAC,GAAG,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QAC/D,IAAI,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,EAAE;YAAE,OAAO,CAAC,CAAA;IACpC,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { z, type ZodType } from 'zod';
2
+ import type { PropertyJSON } from './types.js';
3
+ /**
4
+ * Lazy form-snapshot reader. Passed by the caller (the edit page) so the
5
+ * schema can consult the live form values at validation time without taking
6
+ * a hard dependency on RHF. Returning `{}` is fine — every property defaults
7
+ * to "visible" then.
8
+ */
9
+ export type FormValuesGetter = () => Record<string, unknown>;
10
+ export type Translator = (key: string, params?: Record<string, unknown>) => string;
11
+ /**
12
+ * Map a PropertyJSON to its Zod schema. When the property has a `showWhen`
13
+ * rule and a `getValues` getter is supplied, the schema short-circuits to
14
+ * a no-op while the rule does not match — letting hidden branches pass
15
+ * validation without their required/format checks tripping submission.
16
+ */
17
+ export declare function buildPropertySchema(p: PropertyJSON, t: Translator, getValues?: FormValuesGetter): ZodType;
18
+ /** Build a Zod object schema covering every editable property in a resource. */
19
+ export declare function buildValidationSchema(properties: PropertyJSON[], t: Translator, getValues?: FormValuesGetter): z.ZodObject<Record<string, ZodType>>;
20
+ /** Sensible empty default per type so RHF stays controlled from first render. */
21
+ export declare function defaultValueFor(p: PropertyJSON): unknown;
22
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,CAAC,EAAE,KAAK,OAAO,EAAE,MAAM,KAAK,CAAA;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAG9C;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAE5D,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAA;AAwRlF;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,CAAC,EAAE,YAAY,EACf,CAAC,EAAE,UAAU,EACb,SAAS,CAAC,EAAE,gBAAgB,GAC3B,OAAO,CA0BT;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,YAAY,EAAE,EAC1B,CAAC,EAAE,UAAU,EACb,SAAS,CAAC,EAAE,gBAAgB,GAC3B,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAItC;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,CAAC,EAAE,YAAY,GAAG,OAAO,CAKxD"}