@tailor-platform/app-shell 0.17.1 → 0.19.0

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/dist/index.d.ts CHANGED
@@ -1,407 +1,639 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode, PropsWithChildren } from 'react';
3
- export { Link, useLocation, useNavigate, useParams, useRouteError, useSearchParams } from 'react-router';
4
-
5
- /**
6
- * Error boundary element type for route error handling.
7
- *
8
- * Pass a JSX element that will render when an error occurs.
9
- * Use the `useRouteError` hook from react-router to access the error.
10
- *
11
- * @example
12
- * ```tsx
13
- * import { useRouteError } from "@tailor-platform/app-shell";
14
- *
15
- * const MyErrorBoundary = () => {
16
- * const error = useRouteError() as Error;
17
- * return <div>Error: {error.message}</div>;
18
- * };
19
- *
20
- * // In config:
21
- * errorBoundary: <MyErrorBoundary />
22
- * // Or with props:
23
- * errorBoundary: <MyErrorBoundary theme="dark" onReport={handleReport} />
24
- * ```
25
- */
26
- type ErrorBoundaryComponent = ReactNode;
27
- /**
28
- * Redirect configuration for module or root component
29
- */
30
- type RedirectConfig = {
31
- /**
32
- * Path to redirect to (under /resources/)
33
- */
34
- redirectTo: string;
35
- };
36
- /**
37
- * Helper function to define a redirect to a resource path
38
- *
39
- * @param path - Path under `/resources/` (e.g., "dashboard/overview")
40
- *
41
- * @example
42
- * ```tsx
43
- * defineModule({
44
- * path: "dashboard",
45
- * component: redirectToResource("dashboard/overview"),
46
- * resources: [overviewResource],
47
- * });
48
- * ```
49
- */
50
- declare function redirectToResource(path: string): RedirectConfig;
51
- type CommonPageResource = {
52
- path: string;
53
- type: "component";
54
- component: () => ReactNode;
55
- meta: {
56
- title: string;
57
- icon?: ReactNode;
58
- };
59
- };
60
- /**
61
- * A resource that can be included in the root-level content in the navigation.
62
- */
63
- type Module = Omit<CommonPageResource, "meta"> & {
64
- _type: "module";
65
- meta: CommonPageResource["meta"] & {
66
- icon?: ReactNode;
67
- menuItemClickable: boolean;
68
- };
69
- resources: Array<Resource>;
70
- loader?: () => Response;
71
- errorBoundary: ErrorBoundaryComponent;
72
- };
73
- /**
74
- * A resource that can be included in the sub-content in the root resource.
75
- *
76
- * This resource does not have `category` metadata.
77
- */
78
- type Resource = CommonPageResource & {
79
- _type: "resource";
80
- subResources?: Array<Resource>;
81
- errorBoundary: ErrorBoundaryComponent;
82
- };
83
- type Modules = Array<Module>;
84
- type ResourceMetaProps = {
85
- /**
86
- * Title of the resource used in navigation.
87
- *
88
- * If not provided, the title will be generated from the path.
89
- */
90
- title?: string;
91
- icon?: ReactNode;
92
- /**
93
- * Custom breadcrumb segment title for this resource. Can be a string or a function.
94
- */
95
- breadcrumbTitle?: string | ((segment: string) => string);
96
- };
97
- type CommonProps = {
98
- /**
99
- * Path of the resource.
100
- *
101
- * The path will be used to generate the URL for the resource.
102
- * This also supports dynamic parameters using the syntax `:paramName`.
103
- */
104
- path: string;
105
- /**
106
- * Metadata for the resource.
107
- */
108
- meta?: ResourceMetaProps;
109
- };
110
- type ResourceComponentProps = {
111
- title: string;
112
- icon?: ReactNode;
113
- resources?: Array<Resource>;
114
- };
115
- type ReactResourceProps = {
116
- /**
117
- * React component to render.
118
- */
119
- component: (props: ResourceComponentProps) => ReactNode;
120
- };
121
- type CommonModuleProps = {
122
- /**
123
- * Resource associated to the module.
124
- */
125
- resources: Array<Resource>;
126
- meta: CommonProps["meta"] & {
127
- icon?: ReactNode;
128
- };
129
- };
130
- type DefineModuleProps = CommonProps & CommonModuleProps & {
131
- /**
132
- * React component to render or redirect configuration
133
- *
134
- * @example
135
- * ```tsx
136
- * // Render a component
137
- * component: (props) => <div>{props.title}</div>
138
- *
139
- * // Redirect to a resource
140
- * component: redirectToResource("dashboard/overview")
141
- * ```
142
- */
143
- component: ((props: ResourceComponentProps) => ReactNode) | RedirectConfig;
144
- /**
145
- * Error boundary component for this module and its child resources.
146
- * When an error occurs in this module or its resources, this component will render.
147
- * Use the `useRouteError` hook to access error details within the component.
148
- */
149
- errorBoundary?: ErrorBoundaryComponent;
150
- };
151
- /**
152
- * Define a root-level resource that renders a React component.
153
- *
154
- * @example
155
- * ```
156
- * // Define a minimal resource
157
- * defineReactResource({
158
- * path: "custom-page",
159
- * component: () => {
160
- * return (
161
- * <div>
162
- * <p>This is a custom page.</p>
163
- * </div>
164
- * );
165
- * },
166
- * });
167
- * ```
168
- */
169
- declare function defineModule(props: DefineModuleProps): Module;
170
- type DefineResourceProps = CommonProps & ReactResourceProps & {
171
- /**
172
- * Sub-resources of the resource.
173
- */
174
- subResources?: Array<Resource>;
175
- /**
176
- * Error boundary component for this resource and its sub-resources.
177
- * When an error occurs in this resource, this component will render.
178
- * Overrides module-level or global error boundaries.
179
- * Use the `useRouteError` hook to access error details within the component.
180
- */
181
- errorBoundary?: ErrorBoundaryComponent;
182
- };
183
- /**
184
- * Define a resource that renders a React component.
185
- *
186
- * This resource can be used as a sub-resource of a module or as a root-level resource.
187
- *
188
- * @example
189
- * ```
190
- * // Define a minimal resource
191
- * defineResource({
192
- * path: "custom-page",
193
- * component: () => {
194
- * return (
195
- * <div>
196
- * <p>This is a custom page.</p>
197
- * </div>
198
- * );
199
- * },
200
- * subResources: [
201
- * defineResource({
202
- * path: "sub-page",
203
- * component: () => {
204
- * return (
205
- * <div>
206
- * <p>This is a sub page.</p>
207
- * </div>
208
- * );
209
- * },
210
- * }),
211
- * ]
212
- * });
213
- * ```
214
- *
215
- */
216
- declare function defineResource(props: DefineResourceProps): Resource;
217
-
218
- type AppShellProps = React.PropsWithChildren<{
219
- /**
220
- * App shell title
221
- */
222
- title?: string;
223
- /**
224
- * App shell icon
225
- */
226
- icon?: React.ReactNode;
227
- /**
228
- * Base path for the app shell
229
- */
230
- basePath?: string;
231
- /**
232
- * A component to be rendered at the root level of AppShell,
233
- * or a redirect configuration
234
- *
235
- * @example
236
- * ```tsx
237
- * // Render a component
238
- * rootComponent: () => <DashboardHome />
239
- *
240
- * // Redirect to a resource
241
- * rootComponent: redirectToResource("dashboard/overview")
242
- * ```
243
- */
244
- rootComponent?: (() => React.ReactNode) | RedirectConfig;
245
- /**
246
- * Navigation configuration
247
- */
248
- modules: Modules;
249
- /**
250
- * Settings resources to be included in the settings menu
251
- */
252
- settingsResources?: Array<Resource>;
253
- /**
254
- * Global error boundary component applied to all routes.
255
- * When an error occurs in any route component, this component will render.
256
- * Module and resource-level error boundaries take precedence over this.
257
- * Use the `useRouteError` hook to access error details within the component.
258
- *
259
- * @example
260
- * ```tsx
261
- * import { useRouteError } from "@tailor-platform/app-shell";
262
- *
263
- * const GlobalErrorBoundary = () => {
264
- * const error = useRouteError() as Error;
265
- * return (
266
- * <div>
267
- * <h1>Something went wrong</h1>
268
- * <p>{error.message}</p>
269
- * </div>
270
- * );
271
- * };
272
- *
273
- * <AppShell
274
- * modules: [...],
275
- * errorBoundary: <GlobalErrorBoundary />,
276
- * />
277
- * ```
278
- */
279
- errorBoundary?: ErrorBoundaryComponent;
280
- }>;
281
- declare const AppShell: (props: AppShellProps) => react_jsx_runtime.JSX.Element | null;
282
-
283
- type SidebarLayoutProps = {
284
- children?: (props: {
285
- Outlet: () => React.ReactNode;
286
- }) => React.ReactNode;
287
- sidebar?: React.ReactNode;
288
- };
289
- declare const SidebarLayout: (props: SidebarLayoutProps) => react_jsx_runtime.JSX.Element;
290
- type DefaultSidebarProps = {
291
- header?: React.ReactNode;
292
- footer?: React.ReactNode;
293
- };
294
- declare const DefaultSidebar: (props: DefaultSidebarProps) => react_jsx_runtime.JSX.Element;
295
-
296
- type RootConfiguration = {
297
- modules: Modules;
298
- settingsResources: Resource[];
299
- basePath?: string;
300
- errorBoundary: ErrorBoundaryComponent;
301
- };
302
- type NavChildItem = {
303
- title: string;
304
- url: string;
305
- };
306
- type NavItem = {
307
- title: string;
308
- url: string | undefined;
309
- icon: ReactNode;
310
- isActive?: boolean;
311
- items?: Array<NavChildItem>;
312
- };
313
- type AppShellContextType = {
314
- title?: string;
315
- icon?: ReactNode;
316
- configurations: RootConfiguration;
317
- navItems: Array<NavItem>;
318
- };
319
- declare const useAppShell: () => AppShellContextType;
320
-
321
- type Theme = "dark" | "light" | "system";
322
- type ThemeProviderState = {
323
- theme: Theme;
324
- resolvedTheme: Omit<Theme, "system">;
325
- setTheme: (theme: Theme) => void;
326
- };
327
- declare const useTheme: () => ThemeProviderState;
328
-
329
- interface BuiltinIdPAuthContextType {
330
- /**
331
- * Initiates the login process by redirecting to the OAuth2 authorization endpoint.
332
- */
333
- login: () => Promise<void>;
334
- /**
335
- * Logs out the user by revoking the token and clearing session data.
336
- */
337
- logout: () => Promise<void>;
338
- }
339
- declare const useBuiltinIdpAuth: () => BuiltinIdPAuthContextType;
340
- type Props = {
341
- /**
342
- * API endpoint of your Tailor Platform application. No `/query` suffix needed.
343
- *
344
- * @example https://xyz.erp.dev
345
- */
346
- apiEndpoint: string;
347
- /**
348
- * OAuth2 Client ID of your Tailor Platform application.
349
- */
350
- clientId: string;
351
- /**
352
- * Redirect URI after login is successful.
353
- *
354
- * @defaults `window.location.origin`
355
- */
356
- redirectUri?: string;
357
- };
358
- declare const BuiltinIdPAuthProvider: ({ apiEndpoint, clientId, redirectUri, children, }: PropsWithChildren<Props>) => react_jsx_runtime.JSX.Element;
359
-
360
- declare const PKCE_VERIFIER_KEY = "oauth_pkce_verifier";
361
- declare const OAUTH_STATE_KEY = "oauth_state";
362
- interface BuildAuthorizationUrlParams {
363
- apiEndpoint: string;
364
- clientId: string;
365
- state: string;
366
- codeChallenge: string;
367
- redirectUri?: string;
368
- }
369
- /**
370
- * We need to build a Login URL with the correct parameters to redirect
371
- * to our OAuth endpoint login page
372
- */
373
- declare const buildAuthorizationUrl: ({ apiEndpoint, clientId, state, codeChallenge, redirectUri, }: BuildAuthorizationUrlParams) => string;
374
- interface ExchangeCodeForTokenParams {
375
- apiEndpoint: string;
376
- clientId: string;
377
- returnedState: string | null;
378
- code: string | null;
379
- redirectUri?: string;
380
- silent?: boolean;
381
- }
382
- /**
383
- * We need to exchange the code and state we received from the OAuth endpoint
384
- * for an actual authorization token, in Browser Client case, we get the token
385
- * inside of a cookie so there is nothing else to do beyond that point
386
- */
387
- declare const exchangeCodeForToken: ({ code, returnedState, apiEndpoint, clientId, redirectUri, }: ExchangeCodeForTokenParams) => Promise<string>;
388
- /**
389
- * We need to generate a challenge and state key for OAuth login
390
- * and stores them in sessionStorage for verification on callback redirect
391
- */
392
- declare const prepareLogin: () => Promise<{
393
- codeChallenge: string;
394
- state: string;
395
- }>;
396
- /**
397
- * When redirected from our IdP Provider, we need to exchange code and state
398
- * for a token and clean up the URL params
399
- */
400
- declare const handleOAuthCallback: ({ currentUrl, apiEndpoint, clientId, redirectUri, }: {
401
- currentUrl: URL;
402
- apiEndpoint: string;
403
- clientId: string;
404
- redirectUri: string;
405
- }) => Promise<void>;
406
-
407
- export { AppShell, type AppShellProps, BuiltinIdPAuthProvider, DefaultSidebar, type ErrorBoundaryComponent, OAUTH_STATE_KEY, PKCE_VERIFIER_KEY, type ResourceComponentProps, SidebarLayout, buildAuthorizationUrl, defineModule, defineResource, exchangeCodeForToken, handleOAuthCallback, prepareLogin, redirectToResource, useAppShell, useBuiltinIdpAuth, useTheme };
1
+ import { AuthState } from '@tailor-platform/auth-browser-client';
2
+ import { DocumentNode } from 'graphql';
3
+ import { JSX } from 'react/jsx-runtime';
4
+ import { Link } from 'react-router';
5
+ import { ReactNode } from 'react';
6
+ import { useLocation } from 'react-router';
7
+ import { useNavigate } from 'react-router';
8
+ import { useParams } from 'react-router';
9
+ import { useRouteError } from 'react-router';
10
+ import { useSearchParams } from 'react-router';
11
+
12
+ export declare const AppShell: (props: AppShellProps) => JSX.Element | null;
13
+
14
+ declare type AppShellContextType = {
15
+ title?: string;
16
+ icon?: ReactNode;
17
+ configurations: RootConfiguration;
18
+ navItems: Array<NavItem>;
19
+ };
20
+
21
+ export declare type AppShellProps = React.PropsWithChildren<{
22
+ /**
23
+ * App shell title
24
+ */
25
+ title?: string;
26
+ /**
27
+ * App shell icon
28
+ */
29
+ icon?: React.ReactNode;
30
+ /**
31
+ * Base path for the app shell
32
+ */
33
+ basePath?: string;
34
+ /**
35
+ * A component to be rendered at the root level of AppShell,
36
+ * or a redirect configuration
37
+ *
38
+ * @example
39
+ * ```tsx
40
+ * // Render a component
41
+ * rootComponent: () => <DashboardHome />
42
+ *
43
+ * // Redirect to a resource
44
+ * rootComponent: redirectToResource("dashboard/overview")
45
+ * ```
46
+ */
47
+ rootComponent?: (() => React.ReactNode) | RedirectConfig;
48
+ /**
49
+ * Navigation configuration
50
+ */
51
+ modules: Modules;
52
+ /**
53
+ * Settings resources to be included in the settings menu
54
+ */
55
+ settingsResources?: Array<Resource>;
56
+ /**
57
+ * Locale code used for built-in UI strings.
58
+ *
59
+ * If not provided, auto-detects from browser preferences.
60
+ * No browser locale information avilable, "en" used as default.
61
+ */
62
+ locale?: string;
63
+ /**
64
+ * Global error boundary component applied to all routes.
65
+ *
66
+ * When an error occurs in any route component, this component will render.
67
+ * Module and resource-level error boundaries take precedence over this.
68
+ * Use the `useRouteError` hook to access error details within the component.
69
+ *
70
+ * @example
71
+ * ```tsx
72
+ * import { useRouteError } from "@tailor-platform/app-shell";
73
+ *
74
+ * const GlobalErrorBoundary = () => {
75
+ * const error = useRouteError() as Error;
76
+ * return (
77
+ * <div>
78
+ * <h1>Something went wrong</h1>
79
+ * <p>{error.message}</p>
80
+ * </div>
81
+ * );
82
+ * };
83
+ *
84
+ * <AppShell
85
+ * modules: [...],
86
+ * errorBoundary: <GlobalErrorBoundary />,
87
+ * />
88
+ * ```
89
+ */
90
+ errorBoundary?: ErrorBoundaryComponent;
91
+ }>;
92
+
93
+ declare type AuthContextType = {
94
+ /**
95
+ * Current authentication state.
96
+ */
97
+ authState: AuthState<User>;
98
+ /**
99
+ * Initiates the login process.
100
+ *
101
+ * This redirects the user to the Tailor Platform authentication page.
102
+ */
103
+ login: () => Promise<void>;
104
+ /**
105
+ * Logs out the current user.
106
+ *
107
+ * This clears the authentication tokens and user session.
108
+ */
109
+ logout: () => Promise<void>;
110
+ /**
111
+ * Checks the current authentication status.
112
+ *
113
+ * Remember that this method always makes a network request to verify the auth status.
114
+ * If the user is authenticated, returns the user information and updates `authState` in the context.
115
+ *
116
+ * This also attempts to refresh tokens internally if they are expired.
117
+ */
118
+ checkAuthStatus: () => Promise<AuthState<User>>;
119
+ /**
120
+ * OAuth callback handler.
121
+ */
122
+ handleCallback: () => Promise<void>;
123
+ };
124
+
125
+ /**
126
+ * Authentication provider component.
127
+ *
128
+ * Wrap your application with this component to provide authentication context.
129
+ *
130
+ * @example
131
+ * ```tsx
132
+ * import { AuthProvider } from "@tailor-platform/app-shell";
133
+ *
134
+ * function App() {
135
+ * return (
136
+ * <AuthProvider
137
+ * apiEndpoint="https://xyz.erp.dev"
138
+ * clientId="your-client-id"
139
+ * >
140
+ * <YourAppComponents />
141
+ * </AuthProvider>
142
+ * );
143
+ * }
144
+ * ```
145
+ */
146
+ export declare const AuthProvider: (props: React.PropsWithChildren<AuthProviderProps>) => JSX.Element;
147
+
148
+ declare type AuthProviderProps = {
149
+ /**
150
+ * API endpoint of your Tailor Platform application. No `/query` suffix needed.
151
+ *
152
+ * @example https://xyz.erp.dev
153
+ */
154
+ apiEndpoint: string;
155
+ /**
156
+ * OAuth2 Client ID of your Tailor Platform application.
157
+ */
158
+ clientId: string;
159
+ /**
160
+ * GraphQL query to fetch the current authenticated user.
161
+ *
162
+ * The result of this query should return the user object.
163
+ * If you override `AuthRegister["user"]`, make sure to have the fields match your custom user type.
164
+ *
165
+ * @defaults
166
+ * ```graphql
167
+ * query {
168
+ * me {
169
+ * id
170
+ * email
171
+ * name
172
+ * }
173
+ * }
174
+ * ```
175
+ */
176
+ meQuery?: string | DocumentNode;
177
+ /**
178
+ * Redirect URI after login is successful.
179
+ *
180
+ * @defaults `window.location.origin`
181
+ */
182
+ redirectUri?: string;
183
+ /**
184
+ * Enable automatic login on initialization.
185
+ */
186
+ autoLogin?: boolean;
187
+ /**
188
+ * Guard UI component to show when loading or unauthenticated.
189
+ *
190
+ * If not provided, children will be just rendered in any auth state.
191
+ */
192
+ guardComponent?: () => React.ReactNode;
193
+ };
194
+
195
+ /**
196
+ * Registerable interface for type extension via module augmentation.
197
+ *
198
+ * @example
199
+ * // In your project's TypeScript file (e.g., app-shell.d.ts, App.tsx, etc.)
200
+ * declare module "@tailor-platform/app-shell" {
201
+ * interface AuthRegister {
202
+ * user: {
203
+ * id: string;
204
+ * email: string;
205
+ * name?: string;
206
+ * role: "admin" | "user";
207
+ * organizationId: string;
208
+ * }
209
+ * }
210
+ * }
211
+ */
212
+ export declare interface AuthRegister {
213
+ }
214
+
215
+ declare type CommonModuleProps = {
216
+ /**
217
+ * Resource associated to the module.
218
+ */
219
+ resources: Array<Resource>;
220
+ meta: CommonProps["meta"] & {
221
+ icon?: ReactNode;
222
+ };
223
+ };
224
+
225
+ declare type CommonPageResource = {
226
+ path: string;
227
+ type: "component";
228
+ component: () => ReactNode;
229
+ meta: {
230
+ title: LocalizedString;
231
+ icon?: ReactNode;
232
+ };
233
+ };
234
+
235
+ declare type CommonProps = {
236
+ /**
237
+ * Path of the resource.
238
+ *
239
+ * The path will be used to generate the URL for the resource.
240
+ * This also supports dynamic parameters using the syntax `:paramName`.
241
+ */
242
+ path: string;
243
+ /**
244
+ * Metadata for the resource.
245
+ */
246
+ meta?: ResourceMetaProps;
247
+ };
248
+
249
+ export declare const DefaultSidebar: (props: DefaultSidebarProps) => JSX.Element;
250
+
251
+ declare type DefaultSidebarProps = {
252
+ header?: React.ReactNode;
253
+ footer?: React.ReactNode;
254
+ };
255
+
256
+ /**
257
+ * Default user type when no custom user type is registered.
258
+ *
259
+ * You can extend this type via module augmentation:
260
+ * @example
261
+ * declare module "@tailor-platform/app-shell" {
262
+ * interface Register {
263
+ * user: DefaultUser & {
264
+ * role: "admin" | "user";
265
+ * organizationId: string;
266
+ * }
267
+ * }
268
+ * }
269
+ */
270
+ export declare type DefaultUser = {
271
+ id: string;
272
+ email: string;
273
+ name?: string;
274
+ };
275
+
276
+ /**
277
+ * Defines internationalization labels for multiple locales.
278
+ *
279
+ * `en` locale is required as the default locale.
280
+ * Labels can be either static strings or dynamic functions that take props.
281
+ *
282
+ * @example
283
+ * ```tsx
284
+ * import { defineI18nLabels } from "@tailor-platform/app-shell";
285
+ *
286
+ * export const labels = defineI18nLabels({
287
+ * en: {
288
+ * hello: "Hello",
289
+ * welcome: (props: { name: string }) => `Welcome, ${props.name}!`,
290
+ * },
291
+ * ja: {
292
+ * hello: "こんにちは",
293
+ * welcome: (props: { name: string }) => `ようこそ、${props.name}さん!`,
294
+ * },
295
+ * });
296
+ *
297
+ * // Hook to get the translated label resolver function
298
+ * export const useT = labels.useT;
299
+ *
300
+ * // Usage in component
301
+ * const t = useT();
302
+ * t("hello"); // "Hello"
303
+ * t("welcome", { name: "John" }); // "Welcome, John!"
304
+ * ```
305
+ */
306
+ export declare const defineI18nLabels: <const L extends Exclude<string, "en">, const Def extends Record<string, LabelValue>>(labels: {
307
+ en: Def;
308
+ } & { [K in L]: LabelDefinition<Def>; } & DynamicLocales<Def>) => {
309
+ /**
310
+ * Hook to get the translated label resolver function.
311
+ *
312
+ * @example
313
+ * ```tsx
314
+ * import { useT } from "./i18n-labels";
315
+ *
316
+ * const YourComponent = () => {
317
+ * const t = useT();
318
+ *
319
+ * return (
320
+ * <div>
321
+ * {t("staticLabel")}
322
+ * {t("dynamicLabel", { name: "John" })}
323
+ * </div>
324
+ * );
325
+ * }
326
+ * ```
327
+ */
328
+ useT: () => <K extends keyof Def & string>(key: K, ...args: Def[K] extends (props: infer P) => string ? [props: P] : []) => string;
329
+ /**
330
+ * A function to get the translater for a specific label key.
331
+ * This is expected to be used in `meta.title` in module/resource definitions.
332
+ *
333
+ * Note: When using dynamic labels with props in meta.title, the props are
334
+ * bound at definition time (when calling labels.t), not at render time.
335
+ *
336
+ * @example
337
+ * ```tsx
338
+ * import { labels } from "./i18n-labels";
339
+ *
340
+ * const resource = defineResource({
341
+ * path: "example",
342
+ * meta: {
343
+ * title: labels.t("someLabelKey"),
344
+ * // or with props for dynamic labels
345
+ * title: labels.t("dynamicKey", { id: "123" }),
346
+ * },
347
+ * component: ExampleComponent,
348
+ * });
349
+ * ```
350
+ */
351
+ t: <K extends keyof Def & string>(key: K, ...args: Def[K] extends (props: infer P) => string ? [props: P] : []) => LocalizedString;
352
+ };
353
+
354
+ /**
355
+ * Define a root-level resource that renders a React component.
356
+ *
357
+ * @example
358
+ * ```
359
+ * // Define a minimal resource
360
+ * defineReactResource({
361
+ * path: "custom-page",
362
+ * component: () => {
363
+ * return (
364
+ * <div>
365
+ * <p>This is a custom page.</p>
366
+ * </div>
367
+ * );
368
+ * },
369
+ * });
370
+ * ```
371
+ */
372
+ export declare function defineModule(props: DefineModuleProps): Module;
373
+
374
+ declare type DefineModuleProps = CommonProps & CommonModuleProps & {
375
+ /**
376
+ * React component to render or redirect configuration
377
+ *
378
+ * @example
379
+ * ```tsx
380
+ * // Render a component
381
+ * component: (props) => <div>{props.title}</div>
382
+ *
383
+ * // Redirect to a resource
384
+ * component: redirectToResource("dashboard/overview")
385
+ * ```
386
+ */
387
+ component: ((props: ResourceComponentProps) => ReactNode) | RedirectConfig;
388
+ /**
389
+ * Error boundary component for this module and its child resources.
390
+ * When an error occurs in this module or its resources, this component will render.
391
+ * Use the `useRouteError` hook to access error details within the component.
392
+ */
393
+ errorBoundary?: ErrorBoundaryComponent;
394
+ };
395
+
396
+ /**
397
+ * Define a resource that renders a React component.
398
+ *
399
+ * This resource can be used as a sub-resource of a module or as a root-level resource.
400
+ *
401
+ * @example
402
+ * ```
403
+ * // Define a minimal resource
404
+ * defineResource({
405
+ * path: "custom-page",
406
+ * component: () => {
407
+ * return (
408
+ * <div>
409
+ * <p>This is a custom page.</p>
410
+ * </div>
411
+ * );
412
+ * },
413
+ * subResources: [
414
+ * defineResource({
415
+ * path: "sub-page",
416
+ * component: () => {
417
+ * return (
418
+ * <div>
419
+ * <p>This is a sub page.</p>
420
+ * </div>
421
+ * );
422
+ * },
423
+ * }),
424
+ * ]
425
+ * });
426
+ * ```
427
+ *
428
+ */
429
+ export declare function defineResource(props: DefineResourceProps): Resource;
430
+
431
+ declare type DefineResourceProps = CommonProps & ReactResourceProps & {
432
+ /**
433
+ * Sub-resources of the resource.
434
+ */
435
+ subResources?: Array<Resource>;
436
+ /**
437
+ * Error boundary component for this resource and its sub-resources.
438
+ * When an error occurs in this resource, this component will render.
439
+ * Overrides module-level or global error boundaries.
440
+ * Use the `useRouteError` hook to access error details within the component.
441
+ */
442
+ errorBoundary?: ErrorBoundaryComponent;
443
+ };
444
+
445
+ declare type DynamicLocales<Def extends Record<string, LabelValue>> = {
446
+ [locale: string]: Partial<LabelDefinition<Def>> | undefined;
447
+ };
448
+
449
+ /**
450
+ * Error boundary element type for route error handling.
451
+ *
452
+ * Pass a JSX element that will render when an error occurs.
453
+ * Use the `useRouteError` hook from react-router to access the error.
454
+ *
455
+ * @example
456
+ * ```tsx
457
+ * import { useRouteError } from "@tailor-platform/app-shell";
458
+ *
459
+ * const MyErrorBoundary = () => {
460
+ * const error = useRouteError() as Error;
461
+ * return <div>Error: {error.message}</div>;
462
+ * };
463
+ *
464
+ * // In config:
465
+ * errorBoundary: <MyErrorBoundary />
466
+ * // Or with props:
467
+ * errorBoundary: <MyErrorBoundary theme="dark" onReport={handleReport} />
468
+ * ```
469
+ */
470
+ export declare type ErrorBoundaryComponent = ReactNode;
471
+
472
+ export declare type I18nLabels<Def extends Record<string, LabelValue> = Record<string, LabelValue>, L extends string = never> = {
473
+ en: Def;
474
+ } & {
475
+ [K in L]: LabelDefinition<Def>;
476
+ } & DynamicLocales<Def>;
477
+
478
+ /**
479
+ * Ensures that other locales have the same label structure as the base definition.
480
+ * For dynamic labels (functions), the props type must match.
481
+ */
482
+ declare type LabelDefinition<Def extends Record<string, LabelValue>> = {
483
+ [K in keyof Def]: Def[K] extends (props: infer P) => string ? (props: P) => string : string;
484
+ };
485
+
486
+ /**
487
+ * Label value can be either a static string or a dynamic function that takes props.
488
+ */
489
+ declare type LabelValue = string | ((props: any) => string);
490
+
491
+ export { Link }
492
+
493
+ declare type LocalizedString = string | ((locale: string) => string);
494
+
495
+ /**
496
+ * A resource that can be included in the root-level content in the navigation.
497
+ */
498
+ declare type Module = Omit<CommonPageResource, "meta"> & {
499
+ _type: "module";
500
+ meta: CommonPageResource["meta"] & {
501
+ icon?: ReactNode;
502
+ menuItemClickable: boolean;
503
+ };
504
+ resources: Array<Resource>;
505
+ loader?: () => Response;
506
+ errorBoundary: ErrorBoundaryComponent;
507
+ };
508
+
509
+ declare type Modules = Array<Module>;
510
+
511
+ declare type NavChildItem = {
512
+ title: string;
513
+ url: string;
514
+ };
515
+
516
+ declare type NavItem = {
517
+ title: string;
518
+ url: string | undefined;
519
+ icon: ReactNode;
520
+ isActive?: boolean;
521
+ items?: Array<NavChildItem>;
522
+ };
523
+
524
+ declare type ReactResourceProps = {
525
+ /**
526
+ * React component to render.
527
+ */
528
+ component: (props: ResourceComponentProps) => ReactNode;
529
+ };
530
+
531
+ /**
532
+ * Redirect configuration for module or root component
533
+ */
534
+ declare type RedirectConfig = {
535
+ /**
536
+ * Path to redirect to (under /resources/)
537
+ */
538
+ redirectTo: string;
539
+ };
540
+
541
+ /**
542
+ * Helper function to define a redirect to a resource path
543
+ *
544
+ * @param path - Path under `/resources/` (e.g., "dashboard/overview")
545
+ *
546
+ * @example
547
+ * ```tsx
548
+ * defineModule({
549
+ * path: "dashboard",
550
+ * component: redirectToResource("dashboard/overview"),
551
+ * resources: [overviewResource],
552
+ * });
553
+ * ```
554
+ */
555
+ export declare function redirectToResource(path: string): RedirectConfig;
556
+
557
+ /**
558
+ * A resource that can be included in the sub-content in the root resource.
559
+ *
560
+ * This resource does not have `category` metadata.
561
+ */
562
+ declare type Resource = CommonPageResource & {
563
+ _type: "resource";
564
+ subResources?: Array<Resource>;
565
+ errorBoundary: ErrorBoundaryComponent;
566
+ };
567
+
568
+ export declare type ResourceComponentProps = {
569
+ title: string;
570
+ icon?: ReactNode;
571
+ resources?: Array<Resource>;
572
+ };
573
+
574
+ declare type ResourceMetaProps = {
575
+ /**
576
+ * Title of the resource used in navigation.
577
+ *
578
+ * If not provided, the title will be generated from the path.
579
+ */
580
+ title?: LocalizedString;
581
+ icon?: ReactNode;
582
+ /**
583
+ * Custom breadcrumb segment title for this resource. Can be a string or a function.
584
+ */
585
+ breadcrumbTitle?: string | ((segment: string) => string);
586
+ };
587
+
588
+ declare type RootConfiguration = {
589
+ modules: Modules;
590
+ settingsResources: Resource[];
591
+ basePath?: string;
592
+ errorBoundary: ErrorBoundaryComponent;
593
+ locale: string;
594
+ };
595
+
596
+ export declare const SidebarLayout: (props: SidebarLayoutProps) => JSX.Element;
597
+
598
+ declare type SidebarLayoutProps = {
599
+ children?: (props: {
600
+ Outlet: () => React.ReactNode;
601
+ }) => React.ReactNode;
602
+ sidebar?: React.ReactNode;
603
+ };
604
+
605
+ declare type Theme = "dark" | "light" | "system";
606
+
607
+ declare type ThemeProviderState = {
608
+ theme: Theme;
609
+ resolvedTheme: Omit<Theme, "system">;
610
+ setTheme: (theme: Theme) => void;
611
+ };
612
+
613
+ export declare const useAppShell: () => AppShellContextType;
614
+
615
+ export declare const useAuth: () => AuthContextType;
616
+
617
+ export { useLocation }
618
+
619
+ export { useNavigate }
620
+
621
+ export { useParams }
622
+
623
+ /**
624
+ * User type that can be extended via the AuthRegister interface.
625
+ *
626
+ * If `AuthRegister["user"]` is defined, it will be used as the User type.
627
+ * Otherwise, the DefaultUser type will be used.
628
+ */
629
+ declare type User = AuthRegister extends {
630
+ user: infer TUser;
631
+ } ? TUser : DefaultUser;
632
+
633
+ export { useRouteError }
634
+
635
+ export { useSearchParams }
636
+
637
+ export declare const useTheme: () => ThemeProviderState;
638
+
639
+ export { }