@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.
- package/README.md +4 -1
- package/dist/components/index.d.ts +0 -3
- package/dist/contexts/AuthControllerContext.d.ts +2 -1
- package/dist/contexts/CustomizationControllerContext.d.ts +2 -1
- package/dist/contexts/DialogsProvider.d.ts +2 -1
- package/dist/contexts/RebaseDataContext.d.ts +10 -1
- package/dist/contexts/StorageSourceContext.d.ts +11 -1
- package/dist/core/RebaseProps.d.ts +2 -12
- package/dist/debug/index.d.ts +19 -0
- package/dist/debug.js +3631 -0
- package/dist/hooks/data/delete.d.ts +16 -7
- package/dist/hooks/data/save.d.ts +18 -4
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useAdminModeController.d.ts +5 -4
- package/dist/hooks/useNavigationGroupLabel.d.ts +17 -0
- package/dist/hooks/useStudioBridge.d.ts +33 -0
- package/dist/index.es.js +2599 -6980
- package/dist/index.es.js.map +1 -1
- package/dist/vitePlugin.d.ts +22 -0
- package/dist/vitePlugin.js +40 -1
- package/package.json +42 -31
- package/src/auth/api.ts +0 -134
- package/src/auth/index.ts +0 -26
- package/src/auth/types.ts +0 -115
- package/src/auth/useRebaseAuthController.ts +0 -345
- package/src/collections/collection_view_config.ts +0 -76
- package/src/collections/entity-display-cache.ts +0 -195
- package/src/collections/entity-display.ts +0 -77
- package/src/collections/entity_image_preview.ts +0 -61
- package/src/collections/filter-operator-resolution.ts +0 -119
- package/src/collections/form-layout.ts +0 -394
- package/src/collections/index.ts +0 -13
- package/src/collections/navigation_from_path.ts +0 -123
- package/src/collections/navigation_utils.ts +0 -171
- package/src/collections/parent_references_from_path.ts +0 -59
- package/src/collections/property-path.ts +0 -30
- package/src/collections/property_presentation.ts +0 -264
- package/src/collections/summary-property.ts +0 -114
- package/src/collections/title-property.ts +0 -312
- package/src/components/AIIcon.tsx +0 -47
- package/src/components/AuthSimulationMenu.tsx +0 -0
- package/src/components/ConfirmationDialog.tsx +0 -48
- package/src/components/Debug/UIReferenceView.tsx +0 -1053
- package/src/components/Debug/UIStyleGuide.tsx +0 -159
- package/src/components/Debug/collection-views/CardViewDemo.tsx +0 -87
- package/src/components/Debug/collection-views/CollectionTableDemo.tsx +0 -107
- package/src/components/Debug/collection-views/KanbanBoardDemo.tsx +0 -89
- package/src/components/Debug/collection-views/index.ts +0 -3
- package/src/components/Debug/collection-views/sample_data.ts +0 -44
- package/src/components/Debug/crm-dashboard/CalendarWidget.tsx +0 -387
- package/src/components/Debug/crm-dashboard/CrmDashboardDemo.tsx +0 -1100
- package/src/components/Debug/crm-dashboard/DashboardMetrics.tsx +0 -131
- package/src/components/Debug/crm-dashboard/PipelineOverview.tsx +0 -288
- package/src/components/Debug/crm-dashboard/RecentActivity.tsx +0 -213
- package/src/components/Debug/crm-dashboard/TaskFilters.tsx +0 -182
- package/src/components/Debug/crm-dashboard/TaskTable.tsx +0 -425
- package/src/components/Debug/crm-dashboard/TasksView.tsx +0 -234
- package/src/components/ErrorTooltip.tsx +0 -12
- package/src/components/ErrorView.tsx +0 -94
- package/src/components/LanguageToggle.tsx +0 -59
- package/src/components/LoginView/LoginView.tsx +0 -1235
- package/src/components/LoginView/index.ts +0 -2
- package/src/components/LoginView/oauth-redirect-flow.ts +0 -184
- package/src/components/NotFoundPage.tsx +0 -27
- package/src/components/RebaseAuth.tsx +0 -27
- package/src/components/RebaseLogo.tsx +0 -88
- package/src/components/SchemaDriftBanner.tsx +0 -102
- package/src/components/UnsavedChangesDialog.tsx +0 -46
- package/src/components/UserDisplay.tsx +0 -54
- package/src/components/UserSelectPopover.tsx +0 -399
- package/src/components/UserSettingsView.tsx +0 -318
- package/src/components/common/index.ts +0 -6
- package/src/components/common/table_height.tsx +0 -21
- package/src/components/common/types.tsx +0 -66
- package/src/components/common/useColumnsIds.tsx +0 -261
- package/src/components/common/useDataTableController.tsx +0 -571
- package/src/components/common/useDebouncedData.ts +0 -49
- package/src/components/common/useScrollRestoration.tsx +0 -68
- package/src/components/index.tsx +0 -26
- package/src/contexts/AdminModeController.tsx +0 -11
- package/src/contexts/AnalyticsContext.tsx +0 -4
- package/src/contexts/AuthControllerContext.tsx +0 -4
- package/src/contexts/CollectionResolverContext.tsx +0 -24
- package/src/contexts/CollectionScopeContext.tsx +0 -68
- package/src/contexts/ComponentOverrideContext.tsx +0 -81
- package/src/contexts/CustomizationControllerContext.tsx +0 -4
- package/src/contexts/DataDriverContext.tsx +0 -4
- package/src/contexts/DataSourcesContext.tsx +0 -36
- package/src/contexts/DatabaseAdminContext.tsx +0 -4
- package/src/contexts/DialogsProvider.tsx +0 -56
- package/src/contexts/EffectiveRoleController.tsx +0 -12
- package/src/contexts/ModeController.tsx +0 -11
- package/src/contexts/RebaseClientInstanceContext.tsx +0 -7
- package/src/contexts/RebaseDataContext.tsx +0 -4
- package/src/contexts/SnackbarProvider.tsx +0 -15
- package/src/contexts/StorageSourceContext.tsx +0 -4
- package/src/contexts/StorageSourcesContext.tsx +0 -30
- package/src/contexts/UserConfigurationPersistenceContext.tsx +0 -4
- package/src/contexts/index.ts +0 -18
- package/src/core/PluginLifecycleManager.tsx +0 -96
- package/src/core/PluginProviderStack.tsx +0 -40
- package/src/core/Rebase.tsx +0 -488
- package/src/core/RebaseProps.tsx +0 -333
- package/src/core/RebaseRouter.tsx +0 -18
- package/src/core/RebaseRoutes.tsx +0 -24
- package/src/core/index.tsx +0 -5
- package/src/hooks/ApiConfigContext.tsx +0 -83
- package/src/hooks/data/collectionQuery.ts +0 -55
- package/src/hooks/data/delete.ts +0 -56
- package/src/hooks/data/save.ts +0 -78
- package/src/hooks/data/useCollection.tsx +0 -183
- package/src/hooks/data/useData.tsx +0 -18
- package/src/hooks/data/useDataOrder.ts +0 -26
- package/src/hooks/data/useFetch.tsx +0 -156
- package/src/hooks/data/useRelationSelector.tsx +0 -280
- package/src/hooks/index.tsx +0 -45
- package/src/hooks/useAdminModeController.tsx +0 -23
- package/src/hooks/useAnalyticsController.tsx +0 -8
- package/src/hooks/useAuthController.tsx +0 -15
- package/src/hooks/useAuthSubscription.ts +0 -130
- package/src/hooks/useBackendStorageSource.ts +0 -295
- package/src/hooks/useBridgeRegistration.tsx +0 -32
- package/src/hooks/useBrowserTitleAndIcon.tsx +0 -23
- package/src/hooks/useBuildAdminModeController.tsx +0 -29
- package/src/hooks/useBuildEffectiveRoleController.tsx +0 -30
- package/src/hooks/useBuildLocalConfigurationPersistence.tsx +0 -83
- package/src/hooks/useBuildModeController.tsx +0 -73
- package/src/hooks/useClipboard.tsx +0 -158
- package/src/hooks/useCollapsedGroups.ts +0 -116
- package/src/hooks/useComponentOverride.tsx +0 -59
- package/src/hooks/useCustomizationController.tsx +0 -14
- package/src/hooks/useDialogsController.tsx +0 -15
- package/src/hooks/useEffectiveRoleController.tsx +0 -10
- package/src/hooks/useLargeLayout.tsx +0 -65
- package/src/hooks/useModeController.tsx +0 -23
- package/src/hooks/useNavigationBlocker.tsx +0 -108
- package/src/hooks/usePermissions.ts +0 -45
- package/src/hooks/useRebaseClient.tsx +0 -10
- package/src/hooks/useRebaseContext.tsx +0 -84
- package/src/hooks/useRebaseRegistry.tsx +0 -91
- package/src/hooks/useResolvedComponent.tsx +0 -195
- package/src/hooks/useSlot.tsx +0 -64
- package/src/hooks/useSnackbarController.tsx +0 -80
- package/src/hooks/useStorageSource.tsx +0 -11
- package/src/hooks/useStudioBridge.tsx +0 -258
- package/src/hooks/useTranslation.ts +0 -38
- package/src/hooks/useUnsavedChangesDialog.tsx +0 -67
- package/src/hooks/useUserConfigurationPersistence.tsx +0 -11
- package/src/i18n/RebaseI18nProvider.tsx +0 -159
- package/src/index.ts +0 -32
- package/src/internal/common.tsx +0 -28
- package/src/internal/useRestoreScroll.tsx +0 -69
- package/src/locales/de.ts +0 -941
- package/src/locales/en.ts +0 -1021
- package/src/locales/es.ts +0 -962
- package/src/locales/fr.ts +0 -941
- package/src/locales/hi.ts +0 -941
- package/src/locales/it.ts +0 -941
- package/src/locales/pt.ts +0 -949
- package/src/util/constants.ts +0 -7
- package/src/util/createFormexStub.tsx +0 -66
- package/src/util/entity_cache.ts +0 -242
- package/src/util/enums.ts +0 -34
- package/src/util/icon_list.ts +0 -22
- package/src/util/icons.tsx +0 -129
- package/src/util/index.ts +0 -13
- package/src/util/local_storage.ts +0 -66
- package/src/util/previews.ts +0 -127
- package/src/util/useStorageUploadController.tsx +0 -354
- package/src/vitePlugin.ts +0 -215
- /package/dist/{components/Debug → debug}/UIReferenceView.d.ts +0 -0
- /package/dist/{components/Debug → debug}/UIStyleGuide.d.ts +0 -0
- /package/dist/{components/Debug → debug}/collection-views/CardViewDemo.d.ts +0 -0
- /package/dist/{components/Debug → debug}/collection-views/CollectionTableDemo.d.ts +0 -0
- /package/dist/{components/Debug → debug}/collection-views/KanbanBoardDemo.d.ts +0 -0
- /package/dist/{components/Debug → debug}/collection-views/index.d.ts +0 -0
- /package/dist/{components/Debug → debug}/collection-views/sample_data.d.ts +0 -0
- /package/dist/{components/Debug → debug}/crm-dashboard/CalendarWidget.d.ts +0 -0
- /package/dist/{components/Debug → debug}/crm-dashboard/CrmDashboardDemo.d.ts +0 -0
- /package/dist/{components/Debug → debug}/crm-dashboard/DashboardMetrics.d.ts +0 -0
- /package/dist/{components/Debug → debug}/crm-dashboard/PipelineOverview.d.ts +0 -0
- /package/dist/{components/Debug → debug}/crm-dashboard/RecentActivity.d.ts +0 -0
- /package/dist/{components/Debug → debug}/crm-dashboard/TaskFilters.d.ts +0 -0
- /package/dist/{components/Debug → debug}/crm-dashboard/TaskTable.d.ts +0 -0
- /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);
|