@donotdev/ui 0.0.13 → 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 (147) 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 +2 -2
  6. package/dist/components/common/ProgressBar.js +2 -2
  7. package/dist/components/common/TechBento.d.ts +14 -2
  8. package/dist/components/common/TechBento.d.ts.map +1 -1
  9. package/dist/components/common/TechBento.js +8 -9
  10. package/dist/components/cookie-consent/CookieConsent.d.ts.map +1 -1
  11. package/dist/components/cookie-consent/CookieConsent.js +3 -4
  12. package/dist/components/layout/components/DropdownNavigation.d.ts.map +1 -1
  13. package/dist/components/layout/components/DropdownNavigation.js +3 -12
  14. package/dist/components/layout/components/FloatingLanguageSwitcher.js +1 -1
  15. package/dist/components/layout/components/Notifications.d.ts +1 -3
  16. package/dist/components/layout/components/Notifications.d.ts.map +1 -1
  17. package/dist/components/layout/components/Notifications.js +4 -2
  18. package/dist/components/layout/components/header/AppBranding.d.ts.map +1 -1
  19. package/dist/components/layout/components/header/AppBranding.js +2 -1
  20. package/dist/components/layout/components/header/AppIcon.d.ts.map +1 -1
  21. package/dist/components/layout/components/header/AppIcon.js +5 -2
  22. package/dist/components/layout/components/header/CacheSettings.d.ts.map +1 -1
  23. package/dist/components/layout/components/header/CacheSettings.js +3 -1
  24. package/dist/components/layout/components/header/HeaderNavigation.d.ts +6 -0
  25. package/dist/components/layout/components/header/HeaderNavigation.d.ts.map +1 -1
  26. package/dist/components/layout/components/header/HeaderNavigation.js +12 -2
  27. package/dist/components/license/LicenseWatermark.d.ts.map +1 -1
  28. package/dist/components/license/LicenseWatermark.js +3 -1
  29. package/dist/crud/components/CrudCardLink.d.ts +17 -0
  30. package/dist/crud/components/CrudCardLink.d.ts.map +1 -0
  31. package/dist/crud/components/CrudCardLink.js +17 -0
  32. package/dist/crud/components/EntityCardList.d.ts.map +1 -1
  33. package/dist/crud/components/EntityCardList.js +24 -79
  34. package/dist/crud/components/EntityDisplayRenderer.d.ts +1 -1
  35. package/dist/crud/components/EntityDisplayRenderer.d.ts.map +1 -1
  36. package/dist/crud/components/EntityDisplayRenderer.js +6 -2
  37. package/dist/crud/components/EntityFormRenderer.d.ts +1 -1
  38. package/dist/crud/components/EntityFormRenderer.d.ts.map +1 -1
  39. package/dist/crud/components/EntityFormRenderer.js +29 -18
  40. package/dist/crud/components/EntityList.d.ts +1 -1
  41. package/dist/crud/components/EntityList.d.ts.map +1 -1
  42. package/dist/crud/components/EntityList.js +1 -1
  43. package/dist/crud/components/EntityRecommendations.d.ts +28 -0
  44. package/dist/crud/components/EntityRecommendations.d.ts.map +1 -0
  45. package/dist/crud/components/EntityRecommendations.js +31 -0
  46. package/dist/crud/components/index.d.ts +2 -1
  47. package/dist/crud/components/index.d.ts.map +1 -1
  48. package/dist/crud/components/index.js +1 -0
  49. package/dist/index.js +4 -4
  50. package/dist/internal/common/RouteErrorFallback.d.ts.map +1 -1
  51. package/dist/internal/devtools/components/AuthDebugButton.js +1 -1
  52. package/dist/internal/devtools/components/DesignTab.d.ts.map +1 -1
  53. package/dist/internal/devtools/components/DesignTab.js +3 -2
  54. package/dist/internal/devtools/components/LayoutReset.d.ts.map +1 -1
  55. package/dist/internal/devtools/components/LayoutReset.js +2 -0
  56. package/dist/internal/devtools/components/StoresTab.d.ts.map +1 -1
  57. package/dist/internal/devtools/components/StoresTab.js +3 -0
  58. package/dist/internal/devtools/utils/envVarDiscovery.d.ts +1 -0
  59. package/dist/internal/devtools/utils/envVarDiscovery.d.ts.map +1 -1
  60. package/dist/internal/devtools/utils/envVarDiscovery.js +5 -0
  61. package/dist/internal/devtools/utils/virtualModuleInspector.d.ts.map +1 -1
  62. package/dist/internal/devtools/utils/virtualModuleInspector.js +27 -21
  63. package/dist/internal/initializers/BaseStoresInitializer.d.ts.map +1 -1
  64. package/dist/internal/initializers/BaseStoresInitializer.js +30 -6
  65. package/dist/internal/layout/components/AutoMetaTags.d.ts.map +1 -1
  66. package/dist/internal/layout/components/AutoMetaTags.js +10 -8
  67. package/dist/internal/layout/components/FontPreloadLinks.d.ts +16 -0
  68. package/dist/internal/layout/components/FontPreloadLinks.d.ts.map +1 -0
  69. package/dist/internal/layout/components/FontPreloadLinks.js +32 -0
  70. package/dist/internal/layout/components/PerformanceHints.d.ts +7 -12
  71. package/dist/internal/layout/components/PerformanceHints.d.ts.map +1 -1
  72. package/dist/internal/layout/components/PerformanceHints.js +8 -12
  73. package/dist/internal/layout/components/footer/useLegalLinks.d.ts +6 -5
  74. package/dist/internal/layout/components/footer/useLegalLinks.d.ts.map +1 -1
  75. package/dist/internal/layout/components/footer/useLegalLinks.js +6 -2
  76. package/dist/internal/layout/zones/DnDevFooter.d.ts +6 -0
  77. package/dist/internal/layout/zones/DnDevFooter.d.ts.map +1 -1
  78. package/dist/internal/layout/zones/DnDevFooter.js +10 -4
  79. package/dist/internal/layout/zones/DnDevHeader.d.ts +7 -0
  80. package/dist/internal/layout/zones/DnDevHeader.d.ts.map +1 -1
  81. package/dist/internal/layout/zones/DnDevHeader.js +7 -0
  82. package/dist/internal/layout/zones/DnDevMergedBar.d.ts +7 -0
  83. package/dist/internal/layout/zones/DnDevMergedBar.d.ts.map +1 -1
  84. package/dist/internal/layout/zones/DnDevMergedBar.js +9 -0
  85. package/dist/internal/layout/zones/DnDevSidebar.d.ts +4 -0
  86. package/dist/internal/layout/zones/DnDevSidebar.d.ts.map +1 -1
  87. package/dist/internal/layout/zones/DnDevSidebar.js +13 -1
  88. package/dist/next.d.ts +1 -0
  89. package/dist/next.d.ts.map +1 -1
  90. package/dist/next.js +1 -0
  91. package/dist/routing/AuthGuard.d.ts +1 -1
  92. package/dist/routing/AuthGuard.d.ts.map +1 -1
  93. package/dist/routing/AuthGuard.js +3 -1
  94. package/dist/routing/GoTo.d.ts.map +1 -1
  95. package/dist/routing/GoTo.js +3 -1
  96. package/dist/routing/GoToDialog.d.ts.map +1 -1
  97. package/dist/routing/GoToDialog.js +2 -7
  98. package/dist/routing/GoToInput.d.ts +0 -3
  99. package/dist/routing/GoToInput.d.ts.map +1 -1
  100. package/dist/routing/GoToInput.js +4 -2
  101. package/dist/routing/Link.js +1 -1
  102. package/dist/routing/NavigationItem.d.ts +29 -7
  103. package/dist/routing/NavigationItem.d.ts.map +1 -1
  104. package/dist/routing/NavigationItem.js +22 -6
  105. package/dist/routing/hooks/hooks.next.js +1 -1
  106. package/dist/routing/hooks/hooks.vite.js +1 -1
  107. package/dist/routing/hooks/useRedirectGuard.next.d.ts.map +1 -1
  108. package/dist/routing/hooks/useRedirectGuard.next.js +9 -8
  109. package/dist/routing/hooks/useRedirectGuard.vite.d.ts.map +1 -1
  110. package/dist/routing/hooks/useRedirectGuard.vite.js +9 -8
  111. package/dist/routing/hooks/useSearchParams.next.d.ts +18 -1
  112. package/dist/routing/hooks/useSearchParams.next.d.ts.map +1 -1
  113. package/dist/routing/hooks/useSearchParams.next.js +16 -0
  114. package/dist/routing/hooks/useSearchParams.vite.d.ts +16 -0
  115. package/dist/routing/hooks/useSearchParams.vite.d.ts.map +1 -1
  116. package/dist/routing/hooks/useSearchParams.vite.js +17 -1
  117. package/dist/routing/index.d.ts.map +1 -1
  118. package/dist/routing/index.js +2 -0
  119. package/dist/routing/useNavigation.d.ts +30 -0
  120. package/dist/routing/useNavigation.d.ts.map +1 -1
  121. package/dist/routing/useNavigation.js +40 -3
  122. package/dist/routing/useRouteDiscovery.d.ts +2 -2
  123. package/dist/routing/useRouteDiscovery.d.ts.map +1 -1
  124. package/dist/routing/useRouteDiscovery.js +10 -4
  125. package/dist/styles/index.css +268 -82
  126. package/dist/utils/index.d.ts +1 -0
  127. package/dist/utils/index.d.ts.map +1 -1
  128. package/dist/utils/index.js +1 -0
  129. package/dist/utils/sanitizeSvg.d.ts +13 -0
  130. package/dist/utils/sanitizeSvg.d.ts.map +1 -0
  131. package/dist/utils/sanitizeSvg.js +47 -0
  132. package/dist/utils/useBillingVisibility.d.ts.map +1 -1
  133. package/dist/utils/useBillingVisibility.js +0 -7
  134. package/dist/utils/useCrudSafe.d.ts +0 -2
  135. package/dist/utils/useCrudSafe.d.ts.map +1 -1
  136. package/dist/utils/useFormStoreSafe.d.ts +3 -1
  137. package/dist/utils/useFormStoreSafe.d.ts.map +1 -1
  138. package/dist/utils/useFormStoreSafe.js +4 -5
  139. package/dist/vite-routing/AppRoutes.d.ts +19 -8
  140. package/dist/vite-routing/AppRoutes.d.ts.map +1 -1
  141. package/dist/vite-routing/AppRoutes.js +0 -3
  142. package/package.json +15 -11
  143. package/assets/fonts/fonts.css +0 -206
  144. package/dist/dndev.css +0 -10733
  145. package/dist/routing/Navigate.d.ts +0 -10
  146. package/dist/routing/Navigate.d.ts.map +0 -1
  147. package/dist/routing/Navigate.js +0 -10
