@donotdev/ui 0.0.9 → 0.0.10

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 (45) hide show
  1. package/dist/crud/components/fields/display/DateFieldDisplay.d.ts.map +1 -1
  2. package/dist/crud/components/fields/display/DateFieldDisplay.js +2 -3
  3. package/dist/crud/components/fields/display/LinkFieldDisplay.d.ts.map +1 -1
  4. package/dist/crud/components/fields/display/LinkFieldDisplay.js +6 -5
  5. package/dist/crud/components/fields/display/NumberFieldDisplay.d.ts.map +1 -1
  6. package/dist/crud/components/fields/display/NumberFieldDisplay.js +2 -3
  7. package/dist/crud/components/fields/display/PhoneNumberDisplay.d.ts.map +1 -1
  8. package/dist/crud/components/fields/display/PhoneNumberDisplay.js +1 -2
  9. package/dist/dndev.css +288 -143
  10. package/dist/index.js +5 -5
  11. package/dist/internal/common/RouteErrorFallback.d.ts.map +1 -1
  12. package/dist/internal/common/RouteErrorFallback.js +1 -2
  13. package/dist/internal/layout/DnDevLayout.d.ts.map +1 -1
  14. package/dist/internal/layout/DnDevLayout.js +3 -2
  15. package/dist/internal/layout/components/footer/FooterBranding.d.ts +0 -2
  16. package/dist/internal/layout/components/footer/FooterBranding.d.ts.map +1 -1
  17. package/dist/internal/layout/components/footer/FooterBranding.js +2 -6
  18. package/dist/internal/layout/components/footer/FooterCopyright.d.ts +0 -2
  19. package/dist/internal/layout/components/footer/FooterCopyright.d.ts.map +1 -1
  20. package/dist/internal/layout/components/footer/FooterCopyright.js +2 -6
  21. package/dist/internal/layout/config/presets/moolti.js +2 -2
  22. package/dist/internal/layout/zones/DnDevFooter.d.ts.map +1 -1
  23. package/dist/internal/layout/zones/DnDevFooter.js +2 -2
  24. package/dist/routing/GoTo.d.ts +1 -1
  25. package/dist/routing/GoTo.d.ts.map +1 -1
  26. package/dist/routing/GoTo.js +1 -1
  27. package/dist/routing/hooks/hooks.next.js +1 -1
  28. package/dist/routing/hooks/hooks.vite.js +1 -1
  29. package/dist/routing/hooks/useFormNavigationBlocker.d.ts +14 -0
  30. package/dist/routing/hooks/useFormNavigationBlocker.d.ts.map +1 -0
  31. package/dist/routing/hooks/useFormNavigationBlocker.js +42 -0
  32. package/dist/routing/hooks/useNavigate.next.d.ts +1 -1
  33. package/dist/routing/hooks/useNavigate.next.d.ts.map +1 -1
  34. package/dist/routing/hooks/useNavigate.next.js +7 -1
  35. package/dist/routing/hooks/useNavigate.vite.d.ts +1 -1
  36. package/dist/routing/hooks/useNavigate.vite.d.ts.map +1 -1
  37. package/dist/routing/hooks/useNavigate.vite.js +7 -1
  38. package/dist/styles/index.css +288 -143
  39. package/dist/utils/index.d.ts +1 -0
  40. package/dist/utils/index.d.ts.map +1 -1
  41. package/dist/utils/index.js +1 -0
  42. package/dist/utils/useFormStoreSafe.d.ts +59 -0
  43. package/dist/utils/useFormStoreSafe.d.ts.map +1 -0
  44. package/dist/utils/useFormStoreSafe.js +115 -0
  45. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"RouteErrorFallback.d.ts","sourceRoot":"","sources":["../../../src/internal/common/RouteErrorFallback.tsx"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,UAAU,uBAAuB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,aAAa,CAAC,uBAAuB,CAqPrE,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"RouteErrorFallback.d.ts","sourceRoot":"","sources":["../../../src/internal/common/RouteErrorFallback.tsx"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,UAAU,uBAAuB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,aAAa,CAAC,uBAAuB,CAyPrE,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -14,7 +14,6 @@ import { useEffect, useState } from 'react';
14
14
  import { Button, BUTTON_VARIANT, Card, CARD_VARIANT, Alert, ALERT_VARIANT, Stack, } from '@donotdev/components';
15
15
  import { handleError, useTranslation } from '@donotdev/core';
16
16
  import { useLocation, useBack } from '@donotdev/ui/routing/hooks';
17
- import { PageContainer } from '../../components/layout/PageContainer';
18
17
  // Platform-specific hooks via conditional exports
19
18
  import { Link } from '../../routing/Link';
20
19
  /**
@@ -95,7 +94,7 @@ export const RouteErrorFallback = ({ error, resetError, componentStack, eventId,
95
94
  }
96
95
  }
97
96
  };
98
- return (_jsx(PageContainer, { children: _jsx(Card, { variant: CARD_VARIANT.DEFAULT, elevated: true, className: "dndev-w-full", style: { maxWidth: '65ch', margin: '0 auto' }, children: _jsxs(Stack, { gap: "large", align: "center", className: "dndev-text-center", children: [_jsx(Stack, { align: "center", justify: "center", style: {
97
+ return (_jsx("div", { className: "dndev-container", "data-variant": "standard", "data-centered": "true", children: _jsx(Card, { variant: CARD_VARIANT.DEFAULT, elevated: true, className: "dndev-w-full", style: { maxWidth: '65ch', margin: '0 auto' }, children: _jsxs(Stack, { gap: "large", align: "center", className: "dndev-text-center", children: [_jsx(Stack, { align: "center", justify: "center", style: {
99
98
  width: '5rem',
100
99
  height: '5rem',
101
100
  backgroundColor: 'rgba(220, 38, 38, 0.1)',
@@ -1 +1 @@
1
- {"version":3,"file":"DnDevLayout.d.ts","sourceRoot":"","sources":["../../../src/internal/layout/DnDevLayout.tsx"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAIV,YAAY,EACb,MAAM,gBAAgB,CAAC;AA0CxB,UAAU,yBAAyB;IACjC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW,GAAI,kCAIzB,yBAAyB,4CA2T3B,CAAC"}
1
+ {"version":3,"file":"DnDevLayout.d.ts","sourceRoot":"","sources":["../../../src/internal/layout/DnDevLayout.tsx"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAIV,YAAY,EACb,MAAM,gBAAgB,CAAC;AA0CxB,UAAU,yBAAyB;IACjC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW,GAAI,kCAIzB,yBAAyB,4CAwT3B,CAAC"}
@@ -66,8 +66,9 @@ export const DnDevLayout = ({ children, layout, className, }) => {
66
66
  const app = useAppConfig('app');
67
67
  // Subscribe to language changes for zone re-renders
68
68
  useTranslation('dndev');
69
- // Breadcrumbs from layout prop only
69
+ // Layout config props
70
70
  const breadcrumbs = layout?.breadcrumbs ?? 'smart';
71
+ const footerMode = layout?.footerMode;
71
72
  // Route detection for animations
72
73
  const location = useLocation();
73
74
  const pathname = location.pathname;
@@ -246,5 +247,5 @@ export const DnDevLayout = ({ children, layout, className, }) => {
246
247
  };
247
248
  startTransition(updateDOM);
248
249
  }, [effectivePreset]);
249
- return (_jsxs("div", { className: cn('dndev-layout', className), children: [resolvedHeader, resolvedSidebar, _jsxs("main", { ref: mainRef, role: "main", className: "main", children: [breadcrumbs !== 'never' && (_jsx("div", { className: "breadcrumbs-container", children: _jsx(Breadcrumbs, { variant: breadcrumbs === 'always' ? 'default' : 'smart' }) })), isDev() && (_jsx(Suspense, { fallback: null, children: _jsx(DebugTools, {}) })), _jsx(Stack, { flex: "1", className: "dndev-min-h-0", children: content }, pathname), resolvedFooter && (_jsx("div", { className: "footer-mobile", children: resolvedFooter }))] }), resolvedFooter && _jsx("div", { className: "footer-desktop", children: resolvedFooter }), resolvedMergedBar, _jsx(GoToWrapper, {})] }));
250
+ return (_jsxs("div", { className: cn('dndev-layout', className), "data-footer-mode": footerMode, children: [resolvedHeader, resolvedSidebar, _jsxs("main", { ref: mainRef, role: "main", className: "main", children: [breadcrumbs !== 'never' && (_jsx("div", { className: "breadcrumbs-container", children: _jsx(Breadcrumbs, { variant: breadcrumbs === 'always' ? 'default' : 'smart' }) })), isDev() && (_jsx(Suspense, { fallback: null, children: _jsx(DebugTools, {}) })), content] }), resolvedFooter, resolvedMergedBar, _jsx(GoToWrapper, {})] }));
250
251
  };
@@ -1,8 +1,6 @@
1
1
  export interface FooterBrandingProps {
2
2
  /** Additional CSS classes */
3
3
  className?: string;
4
- /** Text size */
5
- size?: 'xs' | 'sm';
6
4
  }
7
5
  /**
8
6
  * FooterBranding - Framework branding link (power move)
@@ -1 +1 @@
1
- {"version":3,"file":"FooterBranding.d.ts","sourceRoot":"","sources":["../../../../../src/internal/layout/components/footer/FooterBranding.tsx"],"names":[],"mappings":"AAeA,MAAM,WAAW,mBAAmB;IAClC,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,gBAAgB;IAChB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAoCnE,CAAC;AAEF,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"FooterBranding.d.ts","sourceRoot":"","sources":["../../../../../src/internal/layout/components/footer/FooterBranding.tsx"],"names":[],"mappings":"AAeA,MAAM,WAAW,mBAAmB;IAClC,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,aAAa,CAAC,mBAAmB,CA8BnE,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -20,20 +20,16 @@ import { useAppConfig } from '@donotdev/core';
20
20
  * @since 0.0.1
21
21
  * @author AMBROISE PARK Consulting
22
22
  */
23
- export const FooterBranding = ({ className, size = 'sm', }) => {
23
+ export const FooterBranding = ({ className, }) => {
24
24
  const appUrl = useAppConfig('url');
25
25
  const isFrameworkSite = appUrl === 'https://donotdev.com';
26
- const sizeStyles = {
27
- xs: { fontSize: 'var(--font-size-xs)' },
28
- sm: { fontSize: 'var(--font-size-sm)' },
29
- };
30
26
  return (_jsxs("a", { href: isFrameworkSite
31
27
  ? 'https://www.ambroise-park.com'
32
28
  : 'https://donotdev.com', target: "_blank", rel: "noopener noreferrer", className: className, style: {
33
29
  display: 'inline-flex',
34
30
  alignItems: 'center',
35
31
  gap: 'var(--gap-sm)',
36
- ...sizeStyles[size],
32
+ fontSize: 'var(--font-size-xs)',
37
33
  }, children: [isFrameworkSite ? 'AMBROISE-PARK' : 'DoNotDev', _jsx(ExternalLink, { style: { width: '12px', height: '12px' }, "aria-hidden": "true" })] }));
38
34
  };
39
35
  export default FooterBranding;
@@ -5,8 +5,6 @@ export interface FooterCopyrightProps {
5
5
  year?: number;
6
6
  /** Additional CSS classes */
7
7
  className?: string;
8
- /** Text size */
9
- size?: 'xs' | 'sm';
10
8
  }
11
9
  /**
12
10
  * FooterCopyright - Copyright notice component
@@ -1 +1 @@
1
- {"version":3,"file":"FooterCopyright.d.ts","sourceRoot":"","sources":["../../../../../src/internal/layout/components/footer/FooterCopyright.tsx"],"names":[],"mappings":"AAcA,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,gBAAgB;IAChB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,aAAa,CAAC,oBAAoB,CA2BrE,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"FooterCopyright.d.ts","sourceRoot":"","sources":["../../../../../src/internal/layout/components/footer/FooterCopyright.tsx"],"names":[],"mappings":"AAcA,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,aAAa,CAAC,oBAAoB,CAqBrE,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -20,18 +20,14 @@ import { useTranslation, useAppConfig } from '@donotdev/core';
20
20
  * @since 0.0.1
21
21
  * @author AMBROISE PARK Consulting
22
22
  */
23
- export const FooterCopyright = ({ appName, year = new Date().getFullYear(), className, size = 'xs', }) => {
23
+ export const FooterCopyright = ({ appName, year = new Date().getFullYear(), className, }) => {
24
24
  const { t } = useTranslation('dndev');
25
25
  const app = useAppConfig('app');
26
26
  const resolvedAppName = appName || app?.name || 'App';
27
- const sizeStyles = {
28
- xs: { fontSize: 'var(--font-size-xs)' },
29
- sm: { fontSize: 'var(--font-size-sm)' },
30
- };
31
27
  return (_jsxs("span", { className: cn(className), style: {
32
28
  flexShrink: 0,
33
29
  color: 'var(--muted-foreground)',
34
- ...sizeStyles[size],
30
+ fontSize: 'var(--font-size-xs)',
35
31
  }, children: ["\u00A9 ", year, " ", resolvedAppName, ". ", t('footer.legal.allRightsReserved')] }));
36
32
  };
37
33
  export default FooterCopyright;
@@ -32,7 +32,7 @@ export const mooltiPreset = {
32
32
  sidebar: {
33
33
  top: () => _jsx(AppBranding, { display: DISPLAY.AUTO }),
34
34
  content: () => (_jsxs(_Fragment, { children: [_jsx(GoTo, { display: DISPLAY.AUTO }), _jsx(DnDevNavigationMenu, { vertical: true, display: DISPLAY.AUTO })] })),
35
- bottom: () => (_jsxs(Stack, { direction: "column", gap: "tight", align: "stretch", children: [_jsx(AuthHeader, { display: DISPLAY.AUTO }), _jsx(LanguageSelector, { display: DISPLAY.AUTO }), _jsx(ThemeToggle, { display: DISPLAY.AUTO }), _jsx(FooterCopyright, { size: "xs" })] })),
35
+ bottom: () => (_jsxs(Stack, { direction: "column", gap: "tight", align: "stretch", children: [_jsx(AuthHeader, { display: DISPLAY.AUTO }), _jsx(LanguageSelector, { display: DISPLAY.AUTO }), _jsx(ThemeToggle, { display: DISPLAY.AUTO }), _jsx(FooterCopyright, {})] })),
36
36
  defaultWidth: 256,
37
37
  minWidth: 48,
38
38
  maxWidth: 400,
@@ -48,7 +48,7 @@ export const mooltiPreset = {
48
48
  _jsxs(_Fragment, { children: [_jsx(GoTo, { display: DISPLAY.AUTO }), _jsx(DnDevNavigationMenu, { vertical: true, display: DISPLAY.AUTO })] })),
49
49
  bottom: () => (
50
50
  // sidebar.bottom → bottom (Auth, Language, Theme, Footer)
51
- _jsxs(Stack, { direction: "column", gap: "tight", align: "stretch", children: [_jsx(AuthHeader, { display: DISPLAY.AUTO }), _jsx(LanguageSelector, { display: DISPLAY.AUTO }), _jsx(ThemeToggle, { display: DISPLAY.AUTO }), _jsx(FooterCopyright, { size: "xs" })] })),
51
+ _jsxs(Stack, { direction: "column", gap: "tight", align: "stretch", children: [_jsx(AuthHeader, { display: DISPLAY.AUTO }), _jsx(LanguageSelector, { display: DISPLAY.AUTO }), _jsx(ThemeToggle, { display: DISPLAY.AUTO }), _jsx(FooterCopyright, {})] })),
52
52
  },
53
53
  },
54
54
  };
@@ -1 +1 @@
1
- {"version":3,"file":"DnDevFooter.d.ts","sourceRoot":"","sources":["../../../../src/internal/layout/zones/DnDevFooter.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAUlD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,MAAM,WAAW,gBAAgB;IAC/B,uCAAuC;IACvC,GAAG,CAAC,EAAE,WAAW,CAAC;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,iBAAS,oBAAoB,CAAC,EAAE,GAAQ,EAAE,EAAE,gBAAgB,GAAG,SAAS,CAsEvE;AAED,eAAO,MAAM,WAAW,kEAA6B,CAAC"}
1
+ {"version":3,"file":"DnDevFooter.d.ts","sourceRoot":"","sources":["../../../../src/internal/layout/zones/DnDevFooter.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAUlD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,MAAM,WAAW,gBAAgB;IAC/B,uCAAuC;IACvC,GAAG,CAAC,EAAE,WAAW,CAAC;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,iBAAS,oBAAoB,CAAC,EAAE,GAAQ,EAAE,EAAE,gBAAgB,GAAG,SAAS,CA8EvE;AAED,eAAO,MAAM,WAAW,kEAA6B,CAAC"}
@@ -49,9 +49,9 @@ function DnDevFooterComponent({ app = {} }) {
49
49
  : copyrightConfig;
50
50
  // Desktop/Wide: 2-zone layout [Copyright] | [Links + DoNotDev]
51
51
  if (isLaptopOrDesktop) {
52
- return (_jsx("footer", { role: "contentinfo", className: "footer", children: _jsxs(Stack, { direction: "row", align: "center", justify: "between", gap: "none", children: [showCopyright && (_jsx("div", { className: "dndev-flex dndev-justify-start", children: _jsx("span", { className: "footer-copyright", children: copyrightText }) })), _jsx("div", { className: "dndev-flex dndev-justify-end", children: _jsxs(Stack, { direction: "row", gap: "medium", align: "center", children: [links.map((link) => (_jsx(Link, { path: link.path, children: maybeTranslate(t, link.label) }, link.path))), _jsx(FooterBranding, {})] }) })] }) }));
52
+ return (_jsx("footer", { role: "contentinfo", className: "footer", children: _jsxs(Stack, { direction: "row", align: "center", justify: "between", gap: "none", children: [showCopyright && (_jsx("div", { className: "dndev-flex dndev-justify-start", children: _jsx("span", { className: "footer-copyright", children: copyrightText }) })), _jsx("div", { className: "dndev-flex dndev-justify-end", children: _jsxs(Stack, { direction: "row", gap: "medium", align: "center", children: [links.map((link) => (_jsx(Link, { path: link.path, style: { fontSize: 'var(--font-size-xs)' }, children: maybeTranslate(t, link.label) }, link.path))), _jsx(FooterBranding, {})] }) })] }) }));
53
53
  }
54
54
  // Mobile/Tablet: stacked layout
55
- return (_jsx("footer", { role: "contentinfo", className: "footer", children: _jsxs(Stack, { align: "center", gap: "tight", children: [showCopyright && (_jsx("span", { className: "footer-copyright", children: copyrightText })), _jsxs(Stack, { direction: "row", wrap: "wrap", gap: "tight", justify: "center", align: "center", children: [links.map((link) => (_jsx(Link, { path: link.path, children: maybeTranslate(t, link.label) }, link.path))), _jsx(FooterBranding, {})] })] }) }));
55
+ return (_jsx("footer", { role: "contentinfo", className: "footer", children: _jsxs(Stack, { align: "center", gap: "tight", children: [showCopyright && (_jsx("span", { className: "footer-copyright", children: copyrightText })), _jsxs(Stack, { direction: "row", wrap: "wrap", gap: "tight", justify: "center", align: "center", children: [links.map((link) => (_jsx(Link, { path: link.path, style: { fontSize: 'var(--font-size-xs)' }, children: maybeTranslate(t, link.label) }, link.path))), _jsx(FooterBranding, {})] })] }) }));
56
56
  }
57
57
  export const DnDevFooter = memo(DnDevFooterComponent);
@@ -16,6 +16,6 @@ export interface GoToProps {
16
16
  * Simple button: Search icon + "Go to" label + keyboard shortcut.
17
17
  * Opens command dialog on click.
18
18
  */
19
- export declare const GoTo: ({ display, className, onOpen }: GoToProps) => import("react/jsx-runtime").JSX.Element;
19
+ export declare const GoTo: ({ display, className, onOpen, }: GoToProps) => import("react/jsx-runtime").JSX.Element;
20
20
  export default GoTo;
21
21
  //# sourceMappingURL=GoTo.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GoTo.d.ts","sourceRoot":"","sources":["../../src/routing/GoTo.tsx"],"names":[],"mappings":"AAaA,OAAO,EAA0B,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAGvE,MAAM,WAAW,SAAS;IACxB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;IACjD,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6FAA6F;IAC7F,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;GAKG;AACH,eAAO,MAAM,IAAI,GAAI,gCAA+C,SAAS,4CAsC5E,CAAC;AAEF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"GoTo.d.ts","sourceRoot":"","sources":["../../src/routing/GoTo.tsx"],"names":[],"mappings":"AAaA,OAAO,EAA0B,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAGvE,MAAM,WAAW,SAAS;IACxB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;IACjD,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6FAA6F;IAC7F,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;GAKG;AACH,eAAO,MAAM,IAAI,GAAI,iCAIlB,SAAS,4CAsCX,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -17,7 +17,7 @@ import { useOverlayStore, useTranslation } from '@donotdev/core';
17
17
  * Simple button: Search icon + "Go to" label + keyboard shortcut.
18
18
  * Opens command dialog on click.
19
19
  */
20
- export const GoTo = ({ display = DISPLAY.AUTO, className, onOpen }) => {
20
+ export const GoTo = ({ display = DISPLAY.AUTO, className, onOpen, }) => {
21
21
  const { t } = useTranslation('dndev');
22
22
  const openCommandDialog = useOverlayStore((state) => state.openCommandDialog);
23
23
  // Platform-aware shortcut (Mac: ⌘K, others: Ctrl+K)
@@ -1 +1 @@
1
- "use client";import{useRouter as f}from"next/navigation";import{useCallback as h}from"react";import{isClient as S,useOverlayStore as y}from"@donotdev/core";function d(){let e=f(),t=y(r=>r.closeAll);return h((r,i)=>{if(r==="back")return t(),e.back();if(t(),i?.preserveScroll&&S()){let o=window.scrollY;i?.replace?e.replace(r):e.push(r),requestAnimationFrame(()=>{window.scrollTo({top:o,behavior:"auto"})});return}return i?.replace?e.replace(r):e.push(r)},[e,t])}function k(){let e=f();return h(()=>e.back(),[e])}function v(){let e=f();return h(()=>e.refresh(),[e])}function T(){let e=f();return h(t=>e.prefetch(t),[e])}import{usePathname as b,useSearchParams as w}from"next/navigation";function l(){let e=b(),t=w(),r=t.toString()?`?${t.toString()}`:"";return{pathname:e||"/",search:r,hash:"",state:null}}import{useParams as C}from"next/navigation";function g(){return C()}function I(e){let r=g()[e];if(typeof r=="string")return r;if(Array.isArray(r)&&r.length>0)return r[0]}import{useSearchParams as N}from"next/navigation";function R(){return N()}import{usePathname as G}from"next/navigation";function $(e){let t=G(),r=e.replace(/:[^/]+/g,"([^/]+)").replace(/\*/g,".*"),i=new RegExp(`^${r}$`),o=t.match(i);if(!o)return null;let s=e.match(/:[^/]+/g)?.map(a=>a.slice(1))||[],n={};return s.forEach((a,c)=>{n[a]=o[c+1]||""}),{params:n,pathname:t,pattern:e}}import{useCallback as P}from"react";function K(){let e=R(),t=d(),r=l(),i=P((n,a)=>{let c=new URLSearchParams(e.toString());c.set(n,a);let m=c.toString(),A=`${r.pathname||"/"}${m?`?${m}`:""}`;t(A)},[e,t,r.pathname]),o=P(n=>{let a=new URLSearchParams(e.toString());a.delete(n);let c=a.toString(),u=`${r.pathname||"/"}${c?`?${c}`:""}`;t(u)},[e,t,r.pathname]),s=P(()=>{let n=r.pathname||"/";t(n)},[t,r.pathname]);return{query:e,setQuery:i,removeQuery:o,clearQueries:s}}import{useMemo as E}from"react";import{isClient as Q,FEATURE_STATUS as F}from"@donotdev/core";import{useAuthConfig as M}from"@donotdev/core";import*as O from"@donotdev/auth";import{DEGRADED_AUTH_API as U}from"@donotdev/core";var x=O?.useAuth;function L(e){return U[e]}function p(e){return x?x(e):L(e)}function j(e={}){let{auth:t,redirectTo:r,condition:i}=e;if(!Q())return{shouldRedirect:!1,redirectTo:null,isChecking:!1};let o=l(),s=M(),n=p("user"),a=p("can"),c=p("status");return E(()=>{if(c===F.INITIALIZING)return{shouldRedirect:!1,redirectTo:null,isChecking:!0};if(i){let u=i(n,c);return{shouldRedirect:u,redirectTo:u&&r||null,isChecking:!1}}if(t!==!1&&t!==void 0){if(!a)return{shouldRedirect:!1,redirectTo:null,isChecking:!1};if(!a.navigate(t)){let u=null;return typeof t=="object"&&t.required&&!n?o.search.includes("code=")||o.search.includes("state=")||o.search.includes("error=")?u=`${s.authRoute}${o.search}`:u=s.authRoute:typeof t=="object"&&t.role?u=s.roleRoute:typeof t=="object"&&t.tier?u=s.tierRoute:u=s.roleRoute,{shouldRedirect:!0,redirectTo:r||u,isChecking:!1}}}return{shouldRedirect:!1,redirectTo:null,isChecking:!1}},[t,c,n,a,i,r,o.search,s.authRoute,s.roleRoute,s.tierRoute])}export{k as useBack,l as useLocation,$ as useMatch,d as useNavigate,g as useParams,T as usePrefetch,K as useQueryParams,j as useRedirectGuard,v as useRefresh,I as useRouteParam,R as useSearchParams};
1
+ "use client";import{useRouter as h}from"next/navigation";import{useCallback as p}from"react";import{isClient as F,useOverlayStore as w}from"@donotdev/core";import*as D from"@donotdev/crud";var m=D?.useFormStore,A={forms:{},startSubmit:()=>{},setUploading:()=>{},setValidating:()=>{},setSubmitting:()=>{},setSuccess:()=>{},setError:()=>{},reset:()=>{},cleanup:()=>{},setIsDirty:()=>{},hasDirtyForms:()=>!1,getDirtyFormIds:()=>[],getStatus:()=>"idle",isLoading:()=>!1,getUploadProgress:()=>0,getError:()=>null,getIsDirty:()=>!1};function x(e){return m?m(e):e(A)}x.getState=()=>m&&typeof m.getState=="function"?m.getState():A;async function T(e="You have unsaved changes. Discard them?"){return x.getState().hasDirtyForms()&&typeof window<"u"&&window.confirm?window.confirm(e):!0}function g(){let e=h(),t=w(r=>r.closeAll);return p(async(r,u)=>{if(r==="back")return t(),e.back();if(await T()){if(t(),u?.preserveScroll&&F()){let o=window.scrollY;u?.replace?e.replace(r):e.push(r),requestAnimationFrame(()=>{window.scrollTo({top:o,behavior:"auto"})});return}return u?.replace?e.replace(r):e.push(r)}},[e,t])}function b(){let e=h();return p(()=>e.back(),[e])}function k(){let e=h();return p(()=>e.refresh(),[e])}function E(){let e=h();return p(t=>e.prefetch(t),[e])}import{usePathname as I,useSearchParams as N}from"next/navigation";function f(){let e=I(),t=N(),r=t.toString()?`?${t.toString()}`:"";return{pathname:e||"/",search:r,hash:"",state:null}}import{useParams as C}from"next/navigation";function R(){return C()}function G(e){let r=R()[e];if(typeof r=="string")return r;if(Array.isArray(r)&&r.length>0)return r[0]}import{useSearchParams as O}from"next/navigation";function S(){return O()}import{usePathname as U}from"next/navigation";function $(e){let t=U(),r=e.replace(/:[^/]+/g,"([^/]+)").replace(/\*/g,".*"),u=new RegExp(`^${r}$`),i=t.match(u);if(!i)return null;let o=e.match(/:[^/]+/g)?.map(n=>n.slice(1))||[],s={};return o.forEach((n,c)=>{s[n]=i[c+1]||""}),{params:s,pathname:t,pattern:e}}import{useCallback as y}from"react";function K(){let e=S(),t=g(),r=f(),u=y((s,n)=>{let c=new URLSearchParams(e.toString());c.set(s,n);let l=c.toString(),P=`${r.pathname||"/"}${l?`?${l}`:""}`;t(P)},[e,t,r.pathname]),i=y(s=>{let n=new URLSearchParams(e.toString());n.delete(s);let c=n.toString(),a=`${r.pathname||"/"}${c?`?${c}`:""}`;t(a)},[e,t,r.pathname]),o=y(()=>{let s=r.pathname||"/";t(s)},[t,r.pathname]);return{query:e,setQuery:u,removeQuery:i,clearQueries:o}}import{useMemo as Q}from"react";import{isClient as j,FEATURE_STATUS as q}from"@donotdev/core";import{useAuthConfig as Y}from"@donotdev/core";import*as _ from"@donotdev/auth";import{DEGRADED_AUTH_API as L}from"@donotdev/core";var v=_?.useAuth;function M(e){return L[e]}function d(e){return v?v(e):M(e)}function B(e={}){let{auth:t,redirectTo:r,condition:u}=e;if(!j())return{shouldRedirect:!1,redirectTo:null,isChecking:!1};let i=f(),o=Y(),s=d("user"),n=d("can"),c=d("status");return Q(()=>{if(c===q.INITIALIZING)return{shouldRedirect:!1,redirectTo:null,isChecking:!0};if(u){let a=u(s,c);return{shouldRedirect:a,redirectTo:a&&r||null,isChecking:!1}}if(t!==!1&&t!==void 0){if(!n)return{shouldRedirect:!1,redirectTo:null,isChecking:!1};if(!n.navigate(t)){let a=null;return typeof t=="object"&&t.required&&!s?i.search.includes("code=")||i.search.includes("state=")||i.search.includes("error=")?a=`${o.authRoute}${i.search}`:a=o.authRoute:typeof t=="object"&&t.role?a=o.roleRoute:typeof t=="object"&&t.tier?a=o.tierRoute:a=o.roleRoute,{shouldRedirect:!0,redirectTo:r||a,isChecking:!1}}}return{shouldRedirect:!1,redirectTo:null,isChecking:!1}},[t,c,s,n,u,r,i.search,o.authRoute,o.roleRoute,o.tierRoute])}export{b as useBack,f as useLocation,$ as useMatch,g as useNavigate,R as useParams,E as usePrefetch,K as useQueryParams,B as useRedirectGuard,k as useRefresh,G as useRouteParam,S as useSearchParams};
@@ -1 +1 @@
1
- "use client";import{useCallback as m}from"react";import{useNavigate as P}from"react-router-dom";import{isClient as y,useOverlayStore as S}from"@donotdev/core";function h(){let e=P(),t=S(r=>r.closeAll);return m((r,i)=>r==="back"?(t(),e(-1)):(t(),i?.replace?e(r,{replace:!0}):e(r)),[e,t])}function v(){let e=P();return m(()=>e(-1),[e])}function k(){return m(()=>{y()&&window.location.reload()},[])}function T(){return m(e=>{},[])}import{useLocation as C}from"react-router-dom";function f(){return C()}import{useParams as I}from"react-router-dom";function d(){return I()}function b(e){let r=d()[e];if(typeof r=="string")return r;if(Array.isArray(r)&&r.length>0)return r[0]}import{useSearchParams as G}from"react-router-dom";function g(){return G()[0]}import{useMatch as w}from"react-router-dom";function N(e){return w(e)}import{useCallback as R}from"react";function K(){let e=g(),t=h(),r=f(),i=R((n,u)=>{let a=new URLSearchParams(e.toString());a.set(n,u);let l=a.toString(),A=`${r.pathname||"/"}${l?`?${l}`:""}`;t(A)},[e,t,r.pathname]),c=R(n=>{let u=new URLSearchParams(e.toString());u.delete(n);let a=u.toString(),o=`${r.pathname||"/"}${a?`?${a}`:""}`;t(o)},[e,t,r.pathname]),s=R(()=>{let n=r.pathname||"/";t(n)},[t,r.pathname]);return{query:e,setQuery:i,removeQuery:c,clearQueries:s}}import{useMemo as $}from"react";import{isClient as M,FEATURE_STATUS as Q}from"@donotdev/core";import{useAuthConfig as E}from"@donotdev/core";import*as L from"@donotdev/auth";import{DEGRADED_AUTH_API as O}from"@donotdev/core";var x=L?.useAuth;function U(e){return O[e]}function p(e){return x?x(e):U(e)}function _(e={}){let{auth:t,redirectTo:r,condition:i}=e;if(!M())return{shouldRedirect:!1,redirectTo:null,isChecking:!1};let c=f(),s=E(),n=p("user"),u=p("can"),a=p("status");return $(()=>{if(a===Q.INITIALIZING)return{shouldRedirect:!1,redirectTo:null,isChecking:!0};if(i){let o=i(n,a);return{shouldRedirect:o,redirectTo:o&&r||null,isChecking:!1}}if(t!==!1&&t!==void 0){if(!u)return{shouldRedirect:!1,redirectTo:null,isChecking:!1};if(!u.navigate(t)){let o=null;return typeof t=="object"&&t.required&&!n?c.search.includes("code=")||c.search.includes("state=")||c.search.includes("error=")?o=`${s.authRoute}${c.search}`:o=s.authRoute:typeof t=="object"&&t.role?o=s.roleRoute:typeof t=="object"&&t.tier?o=s.tierRoute:o=s.roleRoute,{shouldRedirect:!0,redirectTo:r||o,isChecking:!1}}}return{shouldRedirect:!1,redirectTo:null,isChecking:!1}},[t,a,n,u,i,r,c.search,s.authRoute,s.roleRoute,s.tierRoute])}export{v as useBack,f as useLocation,N as useMatch,h as useNavigate,d as useParams,T as usePrefetch,K as useQueryParams,_ as useRedirectGuard,k as useRefresh,b as useRouteParam,g as useSearchParams};
1
+ "use client";import{useCallback as d}from"react";import{useNavigate as T}from"react-router-dom";import{isClient as F,useOverlayStore as k}from"@donotdev/core";import*as D from"@donotdev/crud";var f=D?.useFormStore,A={forms:{},startSubmit:()=>{},setUploading:()=>{},setValidating:()=>{},setSubmitting:()=>{},setSuccess:()=>{},setError:()=>{},reset:()=>{},cleanup:()=>{},setIsDirty:()=>{},hasDirtyForms:()=>!1,getDirtyFormIds:()=>[],getStatus:()=>"idle",isLoading:()=>!1,getUploadProgress:()=>0,getError:()=>null,getIsDirty:()=>!1};function P(e){return f?f(e):e(A)}P.getState=()=>f&&typeof f.getState=="function"?f.getState():A;async function x(e="You have unsaved changes. Discard them?"){return P.getState().hasDirtyForms()&&typeof window<"u"&&window.confirm?window.confirm(e):!0}function h(){let e=T(),t=k(r=>r.closeAll);return d(async(r,c)=>{if(r==="back")return t(),e(-1);if(await x())return t(),c?.replace?e(r,{replace:!0}):e(r)},[e,t])}function w(){let e=T();return d(()=>e(-1),[e])}function b(){return d(()=>{F()&&window.location.reload()},[])}function I(){return d(e=>{},[])}import{useLocation as E}from"react-router-dom";function m(){return E()}import{useParams as C}from"react-router-dom";function g(){return C()}function G(e){let r=g()[e];if(typeof r=="string")return r;if(Array.isArray(r)&&r.length>0)return r[0]}import{useSearchParams as O}from"react-router-dom";function R(){return O()[0]}import{useMatch as N}from"react-router-dom";function U(e){return N(e)}import{useCallback as y}from"react";function L(){let e=R(),t=h(),r=m(),c=y((n,i)=>{let a=new URLSearchParams(e.toString());a.set(n,i);let l=a.toString(),S=`${r.pathname||"/"}${l?`?${l}`:""}`;t(S)},[e,t,r.pathname]),u=y(n=>{let i=new URLSearchParams(e.toString());i.delete(n);let a=i.toString(),o=`${r.pathname||"/"}${a?`?${a}`:""}`;t(o)},[e,t,r.pathname]),s=y(()=>{let n=r.pathname||"/";t(n)},[t,r.pathname]);return{query:e,setQuery:c,removeQuery:u,clearQueries:s}}import{useMemo as $}from"react";import{isClient as Q,FEATURE_STATUS as j}from"@donotdev/core";import{useAuthConfig as q}from"@donotdev/core";import*as _ from"@donotdev/auth";import{DEGRADED_AUTH_API as K}from"@donotdev/core";var v=_?.useAuth;function M(e){return K[e]}function p(e){return v?v(e):M(e)}function B(e={}){let{auth:t,redirectTo:r,condition:c}=e;if(!Q())return{shouldRedirect:!1,redirectTo:null,isChecking:!1};let u=m(),s=q(),n=p("user"),i=p("can"),a=p("status");return $(()=>{if(a===j.INITIALIZING)return{shouldRedirect:!1,redirectTo:null,isChecking:!0};if(c){let o=c(n,a);return{shouldRedirect:o,redirectTo:o&&r||null,isChecking:!1}}if(t!==!1&&t!==void 0){if(!i)return{shouldRedirect:!1,redirectTo:null,isChecking:!1};if(!i.navigate(t)){let o=null;return typeof t=="object"&&t.required&&!n?u.search.includes("code=")||u.search.includes("state=")||u.search.includes("error=")?o=`${s.authRoute}${u.search}`:o=s.authRoute:typeof t=="object"&&t.role?o=s.roleRoute:typeof t=="object"&&t.tier?o=s.tierRoute:o=s.roleRoute,{shouldRedirect:!0,redirectTo:r||o,isChecking:!1}}}return{shouldRedirect:!1,redirectTo:null,isChecking:!1}},[t,a,n,i,c,r,u.search,s.authRoute,s.roleRoute,s.tierRoute])}export{w as useBack,m as useLocation,U as useMatch,h as useNavigate,g as useParams,I as usePrefetch,L as useQueryParams,B as useRedirectGuard,b as useRefresh,G as useRouteParam,R as useSearchParams};
@@ -0,0 +1,14 @@
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
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,42 @@
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;
@@ -1,5 +1,5 @@
1
1
  import type { NavigateOptions } from './types';
2
- export declare function useNavigate(): (to: string, options?: NavigateOptions) => void;
2
+ export declare function useNavigate(): (to: string, options?: NavigateOptions) => Promise<void>;
3
3
  export declare function useBack(): () => void;
4
4
  export declare function useRefresh(): () => void;
5
5
  export declare function usePrefetch(): (to: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useNavigate.next.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useNavigate.next.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,wBAAgB,WAAW,SAKlB,MAAM,YAAY,eAAe,UA0BzC;AAED,wBAAgB,OAAO,eAGtB;AAED,wBAAgB,UAAU,eAGzB;AAED,wBAAgB,WAAW,SAED,MAAM,UAC/B"}
1
+ {"version":3,"file":"useNavigate.next.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useNavigate.next.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,wBAAgB,WAAW,SAKZ,MAAM,YAAY,eAAe,mBAgC/C;AAED,wBAAgB,OAAO,eAGtB;AAED,wBAAgB,UAAU,eAGzB;AAED,wBAAgB,WAAW,SAED,MAAM,UAC/B"}
@@ -11,14 +11,20 @@
11
11
  import { useRouter as useNextRouter } from 'next/navigation';
12
12
  import { useCallback } from 'react';
13
13
  import { isClient, useOverlayStore } from '@donotdev/core';
14
+ import { checkFormNavigationSafe } from '../../utils/useFormStoreSafe';
14
15
  export function useNavigate() {
15
16
  const router = useNextRouter();
16
17
  const closeAll = useOverlayStore((state) => state.closeAll);
17
- return useCallback((to, options) => {
18
+ return useCallback(async (to, options) => {
18
19
  if (to === 'back') {
19
20
  closeAll();
20
21
  return router.back();
21
22
  }
23
+ // Check FormStore for dirty forms before navigation (safe - works if CRUD not installed)
24
+ const shouldProceed = await checkFormNavigationSafe();
25
+ if (!shouldProceed) {
26
+ return; // Navigation blocked by user
27
+ }
22
28
  closeAll();
23
29
  if (options?.preserveScroll && isClient()) {
24
30
  const scrollY = window.scrollY;
@@ -1,5 +1,5 @@
1
1
  import type { NavigateOptions } from './types';
2
- export declare function useNavigate(): (to: string, options?: NavigateOptions) => void | Promise<void>;
2
+ export declare function useNavigate(): (to: string, options?: NavigateOptions) => Promise<void>;
3
3
  export declare function useBack(): () => void | Promise<void>;
4
4
  export declare function useRefresh(): () => void;
5
5
  export declare function usePrefetch(): (_to: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useNavigate.vite.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useNavigate.vite.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,wBAAgB,WAAW,SAKlB,MAAM,YAAY,eAAe,0BAazC;AAED,wBAAgB,OAAO,+BAGtB;AAED,wBAAgB,UAAU,eAIzB;AAED,wBAAgB,WAAW,UACA,MAAM,UAGhC"}
1
+ {"version":3,"file":"useNavigate.vite.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useNavigate.vite.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,wBAAgB,WAAW,SAKZ,MAAM,YAAY,eAAe,mBAmB/C;AAED,wBAAgB,OAAO,+BAGtB;AAED,wBAAgB,UAAU,eAIzB;AAED,wBAAgB,WAAW,UACA,MAAM,UAGhC"}
@@ -11,14 +11,20 @@
11
11
  import { useCallback } from 'react';
12
12
  import { useNavigate as useRouterNavigate } from 'react-router-dom';
13
13
  import { isClient, useOverlayStore } from '@donotdev/core';
14
+ import { checkFormNavigationSafe } from '../../utils/useFormStoreSafe';
14
15
  export function useNavigate() {
15
16
  const navigate = useRouterNavigate();
16
17
  const closeAll = useOverlayStore((state) => state.closeAll);
17
- return useCallback((to, options) => {
18
+ return useCallback(async (to, options) => {
18
19
  if (to === 'back') {
19
20
  closeAll();
20
21
  return navigate(-1);
21
22
  }
23
+ // Check FormStore for dirty forms before navigation (safe - works if CRUD not installed)
24
+ const shouldProceed = await checkFormNavigationSafe();
25
+ if (!shouldProceed) {
26
+ return; // Navigation blocked by user
27
+ }
22
28
  closeAll();
23
29
  if (options?.replace)
24
30
  return navigate(to, { replace: true });