@donotdev/ui 0.0.14 → 0.0.16
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/dist/components/common/TechBento.d.ts.map +1 -1
- package/dist/components/common/TechBento.js +1 -1
- package/dist/components/layout/components/header/HeaderNavigation.d.ts.map +1 -1
- package/dist/components/layout/components/header/HeaderNavigation.js +2 -2
- package/dist/components/layout/components/index.d.ts +3 -0
- package/dist/components/layout/components/index.d.ts.map +1 -1
- package/dist/components/layout/components/index.js +3 -0
- package/dist/crud/components/CrudCardLink.d.ts.map +1 -1
- package/dist/crud/components/EntityCardList.d.ts +1 -1
- package/dist/crud/components/EntityCardList.d.ts.map +1 -1
- package/dist/crud/components/EntityCardList.js +24 -35
- package/dist/crud/components/EntityDisplayRenderer.d.ts +1 -1
- package/dist/crud/components/EntityDisplayRenderer.d.ts.map +1 -1
- package/dist/crud/components/EntityDisplayRenderer.js +6 -2
- package/dist/crud/components/EntityFormRenderer.d.ts +1 -1
- package/dist/crud/components/EntityFormRenderer.d.ts.map +1 -1
- package/dist/crud/components/EntityFormRenderer.js +12 -29
- package/dist/crud/components/EntityList.d.ts.map +1 -1
- package/dist/crud/components/EntityList.js +7 -43
- package/dist/crud/components/EntityRecommendations.d.ts +1 -0
- package/dist/crud/components/EntityRecommendations.d.ts.map +1 -1
- package/dist/crud/components/EntityRecommendations.js +3 -2
- package/dist/dndev.css +11581 -0
- package/dist/index.js +4 -4
- package/dist/internal/devtools/components/DesignTab.d.ts.map +1 -1
- package/dist/internal/layout/components/AutoMetaTags.d.ts.map +1 -1
- package/dist/internal/layout/components/AutoMetaTags.js +2 -9
- package/dist/internal/layout/components/FontPreloadLinks.d.ts.map +1 -1
- package/dist/internal/layout/components/FontPreloadLinks.js +1 -0
- package/dist/internal/layout/components/footer/useLegalLinks.d.ts.map +1 -1
- package/dist/internal/providers/NavigationProvider.d.ts.map +1 -1
- package/dist/internal/providers/NavigationProvider.js +3 -5
- package/dist/providers/ViteAppProviders.d.ts.map +1 -1
- package/dist/providers/ViteAppProviders.js +3 -5
- package/dist/routing/GoToInput.d.ts.map +1 -1
- package/dist/routing/GoToInput.js +6 -6
- package/dist/routing/Link.d.ts.map +1 -1
- package/dist/routing/hooks/hooks.next.js +1 -1
- package/dist/routing/hooks/hooks.vite.js +1 -1
- package/dist/routing/hooks/useNavigate.next.d.ts +1 -1
- package/dist/routing/hooks/useNavigate.next.d.ts.map +1 -1
- package/dist/routing/hooks/useNavigate.next.js +1 -7
- package/dist/routing/hooks/useNavigate.vite.d.ts +1 -1
- package/dist/routing/hooks/useNavigate.vite.d.ts.map +1 -1
- package/dist/routing/hooks/useNavigate.vite.js +1 -7
- package/dist/routing/useRouteDiscovery.d.ts +4 -15
- package/dist/routing/useRouteDiscovery.d.ts.map +1 -1
- package/dist/routing/useRouteDiscovery.js +6 -5
- package/dist/styles/index.css +96 -63
- package/dist/utils/sanitizeSvg.d.ts.map +1 -1
- package/dist/utils/useFormStoreSafe.d.ts +2 -15
- package/dist/utils/useFormStoreSafe.d.ts.map +1 -1
- package/dist/utils/useFormStoreSafe.js +3 -33
- package/dist/vite-routing/AppRoutes.d.ts.map +1 -1
- package/dist/vite-routing/AppRoutes.js +1 -1
- package/dist/vite-routing/RootLayout.d.ts.map +1 -1
- package/dist/vite-routing/RootLayout.js +10 -15
- package/package.json +10 -10
- package/dist/routing/hooks/useFormNavigationBlocker.d.ts +0 -14
- package/dist/routing/hooks/useFormNavigationBlocker.d.ts.map +0 -1
- package/dist/routing/hooks/useFormNavigationBlocker.js +0 -42
|
@@ -12,9 +12,9 @@ declare const DEGRADED_FORM_STORE_STATE: {
|
|
|
12
12
|
readonly setError: () => void;
|
|
13
13
|
readonly reset: () => void;
|
|
14
14
|
readonly cleanup: () => void;
|
|
15
|
-
readonly setIsDirty: () => void;
|
|
15
|
+
readonly setIsDirty: (_formId: string, _isDirty: boolean) => void;
|
|
16
16
|
readonly hasDirtyForms: () => boolean;
|
|
17
|
-
readonly getDirtyFormIds: () =>
|
|
17
|
+
readonly getDirtyFormIds: () => string[];
|
|
18
18
|
readonly getStatus: () => "idle";
|
|
19
19
|
readonly isLoading: () => boolean;
|
|
20
20
|
readonly getUploadProgress: () => number;
|
|
@@ -44,18 +44,5 @@ export declare function useFormStoreSafe<T>(selector: (state: FormStoreLike) =>
|
|
|
44
44
|
export declare namespace useFormStoreSafe {
|
|
45
45
|
var getState: () => typeof DEGRADED_FORM_STORE_STATE;
|
|
46
46
|
}
|
|
47
|
-
/**
|
|
48
|
-
* Check if any forms are dirty (safe version).
|
|
49
|
-
* Returns false if CRUD package not available.
|
|
50
|
-
*/
|
|
51
|
-
export declare function useHasDirtyFormsSafe(): boolean;
|
|
52
|
-
/**
|
|
53
|
-
* Check if navigation should be blocked (safe version).
|
|
54
|
-
* Returns a function that checks FormStore and shows confirmation if needed.
|
|
55
|
-
*
|
|
56
|
-
* @param message - Confirmation message
|
|
57
|
-
* @returns Promise<boolean> - true if navigation should proceed
|
|
58
|
-
*/
|
|
59
|
-
export declare function checkFormNavigationSafe(message?: string): Promise<boolean>;
|
|
60
47
|
export {};
|
|
61
48
|
//# sourceMappingURL=useFormStoreSafe.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFormStoreSafe.d.ts","sourceRoot":"","sources":["../../src/utils/useFormStoreSafe.ts"],"names":[],"mappings":"AAwBA;;;GAGG;AACH,QAAA,MAAM,yBAAyB
|
|
1
|
+
{"version":3,"file":"useFormStoreSafe.d.ts","sourceRoot":"","sources":["../../src/utils/useFormStoreSafe.ts"],"names":[],"mappings":"AAwBA;;;GAGG;AACH,QAAA,MAAM,yBAAyB;;;;;;;;;;mCAYP,MAAM,YAAY,OAAO;;oCAElB,MAAM,EAAE;;;;;;CAO7B,CAAC;AAEX,sFAAsF;AACtF,KAAK,aAAa,GAAG,OAAO,yBAAyB,CAAC;AAUtD;;GAEG;AACH,eAAO,MAAM,oBAAoB,SAAyC,CAAC;AAE3E;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,CAAC,GAAG,CAAC,CAK5E;yBALe,gBAAgB;wBAaA,OAAO,yBAAyB"}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @see packages/ui/src/utils/useAuthSafe.ts for pattern reference
|
|
13
13
|
* @see docs/development/GRACEFUL_DEGRADATION.md
|
|
14
|
-
* @version 0.0.
|
|
14
|
+
* @version 0.0.2
|
|
15
15
|
* @since 0.0.1
|
|
16
16
|
* @author AMBROISE PARK Consulting
|
|
17
17
|
*/
|
|
@@ -34,8 +34,8 @@ const DEGRADED_FORM_STORE_STATE = {
|
|
|
34
34
|
reset: () => { },
|
|
35
35
|
cleanup: () => { },
|
|
36
36
|
// Dirty state management
|
|
37
|
-
setIsDirty: () => { },
|
|
38
|
-
hasDirtyForms: () => false,
|
|
37
|
+
setIsDirty: (_formId, _isDirty) => { },
|
|
38
|
+
hasDirtyForms: () => false,
|
|
39
39
|
getDirtyFormIds: () => [],
|
|
40
40
|
// Getters
|
|
41
41
|
getStatus: () => 'idle',
|
|
@@ -75,12 +75,6 @@ export function useFormStoreSafe(selector) {
|
|
|
75
75
|
* Use this in non-React contexts or for one-time checks.
|
|
76
76
|
*
|
|
77
77
|
* @returns FormStore state, or degraded state if CRUD not available
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```tsx
|
|
81
|
-
* const state = useFormStoreSafe.getState();
|
|
82
|
-
* const hasDirty = state.hasDirtyForms(); // Always safe to call
|
|
83
|
-
* ```
|
|
84
78
|
*/
|
|
85
79
|
useFormStoreSafe.getState = () => {
|
|
86
80
|
if (realUseFormStore && typeof realUseFormStore.getState === 'function') {
|
|
@@ -88,27 +82,3 @@ useFormStoreSafe.getState = () => {
|
|
|
88
82
|
}
|
|
89
83
|
return DEGRADED_FORM_STORE_STATE;
|
|
90
84
|
};
|
|
91
|
-
/**
|
|
92
|
-
* Check if any forms are dirty (safe version).
|
|
93
|
-
* Returns false if CRUD package not available.
|
|
94
|
-
*/
|
|
95
|
-
export function useHasDirtyFormsSafe() {
|
|
96
|
-
return useFormStoreSafe((state) => state.hasDirtyForms());
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Check if navigation should be blocked (safe version).
|
|
100
|
-
* Returns a function that checks FormStore and shows confirmation if needed.
|
|
101
|
-
*
|
|
102
|
-
* @param message - Confirmation message
|
|
103
|
-
* @returns Promise<boolean> - true if navigation should proceed
|
|
104
|
-
*/
|
|
105
|
-
export async function checkFormNavigationSafe(message = 'You have unsaved changes. Discard them?') {
|
|
106
|
-
const state = useFormStoreSafe.getState();
|
|
107
|
-
const hasDirtyForms = state.hasDirtyForms();
|
|
108
|
-
if (!hasDirtyForms)
|
|
109
|
-
return true; // No dirty forms = allow navigation
|
|
110
|
-
if (typeof window !== 'undefined' && window.confirm) {
|
|
111
|
-
return window.confirm(message);
|
|
112
|
-
}
|
|
113
|
-
return true;
|
|
114
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppRoutes.d.ts","sourceRoot":"","sources":["../../src/vite-routing/AppRoutes.tsx"],"names":[],"mappings":"AAoDA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAM7D,OAAO,KAAK,EAAE,aAAa,EAAuB,MAAM,OAAO,CAAC;AAGhE,yEAAyE;AACzE,KAAK,oBAAoB,
|
|
1
|
+
{"version":3,"file":"AppRoutes.d.ts","sourceRoot":"","sources":["../../src/vite-routing/AppRoutes.tsx"],"names":[],"mappings":"AAoDA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAM7D,OAAO,KAAK,EAAE,aAAa,EAAuB,MAAM,OAAO,CAAC;AAGhE,yEAAyE;AACzE,KAAK,oBAAoB,GACrB,CAAC,MAAM,OAAO,CAAC;IAAE,OAAO,EAAE,aAAa,CAAA;CAAE,CAAC,CAAC,GAC3C,MAAM,CAAC;AA6FX;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;CAChC;AAED,4DAA4D;AAC5D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,oBAAoB,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,UAAU,sBAAsB;IAC9B,4CAA4C;IAC5C,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,yCA8D9D"}
|
|
@@ -81,7 +81,7 @@ function NotFoundPage() {
|
|
|
81
81
|
* <LazyRoute component={route.component} path={route.path} />
|
|
82
82
|
* ```
|
|
83
83
|
*/
|
|
84
|
-
const LazyRoute = ({ component, path }) => {
|
|
84
|
+
const LazyRoute = ({ component, path, }) => {
|
|
85
85
|
if (!lazyComponentCache.has(path)) {
|
|
86
86
|
lazyComponentCache.set(path, lazy(component));
|
|
87
87
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RootLayout.d.ts","sourceRoot":"","sources":["../../src/vite-routing/RootLayout.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"RootLayout.d.ts","sourceRoot":"","sources":["../../src/vite-routing/RootLayout.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAwLnD;;GAEG;AACH,UAAU,oBAAoB;IAC5B,2BAA2B;IAC3B,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,EAAE,oBAAoB,2CAgC1D"}
|
|
@@ -51,21 +51,17 @@ const RedirectOverlay = lazy(() => import('../components/common/RedirectOverlay'
|
|
|
51
51
|
function CustomScrollRestoration() {
|
|
52
52
|
const location = useLocation();
|
|
53
53
|
const scrollPositions = useRef(new Map());
|
|
54
|
-
const
|
|
54
|
+
const prevLocationKey = useRef(null);
|
|
55
55
|
useEffect(() => {
|
|
56
|
-
// Skip on first render (initial page load)
|
|
57
|
-
if (isFirstRender.current) {
|
|
58
|
-
isFirstRender.current = false;
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
56
|
const mainElement = document.querySelector('main[role="main"]');
|
|
62
57
|
if (!mainElement)
|
|
63
58
|
return;
|
|
64
|
-
// Save
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
59
|
+
// Save scroll position of the page we're leaving (Item 89)
|
|
60
|
+
if (prevLocationKey.current) {
|
|
61
|
+
scrollPositions.current.set(prevLocationKey.current, mainElement.scrollTop);
|
|
62
|
+
}
|
|
63
|
+
// Check if this is a back/forward navigation (POP) by checking saved position
|
|
64
|
+
const savedPosition = scrollPositions.current.get(location.key);
|
|
69
65
|
if (savedPosition !== undefined) {
|
|
70
66
|
// POP navigation - restore scroll position
|
|
71
67
|
requestAnimationFrame(() => {
|
|
@@ -75,11 +71,10 @@ function CustomScrollRestoration() {
|
|
|
75
71
|
else {
|
|
76
72
|
// PUSH navigation - scroll to top
|
|
77
73
|
mainElement.scrollTop = 0;
|
|
78
|
-
// Save this position for potential back navigation
|
|
79
|
-
scrollPositions.current.set(currentKey, 0);
|
|
80
74
|
}
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
prevLocationKey.current = location.key;
|
|
76
|
+
// Cleanup: Keep only last 20 positions to prevent memory leaks
|
|
77
|
+
if (scrollPositions.current.size > 20) {
|
|
83
78
|
const firstKey = scrollPositions.current.keys().next().value;
|
|
84
79
|
if (firstKey) {
|
|
85
80
|
scrollPositions.current.delete(firstKey);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@donotdev/ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"scripts": {
|
|
45
45
|
"dev": "tsc --noEmit --watch --listFiles false --listEmittedFiles false",
|
|
46
46
|
"clean": "rimraf dist tsconfig.tsbuildinfo",
|
|
47
|
-
"type-check": "tsc --noEmit"
|
|
47
|
+
"type-check": "bunx tsc --noEmit"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@fontsource/inter": "^5.2.8",
|
|
@@ -56,14 +56,14 @@
|
|
|
56
56
|
"react-hook-form": "^7.71.1"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@donotdev/adv-comps": "^0.0.
|
|
60
|
-
"@donotdev/auth": "^0.0.
|
|
61
|
-
"@donotdev/billing": "^0.0.
|
|
62
|
-
"@donotdev/components": "^0.0.
|
|
63
|
-
"@donotdev/core": "^0.0.
|
|
64
|
-
"@donotdev/crud": "^0.0.
|
|
65
|
-
"@donotdev/firebase": "^0.0.
|
|
66
|
-
"@donotdev/oauth": "^0.0.
|
|
59
|
+
"@donotdev/adv-comps": "^0.0.13",
|
|
60
|
+
"@donotdev/auth": "^0.0.9",
|
|
61
|
+
"@donotdev/billing": "^0.0.8",
|
|
62
|
+
"@donotdev/components": "^0.0.19",
|
|
63
|
+
"@donotdev/core": "^0.0.25",
|
|
64
|
+
"@donotdev/crud": "^0.0.16",
|
|
65
|
+
"@donotdev/firebase": "^0.0.12",
|
|
66
|
+
"@donotdev/oauth": "^0.0.8",
|
|
67
67
|
"firebase": "^12.9.0",
|
|
68
68
|
"lucide-react": "^0.574.0",
|
|
69
69
|
"react": "^19.2.4",
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hook to block React Router navigation when forms are dirty.
|
|
3
|
-
* Uses FormStore as single source of truth.
|
|
4
|
-
* Safe - gracefully degrades if CRUD package not installed.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```tsx
|
|
8
|
-
* // In your app root/layout
|
|
9
|
-
* useFormNavigationBlocker();
|
|
10
|
-
* ```
|
|
11
|
-
*/
|
|
12
|
-
export declare function useFormNavigationBlocker(): void;
|
|
13
|
-
export default useFormNavigationBlocker;
|
|
14
|
-
//# sourceMappingURL=useFormNavigationBlocker.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useFormNavigationBlocker.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useFormNavigationBlocker.ts"],"names":[],"mappings":"AAqBA;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAmB/C;AAED,eAAe,wBAAwB,CAAC"}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
// packages/ui/src/routing/hooks/useFormNavigationBlocker.ts
|
|
3
|
-
/**
|
|
4
|
-
* @fileoverview Form Navigation Blocker Hook
|
|
5
|
-
* @description React Router integration for blocking navigation when forms are dirty.
|
|
6
|
-
* Uses FormStore as single source of truth. Safe - works if CRUD package not installed.
|
|
7
|
-
*
|
|
8
|
-
* @version 0.0.1
|
|
9
|
-
* @since 0.0.1
|
|
10
|
-
* @author AMBROISE PARK Consulting
|
|
11
|
-
*/
|
|
12
|
-
import { useBlocker } from 'react-router-dom';
|
|
13
|
-
import { useEffect } from 'react';
|
|
14
|
-
import { useHasDirtyFormsSafe, checkFormNavigationSafe, } from '../../utils/useFormStoreSafe';
|
|
15
|
-
/**
|
|
16
|
-
* Hook to block React Router navigation when forms are dirty.
|
|
17
|
-
* Uses FormStore as single source of truth.
|
|
18
|
-
* Safe - gracefully degrades if CRUD package not installed.
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* ```tsx
|
|
22
|
-
* // In your app root/layout
|
|
23
|
-
* useFormNavigationBlocker();
|
|
24
|
-
* ```
|
|
25
|
-
*/
|
|
26
|
-
export function useFormNavigationBlocker() {
|
|
27
|
-
const hasDirtyForms = useHasDirtyFormsSafe();
|
|
28
|
-
const blocker = useBlocker(({ currentLocation, nextLocation }) => hasDirtyForms && currentLocation.pathname !== nextLocation.pathname);
|
|
29
|
-
useEffect(() => {
|
|
30
|
-
if (blocker.state === 'blocked') {
|
|
31
|
-
checkFormNavigationSafe().then((proceed) => {
|
|
32
|
-
if (proceed) {
|
|
33
|
-
blocker.proceed();
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
blocker.reset();
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
}, [blocker]);
|
|
41
|
-
}
|
|
42
|
-
export default useFormNavigationBlocker;
|