@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.
- package/assets/fonts/fonts.css +4 -4
- package/dist/components/auth/AuthHeader.d.ts +5 -0
- package/dist/components/auth/AuthHeader.d.ts.map +1 -1
- package/dist/components/auth/AuthHeader.js +22 -8
- package/dist/components/auth/AuthMenu.d.ts +6 -2
- package/dist/components/auth/AuthMenu.d.ts.map +1 -1
- package/dist/components/auth/AuthMenu.js +2 -2
- package/dist/components/common/RedirectOverlay.d.ts +37 -0
- package/dist/components/common/RedirectOverlay.d.ts.map +1 -0
- package/dist/components/common/RedirectOverlay.js +243 -0
- package/dist/components/common/index.d.ts +1 -0
- package/dist/components/common/index.d.ts.map +1 -1
- package/dist/components/common/index.js +1 -0
- package/dist/components/layout/components/header/SettingsMenu.d.ts.map +1 -1
- package/dist/components/layout/components/header/SettingsMenu.js +1 -1
- package/dist/crud/components/DisplayFieldRenderer.js +1 -1
- package/dist/dndev.css +517 -90
- package/dist/index.js +4 -4
- package/dist/internal/devtools/components/DesignTab.d.ts.map +1 -1
- package/dist/internal/devtools/components/DesignTab.js +25 -3
- package/dist/internal/layout/components/PerformanceHints.d.ts +64 -0
- package/dist/internal/layout/components/PerformanceHints.d.ts.map +1 -0
- package/dist/internal/layout/components/PerformanceHints.js +88 -0
- package/dist/internal/layout/components/footer/FooterBranding.js +1 -1
- package/dist/internal/layout/config/presets/admin.d.ts +2 -2
- package/dist/internal/layout/config/presets/admin.d.ts.map +1 -1
- package/dist/internal/layout/config/presets/admin.js +8 -4
- package/dist/providers/NextJsAppProviders.d.ts.map +1 -1
- package/dist/providers/NextJsAppProviders.js +5 -1
- package/dist/providers/ViteAppProviders.d.ts.map +1 -1
- package/dist/providers/ViteAppProviders.js +4 -1
- package/dist/routing/hooks/hooks.next.d.ts +1 -0
- package/dist/routing/hooks/hooks.next.d.ts.map +1 -1
- package/dist/routing/hooks/hooks.next.js +1 -1
- package/dist/routing/hooks/hooks.vite.d.ts +1 -0
- package/dist/routing/hooks/hooks.vite.d.ts.map +1 -1
- package/dist/routing/hooks/hooks.vite.js +1 -1
- package/dist/routing/hooks/useRouteParam.next.d.ts +18 -0
- package/dist/routing/hooks/useRouteParam.next.d.ts.map +1 -0
- package/dist/routing/hooks/useRouteParam.next.js +38 -0
- package/dist/routing/hooks/useRouteParam.vite.d.ts +18 -0
- package/dist/routing/hooks/useRouteParam.vite.d.ts.map +1 -0
- package/dist/routing/hooks/useRouteParam.vite.js +38 -0
- package/dist/routing/index.d.ts +1 -1
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +1 -1
- package/dist/routing/useGoTo.d.ts +3 -4
- package/dist/routing/useGoTo.d.ts.map +1 -1
- package/dist/routing/useGoTo.js +16 -23
- package/dist/styles/index.css +513 -86
- package/dist/utils/useCrudSafe.d.ts.map +1 -1
- package/dist/utils/useCrudSafe.js +2 -1
- package/dist/vite-routing/RootLayout.d.ts.map +1 -1
- package/dist/vite-routing/RootLayout.js +4 -1
- package/package.json +10 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DesignTab.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/components/DesignTab.tsx"],"names":[],"mappings":"
|
|
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 && (
|
|
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-
|
|
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-
|
|
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 = '
|
|
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),
|
|
16
|
-
* - Sidebar: Navigation menu
|
|
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,
|
|
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),
|
|
7
|
-
* - Sidebar: Navigation menu
|
|
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
|
-
|
|
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;
|
|
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;
|
|
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
|
|
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
|
|
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
|
+
}
|
package/dist/routing/index.d.ts
CHANGED
|
@@ -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"}
|
package/dist/routing/index.js
CHANGED
|
@@ -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":"
|
|
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"}
|