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