@@ -1 +1 @@
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"}
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,CAoPrE,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -62,7 +62,7 @@ export const AuthDebugButton = () => {
62
62
  zIndex: 'calc(var(--z-toast) + 100)',
63
63
  marginBottom: 'var(--gap-sm)',
64
64
  padding: 'var(--gap-md)',
65
- right: 0,
65
+ insetInlineEnd: 0,
66
66
  backgroundColor: 'rgba(0, 0, 0, 0.9)',
67
67
  color: 'white',
68
68
  borderRadius: 'var(--radius-lg)',
@@ -1 +1 @@
1
- {"version":3,"file":"DesignTab.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/components/DesignTab.tsx"],"names":[],"mappings":"AA+CA,eAAO,MAAM,SAAS,+CA2yBrB,CAAC"}
1
+ {"version":3,"file":"DesignTab.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/components/DesignTab.tsx"],"names":[],"mappings":"AA+CA,eAAO,MAAM,SAAS,+CA4yBrB,CAAC"}
@@ -416,10 +416,11 @@ export const DesignTab = () => {
416
416
  return normalizeFontSize(style.fontSize) === normalizedSize;
417
417
  });
418
418
  found.forEach((el) => {
419
- console.log(el, el.textContent?.trim().substring(0, 50));
419
+ // Log text content only (not the DOM node) to avoid memory leaks from retained element refs
420
+ console.log('[DesignTab]', el.textContent?.trim().substring(0, 50));
420
421
  el.style.outline = '2px solid red';
421
422
  });
