@donotdev/ui 0.0.12 → 0.0.14

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 (159) hide show
  1. package/dist/components/auth/AuthMenu.d.ts.map +1 -1
  2. package/dist/components/auth/AuthMenu.js +19 -20
  3. package/dist/components/common/FeatureCard.d.ts +3 -1
  4. package/dist/components/common/FeatureCard.d.ts.map +1 -1
  5. package/dist/components/common/FeatureCard.js +3 -3
  6. package/dist/components/common/ProgressBar.js +2 -2
  7. package/dist/components/common/RedirectOverlay.js +1 -1
  8. package/dist/components/common/TechBento.d.ts +14 -2
  9. package/dist/components/common/TechBento.d.ts.map +1 -1
  10. package/dist/components/common/TechBento.js +8 -9
  11. package/dist/components/cookie-consent/CookieConsent.d.ts.map +1 -1
  12. package/dist/components/cookie-consent/CookieConsent.js +6 -7
  13. package/dist/components/layout/GameContainer.d.ts +24 -8
  14. package/dist/components/layout/GameContainer.d.ts.map +1 -1
  15. package/dist/components/layout/GameContainer.js +21 -3
  16. package/dist/components/layout/GameFlow.d.ts.map +1 -1
  17. package/dist/components/layout/GameFlow.js +27 -11
  18. package/dist/components/layout/components/DropdownNavigation.d.ts.map +1 -1
  19. package/dist/components/layout/components/DropdownNavigation.js +3 -12
  20. package/dist/components/layout/components/FloatingLanguageSwitcher.js +1 -1
  21. package/dist/components/layout/components/Notifications.d.ts +1 -3
  22. package/dist/components/layout/components/Notifications.d.ts.map +1 -1
  23. package/dist/components/layout/components/Notifications.js +4 -2
  24. package/dist/components/layout/components/header/AppBranding.d.ts.map +1 -1
  25. package/dist/components/layout/components/header/AppBranding.js +2 -1
  26. package/dist/components/layout/components/header/AppIcon.d.ts.map +1 -1
  27. package/dist/components/layout/components/header/AppIcon.js +5 -2
  28. package/dist/components/layout/components/header/CacheSettings.d.ts.map +1 -1
  29. package/dist/components/layout/components/header/CacheSettings.js +4 -2
  30. package/dist/components/layout/components/header/HeaderNavigation.d.ts +6 -0
  31. package/dist/components/layout/components/header/HeaderNavigation.d.ts.map +1 -1
  32. package/dist/components/layout/components/header/HeaderNavigation.js +12 -2
  33. package/dist/components/license/LicenseWatermark.d.ts.map +1 -1
  34. package/dist/components/license/LicenseWatermark.js +3 -1
  35. package/dist/crud/components/CrudCardLink.d.ts +17 -0
  36. package/dist/crud/components/CrudCardLink.d.ts.map +1 -0
  37. package/dist/crud/components/CrudCardLink.js +17 -0
  38. package/dist/crud/components/EntityCardList.d.ts.map +1 -1
  39. package/dist/crud/components/EntityCardList.js +32 -81
  40. package/dist/crud/components/EntityDisplayRenderer.d.ts +1 -1
  41. package/dist/crud/components/EntityDisplayRenderer.d.ts.map +1 -1
  42. package/dist/crud/components/EntityDisplayRenderer.js +8 -4
  43. package/dist/crud/components/EntityFormRenderer.d.ts +1 -1
  44. package/dist/crud/components/EntityFormRenderer.d.ts.map +1 -1
  45. package/dist/crud/components/EntityFormRenderer.js +29 -18
  46. package/dist/crud/components/EntityList.d.ts +1 -1
  47. package/dist/crud/components/EntityList.d.ts.map +1 -1
  48. package/dist/crud/components/EntityList.js +8 -10
  49. package/dist/crud/components/EntityRecommendations.d.ts +28 -0
  50. package/dist/crud/components/EntityRecommendations.d.ts.map +1 -0
  51. package/dist/crud/components/EntityRecommendations.js +31 -0
  52. package/dist/crud/components/Form.js +1 -1
  53. package/dist/crud/components/index.d.ts +2 -1
  54. package/dist/crud/components/index.d.ts.map +1 -1
  55. package/dist/crud/components/index.js +1 -0
  56. package/dist/index.js +4 -4
  57. package/dist/internal/common/RouteErrorFallback.d.ts.map +1 -1
  58. package/dist/internal/common/RouteErrorFallback.js +3 -3
  59. package/dist/internal/devtools/components/AuthDebugButton.js +1 -1
  60. package/dist/internal/devtools/components/ConfigTab.js +1 -1
  61. package/dist/internal/devtools/components/CookieTab.js +1 -1
  62. package/dist/internal/devtools/components/DesignTab.d.ts.map +1 -1
  63. package/dist/internal/devtools/components/DesignTab.js +5 -4
  64. package/dist/internal/devtools/components/LayoutReset.d.ts.map +1 -1
  65. package/dist/internal/devtools/components/LayoutReset.js +2 -0
  66. package/dist/internal/devtools/components/StoresTab.d.ts.map +1 -1
  67. package/dist/internal/devtools/components/StoresTab.js +5 -2
  68. package/dist/internal/devtools/utils/envVarDiscovery.d.ts +1 -0
  69. package/dist/internal/devtools/utils/envVarDiscovery.d.ts.map +1 -1
  70. package/dist/internal/devtools/utils/envVarDiscovery.js +5 -0
  71. package/dist/internal/devtools/utils/virtualModuleInspector.d.ts.map +1 -1
  72. package/dist/internal/devtools/utils/virtualModuleInspector.js +27 -21
  73. package/dist/internal/initializers/BaseStoresInitializer.d.ts.map +1 -1
  74. package/dist/internal/initializers/BaseStoresInitializer.js +30 -6
  75. package/dist/internal/layout/components/AutoMetaTags.d.ts.map +1 -1
  76. package/dist/internal/layout/components/AutoMetaTags.js +10 -8
  77. package/dist/internal/layout/components/FontPreloadLinks.d.ts +16 -0
  78. package/dist/internal/layout/components/FontPreloadLinks.d.ts.map +1 -0
  79. package/dist/internal/layout/components/FontPreloadLinks.js +32 -0
  80. package/dist/internal/layout/components/PerformanceHints.d.ts +7 -12
  81. package/dist/internal/layout/components/PerformanceHints.d.ts.map +1 -1
  82. package/dist/internal/layout/components/PerformanceHints.js +8 -12
  83. package/dist/internal/layout/components/footer/useLegalLinks.d.ts +6 -5
  84. package/dist/internal/layout/components/footer/useLegalLinks.d.ts.map +1 -1
  85. package/dist/internal/layout/components/footer/useLegalLinks.js +6 -2
  86. package/dist/internal/layout/zones/DnDevFooter.d.ts +6 -0
  87. package/dist/internal/layout/zones/DnDevFooter.d.ts.map +1 -1
  88. package/dist/internal/layout/zones/DnDevFooter.js +10 -4
  89. package/dist/internal/layout/zones/DnDevHeader.d.ts +7 -0
  90. package/dist/internal/layout/zones/DnDevHeader.d.ts.map +1 -1
  91. package/dist/internal/layout/zones/DnDevHeader.js +7 -0
  92. package/dist/internal/layout/zones/DnDevMergedBar.d.ts +7 -0
  93. package/dist/internal/layout/zones/DnDevMergedBar.d.ts.map +1 -1
  94. package/dist/internal/layout/zones/DnDevMergedBar.js +10 -1
  95. package/dist/internal/layout/zones/DnDevSidebar.d.ts +4 -0
  96. package/dist/internal/layout/zones/DnDevSidebar.d.ts.map +1 -1
  97. package/dist/internal/layout/zones/DnDevSidebar.js +13 -1
  98. package/dist/next.d.ts +1 -0
  99. package/dist/next.d.ts.map +1 -1
  100. package/dist/next.js +1 -0
  101. package/dist/routing/404.js +3 -3
  102. package/dist/routing/AuthGuard.d.ts +1 -1
  103. package/dist/routing/AuthGuard.d.ts.map +1 -1
  104. package/dist/routing/AuthGuard.js +3 -1
  105. package/dist/routing/AuthGuardFallback.js +2 -2
  106. package/dist/routing/GoTo.d.ts.map +1 -1
  107. package/dist/routing/GoTo.js +3 -1
  108. package/dist/routing/GoToDialog.d.ts.map +1 -1
  109. package/dist/routing/GoToDialog.js +2 -7
  110. package/dist/routing/GoToInput.d.ts +0 -3
  111. package/dist/routing/GoToInput.d.ts.map +1 -1
  112. package/dist/routing/GoToInput.js +4 -2
  113. package/dist/routing/Link.js +1 -1
  114. package/dist/routing/NavigationItem.d.ts +29 -7
  115. package/dist/routing/NavigationItem.d.ts.map +1 -1
  116. package/dist/routing/NavigationItem.js +22 -6
  117. package/dist/routing/hooks/hooks.next.js +1 -1
  118. package/dist/routing/hooks/hooks.vite.js +1 -1
  119. package/dist/routing/hooks/useRedirectGuard.next.d.ts.map +1 -1
  120. package/dist/routing/hooks/useRedirectGuard.next.js +9 -8
  121. package/dist/routing/hooks/useRedirectGuard.vite.d.ts.map +1 -1
  122. package/dist/routing/hooks/useRedirectGuard.vite.js +9 -8
  123. package/dist/routing/hooks/useSearchParams.next.d.ts +18 -1
  124. package/dist/routing/hooks/useSearchParams.next.d.ts.map +1 -1
  125. package/dist/routing/hooks/useSearchParams.next.js +16 -0
  126. package/dist/routing/hooks/useSearchParams.vite.d.ts +16 -0
  127. package/dist/routing/hooks/useSearchParams.vite.d.ts.map +1 -1
  128. package/dist/routing/hooks/useSearchParams.vite.js +17 -1
  129. package/dist/routing/index.d.ts.map +1 -1
  130. package/dist/routing/index.js +2 -0
  131. package/dist/routing/useNavigation.d.ts +30 -0
  132. package/dist/routing/useNavigation.d.ts.map +1 -1
  133. package/dist/routing/useNavigation.js +40 -3
  134. package/dist/routing/useRouteDiscovery.d.ts +2 -2
  135. package/dist/routing/useRouteDiscovery.d.ts.map +1 -1
  136. package/dist/routing/useRouteDiscovery.js +10 -4
  137. package/dist/styles/index.css +366 -120
  138. package/dist/utils/index.d.ts +1 -0
  139. package/dist/utils/index.d.ts.map +1 -1
  140. package/dist/utils/index.js +1 -0
  141. package/dist/utils/sanitizeSvg.d.ts +13 -0
  142. package/dist/utils/sanitizeSvg.d.ts.map +1 -0
  143. package/dist/utils/sanitizeSvg.js +47 -0
  144. package/dist/utils/useBillingVisibility.d.ts.map +1 -1
  145. package/dist/utils/useBillingVisibility.js +0 -7
  146. package/dist/utils/useCrudSafe.d.ts +0 -2
  147. package/dist/utils/useCrudSafe.d.ts.map +1 -1
  148. package/dist/utils/useFormStoreSafe.d.ts +3 -1
  149. package/dist/utils/useFormStoreSafe.d.ts.map +1 -1
  150. package/dist/utils/useFormStoreSafe.js +4 -5
  151. package/dist/vite-routing/AppRoutes.d.ts +19 -8
  152. package/dist/vite-routing/AppRoutes.d.ts.map +1 -1
  153. package/dist/vite-routing/AppRoutes.js +0 -3
  154. package/package.json +15 -11
  155. package/assets/fonts/fonts.css +0 -206
  156. package/dist/dndev.css +0 -10673
  157. package/dist/routing/Navigate.d.ts +0 -10
  158. package/dist/routing/Navigate.d.ts.map +0 -1
  159. package/dist/routing/Navigate.js +0 -10
