@rebasepro/app 0.0.1-canary.4829d6e

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 (268) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -0
  3. package/dist/auth/api.d.ts +66 -0
  4. package/dist/auth/index.d.ts +13 -0
  5. package/dist/auth/types.d.ts +127 -0
  6. package/dist/auth/useRebaseAuthController.d.ts +13 -0
  7. package/dist/components/AIIcon.d.ts +17 -0
  8. package/dist/components/AuthSimulationMenu.d.ts +0 -0
  9. package/dist/components/ConfirmationDialog.d.ts +9 -0
  10. package/dist/components/Debug/UIReferenceView.d.ts +13 -0
  11. package/dist/components/Debug/UIStyleGuide.d.ts +2 -0
  12. package/dist/components/Debug/collection-views/CardViewDemo.d.ts +2 -0
  13. package/dist/components/Debug/collection-views/CollectionTableDemo.d.ts +2 -0
  14. package/dist/components/Debug/collection-views/KanbanBoardDemo.d.ts +2 -0
  15. package/dist/components/Debug/collection-views/index.d.ts +3 -0
  16. package/dist/components/Debug/collection-views/sample_data.d.ts +23 -0
  17. package/dist/components/Debug/crm-dashboard/CalendarWidget.d.ts +22 -0
  18. package/dist/components/Debug/crm-dashboard/CrmDashboardDemo.d.ts +2 -0
  19. package/dist/components/Debug/crm-dashboard/DashboardMetrics.d.ts +15 -0
  20. package/dist/components/Debug/crm-dashboard/PipelineOverview.d.ts +34 -0
  21. package/dist/components/Debug/crm-dashboard/RecentActivity.d.ts +19 -0
  22. package/dist/components/Debug/crm-dashboard/TaskFilters.d.ts +30 -0
  23. package/dist/components/Debug/crm-dashboard/TaskTable.d.ts +50 -0
  24. package/dist/components/Debug/crm-dashboard/TasksView.d.ts +41 -0
  25. package/dist/components/ErrorTooltip.d.ts +3 -0
  26. package/dist/components/ErrorView.d.ts +21 -0
  27. package/dist/components/LanguageToggle.d.ts +2 -0
  28. package/dist/components/LoginView/LoginView.d.ts +113 -0
  29. package/dist/components/LoginView/index.d.ts +2 -0
  30. package/dist/components/NotFoundPage.d.ts +2 -0
  31. package/dist/components/RebaseAuth.d.ts +10 -0
  32. package/dist/components/RebaseLogo.d.ts +7 -0
  33. package/dist/components/SchemaDriftBanner.d.ts +27 -0
  34. package/dist/components/UnsavedChangesDialog.d.ts +9 -0
  35. package/dist/components/UserDisplay.d.ts +7 -0
  36. package/dist/components/UserSelectPopover.d.ts +63 -0
  37. package/dist/components/UserSettingsView.d.ts +2 -0
  38. package/dist/components/common/index.d.ts +6 -0
  39. package/dist/components/common/table_height.d.ts +5 -0
  40. package/dist/components/common/types.d.ts +66 -0
  41. package/dist/components/common/useColumnsIds.d.ts +9 -0
  42. package/dist/components/common/useDataTableController.d.ts +45 -0
  43. package/dist/components/common/useDebouncedData.d.ts +9 -0
  44. package/dist/components/common/useScrollRestoration.d.ts +14 -0
  45. package/dist/components/index.d.ts +18 -0
  46. package/dist/contexts/AdminModeController.d.ts +4 -0
  47. package/dist/contexts/AnalyticsContext.d.ts +3 -0
  48. package/dist/contexts/AuthControllerContext.d.ts +3 -0
  49. package/dist/contexts/CollectionScopeContext.d.ts +50 -0
  50. package/dist/contexts/ComponentOverrideContext.d.ts +42 -0
  51. package/dist/contexts/CustomizationControllerContext.d.ts +3 -0
  52. package/dist/contexts/DataDriverContext.d.ts +3 -0
  53. package/dist/contexts/DataSourcesContext.d.ts +31 -0
  54. package/dist/contexts/DatabaseAdminContext.d.ts +3 -0
  55. package/dist/contexts/DialogsProvider.d.ts +4 -0
  56. package/dist/contexts/EffectiveRoleController.d.ts +4 -0
  57. package/dist/contexts/ModeController.d.ts +4 -0
  58. package/dist/contexts/RebaseClientInstanceContext.d.ts +6 -0
  59. package/dist/contexts/RebaseDataContext.d.ts +3 -0
  60. package/dist/contexts/SnackbarProvider.d.ts +2 -0
  61. package/dist/contexts/StorageSourceContext.d.ts +3 -0
  62. package/dist/contexts/StorageSourcesContext.d.ts +25 -0
  63. package/dist/contexts/UserConfigurationPersistenceContext.d.ts +3 -0
  64. package/dist/contexts/index.d.ts +17 -0
  65. package/dist/core/PluginLifecycleManager.d.ts +17 -0
  66. package/dist/core/PluginProviderStack.d.ts +21 -0
  67. package/dist/core/Rebase.d.ts +15 -0
  68. package/dist/core/RebaseProps.d.ts +291 -0
  69. package/dist/core/RebaseRouter.d.ts +4 -0
  70. package/dist/core/RebaseRoutes.d.ts +17 -0
  71. package/dist/core/index.d.ts +4 -0
  72. package/dist/hooks/ApiConfigContext.d.ts +24 -0
  73. package/dist/hooks/data/delete.d.ts +33 -0
  74. package/dist/hooks/data/save.d.ts +40 -0
  75. package/dist/hooks/data/useCollection.d.ts +62 -0
  76. package/dist/hooks/data/useData.d.ts +13 -0
  77. package/dist/hooks/data/useDataOrder.d.ts +12 -0
  78. package/dist/hooks/data/useFetch.d.ts +43 -0
  79. package/dist/hooks/data/useRelationSelector.d.ts +52 -0
  80. package/dist/hooks/index.d.ts +36 -0
  81. package/dist/hooks/useAdminModeController.d.ts +19 -0
  82. package/dist/hooks/useAnalyticsController.d.ts +5 -0
  83. package/dist/hooks/useAuthController.d.ts +11 -0
  84. package/dist/hooks/useAuthSubscription.d.ts +2 -0
  85. package/dist/hooks/useBackendStorageSource.d.ts +30 -0
  86. package/dist/hooks/useBridgeRegistration.d.ts +18 -0
  87. package/dist/hooks/useBrowserTitleAndIcon.d.ts +6 -0
  88. package/dist/hooks/useBuildAdminModeController.d.ts +6 -0
  89. package/dist/hooks/useBuildEffectiveRoleController.d.ts +8 -0
  90. package/dist/hooks/useBuildLocalConfigurationPersistence.d.ts +2 -0
  91. package/dist/hooks/useBuildModeController.d.ts +6 -0
  92. package/dist/hooks/useClipboard.d.ts +57 -0
  93. package/dist/hooks/useCollapsedGroups.d.ts +27 -0
  94. package/dist/hooks/useComponentOverride.d.ts +32 -0
  95. package/dist/hooks/useCustomizationController.d.ts +11 -0
  96. package/dist/hooks/useDialogsController.d.ts +11 -0
  97. package/dist/hooks/useEffectiveRoleController.d.ts +7 -0
  98. package/dist/hooks/useLargeLayout.d.ts +1 -0
  99. package/dist/hooks/useModeController.d.ts +19 -0
  100. package/dist/hooks/usePermissions.d.ts +12 -0
  101. package/dist/hooks/useRebaseClient.d.ts +5 -0
  102. package/dist/hooks/useRebaseContext.d.ts +11 -0
  103. package/dist/hooks/useRebaseRegistry.d.ts +34 -0
  104. package/dist/hooks/useResolvedComponent.d.ts +47 -0
  105. package/dist/hooks/useSlot.d.ts +18 -0
  106. package/dist/hooks/useSnackbarController.d.ts +20 -0
  107. package/dist/hooks/useStorageSource.d.ts +6 -0
  108. package/dist/hooks/useStudioBridge.d.ts +79 -0
  109. package/dist/hooks/useTranslation.d.ts +17 -0
  110. package/dist/hooks/useUnsavedChangesDialog.d.ts +12 -0
  111. package/dist/hooks/useUserConfigurationPersistence.d.ts +8 -0
  112. package/dist/i18n/RebaseI18nProvider.d.ts +33 -0
  113. package/dist/index.d.ts +16 -0
  114. package/dist/index.es.js +16843 -0
  115. package/dist/index.es.js.map +1 -0
  116. package/dist/index.umd.js +17021 -0
  117. package/dist/index.umd.js.map +1 -0
  118. package/dist/internal/common.d.ts +14 -0
  119. package/dist/internal/useRestoreScroll.d.ts +15 -0
  120. package/dist/locales/de.d.ts +2 -0
  121. package/dist/locales/en.d.ts +10 -0
  122. package/dist/locales/es.d.ts +10 -0
  123. package/dist/locales/fr.d.ts +2 -0
  124. package/dist/locales/hi.d.ts +2 -0
  125. package/dist/locales/it.d.ts +2 -0
  126. package/dist/locales/pt.d.ts +7 -0
  127. package/dist/util/constants.d.ts +1 -0
  128. package/dist/util/createFormexStub.d.ts +2 -0
  129. package/dist/util/entity_cache.d.ts +22 -0
  130. package/dist/util/enums.d.ts +5 -0
  131. package/dist/util/icon_list.d.ts +5 -0
  132. package/dist/util/icons.d.ts +20 -0
  133. package/dist/util/index.d.ts +8 -0
  134. package/dist/util/previews.d.ts +4 -0
  135. package/dist/util/useStorageUploadController.d.ts +44 -0
  136. package/dist/vitePlugin.d.ts +60 -0
  137. package/dist/vitePlugin.js +113 -0
  138. package/package.json +145 -0
  139. package/src/auth/api.ts +148 -0
  140. package/src/auth/index.ts +25 -0
  141. package/src/auth/types.ts +115 -0
  142. package/src/auth/useRebaseAuthController.ts +328 -0
  143. package/src/components/AIIcon.tsx +47 -0
  144. package/src/components/AuthSimulationMenu.tsx +0 -0
  145. package/src/components/ConfirmationDialog.tsx +48 -0
  146. package/src/components/Debug/UIReferenceView.tsx +958 -0
  147. package/src/components/Debug/UIStyleGuide.tsx +156 -0
  148. package/src/components/Debug/collection-views/CardViewDemo.tsx +85 -0
  149. package/src/components/Debug/collection-views/CollectionTableDemo.tsx +107 -0
  150. package/src/components/Debug/collection-views/KanbanBoardDemo.tsx +90 -0
  151. package/src/components/Debug/collection-views/index.ts +3 -0
  152. package/src/components/Debug/collection-views/sample_data.ts +42 -0
  153. package/src/components/Debug/crm-dashboard/CalendarWidget.tsx +389 -0
  154. package/src/components/Debug/crm-dashboard/CrmDashboardDemo.tsx +1102 -0
  155. package/src/components/Debug/crm-dashboard/DashboardMetrics.tsx +133 -0
  156. package/src/components/Debug/crm-dashboard/PipelineOverview.tsx +290 -0
  157. package/src/components/Debug/crm-dashboard/RecentActivity.tsx +215 -0
  158. package/src/components/Debug/crm-dashboard/TaskFilters.tsx +184 -0
  159. package/src/components/Debug/crm-dashboard/TaskTable.tsx +427 -0
  160. package/src/components/Debug/crm-dashboard/TasksView.tsx +234 -0
  161. package/src/components/ErrorTooltip.tsx +12 -0
  162. package/src/components/ErrorView.tsx +94 -0
  163. package/src/components/LanguageToggle.tsx +59 -0
  164. package/src/components/LoginView/LoginView.tsx +932 -0
  165. package/src/components/LoginView/index.ts +2 -0
  166. package/src/components/NotFoundPage.tsx +27 -0
  167. package/src/components/RebaseAuth.tsx +27 -0
  168. package/src/components/RebaseLogo.tsx +29 -0
  169. package/src/components/SchemaDriftBanner.tsx +102 -0
  170. package/src/components/UnsavedChangesDialog.tsx +46 -0
  171. package/src/components/UserDisplay.tsx +54 -0
  172. package/src/components/UserSelectPopover.tsx +399 -0
  173. package/src/components/UserSettingsView.tsx +318 -0
  174. package/src/components/common/index.ts +6 -0
  175. package/src/components/common/table_height.tsx +21 -0
  176. package/src/components/common/types.tsx +66 -0
  177. package/src/components/common/useColumnsIds.tsx +222 -0
  178. package/src/components/common/useDataTableController.tsx +514 -0
  179. package/src/components/common/useDebouncedData.ts +49 -0
  180. package/src/components/common/useScrollRestoration.tsx +68 -0
  181. package/src/components/index.tsx +26 -0
  182. package/src/contexts/AdminModeController.tsx +11 -0
  183. package/src/contexts/AnalyticsContext.tsx +4 -0
  184. package/src/contexts/AuthControllerContext.tsx +4 -0
  185. package/src/contexts/CollectionScopeContext.tsx +67 -0
  186. package/src/contexts/ComponentOverrideContext.tsx +81 -0
  187. package/src/contexts/CustomizationControllerContext.tsx +4 -0
  188. package/src/contexts/DataDriverContext.tsx +4 -0
  189. package/src/contexts/DataSourcesContext.tsx +36 -0
  190. package/src/contexts/DatabaseAdminContext.tsx +4 -0
  191. package/src/contexts/DialogsProvider.tsx +56 -0
  192. package/src/contexts/EffectiveRoleController.tsx +12 -0
  193. package/src/contexts/ModeController.tsx +11 -0
  194. package/src/contexts/RebaseClientInstanceContext.tsx +7 -0
  195. package/src/contexts/RebaseDataContext.tsx +4 -0
  196. package/src/contexts/SnackbarProvider.tsx +15 -0
  197. package/src/contexts/StorageSourceContext.tsx +4 -0
  198. package/src/contexts/StorageSourcesContext.tsx +30 -0
  199. package/src/contexts/UserConfigurationPersistenceContext.tsx +4 -0
  200. package/src/contexts/index.ts +17 -0
  201. package/src/core/PluginLifecycleManager.tsx +95 -0
  202. package/src/core/PluginProviderStack.tsx +40 -0
  203. package/src/core/Rebase.tsx +439 -0
  204. package/src/core/RebaseProps.tsx +320 -0
  205. package/src/core/RebaseRouter.tsx +17 -0
  206. package/src/core/RebaseRoutes.tsx +24 -0
  207. package/src/core/index.tsx +5 -0
  208. package/src/hooks/ApiConfigContext.tsx +41 -0
  209. package/src/hooks/data/delete.ts +55 -0
  210. package/src/hooks/data/save.ts +77 -0
  211. package/src/hooks/data/useCollection.tsx +176 -0
  212. package/src/hooks/data/useData.tsx +18 -0
  213. package/src/hooks/data/useDataOrder.ts +26 -0
  214. package/src/hooks/data/useFetch.tsx +140 -0
  215. package/src/hooks/data/useRelationSelector.tsx +234 -0
  216. package/src/hooks/index.tsx +45 -0
  217. package/src/hooks/useAdminModeController.tsx +23 -0
  218. package/src/hooks/useAnalyticsController.tsx +8 -0
  219. package/src/hooks/useAuthController.tsx +14 -0
  220. package/src/hooks/useAuthSubscription.ts +87 -0
  221. package/src/hooks/useBackendStorageSource.ts +288 -0
  222. package/src/hooks/useBridgeRegistration.tsx +32 -0
  223. package/src/hooks/useBrowserTitleAndIcon.tsx +23 -0
  224. package/src/hooks/useBuildAdminModeController.tsx +24 -0
  225. package/src/hooks/useBuildEffectiveRoleController.tsx +31 -0
  226. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +75 -0
  227. package/src/hooks/useBuildModeController.tsx +71 -0
  228. package/src/hooks/useClipboard.tsx +158 -0
  229. package/src/hooks/useCollapsedGroups.ts +116 -0
  230. package/src/hooks/useComponentOverride.tsx +59 -0
  231. package/src/hooks/useCustomizationController.tsx +14 -0
  232. package/src/hooks/useDialogsController.tsx +15 -0
  233. package/src/hooks/useEffectiveRoleController.tsx +10 -0
  234. package/src/hooks/useLargeLayout.tsx +65 -0
  235. package/src/hooks/useModeController.tsx +23 -0
  236. package/src/hooks/usePermissions.ts +44 -0
  237. package/src/hooks/useRebaseClient.tsx +10 -0
  238. package/src/hooks/useRebaseContext.tsx +83 -0
  239. package/src/hooks/useRebaseRegistry.tsx +91 -0
  240. package/src/hooks/useResolvedComponent.tsx +159 -0
  241. package/src/hooks/useSlot.tsx +64 -0
  242. package/src/hooks/useSnackbarController.tsx +52 -0
  243. package/src/hooks/useStorageSource.tsx +11 -0
  244. package/src/hooks/useStudioBridge.tsx +209 -0
  245. package/src/hooks/useTranslation.ts +33 -0
  246. package/src/hooks/useUnsavedChangesDialog.tsx +64 -0
  247. package/src/hooks/useUserConfigurationPersistence.tsx +11 -0
  248. package/src/i18n/RebaseI18nProvider.tsx +160 -0
  249. package/src/index.ts +25 -0
  250. package/src/internal/common.tsx +16 -0
  251. package/src/internal/useRestoreScroll.tsx +69 -0
  252. package/src/locales/de.ts +902 -0
  253. package/src/locales/en.ts +980 -0
  254. package/src/locales/es.ts +922 -0
  255. package/src/locales/fr.ts +901 -0
  256. package/src/locales/hi.ts +901 -0
  257. package/src/locales/it.ts +901 -0
  258. package/src/locales/pt.ts +909 -0
  259. package/src/util/constants.ts +7 -0
  260. package/src/util/createFormexStub.tsx +66 -0
  261. package/src/util/entity_cache.ts +239 -0
  262. package/src/util/enums.ts +32 -0
  263. package/src/util/icon_list.ts +22 -0
  264. package/src/util/icons.tsx +149 -0
  265. package/src/util/index.ts +12 -0
  266. package/src/util/previews.ts +105 -0
  267. package/src/util/useStorageUploadController.tsx +350 -0
  268. package/src/vitePlugin.ts +196 -0
