@rebasepro/app 0.17.3 → 0.18.1

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 (185) hide show
  1. package/README.md +4 -1
  2. package/dist/components/index.d.ts +0 -3
  3. package/dist/contexts/AuthControllerContext.d.ts +2 -1
  4. package/dist/contexts/CustomizationControllerContext.d.ts +2 -1
  5. package/dist/contexts/DialogsProvider.d.ts +2 -1
  6. package/dist/contexts/RebaseDataContext.d.ts +10 -1
  7. package/dist/contexts/StorageSourceContext.d.ts +11 -1
  8. package/dist/core/RebaseProps.d.ts +2 -12
  9. package/dist/debug/index.d.ts +19 -0
  10. package/dist/debug.js +3631 -0
  11. package/dist/hooks/data/delete.d.ts +16 -7
  12. package/dist/hooks/data/save.d.ts +18 -4
  13. package/dist/hooks/index.d.ts +1 -0
  14. package/dist/hooks/useAdminModeController.d.ts +5 -4
  15. package/dist/hooks/useNavigationGroupLabel.d.ts +17 -0
  16. package/dist/hooks/useStudioBridge.d.ts +33 -0
  17. package/dist/index.es.js +2599 -6980
  18. package/dist/index.es.js.map +1 -1
  19. package/dist/vitePlugin.d.ts +22 -0
  20. package/dist/vitePlugin.js +40 -1
  21. package/package.json +42 -31
  22. package/src/auth/api.ts +0 -134
  23. package/src/auth/index.ts +0 -26
  24. package/src/auth/types.ts +0 -115
  25. package/src/auth/useRebaseAuthController.ts +0 -345
  26. package/src/collections/collection_view_config.ts +0 -76
  27. package/src/collections/entity-display-cache.ts +0 -195
  28. package/src/collections/entity-display.ts +0 -77
  29. package/src/collections/entity_image_preview.ts +0 -61
  30. package/src/collections/filter-operator-resolution.ts +0 -119
  31. package/src/collections/form-layout.ts +0 -394
  32. package/src/collections/index.ts +0 -13
  33. package/src/collections/navigation_from_path.ts +0 -123
  34. package/src/collections/navigation_utils.ts +0 -171
  35. package/src/collections/parent_references_from_path.ts +0 -59
  36. package/src/collections/property-path.ts +0 -30
  37. package/src/collections/property_presentation.ts +0 -264
  38. package/src/collections/summary-property.ts +0 -114
  39. package/src/collections/title-property.ts +0 -312
  40. package/src/components/AIIcon.tsx +0 -47
  41. package/src/components/AuthSimulationMenu.tsx +0 -0
  42. package/src/components/ConfirmationDialog.tsx +0 -48
  43. package/src/components/Debug/UIReferenceView.tsx +0 -1053
  44. package/src/components/Debug/UIStyleGuide.tsx +0 -159
  45. package/src/components/Debug/collection-views/CardViewDemo.tsx +0 -87
  46. package/src/components/Debug/collection-views/CollectionTableDemo.tsx +0 -107
  47. package/src/components/Debug/collection-views/KanbanBoardDemo.tsx +0 -89
  48. package/src/components/Debug/collection-views/index.ts +0 -3
  49. package/src/components/Debug/collection-views/sample_data.ts +0 -44
  50. package/src/components/Debug/crm-dashboard/CalendarWidget.tsx +0 -387
  51. package/src/components/Debug/crm-dashboard/CrmDashboardDemo.tsx +0 -1100
  52. package/src/components/Debug/crm-dashboard/DashboardMetrics.tsx +0 -131
  53. package/src/components/Debug/crm-dashboard/PipelineOverview.tsx +0 -288
  54. package/src/components/Debug/crm-dashboard/RecentActivity.tsx +0 -213
  55. package/src/components/Debug/crm-dashboard/TaskFilters.tsx +0 -182
  56. package/src/components/Debug/crm-dashboard/TaskTable.tsx +0 -425
  57. package/src/components/Debug/crm-dashboard/TasksView.tsx +0 -234
  58. package/src/components/ErrorTooltip.tsx +0 -12
  59. package/src/components/ErrorView.tsx +0 -94
  60. package/src/components/LanguageToggle.tsx +0 -59
  61. package/src/components/LoginView/LoginView.tsx +0 -1235
  62. package/src/components/LoginView/index.ts +0 -2
  63. package/src/components/LoginView/oauth-redirect-flow.ts +0 -184
  64. package/src/components/NotFoundPage.tsx +0 -27
  65. package/src/components/RebaseAuth.tsx +0 -27
  66. package/src/components/RebaseLogo.tsx +0 -88
  67. package/src/components/SchemaDriftBanner.tsx +0 -102
  68. package/src/components/UnsavedChangesDialog.tsx +0 -46
  69. package/src/components/UserDisplay.tsx +0 -54
  70. package/src/components/UserSelectPopover.tsx +0 -399
  71. package/src/components/UserSettingsView.tsx +0 -318
  72. package/src/components/common/index.ts +0 -6
  73. package/src/components/common/table_height.tsx +0 -21
  74. package/src/components/common/types.tsx +0 -66
  75. package/src/components/common/useColumnsIds.tsx +0 -261
  76. package/src/components/common/useDataTableController.tsx +0 -571
  77. package/src/components/common/useDebouncedData.ts +0 -49
  78. package/src/components/common/useScrollRestoration.tsx +0 -68
  79. package/src/components/index.tsx +0 -26
  80. package/src/contexts/AdminModeController.tsx +0 -11
  81. package/src/contexts/AnalyticsContext.tsx +0 -4
  82. package/src/contexts/AuthControllerContext.tsx +0 -4
  83. package/src/contexts/CollectionResolverContext.tsx +0 -24
  84. package/src/contexts/CollectionScopeContext.tsx +0 -68
  85. package/src/contexts/ComponentOverrideContext.tsx +0 -81
  86. package/src/contexts/CustomizationControllerContext.tsx +0 -4
  87. package/src/contexts/DataDriverContext.tsx +0 -4
  88. package/src/contexts/DataSourcesContext.tsx +0 -36
  89. package/src/contexts/DatabaseAdminContext.tsx +0 -4
  90. package/src/contexts/DialogsProvider.tsx +0 -56
  91. package/src/contexts/EffectiveRoleController.tsx +0 -12
  92. package/src/contexts/ModeController.tsx +0 -11
  93. package/src/contexts/RebaseClientInstanceContext.tsx +0 -7
  94. package/src/contexts/RebaseDataContext.tsx +0 -4
  95. package/src/contexts/SnackbarProvider.tsx +0 -15
  96. package/src/contexts/StorageSourceContext.tsx +0 -4
  97. package/src/contexts/StorageSourcesContext.tsx +0 -30
  98. package/src/contexts/UserConfigurationPersistenceContext.tsx +0 -4
  99. package/src/contexts/index.ts +0 -18
  100. package/src/core/PluginLifecycleManager.tsx +0 -96
  101. package/src/core/PluginProviderStack.tsx +0 -40
  102. package/src/core/Rebase.tsx +0 -488
  103. package/src/core/RebaseProps.tsx +0 -333
  104. package/src/core/RebaseRouter.tsx +0 -18
  105. package/src/core/RebaseRoutes.tsx +0 -24
  106. package/src/core/index.tsx +0 -5
  107. package/src/hooks/ApiConfigContext.tsx +0 -83
  108. package/src/hooks/data/collectionQuery.ts +0 -55
  109. package/src/hooks/data/delete.ts +0 -56
  110. package/src/hooks/data/save.ts +0 -78
  111. package/src/hooks/data/useCollection.tsx +0 -183
  112. package/src/hooks/data/useData.tsx +0 -18
  113. package/src/hooks/data/useDataOrder.ts +0 -26
  114. package/src/hooks/data/useFetch.tsx +0 -156
  115. package/src/hooks/data/useRelationSelector.tsx +0 -280
  116. package/src/hooks/index.tsx +0 -45
  117. package/src/hooks/useAdminModeController.tsx +0 -23
  118. package/src/hooks/useAnalyticsController.tsx +0 -8
  119. package/src/hooks/useAuthController.tsx +0 -15
  120. package/src/hooks/useAuthSubscription.ts +0 -130
  121. package/src/hooks/useBackendStorageSource.ts +0 -295
  122. package/src/hooks/useBridgeRegistration.tsx +0 -32
  123. package/src/hooks/useBrowserTitleAndIcon.tsx +0 -23
  124. package/src/hooks/useBuildAdminModeController.tsx +0 -29
  125. package/src/hooks/useBuildEffectiveRoleController.tsx +0 -30
  126. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +0 -83
  127. package/src/hooks/useBuildModeController.tsx +0 -73
  128. package/src/hooks/useClipboard.tsx +0 -158
  129. package/src/hooks/useCollapsedGroups.ts +0 -116
  130. package/src/hooks/useComponentOverride.tsx +0 -59
  131. package/src/hooks/useCustomizationController.tsx +0 -14
  132. package/src/hooks/useDialogsController.tsx +0 -15
  133. package/src/hooks/useEffectiveRoleController.tsx +0 -10
  134. package/src/hooks/useLargeLayout.tsx +0 -65
  135. package/src/hooks/useModeController.tsx +0 -23
  136. package/src/hooks/useNavigationBlocker.tsx +0 -108
  137. package/src/hooks/usePermissions.ts +0 -45
  138. package/src/hooks/useRebaseClient.tsx +0 -10
  139. package/src/hooks/useRebaseContext.tsx +0 -84
  140. package/src/hooks/useRebaseRegistry.tsx +0 -91
  141. package/src/hooks/useResolvedComponent.tsx +0 -195
  142. package/src/hooks/useSlot.tsx +0 -64
  143. package/src/hooks/useSnackbarController.tsx +0 -80
  144. package/src/hooks/useStorageSource.tsx +0 -11
  145. package/src/hooks/useStudioBridge.tsx +0 -258
  146. package/src/hooks/useTranslation.ts +0 -38
  147. package/src/hooks/useUnsavedChangesDialog.tsx +0 -67
  148. package/src/hooks/useUserConfigurationPersistence.tsx +0 -11
  149. package/src/i18n/RebaseI18nProvider.tsx +0 -159
  150. package/src/index.ts +0 -32
  151. package/src/internal/common.tsx +0 -28
  152. package/src/internal/useRestoreScroll.tsx +0 -69
  153. package/src/locales/de.ts +0 -941
  154. package/src/locales/en.ts +0 -1021
  155. package/src/locales/es.ts +0 -962
  156. package/src/locales/fr.ts +0 -941
  157. package/src/locales/hi.ts +0 -941
  158. package/src/locales/it.ts +0 -941
  159. package/src/locales/pt.ts +0 -949
  160. package/src/util/constants.ts +0 -7
  161. package/src/util/createFormexStub.tsx +0 -66
  162. package/src/util/entity_cache.ts +0 -242
  163. package/src/util/enums.ts +0 -34
  164. package/src/util/icon_list.ts +0 -22
  165. package/src/util/icons.tsx +0 -129
  166. package/src/util/index.ts +0 -13
  167. package/src/util/local_storage.ts +0 -66
  168. package/src/util/previews.ts +0 -127
  169. package/src/util/useStorageUploadController.tsx +0 -354
  170. package/src/vitePlugin.ts +0 -215
  171. /package/dist/{components/Debug → debug}/UIReferenceView.d.ts +0 -0
  172. /package/dist/{components/Debug → debug}/UIStyleGuide.d.ts +0 -0
  173. /package/dist/{components/Debug → debug}/collection-views/CardViewDemo.d.ts +0 -0
  174. /package/dist/{components/Debug → debug}/collection-views/CollectionTableDemo.d.ts +0 -0
  175. /package/dist/{components/Debug → debug}/collection-views/KanbanBoardDemo.d.ts +0 -0
  176. /package/dist/{components/Debug → debug}/collection-views/index.d.ts +0 -0
  177. /package/dist/{components/Debug → debug}/collection-views/sample_data.d.ts +0 -0
  178. /package/dist/{components/Debug → debug}/crm-dashboard/CalendarWidget.d.ts +0 -0
  179. /package/dist/{components/Debug → debug}/crm-dashboard/CrmDashboardDemo.d.ts +0 -0
  180. /package/dist/{components/Debug → debug}/crm-dashboard/DashboardMetrics.d.ts +0 -0
  181. /package/dist/{components/Debug → debug}/crm-dashboard/PipelineOverview.d.ts +0 -0
  182. /package/dist/{components/Debug → debug}/crm-dashboard/RecentActivity.d.ts +0 -0
  183. /package/dist/{components/Debug → debug}/crm-dashboard/TaskFilters.d.ts +0 -0
  184. /package/dist/{components/Debug → debug}/crm-dashboard/TaskTable.d.ts +0 -0
  185. /package/dist/{components/Debug → debug}/crm-dashboard/TasksView.d.ts +0 -0