@@ -17,7 +17,7 @@ import { Stack } from '@donotdev/components';
17
17
  import { useBreakpoint, useTranslation, maybeTranslate } from '@donotdev/core';
18
18
  import { Link } from '../../../routing/Link';
19
19
  import { FooterBranding } from '../components/footer/FooterBranding';
20
- import { useLegalLinks, } from '../components/footer/useLegalLinks';
20
+ import { getLegalLinks, } from '../components/footer/useLegalLinks';
21
21
  /**
22
22
  * DnDevFooter - Simple footer: Copyright (left) | LegalLinks + DoNotDev (right)
23
23
  *
@@ -31,16 +31,22 @@ import { useLegalLinks, } from '../components/footer/useLegalLinks';
31
31
  * 4. app.footer.copyright === string -> custom copyright
32
32
  * 5. LegalLinks from app.footer.legalLinks (defaults if undefined)
33
33
  * 6. DoNotDev branding always appended
34
+ *
35
+ * @critical The `<footer>` MUST have `role="contentinfo"` and className `"footer"`.
36
+ * ALL footer CSS in layout-variables.css targets `footer[role='contentinfo']`.
37
+ * This controls: grid placement, height, border, footer-mode scroll behavior,
38
+ * preset-specific visibility (moolti/plain hide footer, blog hides on mobile).
39
+ * DO NOT change role, tag, or className.
34
40
  */
35
41
  function DnDevFooterComponent({ app = {} }) {
36
42
  const { t } = useTranslation('dndev');
37
43
  const isLaptopOrDesktop = useBreakpoint('isLaptopOrDesktop');
44
+ // Get legal links (defaults or custom) — must be called before any return
45
+ const links = getLegalLinks(app?.footer);
38
46
  // Explicit null hides footer
39
47
  if (app?.footer === null) {
40
48
  return null;
41
49
  }
42
- // Get legal links (defaults or custom)
43
- const links = useLegalLinks(app.footer);
44
50
  // Copyright: null = hide, undefined = default, string = custom
45
51
  const copyrightConfig = app.footer?.copyright;
46
52
  const showCopyright = copyrightConfig !== null;
@@ -49,7 +55,7 @@ function DnDevFooterComponent({ app = {} }) {
49
55
  : copyrightConfig;
50
56
  // Desktop/Wide: 2-zone layout [Copyright] | [Links + DoNotDev]
51
57
  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, style: { fontSize: 'var(--font-size-xs)' }, children: maybeTranslate(t, link.label) }, link.path))), _jsx(FooterBranding, {})] }) })] }) }));
58
+ return (_jsx("footer", { role: "contentinfo", className: "footer", children: _jsxs(Stack, { direction: "row", align: "center", justify: "between", gap: "none", children: [showCopyright && (_jsx("div", { style: { display: 'flex', justifyContent: 'flex-start' }, children: _jsx("span", { className: "footer-copyright", children: copyrightText }) })), _jsx("div", { style: { display: 'flex', justifyContent: 'flex-end' }, children: _jsxs(Stack, { direction: "row", 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
59
  }
54
60
  // Mobile/Tablet: stacked layout
55
61
  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, {})] })] }) }));
