@alepha/react 0.9.2 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +46 -0
  2. package/dist/index.browser.js +378 -325
  3. package/dist/index.browser.js.map +1 -1
  4. package/dist/index.cjs +570 -458
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.cts +305 -213
  7. package/dist/index.d.cts.map +1 -1
  8. package/dist/index.d.ts +304 -212
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +567 -460
  11. package/dist/index.js.map +1 -1
  12. package/package.json +16 -13
  13. package/src/components/ErrorViewer.tsx +1 -1
  14. package/src/components/Link.tsx +4 -24
  15. package/src/components/NestedView.tsx +20 -9
  16. package/src/components/NotFound.tsx +5 -2
  17. package/src/descriptors/$page.ts +86 -12
  18. package/src/errors/Redirection.ts +13 -0
  19. package/src/hooks/useActive.ts +28 -30
  20. package/src/hooks/useAlepha.ts +16 -2
  21. package/src/hooks/useClient.ts +7 -2
  22. package/src/hooks/useInject.ts +4 -1
  23. package/src/hooks/useQueryParams.ts +9 -6
  24. package/src/hooks/useRouter.ts +18 -30
  25. package/src/hooks/useRouterEvents.ts +7 -4
  26. package/src/hooks/useRouterState.ts +8 -20
  27. package/src/hooks/useSchema.ts +10 -15
  28. package/src/hooks/useStore.ts +9 -8
  29. package/src/index.browser.ts +11 -11
  30. package/src/index.shared.ts +4 -5
  31. package/src/index.ts +21 -30
  32. package/src/providers/ReactBrowserProvider.ts +155 -65
  33. package/src/providers/ReactBrowserRouterProvider.ts +132 -0
  34. package/src/providers/{PageDescriptorProvider.ts → ReactPageProvider.ts} +164 -112
  35. package/src/providers/ReactServerProvider.ts +100 -68
  36. package/src/{hooks/RouterHookApi.ts → services/ReactRouter.ts} +75 -61
  37. package/src/contexts/RouterContext.ts +0 -14
  38. package/src/errors/RedirectionError.ts +0 -10
  39. package/src/providers/BrowserRouterProvider.ts +0 -146
  40. package/src/providers/ReactBrowserRenderer.ts +0 -93
package/dist/index.d.cts CHANGED
@@ -1,21 +1,15 @@
1
- import * as _alepha_core2 from "@alepha/core";
2
- import * as _alepha_core16 from "@alepha/core";
3
- import * as _alepha_core0$1 from "@alepha/core";
4
- import * as _alepha_core6 from "@alepha/core";
5
- import * as _alepha_core0 from "@alepha/core";
1
+ import * as _alepha_core14 from "@alepha/core";
6
2
  import { Alepha, Async, Descriptor, KIND, Service, State, Static, TObject, TSchema } from "@alepha/core";
7
- import { ApiLinksResponse, RequestConfigSchema, ServerHandler, ServerRequest, ServerRouterProvider, ServerTimingProvider } from "@alepha/server";
8
- import * as react0$1 from "react";
9
- import * as react0 from "react";
10
- import * as react1 from "react";
11
- import React, { AnchorHTMLAttributes, ErrorInfo, FC, PropsWithChildren, ReactNode } from "react";
12
- import { ServerRouteCache } from "@alepha/server-cache";
3
+ import { RequestConfigSchema, ServerHandler, ServerRequest, ServerRouterProvider, ServerTimingProvider } from "@alepha/server";
4
+ import * as _alepha_logger1 from "@alepha/logger";
5
+ import { DateTimeProvider } from "@alepha/datetime";
13
6
  import { ClientScope, HttpVirtualClient, LinkProvider, VirtualAction } from "@alepha/server-links";
14
7
  import { Root } from "react-dom/client";
15
8
  import { Route, RouterProvider } from "@alepha/router";
16
- import * as react_jsx_runtime1 from "react/jsx-runtime";
9
+ import * as react0 from "react";
10
+ import React, { AnchorHTMLAttributes, CSSProperties, ErrorInfo, FC, PropsWithChildren, ReactNode } from "react";
11
+ import { ServerRouteCache } from "@alepha/server-cache";
17
12
  import * as react_jsx_runtime0 from "react/jsx-runtime";
18
- import * as react_jsx_runtime2 from "react/jsx-runtime";
19
13
  import { ServerStaticProvider } from "@alepha/server-static";
20
14
 
21
15
  //#region src/components/ClientOnly.d.ts