@@ -0,0 +1,158 @@
1
+ // FORKED FROM https://github.com/fayeed/use-clipboard
2
+
3
+ import { MutableRefObject, useCallback, useEffect, useRef, useState, useMemo } from "react";
4
+
5
+ export interface UseClipboardProps {
6
+ /**
7
+ * It's callback function that is called after the `copy` command
8
+ * is executed.
9
+ *
10
+ * @param text: The selected clipboard text.
11
+ */
12
+ onSuccess?: (text: string) => void;
13
+
14
+ /**
15
+ * Triggers when the hook encounters an error.
16
+ * If passed hook won't throw an error.
17
+ *
18
+ * @param error: cause of the error
19
+ */
20
+ onError?: (error: string) => void;
21
+
22
+ /**
23
+ * Disables the new clipboard API `navigator.clipboard` even if
24
+ * it is supported.
25
+ */
26
+ disableClipboardAPI?: boolean;
27
+
28
+ /**
29
+ * revert back the isCopied flag to false again if a value is set.
30
+ */
31
+ copiedDuration?: number;
32
+ }
33
+
34
+ export interface useClipboardReturnType {
35
+ /**
36
+ * Use ref to pull the text content from.
37
+ */
38
+ ref: MutableRefObject<any>;
39
+
40
+ /**
41
+ * Use it to perform the copy operation
42
+ */
43
+ copy: (text?: string) => void;
44
+
45
+ /**
46
+ * Use it to perform the cut operation
47
+ */
48
+ cut: () => void;
49
+
50
+ /**
51
+ * Indicates wheater the content was successfully copied or not.
52
+ */
53
+ isCoppied: boolean;
54
+
55
+ /**
56
+ * Current selected clipboard content.
57
+ */
58
+ clipboard: string;
59
+
60
+ /**
61
+ * Clears the user clipboard.
62
+ */
63
+ clearClipboard: () => void;
64
+
65
+ /**
66
+ * Check to see if the browser supports the new `navigator.clipboard` API.
67
+ */
68
+ isSupported: () => boolean;
69
+ }
70
+
71
+ export const useClipboard = (
72
+ options?: UseClipboardProps
73
+ ): useClipboardReturnType => {
74
+ const { onSuccess, onError, disableClipboardAPI = false, copiedDuration } =
75
+ options || {};
76
+ const ref = useRef<any>(null);
77
+ const [isCoppied, setIsCoppied] = useState(false);
78
+ const [clipboard, setClipbaord] = useState("");
79
+
80
+ useEffect(() => {
81
+ if (copiedDuration) setTimeout(() => setIsCoppied(false), copiedDuration);
82
+ }, [isCoppied]);
83
+
84
+ const isSupported = useCallback(() => navigator.clipboard !== undefined, []);
85
+
86
+ const handleError = useCallback((error: string) => {
87
+ if (onError) onError(error);
88
+ else throw new Error(error);
89
+ }, [onError]);
90
+
91
+ const handleSuccess = useCallback((text: string) => {
92
+ if (onSuccess) onSuccess(text);
93
+ setIsCoppied(true);
94
+ setClipbaord(text);
95
+ }, [onSuccess]);
96
+
97
+ const copyToClipboard = useCallback((text: string) => {
98
+ navigator.clipboard
99
+ .writeText(text)
100
+ .then(() => handleSuccess(text))
101
+ .catch((err) => {
102
+ handleError(err);
103
+ setIsCoppied(false);
104
+ });
105
+ }, [handleError, handleSuccess]);
106
+
107
+ const clearClipboard = useCallback(() => {
108
+ if (isSupported()) {
109
+ navigator.clipboard.writeText("");
110
+ }
111
+ }, [isSupported]);
112
+
113
+ const action = useCallback(
114
+ (operation = "copy", text?: string) => {
115
+ const element = ref.current as HTMLElement;
116
+
117
+ const isInput =
118
+ element &&
119
+ (element.tagName === "INPUT" || element.tagName === "TEXTAREA");
120
+
121
+ const input = ref.current as HTMLInputElement;
122
+
123
+ if (isSupported() && !disableClipboardAPI) {
124
+ if (text) {
125
+ copyToClipboard(text);
126
+ } else if (element) {
127
+ if (isInput) {
128
+ copyToClipboard(input.value);
129
+
130
+ if (operation === "cut") {
131
+ input.value = "";
132
+ }
133
+ } else {
134
+ copyToClipboard(element.innerText);
135
+ }
136
+ } else {
137
+ handleError("Both the ref & text were undefined");
138
+ }
139
+ }
140
+ },
141
+ [disableClipboardAPI, copyToClipboard, handleError]
142
+ );
143
+
144
+ const copy = useCallback((text?: string) =>
145
+ action("copy", typeof text === "object" ? undefined : text), [action]);
146
+
147
+ const cut = useCallback(() => action("cut"), [action]);
148
+
149
+ return useMemo(() => ({
150
+ ref,
151
+ isCoppied,
152
+ clipboard,
153
+ clearClipboard,
154
+ isSupported,
155
+ copy,
156
+ cut
157
+ }), [isCoppied, clipboard, clearClipboard, isSupported, copy, cut]);
158
+ };
@@ -0,0 +1,116 @@
1
+ import { useCallback, useEffect, useState, useMemo } from "react";
2
+
3
+ const STORAGE_KEY_PREFIX = "rebase-collapsed-groups";
4
+
5
+ /**
6
+ * Custom hook for managing collapsed/expanded state of navigation groups
7
+ * with localStorage persistence. Automatically cleans up stale group entries
8
+ * when groups are removed from the navigation.
9
+ *
10
+ * Groups that have never been toggled by the user fall back to
11
+ * `defaults[groupName]` (driven by `collapsedByDefault` in config).
12
+ *
13
+ * @param groupNames - Array of group names to track
14
+ * @param namespace - Namespace for localStorage key (e.g., "home", "drawer") to allow independent state
15
+ * @param defaults - Optional map of group name → collapsed boolean from config
16
+ */
17
+ export function useCollapsedGroups(
18
+ groupNames: string[],
19
+ namespace = "default",
20
+ defaults?: Record<string, boolean>
21
+ ) {
22
+ const storageKey = `${STORAGE_KEY_PREFIX}-${namespace}`;
23
+
24
+ // Load collapsed groups from localStorage on mount
25
+ const [collapsedGroups, setCollapsedGroups] = useState<Record<string, boolean>>(() => {
26
+ try {
27
+ const stored = localStorage.getItem(storageKey);
28
+ return stored ? JSON.parse(stored) : {};
29
+ } catch {
30
+ return {};
31
+ }
32
+ });
33
+
34
+ // Save to localStorage whenever collapsedGroups changes
35
+ useEffect(() => {
36
+ try {
37
+ localStorage.setItem(storageKey, JSON.stringify(collapsedGroups));
38
+ } catch {
39
+ // Silently fail if localStorage is not available
40
+ }
41
+ }, [collapsedGroups, storageKey]);
42
+
43
+ // Clean up collapsed groups state when groups change - remove entries for groups that no longer exist
44
+ useEffect(() => {
45
+ // Only clean up if we have actual groups loaded (avoid cleaning up during initial load)
46
+ if (groupNames.length === 0) return;
47
+
48
+ const currentGroupNames = new Set(groupNames);
49
+
50
+ setCollapsedGroups(prev => {
51
+ const cleaned = Object.fromEntries(
52
+ Object.entries(prev).filter(([groupName]) => currentGroupNames.has(groupName))
53
+ );
54
+
55
+ // Only update if something actually changed
56
+ const prevKeys = Object.keys(prev);
57
+ const cleanedKeys = Object.keys(cleaned);
58
+
59
+ if (prevKeys.length === cleanedKeys.length && prevKeys.every(key => cleanedKeys.includes(key))) {
60
+ return prev;
61
+ }
62
+
63
+ return cleaned;
64
+ });
65
+ }, [groupNames]);
66
+
67
+ const isGroupCollapsed = useCallback((name: string) => {
68
+ // If the user has explicitly toggled this group, use that value
69
+ if (name in collapsedGroups) {
70
+ return collapsedGroups[name];
71
+ }
72
+ // Otherwise fall back to the config default
73
+ return defaults?.[name] ?? false;
74
+ }, [collapsedGroups, defaults]);
75
+
76
+ const toggleGroupCollapsed = useCallback((name: string) => {
77
+ setCollapsedGroups(prev => {
78
+ // Resolve current effective state (explicit or default)
79
+ const currentlyCollapsed = name in prev
80
+ ? prev[name]
81
+ : (defaults?.[name] ?? false);
82
+ return { ...prev,
83
+ [name]: !currentlyCollapsed };
84
+ });
85
+ }, [defaults]);
86
+
87
+ return useMemo(() => ({
88
+ isGroupCollapsed,
89
+ toggleGroupCollapsed
90
+ }), [isGroupCollapsed, toggleGroupCollapsed]);
91
+ }
92
+
93
+ /**
94
+ * Build a defaults map from navigationGroupMappings for a given namespace.
95
+ * Returns a Record<groupName, collapsed> that can be passed to useCollapsedGroups.
96
+ */
97
+ export function buildCollapsedDefaults(
98
+ mappings: Array<{ name: string; collapsedByDefault?: boolean | { drawer?: boolean; home?: boolean } }> | undefined,
99
+ namespace: "drawer" | "home"
100
+ ): Record<string, boolean> {
101
+ if (!mappings) return {};
102
+ const result: Record<string, boolean> = {};
103
+ for (const mapping of mappings) {
104
+ const val = mapping.collapsedByDefault;
105
+ if (val === undefined) continue;
106
+ if (typeof val === "boolean") {
107
+ result[mapping.name] = val;
108
+ } else {
109
+ const ns = val[namespace];
110
+ if (ns !== undefined) {
111
+ result[mapping.name] = ns;
112
+ }
113
+ }
114
+ }
115
+ return result;
116
+ }
@@ -0,0 +1,59 @@
1
+ import React, { useContext, useMemo } from "react";
2
+ import type { OverridableComponentName } from "@rebasepro/types";
3
+ import { ComponentOverrideContext } from "../contexts/ComponentOverrideContext";
4
+
5
+ /**
6
+ * Resolves a potentially overridden component.
7
+ *
8
+ * Resolution order:
9
+ * 1. Collection-scoped override (highest priority)
10
+ * 2. Global override
11
+ * 3. Default component (fallback)
12
+ *
13
+ * Supports two override modes:
14
+ * - **Eject** (default): The override component fully replaces the default.
15
+ * - **Wrap** (`wrap: true`): The override component wraps the default.
16
+ * The default is passed as `OriginalComponent` in props.
17
+ *
18
+ * @param name - The overridable component name (e.g. `"Entity.Form"`)
19
+ * @param DefaultComponent - The built-in default component
20
+ * @returns The resolved component — either the default, a full replacement, or a wrapper
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * import { useComponentOverride } from "@rebasepro/app";
25
+ *
26
+ * function EntityFormWrapper(props: EntityFormProps) {
27
+ * const ResolvedForm = useComponentOverride("Entity.Form", DefaultEntityForm);
28
+ * return <ResolvedForm {...props} />;
29
+ * }
30
+ * ```
31
+ *
32
+ * @group Hooks
33
+ */
34
+ export function useComponentOverride<P>(
35
+ name: OverridableComponentName,
36
+ DefaultComponent: React.ComponentType<P>
37
+ ): React.ComponentType<P> {
38
+ const { globalOverrides, collectionOverrides } = useContext(ComponentOverrideContext);
39
+
40
+ return useMemo(() => {
41
+ // Collection-level overrides have highest priority
42
+ const override = collectionOverrides[name] ?? globalOverrides[name];
43
+
44
+ if (!override) return DefaultComponent;
45
+
46
+ if (override.wrap) {
47
+ // Wrapping mode: inject OriginalComponent as a prop
48
+ const UserComponent = override.Component;
49
+ const Wrapper = (props: P) => (
50
+ <UserComponent {...(props as Record<string, unknown>)} OriginalComponent={DefaultComponent} />
51
+ );
52
+ Wrapper.displayName = `Wrapped(${name})`;
53
+ return Wrapper as React.ComponentType<P>;
54
+ }
55
+
56
+ // Eject mode: full replacement
57
+ return override.Component as React.ComponentType<P>;
58
+ }, [collectionOverrides, globalOverrides, name, DefaultComponent]);
59
+ }
@@ -0,0 +1,14 @@
1
+ import type { CustomizationController } from "@rebasepro/types";
2
+ import { useContext } from "react";
3
+ import { CustomizationControllerContext } from "../contexts/CustomizationControllerContext";
4
+
5
+ /**
6
+ * Use this hook to retrieve the customization controller.
7
+ * This hook includes all the customization options that can be used
8
+ * to customize the CMS.
9
+ *
10
+ * You will likely not need to use this hook directly.
11
+ *
12
+ * @group Hooks and utilities
13
+ */
14
+ export const useCustomizationController = (): CustomizationController => useContext(CustomizationControllerContext);
@@ -0,0 +1,15 @@
1
+ import type { DialogsController } from "@rebasepro/types";
2
+ import { useContext } from "react";
3
+ import { DialogsControllerContext } from "../contexts/DialogsProvider";
4
+ ;
5
+
6
+ /**
7
+ * Use this hook to open a dialog imperatively.
8
+ * Alternatively, you can use dialogs declaratively using the `Dialog` component.
9
+ *
10
+ * Consider that in order to use this hook you need to have a parent
11
+ * `Rebase`
12
+ *
13
+ * @group Hooks and utilities
14
+ */
15
+ export const useDialogsController = (): DialogsController => useContext(DialogsControllerContext);
@@ -0,0 +1,10 @@
1
+ import { useContext } from "react";
2
+ import { EffectiveRoleControllerContext } from "../contexts/EffectiveRoleController";
3
+
4
+ /**
5
+ * Hook to retrieve the {@link EffectiveRoleController}
6
+ *
7
+ * @see EffectiveRoleController
8
+ * @category Hooks and utilities
9
+ */
10
+ export const useEffectiveRoleController = () => useContext(EffectiveRoleControllerContext);
@@ -0,0 +1,65 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ type LayoutListener = (isLargeLayout: boolean) => void;
4
+
5
+ const breakpoints = {
6
+ xs: 0,
7
+ sm: 640,
8
+ md: 768,
9
+ lg: 1024,
10
+ xl: 1280,
11
+ "2xl": 1536,
12
+ "3xl": 1920
13
+ }
14
+
15
+ // Global state and listeners array
16
+ let isLargeLayoutGlobal = checkLargeLayout("lg"); // Default value
17
+ const listeners: LayoutListener[] = [];
18
+
19
+ // Utility to notify all listeners
20
+ const notifyListeners = () => {
21
+ listeners.forEach(listener => listener(isLargeLayoutGlobal));
22
+ };
23
+
24
+ // Listen to resize events once, at a global level
25
+ if (typeof window !== "undefined")
26
+ window.addEventListener("resize", () => {
27
+ const newIsLargeLayout = checkLargeLayout("lg");
28
+ if (newIsLargeLayout !== isLargeLayoutGlobal) {
29
+ isLargeLayoutGlobal = newIsLargeLayout;
30
+ notifyListeners();
31
+ }
32
+ });
33
+
34
+ export const useLargeLayout = () => {
35
+ const [isLargeLayout, setIsLargeLayout] = useState(isLargeLayoutGlobal);
36
+
37
+ useEffect(() => {
38
+ // Listener function to update component state
39
+ const listener: LayoutListener = (newIsLargeLayout) => {
40
+ setIsLargeLayout(newIsLargeLayout);
41
+ };
42
+
43
+ // Register listener
44
+ listeners.push(listener);
45
+
46
+ // Initial state
47
+ setIsLargeLayout(isLargeLayoutGlobal);
48
+
49
+ // Clean up by removing the listener
50
+ return () => {
51
+ const index = listeners.indexOf(listener);
52
+ if (index > -1) {
53
+ listeners.splice(index, 1);
54
+ }
55
+ };
56
+ }, []);
57
+
58
+ return isLargeLayout;
59
+ };
60
+
61
+ function checkLargeLayout(breakpoint: "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" = "lg"): boolean {
62
+ if (typeof window === "undefined")
63
+ return false;
64
+ return window.matchMedia(`(min-width: ${breakpoints[breakpoint] + 1}px)`).matches;
65
+ }
@@ -0,0 +1,23 @@
1
+ import { ModeControllerContext } from "../contexts/ModeController";
2
+ import { useContext } from "react";
3
+
4
+ /**
5
+ * Use this controller to change color mode
6
+ * @group Hooks and utilities
7
+ */
8
+ export interface ModeController {
9
+ mode: "light" | "dark";
10
+ setMode: (mode: "light" | "dark" | "system") => void;
11
+ }
12
+
13
+ /**
14
+ * Hook to retrieve the current mode ("light" | "dark"), and `setMode`
15
+ * or `toggle` functions to change it.
16
+ *
17
+ * Consider that in order to use this hook you need to have a parent
18
+ * `Rebase`
19
+ *
20
+ * @see ModeController
21
+ * @group Hooks and utilities
22
+ */
23
+ export const useModeController = () => useContext(ModeControllerContext);
@@ -0,0 +1,44 @@
1
+ import type { CollectionConfig } from "@rebasepro/types";
2
+ import { useAuthController } from "./useAuthController";
3
+ import { Entity } from "@rebasepro/types";
4
+ import { canCreateEntity, canEditEntity, canDeleteEntity, canReadCollection } from "@rebasepro/common";
5
+ import { useCallback, useMemo } from "react";
6
+
7
+ /**
8
+ * Hook to evaluate roles and permissions for the current user.
9
+ * It abstracts away the need to pass `authController` to permission evaluation functions.
10
+ */
11
+ export function usePermissions() {
12
+ const authController = useAuthController();
13
+
14
+ const canCreate = useCallback(
15
+ (collection: CollectionConfig<any>, path: string) =>
16
+ canCreateEntity(collection, authController, path, null),
17
+ [authController]
18
+ );
19
+
20
+ const canEdit = useCallback(
21
+ (collection: CollectionConfig<any>, path: string, entity: Entity<any> | null) =>
22
+ canEditEntity(collection, authController, path, entity),
23
+ [authController]
24
+ );
25
+
26
+ const canDelete = useCallback(
27
+ (collection: CollectionConfig<any>, path: string, entity: Entity<any> | null) =>
28
+ canDeleteEntity(collection, authController, path, entity),
29
+ [authController]
30
+ );
31
+
32
+ const canRead = useCallback(
33
+ (collection: CollectionConfig<any>) =>
34
+ canReadCollection(collection, authController),
35
+ [authController]
36
+ );
37
+
38
+ return useMemo(() => ({
39
+ canCreate,
40
+ canEdit,
41
+ canDelete,
42
+ canRead
43
+ }), [canCreate, canEdit, canDelete, canRead]);
44
+ }
@@ -0,0 +1,10 @@
1
+ import { useContext } from "react";
2
+ import { RebaseClientInstanceContext } from "../contexts/RebaseClientInstanceContext";
3
+
4
+ /**
5
+ * Hook to retrieve the full RebaseClient instance from context.
6
+ * Returns `undefined` if no client was provided to `<Rebase>`.
7
+ */
8
+ export function useRebaseClient<T = any>(): T | undefined {
9
+ return useContext(RebaseClientInstanceContext) as T | undefined;
10
+ }
@@ -0,0 +1,83 @@
1
+ import { AuthController, RebaseContext, User } from "@rebasepro/types";
2
+ import { wrapAsSdkData } from "@rebasepro/common";
3
+ import { useAuthController } from "./useAuthController";
4
+ import { useRebaseClient } from "./useRebaseClient";
5
+ import { useData } from "./data/useData";
6
+ import { useStorageSource } from "./useStorageSource";
7
+ import { useSnackbarController } from "./useSnackbarController";
8
+ import { useUserConfigurationPersistence } from "./useUserConfigurationPersistence";
9
+ import { useDialogsController } from "./useDialogsController";
10
+ import { useCustomizationController } from "./useCustomizationController";
11
+ import { useAnalyticsController } from "./useAnalyticsController";
12
+ import { useEffectiveRoleController } from "./useEffectiveRoleController";
13
+ import React, { useEffect, useContext } from "react";
14
+
15
+
16
+ // DatabaseAdmin is provided by <Rebase> via DatabaseAdminContext.
17
+ import { DatabaseAdminContext } from "../contexts/DatabaseAdminContext";
18
+
19
+ /**
20
+ * Hook to retrieve the {@link RebaseContext}.
21
+ *
22
+ * Consider that in order to use this hook you need to have a parent
23
+ * `Rebase` component.
24
+ *
25
+ * @see RebaseContext
26
+ * @group Hooks and utilities
27
+ */
28
+ export const useRebaseContext = <USER extends User = User, AuthControllerType extends AuthController<USER> = AuthController<USER>>(): RebaseContext<USER, AuthControllerType> => {
29
+
30
+ const client = useRebaseClient<any>();
31
+
32
+ const authController = useAuthController<USER, AuthControllerType>();
33
+ // `context.data` is the flat SDK view — identical in shape to the backend
34
+ // `context.data` and the frontend SDK client, so callbacks behave the same
35
+ // everywhere. The admin CMS reads Entities via `useData()` directly.
36
+ const entityData = useData();
37
+ const data = React.useMemo(() => wrapAsSdkData(entityData), [entityData]);
38
+ const storageSource = useStorageSource();
39
+ const snackbarController = useSnackbarController();
40
+ const userConfigPersistence = useUserConfigurationPersistence();
41
+ const dialogsController = useDialogsController();
42
+ const customizationController = useCustomizationController();
43
+ const analyticsController = useAnalyticsController();
44
+ const effectiveRoleController = useEffectiveRoleController();
45
+
46
+
47
+ // Will get `databaseAdmin` from context
48
+ const databaseAdmin = useContext(DatabaseAdminContext);
49
+
50
+ const rebaseContextRef = React.useRef<RebaseContext<USER, AuthControllerType>>({
51
+ authController,
52
+ data,
53
+ storageSource,
54
+ snackbarController,
55
+ userConfigPersistence,
56
+ dialogsController,
57
+ customizationController,
58
+ analyticsController,
59
+ effectiveRoleController,
60
+ databaseAdmin,
61
+ client: client! // Client should be provided
62
+ });
63
+
64
+ React.useEffect(() => {
65
+ rebaseContextRef.current = {
66
+ authController,
67
+ data,
68
+ storageSource,
69
+ snackbarController,
70
+ userConfigPersistence,
71
+ dialogsController,
72
+ customizationController,
73
+ analyticsController,
74
+ effectiveRoleController,
75
+ databaseAdmin,
76
+ client: client!
77
+ };
78
+ }, [authController, data, storageSource, snackbarController, userConfigPersistence,
79
+ dialogsController, customizationController, analyticsController,
80
+ effectiveRoleController, databaseAdmin, client]);
81
+
82
+ return rebaseContextRef.current;
83
+ }