@alepha/react 0.7.7 → 0.8.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.
@@ -209,13 +209,6 @@ export class PageDescriptorProvider {
209
209
  params[key] = String(params[key]);
210
210
  }
211
211
 
212
- // if (it.route.head && !it.error) {
213
- // this.fillHead(it.route, request, {
214
- // ...props,
215
- // ...context,
216
- // });
217
- // }
218
-
219
212
  acc += "/";
220
213
  acc += it.route.path ? this.compile(it.route.path, params) : "";
221
214
  const path = acc.replace(/\/+/, "/");
@@ -357,17 +350,31 @@ export class PageDescriptorProvider {
357
350
  }
358
351
 
359
352
  protected readonly configure = $hook({
360
- name: "configure",
353
+ on: "configure",
361
354
  handler: () => {
362
355
  let hasNotFoundHandler = false;
363
356
  const pages = this.alepha.getDescriptorValues($page);
357
+
358
+ const hasParent = (it: { [OPTIONS]: PageDescriptorOptions }) => {
359
+ for (const page of pages) {
360
+ const children = page.value[OPTIONS].children
361
+ ? Array.isArray(page.value[OPTIONS].children)
362
+ ? page.value[OPTIONS].children
363
+ : page.value[OPTIONS].children()
364
+ : [];
365
+ if (children.includes(it)) {
366
+ return true;
367
+ }
368
+ }
369
+ };
370
+
364
371
  for (const { value, key } of pages) {
365
372
  value[OPTIONS].name ??= key;
366
373
  }
367
374
 
368
375
  for (const { value } of pages) {
369
376
  // skip children, we only want root pages
370
- if (value[OPTIONS].parent) {
377
+ if (hasParent(value)) {
371
378
  continue;
372
379
  }
373
380
 
@@ -397,7 +404,11 @@ export class PageDescriptorProvider {
397
404
  pages: Array<{ value: { [OPTIONS]: PageDescriptorOptions } }>,
398
405
  target: { [OPTIONS]: PageDescriptorOptions },
399
406
  ): PageRouteEntry {
400
- const children = target[OPTIONS].children ?? [];
407
+ const children = target[OPTIONS].children
408
+ ? Array.isArray(target[OPTIONS].children)
409
+ ? target[OPTIONS].children
410
+ : target[OPTIONS].children()
411
+ : [];
401
412
 
402
413
  return {
403
414
  ...target[OPTIONS],
@@ -125,7 +125,7 @@ export class ReactBrowserProvider {
125
125
  // -------------------------------------------------------------------------------------------------------------------
126
126
 
127
127
  public readonly ready = $hook({
128
- name: "ready",
128
+ on: "ready",
129
129
  handler: async () => {
130
130
  const hydration = this.getHydrationState();
131
131
  const previous = hydration?.layers ?? [];
@@ -43,7 +43,7 @@ export class ReactBrowserRenderer {
43
43
  }
44
44
 
45
45
  public readonly ready = $hook({
46
- name: "react:browser:render",
46
+ on: "react:browser:render",
47
47
  handler: async ({ state, context, hydration }) => {
48
48
  const element = this.browserRouterProvider.root(state, context);
49
49
 
@@ -60,7 +60,7 @@ export class ReactServerProvider {
60
60
  );
61
61
 
62
62
  public readonly onConfigure = $hook({
63
- name: "configure",
63
+ on: "configure",
64
64
  handler: async () => {
65
65
  const pages = this.alepha.getDescriptorValues($page);
66
66
 
@@ -1,523 +0,0 @@
1
- import * as _alepha_core1 from "@alepha/core";
2
- import * as _alepha_core5 from "@alepha/core";
3
- import * as _alepha_core7 from "@alepha/core";
4
- import { Alepha, Async, KIND, Module, OPTIONS, Service, Static, TObject, TSchema } from "@alepha/core";
5
- import { Route, RouterProvider } from "@alepha/router";
6
- import * as react12 from "react";
7
- import * as react13 from "react";
8
- import React, { AnchorHTMLAttributes, ErrorInfo, FC, PropsWithChildren, ReactNode } from "react";
9
- import * as react_jsx_runtime10 from "react/jsx-runtime";
10
- import * as react_jsx_runtime11 from "react/jsx-runtime";
11
- import { ClientScope, HttpVirtualClient, LinkProvider } from "@alepha/server-links";
12
- import { Root } from "react-dom/client";
13
- import { ApiLinksResponse, ServerRequest } from "@alepha/server";
14
- import { ServerRouteCache } from "@alepha/server-cache";
15
- import * as _sinclair_typebox0 from "@sinclair/typebox";
16
-
17
- //#region src/components/ClientOnly.d.ts
18
- interface ClientOnlyProps {
19
- fallback?: ReactNode;
20
- disabled?: boolean;
21
- }
22
- /**
23
- * A small utility component that renders its children only on the client side.
24
- *
25
- * Optionally, you can provide a fallback React node that will be rendered.
26
- *
27
- * You should use this component when
28
- * - you have code that relies on browser-specific APIs
29
- * - you want to avoid server-side rendering for a specific part of your application
30
- * - you want to prevent pre-rendering of a component
31
- */
32
- declare const ClientOnly: (props: PropsWithChildren<ClientOnlyProps>) => ReactNode;
33
- //#endregion
34
- //#region src/components/ErrorBoundary.d.ts
35
- /**
36
- * Props for the ErrorBoundary component.
37
- */
38
- interface ErrorBoundaryProps {
39
- /**
40
- * Fallback React node to render when an error is caught.
41
- * If not provided, a default error message will be shown.
42
- */
43
- fallback: (error: Error) => ReactNode;
44
- /**
45
- * Optional callback that receives the error and error info.
46
- * Use this to log errors to a monitoring service.
47
- */
48
- onError?: (error: Error, info: ErrorInfo) => void;
49
- }
50
- /**
51
- * State of the ErrorBoundary component.
52
- */
53
- interface ErrorBoundaryState {
54
- error?: Error;
55
- }
56
- /**
57
- * A reusable error boundary for catching rendering errors
58
- * in any part of the React component tree.
59
- */
60
- declare class ErrorBoundary extends React.Component<PropsWithChildren<ErrorBoundaryProps>, ErrorBoundaryState> {
61
- constructor(props: ErrorBoundaryProps);
62
- /**
63
- * Update state so the next render shows the fallback UI.
64
- */
65
- static getDerivedStateFromError(error: Error): ErrorBoundaryState;
66
- /**
67
- * Lifecycle method called when an error is caught.
68
- * You can log the error or perform side effects here.
69
- */
70
- componentDidCatch(error: Error, info: ErrorInfo): void;
71
- render(): ReactNode;
72
- }
73
- //#endregion
74
- //#region src/providers/PageDescriptorProvider.d.ts
75
- declare const envSchema: _alepha_core1.TObject<{
76
- REACT_STRICT_MODE: _sinclair_typebox0.TBoolean;
77
- }>;
78
- declare module "@alepha/core" {
79
- interface Env extends Partial<Static<typeof envSchema>> {}
80
- }
81
- declare class PageDescriptorProvider {
82
- protected readonly log: _alepha_core1.Logger;
83
- protected readonly env: {
84
- REACT_STRICT_MODE: boolean;
85
- };
86
- protected readonly alepha: Alepha;
87
- protected readonly pages: PageRoute[];
88
- getPages(): PageRoute[];
89
- page(name: string): PageRoute;
90
- url(name: string, options?: {
91
- params?: Record<string, string>;
92
- base?: string;
93
- }): URL;
94
- root(state: RouterState, context: PageReactContext): ReactNode;
95
- createLayers(route: PageRoute, request: PageRequest): Promise<CreateLayersResult>;
96
- protected getErrorHandler(route: PageRoute): ((error: Error) => ReactNode) | undefined;
97
- protected createElement(page: PageRoute, props: Record<string, any>): Promise<ReactNode>;
98
- renderError(error: Error): ReactNode;
99
- renderEmptyView(): ReactNode;
100
- href(page: {
101
- options: {
102
- name?: string;
103
- };
104
- }, params?: Record<string, any>): string;
105
- compile(path: string, params?: Record<string, string>): string;
106
- protected renderView(index: number, path: string, view: ReactNode | undefined, page: PageRoute): ReactNode;
107
- protected readonly configure: _alepha_core1.HookDescriptor<"configure">;
108
- protected map(pages: Array<{
109
- value: {
110
- [OPTIONS]: PageDescriptorOptions;
111
- };
112
- }>, target: {
113
- [OPTIONS]: PageDescriptorOptions;
114
- }): PageRouteEntry;
115
- add(entry: PageRouteEntry): void;
116
- protected createMatch(page: PageRoute): string;
117
- protected _next: number;
118
- protected nextId(): string;
119
- }
120
- declare const isPageRoute: (it: any) => it is PageRoute;
121
- interface PageRouteEntry extends Omit<PageDescriptorOptions, "children" | "parent"> {
122
- children?: PageRouteEntry[];
123
- }
124
- interface PageRoute extends PageRouteEntry {
125
- type: "page";
126
- name: string;
127
- parent?: PageRoute;
128
- match: string;
129
- }
130
- interface Layer {
131
- config?: {
132
- query?: Record<string, any>;
133
- params?: Record<string, any>;
134
- context?: Record<string, any>;
135
- };
136
- name: string;
137
- props?: Record<string, any>;
138
- error?: Error;
139
- part?: string;
140
- element: ReactNode;
141
- index: number;
142
- path: string;
143
- route?: PageRoute;
144
- }
145
- type PreviousLayerData = Omit<Layer, "element" | "index" | "path">;
146
- interface AnchorProps {
147
- href: string;
148
- onClick: (ev: any) => any;
149
- }
150
- interface RouterState {
151
- pathname: string;
152
- search: string;
153
- layers: Array<Layer>;
154
- }
155
- interface TransitionOptions {
156
- state?: RouterState;
157
- previous?: PreviousLayerData[];
158
- context?: PageReactContext;
159
- }
160
- interface RouterStackItem {
161
- route: PageRoute;
162
- config?: Record<string, any>;
163
- props?: Record<string, any>;
164
- error?: Error;
165
- }
166
- interface RouterRenderResult {
167
- state: RouterState;
168
- context: PageReactContext;
169
- redirect?: string;
170
- }
171
- interface PageRequest extends PageReactContext {
172
- params: Record<string, any>;
173
- query: Record<string, string>;
174
- previous?: PreviousLayerData[];
175
- }
176
- interface CreateLayersResult extends RouterState {
177
- redirect?: string;
178
- }
179
- /**
180
- * It's like RouterState, but publicly available in React context.
181
- * This is where we store all plugin data!
182
- */
183
- interface PageReactContext {
184
- url: URL;
185
- onError: (error: Error) => ReactNode;
186
- links?: ApiLinksResponse;
187
- }
188
- //#endregion
189
- //#region src/descriptors/$page.d.ts
190
- declare const KEY = "PAGE";
191
- interface PageConfigSchema {
192
- query?: TSchema;
193
- params?: TSchema;
194
- }
195
- type TPropsDefault = any;
196
- type TPropsParentDefault = {};
197
- interface PageDescriptorOptions<TConfig extends PageConfigSchema = PageConfigSchema, TProps extends object = TPropsDefault, TPropsParent extends object = TPropsParentDefault> {
198
- /**
199
- * Name your page.
200
- *
201
- * @default Descriptor key
202
- */
203
- name?: string;
204
- /**
205
- * Optional description of the page.
206
- */
207
- description?: string;
208
- /**
209
- * Add a pathname to the page.
210
- *
211
- * Pathname can contain parameters, like `/post/:slug`.
212
- *
213
- * @default ""
214
- */
215
- path?: string;
216
- /**
217
- * Add an input schema to define:
218
- * - `params`: parameters from the pathname.
219
- * - `query`: query parameters from the URL.
220
- */
221
- schema?: TConfig;
222
- /**
223
- * Load data before rendering the page.
224
- *
225
- * This function receives
226
- * - the request context and
227
- * - the parent props (if page has a parent)
228
- *
229
- * In SSR, the returned data will be serialized and sent to the client, then reused during the client-side hydration.
230
- *
231
- * Resolve can be stopped by throwing an error, which will be handled by the `errorHandler` function.
232
- * It's common to throw a `NotFoundError` to display a 404 page.
233
- *
234
- * RedirectError can be thrown to redirect the user to another page.
235
- */
236
- resolve?: (context: PageResolve<TConfig, TPropsParent>) => Async<TProps>;
237
- /**
238
- * The component to render when the page is loaded.
239
- *
240
- * If `lazy` is defined, this will be ignored.
241
- * Prefer using `lazy` to improve the initial loading time.
242
- */
243
- component?: FC<TProps & TPropsParent>;
244
- /**
245
- * Lazy load the component when the page is loaded.
246
- *
247
- * It's recommended to use this for components to improve the initial loading time
248
- * and enable code-splitting.
249
- */
250
- lazy?: () => Promise<{
251
- default: FC<TProps & TPropsParent>;
252
- }>;
253
- /**
254
- * Set some children pages and make the page a parent page.
255
- *
256
- * /!\ Parent page can't be rendered directly. /!\
257
- *
258
- * If you still want to render at this pathname, add a child page with an empty path.
259
- */
260
- children?: Array<{
261
- [OPTIONS]: PageDescriptorOptions;
262
- }>;
263
- parent?: {
264
- [OPTIONS]: PageDescriptorOptions<PageConfigSchema, TPropsParent>;
265
- };
266
- can?: () => boolean;
267
- errorHandler?: (error: Error) => ReactNode;
268
- prerender?: boolean | {
269
- entries?: Array<Partial<PageRequestConfig<TConfig>>>;
270
- };
271
- /**
272
- * If true, the page will be rendered on the client-side.
273
- */
274
- client?: boolean | ClientOnlyProps;
275
- afterHandler?: (request: ServerRequest) => any;
276
- cache?: ServerRouteCache;
277
- }
278
- interface PageDescriptor<TConfig extends PageConfigSchema = PageConfigSchema, TProps extends object = TPropsDefault, TPropsParent extends object = TPropsParentDefault> {
279
- [KIND]: typeof KEY;
280
- [OPTIONS]: PageDescriptorOptions<TConfig, TProps, TPropsParent>;
281
- /**
282
- * For testing or build purposes, this will render the page (with or without the HTML layout) and return the HTML and context.
283
- * Only valid for server-side rendering, it will throw an error if called on the client-side.
284
- */
285
- render: (options?: PageDescriptorRenderOptions) => Promise<PageDescriptorRenderResult>;
286
- }
287
- /**
288
- * Main descriptor for defining a React route in the application.
289
- */
290
- declare const $page: {
291
- <TConfig extends PageConfigSchema = PageConfigSchema, TProps extends object = any, TPropsParent extends object = TPropsParentDefault>(options: PageDescriptorOptions<TConfig, TProps, TPropsParent>): PageDescriptor<TConfig, TProps, TPropsParent>;
292
- [KIND]: string;
293
- };
294
- interface PageDescriptorRenderOptions {
295
- params?: Record<string, string>;
296
- query?: Record<string, string>;
297
- html?: boolean;
298
- hydration?: boolean;
299
- }
300
- interface PageDescriptorRenderResult {
301
- html: string;
302
- context: PageReactContext;
303
- }
304
- interface PageRequestConfig<TConfig extends PageConfigSchema = PageConfigSchema> {
305
- params: TConfig["params"] extends TSchema ? Static<TConfig["params"]> : Record<string, string>;
306
- query: TConfig["query"] extends TSchema ? Static<TConfig["query"]> : Record<string, string>;
307
- }
308
- type PageResolve<TConfig extends PageConfigSchema = PageConfigSchema, TPropsParent extends object = TPropsParentDefault> = PageRequestConfig<TConfig> & TPropsParent & PageReactContext;
309
- //#endregion
310
- //#region src/components/Link.d.ts
311
- interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
312
- to: string | PageDescriptor;
313
- children?: React.ReactNode;
314
- }
315
- declare const Link: (props: LinkProps) => react_jsx_runtime10.JSX.Element | null;
316
- //#endregion
317
- //#region src/components/NestedView.d.ts
318
- interface NestedViewProps {
319
- children?: ReactNode;
320
- }
321
- /**
322
- * A component that renders the current view of the nested router layer.
323
- *
324
- * To be simple, it renders the `element` of the current child page of a parent page.
325
- *
326
- * @example
327
- * ```tsx
328
- * import { NestedView } from "@alepha/react";
329
- *
330
- * class App {
331
- * parent = $page({
332
- * component: () => <NestedView />,
333
- * });
334
- *
335
- * child = $page({
336
- * parent: this.root,
337
- * component: () => <div>Child Page</div>,
338
- * });
339
- * }
340
- * ```
341
- */
342
- declare const NestedView: (props: NestedViewProps) => react_jsx_runtime11.JSX.Element;
343
- //#endregion
344
- //#region src/contexts/RouterContext.d.ts
345
- interface RouterContextValue {
346
- alepha: Alepha;
347
- state: RouterState;
348
- context: PageReactContext;
349
- }
350
- declare const RouterContext: react12.Context<RouterContextValue | undefined>;
351
- //#endregion
352
- //#region src/contexts/RouterLayerContext.d.ts
353
- interface RouterLayerContextValue {
354
- index: number;
355
- path: string;
356
- }
357
- declare const RouterLayerContext: react13.Context<RouterLayerContextValue | undefined>;
358
- //#endregion
359
- //#region src/providers/BrowserRouterProvider.d.ts
360
- interface BrowserRoute extends Route {
361
- page: PageRoute;
362
- }
363
- declare class BrowserRouterProvider extends RouterProvider<BrowserRoute> {
364
- protected readonly log: _alepha_core5.Logger;
365
- protected readonly alepha: Alepha;
366
- protected readonly pageDescriptorProvider: PageDescriptorProvider;
367
- add(entry: PageRouteEntry): void;
368
- protected readonly configure: _alepha_core5.HookDescriptor<"configure">;
369
- transition(url: URL, options?: TransitionOptions): Promise<RouterRenderResult>;
370
- root(state: RouterState, context: PageReactContext): ReactNode;
371
- }
372
- //#endregion
373
- //#region src/providers/ReactBrowserProvider.d.ts
374
- declare class ReactBrowserProvider {
375
- protected readonly log: _alepha_core7.Logger;
376
- protected readonly client: LinkProvider;
377
- protected readonly alepha: Alepha;
378
- protected readonly router: BrowserRouterProvider;
379
- protected root: Root;
380
- transitioning?: {
381
- to: string;
382
- };
383
- state: RouterState;
384
- get document(): Document;
385
- get history(): History;
386
- get url(): string;
387
- invalidate(props?: Record<string, any>): Promise<void>;
388
- go(url: string, options?: RouterGoOptions): Promise<void>;
389
- protected render(options?: {
390
- url?: string;
391
- previous?: PreviousLayerData[];
392
- }): Promise<RouterRenderResult>;
393
- /**
394
- * Get embedded layers from the server.
395
- */
396
- protected getHydrationState(): ReactHydrationState | undefined;
397
- readonly ready: _alepha_core7.HookDescriptor<"ready">;
398
- }
399
- interface RouterGoOptions {
400
- replace?: boolean;
401
- match?: TransitionOptions;
402
- params?: Record<string, string>;
403
- }
404
- interface ReactHydrationState {
405
- layers?: Array<PreviousLayerData>;
406
- links?: ApiLinksResponse;
407
- }
408
- //#endregion
409
- //#region src/hooks/RouterHookApi.d.ts
410
- declare class RouterHookApi {
411
- private readonly pages;
412
- private readonly state;
413
- private readonly layer;
414
- private readonly browser?;
415
- constructor(pages: PageRoute[], state: RouterState, layer: {
416
- path: string;
417
- }, browser?: ReactBrowserProvider | undefined);
418
- get current(): RouterState;
419
- get pathname(): string;
420
- get query(): Record<string, string>;
421
- back(): Promise<void>;
422
- forward(): Promise<void>;
423
- invalidate(props?: Record<string, any>): Promise<void>;
424
- /**
425
- * Create a valid href for the given pathname.
426
- *
427
- * @param pathname
428
- * @param layer
429
- */
430
- createHref(pathname: HrefLike, layer?: {
431
- path: string;
432
- }, options?: {
433
- params?: Record<string, any>;
434
- }): string;
435
- go(path: string, options?: RouterGoOptions): Promise<void>;
436
- go<T extends object>(path: keyof VirtualRouter<T>, options?: RouterGoOptions): Promise<void>;
437
- anchor(path: string, options?: {
438
- params?: Record<string, any>;
439
- }): AnchorProps;
440
- anchor<T extends object>(path: keyof VirtualRouter<T>, options?: {
441
- params?: Record<string, any>;
442
- }): AnchorProps;
443
- /**
444
- * Set query params.
445
- *
446
- * @param record
447
- * @param options
448
- */
449
- setQueryParams(record: Record<string, any> | ((queryParams: Record<string, any>) => Record<string, any>), options?: {
450
- /**
451
- * If true, this will add a new entry to the history stack.
452
- */
453
- push?: boolean;
454
- }): void;
455
- }
456
- type HrefLike = string | {
457
- options: {
458
- path?: string;
459
- name?: string;
460
- };
461
- };
462
- type VirtualRouter<T> = { [K in keyof T as T[K] extends PageDescriptor ? K : never]: T[K] };
463
- //#endregion
464
- //#region src/errors/RedirectionError.d.ts
465
- declare class RedirectionError extends Error {
466
- readonly page: HrefLike;
467
- constructor(page: HrefLike);
468
- }
469
- //#endregion
470
- //#region src/hooks/useActive.d.ts
471
- declare const useActive: (path: HrefLike) => UseActiveHook;
472
- interface UseActiveHook {
473
- isActive: boolean;
474
- anchorProps: AnchorProps;
475
- isPending: boolean;
476
- name?: string;
477
- }
478
- //#endregion
479
- //#region src/hooks/useAlepha.d.ts
480
- declare const useAlepha: () => Alepha;
481
- //#endregion
482
- //#region src/hooks/useClient.d.ts
483
- declare const useClient: <T extends object>(_scope?: ClientScope) => HttpVirtualClient<T>;
484
- //#endregion
485
- //#region src/hooks/useInject.d.ts
486
- declare const useInject: <T extends object>(clazz: Service<T>) => T;
487
- //#endregion
488
- //#region src/hooks/useQueryParams.d.ts
489
- interface UseQueryParamsHookOptions {
490
- format?: "base64" | "querystring";
491
- key?: string;
492
- push?: boolean;
493
- }
494
- declare const useQueryParams: <T extends TObject>(schema: T, options?: UseQueryParamsHookOptions) => [Static<T>, (data: Static<T>) => void];
495
- //#endregion
496
- //#region src/hooks/useRouter.d.ts
497
- declare const useRouter: () => RouterHookApi;
498
- //#endregion
499
- //#region src/hooks/useRouterEvents.d.ts
500
- declare const useRouterEvents: (opts?: {
501
- onBegin?: (ev: {
502
- state: RouterState;
503
- }) => void;
504
- onEnd?: (ev: {
505
- state: RouterState;
506
- }) => void;
507
- onError?: (ev: {
508
- state: RouterState;
509
- error: Error;
510
- }) => void;
511
- }, deps?: any[]) => void;
512
- //#endregion
513
- //#region src/hooks/useRouterState.d.ts
514
- declare const useRouterState: () => RouterState;
515
- //#endregion
516
- //#region src/index.browser.d.ts
517
- declare class AlephaReact implements Module {
518
- readonly name = "alepha.react";
519
- readonly $services: (alepha: Alepha) => Alepha;
520
- }
521
- //#endregion
522
- export { $page, AlephaReact, AnchorProps, BrowserRoute, BrowserRouterProvider, ClientOnly, CreateLayersResult, ErrorBoundary, HrefLike, Layer, Link, NestedView, PageConfigSchema, PageDescriptor, PageDescriptorOptions, PageDescriptorProvider, PageDescriptorRenderOptions, PageDescriptorRenderResult, PageReactContext, PageRequest, PageRequestConfig, PageResolve, PageRoute, PageRouteEntry, PreviousLayerData, ReactBrowserProvider, ReactHydrationState, RedirectionError, RouterContext, RouterContextValue, RouterGoOptions, RouterHookApi, RouterLayerContext, RouterLayerContextValue, RouterRenderResult, RouterStackItem, RouterState, TPropsDefault, TPropsParentDefault, TransitionOptions, UseActiveHook, UseQueryParamsHookOptions, VirtualRouter, isPageRoute, useActive, useAlepha, useClient, useInject, useQueryParams, useRouter, useRouterEvents, useRouterState };
523
- //# sourceMappingURL=index.browser.d.ts.map