@@ -35,6 +29,17 @@ interface ClientOnlyProps {
35
29
  */
36
30
  declare const ClientOnly: (props: PropsWithChildren<ClientOnlyProps>) => ReactNode;
37
31
  //#endregion
32
+ //#region src/errors/Redirection.d.ts
33
+ /**
34
+ * Used for Redirection during the page loading.
35
+ *
36
+ * Depends on the context, it can be thrown or just returned.
37
+ */
38
+ declare class Redirection extends Error {
39
+ readonly redirect: string;
40
+ constructor(redirect: string);
41
+ }
42
+ //#endregion
38
43
  //#region src/descriptors/$page.d.ts
39
44
  /**
40
45
  * Main descriptor for defining a React route in the application.
@@ -109,30 +114,81 @@ interface PageDescriptorOptions<TConfig extends PageConfigSchema = PageConfigSch
109
114
  children?: Array<PageDescriptor> | (() => Array<PageDescriptor>);
110
115
  parent?: PageDescriptor<PageConfigSchema, TPropsParent>;
111
116
  can?: () => boolean;
112
- errorHandler?: (error: Error) => ReactNode;
113
117
  /**
114
- * If true, the page will be rendered on the build time.
115
- * Works only with viteAlepha plugin.
118
+ * Catch any error from the `resolve` function or during `rendering`.
119
+ *
120
+ * Expected to return one of the following:
121
+ * - a ReactNode to render an error page
122
+ * - a Redirection to redirect the user
123
+ * - undefined to let the error propagate
124
+ *
125
+ * If not defined, the error will be thrown and handled by the server or client error handler.
126
+ * If a leaf $page does not define an error handler, the error can be caught by parent pages.
116
127
  *
128
+ * @example Catch a 404 from API and render a custom not found component:
129
+ * ```ts
130
+ * resolve: async ({ params, query }) => {
131
+ * api.fetch("/api/resource", { params, query });
132
+ * },
133
+ * errorHandler: (error, context) => {
134
+ * if (HttpError.is(error, 404)) {
135
+ * return <ResourceNotFound />;
136
+ * }
137
+ * }
138
+ * ```
139
+ *
140
+ * @example Catch an 401 error and redirect the user to the login page:
141
+ * ```ts
142
+ * resolve: async ({ params, query }) => {
143
+ * // but the user is not authenticated
144
+ * api.fetch("/api/resource", { params, query });
145
+ * },
146
+ * errorHandler: (error, context) => {
147
+ * if (HttpError.is(error, 401)) {
148
+ * // throwing a Redirection is also valid!
149
+ * return new Redirection("/login");
150
+ * }
151
+ * }
152
+ * ```
153
+ */
154
+ errorHandler?: ErrorHandler;
155
+ /**
156
+ * If true, the page will be considered as a static page, immutable and cacheable.
117
157
  * Replace boolean by an object to define static entries. (e.g. list of params/query)
158
+ *
159
+ * For now, it only works with `@alepha/vite` which can pre-render the page at build time.
160
+ *
161
+ * It will act as timeless cached page server-side. You can use `cache` to configure the cache behavior.
118
162
  */
119
163
  static?: boolean | {
120
164
  entries?: Array<Partial<PageRequestConfig<TConfig>>>;
121
165
  };
166
+ cache?: ServerRouteCache;
122
167
  /**
123
- * If true, the page will be rendered on the client-side.
168
+ * If true, force the page to be rendered only on the client-side.
169
+ * It uses the `<ClientOnly/>` component to render the page.
124
170
  */
125
171
  client?: boolean | ClientOnlyProps;
126
- afterHandler?: (request: ServerRequest) => any;
127
- cache?: ServerRouteCache;
172
+ /**
173
+ * Called before the server response is sent to the client.
174
+ */
175
+ onServerResponse?: (request: ServerRequest) => any;
176
+ /**
177
+ * Called when user leaves the page. (browser only)
178
+ */
179
+ onLeave?: () => void;
128
180
  }
181
+ type ErrorHandler = (error: Error, state: ReactRouterState) => ReactNode | Redirection | undefined;
129
182
  declare class PageDescriptor<TConfig extends PageConfigSchema = PageConfigSchema, TProps extends object = TPropsDefault, TPropsParent extends object = TPropsParentDefault> extends Descriptor<PageDescriptorOptions<TConfig, TProps, TPropsParent>> {
183
+ protected onInit(): void;
130
184
  get name(): string;
131
185
  /**
132
186
  * For testing or build purposes, this will render the page (with or without the HTML layout) and return the HTML and context.
133
187
  * Only valid for server-side rendering, it will throw an error if called on the client-side.
134
188
  */
135
189
  render(options?: PageDescriptorRenderOptions): Promise<PageDescriptorRenderResult>;
190
+ match(url: string): boolean;
191
+ pathname(config: any): string;
136
192
  }
