@donotdev/ui 0.0.6 → 0.0.8

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 (55) hide show
  1. package/assets/fonts/fonts.css +4 -4
  2. package/dist/components/auth/AuthHeader.d.ts +5 -0
  3. package/dist/components/auth/AuthHeader.d.ts.map +1 -1
  4. package/dist/components/auth/AuthHeader.js +22 -8
  5. package/dist/components/auth/AuthMenu.d.ts +6 -2
  6. package/dist/components/auth/AuthMenu.d.ts.map +1 -1
  7. package/dist/components/auth/AuthMenu.js +2 -2
  8. package/dist/components/common/RedirectOverlay.d.ts +37 -0
  9. package/dist/components/common/RedirectOverlay.d.ts.map +1 -0
  10. package/dist/components/common/RedirectOverlay.js +243 -0
  11. package/dist/components/common/index.d.ts +1 -0
  12. package/dist/components/common/index.d.ts.map +1 -1
  13. package/dist/components/common/index.js +1 -0
  14. package/dist/components/layout/components/header/SettingsMenu.d.ts.map +1 -1
  15. package/dist/components/layout/components/header/SettingsMenu.js +1 -1
  16. package/dist/crud/components/DisplayFieldRenderer.js +1 -1
  17. package/dist/dndev.css +517 -90
  18. package/dist/index.js +4 -4
  19. package/dist/internal/devtools/components/DesignTab.d.ts.map +1 -1
  20. package/dist/internal/devtools/components/DesignTab.js +25 -3
  21. package/dist/internal/layout/components/PerformanceHints.d.ts +64 -0
  22. package/dist/internal/layout/components/PerformanceHints.d.ts.map +1 -0
  23. package/dist/internal/layout/components/PerformanceHints.js +88 -0
  24. package/dist/internal/layout/components/footer/FooterBranding.js +1 -1
  25. package/dist/internal/layout/config/presets/admin.d.ts +2 -2
  26. package/dist/internal/layout/config/presets/admin.d.ts.map +1 -1
  27. package/dist/internal/layout/config/presets/admin.js +8 -4
  28. package/dist/providers/NextJsAppProviders.d.ts.map +1 -1
  29. package/dist/providers/NextJsAppProviders.js +5 -1
  30. package/dist/providers/ViteAppProviders.d.ts.map +1 -1
  31. package/dist/providers/ViteAppProviders.js +4 -1
  32. package/dist/routing/hooks/hooks.next.d.ts +1 -0
  33. package/dist/routing/hooks/hooks.next.d.ts.map +1 -1
  34. package/dist/routing/hooks/hooks.next.js +1 -1
  35. package/dist/routing/hooks/hooks.vite.d.ts +1 -0
  36. package/dist/routing/hooks/hooks.vite.d.ts.map +1 -1
  37. package/dist/routing/hooks/hooks.vite.js +1 -1
  38. package/dist/routing/hooks/useRouteParam.next.d.ts +18 -0
  39. package/dist/routing/hooks/useRouteParam.next.d.ts.map +1 -0
  40. package/dist/routing/hooks/useRouteParam.next.js +38 -0
  41. package/dist/routing/hooks/useRouteParam.vite.d.ts +18 -0
  42. package/dist/routing/hooks/useRouteParam.vite.d.ts.map +1 -0
  43. package/dist/routing/hooks/useRouteParam.vite.js +38 -0
  44. package/dist/routing/index.d.ts +1 -1
  45. package/dist/routing/index.d.ts.map +1 -1
  46. package/dist/routing/index.js +1 -1
  47. package/dist/routing/useGoTo.d.ts +3 -4
  48. package/dist/routing/useGoTo.d.ts.map +1 -1
  49. package/dist/routing/useGoTo.js +16 -23
  50. package/dist/styles/index.css +513 -86
  51. package/dist/utils/useCrudSafe.d.ts.map +1 -1
  52. package/dist/utils/useCrudSafe.js +2 -1
  53. package/dist/vite-routing/RootLayout.d.ts.map +1 -1
  54. package/dist/vite-routing/RootLayout.js +4 -1
  55. package/package.json +10 -11
@@ -1 +1 @@
1
- {"version":3,"file":"DesignTab.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/components/DesignTab.tsx"],"names":[],"mappings":"AA8CA,eAAO,MAAM,SAAS,+CAsuBrB,CAAC"}
1
+ {"version":3,"file":"DesignTab.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/components/DesignTab.tsx"],"names":[],"mappings":"AA+CA,eAAO,MAAM,SAAS,+CA2yBrB,CAAC"}
@@ -175,6 +175,9 @@ export const DesignTab = () => {
175
175
  '--input',
176
176
  '--ring',
177
177
  '--radius',
178
+ '--font-sans',
179
+ '--font-mono',
180
+ '--font-family',
178
181
  ];
179
182
  relevantVars.forEach((varName) => {
180
183
  const value = style.getPropertyValue(varName).trim();
@@ -194,6 +197,7 @@ export const DesignTab = () => {
194
197
  const analyzeTypography = () => {
195
198
  const elements = document.querySelectorAll('*');
196
199
  const fontSizeMap = new Map();
200
+ const fontFamilyMap = new Map();
197
201
  let analyzedCount = 0;
198
202
  elements.forEach((el) => {
199
203
  if (isOverlayElement(el))
@@ -216,12 +220,23 @@ export const DesignTab = () => {
216
220
  const fontSize = style.fontSize;
217
221
  const fontSizeRounded = parseFloat(fontSize).toFixed(2) + 'px';
218
222
  fontSizeMap.set(fontSizeRounded, (fontSizeMap.get(fontSizeRounded) || 0) + 1);
223
+ const fontFamily = style.fontFamily
224
+ ?.split(',')[0]
225
+ ?.trim()
226
+ ?.replace(/['"]/g, '');
227
+ if (fontFamily) {
228
+ fontFamilyMap.set(fontFamily, (fontFamilyMap.get(fontFamily) || 0) + 1);
229
+ }
219
230
  });
220
231
  const fontSizes = Array.from(fontSizeMap.entries())
221
232
  .map(([size, count]) => ({ size, count }))
222
233
  .sort((a, b) => b.count - a.count);
234
+ const fontFamilies = Array.from(fontFamilyMap.entries())
235
+ .map(([family, count]) => ({ family, count }))
236
+ .sort((a, b) => b.count - a.count);
223
237
  return {
224
238
  fontSizes,
239
+ fontFamilies,
225
240
  totalElements: analyzedCount,
226
241
  };
227
242
  };
@@ -376,7 +391,14 @@ export const DesignTab = () => {
376
391
  flexShrink: 0,
377
392
  } }), _jsxs(Text, { className: "dndev-text-xs dndev-font-mono", style: { flex: 1 }, children: [c.percentage.toFixed(1), "%"] }), _jsx(Badge, { variant: BADGE_VARIANT.SECONDARY, children: c.category })] }, i))) })),