@@ -12,6 +12,13 @@ export interface DnDevHeaderProps {
12
12
  *
13
13
  * Layout: start (start-aligned) | center (absolutely centered) | end (end-aligned)
14
14
  * Center is absolutely positioned overlay, independent of start/end content.
15
+ *
16
+ * @critical The `<header>` MUST have `role="banner"` and className `"header"`.
17
+ * ALL header CSS in layout-variables.css targets `header[role='banner']`.
18
+ * The inner divs MUST use classNames `"header-start"`, `"header-center"`, `"header-end"`.
19
+ * Removing or renaming any of these silently breaks header layout, spacing, visibility,
20
+ * and preset-specific rules (e.g. landing compact mode, mergedBar hiding).
21
+ * DO NOT change role, tag, or classNames.
15
22
  */
16
23
  declare function DnDevHeaderComponent({ start, center, end, }: DnDevHeaderProps): ReactNode;
17
24
  export declare const DnDevHeader: import("react").MemoExoticComponent<typeof DnDevHeaderComponent>;
@@ -1 +1 @@
1
- {"version":3,"file":"DnDevHeader.d.ts","sourceRoot":"","sources":["../../../../src/internal/layout/zones/DnDevHeader.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,4DAA4D;IAC5D,GAAG,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;CACxB;AAED;;;;;GAKG;AACH,iBAAS,oBAAoB,CAAC,EAC5B,KAAK,EACL,MAAM,EACN,GAAG,GACJ,EAAE,gBAAgB,GAAG,SAAS,CAgB9B;AAED,eAAO,MAAM,WAAW,kEAA6B,CAAC"}
1
+ {"version":3,"file":"DnDevHeader.d.ts","sourceRoot":"","sources":["../../../../src/internal/layout/zones/DnDevHeader.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,4DAA4D;IAC5D,GAAG,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;;GAYG;AACH,iBAAS,oBAAoB,CAAC,EAC5B,KAAK,EACL,MAAM,EACN,GAAG,GACJ,EAAE,gBAAgB,GAAG,SAAS,CAgB9B;AAED,eAAO,MAAM,WAAW,kEAA6B,CAAC"}
@@ -20,6 +20,13 @@ import { cn } from '@donotdev/components';
20
20
  *
21
21
  * Layout: start (start-aligned) | center (absolutely centered) | end (end-aligned)
22
22
  * Center is absolutely positioned overlay, independent of start/end content.
23
+ *
24
+ * @critical The `<header>` MUST have `role="banner"` and className `"header"`.
25
+ * ALL header CSS in layout-variables.css targets `header[role='banner']`.
26
+ * The inner divs MUST use classNames `"header-start"`, `"header-center"`, `"header-end"`.
27
+ * Removing or renaming any of these silently breaks header layout, spacing, visibility,
28
+ * and preset-specific rules (e.g. landing compact mode, mergedBar hiding).
29
+ * DO NOT change role, tag, or classNames.
23
30
  */
24
31
  function DnDevHeaderComponent({ start, center, end, }) {
25
32
  // Check if center has content
@@ -20,6 +20,13 @@ export interface DnDevMergedBarProps {
20
20
  * Slots are customizable per-preset with smart defaults:
21
21
  * - trigger: What shows in the fixed bar (default: header.start or AppBranding)
22
22
  * - top/content/bottom: Sheet content (default: derived from sidebar)
23
+ *
24
+ * @critical The outer `<div>` MUST have className `"merged-bar"` and `data-position`.
25
+ * ALL mergedBar CSS in layout-variables.css targets `.merged-bar` and `.merged-bar[data-position]`.
26
+ * This controls: position:fixed placement, display:none/flex toggling per preset + breakpoint,
27
+ * safe area padding, border, and z-index. Inner divs MUST keep `"merged-bar-trigger"`,
28
+ * `"merged-bar-sheet-content"`, `"merged-bar-sheet-scroll"` classNames.
29
+ * DO NOT change classNames or data attributes.
23
30
  */
24
31
  declare function DnDevMergedBarComponent({ position, height, trigger, top, content, bottom, }: DnDevMergedBarProps): ReactNode;
25
32
  export declare const DnDevMergedBar: import("react").MemoExoticComponent<typeof DnDevMergedBarComponent>;
@@ -1 +1 @@
1
- {"version":3,"file":"DnDevMergedBar.d.ts","sourceRoot":"","sources":["../../../../src/internal/layout/zones/DnDevMergedBar.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,mBAAmB;IAClC,mBAAmB;IACnB,QAAQ,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC3B,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,OAAO,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC3B,4DAA4D;IAC5D,GAAG,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACvB,gEAAgE;IAChE,OAAO,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC3B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,iBAAS,uBAAuB,CAAC,EAC/B,QAAQ,EACR,MAAM,EACN,OAAO,EACP,GAAG,EACH,OAAO,EACP,MAAM,GACP,EAAE,mBAAmB,GAAG,SAAS,CA8DjC;AAED,eAAO,MAAM,cAAc,qEAAgC,CAAC"}
1
+ {"version":3,"file":"DnDevMergedBar.d.ts","sourceRoot":"","sources":["../../../../src/internal/layout/zones/DnDevMergedBar.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,mBAAmB;IAClC,mBAAmB;IACnB,QAAQ,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC3B,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,OAAO,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC3B,4DAA4D;IAC5D,GAAG,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACvB,gEAAgE;IAChE,OAAO,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC3B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;;;;;;;;GAcG;AACH,iBAAS,uBAAuB,CAAC,EAC/B,QAAQ,EACR,MAAM,EACN,OAAO,EACP,GAAG,EACH,OAAO,EACP,MAAM,GACP,EAAE,mBAAmB,GAAG,SAAS,CAgEjC;AAED,eAAO,MAAM,cAAc,qEAAgC,CAAC"}
@@ -24,10 +24,19 @@ import { useLocation } from '@donotdev/ui/routing/hooks';
24
24
  * Slots are customizable per-preset with smart defaults:
25
25
  * - trigger: What shows in the fixed bar (default: header.start or AppBranding)
26
26
  * - top/content/bottom: Sheet content (default: derived from sidebar)
27
+ *
28
+ * @critical The outer `<div>` MUST have className `"merged-bar"` and `data-position`.
29
+ * ALL mergedBar CSS in layout-variables.css targets `.merged-bar` and `.merged-bar[data-position]`.
30
+ * This controls: position:fixed placement, display:none/flex toggling per preset + breakpoint,
31
+ * safe area padding, border, and z-index. Inner divs MUST keep `"merged-bar-trigger"`,
32
+ * `"merged-bar-sheet-content"`, `"merged-bar-sheet-scroll"` classNames.
33
+ * DO NOT change classNames or data attributes.
27
34
  */
28
35
  function DnDevMergedBarComponent({ position, height, trigger, top, content, bottom, }) {
29
36
  const { t } = useTranslation('dndev');
30
37
  const Icon = position === 'top' ? Menu : ChevronUp;
38
+ // Sheet component accepts 'left'|'right'|'top'|'bottom' (physical), not logical properties.
39
+ // For RTL apps, this would need Sheet to support 'start'/'end' sides — tracked separately.
31
40
  const sheetSide = position === 'top' ? 'left' : position;
32
41
  const [open, setOpen] = useState(false);
33
42
  const location = useLocation();
@@ -36,7 +45,7 @@ function DnDevMergedBarComponent({ position, height, trigger, top, content, bott
36
45
  setOpen(false);
37
46
  }, [location.pathname]);
38
47
  // Build sheet content
39
- const sheetNode = (_jsxs(Stack, { direction: "column", gap: "medium", className: "merged-bar-sheet-content", children: [top && (_jsxs(_Fragment, { children: [top, _jsx(Separator, { variant: SEPARATOR_VARIANT.MUTED })] })), content && _jsx("div", { className: "merged-bar-sheet-scroll", children: content }), bottom && (_jsxs(_Fragment, { children: [_jsx(Separator, { variant: SEPARATOR_VARIANT.MUTED }), bottom] }))] }));
48
+ const sheetNode = (_jsxs(Stack, { direction: "column", className: "merged-bar-sheet-content", children: [top && (_jsxs(_Fragment, { children: [top, _jsx(Separator, { variant: SEPARATOR_VARIANT.MUTED })] })), content && _jsx("div", { className: "merged-bar-sheet-scroll", children: content }), bottom && (_jsxs(_Fragment, { children: [_jsx(Separator, { variant: SEPARATOR_VARIANT.MUTED }), bottom] }))] }));
40
49
  const triggerButton = (_jsx(Button, { variant: BUTTON_VARIANT.GHOST, icon: Icon, "aria-label": "Open navigation" }));
41
50
  return (_jsx("div", { className: "merged-bar", "data-position": position, children: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "merged-bar-trigger", children: [trigger, _jsx(Sheet, { trigger: triggerButton, side: sheetSide, open: open, onOpenChange: setOpen, title: t('sheet.navigation', { defaultValue: 'Navigation' }), children: sheetNode })] }) }));
42
51
  }
@@ -18,6 +18,10 @@ export interface DnDevSidebarProps {
18
18
  *
19
19
  * Structure: aside.sidebar > nav.sidebar-nav + div.resize-handle
20
20
  * Resize logic lives on aside directly. No wrapper components.
21
+ *
22
+ * @critical The `<aside>` MUST have `role="navigation"` — ALL CSS in layout-variables.css
23
+ * targets `aside[role='navigation'].sidebar`. Removing it silently breaks every sidebar feature.
24
+ * DO NOT remove or change role="navigation" under any circumstance.
21
25
  */
22
26
  declare function DnDevSidebarComponent({ top, content, bottom, defaultWidth, minWidth, maxWidth, }: DnDevSidebarProps): ReactNode;
23
27
  export declare const DnDevSidebar: import("react").MemoExoticComponent<typeof DnDevSidebarComponent>;
@@ -1 +1 @@
1
- {"version":3,"file":"DnDevSidebar.d.ts","sourceRoot":"","sources":["../../../../src/internal/layout/zones/DnDevSidebar.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvC,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,GAAG,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACvB,gEAAgE;IAChE,OAAO,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC3B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,iBAAS,qBAAqB,CAAC,EAC7B,GAAG,EACH,OAAO,EACP,MAAM,EACN,YAAiD,EACjD,QAAyC,EACzC,QAAyC,GAC1C,EAAE,iBAAiB,GAAG,SAAS,CAiM/B;AAED,eAAO,MAAM,YAAY,mEAA8B,CAAC"}
1
+ {"version":3,"file":"DnDevSidebar.d.ts","sourceRoot":"","sources":["../../../../src/internal/layout/zones/DnDevSidebar.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvC,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,GAAG,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACvB,gEAAgE;IAChE,OAAO,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC3B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,iBAAS,qBAAqB,CAAC,EAC7B,GAAG,EACH,OAAO,EACP,MAAM,EACN,YAAiD,EACjD,QAAyC,EACzC,QAAyC,GAC1C,EAAE,iBAAiB,GAAG,SAAS,CAyM/B;AAED,eAAO,MAAM,YAAY,mEAA8B,CAAC"}
@@ -23,6 +23,10 @@ const RESIZE_HANDLE_WIDTH = 6;
23
23
  *
24
24
  * Structure: aside.sidebar > nav.sidebar-nav + div.resize-handle
25
25
  * Resize logic lives on aside directly. No wrapper components.
26
+ *
27
+ * @critical The `<aside>` MUST have `role="navigation"` — ALL CSS in layout-variables.css
28
+ * targets `aside[role='navigation'].sidebar`. Removing it silently breaks every sidebar feature.
29
+ * DO NOT remove or change role="navigation" under any circumstance.
26
30
  */
27
31
  function DnDevSidebarComponent({ top, content, bottom, defaultWidth = DEFAULT_SLOTS.sidebar.defaultWidth, minWidth = DEFAULT_SLOTS.sidebar.minWidth, maxWidth = DEFAULT_SLOTS.sidebar.maxWidth, }) {
28
32
  // Resize state
@@ -158,6 +162,14 @@ function DnDevSidebarComponent({ top, content, bottom, defaultWidth = DEFAULT_SL
158
162
  break;
159
163
  }
160
164
  };
161
- return (_jsxs("aside", { ref: asideRef, role: "navigation", className: "sidebar", "data-dragging": isDragging, "data-collapsed": isCollapsed, children: [top && _jsx("div", { className: "sidebar-top", children: top }), _jsx("div", { className: "sidebar-content", children: content }), bottom && _jsx("div", { className: "sidebar-bottom", children: bottom }), _jsx("div", { className: "dndev-sidebar-resize-handle", onPointerDown: handlePointerDown, onDoubleClick: toggleCollapse, onKeyDown: handleKeyDown, role: "separator", "aria-label": "Resize sidebar. Double-click or Enter to toggle. Home to collapse, End to fit content.", "aria-valuenow": sidebarWidth, "aria-valuemin": minWidth, "aria-valuemax": maxWidth, "aria-orientation": "vertical", tabIndex: 0 })] }));
165
+ return (
166
+ /**
167
+ * CRITICAL: role="navigation" is required.
168
+ * ALL sidebar CSS selectors in layout-variables.css use `aside[role='navigation'].sidebar`.
169
+ * Removing role="navigation" breaks: grid placement, display:none for no-sidebar presets,
170
+ * resize handle styles, collapsed styles — essentially ALL sidebar behavior.
171
+ * aria-label provides the accessible name. Both attributes are required.
172
+ */
173
+ _jsxs("aside", { ref: asideRef, role: "navigation", "aria-label": "Site navigation", className: "sidebar", "data-dragging": isDragging, "data-collapsed": isCollapsed, children: [top && _jsx("div", { className: "sidebar-top", children: top }), _jsx("div", { className: "sidebar-content", children: content }), bottom && _jsx("div", { className: "sidebar-bottom", children: bottom }), _jsx("div", { className: "dndev-sidebar-resize-handle", onPointerDown: handlePointerDown, onDoubleClick: toggleCollapse, onKeyDown: handleKeyDown, role: "separator", "aria-label": "Resize sidebar. Double-click or Enter to toggle. Home to collapse, End to fit content.", "aria-valuenow": sidebarWidth, "aria-valuemin": minWidth, "aria-valuemax": maxWidth, "aria-orientation": "vertical", tabIndex: 0 })] }));
162
174
  }
163
175
  export const DnDevSidebar = memo(DnDevSidebarComponent);
package/dist/next.d.ts CHANGED
@@ -7,4 +7,5 @@
7
7
  * @author AMBROISE PARK Consulting
8
8
  */
9
9
  export { NextJsAppProviders } from './providers/NextJsAppProviders';
10
+ export { FontPreloadLinks, default as FontPreloadLinksDefault, } from './internal/layout/components/FontPreloadLinks';
10
11
  //# sourceMappingURL=next.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../src/next.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC"}
1
+ {"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../src/next.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EACL,gBAAgB,EAChB,OAAO,IAAI,uBAAuB,GACnC,MAAM,+CAA+C,CAAC"}
package/dist/next.js CHANGED
@@ -8,3 +8,4 @@
8
8
  * @author AMBROISE PARK Consulting
9
9
  */
10
10
  export { NextJsAppProviders } from './providers/NextJsAppProviders';
11
+ export { FontPreloadLinks, default as FontPreloadLinksDefault, } from './internal/layout/components/FontPreloadLinks';
@@ -64,7 +64,7 @@ export default function NotFoundPage() {
64
64
  const handleBack = () => {
65
65
  navigate('back');
66
66
  };
67
- return (_jsx(PageContainer, { variant: "docs", centered: true, children: _jsxs(Stack, { gap: "large", align: "center", justify: "center", children: [_jsxs(Stack, { gap: "medium", align: "center", children: [_jsx(Text, { level: "h1", style: {
67
+ return (_jsx(PageContainer, { variant: "docs", centered: true, children: _jsxs(Stack, { gap: "large", align: "center", justify: "center", children: [_jsxs(Stack, { align: "center", children: [_jsx(Text, { level: "h1", style: {
68
68
  fontSize: 'clamp(4rem, 12vw, 8rem)',
69
69
  fontWeight: 'var(--font-weight-bold)',
70
70
  lineHeight: 1,
@@ -95,10 +95,10 @@ export default function NotFoundPage() {
95
95
  overflow: 'hidden',
96
96
  textOverflow: 'ellipsis',
97
97
  border: '1px solid var(--border-hairline)',
98
- }, children: location.pathname }))] }), suggestedRoutes.length > 0 && (_jsxs(Stack, { gap: "medium", align: "center", children: [_jsx("p", { className: "dndev-text-base", style: {
98
+ }, children: location.pathname }))] }), suggestedRoutes.length > 0 && (_jsxs(Stack, { align: "center", children: [_jsx("p", { className: "dndev-text-base", style: {
99
99
  fontSize: 'var(--font-size-md)',
100
100
  fontWeight: 'var(--font-weight-semibold)',
101
101
  margin: 0,
102
102
  color: 'var(--muted-foreground)',
103
- }, children: t('errors.notFound.suggestions', 'You might be looking for:') }), _jsx(Stack, { direction: "row", wrap: "wrap", justify: "center", gap: "tight", children: suggestedRoutes.map((route) => (_jsx(Link, { path: route.path, replace: true, children: _jsx(Button, { variant: BUTTON_VARIANT.OUTLINE, icon: _jsx(Icon, { icon: route.icon, fallback: LinkIcon }), "aria-label": t('errors.notFound.navigateTo', `Navigate to ${route.label}`, { label: route.label }), children: route.label }) }, route.path))) })] })), _jsxs(Stack, { direction: "row", wrap: "wrap", justify: "center", gap: "medium", children: [_jsx(Link, { path: "/", replace: true, children: _jsx(Button, { variant: BUTTON_VARIANT.DEFAULT, icon: Home, "aria-label": t('errors.notFound.goHome', 'Go to home page'), children: t('errors.notFound.goHome', 'Go Home') }) }), _jsx(Button, { variant: BUTTON_VARIANT.OUTLINE, icon: ArrowLeft, onClick: handleBack, "aria-label": t('errors.notFound.goBack', 'Go back to previous page'), children: t('errors.notFound.goBack', 'Go Back') })] })] }) }));
103
+ }, children: t('errors.notFound.suggestions', 'You might be looking for:') }), _jsx(Stack, { direction: "row", wrap: "wrap", justify: "center", gap: "tight", children: suggestedRoutes.map((route) => (_jsx(Link, { path: route.path, replace: true, children: _jsx(Button, { variant: BUTTON_VARIANT.OUTLINE, icon: _jsx(Icon, { icon: route.icon, fallback: LinkIcon }), "aria-label": t('errors.notFound.navigateTo', `Navigate to ${route.label}`, { label: route.label }), children: route.label }) }, route.path))) })] })), _jsxs(Stack, { direction: "row", wrap: "wrap", justify: "center", children: [_jsx(Link, { path: "/", replace: true, children: _jsx(Button, { variant: BUTTON_VARIANT.DEFAULT, icon: Home, "aria-label": t('errors.notFound.goHome', 'Go to home page'), children: t('errors.notFound.goHome', 'Go Home') }) }), _jsx(Button, { variant: BUTTON_VARIANT.OUTLINE, icon: ArrowLeft, onClick: handleBack, "aria-label": t('errors.notFound.goBack', 'Go back to previous page'), children: t('errors.notFound.goBack', 'Go Back') })] })] }) }));
104
104
  }
@@ -78,7 +78,7 @@ export declare function useHasRole(role: typeof USER_ROLES.GUEST | typeof USER_R
78
78
  export declare function useAuthState(): {
79
79
  authenticated: boolean;
80
80
  role: string | undefined;
81
- tier: any;
81
+ tier: string;
82
82
  loading: boolean;
83
83
  userId: string | undefined;
84
84
  };
@@ -1 +1 @@
1
- {"version":3,"file":"AuthGuard.d.ts","sourceRoot":"","sources":["../../src/routing/AuthGuard.tsx"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,aAAa,EACnB,MAAM,OAAO,CAAC;AAEf,OAAO,EAGL,UAAU,EACV,kBAAkB,EAClB,KAAK,QAAQ,EACd,MAAM,gBAAgB,CAAC;AAaxB;;GAEG;AACH,UAAU,cAAc;IACtB,wCAAwC;IACxC,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC;IACvB,wCAAwC;IACxC,QAAQ,EAAE,SAAS,CAAC;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,QAAQ,EACR,QAAQ,EAAE,QAAiB,GAC5B,EAAE,cAAc,2CA2HhB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,OAAO,CAG9D;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,uBAAiB,CAAC;AAE3C;;;;;;GAMG;AACH,wBAAgB,WAAW,IACvB,OAAO,UAAU,CAAC,KAAK,GACvB,OAAO,UAAU,CAAC,IAAI,GACtB,OAAO,UAAU,CAAC,KAAK,CAS1B;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,IAAI,EACA,OAAO,UAAU,CAAC,KAAK,GACvB,OAAO,UAAU,CAAC,IAAI,GACtB,OAAO,UAAU,CAAC,KAAK,GAC1B,OAAO,CAIT;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY;;;;;;EAW3B;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EACvC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,EAC3B,IAAI,EAAE,QAAQ,GAAG,KAAK,WAEW,CAAC,6CAOnC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB;IAC3B,iCAAiC;kBACrB,KAAK;IAEjB,oCAAoC;oBACtB,QAAQ;IAEtB,yCAAyC;gBAC/B,QAAQ;IAKlB,uDAAuD;iBAC5C,QAAQ;IAKnB,gCAAgC;iBAExB,CAAC,OAAO,kBAAkB,EAAE,MAAM,OAAO,kBAAkB,CAAC,KACjE,QAAQ;IAKX,eAAe;eACN,QAAQ;IAKjB,mBAAmB;mBACN,QAAQ;IAKrB,sCAAsC;oBACxB,QAAQ;IAMtB,wBAAwB;uBACL,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,KAAG,QAAQ;CAItE,CAAC;AAEF,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"AuthGuard.d.ts","sourceRoot":"","sources":["../../src/routing/AuthGuard.tsx"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,aAAa,EACnB,MAAM,OAAO,CAAC;AAEf,OAAO,EAGL,UAAU,EACV,kBAAkB,EAClB,KAAK,QAAQ,EACd,MAAM,gBAAgB,CAAC;AAaxB;;GAEG;AACH,UAAU,cAAc;IACtB,wCAAwC;IACxC,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC;IACvB,wCAAwC;IACxC,QAAQ,EAAE,SAAS,CAAC;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,QAAQ,EACR,QAAQ,EAAE,QAAiB,GAC5B,EAAE,cAAc,2CA6HhB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,OAAO,CAG9D;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,uBAAiB,CAAC;AAE3C;;;;;;GAMG;AACH,wBAAgB,WAAW,IACvB,OAAO,UAAU,CAAC,KAAK,GACvB,OAAO,UAAU,CAAC,IAAI,GACtB,OAAO,UAAU,CAAC,KAAK,CAS1B;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,IAAI,EACA,OAAO,UAAU,CAAC,KAAK,GACvB,OAAO,UAAU,CAAC,IAAI,GACtB,OAAO,UAAU,CAAC,KAAK,GAC1B,OAAO,CAIT;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY;;;;;;EAW3B;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EACvC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,EAC3B,IAAI,EAAE,QAAQ,GAAG,KAAK,WAEW,CAAC,6CAOnC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB;IAC3B,iCAAiC;kBACrB,KAAK;IAEjB,oCAAoC;oBACtB,QAAQ;IAEtB,yCAAyC;gBAC/B,QAAQ;IAKlB,uDAAuD;iBAC5C,QAAQ;IAKnB,gCAAgC;iBAExB,CAAC,OAAO,kBAAkB,EAAE,MAAM,OAAO,kBAAkB,CAAC,KACjE,QAAQ;IAKX,eAAe;eACN,QAAQ;IAKjB,mBAAmB;mBACN,QAAQ;IAKrB,sCAAsC;oBACxB,QAAQ;IAMtB,wBAAwB;uBACL,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,KAAG,QAAQ;CAItE,CAAC;AAEF,eAAe,SAAS,CAAC"}
@@ -53,7 +53,9 @@ export function AuthGuard({ auth, children, fallback: Fallback = Loader, }) {
53
53
  const timer = setTimeout(() => {
54
54
  if (status === FEATURE_STATUS.INITIALIZING) {
55
55
  setSlowWarning(true);
56
- console.warn('[AuthGuard] Auth taking longer than usual (>5s)');
56
+ if (process.env.NODE_ENV === 'development') {
57
+ console.warn('[AuthGuard] Auth taking longer than usual (>5s)');
58
+ }
57
59
  }
58
60
  }, 5000);
59
61
  return () => clearTimeout(timer);
@@ -50,14 +50,14 @@ export function AuthGuardFallback({ title, description, showBackButton = true, o
50
50
  maxWidth: '28rem',
51
51
  border: 'none',
52
52
  boxShadow: 'var(--shadow-xl)',
53
- }, title: _jsxs(Stack, { gap: "medium", children: [_jsx(Stack, { justify: "center", children: _jsx("div", { style: {
53
+ }, title: _jsxs(Stack, { children: [_jsx(Stack, { justify: "center", children: _jsx("div", { style: {
54
54
  borderRadius: '9999px',
55
55
  backgroundColor: 'color-mix(in oklab, var(--primary) 10%, transparent)',
56
56
  padding: 'var(--gap-md)',
57
57
  }, children: _jsx(Lock, { className: "dndev-size-touch", style: { color: 'var(--primary)' } }) }) }), _jsx("div", { style: {
58
58
  fontSize: 'var(--font-size-2xl)',
59
59
  fontWeight: 700,
60
- }, children: t('auth.fallback.title', 'Authentication Required') }), _jsx("p", { style: { color: 'var(--muted-foreground)' }, children: t('auth.fallback.description', 'Please sign in to access this page') })] }), children: _jsxs(Stack, { gap: "medium", children: [_jsxs(Stack, { gap: "large", children: [_jsx("div", { children: _jsx("p", { style: {
60
+ }, children: t('auth.fallback.title', 'Authentication Required') }), _jsx("p", { style: { color: 'var(--muted-foreground)' }, children: t('auth.fallback.description', 'Please sign in to access this page') })] }), children: _jsxs(Stack, { children: [_jsxs(Stack, { gap: "large", children: [_jsx("div", { children: _jsx("p", { style: {
61
61
  fontSize: 'var(--font-size-sm)',
62
62
  color: 'var(--muted-foreground)',
63
63
  }, children: t('auth.fallback.chooseProvider') }) }), _jsx(Suspense, { fallback: _jsx("div", { children: "Loading providers..." }), children: _jsx(MultipleAuthProviders, { layout: "vertical", spacing: "tight", fullWidth: true, ariaLabel: t('auth.fallback.authOptions') }) })] }), showBackButton && (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx("div", { children: _jsx(Button, { onClick: handleBack, className: "dndev-gap-sm", icon: ArrowLeft, children: t('common.back') }) })] })), _jsxs(Stack, { gap: "tight", style: {
@@ -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,iCAIlB,SAAS,4CAsCX,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,4CA0CX,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -21,8 +21,10 @@ 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)
24
+ // navigator.userAgentData?.platform is modern; navigator.platform is the deprecated fallback
24
25
  const isMac = typeof navigator !== 'undefined' &&
25
- /Mac|iPhone|iPad/.test(navigator.platform);
26
+ /Mac|iPhone|iPad/.test(navigator
27
+ .userAgentData?.platform ?? navigator.platform);
26
28
  const shortcut = isMac ? '⌘K' : 'Ctrl+K';
27
29
  const handleClick = () => {
28
30
  openCommandDialog();
@@ -1 +1 @@
1
- {"version":3,"file":"GoToDialog.d.ts","sourceRoot":"","sources":["../../src/routing/GoToDialog.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AA2J3C;;;GAGG;AACH,QAAA,MAAM,UAAU,EAAE,aAUjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"GoToDialog.d.ts","sourceRoot":"","sources":["../../src/routing/GoToDialog.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAwJ3C;;;GAGG;AACH,QAAA,MAAM,UAAU,EAAE,aAUjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -8,7 +8,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  * @since 0.0.1
9
9
  * @author AMBROISE PARK Consulting
10
10
  */
11
- import { Clock, Link as LinkIcon, Star } from 'lucide-react';
11
+ import { Link as LinkIcon, Star } from 'lucide-react';
12
12
  import { useCallback, useEffect, useRef } from 'react';
13
13
  import { Badge, Command, CommandDialog } from '@donotdev/components';
14
14
  import { useOverlayStore, useTranslation } from '@donotdev/core';
@@ -64,12 +64,7 @@ const GoToDialogContent = () => {
64
64
  });
65
65
  }
66
66
  if (recentItems.length > 0) {
67
- const recentCommandItems = recentItems
68
- .flatMap((item) => createItems([item], true))
69
- .map((item) => ({
70
- ...item,
71
- icon: _jsx(Icon, { icon: Clock, className: "dndev-size-sm" }),
72
- }));
67
+ const recentCommandItems = recentItems.flatMap((item) => createItems([item], true));
73
68
  if (recentCommandItems.length > 0) {
74
69
  commandGroups.push({
75
70
  heading: t('globalGoTo.recent', 'Recent'),
@@ -1,6 +1,3 @@
1
- /**
2
- * Navigation input - typeable search that syncs with command dialog
3
- */
4
1
  declare const GoToInput: () => import("react/jsx-runtime").JSX.Element;
5
2
  export default GoToInput;
6
3
  //# sourceMappingURL=GoToInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GoToInput.d.ts","sourceRoot":"","sources":["../../src/routing/GoToInput.tsx"],"names":[],"mappings":"AAwBA;;GAEG;AACH,QAAA,MAAM,SAAS,+CAyEd,CAAC;AAEF,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"GoToInput.d.ts","sourceRoot":"","sources":["../../src/routing/GoToInput.tsx"],"names":[],"mappings":"AA+BA,QAAA,MAAM,SAAS,+CAyEd,CAAC;AAEF,eAAe,SAAS,CAAC"}
@@ -16,6 +16,8 @@ import { useTranslation } from '@donotdev/core';
16
16
  /**
17
17
  * Navigation input - typeable search that syncs with command dialog
18
18
  */
19
+ /** Detect macOS/iOS for keyboard shortcut label (defaults to ⌘K during SSR) */
20
+ const isMac = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.userAgent);
19
21
  const GoToInput = () => {
20
22
  const { t } = useTranslation('dndev');
21
23
  const [value, setValue] = useState('');
@@ -37,11 +39,11 @@ const GoToInput = () => {
37
39
  openCommandDialog(value);
38
40
  }
39
41
  }, [openCommandDialog, value]);
40
- return (_jsxs(Stack, { direction: "row", align: "center", className: "dndev-relative dndev-w-full dndev-max-w-sm", role: "search", children: [_jsx(Search, { className: "dndev-absolute dndev-size-md", style: { left: '0.75rem', opacity: 0.5 }, "aria-hidden": "true" }), _jsx("input", { ref: inputRef, type: "text", value: value, onChange: (e) => setValue(e.target.value), onFocus: handleFocus, onKeyDown: handleKeyDown, placeholder: t('globalGoTo.searchPlaceholder', 'Search pages...'), className: "dndev-input dndev-w-full", style: { paddingLeft: '2.5rem', paddingRight: '5rem' }, "aria-label": t('globalGoTo.ariaLabel', 'Search navigation') }), _jsx("div", { className: "dndev-absolute dndev-flex dndev-items-center dndev-text-sm", style: { right: '0.75rem', gap: '0.25rem', opacity: 0.5 }, "aria-hidden": "true", children: _jsx("kbd", { style: {
42
+ return (_jsxs(Stack, { direction: "row", align: "center", className: "dndev-relative dndev-w-full dndev-max-w-sm", role: "search", children: [_jsx(Search, { className: "dndev-absolute dndev-size-md", style: { insetInlineStart: '0.75rem', opacity: 0.5 }, "aria-hidden": "true" }), _jsx("input", { ref: inputRef, type: "text", value: value, onChange: (e) => setValue(e.target.value), onFocus: handleFocus, onKeyDown: handleKeyDown, placeholder: t('globalGoTo.searchPlaceholder', 'Search pages...'), className: "dndev-input dndev-w-full", style: { paddingInlineStart: '2.5rem', paddingInlineEnd: '5rem' }, "aria-label": t('globalGoTo.ariaLabel', 'Search navigation') }), _jsx("div", { className: "dndev-absolute dndev-flex dndev-items-center dndev-text-sm", style: { insetInlineEnd: '0.75rem', gap: '0.25rem', opacity: 0.5 }, "aria-hidden": "true", children: _jsx("kbd", { style: {
41
43
  padding: '0.25rem 0.5rem',
42
44
  fontSize: 'var(--font-size-xs)',
43
45
  fontFamily: 'var(--font-mono)',
44
46
  borderRadius: 'var(--radius-sm)',
45
- }, children: "\u2318K" }) })] }));
47
+ }, children: isMac ? '⌘K' : 'Ctrl+K' }) })] }));
46
48
  };
47
49
  export default GoToInput;
@@ -25,9 +25,9 @@ import { Icon } from '../components/common/icon';
25
25
  */
26
26
  export const Link = ({ path, replace, prefetch = true, children, icon, label, onClick, className, 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedBy, target, rel, ...rest }) => {
27
27
  const navigate = useNavigate();
28
+ const showCookieBanner = useConsent('showCookieBanner');
28
29
  // Special framework trigger: #cookie-settings
29
30
  if (path === '#cookie-settings') {
30
- const showCookieBanner = useConsent('showCookieBanner');
31
31
  const handleCookieSettings = (e) => {
32
32
  e.preventDefault();
33
33
  e.stopPropagation();
@@ -1,18 +1,40 @@
1
1
  import type { NavigationRoute } from '@donotdev/core';
2
2
  import type { ComponentType } from 'react';
3
- interface NavigationItemProps {
3
+ /**
4
+ * Props for NavigationItemComponent.
5
+ *
6
+ * Source (mutually exclusive):
7
+ * - `path` — auto-resolves label, icon, and active state from the navigation store
8
+ * - `route` — explicit route object (use when the route is not registered in the store)
9
+ */
10
+ export type NavigationItemProps = ({
11
+ path: string;
12
+ route?: never;
13
+ } | {
4
14
  route: NavigationRoute;
15
+ path?: never;
16
+ }) & {
5
17
  showIcons?: boolean;
6
- }
18
+ };
7
19
  /**
8
- * Universal NavigationItem component
9
- * Handles icon + label + link in one place
10
- * Used everywhere in the framework
20
+ * Universal NavigationItem component — nav-trigger style link with icon + label.
11
21
  *
12
- * @version 0.0.1
22
+ * Used internally in menus, sidebars, and dropdowns.
23
+ * Pass `path` to auto-resolve label, icon, and active state from the navigation store.
24
+ * Pass `route` for an explicit one-off item not registered in the store.
25
+ *
26
+ * For standalone Button-style navigation (e.g. header end slot), use
27
+ * `useNavigationRoute(path)` and compose with `Button` + `render` prop directly.
28
+ *
29
+ * @version 0.0.2
13
30
  * @since 0.0.1
14
31
  * @author AMBROISE PARK Consulting
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * <NavigationItemComponent path="/pricing" />
36
+ * <NavigationItemComponent route={{ path: '/pricing', label: t('pricing'), icon: Tag }} />
37
+ * ```
15
38
  */
16
39
  export declare const NavigationItemComponent: ComponentType<NavigationItemProps>;
17
- export {};
18
40
  //# sourceMappingURL=NavigationItem.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NavigationItem.d.ts","sourceRoot":"","sources":["../../src/routing/NavigationItem.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAKtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,UAAU,mBAAmB;IAC3B,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,EAAE,aAAa,CAAC,mBAAmB,CAiBtE,CAAC"}
1
+ {"version":3,"file":"NavigationItem.d.ts","sourceRoot":"","sources":["../../src/routing/NavigationItem.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAMtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAC/B;IAAE,KAAK,EAAE,eAAe,CAAC;IAAC,IAAI,CAAC,EAAE,KAAK,CAAA;CAAE,CAC3C,GAAG;IACF,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,uBAAuB,EAAE,aAAa,CAAC,mBAAmB,CAuBtE,CAAC"}
@@ -4,7 +4,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
4
  * @fileoverview NavigationItem component
5
5
  * @description Universal navigation item component with icon and label
6
6
  *
7
- * @version 0.0.1
7
+ * @version 0.0.2
8
8
  * @since 0.0.1
9
9
  * @author AMBROISE PARK Consulting
10
10
  */
@@ -12,16 +12,32 @@ import { Link as LinkIcon } from 'lucide-react';
12
12
  import { navigationMenuTriggerStylePrimitive } from '@donotdev/components';
13
13
  import { Link } from './Link';
14
14
  import { Icon } from '../components/common/icon';
15
+ import { useNavigationItems } from './useNavigation';
15
16
  /**
16
- * Universal NavigationItem component
17
- * Handles icon + label + link in one place
18
- * Used everywhere in the framework
17
+ * Universal NavigationItem component — nav-trigger style link with icon + label.
19
18
  *
20
- * @version 0.0.1
19
+ * Used internally in menus, sidebars, and dropdowns.
20
+ * Pass `path` to auto-resolve label, icon, and active state from the navigation store.
21
+ * Pass `route` for an explicit one-off item not registered in the store.
22
+ *
23
+ * For standalone Button-style navigation (e.g. header end slot), use
24
+ * `useNavigationRoute(path)` and compose with `Button` + `render` prop directly.
25
+ *
26
+ * @version 0.0.2
21
27
  * @since 0.0.1
22
28
  * @author AMBROISE PARK Consulting
29
+ *
30
+ * @example
31
+ * ```tsx
32
+ * <NavigationItemComponent path="/pricing" />
33
+ * <NavigationItemComponent route={{ path: '/pricing', label: t('pricing'), icon: Tag }} />
34
+ * ```
23
35
  */
24
- export const NavigationItemComponent = ({ route, showIcons = true, }) => {
36
+ export const NavigationItemComponent = ({ path, route: routeProp, showIcons = true, }) => {
37
+ const allItems = useNavigationItems();
38
+ const route = routeProp ?? allItems.find((item) => item.path === path);
39
+ if (!route)
40
+ return null;
25
41
  const hasIcon = showIcons && !!route.icon;
26
42
  const hasLabel = !!route.label;
27
43
  return (_jsxs(Link, { path: route.path, className: navigationMenuTriggerStylePrimitive(), ...(hasIcon && !hasLabel && { 'data-display': 'compact' }), children: [showIcons && _jsx(Icon, { icon: route.icon, fallback: LinkIcon }), _jsx("span", { children: route.label })] }));
@@ -1 +1 @@
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
+ "use client";import{useRouter as p}from"next/navigation";import{useCallback as h}from"react";import{isClient as D,useOverlayStore as v}from"@donotdev/core";import*as F from"@donotdev/crud";var y={forms:{},startSubmit:()=>{},setUploading:()=>{},setValidating:()=>{},setSubmitting:()=>{},setSuccess:()=>{},setError:()=>{},reset:()=>{},cleanup:()=>{},setIsDirty:()=>{},hasDirtyForms:()=>!1,getDirtyFormIds:()=>[],getStatus:()=>"idle",isLoading:()=>!1,getUploadProgress:()=>0,getError:()=>null,getIsDirty:()=>!1},m=F?.useFormStore;function x(e){return m?m(e):e(y)}x.getState=()=>m&&typeof m.getState=="function"?m.getState():y;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=p(),t=v(r=>r.closeAll);return h(async(r,u)=>{if(r==="back")return t(),e.back();if(await T()){if(t(),u?.preserveScroll&&D()){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 w(){let e=p();return h(()=>e.back(),[e])}function E(){let e=p();return h(()=>e.refresh(),[e])}function b(){let e=p();return h(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 O}from"next/navigation";function S(){return O()}function G(e){let r=S()[e];if(typeof r=="string")return r;if(Array.isArray(r)&&r.length>0)return r[0]}import{useSearchParams as C}from"next/navigation";function R(){return C()}import{usePathname as L}from"next/navigation";function _(e){let t=L(),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 A}from"react";function U(){let e=R(),t=g(),r=f(),u=A((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=A(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=A(()=>{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 K}from"@donotdev/core";var k=$?.useAuth;function M(e){return K[e]}function d(e){return k?k(e):M(e)}function B(e={}){let{auth:t,redirectTo:r,condition:u}=e,i=f(),o=Y(),s=d("user"),n=d("can"),c=d("status");return Q(()=>{if(!j())return{shouldRedirect:!1,redirectTo:null,isChecking:!1};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{w as useBack,f as useLocation,_ as useMatch,g as useNavigate,S as useParams,b as usePrefetch,U as useQueryParams,B as useRedirectGuard,E as useRefresh,G as useRouteParam,R as useSearchParams};
@@ -1 +1 @@
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};
1
+ "use client";import{useCallback as p}from"react";import{useNavigate as T}from"react-router-dom";import{isClient as k,useOverlayStore as D}from"@donotdev/core";import*as F from"@donotdev/crud";var y={forms:{},startSubmit:()=>{},setUploading:()=>{},setValidating:()=>{},setSubmitting:()=>{},setSuccess:()=>{},setError:()=>{},reset:()=>{},cleanup:()=>{},setIsDirty:()=>{},hasDirtyForms:()=>!1,getDirtyFormIds:()=>[],getStatus:()=>"idle",isLoading:()=>!1,getUploadProgress:()=>0,getError:()=>null,getIsDirty:()=>!1},f=F?.useFormStore;function P(e){return f?f(e):e(y)}P.getState=()=>f&&typeof f.getState=="function"?f.getState():y;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=D(r=>r.closeAll);return p(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 p(()=>e(-1),[e])}function E(){return p(()=>{k()&&window.location.reload()},[])}function b(){return p(e=>{},[])}import{useLocation as I}from"react-router-dom";function m(){return I()}import{useParams as L}from"react-router-dom";function g(){return L()}function O(e){let r=g()[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 R(){return G()[0]}import{useMatch as C}from"react-router-dom";function _(e){return C(e)}import{useCallback as S}from"react";function N(){let e=R(),t=h(),r=m(),c=S((n,i)=>{let a=new URLSearchParams(e.toString());a.set(n,i);let l=a.toString(),A=`${r.pathname||"/"}${l?`?${l}`:""}`;t(A)},[e,t,r.pathname]),u=S(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=S(()=>{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 U from"@donotdev/auth";import{DEGRADED_AUTH_API as M}from"@donotdev/core";var v=U?.useAuth;function K(e){return M[e]}function d(e){return v?v(e):K(e)}function B(e={}){let{auth:t,redirectTo:r,condition:c}=e,u=m(),s=q(),n=d("user"),i=d("can"),a=d("status");return $(()=>{if(!Q())return{shouldRedirect:!1,redirectTo:null,isChecking:!1};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,_ as useMatch,h as useNavigate,g as useParams,b as usePrefetch,N as useQueryParams,B as useRedirectGuard,E as useRefresh,O as useRouteParam,R as useSearchParams};
@@ -1 +1 @@
1
- {"version":3,"file":"useRedirectGuard.next.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useRedirectGuard.next.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAK9D,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,IAAI,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC;IACxB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mEAAmE;IACnE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC;CAC3D;AAED,MAAM,WAAW,mBAAmB;IAClC,qCAAqC;IACrC,cAAc,EAAE,OAAO,CAAC;IACxB,uDAAuD;IACvD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gDAAgD;IAChD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CA4GrB"}
1
+ {"version":3,"file":"useRedirectGuard.next.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useRedirectGuard.next.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAK9D,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,IAAI,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC;IACxB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mEAAmE;IACnE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC;CAC3D;AAED,MAAM,WAAW,mBAAmB;IAClC,qCAAqC;IACrC,cAAc,EAAE,OAAO,CAAC;IACxB,uDAAuD;IACvD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gDAAgD;IAChD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CA6GrB"}
@@ -24,14 +24,7 @@ import { useAuthSafe } from '../../utils/useAuthSafe';
24
24
  */
25
25
  export function useRedirectGuard(options = {}) {
26
26
  const { auth, redirectTo: customRedirectTo, condition } = options;
27
- // SSR-safe: return safe defaults on server
28
- if (!isClient()) {
29
- return {
30
- shouldRedirect: false,
31
- redirectTo: null,
32
- isChecking: false,
33
- };
34
- }
27
+ // Hooks must be called unconditionally (Rules of Hooks)
35
28
  const location = useLocation();
36
29
  const authConfig = useAuthConfig();
37
30
  const user = useAuthSafe('user');
@@ -39,6 +32,14 @@ export function useRedirectGuard(options = {}) {
39
32
  const status = useAuthSafe('status');
40
33
  // Determine redirect state
41
34
  const redirectState = useMemo(() => {
35
+ // SSR-safe: return safe defaults on server
36
+ if (!isClient()) {
37
+ return {
38
+ shouldRedirect: false,
39
+ redirectTo: null,
40
+ isChecking: false,
41
+ };
42
+ }
42
43
  // Only INITIALIZING = still checking. DEGRADED/ERROR/READY = auth resolved (proceed with current user)
43
44
  if (status === FEATURE_STATUS.INITIALIZING) {
44
45
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"useRedirectGuard.vite.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useRedirectGuard.vite.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAK9D,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,IAAI,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC;IACxB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mEAAmE;IACnE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC;CAC3D;AAED,MAAM,WAAW,mBAAmB;IAClC,qCAAqC;IACrC,cAAc,EAAE,OAAO,CAAC;IACxB,uDAAuD;IACvD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gDAAgD;IAChD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CA4GrB"}
1
+ {"version":3,"file":"useRedirectGuard.vite.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useRedirectGuard.vite.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAK9D,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,IAAI,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC;IACxB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mEAAmE;IACnE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC;CAC3D;AAED,MAAM,WAAW,mBAAmB;IAClC,qCAAqC;IACrC,cAAc,EAAE,OAAO,CAAC;IACxB,uDAAuD;IACvD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gDAAgD;IAChD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CA6GrB"}