422
- console.log(`Found ${found.length} elements with ${f.size}`);
423
+ console.log(`[DesignTab] Found ${found.length} elements with ${f.size}`);
423
424
  };
424
425
  return (_jsxs(Stack, { direction: "row", justify: "between", align: "center", gap: "tight", style: {
425
426
  padding: 'var(--gap-sm)',
@@ -1 +1 @@
1
- {"version":3,"file":"LayoutReset.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/components/LayoutReset.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,eAAO,MAAM,WAAW,EAAE,aAoOxB,CAAC"}
1
+ {"version":3,"file":"LayoutReset.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/components/LayoutReset.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,eAAO,MAAM,WAAW,EAAE,aAqOxB,CAAC"}
@@ -20,6 +20,8 @@ export const LayoutReset = memo(() => {
20
20
  return;
21
21
  if (!isClient())
22
22
  return; // SSR guard
23
+ if (process.env.NODE_ENV !== 'development')
24
+ return; // DevTools only
23
25
  setIsResetting(true);
24
26
  try {
25
27
  // Clear all caches and stores (comprehensive reset)
@@ -1 +1 @@
1
- {"version":3,"file":"StoresTab.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/components/StoresTab.tsx"],"names":[],"mappings":"AAwCA,eAAO,MAAM,SAAS,+CAoHrB,CAAC"}
1
+ {"version":3,"file":"StoresTab.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/components/StoresTab.tsx"],"names":[],"mappings":"AAwCA,eAAO,MAAM,SAAS,+CAsHrB,CAAC"}
@@ -53,6 +53,9 @@ export const StoresTab = () => {
53
53
  setStoreStates(states);
54
54
  }, []);
55
55
  useEffect(() => {
56
+ // StoresTab is only rendered inside DevTools (dev-only), but guard defensively
57
+ if (process.env.NODE_ENV !== 'development')
58
+ return;
56
59
  refreshStores();
57
60
  const interval = setInterval(refreshStores, 1000);
58
61
  return () => clearInterval(interval);
@@ -15,6 +15,7 @@ export declare function discoverEnvVarsByPattern(env: Record<string, string>, pa
15
15
  export declare function groupEnvVarsByCategory(env: Record<string, string>): {
16
16
  stripe?: Record<string, string>;
17
17
  firebase?: Record<string, string>;
18
+ supabase?: Record<string, string>;
18
19
  oauth?: Record<string, string>;
19
20
  emulator?: Record<string, string>;
20
21
  other?: Record<string, string>;
@@ -1 +1 @@
1
- {"version":3,"file":"envVarDiscovery.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/utils/envVarDiscovery.ts"],"names":[],"mappings":"AA8BA;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,QAAQ,EAAE,MAAM,EAAE,GACjB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWxB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC,CA2CA;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,QAAQ,EAAE,MAAM,EAAE,GACjB,MAAM,GAAG,SAAS,CAOpB"}
1
+ {"version":3,"file":"envVarDiscovery.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/utils/envVarDiscovery.ts"],"names":[],"mappings":"AA8BA;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,QAAQ,EAAE,MAAM,EAAE,GACjB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWxB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC,CA+CA;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,QAAQ,EAAE,MAAM,EAAE,GACjB,MAAM,GAAG,SAAS,CAOpB"}
@@ -62,6 +62,11 @@ export function groupEnvVarsByCategory(env) {
62
62
  result.firebase = {};
63
63
  result.firebase[key] = value;
64
64
  }
65
+ else if (matchesPattern(key, '*SUPABASE*')) {
66
+ if (!result.supabase)
67
+ result.supabase = {};
68
+ result.supabase[key] = value;
69
+ }
65
70
  else if (matchesPattern(key, '*OAUTH*') ||
66
71
  matchesPattern(key, '*GOOGLE*CLIENT*') ||
67
72
  matchesPattern(key, '*GITHUB*CLIENT*') ||
@@ -1 +1 @@
1
- {"version":3,"file":"virtualModuleInspector.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/utils/virtualModuleInspector.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EACV,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,OAAO,EAER,MAAM,UAAU,CAAC;AAElB,qBAAa,sBAAsB;WACpB,eAAe,IAAI,OAAO,CAAC,mBAAmB,CAAC;WAwE/C,cAAc,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAyD3D,MAAM,CAAC,sBAAsB,IAAI,UAAU;IAoB3C,MAAM,CAAC,kBAAkB,IAAI,OAAO;WAgGvB,kBAAkB,IAAI,OAAO,CAAC,iBAAiB,CAAC;CAgF9D"}
1
+ {"version":3,"file":"virtualModuleInspector.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/utils/virtualModuleInspector.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EACV,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,OAAO,EAER,MAAM,UAAU,CAAC;AAElB,qBAAa,sBAAsB;WACpB,eAAe,IAAI,OAAO,CAAC,mBAAmB,CAAC;WA4E/C,cAAc,IAAI,OAAO,CAAC,mBAAmB,CAAC;IA2D3D,MAAM,CAAC,sBAAsB,IAAI,UAAU;IAoB3C,MAAM,CAAC,kBAAkB,IAAI,OAAO;WAgGvB,kBAAkB,IAAI,OAAO,CAAC,iBAAiB,CAAC;CAgF9D"}
@@ -36,12 +36,14 @@ export class VirtualModuleInspector {
36
36
  }
37
37
  }
38
38
  const tokenCount = Object.keys(designTokens).length;
39
- console.log('🎯 Design Tokens:', {
40
- platform,
41
- tokenCount,
42
- sampleTokens: Object.keys(designTokens).slice(0, 5),
43
- source,
44
- });
39
+ if (process.env.NODE_ENV === 'development') {
40
+ console.log('[VirtualModuleInspector] Design Tokens:', {
41
+ platform,
42
+ tokenCount,
43
+ sampleTokens: Object.keys(designTokens).slice(0, 5),
44
+ source,
45
+ });
46
+ }
45
47
  return {
46
48
  success: true,
47
49
  data: {
@@ -58,16 +60,18 @@ export class VirtualModuleInspector {
58
60
  }
59
61
  catch (error) {
60
62
  const errorMessage = error instanceof Error ? error.message : String(error);
61
- console.group('❌ Design Tokens Failed');
62
- console.error('Error:', errorMessage);
63
- console.log('Platform:', detectPlatform());
64
- console.log('Environment:', {
65
- isClient: typeof window !== 'undefined',
66
- hasConfig: !!getDndevConfig(),
67
- hasThemes: !!getDndevConfig()?.themes,
68
- hasVariables: !!getDndevConfig()?.themes?.variables,
69
- });
70
- console.groupEnd();
63
+ if (process.env.NODE_ENV === 'development') {
64
+ console.group('[VirtualModuleInspector] Design Tokens Failed');
65
+ console.error('Error:', errorMessage);
66
+ console.log('Platform:', detectPlatform());
67
+ console.log('Environment:', {
68
+ isClient: typeof window !== 'undefined',
69
+ hasConfig: !!getDndevConfig(),
70
+ hasThemes: !!getDndevConfig()?.themes,
71
+ hasVariables: !!getDndevConfig()?.themes?.variables,
72
+ });
73
+ console.groupEnd();
74
+ }
71
75
  return {
72
76
  success: false,
73
77
  data: null,
@@ -100,11 +104,13 @@ export class VirtualModuleInspector {
100
104
  console.warn('Failed to fetch i18n from API route:', error);
101
105
  }
102
106
  }
103
- console.log('🌐 i18n Mapping:', {
104
- platform,
105
- namespaces: Object.keys(i18nMapping),
106
- source,
107
- });
107
+ if (process.env.NODE_ENV === 'development') {
108
+ console.log('🌐 i18n Mapping:', {
109
+ platform,
110
+ namespaces: Object.keys(i18nMapping),
111
+ source,
112
+ });
113
+ }
108
114
  return {
109
115
  success: true,
110
116
  data: {
@@ -1 +1 @@
1
- {"version":3,"file":"BaseStoresInitializer.d.ts","sourceRoot":"","sources":["../../../src/internal/initializers/BaseStoresInitializer.tsx"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAa,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AA4DvC;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACnC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAyGD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,QAAQ,EACR,QAAQ,EACR,YAAiB,EACjB,aAAqB,EACrB,aAAa,GACd,EAAE,0BAA0B,kDAgJ5B"}
1
+ {"version":3,"file":"BaseStoresInitializer.d.ts","sourceRoot":"","sources":["../../../src/internal/initializers/BaseStoresInitializer.tsx"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAa,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AA4DvC;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACnC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAyGD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,QAAQ,EACR,QAAQ,EACR,YAAiB,EACjB,aAAqB,EACrB,aAAa,GACd,EAAE,0BAA0B,kDA+K5B"}
@@ -9,7 +9,7 @@ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
9
9
  * @since 0.0.1
10
10
  * @author AMBROISE PARK Consulting
11
11
  */
12
- import { useEffect, useLayoutEffect, useRef } from 'react';
12
+ import { useEffect, useLayoutEffect, useRef, useState } from 'react';
13
13
  import { useThemeStore, useNavigationStore, useOverlayStore, useNetworkStore, useAbortControllerStore, useConsentStore, useConsentReady, useThemeReady, getPlatformEnvVar, } from '@donotdev/core';
14
14
  import { useI18nReady } from '@donotdev/core';
15
15
  import { handleError, isClient, getDndevConfig, globalEmitter, } from '@donotdev/core';
@@ -224,12 +224,36 @@ export function BaseStoresInitializer({ children, handlers, customStores = [], s
224
224
  const themeReady = useThemeReady();
225
225
  const i18nReady = useI18nReady();
226
226
  const criticalCustomStores = customStores.filter((config) => config.type === 'critical');
227
- const customReadiness = criticalCustomStores.map((config) => {
228
- const store = config.store;
229
- return store((state) => ('isReady' in state ? state.isReady : false));
227
+ // Track custom store readiness via subscriptions — never call hooks inside .map()
228
+ const [allCustomReady, setAllCustomReady] = useState(() => {
229
+ if (criticalCustomStores.length === 0)
230
+ return true;
231
+ return criticalCustomStores.every((config) => {
232
+ const state = config.store.getState();
233
+ return 'isReady' in state && state.isReady === true;
234
+ });
230
235
  });
231
- const allCustomReady = criticalCustomStores.length === 0 ||
232
- customReadiness.every((ready) => ready === true);
236
+ useEffect(() => {
237
+ if (criticalCustomStores.length === 0) {
238
+ setAllCustomReady(true);
239
+ return;
240
+ }
241
+ const checkAll = () => criticalCustomStores.every((config) => {
242
+ const state = config.store.getState();
243
+ return 'isReady' in state && state.isReady === true;
244
+ });
245
+ // Subscribe to each critical custom store for readiness updates
246
+ const unsubscribers = criticalCustomStores.map((config) => config.store.subscribe(() => {
247
+ setAllCustomReady(checkAll());
248
+ }));
249
+ // Initial check in case stores became ready before subscriptions were set up
250
+ setAllCustomReady(checkAll());
251
+ return () => {
252
+ unsubscribers.forEach((unsub) => unsub());
253
+ };
254
+ // criticalCustomStores reference changes only when customStores prop changes
255
+ // eslint-disable-next-line react-hooks/exhaustive-deps
256
+ }, [customStores]);
233
257
  const criticalReady = consentReady && themeReady && i18nReady && allCustomReady;
234
258
  // Two-phase loader: wait for BOTH framework AND route to be ready
235
259
  useLayoutEffect(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"AutoMetaTags.d.ts","sourceRoot":"","sources":["../../../../src/internal/layout/components/AutoMetaTags.tsx"],"names":[],"mappings":"AA0DA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAyE3C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,EAAE,aAoN1B,CAAC;AAEF;;;GAGG;AAEH,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"AutoMetaTags.d.ts","sourceRoot":"","sources":["../../../../src/internal/layout/components/AutoMetaTags.tsx"],"names":[],"mappings":"AA0DA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAyE3C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,EAAE,aAmN1B,CAAC;AAEF;;;GAGG;AAEH,eAAe,YAAY,CAAC"}
@@ -122,16 +122,15 @@ export const AutoMetaTags = () => {
122
122
  const location = useLocation();
123
123
  const seoConfig = useSeoConfig();
124
124
  const isClient = useIsClient();
125
- // Return null if SEO is disabled
126
- if (!seoConfig)
127
- return null;
128
- const { defaultNamespace = 'home', defaultImage, twitterHandle, staticTags = {}, } = seoConfig;
129
125
  const siteName = useAppConfig('name');
130
126
  const baseUrl = getPlatformEnvVar('APP_URL') || '';
131
- // Get route metadata
127
+ // Get route metadata — computed from current pathname and client flag
132
128
  const routeMeta = getRouteMetadata(location.pathname, isClient);
133
- // Memoize computed values for performance
129
+ // Memoize computed values for performance — must be called before any early return
134
130
  const metaData = useMemo(() => {
131
+ if (!seoConfig)
132
+ return null;
133
+ const { defaultNamespace = 'home', defaultImage, } = seoConfig;
135
134
  // Construct absolute URL for canonical link
136
135
  const currentUrl = `${baseUrl}${location.pathname}`;
137
136
  const ns = routeMeta.ns || defaultNamespace;
@@ -175,10 +174,13 @@ export const AutoMetaTags = () => {
175
174
  routeMeta,
176
175
  siteName,
177
176
  baseUrl,
178
- defaultNamespace,
179
- defaultImage,
177
+ seoConfig,
180
178
  t,
181
179
  ]);
180
+ // Return null if SEO is disabled — after all hooks have been called
181
+ if (!seoConfig || !metaData)
182
+ return null;
183
+ const { twitterHandle, staticTags = {} } = seoConfig;
182
184
  return (_jsxs(Helmet, { children: [_jsx("title", { children: metaData.title }), metaData.description && (_jsx("meta", { name: "description", content: metaData.description })), _jsx("link", { rel: "canonical", href: metaData.url }), metaData.keywords && (_jsx("meta", { name: "keywords", content: Array.isArray(metaData.keywords)
183
185
  ? metaData.keywords.join(', ')
184
186
  : metaData.keywords })), metaData.author && _jsx("meta", { name: "author", content: metaData.author }), metaData.noindex && _jsx("meta", { name: "robots", content: "noindex, nofollow" }), _jsx("meta", { property: "og:title", content: metaData.title }), metaData.description && (_jsx("meta", { property: "og:description", content: metaData.description })), _jsx("meta", { property: "og:url", content: metaData.url }), _jsx("meta", { property: "og:type", content: metaData.type }), metaData.image && _jsx("meta", { property: "og:image", content: metaData.image }), _jsx("meta", { property: "og:site_name", content: siteName }), metaData.type === 'article' && (_jsxs(_Fragment, { children: [metaData.author && (_jsx("meta", { property: "article:author", content: metaData.author })), metaData.publishDate && (_jsx("meta", { property: "article:published_time", content: metaData.publishDate })), metaData.modifiedDate && (_jsx("meta", { property: "article:modified_time", content: metaData.modifiedDate }))] })), _jsx("meta", { name: "twitter:card", content: "summary_large_image" }), _jsx("meta", { name: "twitter:title", content: metaData.title }), metaData.description && (_jsx("meta", { name: "twitter:description", content: metaData.description })), metaData.image && _jsx("meta", { name: "twitter:image", content: metaData.image }), twitterHandle && (_jsx("meta", { name: "twitter:site", content: `@${twitterHandle}` })), metaData.author && (_jsx("meta", { name: "twitter:creator", content: metaData.author })), _jsx("meta", { name: "format-detection", content: "telephone=no" }), _jsx("meta", { name: "mobile-web-app-capable", content: "yes" }), _jsx("meta", { name: "apple-mobile-web-app-status-bar-style", content: "default" }), Object.entries(staticTags).map(([name, content]) => (_jsx("meta", { name: name, content: content }, name))), metaData.image && metaData.image.startsWith('http') && (_jsx("link", { rel: "dns-prefetch", href: new URL(metaData.image).origin })), _jsx("script", { type: "application/ld+json", children: JSON.stringify({
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @fileoverview FontPreloadLinks - Server-only component for Next.js
3
+ * @description Reads public/dndev-font-preloads.json (written at build by FontPreloadWebpackPlugin) and renders preload link tags for Lighthouse-friendly LCP. Include in root layout so initial HTML contains the links.
4
+ *
5
+ * @version 0.0.1
6
+ * @since 0.0.1
7
+ * @author AMBROISE PARK Consulting
8
+ */
9
+ import type { ReactNode } from 'react';
10
+ /**
11
+ * Server component: renders preload links for fonts listed in public/dndev-font-preloads.json.
12
+ * No-op if manifest is missing or empty. Use in root layout.tsx for SSR preload in initial HTML.
13
+ */
14
+ export declare function FontPreloadLinks(): Promise<ReactNode>;
15
+ export default FontPreloadLinks;
16
+ //# sourceMappingURL=FontPreloadLinks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FontPreloadLinks.d.ts","sourceRoot":"","sources":["../../../../src/internal/layout/components/FontPreloadLinks.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AASvC;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,SAAS,CAAC,CA6B3D;AAED,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * @fileoverview FontPreloadLinks - Server-only component for Next.js
4
+ * @description Reads public/dndev-font-preloads.json (written at build by FontPreloadWebpackPlugin) and renders preload link tags for Lighthouse-friendly LCP. Include in root layout so initial HTML contains the links.
5
+ *
6
+ * @version 0.0.1
7
+ * @since 0.0.1
8
+ * @author AMBROISE PARK Consulting
9
+ */
10
+ import fs from 'node:fs/promises';
11
+ import path from 'node:path';
12
+ const MANIFEST_FILENAME = 'dndev-font-preloads.json';
13
+ /**
14
+ * Server component: renders preload links for fonts listed in public/dndev-font-preloads.json.
15
+ * No-op if manifest is missing or empty. Use in root layout.tsx for SSR preload in initial HTML.
16
+ */
17
+ export async function FontPreloadLinks() {
18
+ const manifestPath = path.join(process.cwd(), 'public', MANIFEST_FILENAME);
19
+ let entries = [];
20
+ try {
21
+ const content = await fs.readFile(manifestPath, 'utf8');
22
+ const parsed = JSON.parse(content);
23
+ entries = Array.isArray(parsed) ? parsed : [];
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ if (entries.length === 0)
29
+ return null;
30
+ return (_jsx(_Fragment, { children: entries.map((e) => (_jsx("link", { rel: "preload", as: "font", href: e.href, type: e.type ?? 'font/woff2', crossOrigin: "anonymous" }, e.href))) }));
31
+ }
32
+ export default FontPreloadLinks;
@@ -19,9 +19,9 @@ interface PerformanceHintsProps {
19
19
  */
20
20
  dnsPrefetch?: string[];
21
21
  /**
22
- * Fonts to preload for faster LCP
23
- * Pass string[] for simple paths, or FontPreload[] for full control
24
- * @default ['/fonts/Inter-latin.woff2']
22
+ * Additional fonts to preload (optional). Framework injects preloads at build time for Vite/Next;
23
+ * use this prop only for extra or custom font URLs.
24
+ * @default []
25
25
  */
26
26
  fontPreloads?: (string | FontPreload)[];
27
27
  /**
@@ -43,18 +43,13 @@ interface PerformanceHintsProps {
43
43
  *
44
44
  * @example
45
45
  * ```tsx
46
- * // Use defaults (preloads Inter-latin.woff2)
46
+ * // Default: preconnect/dns-prefetch only; font preload handled by framework build (Vite/Next)
47
47
  * <PerformanceHints />
48
48
  *
49
- * // Custom font preloads
50
- * <PerformanceHints fontPreloads={['/fonts/Roboto-400-latin.woff2']} />
49
+ * // Add custom font preload URLs
50
+ * <PerformanceHints fontPreloads={[customFontUrl]} />
51
51
  *
52
- * // Full control over font preload
53
- * <PerformanceHints
54
- * fontPreloads={[{ href: '/fonts/Custom.woff2', type: 'font/woff2' }]}
55
- * />
56
- *
57
- * // Disable font preloads (e.g., when using next/font)
52
+ * // Disable font preloads
58
53
  * <PerformanceHints disableFontPreloads />
59
54
  * ```
60
55
  */
@@ -1 +1 @@
1
- {"version":3,"file":"PerformanceHints.d.ts","sourceRoot":"","sources":["../../../../src/internal/layout/components/PerformanceHints.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAmC3C,UAAU,WAAW;IACnB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,WAAW,CAAC,EAAE,WAAW,GAAG,iBAAiB,CAAC;CAC/C;AAED,UAAU,qBAAqB;IAC7B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC;IACxC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,QAAA,MAAM,gBAAgB,EAAE,aAAa,CAAC,qBAAqB,CA6D1D,CAAC;AAEF,eAAe,gBAAgB,CAAC;AAChC,YAAY,EAAE,WAAW,EAAE,qBAAqB,EAAE,CAAC"}
1
+ {"version":3,"file":"PerformanceHints.d.ts","sourceRoot":"","sources":["../../../../src/internal/layout/components/PerformanceHints.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAoC3C,UAAU,WAAW;IACnB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,WAAW,CAAC,EAAE,WAAW,GAAG,iBAAiB,CAAC;CAC/C;AAED,UAAU,qBAAqB;IAC7B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC;IACxC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,gBAAgB,EAAE,aAAa,CAAC,qBAAqB,CA6D1D,CAAC;AAEF,eAAe,gBAAgB,CAAC;AAChC,YAAY,EAAE,WAAW,EAAE,qBAAqB,EAAE,CAAC"}
@@ -39,9 +39,10 @@ const DEFAULT_DNS_PREFETCH = [
39
39
  'https://www.googletagmanager.com',
40
40
  ];
41
41
  /**
42
- * Default critical fonts to preload
43
- * Empty by default - apps should specify their own fonts based on their font-display strategy
44
- * Note: Don't preload fonts with font-display: optional (they're meant to be non-blocking)
42
+ * Default critical fonts to preload.
43
+ * Empty: when using the framework's Vite or Next setup, font preload is handled by build-time
44
+ * injection (Vite: FontPreloadPlugin patches index.html; Next: FontPreloadLinks in root layout
45
+ * reads public/dndev-font-preloads.json). Pass fontPreloads only for extra/custom URLs.
45
46
  */
46
47
  const DEFAULT_FONT_PRELOADS = [];
47
48
  /**
@@ -52,18 +53,13 @@ const DEFAULT_FONT_PRELOADS = [];
52
53
  *
53
54
  * @example
54
55
  * ```tsx
55
- * // Use defaults (preloads Inter-latin.woff2)
56
+ * // Default: preconnect/dns-prefetch only; font preload handled by framework build (Vite/Next)
56
57
  * <PerformanceHints />
57
58
  *
58
- * // Custom font preloads
59
- * <PerformanceHints fontPreloads={['/fonts/Roboto-400-latin.woff2']} />
59
+ * // Add custom font preload URLs
60
+ * <PerformanceHints fontPreloads={[customFontUrl]} />
60
61
  *
61
- * // Full control over font preload
62
- * <PerformanceHints
63
- * fontPreloads={[{ href: '/fonts/Custom.woff2', type: 'font/woff2' }]}
64
- * />
65
- *
66
- * // Disable font preloads (e.g., when using next/font)
62
+ * // Disable font preloads
67
63
  * <PerformanceHints disableFontPreloads />
68
64
  * ```
69
65
  */
@@ -4,11 +4,12 @@ export interface FooterLegalLink {
4
4
  label: string;
5
5
  }
6
6
  /**
7
- * Hook to get the configured legal links
7
+ * Returns the configured legal links for the footer.
8
8
  * Handles the logic: null = hide, undefined = defaults, array = custom
9
+ *
10
+ * @remarks Not a hook — no React state or effects. Named with `get` prefix.
9
11
  */
10
- export declare const useLegalLinks: (footerConfig: AppMetadata["footer"]) => {
11
- path: string;
12
- label: string;
13
- }[];
12
+ export declare const getLegalLinks: (footerConfig: AppMetadata["footer"]) => FooterLegalLink[];
13
+ /** @deprecated Use getLegalLinks instead */
14
+ export declare const useLegalLinks: (footerConfig: AppMetadata["footer"]) => FooterLegalLink[];
14
15
  //# sourceMappingURL=useLegalLinks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLegalLinks.d.ts","sourceRoot":"","sources":["../../../../../src/internal/layout/components/footer/useLegalLinks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAQD;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,cAAc,WAAW,CAAC,QAAQ,CAAC;;;GAQhE,CAAC"}
1
+ {"version":3,"file":"useLegalLinks.d.ts","sourceRoot":"","sources":["../../../../../src/internal/layout/components/footer/useLegalLinks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAQD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,cAAc,WAAW,CAAC,QAAQ,CAAC,KAAG,eAAe,EAQlF,CAAC;AAEF,4CAA4C;AAC5C,eAAO,MAAM,aAAa,iBAXkB,WAAW,CAAC,QAAQ,CAAC,KAAG,eAAe,EAWzC,CAAC"}
@@ -5,10 +5,12 @@ const DEFAULT_LINKS = [
5
5
  { label: 'footer.legal.termsOfService', path: '/terms' },
6
6
  ];
7
7
  /**
8
- * Hook to get the configured legal links
8
+ * Returns the configured legal links for the footer.
9
9
  * Handles the logic: null = hide, undefined = defaults, array = custom
10
+ *
11
+ * @remarks Not a hook — no React state or effects. Named with `get` prefix.
10
12
  */
11
- export const useLegalLinks = (footerConfig) => {
13
+ export const getLegalLinks = (footerConfig) => {
12
14
  // If explicitly null, return empty array (hidden)
13
15
  if (footerConfig?.legalLinks === null) {
14
16
  return [];
@@ -16,3 +18,5 @@ export const useLegalLinks = (footerConfig) => {
16
18
  // Use configured links or defaults
17
19
  return footerConfig?.legalLinks ?? DEFAULT_LINKS;
18
20
  };
21
+ /** @deprecated Use getLegalLinks instead */
22
+ export const useLegalLinks = getLegalLinks;
@@ -17,6 +17,12 @@ export interface DnDevFooterProps {
17
17
  * 4. app.footer.copyright === string -> custom copyright
18
18
  * 5. LegalLinks from app.footer.legalLinks (defaults if undefined)
19
19
  * 6. DoNotDev branding always appended
20
+ *
21
+ * @critical The `<footer>` MUST have `role="contentinfo"` and className `"footer"`.
22
+ * ALL footer CSS in layout-variables.css targets `footer[role='contentinfo']`.
23
+ * This controls: grid placement, height, border, footer-mode scroll behavior,
24
+ * preset-specific visibility (moolti/plain hide footer, blog hides on mobile).
25
+ * DO NOT change role, tag, or className.
20
26
  */
21
27
  declare function DnDevFooterComponent({ app }: DnDevFooterProps): ReactNode;
22
28
  export declare const DnDevFooter: import("react").MemoExoticComponent<typeof DnDevFooterComponent>;
@@ -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,CA8EvE;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;;;;;;;;;;;;;;;;;;;GAmBG;AACH,iBAAS,oBAAoB,CAAC,EAAE,GAAQ,EAAE,EAAE,gBAAgB,GAAG,SAAS,CA8EvE;AAED,eAAO,MAAM,WAAW,kEAA6B,CAAC"}
@@ -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", 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();