378
393
  },
379
- ] }))] }) })), typography && (_jsxs(Card, { content: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Font Sizes" }), _jsxs(Badge, { variant: BADGE_VARIANT.SECONDARY, children: [typography.totalElements, " elements"] })] }), children: [_jsxs(Stack, { direction: "row", align: "center", justify: "between", children: [_jsxs(Label, { className: "dndev-text-sm dndev-font-semibold", children: [typography.fontSizes.length, " sizes"] }), (highlightedSize || Object.keys(fontSizeColors).length > 0) && (_jsx(Button, { variant: BUTTON_VARIANT.GHOST, onClick: clearHighlights, style: { padding: '0 var(--gap-xs)', height: 'auto' }, children: _jsx(Text, { className: "dndev-text-xs", children: "Clear All" }) }))] }), _jsx(Stack, { gap: "tight", className: "dndev-mt-xs", children: typography.fontSizes.map((f, i) => {
394
+ ] }))] }) })), typography && typography.fontFamilies.length > 0 && (_jsx(Card, { content: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Font Families" }), _jsxs(Badge, { variant: BADGE_VARIANT.SECONDARY, children: [typography.fontFamilies.length, " families"] })] }), children: _jsx(Stack, { gap: "tight", className: "dndev-mt-xs", children: typography.fontFamilies.map((f, i) => (_jsxs(Stack, { direction: "row", justify: "between", align: "center", gap: "tight", style: {
395
+ padding: 'var(--gap-sm)',
396
+ borderRadius: 'var(--radius-sm)',
397
+ }, children: [_jsx(Text, { className: "dndev-font-mono dndev-text-xs", style: { flex: 1 }, children: f.family }), _jsxs(Text, { className: "dndev-text-xs", style: {
398
+ opacity: 0.6,
399
+ minWidth: '2rem',
400
+ textAlign: 'end',
401
+ }, children: [f.count, "\u00D7"] })] }, i))) }) })), typography && (_jsxs(Card, { content: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Font Sizes" }), _jsxs(Badge, { variant: BADGE_VARIANT.SECONDARY, children: [typography.totalElements, " elements"] })] }), children: [_jsxs(Stack, { direction: "row", align: "center", justify: "between", children: [_jsxs(Label, { className: "dndev-text-sm dndev-font-semibold", children: [typography.fontSizes.length, " sizes"] }), (highlightedSize || Object.keys(fontSizeColors).length > 0) && (_jsx(Button, { variant: BUTTON_VARIANT.GHOST, onClick: clearHighlights, style: { padding: '0 var(--gap-sm)', height: 'auto' }, children: _jsx(Text, { className: "dndev-text-xs", children: "Clear All" }) }))] }), _jsx(Stack, { gap: "tight", className: "dndev-mt-xs", children: typography.fontSizes.map((f, i) => {
380
402
  const isOrphan = f.count < 5;
381
403
  const isHighlighted = highlightedSize === f.size;
382
404
  const currentColor = fontSizeColors[f.size] || '';
@@ -400,7 +422,7 @@ export const DesignTab = () => {
400
422
  console.log(`Found ${found.length} elements with ${f.size}`);
401
423
  };
402
424
  return (_jsxs(Stack, { direction: "row", justify: "between", align: "center", gap: "tight", style: {
403
- padding: 'var(--gap-xs)',
425
+ padding: 'var(--gap-sm)',
404
426
  borderRadius: 'var(--radius-sm)',
405
427
  backgroundColor: isHighlighted
406
428
  ? 'var(--primary)'
@@ -412,7 +434,7 @@ export const DesignTab = () => {
412
434
  e.stopPropagation();
413
435
  findOrphanElements();
414
436
  }, style: {
415
- padding: '0 var(--gap-xs)',
437
+ padding: '0 var(--gap-sm)',
416
438
  height: '1.5rem',
417
439
  minWidth: '2rem',
418
440
  }, title: `Find ${f.size} elements in console`, children: _jsx(Text, { className: "dndev-text-xs", children: "\uD83D\uDD0D" }) })) : (_jsx("input", { type: "color", value: currentColor || '#000000', onChange: (e) => applyFontSizeColor(f.size, e.target.value), onClick: (e) => e.stopPropagation(), style: {
@@ -0,0 +1,64 @@
1
+ import type { ComponentType } from 'react';
2
+ interface FontPreload {
3
+ /** Path to font file (e.g., '/fonts/Inter-latin.woff2') */
4
+ href: string;
5
+ /** Font MIME type @default 'font/woff2' */
6
+ type?: string;
7
+ /** Cross-origin setting @default 'anonymous' */
8
+ crossOrigin?: 'anonymous' | 'use-credentials';
9
+ }
10
+ interface PerformanceHintsProps {
11
+ /**
12
+ * Additional origins to preconnect to
13
+ * These are merged with defaults
14
+ */
15
+ preconnects?: string[];
16
+ /**
17
+ * Additional origins to dns-prefetch
18
+ * These are merged with defaults
19
+ */
20
+ dnsPrefetch?: string[];
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']
25
+ */
26
+ fontPreloads?: (string | FontPreload)[];
27
+ /**
28
+ * Disable default preconnects (use only custom ones)
29
+ * @default false
30
+ */
31
+ disableDefaults?: boolean;
32
+ /**
33
+ * Disable default font preloads
34
+ * @default false
35
+ */
36
+ disableFontPreloads?: boolean;
37
+ }
38
+ /**
39
+ * PerformanceHints component
40
+ *
41
+ * Adds preconnect, dns-prefetch, and font preload hints to improve page load.
42
+ * Automatically includes common third-party origins and critical fonts.
43
+ *
44
+ * @example
45
+ * ```tsx
46
+ * // Use defaults (preloads Inter-latin.woff2)
47
+ * <PerformanceHints />
48
+ *
49
+ * // Custom font preloads
50
+ * <PerformanceHints fontPreloads={['/fonts/Roboto-400-latin.woff2']} />
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)
58
+ * <PerformanceHints disableFontPreloads />
59
+ * ```
60
+ */
61
+ declare const PerformanceHints: ComponentType<PerformanceHintsProps>;
62
+ export default PerformanceHints;
63
+ export type { FontPreload, PerformanceHintsProps };
64
+ //# sourceMappingURL=PerformanceHints.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,88 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ // packages/ui/src/internal/layout/components/PerformanceHints.tsx
4
+ /**
5
+ * @fileoverview Performance hints for faster page loads
6
+ * @description Adds preconnect, dns-prefetch, and font preload hints
7
+ *
8
+ * - Preconnect establishes early connections (DNS + TCP + TLS) to origins
9
+ * the page will need, saving 100-300ms per origin on slow networks.
10
+ * - Font preload initiates font downloads early, reducing LCP by ~500-1000ms
11
+ *
12
+ * @version 0.0.2
13
+ * @since 0.0.1
14
+ * @author AMBROISE PARK Consulting
15
+ */
16
+ import { Helmet } from 'react-helmet-async';
17
+ /**
18
+ * Common third-party origins that benefit from preconnect
19
+ * Only includes origins that are commonly used and safe to preconnect
20
+ */
21
+ const DEFAULT_PRECONNECTS = [
22
+ // YouTube embeds - thumbnails and iframe
23
+ 'https://img.youtube.com',
24
+ 'https://www.youtube.com',
25
+ // Google Fonts (if used)
26
+ 'https://fonts.googleapis.com',
27
+ 'https://fonts.gstatic.com',
28
+ // Google APIs (Firebase, Analytics, etc.)
29
+ 'https://www.googleapis.com',
30
+ // Stripe (if used)
31
+ 'https://js.stripe.com',
32
+ ];
33
+ /**
34
+ * Origins to dns-prefetch only (less aggressive than preconnect)
35
+ * Use for origins that might be needed but aren't certain
36
+ */
37
+ const DEFAULT_DNS_PREFETCH = [
38
+ 'https://www.google-analytics.com',
39
+ 'https://www.googletagmanager.com',
40
+ ];
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)
45
+ */
46
+ const DEFAULT_FONT_PRELOADS = [];
47
+ /**
48
+ * PerformanceHints component
49
+ *
50
+ * Adds preconnect, dns-prefetch, and font preload hints to improve page load.
51
+ * Automatically includes common third-party origins and critical fonts.
52
+ *
53
+ * @example
54
+ * ```tsx
55
+ * // Use defaults (preloads Inter-latin.woff2)
56
+ * <PerformanceHints />
57
+ *
58
+ * // Custom font preloads
59
+ * <PerformanceHints fontPreloads={['/fonts/Roboto-400-latin.woff2']} />
60
+ *
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)
67
+ * <PerformanceHints disableFontPreloads />
68
+ * ```
69
+ */
70
+ const PerformanceHints = ({ preconnects = [], dnsPrefetch = [], fontPreloads = [], disableDefaults = false, disableFontPreloads = false, }) => {
71
+ // Merge defaults with custom origins
72
+ const allPreconnects = disableDefaults
73
+ ? preconnects
74
+ : [...new Set([...DEFAULT_PRECONNECTS, ...preconnects])];
75
+ const allDnsPrefetch = disableDefaults
76
+ ? dnsPrefetch
77
+ : [...new Set([...DEFAULT_DNS_PREFETCH, ...dnsPrefetch])];
78
+ // Normalize font preloads to FontPreload objects
79
+ const normalizeFontPreload = (font) => typeof font === 'string' ? { href: font } : font;
80
+ const customFontPaths = fontPreloads.map((f) => typeof f === 'string' ? f : f.href);
81
+ const allFontPreloads = disableFontPreloads
82
+ ? []
83
+ : fontPreloads.length > 0
84
+ ? fontPreloads.map(normalizeFontPreload)
85
+ : DEFAULT_FONT_PRELOADS.filter((f) => !customFontPaths.includes(f)).map(normalizeFontPreload);
86
+ return (_jsxs(Helmet, { children: [allFontPreloads.map((font) => (_jsx("link", { rel: "preload", as: "font", href: font.href, type: font.type || 'font/woff2', crossOrigin: font.crossOrigin || 'anonymous' }, `font-${font.href}`))), allPreconnects.map((origin) => (_jsx("link", { rel: "preconnect", href: origin, crossOrigin: "anonymous" }, `preconnect-${origin}`))), allDnsPrefetch.map((origin) => (_jsx("link", { rel: "dns-prefetch", href: origin }, `dns-${origin}`)))] }));
87
+ };
88
+ export default PerformanceHints;
@@ -20,7 +20,7 @@ import { useAppConfig } from '@donotdev/core';
20
20
  * @since 0.0.1
21
21
  * @author AMBROISE PARK Consulting
22
22
  */
23
- export const FooterBranding = ({ className, size = 'xs', }) => {
23
+ export const FooterBranding = ({ className, size = 'sm', }) => {
24
24
  const appUrl = useAppConfig('url');
25
25
  const isFrameworkSite = appUrl === 'https://donotdev.com';
26
26
  const sizeStyles = {
@@ -12,8 +12,8 @@ import type { PresetConfig } from '@donotdev/core';
12
12
  * Admin preset - admin panel layout
13
13
  *
14
14
  * Zones:
15
- * - Header: Logo + title (left), actions (right)
16
- * - Sidebar: Navigation menu, user profile at bottom
15
+ * - Header: Logo + title (left), GoTo + Auth + Language + Theme (right)
16
+ * - Sidebar: Navigation menu only (no bottom controls - they're in header)
17
17
  * - Footer: Automatic footer (copyright + legal links + DoNotDev branding)
18
18
  *
19
19
  * Mobile behavior:
@@ -1 +1 @@
1
- {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../../../../src/internal/layout/config/presets/admin.tsx"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,EAAE,YAczB,CAAC"}
1
+ {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../../../../src/internal/layout/config/presets/admin.tsx"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,EAAE,YAkBzB,CAAC"}
@@ -3,8 +3,8 @@
3
3
  * Admin preset - admin panel layout
4
4
  *
5
5
  * Zones:
6
- * - Header: Logo + title (left), actions (right)
7
- * - Sidebar: Navigation menu, user profile at bottom
6
+ * - Header: Logo + title (left), GoTo + Auth + Language + Theme (right)
7
+ * - Sidebar: Navigation menu only (no bottom controls - they're in header)
8
8
  * - Footer: Automatic footer (copyright + legal links + DoNotDev branding)
9
9
  *
10
10
  * Mobile behavior:
@@ -13,8 +13,12 @@
13
13
  */
14
14
  export const adminPreset = {
15
15
  name: 'admin',
16
- // header omitted → uses DEFAULT_SLOTS.header
17
- // sidebar omitted → uses DEFAULT_SLOTS.sidebar
16
+ // header omitted → uses DEFAULT_SLOTS.header (GoTo + Auth + Language + Theme)
17
+ sidebar: {
18
+ // content omitted → uses DEFAULT_SLOTS.sidebar.content (NavigationMenu)
19
+ // bottom explicitly empty - Auth/Language/Theme are in header, no duplication
20
+ bottom: () => null,
21
+ },
18
22
  footer: {},
19
23
  mobile: {
20
24
  mergedBar: {
@@ -1 +1 @@
1
- {"version":3,"file":"NextJsAppProviders.d.ts","sourceRoot":"","sources":["../../src/providers/NextJsAppProviders.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAiDxD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,2CAyChE"}
1
+ {"version":3,"file":"NextJsAppProviders.d.ts","sourceRoot":"","sources":["../../src/providers/NextJsAppProviders.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAuDxD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,2CAiDhE"}
@@ -15,6 +15,7 @@ import { QueryProviders, AppConfigProvider } from '@donotdev/core';
15
15
  import { useConsent } from '@donotdev/core';
16
16
  import { NextJsStoresInitializer } from '../internal/initializers/NextJsStoresInitializer';
17
17
  import FaviconHead from '../internal/layout/components/FaviconHead';
18
+ import PerformanceHints from '../internal/layout/components/PerformanceHints';
18
19
  // import NextJsAutoMetaTags from '../internal/layout/components/NextJsAutoMetaTags'; // Deprecated - metadata now server-side
19
20
  import { DnDevLayout } from '../internal/layout/DnDevLayout';
20
21
  import { SentryInitializer } from '../internal/providers/SentryInitializer';
@@ -27,6 +28,9 @@ const PWAUpdateNotification = lazy(() => import('../internal/layout/components/P
27
28
  const LicenseWatermark = lazy(() => import('../components/license/LicenseWatermark').then((m) => ({
28
29
  default: m.LicenseWatermark,
29
30
  })));
31
+ const RedirectOverlay = lazy(() => import('../components/common/RedirectOverlay').then((m) => ({
32
+ default: m.RedirectOverlay,
33
+ })));
30
34
  /**
31
35
  * ConsentBanner - Lazy loaded consent component
32
36
  * Only shows if user hasn't consented yet
@@ -45,5 +49,5 @@ function ConsentBanner() {
45
49
  }
46
50
  export function NextJsAppProviders(props) {
47
51
  const { config = {}, layout, children, serverCookies, customStores } = props;
48
- return (_jsxs(AppConfigProvider, { config: config, platform: "nextjs", children: [_jsx(SentryInitializer, {}), _jsx(HelmetProvider, { children: _jsxs(NextJsStoresInitializer, { serverCookies: serverCookies, customStores: customStores, children: [_jsx(FaviconHead, {}), _jsx(QueryProviders, { children: _jsxs(UIProviders, { children: [_jsx(DnDevLayout, { layout: layout, children: children }), _jsx(ConsentBanner, {}), _jsx(Suspense, { fallback: null, children: _jsx(PWAUpdateNotification, {}) }), _jsx(Suspense, { fallback: null, children: _jsx(LicenseWatermark, {}) })] }) })] }) })] }));
52
+ return (_jsxs(AppConfigProvider, { config: config, platform: "nextjs", children: [_jsx(SentryInitializer, {}), _jsx(HelmetProvider, { children: _jsxs(NextJsStoresInitializer, { serverCookies: serverCookies, customStores: customStores, children: [_jsx(FaviconHead, {}), _jsx(PerformanceHints, {}), _jsx(QueryProviders, { children: _jsxs(UIProviders, { children: [_jsx(DnDevLayout, { layout: layout, children: children }), _jsx(ConsentBanner, {}), _jsx(Suspense, { fallback: null, children: _jsx(PWAUpdateNotification, {}) }), _jsx(Suspense, { fallback: null, children: _jsx(LicenseWatermark, {}) }), _jsx(Suspense, { fallback: null, children: _jsx(RedirectOverlay, {}) })] }) })] }) })] }));
49
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ViteAppProviders.d.ts","sourceRoot":"","sources":["../../src/providers/ViteAppProviders.tsx"],"names":[],"mappings":"AAcA,OAAO,aAAa,CAAC;AACrB,OAAO,gBAAgB,CAAC;AACxB,OAAO,sBAAsB,CAAC;AAC9B,OAAO,gBAAgB,CAAC;AACxB,OAAO,gBAAgB,CAAC;AAGxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAsBxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,2CA+BxD"}
1
+ {"version":3,"file":"ViteAppProviders.d.ts","sourceRoot":"","sources":["../../src/providers/ViteAppProviders.tsx"],"names":[],"mappings":"AAcA,OAAO,aAAa,CAAC;AACrB,OAAO,gBAAgB,CAAC;AACxB,OAAO,sBAAsB,CAAC;AAC9B,OAAO,gBAAgB,CAAC;AACxB,OAAO,gBAAgB,CAAC;AAGxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AA2BxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,2CAkCxD"}
@@ -30,6 +30,9 @@ const HelmetProvider = lazy(() => import('react-helmet-async').then((m) => ({ de
30
30
  const FaviconHead = lazy(() => import('../internal/layout/components/FaviconHead').then((m) => ({
31
31
  default: m.default,
32
32
  })));
33
+ const PerformanceHints = lazy(() => import('../internal/layout/components/PerformanceHints').then((m) => ({
34
+ default: m.default,
35
+ })));
33
36
  /**
34
37
  * ViteAppProviders - Vite platform-specific app providers
35
38
  *
@@ -77,5 +80,5 @@ export function ViteAppProviders(props) {
77
80
  routeGroups,
78
81
  layout,
79
82
  });
80
- return (_jsxs(AppConfigProvider, { config: config, platform: "vite", children: [_jsx(SentryInitializer, {}), _jsx(ViteStoresInitializer, { customStores: customStores, children: _jsx(Suspense, { fallback: null, children: _jsxs(HelmetProvider, { children: [_jsx(FaviconHead, {}), _jsx(NavigationProvider, { router: router })] }) }) })] }));
83
+ return (_jsxs(AppConfigProvider, { config: config, platform: "vite", children: [_jsx(SentryInitializer, {}), _jsx(ViteStoresInitializer, { customStores: customStores, children: _jsx(Suspense, { fallback: null, children: _jsxs(HelmetProvider, { children: [_jsx(FaviconHead, {}), _jsx(PerformanceHints, {}), _jsx(NavigationProvider, { router: router })] }) }) })] }));
81
84
  }
@@ -10,6 +10,7 @@
10
10
  export { useNavigate, useBack, useRefresh, usePrefetch, } from './useNavigate.next';
11
11
  export { useLocation } from './useLocation.next';
12
12
  export { useParams } from './useParams.next';
13
+ export { useRouteParam } from './useRouteParam.next';
13
14
  export { useSearchParams } from './useSearchParams.next';
14
15
  export { useMatch } from './useMatch.next';
15
16
  export { useQueryParams } from './useQueryParams.next';
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.next.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/hooks.next.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,EACL,WAAW,EACX,OAAO,EACP,UAAU,EACV,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,YAAY,EACV,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"hooks.next.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/hooks.next.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,EACL,WAAW,EACX,OAAO,EACP,UAAU,EACV,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,YAAY,EACV,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,yBAAyB,CAAC"}
@@ -1 +1 @@
1
- "use client";import{useCallback as f}from"react";import{useRouter as h}from"next/navigation";import{isClient as x,useOverlayStore as S}from"@donotdev/core";function d(){let e=h(),t=S(r=>r.closeAll);return f((r,i)=>{if(r==="back")return t(),e.back();if(t(),i?.preserveScroll&&x()){let o=window.scrollY;i?.replace?e.replace(r):e.push(r),requestAnimationFrame(()=>{window.scrollTo({top:o,behavior:"auto"})});return}return i?.replace?e.replace(r):e.push(r)},[e,t])}function y(){let e=h();return f(()=>e.back(),[e])}function k(){let e=h();return f(()=>e.refresh(),[e])}function T(){let e=h();return f(t=>e.prefetch(t),[e])}import{usePathname as v,useSearchParams as b}from"next/navigation";function l(){let e=v(),t=b(),r=t.toString()?`?${t.toString()}`:"";return{pathname:e||"/",search:r,hash:"",state:null}}import{useParams as w}from"next/navigation";function C(){return w()}import{useSearchParams as I}from"next/navigation";function g(){return I()}import{usePathname as N}from"next/navigation";function G(e){let t=N(),r=e.replace(/:[^/]+/g,"([^/]+)").replace(/\*/g,".*"),i=new RegExp(`^${r}$`),o=t.match(i);if(!o)return null;let s=e.match(/:[^/]+/g)?.map(a=>a.slice(1))||[],n={};return s.forEach((a,c)=>{n[a]=o[c+1]||""}),{params:n,pathname:t,pattern:e}}import{useCallback as R}from"react";function $(){let e=g(),t=d(),r=l(),i=R((n,a)=>{let c=new URLSearchParams(e.toString());c.set(n,a);let m=c.toString(),P=`${r.pathname||"/"}${m?`?${m}`:""}`;t(P)},[e,t,r.pathname]),o=R(n=>{let a=new URLSearchParams(e.toString());a.delete(n);let c=a.toString(),u=`${r.pathname||"/"}${c?`?${c}`:""}`;t(u)},[e,t,r.pathname]),s=R(()=>{let n=r.pathname||"/";t(n)},[t,r.pathname]);return{query:e,setQuery:i,removeQuery:o,clearQueries:s}}import{useMemo as L}from"react";import{isClient as E,FEATURE_STATUS as Q}from"@donotdev/core";import{useAuthConfig as F}from"@donotdev/core";import{DEGRADED_AUTH_API as K}from"@donotdev/core";import*as O from"@donotdev/auth";var A=O?.useAuth;function U(e){return K[e]}function p(e){return A?A(e):U(e)}function M(e={}){let{auth:t,redirectTo:r,condition:i}=e;if(!E())return{shouldRedirect:!1,redirectTo:null,isChecking:!1};let o=l(),s=F(),n=p("user"),a=p("can"),c=p("status");return L(()=>{if(c===Q.INITIALIZING)return{shouldRedirect:!1,redirectTo:null,isChecking:!0};if(i){let u=i(n,c);return{shouldRedirect:u,redirectTo:u&&r||null,isChecking:!1}}if(t!==!1&&t!==void 0){if(!a)return{shouldRedirect:!1,redirectTo:null,isChecking:!1};if(!a.navigate(t)){let u=null;return typeof t=="object"&&t.required&&!n?o.search.includes("code=")||o.search.includes("state=")||o.search.includes("error=")?u=`${s.authRoute}${o.search}`:u=s.authRoute:typeof t=="object"&&t.role?u=s.roleRoute:typeof t=="object"&&t.tier?u=s.tierRoute:u=s.roleRoute,{shouldRedirect:!0,redirectTo:r||u,isChecking:!1}}}return{shouldRedirect:!1,redirectTo:null,isChecking:!1}},[t,c,n,a,i,r,o.search,s.authRoute,s.roleRoute,s.tierRoute])}export{y as useBack,l as useLocation,G as useMatch,d as useNavigate,C as useParams,T as usePrefetch,$ as useQueryParams,M as useRedirectGuard,k as useRefresh,g as useSearchParams};
1
+ "use client";import{useCallback as f}from"react";import{useRouter as h}from"next/navigation";import{isClient as S,useOverlayStore as y}from"@donotdev/core";function d(){let e=h(),t=y(r=>r.closeAll);return f((r,i)=>{if(r==="back")return t(),e.back();if(t(),i?.preserveScroll&&S()){let o=window.scrollY;i?.replace?e.replace(r):e.push(r),requestAnimationFrame(()=>{window.scrollTo({top:o,behavior:"auto"})});return}return i?.replace?e.replace(r):e.push(r)},[e,t])}function k(){let e=h();return f(()=>e.back(),[e])}function v(){let e=h();return f(()=>e.refresh(),[e])}function T(){let e=h();return f(t=>e.prefetch(t),[e])}import{usePathname as b,useSearchParams as w}from"next/navigation";function l(){let e=b(),t=w(),r=t.toString()?`?${t.toString()}`:"";return{pathname:e||"/",search:r,hash:"",state:null}}import{useParams as C}from"next/navigation";function g(){return C()}function I(e){let r=g()[e];if(typeof r=="string")return r;if(Array.isArray(r)&&r.length>0)return r[0]}import{useSearchParams as N}from"next/navigation";function R(){return N()}import{usePathname as G}from"next/navigation";function $(e){let t=G(),r=e.replace(/:[^/]+/g,"([^/]+)").replace(/\*/g,".*"),i=new RegExp(`^${r}$`),o=t.match(i);if(!o)return null;let s=e.match(/:[^/]+/g)?.map(a=>a.slice(1))||[],n={};return s.forEach((a,c)=>{n[a]=o[c+1]||""}),{params:n,pathname:t,pattern:e}}import{useCallback as P}from"react";function K(){let e=R(),t=d(),r=l(),i=P((n,a)=>{let c=new URLSearchParams(e.toString());c.set(n,a);let m=c.toString(),A=`${r.pathname||"/"}${m?`?${m}`:""}`;t(A)},[e,t,r.pathname]),o=P(n=>{let a=new URLSearchParams(e.toString());a.delete(n);let c=a.toString(),u=`${r.pathname||"/"}${c?`?${c}`:""}`;t(u)},[e,t,r.pathname]),s=P(()=>{let n=r.pathname||"/";t(n)},[t,r.pathname]);return{query:e,setQuery:i,removeQuery:o,clearQueries:s}}import{useMemo as E}from"react";import{isClient as Q,FEATURE_STATUS as F}from"@donotdev/core";import{useAuthConfig as M}from"@donotdev/core";import{DEGRADED_AUTH_API as O}from"@donotdev/core";import*as U from"@donotdev/auth";var x=U?.useAuth;function L(e){return O[e]}function p(e){return x?x(e):L(e)}function j(e={}){let{auth:t,redirectTo:r,condition:i}=e;if(!Q())return{shouldRedirect:!1,redirectTo:null,isChecking:!1};let o=l(),s=M(),n=p("user"),a=p("can"),c=p("status");return E(()=>{if(c===F.INITIALIZING)return{shouldRedirect:!1,redirectTo:null,isChecking:!0};if(i){let u=i(n,c);return{shouldRedirect:u,redirectTo:u&&r||null,isChecking:!1}}if(t!==!1&&t!==void 0){if(!a)return{shouldRedirect:!1,redirectTo:null,isChecking:!1};if(!a.navigate(t)){let u=null;return typeof t=="object"&&t.required&&!n?o.search.includes("code=")||o.search.includes("state=")||o.search.includes("error=")?u=`${s.authRoute}${o.search}`:u=s.authRoute:typeof t=="object"&&t.role?u=s.roleRoute:typeof t=="object"&&t.tier?u=s.tierRoute:u=s.roleRoute,{shouldRedirect:!0,redirectTo:r||u,isChecking:!1}}}return{shouldRedirect:!1,redirectTo:null,isChecking:!1}},[t,c,n,a,i,r,o.search,s.authRoute,s.roleRoute,s.tierRoute])}export{k as useBack,l as useLocation,$ as useMatch,d as useNavigate,g as useParams,T as usePrefetch,K as useQueryParams,j as useRedirectGuard,v as useRefresh,I as useRouteParam,R as useSearchParams};
@@ -10,6 +10,7 @@
10
10
  export { useNavigate, useBack, useRefresh, usePrefetch, } from './useNavigate.vite';
11
11
  export { useLocation } from './useLocation.vite';
12
12
  export { useParams } from './useParams.vite';
13
+ export { useRouteParam } from './useRouteParam.vite';
13
14
  export { useSearchParams } from './useSearchParams.vite';
14
15
  export { useMatch } from './useMatch.vite';
15
16
  export { useQueryParams } from './useQueryParams.vite';
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.vite.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/hooks.vite.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,EACL,WAAW,EACX,OAAO,EACP,UAAU,EACV,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,YAAY,EACV,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"hooks.vite.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/hooks.vite.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,EACL,WAAW,EACX,OAAO,EACP,UAAU,EACV,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,YAAY,EACV,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,yBAAyB,CAAC"}
@@ -1 +1 @@
1
- "use client";import{useCallback as m}from"react";import{useNavigate as A}from"react-router-dom";import{isClient as x,useOverlayStore as S}from"@donotdev/core";function p(){let e=A(),t=S(r=>r.closeAll);return m((r,i)=>r==="back"?(t(),e(-1)):(t(),i?.replace?e(r,{replace:!0}):e(r)),[e,t])}function y(){let e=A();return m(()=>e(-1),[e])}function v(){return m(()=>{x()&&window.location.reload()},[])}function k(){return m(e=>{},[])}import{useLocation as T}from"react-router-dom";function l(){return T()}import{useParams as C}from"react-router-dom";function I(){return C()}import{useSearchParams as b}from"react-router-dom";function d(){return b()[0]}import{useMatch as G}from"react-router-dom";function w(e){return G(e)}import{useCallback as R}from"react";function N(){let e=d(),t=p(),r=l(),i=R((n,u)=>{let a=new URLSearchParams(e.toString());a.set(n,u);let f=a.toString(),g=`${r.pathname||"/"}${f?`?${f}`:""}`;t(g)},[e,t,r.pathname]),c=R(n=>{let u=new URLSearchParams(e.toString());u.delete(n);let a=u.toString(),o=`${r.pathname||"/"}${a?`?${a}`:""}`;t(o)},[e,t,r.pathname]),s=R(()=>{let n=r.pathname||"/";t(n)},[t,r.pathname]);return{query:e,setQuery:i,removeQuery:c,clearQueries:s}}import{useMemo as U}from"react";import{isClient as $,FEATURE_STATUS as M}from"@donotdev/core";import{useAuthConfig as Q}from"@donotdev/core";import{DEGRADED_AUTH_API as K}from"@donotdev/core";import*as L from"@donotdev/auth";var P=L?.useAuth;function O(e){return K[e]}function h(e){return P?P(e):O(e)}function E(e={}){let{auth:t,redirectTo:r,condition:i}=e;if(!$())return{shouldRedirect:!1,redirectTo:null,isChecking:!1};let c=l(),s=Q(),n=h("user"),u=h("can"),a=h("status");return U(()=>{if(a===M.INITIALIZING)return{shouldRedirect:!1,redirectTo:null,isChecking:!0};if(i){let o=i(n,a);return{shouldRedirect:o,redirectTo:o&&r||null,isChecking:!1}}if(t!==!1&&t!==void 0){if(!u)return{shouldRedirect:!1,redirectTo:null,isChecking:!1};if(!u.navigate(t)){let o=null;return typeof t=="object"&&t.required&&!n?c.search.includes("code=")||c.search.includes("state=")||c.search.includes("error=")?o=`${s.authRoute}${c.search}`:o=s.authRoute:typeof t=="object"&&t.role?o=s.roleRoute:typeof t=="object"&&t.tier?o=s.tierRoute:o=s.roleRoute,{shouldRedirect:!0,redirectTo:r||o,isChecking:!1}}}return{shouldRedirect:!1,redirectTo:null,isChecking:!1}},[t,a,n,u,i,r,c.search,s.authRoute,s.roleRoute,s.tierRoute])}export{y as useBack,l as useLocation,w as useMatch,p as useNavigate,I as useParams,k as usePrefetch,N as useQueryParams,E as useRedirectGuard,v as useRefresh,d as useSearchParams};
1
+ "use client";import{useCallback as m}from"react";import{useNavigate as P}from"react-router-dom";import{isClient as y,useOverlayStore as S}from"@donotdev/core";function h(){let e=P(),t=S(r=>r.closeAll);return m((r,i)=>r==="back"?(t(),e(-1)):(t(),i?.replace?e(r,{replace:!0}):e(r)),[e,t])}function v(){let e=P();return m(()=>e(-1),[e])}function k(){return m(()=>{y()&&window.location.reload()},[])}function T(){return m(e=>{},[])}import{useLocation as C}from"react-router-dom";function f(){return C()}import{useParams as I}from"react-router-dom";function d(){return I()}function b(e){let r=d()[e];if(typeof r=="string")return r;if(Array.isArray(r)&&r.length>0)return r[0]}import{useSearchParams as G}from"react-router-dom";function g(){return G()[0]}import{useMatch as w}from"react-router-dom";function N(e){return w(e)}import{useCallback as R}from"react";function K(){let e=g(),t=h(),r=f(),i=R((n,u)=>{let a=new URLSearchParams(e.toString());a.set(n,u);let l=a.toString(),A=`${r.pathname||"/"}${l?`?${l}`:""}`;t(A)},[e,t,r.pathname]),c=R(n=>{let u=new URLSearchParams(e.toString());u.delete(n);let a=u.toString(),o=`${r.pathname||"/"}${a?`?${a}`:""}`;t(o)},[e,t,r.pathname]),s=R(()=>{let n=r.pathname||"/";t(n)},[t,r.pathname]);return{query:e,setQuery:i,removeQuery:c,clearQueries:s}}import{useMemo as $}from"react";import{isClient as M,FEATURE_STATUS as Q}from"@donotdev/core";import{useAuthConfig as E}from"@donotdev/core";import{DEGRADED_AUTH_API as L}from"@donotdev/core";import*as O from"@donotdev/auth";var x=O?.useAuth;function U(e){return L[e]}function p(e){return x?x(e):U(e)}function _(e={}){let{auth:t,redirectTo:r,condition:i}=e;if(!M())return{shouldRedirect:!1,redirectTo:null,isChecking:!1};let c=f(),s=E(),n=p("user"),u=p("can"),a=p("status");return $(()=>{if(a===Q.INITIALIZING)return{shouldRedirect:!1,redirectTo:null,isChecking:!0};if(i){let o=i(n,a);return{shouldRedirect:o,redirectTo:o&&r||null,isChecking:!1}}if(t!==!1&&t!==void 0){if(!u)return{shouldRedirect:!1,redirectTo:null,isChecking:!1};if(!u.navigate(t)){let o=null;return typeof t=="object"&&t.required&&!n?c.search.includes("code=")||c.search.includes("state=")||c.search.includes("error=")?o=`${s.authRoute}${c.search}`:o=s.authRoute:typeof t=="object"&&t.role?o=s.roleRoute:typeof t=="object"&&t.tier?o=s.tierRoute:o=s.roleRoute,{shouldRedirect:!0,redirectTo:r||o,isChecking:!1}}}return{shouldRedirect:!1,redirectTo:null,isChecking:!1}},[t,a,n,u,i,r,c.search,s.authRoute,s.roleRoute,s.tierRoute])}export{v as useBack,f as useLocation,N as useMatch,h as useNavigate,d as useParams,T as usePrefetch,K as useQueryParams,_ as useRedirectGuard,k as useRefresh,b as useRouteParam,g as useSearchParams};
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Safely extract a route parameter as a string
3
+ *
4
+ * Handles the fact that useParams can return string | string[] | undefined.
5
+ * For standard path parameters (not catch-all routes), this will always be a string.
6
+ *
7
+ * @param paramName - Name of the route parameter
8
+ * @returns The parameter value as a string, or undefined if not present
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * // Route: /product/:id
13
+ * const id = useRouteParam('id'); // string | undefined
14
+ * if (!id) return <NotFound />;
15
+ * ```
16
+ */
17
+ export declare function useRouteParam(paramName: string): string | undefined;
18
+ //# sourceMappingURL=useRouteParam.next.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRouteParam.next.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useRouteParam.next.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAanE"}
@@ -0,0 +1,38 @@
1
+ 'use client';
2
+ // packages/ui/src/routing/hooks/useRouteParam.next.ts
3
+ /**
4
+ * @fileoverview useRouteParam hook - Next.js implementation
5
+ * @description Helper hook to safely extract a single route parameter as a string
6
+ *
7
+ * @version 0.0.1
8
+ * @since 0.0.1
9
+ * @author AMBROISE PARK Consulting
10
+ */
11
+ import { useParams } from './useParams.next';
12
+ /**
13
+ * Safely extract a route parameter as a string
14
+ *
15
+ * Handles the fact that useParams can return string | string[] | undefined.
16
+ * For standard path parameters (not catch-all routes), this will always be a string.
17
+ *
18
+ * @param paramName - Name of the route parameter
19
+ * @returns The parameter value as a string, or undefined if not present
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * // Route: /product/:id
24
+ * const id = useRouteParam('id'); // string | undefined
25
+ * if (!id) return <NotFound />;
26
+ * ```
27
+ */
28
+ export function useRouteParam(paramName) {
29
+ const params = useParams();
30
+ const value = params[paramName];
31
+ if (typeof value === 'string') {
32
+ return value;
33
+ }
34
+ if (Array.isArray(value) && value.length > 0) {
35
+ return value[0];
36
+ }
37
+ return undefined;
38
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Safely extract a route parameter as a string
3
+ *
4
+ * Handles the fact that useParams can return string | string[] | undefined.
5
+ * For standard path parameters (not catch-all routes), this will always be a string.
6
+ *
7
+ * @param paramName - Name of the route parameter
8
+ * @returns The parameter value as a string, or undefined if not present
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * // Route: /product/:id
13
+ * const id = useRouteParam('id'); // string | undefined
14
+ * if (!id) return <NotFound />;
15
+ * ```
16
+ */
17
+ export declare function useRouteParam(paramName: string): string | undefined;
18
+ //# sourceMappingURL=useRouteParam.vite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRouteParam.vite.d.ts","sourceRoot":"","sources":["../../../src/routing/hooks/useRouteParam.vite.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAanE"}
@@ -0,0 +1,38 @@
1
+ 'use client';
2
+ // packages/ui/src/routing/hooks/useRouteParam.vite.ts
3
+ /**
4
+ * @fileoverview useRouteParam hook - Vite/React Router implementation
5
+ * @description Helper hook to safely extract a single route parameter as a string
6
+ *
7
+ * @version 0.0.1
8
+ * @since 0.0.1
9
+ * @author AMBROISE PARK Consulting
10
+ */
11
+ import { useParams } from './useParams.vite';
12
+ /**
13
+ * Safely extract a route parameter as a string
14
+ *
15
+ * Handles the fact that useParams can return string | string[] | undefined.
16
+ * For standard path parameters (not catch-all routes), this will always be a string.
17
+ *
18
+ * @param paramName - Name of the route parameter
19
+ * @returns The parameter value as a string, or undefined if not present
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * // Route: /product/:id
24
+ * const id = useRouteParam('id'); // string | undefined
25
+ * if (!id) return <NotFound />;
26
+ * ```
27
+ */
28
+ export function useRouteParam(paramName) {
29
+ const params = useParams();
30
+ const value = params[paramName];
31
+ if (typeof value === 'string') {
32
+ return value;
33
+ }
34
+ if (Array.isArray(value) && value.length > 0) {
35
+ return value[0];
36
+ }
37
+ return undefined;
38
+ }
@@ -15,7 +15,7 @@ export { default as GoToWrapper } from './GoToWrapper';
15
15
  export { default as GoToInput } from './GoToInput';
16
16
  export * from './DnDevNavigationMenu';
17
17
  export { default as NotFoundPage } from './404';
18
- export { useNavigate, useBack, useRefresh, usePrefetch, useLocation, useParams, useSearchParams, useMatch, useQueryParams, useRedirectGuard, } from '@donotdev/ui/routing/hooks';
18
+ export { useNavigate, useBack, useRefresh, usePrefetch, useLocation, useParams, useRouteParam, useSearchParams, useMatch, useQueryParams, useRedirectGuard, } from '@donotdev/ui/routing/hooks';
19
19
  export type { NavigateOptions, RedirectGuardOptions, RedirectGuardResult, } from '@donotdev/ui/routing/hooks';
20
20
  export * from './useNavigation';
21
21
  export * from './useGoTo';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routing/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAGH,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,QAAQ,CAAC;AACvB,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AAEnD,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,OAAO,CAAC;AAOhD,OAAO,EACL,WAAW,EACX,OAAO,EACP,UAAU,EACV,WAAW,EACX,WAAW,EACX,SAAS,EACT,eAAe,EACf,QAAQ,EACR,cAAc,EACd,gBAAgB,GACjB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,4BAA4B,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routing/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAGH,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,QAAQ,CAAC;AACvB,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AAEnD,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,OAAO,CAAC;AAOhD,OAAO,EACL,WAAW,EACX,OAAO,EACP,UAAU,EACV,WAAW,EACX,WAAW,EACX,SAAS,EACT,aAAa,EACb,eAAe,EACf,QAAQ,EACR,cAAc,EACd,gBAAgB,GACjB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,4BAA4B,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC"}
@@ -23,6 +23,6 @@ export { default as NotFoundPage } from './404';
23
23
  // - hooks.vite.ts when bundled with Vite (vite-app condition)
24
24
  // - hooks.next.ts when bundled with Next.js (default condition)
25
25
  // NOTE: Explicit named exports required - esbuild can't re-export with 'export *' from external
26
- export { useNavigate, useBack, useRefresh, usePrefetch, useLocation, useParams, useSearchParams, useMatch, useQueryParams, useRedirectGuard, } from '@donotdev/ui/routing/hooks';
26
+ export { useNavigate, useBack, useRefresh, usePrefetch, useLocation, useParams, useRouteParam, useSearchParams, useMatch, useQueryParams, useRedirectGuard, } from '@donotdev/ui/routing/hooks';
27
27
  export * from './useNavigation';
28
28
  export * from './useGoTo';
@@ -1,12 +1,11 @@
1
- import { type NavigationItem } from './useNavigation';
2
1
  /**
3
2
  * Hook for navigation with favorites and recents
4
3
  * Command component handles search/filtering
5
4
  */
6
5
  export declare const useGoTo: () => {
7
- navigationItems: NavigationItem[];
8
- favoriteItems: NavigationItem[];
9
- recentItems: NavigationItem[];
6
+ navigationItems: import("./useNavigation").NavigationItem[];
7
+ favoriteItems: import("./useNavigation").NavigationItem[];
8
+ recentItems: import("./useNavigation").NavigationItem[];
10
9
  toggleFavorite: (path: string) => void;
11
10
  isFavorite: (path: string) => boolean;
12
11
  navigateToItem: (path: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useGoTo.d.ts","sourceRoot":"","sources":["../../src/routing/useGoTo.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAO1E;;;GAGG;AACH,eAAO,MAAM,OAAO;;;;2BAmCT,MAAM;uBAUN,MAAM;2BAgBN,MAAM;CAehB,CAAC"}
1
+ {"version":3,"file":"useGoTo.d.ts","sourceRoot":"","sources":["../../src/routing/useGoTo.ts"],"names":[],"mappings":"AAmBA;;;GAGG;AACH,eAAO,MAAM,OAAO;;;;2BA4BT,MAAM;uBAQN,MAAM;2BAcN,MAAM;CAehB,CAAC"}