137
193
  interface PageConfigSchema {
138
194
  query?: TSchema;
@@ -148,24 +204,23 @@ interface PageDescriptorRenderOptions {
148
204
  }
149
205
  interface PageDescriptorRenderResult {
150
206
  html: string;
151
- context: PageReactContext;
207
+ state: ReactRouterState;
152
208
  }
153
209
  interface PageRequestConfig<TConfig extends PageConfigSchema = PageConfigSchema> {
154
210
  params: TConfig["params"] extends TSchema ? Static<TConfig["params"]> : Record<string, string>;
155
211
  query: TConfig["query"] extends TSchema ? Static<TConfig["query"]> : Record<string, string>;
156
212
  }
157
- type PageResolve<TConfig extends PageConfigSchema = PageConfigSchema, TPropsParent extends object = TPropsParentDefault> = PageRequestConfig<TConfig> & TPropsParent & PageReactContext;
158
- //# sourceMappingURL=$page.d.ts.map
213
+ type PageResolve<TConfig extends PageConfigSchema = PageConfigSchema, TPropsParent extends object = TPropsParentDefault> = PageRequestConfig<TConfig> & TPropsParent & Omit<ReactRouterState, "layers" | "onError">;
159
214
  //#endregion
160
- //#region src/providers/PageDescriptorProvider.d.ts
161
- declare const envSchema$1: _alepha_core2.TObject<{
162
- REACT_STRICT_MODE: _alepha_core2.TBoolean;
215
+ //#region src/providers/ReactPageProvider.d.ts
216
+ declare const envSchema$2: _alepha_core14.TObject<{
217
+ REACT_STRICT_MODE: _alepha_core14.TBoolean;
163
218
  }>;
164
219
  declare module "@alepha/core" {
165
- interface Env extends Partial<Static<typeof envSchema$1>> {}
220
+ interface Env extends Partial<Static<typeof envSchema$2>> {}
166
221
  }
167
- declare class PageDescriptorProvider {
168
- protected readonly log: _alepha_core2.Logger;
222
+ declare class ReactPageProvider {
223
+ protected readonly log: _alepha_logger1.Logger;
169
224
  protected readonly env: {
170
225
  REACT_STRICT_MODE: boolean;
171
226
  };
@@ -173,13 +228,23 @@ declare class PageDescriptorProvider {
173
228
  protected readonly pages: PageRoute[];
174
229
  getPages(): PageRoute[];
175
230
  page(name: string): PageRoute;
231
+ pathname(name: string, options?: {
232
+ params?: Record<string, string>;
233
+ query?: Record<string, string>;
234
+ }): string;
176
235
  url(name: string, options?: {
177
236
  params?: Record<string, string>;
178
- base?: string;
237
+ host?: string;
179
238
  }): URL;
180
- root(state: RouterState, context: PageReactContext): ReactNode;
181
- createLayers(route: PageRoute, request: PageRequest): Promise<CreateLayersResult>;
182
- protected getErrorHandler(route: PageRoute): ((error: Error) => ReactNode) | undefined;
239
+ root(state: ReactRouterState): ReactNode;
240
+ /**
241
+ * Create a new RouterState based on a given route and request.
242
+ * This method resolves the layers for the route, applying any query and params schemas defined in the route.
243
+ * It also handles errors and redirects.
244
+ */
245
+ createLayers(route: PageRoute, state: ReactRouterState, previous?: PreviousLayerData[]): Promise<CreateLayersResult>;
246
+ protected createRedirectionLayer(redirect: string): CreateLayersResult;
247
+ protected getErrorHandler(route: PageRoute): ErrorHandler | undefined;
183
248
  protected createElement(page: PageRoute, props: Record<string, any>): Promise<ReactNode>;
184
249
  renderError(error: Error): ReactNode;
185
250
  renderEmptyView(): ReactNode;
@@ -190,7 +255,7 @@ declare class PageDescriptorProvider {
190
255
  }, params?: Record<string, any>): string;
191
256
  compile(path: string, params?: Record<string, string>): string;
192
257
  protected renderView(index: number, path: string, view: ReactNode | undefined, page: PageRoute): ReactNode;
193
- protected readonly configure: _alepha_core2.HookDescriptor<"configure">;
258
+ protected readonly configure: _alepha_core14.HookDescriptor<"configure">;
194
259
  protected map(pages: Array<PageDescriptor>, target: PageDescriptor): PageRouteEntry;
195
260
  add(entry: PageRouteEntry): void;
196
261
  protected createMatch(page: PageRoute): string;
@@ -226,17 +291,29 @@ interface Layer {
226
291
  type PreviousLayerData = Omit<Layer, "element" | "index" | "path">;
227
292
  interface AnchorProps {
228
293
  href: string;
229
- onClick: (ev: any) => any;
294
+ onClick: (ev?: any) => any;
230
295
  }
231
- interface RouterState {
232
- pathname: string;
233
- search: string;
296
+ interface ReactRouterState {
297
+ /**
298
+ * Stack of layers for the current page.
299
+ */
234
300
  layers: Array<Layer>;
235
- }
236
- interface TransitionOptions {
237
- state?: RouterState;
238
- previous?: PreviousLayerData[];
239
- context?: PageReactContext;
301
+ /**
302
+ * URL of the current page.
303
+ */
304
+ url: URL;
305
+ /**
306
+ * Error handler for the current page.
307
+ */
308
+ onError: ErrorHandler;
309
+ /**
310
+ * Params extracted from the URL for the current page.
311
+ */
312
+ params: Record<string, any>;
313
+ /**
314
+ * Query parameters extracted from the URL for the current page.
315
+ */
316
+ query: Record<string, string>;
240
317
  }
241
318
  interface RouterStackItem {
242
319
  route: PageRoute;
@@ -245,82 +322,98 @@ interface RouterStackItem {
245
322
  error?: Error;
246
323
  cache?: boolean;
247
324
  }
248
- interface RouterRenderResult {
249
- state: RouterState;
250
- context: PageReactContext;
251
- redirect?: string;
252
- }
253
- interface PageRequest extends PageReactContext {
254
- params: Record<string, any>;
255
- query: Record<string, string>;
325
+ interface TransitionOptions {
256
326
  previous?: PreviousLayerData[];
257
327
  }
258
- interface CreateLayersResult extends RouterState {
328
+ interface CreateLayersResult {
259
329
  redirect?: string;
260
- }
261
- /**
262
- * It's like RouterState, but publicly available in React context.
263
- * This is where we store all plugin data!
264
- */
265
- interface PageReactContext {
266
- url: URL;
267
- onError: (error: Error) => ReactNode;
268
- links?: ApiLinksResponse;
330
+ state?: ReactRouterState;
269
331
  }
270
332
  //#endregion
271
- //#region src/providers/BrowserRouterProvider.d.ts
333
+ //#region src/providers/ReactBrowserRouterProvider.d.ts
272
334
  interface BrowserRoute extends Route {
273
335
  page: PageRoute;
274
336
  }
275
- declare class BrowserRouterProvider extends RouterProvider<BrowserRoute> {
276
- protected readonly log: _alepha_core16.Logger;
337
+ declare class ReactBrowserRouterProvider extends RouterProvider<BrowserRoute> {
338
+ protected readonly log: _alepha_logger1.Logger;
277
339
  protected readonly alepha: Alepha;
278
- protected readonly pageDescriptorProvider: PageDescriptorProvider;
340
+ protected readonly pageApi: ReactPageProvider;
279
341
  add(entry: PageRouteEntry): void;
280
- protected readonly configure: _alepha_core16.HookDescriptor<"configure">;
281
- transition(url: URL, options?: TransitionOptions): Promise<RouterRenderResult>;
282
- root(state: RouterState, context: PageReactContext): ReactNode;
342
+ protected readonly configure: _alepha_core14.HookDescriptor<"configure">;
343
+ transition(url: URL, previous?: PreviousLayerData[]): Promise<string | void>;
344
+ root(state: ReactRouterState): ReactNode;
283
345
  }
284
- //# sourceMappingURL=BrowserRouterProvider.d.ts.map
285
346
  //#endregion
286
347
  //#region src/providers/ReactBrowserProvider.d.ts
348
+ declare const envSchema$1: _alepha_core14.TObject<{
349
+ REACT_ROOT_ID: _alepha_core14.TString;
350
+ }>;
351
+ declare module "@alepha/core" {
352
+ interface Env extends Partial<Static<typeof envSchema$1>> {}
353
+ }
354
+ interface ReactBrowserRendererOptions {
355
+ scrollRestoration?: "top" | "manual";
356
+ }
287
357
  declare class ReactBrowserProvider {
288
- protected readonly log: _alepha_core0$1.Logger;
358
+ protected readonly env: {
359
+ REACT_ROOT_ID: string;
360
+ };
361
+ protected readonly log: _alepha_logger1.Logger;
289
362
  protected readonly client: LinkProvider;
290
363
  protected readonly alepha: Alepha;
291
- protected readonly router: BrowserRouterProvider;
292
- protected root: Root;
364
+ protected readonly router: ReactBrowserRouterProvider;
365
+ protected readonly dateTimeProvider: DateTimeProvider;
366
+ protected root?: Root;
367
+ options: ReactBrowserRendererOptions;
368
+ protected getRootElement(): HTMLElement;
293
369
  transitioning?: {
294
370
  to: string;
371
+ from?: string;
295
372
  };
296
- state: RouterState;
373
+ get state(): ReactRouterState;
374
+ /**
375
+ * Accessor for Document DOM API.
376
+ */
297
377
  get document(): Document;
378
+ /**
379
+ * Accessor for History DOM API.
380
+ */
298
381
  get history(): History;
382
+ /**
383
+ * Accessor for Location DOM API.
384
+ */
299
385
  get location(): Location;
386
+ get base(): string;
300
387
  get url(): string;
301
- pushState(url: string, replace?: boolean): void;
388
+ pushState(path: string, replace?: boolean): void;
302
389
  invalidate(props?: Record<string, any>): Promise<void>;
303
390
  go(url: string, options?: RouterGoOptions): Promise<void>;
304
391
  protected render(options?: {
305
392
  url?: string;
306
393
  previous?: PreviousLayerData[];
307
- }): Promise<RouterRenderResult>;
394
+ }): Promise<void>;
308
395
  /**
309
396
  * Get embedded layers from the server.
310
397
  */
311
398
  protected getHydrationState(): ReactHydrationState | undefined;
312
- readonly ready: _alepha_core0$1.HookDescriptor<"ready">;
399
+ protected readonly onTransitionEnd: _alepha_core14.HookDescriptor<"react:transition:end">;
400
+ readonly ready: _alepha_core14.HookDescriptor<"ready">;
313
401
  }
314
402
  interface RouterGoOptions {
315
403
  replace?: boolean;
316
404
  match?: TransitionOptions;
317
405
  params?: Record<string, string>;
406
+ query?: Record<string, string>;
407
+ /**
408
+ * Recreate the whole page, ignoring the current state.
409
+ */
410
+ force?: boolean;
318
411
  }
319
- interface ReactHydrationState {
412
+ type ReactHydrationState = {
320
413
  layers?: Array<PreviousLayerData>;
321
- links?: ApiLinksResponse;
322
- }
323
- //# sourceMappingURL=ReactBrowserProvider.d.ts.map
414
+ } & {
415
+ [key: string]: any;
416
+ };
324
417
  //#endregion
325
418
  //#region src/components/ErrorBoundary.d.ts
326
419
  /**
@@ -362,12 +455,22 @@ declare class ErrorBoundary extends React.Component<PropsWithChildren<ErrorBound
362
455
  render(): ReactNode;
363
456
  }
364
457
  //#endregion
458
+ //#region src/components/ErrorViewer.d.ts
459
+ interface ErrorViewerProps {
460
+ error: Error;
461
+ alepha: Alepha;
462
+ }
463
+ declare const ErrorViewer: ({
464
+ error,
465
+ alepha
466
+ }: ErrorViewerProps) => react_jsx_runtime0.JSX.Element;
467
+ //#endregion
365
468
  //#region src/components/Link.d.ts
366
469
  interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
367
- to: string | PageDescriptor;
470
+ to: string;
368
471
  children?: React.ReactNode;
369
472
  }
370
- declare const Link: (props: LinkProps) => react_jsx_runtime1.JSX.Element | null;
473
+ declare const Link: (props: LinkProps) => react_jsx_runtime0.JSX.Element;
371
474
  //#endregion
372
475
  //#region src/components/NestedView.d.ts
373
476
  interface NestedViewProps {
@@ -397,66 +500,102 @@ interface NestedViewProps {
397
500
  declare const NestedView: (props: NestedViewProps) => react_jsx_runtime0.JSX.Element;
398
501
  //#endregion
399
502
  //#region src/components/NotFound.d.ts
400
- declare function NotFoundPage(): react_jsx_runtime2.JSX.Element;
401
- //# sourceMappingURL=NotFound.d.ts.map
503
+ declare function NotFoundPage(props: {
504
+ style?: CSSProperties;
505
+ }): react_jsx_runtime0.JSX.Element;
402
506
  //#endregion
403
507
  //#region src/contexts/AlephaContext.d.ts
404
- declare const AlephaContext: react0$1.Context<Alepha | undefined>;
405
- //# sourceMappingURL=AlephaContext.d.ts.map
406
- //#endregion
407
- //#region src/contexts/RouterContext.d.ts
408
- interface RouterContextValue {
409
- state: RouterState;
410
- context: PageReactContext;
411
- }
412
- declare const RouterContext: react0.Context<RouterContextValue | undefined>;
413
- //# sourceMappingURL=RouterContext.d.ts.map
508
+ declare const AlephaContext: react0.Context<Alepha | undefined>;
414
509
  //#endregion
415
510
  //#region src/contexts/RouterLayerContext.d.ts
416
511
  interface RouterLayerContextValue {
417
512
  index: number;
418
513
  path: string;
419
514
  }
420
- declare const RouterLayerContext: react1.Context<RouterLayerContextValue | undefined>;
421
- //# sourceMappingURL=RouterLayerContext.d.ts.map
515
+ declare const RouterLayerContext: react0.Context<RouterLayerContextValue | undefined>;
422
516
  //#endregion
423
- //#region src/hooks/RouterHookApi.d.ts
424
- declare class RouterHookApi {
425
- private readonly pages;
426
- private readonly context;
427
- private readonly state;
428
- private readonly layer;
429
- private readonly browser?;
430
- constructor(pages: PageRoute[], context: PageReactContext, state: RouterState, layer: {
431
- path: string;
432
- }, browser?: ReactBrowserProvider | undefined);
517
+ //#region src/hooks/useActive.d.ts
518
+ interface UseActiveOptions {
519
+ href: string;
520
+ startWith?: boolean;
521
+ }
522
+ declare const useActive: (args: string | UseActiveOptions) => UseActiveHook;
523
+ interface UseActiveHook {
524
+ isActive: boolean;
525
+ anchorProps: AnchorProps;
526
+ isPending: boolean;
527
+ name?: string;
528
+ }
529
+ //#endregion
530
+ //#region src/hooks/useAlepha.d.ts
531
+ /**
532
+ * Main Alepha hook.
533
+ *
534
+ * It provides access to the Alepha instance within a React component.
535
+ *
536
+ * With Alepha, you can access the core functionalities of the framework:
537
+ *
538
+ * - alepha.state() for state management
539
+ * - alepha.inject() for dependency injection
540
+ * - alepha.emit() for event handling
541
+ * etc...
542
+ */
543
+ declare const useAlepha: () => Alepha;
544
+ //#endregion
545
+ //#region src/hooks/useClient.d.ts
546
+ /**
547
+ * Hook to get a virtual client for the specified scope.
548
+ *
549
+ * It's the React-hook version of `$client()`, from `AlephaServerLinks` module.
550
+ */
551
+ declare const useClient: <T extends object>(scope?: ClientScope) => HttpVirtualClient<T>;
552
+ //#endregion
553
+ //#region src/hooks/useInject.d.ts
554
+ /**
555
+ * Hook to inject a service instance.
556
+ * It's a wrapper of `useAlepha().inject(service)` with a memoization.
557
+ */
558
+ declare const useInject: <T extends object>(service: Service<T>) => T;
559
+ //#endregion
560
+ //#region src/hooks/useQueryParams.d.ts
561
+ /**
562
+ * Not well tested. Use with caution.
563
+ */
564
+ declare const useQueryParams: <T extends TObject>(schema: T, options?: UseQueryParamsHookOptions) => [Static<T>, (data: Static<T>) => void];
565
+ interface UseQueryParamsHookOptions {
566
+ format?: "base64" | "querystring";
567
+ key?: string;
568
+ push?: boolean;
569
+ }
570
+ //#endregion
571
+ //#region src/services/ReactRouter.d.ts
572
+ declare class ReactRouter<T extends object> {
573
+ protected readonly alepha: Alepha;
574
+ protected readonly pageApi: ReactPageProvider;
575
+ get state(): ReactRouterState;
576
+ get pages(): PageRoute[];
577
+ get browser(): ReactBrowserProvider | undefined;
578
+ path(name: keyof VirtualRouter<T>, config?: {
579
+ params?: Record<string, string>;
580
+ query?: Record<string, string>;
581
+ }): string;
433
582
  getURL(): URL;
434
583
  get location(): Location;
435
- get current(): RouterState;
584
+ get current(): ReactRouterState;
436
585
  get pathname(): string;
437
586
  get query(): Record<string, string>;
438
587
  back(): Promise<void>;
439
588
  forward(): Promise<void>;
440
589
  invalidate(props?: Record<string, any>): Promise<void>;
441
- /**
442
- * Create a valid href for the given pathname.
443
- *
444
- * @param pathname
445
- * @param layer
446
- */
447
- createHref(pathname: HrefLike, layer?: {
448
- path: string;
449
- }, options?: {
450
- params?: Record<string, any>;
451
- }): string;
452
590
  go(path: string, options?: RouterGoOptions): Promise<void>;
453
- go<T extends object>(path: keyof VirtualRouter<T>, options?: RouterGoOptions): Promise<void>;
591
+ go(path: keyof VirtualRouter<T>, options?: RouterGoOptions): Promise<void>;
454
592
  anchor(path: string, options?: {
455
593
  params?: Record<string, any>;
456
594
  }): AnchorProps;
457
- anchor<T extends object>(path: keyof VirtualRouter<T>, options?: {
595
+ anchor(path: keyof VirtualRouter<T>, options?: {
458
596
  params?: Record<string, any>;
459
597
  }): AnchorProps;
598
+ base(path: string): string;
460
599
  /**
461
600
  * Set query params.
462
601
  *
@@ -470,75 +609,44 @@ declare class RouterHookApi {
470
609
  push?: boolean;
471
610
  }): void;
472
611
  }
473
- type HrefLike = string | {
474
- options: {
475
- path?: string;
476
- name?: string;
477
- };
478
- };
479
612
  type VirtualRouter<T> = { [K in keyof T as T[K] extends PageDescriptor ? K : never]: T[K] };
480
- //# sourceMappingURL=RouterHookApi.d.ts.map
481
- //#endregion
482
- //#region src/errors/RedirectionError.d.ts
483
- declare class RedirectionError extends Error {
484
- readonly page: HrefLike;
485
- constructor(page: HrefLike);
486
- }
487
- //# sourceMappingURL=RedirectionError.d.ts.map
488
- //#endregion
489
- //#region src/hooks/useActive.d.ts
490
- declare const useActive: (path: HrefLike) => UseActiveHook;
491
- interface UseActiveHook {
492
- isActive: boolean;
493
- anchorProps: AnchorProps;
494
- isPending: boolean;
495
- name?: string;
496
- }
497
- //# sourceMappingURL=useActive.d.ts.map
498
- //#endregion
499
- //#region src/hooks/useAlepha.d.ts
500
- declare const useAlepha: () => Alepha;
501
- //# sourceMappingURL=useAlepha.d.ts.map
502
- //#endregion
503
- //#region src/hooks/useClient.d.ts
504
- declare const useClient: <T extends object>(_scope?: ClientScope) => HttpVirtualClient<T>;
505
- //# sourceMappingURL=useClient.d.ts.map
506
- //#endregion
507
- //#region src/hooks/useInject.d.ts
508
- declare const useInject: <T extends object>(service: Service<T>) => T;
509
- //# sourceMappingURL=useInject.d.ts.map
510
- //#endregion
511
- //#region src/hooks/useQueryParams.d.ts
512
- interface UseQueryParamsHookOptions {
513
- format?: "base64" | "querystring";
514
- key?: string;
515
- push?: boolean;
516
- }
517
- declare const useQueryParams: <T extends TObject>(schema: T, options?: UseQueryParamsHookOptions) => [Static<T>, (data: Static<T>) => void];
518
- //# sourceMappingURL=useQueryParams.d.ts.map
519
613
  //#endregion
520
614
  //#region src/hooks/useRouter.d.ts
521
- declare const useRouter: () => RouterHookApi;
522
- //# sourceMappingURL=useRouter.d.ts.map
615
+ /**
616
+ * Use this hook to access the React Router instance.
617
+ *
618
+ * You can add a type parameter to specify the type of your application.
619
+ * This will allow you to use the router in a typesafe way.
620
+ *
621
+ * @example
622
+ * class App {
623
+ * home = $page();
624
+ * }
625
+ *
626
+ * const router = useRouter<App>();
627
+ * router.go("home"); // typesafe
628
+ */
629
+ declare const useRouter: <T extends object = any>() => ReactRouter<T>;
523
630
  //#endregion
524
631
  //#region src/hooks/useRouterEvents.d.ts
632
+ /**
633
+ * Subscribe to various router events.
634
+ */
525
635
  declare const useRouterEvents: (opts?: {
526
636
  onBegin?: (ev: {
527
- state: RouterState;
637
+ state: ReactRouterState;
528
638
  }) => void;
529
639
  onEnd?: (ev: {
530
- state: RouterState;
640
+ state: ReactRouterState;
531
641
  }) => void;
532
642
  onError?: (ev: {
533
- state: RouterState;
643
+ state: ReactRouterState;
534
644
  error: Error;
535
645
  }) => void;
536
646
  }, deps?: any[]) => void;
537
- //# sourceMappingURL=useRouterEvents.d.ts.map
538
647
  //#endregion
539
648
  //#region src/hooks/useRouterState.d.ts
540
- declare const useRouterState: () => RouterState;
541
- //# sourceMappingURL=useRouterState.d.ts.map
649
+ declare const useRouterState: () => ReactRouterState;
542
650
  //#endregion
543
651
  //#region src/hooks/useSchema.d.ts
544
652
  declare const useSchema: <TConfig extends RequestConfigSchema>(action: VirtualAction<TConfig>) => UseSchemaReturn<TConfig>;
@@ -551,22 +659,20 @@ type UseSchemaReturn<TConfig extends RequestConfigSchema> = TConfig & {
551
659
  declare const ssrSchemaLoading: (alepha: Alepha, name: string) => RequestConfigSchema | {
552
660
  loading: boolean;
553
661
  };
554
- //# sourceMappingURL=useSchema.d.ts.map
555
662
  //#endregion
556
663
  //#region src/hooks/useStore.d.ts
557
664
  /**
558
665
  * Hook to access and mutate the Alepha state.
559
666
  */
560
- declare const useStore: <Key extends keyof State>(key: Key) => [State[Key], (value: State[Key]) => void];
561
- //# sourceMappingURL=useStore.d.ts.map
667
+ declare const useStore: <Key extends keyof State>(key: Key, defaultValue?: State[Key]) => [State[Key], (value: State[Key]) => void];
562
668
  //#endregion
563
669
  //#region src/providers/ReactServerProvider.d.ts
564
- declare const envSchema: _alepha_core6.TObject<{
565
- REACT_SERVER_DIST: _alepha_core6.TString;
566
- REACT_SERVER_PREFIX: _alepha_core6.TString;
567
- REACT_SSR_ENABLED: _alepha_core6.TOptional<_alepha_core6.TBoolean>;
568
- REACT_ROOT_ID: _alepha_core6.TString;
569
- REACT_SERVER_TEMPLATE: _alepha_core6.TOptional<_alepha_core6.TString>;
670
+ declare const envSchema: _alepha_core14.TObject<{
671
+ REACT_SERVER_DIST: _alepha_core14.TString;
672
+ REACT_SERVER_PREFIX: _alepha_core14.TString;
673
+ REACT_SSR_ENABLED: _alepha_core14.TOptional<_alepha_core14.TBoolean>;
674
+ REACT_ROOT_ID: _alepha_core14.TString;
675
+ REACT_SERVER_TEMPLATE: _alepha_core14.TOptional<_alepha_core14.TString>;
570
676
  }>;
571
677
  declare module "@alepha/core" {
572
678
  interface Env extends Partial<Static<typeof envSchema>> {}
@@ -575,9 +681,9 @@ declare module "@alepha/core" {
575
681
  }
576
682
  }
577
683
  declare class ReactServerProvider {
578
- protected readonly log: _alepha_core6.Logger;
684
+ protected readonly log: _alepha_logger1.Logger;
579
685
  protected readonly alepha: Alepha;
580
- protected readonly pageDescriptorProvider: PageDescriptorProvider;
686
+ protected readonly pageApi: ReactPageProvider;
581
687
  protected readonly serverStaticProvider: ServerStaticProvider;
582
688
  protected readonly serverRouterProvider: ServerRouterProvider;
583
689
  protected readonly serverTimingProvider: ServerTimingProvider;
@@ -589,7 +695,7 @@ declare class ReactServerProvider {
589
695
  REACT_ROOT_ID: string;
590
696
  };
591
697
  protected readonly ROOT_DIV_REGEX: RegExp;
592
- readonly onConfigure: _alepha_core6.HookDescriptor<"configure">;
698
+ readonly onConfigure: _alepha_core14.HookDescriptor<"configure">;
593
699
  get template(): string;
594
700
  protected registerPages(templateLoader: TemplateLoader): Promise<void>;
595
701
  protected getPublicDirectory(): string;
@@ -599,15 +705,11 @@ declare class ReactServerProvider {
599
705
  * For testing purposes, creates a render function that can be used.
600
706
  */
601
707
  protected createRenderFunction(name: string, withIndex?: boolean): (options?: PageDescriptorRenderOptions) => Promise<{
602
- context: PageRequest;
603
- state: CreateLayersResult;
604
- html: string;
605
- } | {
606
- context: PageRequest;
708
+ state: ReactRouterState;
607
709
  html: string;
608
710
  }>;
609
- protected createHandler(page: PageRoute, templateLoader: TemplateLoader): ServerHandler;
610
- renderToHtml(template: string, state: RouterState, context: PageReactContext, hydration?: boolean): string;
711
+ protected createHandler(route: PageRoute, templateLoader: TemplateLoader): ServerHandler;
712
+ renderToHtml(template: string, state: ReactRouterState, hydration?: boolean): string | Redirection;
611
713
  protected fillTemplate(response: {
612
714
  html: string;
613
715
  }, app: string, script: string): void;
@@ -616,43 +718,35 @@ type TemplateLoader = () => Promise<string | undefined>;
616
718
  //#endregion
617
719
  //#region src/index.d.ts
618
720
  declare module "@alepha/core" {
721
+ interface State {
722
+ "react.router.state"?: ReactRouterState;
723
+ }
619
724
  interface Hooks {
620
- "react:router:createLayers": {
621
- request: ServerRequest;
622
- context: PageRequest;
623
- layers: PageRequest[];
624
- };
625
725
  "react:server:render:begin": {
626
726
  request?: ServerRequest;
627
- context: PageRequest;
727
+ state: ReactRouterState;
628
728
  };
629
729
  "react:server:render:end": {
630
730
  request?: ServerRequest;
631
- context: PageRequest;
632
- state: RouterState;
731
+ state: ReactRouterState;
633
732
  html: string;
634
733
  };
635
734
  "react:browser:render": {
636
- state: RouterState;
637
- context: PageReactContext;
735
+ state: ReactRouterState;
638
736
  hydration?: ReactHydrationState;
639
737
  };
640
738
  "react:transition:begin": {
641
- state: RouterState;
642
- context: PageReactContext;
739
+ state: ReactRouterState;
643
740
  };
644
741
  "react:transition:success": {
645
- state: RouterState;
646
- context: PageReactContext;
742
+ state: ReactRouterState;
647
743
  };
648
744
  "react:transition:error": {
745
+ state: ReactRouterState;
649
746
  error: Error;
650
- state: RouterState;
651
- context: PageReactContext;
652
747
  };
653
748
  "react:transition:end": {
654
- state: RouterState;
655
- context: PageReactContext;
749
+ state: ReactRouterState;
656
750
  };
657
751
  }
658
752
  }
@@ -666,9 +760,7 @@ declare module "@alepha/core" {
666
760
  * @see {@link $page}
667
761
  * @module alepha.react
668
762
  */
669
- declare const AlephaReact: _alepha_core0.ModuleDescriptor;
670
- //# sourceMappingURL=index.d.ts.map
671
-
763
+ declare const AlephaReact: _alepha_core14.Service<_alepha_core14.Module>;
672
764
  //#endregion
673
- export { $page, AlephaContext, AlephaReact, AnchorProps, ClientOnly, CreateLayersResult, ErrorBoundary, HrefLike, Layer, Link, NestedView, NotFoundPage as NotFound, PageConfigSchema, PageDescriptor, PageDescriptorOptions, PageDescriptorProvider, PageDescriptorRenderOptions, PageDescriptorRenderResult, PageReactContext, PageRequest, PageRequestConfig, PageResolve, PageRoute, PageRouteEntry, PreviousLayerData, ReactBrowserProvider, ReactHydrationState, ReactServerProvider, RedirectionError, RouterContext, RouterContextValue, RouterGoOptions, RouterHookApi, RouterLayerContext, RouterLayerContextValue, RouterRenderResult, RouterStackItem, RouterState, TPropsDefault, TPropsParentDefault, TransitionOptions, UseActiveHook, UseQueryParamsHookOptions, UseSchemaReturn, VirtualRouter, isPageRoute, ssrSchemaLoading, useActive, useAlepha, useClient, useInject, useQueryParams, useRouter, useRouterEvents, useRouterState, useSchema, useStore };
765
+ export { $page, AlephaContext, AlephaReact, AnchorProps, ClientOnly, CreateLayersResult, ErrorBoundary, ErrorHandler, ErrorViewer, Layer, Link, LinkProps, NestedView, NotFoundPage as NotFound, PageConfigSchema, PageDescriptor, PageDescriptorOptions, PageDescriptorRenderOptions, PageDescriptorRenderResult, PageRequestConfig, PageResolve, PageRoute, PageRouteEntry, PreviousLayerData, ReactBrowserProvider, ReactBrowserRendererOptions, ReactHydrationState, ReactPageProvider, ReactRouter, ReactRouterState, ReactServerProvider, Redirection, RouterGoOptions, RouterLayerContext, RouterLayerContextValue, RouterStackItem, TPropsDefault, TPropsParentDefault, TransitionOptions, UseActiveHook, UseActiveOptions, UseQueryParamsHookOptions, UseSchemaReturn, VirtualRouter, isPageRoute, ssrSchemaLoading, useActive, useAlepha, useClient, useInject, useQueryParams, useRouter, useRouterEvents, useRouterState, useSchema, useStore };
674
766
  //# sourceMappingURL=index.d.cts.map