@@ -1,83 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState, useMemo } from "react";
2
- import { PartialCollectionConfig, UserConfigurationPersistence } from "@rebasepro/cms-types";
3
- import { stripCollectionPath } from "@rebasepro/common";
4
- import { isArrayValue, isRecordValue, mergeDeep, readStoredJson, writeStoredJson } from "@rebasepro/utils";
5
-
6
- export function useBuildLocalConfigurationPersistence(): UserConfigurationPersistence {
7
-
8
- const configCache = useRef<Record<string, PartialCollectionConfig>>({});
9
-
10
- // Read during render by every collection view, so an unreadable value here
11
- // used to throw the view away rather than fall back to an unconfigured one.
12
- const getCollectionFromStorage = useCallback(<M extends Record<string, any>>(storageKey: string): PartialCollectionConfig<M> => {
13
- return readStoredJson<PartialCollectionConfig<M>>(storageKey, { fallback: {}, accept: isRecordValue });
14
- }, []);
15
-
16
- const getCollectionConfig = useCallback(<M extends Record<string, any>>(path: string): PartialCollectionConfig<M> => {
17
- const storageKey = `collection_config::${stripCollectionPath(path)}`;
18
- if (configCache.current[storageKey]) {
19
- return configCache.current[storageKey] as PartialCollectionConfig<M>;
20
- }
21
- return getCollectionFromStorage(storageKey);
22
- }, [getCollectionFromStorage]);
23
-
24
- const onCollectionModified = useCallback(<M extends Record<string, any>>(path: string, data: PartialCollectionConfig<M>) => {
25
- const storageKey = `collection_config::${stripCollectionPath(path)}`;
26
- writeStoredJson(storageKey, data);
27
- const cachedConfig = configCache.current[storageKey];
28
- // `getCollectionFromStorage` takes the storage key, not the path — every
29
- // other caller passes one. Reading `path` looked up a key this hook
30
- // never writes, so the fallback could only ever contribute `{}`. It is
31
- // masked today because the one caller merges the stored config in
32
- // before calling, but `onCollectionModified` accepts a partial by type
33
- // and by its public interface, and a real partial would lose the rest.
34
- const newConfig = mergeDeep(cachedConfig ?? getCollectionFromStorage(storageKey), data);
35
- configCache.current[storageKey] = mergeDeep(configCache.current[storageKey], newConfig);
36
- }, [getCollectionFromStorage]);
37
-
38
- const [recentlyVisitedPaths, _setRecentlyVisitedPaths] = useState<string[]>([]);
39
- const [favouritePaths, _setFavouritePaths] = useState<string[]>([]);
40
- const [collapsedGroups, _setCollapsedGroups] = useState<string[]>([]);
41
-
42
- useEffect(() => {
43
- const readPaths = (key: string) => readStoredJson<string[]>(key, { fallback: [], accept: isArrayValue });
44
- _setRecentlyVisitedPaths(readPaths("recently_visited_paths"));
45
- _setFavouritePaths(readPaths("favourite_paths"));
46
- _setCollapsedGroups(readPaths("collapsed_groups"));
47
- }, []);
48
-
49
- const setRecentlyVisitedPaths = useCallback((paths: string[]) => {
50
- writeStoredJson("recently_visited_paths", paths);
51
- _setRecentlyVisitedPaths(paths);
52
- }, []);
53
-
54
- const setFavouritePaths = useCallback((paths: string[]) => {
55
- writeStoredJson("favourite_paths", paths);
56
- _setFavouritePaths(paths);
57
- }, []);
58
-
59
- const setCollapsedGroups = useCallback((paths: string[]) => {
60
- writeStoredJson("collapsed_groups", paths);
61
- _setCollapsedGroups(paths);
62
- }, []);
63
-
64
- return useMemo(() => ({
65
- onCollectionModified,
66
- getCollectionConfig,
67
- recentlyVisitedPaths,
68
- setRecentlyVisitedPaths,
69
- favouritePaths,
70
- setFavouritePaths,
71
- collapsedGroups,
72
- setCollapsedGroups
73
- }), [
74
- onCollectionModified,
75
- getCollectionConfig,
76
- recentlyVisitedPaths,
77
- setRecentlyVisitedPaths,
78
- favouritePaths,
79
- setFavouritePaths,
80
- collapsedGroups,
81
- setCollapsedGroups
82
- ]);
83
- }
@@ -1,73 +0,0 @@
1
- import { useCallback, useEffect, useState, useMemo } from "react";
2
-
3
- import type { ModeController } from "./useModeController";
4
- import { readStoredString, removeStoredString, writeStoredString } from "../util/local_storage";
5
-
6
- /**
7
- * Use this hook to build a color mode controller that determines
8
- * the theme of the admin
9
- */
10
- export function useBuildModeController(): ModeController {
11
-
12
- const prefersDarkModeQuery = useCallback((): boolean => {
13
- if (typeof window === "undefined")
14
- return false;
15
- const mediaQueryList = window.matchMedia("(prefers-color-scheme: dark)");
16
- return mediaQueryList.matches;
17
- }, []);
18
-
19
- const [mode, setMode] = useState<"light" | "dark">(() => {
20
- const storedPrefersDarkMode = readStoredString("prefers-dark-mode");
21
- const prefersDarkModeStorage = storedPrefersDarkMode != null
22
- ? storedPrefersDarkMode === "true"
23
- : null;
24
- const prefersDarkMode = prefersDarkModeStorage ?? prefersDarkModeQuery();
25
- return prefersDarkMode ? "dark" : "light";
26
- });
27
-
28
- useEffect(() => {
29
- const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
30
- const handleChange = (e: MediaQueryListEvent) => {
31
- if (readStoredString("prefers-dark-mode") == null) {
32
- setMode(e.matches ? "dark" : "light");
33
- setDocumentMode(e.matches ? "dark" : "light");
34
- }
35
- };
36
-
37
- // Initial setup
38
- setDocumentMode(mode);
39
-
40
- mediaQuery.addEventListener("change", handleChange);
41
- return () => mediaQuery.removeEventListener("change", handleChange);
42
- }, []);
43
-
44
- const setDocumentMode = (mode: "light" | "dark") => {
45
- if (mode === "dark") {
46
- document.documentElement.classList.add("dark");
47
- } else {
48
- document.documentElement.classList.remove("dark");
49
- }
50
- };
51
-
52
- const setModeInternal = useCallback((mode: "light" | "dark" | "system") => {
53
- if (mode === "light") {
54
- setDocumentMode("light");
55
- writeStoredString("prefers-dark-mode", "false");
56
- setMode("light");
57
- } else if (mode === "dark") {
58
- setDocumentMode("dark");
59
- writeStoredString("prefers-dark-mode", "true");
60
- setMode("dark");
61
- } else {
62
- const preferredMode = prefersDarkModeQuery() ? "dark" : "light";
63
- setDocumentMode(preferredMode);
64
- removeStoredString("prefers-dark-mode");
65
- setMode(preferredMode);
66
- }
67
- }, [prefersDarkModeQuery]);
68
-
69
- return useMemo(() => ({
70
- mode,
71
- setMode: setModeInternal
72
- }), [mode, setModeInternal]);
73
- }
@@ -1,158 +0,0 @@
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
- };
@@ -1,116 +0,0 @@
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
- }
@@ -1,59 +0,0 @@
1
- import React, { useContext, useMemo } from "react";
2
- import type { OverridableComponentName } from "@rebasepro/cms-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
- }
@@ -1,14 +0,0 @@
1
- import type { CustomizationController } from "@rebasepro/cms-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 admin.
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);
@@ -1,15 +0,0 @@
1
- import type { DialogsController } from "@rebasepro/cms-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);
@@ -1,10 +0,0 @@
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);
@@ -1,65 +0,0 @@
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
- }
@@ -1,23 +0,0 @@
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);