chayns-api 3.0.1 → 3.1.0-beta.1

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 (142) hide show
  1. package/dist/cjs/calls/index.js +4 -1
  2. package/dist/cjs/calls/visibilityChangeListener.js +4 -4
  3. package/dist/cjs/components/ChaynsProvider.js +34 -6
  4. package/dist/cjs/components/withHydrationBoundary.js +2 -2
  5. package/dist/cjs/constants/index.js +0 -22
  6. package/dist/cjs/contexts/HistoryLayerContext.js +89 -0
  7. package/dist/cjs/contexts/index.js +38 -0
  8. package/dist/cjs/handler/history/FrameHistoryLayer.js +100 -0
  9. package/dist/cjs/handler/history/HistoryLayer.js +321 -0
  10. package/dist/cjs/handler/history/index.js +19 -0
  11. package/dist/cjs/hooks/history.js +454 -0
  12. package/dist/cjs/hooks/index.js +62 -1
  13. package/dist/cjs/host/ChaynsHost.js +113 -54
  14. package/dist/cjs/host/iframe/HostIframe.js +70 -5
  15. package/dist/cjs/host/module/ModuleHost.js +50 -44
  16. package/dist/cjs/index.js +139 -6
  17. package/dist/cjs/types/history.js +1 -0
  18. package/dist/cjs/umd.index.js +2 -2
  19. package/dist/cjs/utils/EventBus.js +33 -0
  20. package/dist/cjs/{util → utils}/appStorage.js +2 -2
  21. package/dist/cjs/utils/equality.js +19 -0
  22. package/dist/cjs/utils/history/BlockRegistry.js +153 -0
  23. package/dist/cjs/utils/history/NavigationQueue.js +389 -0
  24. package/dist/cjs/utils/history/layerTree.js +32 -0
  25. package/dist/cjs/utils/history/nativeBackHandling.js +61 -0
  26. package/dist/cjs/utils/history/navigationIndex.js +74 -0
  27. package/dist/cjs/utils/history/rootLayer.js +213 -0
  28. package/dist/cjs/utils/history/segments.js +15 -0
  29. package/dist/cjs/utils/history/stateProjector.js +156 -0
  30. package/dist/cjs/utils/history/url.js +47 -0
  31. package/dist/cjs/utils/history/window.js +9 -0
  32. package/dist/cjs/wrapper/AppWrapper.js +24 -24
  33. package/dist/cjs/wrapper/FrameWrapper.js +35 -2
  34. package/dist/cjs/wrapper/ModuleFederationWrapper.js +2 -0
  35. package/dist/cjs/wrapper/StaticChaynsApi.js +1 -1
  36. package/dist/esm/calls/index.js +2 -0
  37. package/dist/esm/calls/visibilityChangeListener.js +1 -1
  38. package/dist/esm/components/ChaynsProvider.js +34 -6
  39. package/dist/esm/components/withHydrationBoundary.js +1 -1
  40. package/dist/esm/constants/index.js +1 -3
  41. package/dist/esm/contexts/HistoryLayerContext.js +76 -0
  42. package/dist/esm/contexts/index.js +3 -0
  43. package/dist/esm/handler/history/FrameHistoryLayer.js +105 -0
  44. package/dist/esm/handler/history/HistoryLayer.js +321 -0
  45. package/dist/esm/handler/history/index.js +2 -0
  46. package/dist/esm/hooks/history.js +428 -0
  47. package/dist/esm/hooks/index.js +2 -1
  48. package/dist/esm/host/ChaynsHost.js +113 -54
  49. package/dist/esm/host/iframe/HostIframe.js +70 -5
  50. package/dist/esm/host/module/ModuleHost.js +50 -44
  51. package/dist/esm/index.js +15 -6
  52. package/dist/esm/types/history.js +1 -0
  53. package/dist/esm/umd.index.js +2 -2
  54. package/dist/esm/utils/EventBus.js +31 -0
  55. package/dist/esm/{util → utils}/appStorage.js +1 -1
  56. package/dist/esm/utils/equality.js +12 -0
  57. package/dist/esm/utils/history/BlockRegistry.js +151 -0
  58. package/dist/esm/utils/history/NavigationQueue.js +386 -0
  59. package/dist/esm/utils/history/layerTree.js +24 -0
  60. package/dist/esm/utils/history/nativeBackHandling.js +59 -0
  61. package/dist/esm/utils/history/navigationIndex.js +62 -0
  62. package/dist/esm/utils/history/rootLayer.js +205 -0
  63. package/dist/esm/utils/history/segments.js +7 -0
  64. package/dist/esm/utils/history/stateProjector.js +147 -0
  65. package/dist/esm/utils/history/url.js +40 -0
  66. package/dist/esm/utils/history/window.js +3 -0
  67. package/dist/esm/wrapper/AppWrapper.js +6 -6
  68. package/dist/esm/wrapper/FrameWrapper.js +35 -2
  69. package/dist/esm/wrapper/ModuleFederationWrapper.js +2 -0
  70. package/dist/esm/wrapper/StaticChaynsApi.js +2 -1
  71. package/dist/types/calls/index.d.ts +5 -0
  72. package/dist/types/components/ChaynsProvider.d.ts +21 -0
  73. package/dist/types/constants/index.d.ts +0 -2
  74. package/dist/types/contexts/HistoryLayerContext.d.ts +33 -0
  75. package/dist/types/contexts/index.d.ts +3 -0
  76. package/dist/types/handler/history/FrameHistoryLayer.d.ts +99 -0
  77. package/dist/types/handler/history/HistoryLayer.d.ts +117 -0
  78. package/dist/types/handler/history/index.d.ts +2 -0
  79. package/dist/types/hooks/history.d.ts +89 -0
  80. package/dist/types/hooks/index.d.ts +1 -0
  81. package/dist/types/host/ChaynsHost.d.ts +12 -0
  82. package/dist/types/host/iframe/HostIframe.d.ts +4 -0
  83. package/dist/types/host/module/ModuleHost.d.ts +4 -0
  84. package/dist/types/index.d.ts +15 -6
  85. package/dist/types/types/IChaynsReact.d.ts +3 -0
  86. package/dist/types/types/history.d.ts +74 -0
  87. package/dist/types/umd.index.d.ts +2 -2
  88. package/dist/types/utils/EventBus.d.ts +10 -0
  89. package/dist/types/{util → utils}/collectCssChunks.d.ts +1 -1
  90. package/dist/types/utils/equality.d.ts +2 -0
  91. package/dist/types/utils/history/BlockRegistry.d.ts +45 -0
  92. package/dist/types/utils/history/NavigationQueue.d.ts +118 -0
  93. package/dist/types/utils/history/layerTree.d.ts +10 -0
  94. package/dist/types/utils/history/nativeBackHandling.d.ts +47 -0
  95. package/dist/types/utils/history/navigationIndex.d.ts +17 -0
  96. package/dist/types/utils/history/rootLayer.d.ts +42 -0
  97. package/dist/types/utils/history/segments.d.ts +2 -0
  98. package/dist/types/utils/history/stateProjector.d.ts +24 -0
  99. package/dist/types/utils/history/url.d.ts +17 -0
  100. package/dist/types/utils/history/window.d.ts +1 -0
  101. package/dist/types/wrapper/FrameWrapper.d.ts +1 -0
  102. package/dist/types/wrapper/StaticChaynsApi.d.ts +1 -0
  103. package/package.json +2 -1
  104. /package/dist/cjs/{constants → contexts}/hydrationContext.js +0 -0
  105. /package/dist/cjs/{constants → contexts}/moduleContext.js +0 -0
  106. /package/dist/cjs/{helper/apiListenerHelper.js → utils/apiListener.js} +0 -0
  107. /package/dist/cjs/{util → utils}/appCall.js +0 -0
  108. /package/dist/cjs/{util → utils}/bindChaynsApi.js +0 -0
  109. /package/dist/cjs/{util → utils}/collectCssChunks.js +0 -0
  110. /package/dist/cjs/{util → utils}/deviceHelper.js +0 -0
  111. /package/dist/cjs/{util → utils}/heightHelper.js +0 -0
  112. /package/dist/cjs/{util → utils}/initModuleFederationSharing.js +0 -0
  113. /package/dist/cjs/{util → utils}/is.js +0 -0
  114. /package/dist/cjs/{util → utils}/postIframeForm.js +0 -0
  115. /package/dist/cjs/{util → utils}/transferNestedFunctions.js +0 -0
  116. /package/dist/cjs/{util → utils}/url.js +0 -0
  117. /package/dist/esm/{constants → contexts}/hydrationContext.js +0 -0
  118. /package/dist/esm/{constants → contexts}/moduleContext.js +0 -0
  119. /package/dist/esm/{helper/apiListenerHelper.js → utils/apiListener.js} +0 -0
  120. /package/dist/esm/{util → utils}/appCall.js +0 -0
  121. /package/dist/esm/{util → utils}/bindChaynsApi.js +0 -0
  122. /package/dist/esm/{util → utils}/collectCssChunks.js +0 -0
  123. /package/dist/esm/{util → utils}/deviceHelper.js +0 -0
  124. /package/dist/esm/{util → utils}/heightHelper.js +0 -0
  125. /package/dist/esm/{util → utils}/initModuleFederationSharing.js +0 -0
  126. /package/dist/esm/{util → utils}/is.js +0 -0
  127. /package/dist/esm/{util → utils}/postIframeForm.js +0 -0
  128. /package/dist/esm/{util → utils}/transferNestedFunctions.js +0 -0
  129. /package/dist/esm/{util → utils}/url.js +0 -0
  130. /package/dist/types/{constants → contexts}/hydrationContext.d.ts +0 -0
  131. /package/dist/types/{constants → contexts}/moduleContext.d.ts +0 -0
  132. /package/dist/types/{helper/apiListenerHelper.d.ts → utils/apiListener.d.ts} +0 -0
  133. /package/dist/types/{util → utils}/appCall.d.ts +0 -0
  134. /package/dist/types/{util → utils}/appStorage.d.ts +0 -0
  135. /package/dist/types/{util → utils}/bindChaynsApi.d.ts +0 -0
  136. /package/dist/types/{util → utils}/deviceHelper.d.ts +0 -0
  137. /package/dist/types/{util → utils}/heightHelper.d.ts +0 -0
  138. /package/dist/types/{util → utils}/initModuleFederationSharing.d.ts +0 -0
  139. /package/dist/types/{util → utils}/is.d.ts +0 -0
  140. /package/dist/types/{util → utils}/postIframeForm.d.ts +0 -0
  141. /package/dist/types/{util → utils}/transferNestedFunctions.d.ts +0 -0
  142. /package/dist/types/{util → utils}/url.d.ts +0 -0
@@ -0,0 +1,99 @@
1
+ import type { ChaynsHistoryLayer, ChaynsHistoryNavigateOptions, ChaynsHistoryNavigationCommitOptions, ChaynsHistoryBlockOptions, ChaynsHistoryLayerEvent, ChaynsHistoryActionResult } from '../../types/history';
2
+ /**
3
+ * Async bridge functions forwarded via comlink from the iframe (FrameWrapper) to
4
+ * the parent window (HostIframe). All methods are async because they cross the
5
+ * comlink boundary.
6
+ *
7
+ * Callbacks that cross the boundary (addBlock) must be wrapped with
8
+ * `comlink.proxy()` by the caller (FrameWrapper.init) before being passed in.
9
+ */
10
+ export interface HistoryBridgeFunctions {
11
+ setRoute(route: string | string[], opts?: ChaynsHistoryNavigateOptions): Promise<void>;
12
+ setParams(params: Record<string, string>, opts?: ChaynsHistoryNavigationCommitOptions): Promise<void>;
13
+ setHash(hash: string, opts?: ChaynsHistoryNavigationCommitOptions): Promise<void>;
14
+ setState(state: Record<string, unknown>, opts?: ChaynsHistoryNavigateOptions): Promise<void>;
15
+ navigate(opts: {
16
+ route?: string | string[];
17
+ state?: Record<string, unknown>;
18
+ activeChild?: string | null;
19
+ activeChildInit?: {
20
+ route?: string | string[];
21
+ state?: Record<string, unknown>;
22
+ };
23
+ } & ChaynsHistoryNavigateOptions): Promise<ChaynsHistoryActionResult>;
24
+ setActiveChild(id: string | null, init?: {
25
+ route?: string | string[];
26
+ state?: Record<string, unknown>;
27
+ }): Promise<ChaynsHistoryActionResult>;
28
+ setSegmentCount(n: number): Promise<void>;
29
+ /** Callback must be wrapped with comlink.proxy by FrameWrapper. Returns an async unsubscribe fn. */
30
+ addBlock(callback: () => Promise<boolean>, opts?: ChaynsHistoryBlockOptions): Promise<() => void>;
31
+ }
32
+ /** Snapshot of the host layer's state transferred to the frame at init time. */
33
+ export interface HistoryInitialState {
34
+ id: string;
35
+ depth: number;
36
+ segments: string[];
37
+ params: Record<string, string>;
38
+ hash: string;
39
+ state: Record<string, unknown> | undefined;
40
+ activeChildId: string | null;
41
+ segmentCount: number;
42
+ }
43
+ /**
44
+ * A `ChaynsHistoryLayer` proxy that runs inside an iframe (FrameWrapper).
45
+ *
46
+ * - **Reads** are served from a local cache for synchronous access.
47
+ * - **Writes** are forwarded to the parent window via `bridge` functions.
48
+ * - The cache is kept in sync by `FrameWrapper.init()`, which sets up a single
49
+ * comlink listener and calls `_applyAndEmit()` on every navigation event.
50
+ * - **Child layers** are not supported in the frame context — manage sub-routing
51
+ * with a local `initRootChaynsHistoryLayer` inside the iframe instead.
52
+ */
53
+ export declare class FrameHistoryLayer implements ChaynsHistoryLayer {
54
+ readonly id: string;
55
+ readonly depth: number;
56
+ private _segments;
57
+ private _params;
58
+ private _hash;
59
+ private _state;
60
+ private _activeChildId;
61
+ private _segmentCount;
62
+ private readonly bus;
63
+ private readonly bridge;
64
+ constructor(bridge: HistoryBridgeFunctions, initial: HistoryInitialState);
65
+ getSegmentCount(): number;
66
+ setSegmentCount(n: number): void;
67
+ createChildLayer(_id: string): ChaynsHistoryLayer;
68
+ destroyChildLayer(_id: string): void;
69
+ setActiveChild(id: string | null, init?: {
70
+ route?: string | string[];
71
+ state?: Record<string, unknown>;
72
+ }): Promise<ChaynsHistoryActionResult>;
73
+ getActiveChildId(): string | null;
74
+ getChildLayer(_id: string): ChaynsHistoryLayer | undefined;
75
+ getRoute(): string[];
76
+ setRoute(route: string | string[], opts?: ChaynsHistoryNavigateOptions): void;
77
+ getParams(): Record<string, string>;
78
+ setParams(params: Record<string, string>, opts?: ChaynsHistoryNavigationCommitOptions): void;
79
+ getHash(): string;
80
+ setHash(hash: string, opts?: ChaynsHistoryNavigationCommitOptions): void;
81
+ getState<T extends object = Record<string, unknown>>(): T | undefined;
82
+ setState(state: object, opts?: ChaynsHistoryNavigateOptions): void;
83
+ navigate(opts: {
84
+ route?: string | string[];
85
+ state?: Record<string, unknown>;
86
+ activeChild?: string | null;
87
+ activeChildInit?: {
88
+ route?: string | string[];
89
+ state?: Record<string, unknown>;
90
+ };
91
+ } & ChaynsHistoryNavigateOptions): Promise<ChaynsHistoryActionResult>;
92
+ addBlock(callback: () => Promise<boolean>, opts?: ChaynsHistoryBlockOptions): () => void;
93
+ addEventListener(type: 'popstate' | 'change', handler: (e: ChaynsHistoryLayerEvent) => void): () => void;
94
+ /**
95
+ * @internal Called by `FrameWrapper` when a navigation event arrives from the host.
96
+ * Updates the local cache and re-emits the event to all registered listeners.
97
+ */
98
+ _applyAndEmit(e: ChaynsHistoryLayerEvent): void;
99
+ }
@@ -0,0 +1,117 @@
1
+ import type { ChaynsHistoryLayer as IChaynsHistoryLayer, ChaynsHistoryLayerEvent, ChaynsHistoryNavigateOptions, ChaynsHistoryNavigationCommitOptions, ChaynsHistoryBlockOptions, ChaynsHistoryActionResult } from '../../types/history';
2
+ import type { NavigationQueue } from '../../utils/history/NavigationQueue';
3
+ import type { BlockRegistry } from '../../utils/history/BlockRegistry';
4
+ export interface ChaynsHistoryLayerDeps {
5
+ /** Reference to the root layer for queue + block registry access. */
6
+ getRoot: () => ChaynsHistoryLayer;
7
+ /** Top-window navigation queue (singleton). */
8
+ getQueue: () => NavigationQueue;
9
+ /** Top-window block registry (singleton). */
10
+ getBlockRegistry: () => BlockRegistry;
11
+ }
12
+ export interface ChaynsHistoryLayerInit {
13
+ id: string;
14
+ parent: ChaynsHistoryLayer | null;
15
+ deps: ChaynsHistoryLayerDeps;
16
+ segmentCount?: number;
17
+ /** Initial URL segments for this layer (length must equal segmentCount). */
18
+ segments?: string[];
19
+ }
20
+ export declare class ChaynsHistoryLayer implements IChaynsHistoryLayer {
21
+ readonly id: string;
22
+ readonly depth: number;
23
+ readonly parent: ChaynsHistoryLayer | null;
24
+ /** Insertion-ordered map of children. */
25
+ private readonly children;
26
+ /** Currently active child id (null = no child active). */
27
+ private activeChildId;
28
+ /** Number of URL segments this layer owns. */
29
+ private segmentCount;
30
+ /** This layer's own URL segments (length must equal segmentCount when active). */
31
+ private segments;
32
+ /** This layer's own state slice (without reserved keys). */
33
+ private ownState;
34
+ /** This layer's own query params. Merged with other active-chain layers when projecting URL. */
35
+ private _params;
36
+ /**
37
+ * This layer's own hash fragment (without `#`).
38
+ * `undefined` = never explicitly set (unset/no opinion).
39
+ * `''` = explicitly cleared.
40
+ * `'foo'` = explicitly set to `'foo'`.
41
+ */
42
+ private _hash;
43
+ /** Pub/sub for change + popstate events scoped to this layer. */
44
+ private readonly bus;
45
+ private readonly deps;
46
+ /** Lazily-resolved bootstrap URL segments. Null = not yet initialised. */
47
+ private _bootstrapPool;
48
+ /** Resolver called once on first consume to build the pool. */
49
+ private _bootstrapUrlResolver;
50
+ private isDestroyed;
51
+ constructor(init: ChaynsHistoryLayerInit);
52
+ getSegmentCount(): number;
53
+ setSegmentCount(n: number): void;
54
+ createChildLayer(id: string): ChaynsHistoryLayer;
55
+ destroyChildLayer(id: string): void;
56
+ getChildLayer(id: string): ChaynsHistoryLayer | undefined;
57
+ getActiveChildId(): string | null;
58
+ setActiveChild(id: string | null, init?: {
59
+ route?: string | string[];
60
+ state?: Record<string, unknown>;
61
+ }): Promise<ChaynsHistoryActionResult>;
62
+ getRoute(): string[];
63
+ setRoute(route: string | string[], opts?: ChaynsHistoryNavigateOptions): void;
64
+ getParams(): Record<string, string>;
65
+ setParams(params: Record<string, string>, opts?: ChaynsHistoryNavigationCommitOptions): void;
66
+ getHash(): string;
67
+ setHash(hash: string, opts?: ChaynsHistoryNavigationCommitOptions): void;
68
+ getState<T extends object = Record<string, unknown>>(): T | undefined;
69
+ setState<T extends object>(state: T, opts?: ChaynsHistoryNavigateOptions): void;
70
+ navigate(opts: {
71
+ route?: string | string[];
72
+ state?: Record<string, unknown>;
73
+ activeChild?: string | null;
74
+ activeChildInit?: {
75
+ route?: string | string[];
76
+ state?: Record<string, unknown>;
77
+ };
78
+ } & ChaynsHistoryNavigateOptions): Promise<ChaynsHistoryActionResult>;
79
+ addBlock(callback: () => Promise<boolean>, opts?: ChaynsHistoryBlockOptions): () => void;
80
+ addEventListener(type: 'popstate' | 'change', handler: (e: ChaynsHistoryLayerEvent) => void): () => void;
81
+ /** @internal */
82
+ _getOwnState(): Record<string, unknown>;
83
+ /** @internal */
84
+ _getOwnSegments(): string[];
85
+ /** @internal */
86
+ _getChildren(): ReadonlyMap<string, ChaynsHistoryLayer>;
87
+ /** @internal Apply mutated own state without firing events (used by projectors). */
88
+ _setOwnStateSilent(next: Record<string, unknown>): void;
89
+ /** @internal Apply mutated segments without firing events. */
90
+ _setOwnSegmentsSilent(next: string[]): void;
91
+ /** @internal */
92
+ _getOwnParams(): Record<string, string>;
93
+ /** @internal */
94
+ _setOwnParamsSilent(params: Record<string, string>): void;
95
+ /** @internal Returns the raw hash value (`undefined` = never set). */
96
+ _getOwnHash(): string | undefined;
97
+ /** @internal */
98
+ _setOwnHashSilent(hash: string | undefined): void;
99
+ /** @internal Set active child without enqueueing (used by projectors / queue processor). */
100
+ _setActiveChildSilent(id: string | null): void;
101
+ /** @internal Emit a typed event. Called by queue after diff confirms relevance. */
102
+ _emit(type: 'change' | 'popstate'): void;
103
+ /** @internal True if this layer is reachable via active chain from root. */
104
+ _isInActiveChain(): boolean;
105
+ /** @internal Register a lazy URL resolver (called once on first bootstrap consume). */
106
+ _setBootstrapUrlResolver(resolver: () => string): void;
107
+ /** @internal Set the bootstrap pool directly (overrides the lazy resolver). */
108
+ _setBootstrapPool(segs: string[]): void;
109
+ /** @internal Consume the next `n` segments from the bootstrap pool. Returns null if pool is exhausted or unset. */
110
+ _consumeBootstrapSegments(n: number): string[] | null;
111
+ /** @internal */
112
+ _isDestroyed(): boolean;
113
+ private markDestroyed;
114
+ private getCumulativeSegmentCount;
115
+ private static normalizeRoute;
116
+ private static filterReservedKeys;
117
+ }
@@ -0,0 +1,2 @@
1
+ export { ChaynsHistoryLayer as ChaynsHistoryLayerClass } from './HistoryLayer';
2
+ export { FrameHistoryLayer, type HistoryBridgeFunctions, type HistoryInitialState } from './FrameHistoryLayer';
@@ -0,0 +1,89 @@
1
+ import type { ChaynsHistoryLayer, ChaynsHistoryNavigateOptions, ChaynsHistoryNavigationCommitOptions, ChaynsHistoryBlockOptions, ChaynsHistoryLayerEvent, ChaynsHistoryActionResult } from '../types/history';
2
+ /**
3
+ * Resolves the active ChaynsHistoryLayer: context first, then
4
+ * `chaynsHost.history.getOwnLayer()` if available, then throws in dev.
5
+ */
6
+ export declare function useChaynsHistoryLayer(): ChaynsHistoryLayer;
7
+ export interface UseChaynsHistoryRouteResult {
8
+ segments: string[];
9
+ setRoute: (route: string | string[], opts?: ChaynsHistoryNavigateOptions) => void;
10
+ }
11
+ /**
12
+ * Returns the current route segments and a setter for the nearest ChaynsHistoryLayer.
13
+ * Re-renders only when the segments change.
14
+ */
15
+ export declare function useChaynsHistoryRoute(): UseChaynsHistoryRouteResult;
16
+ /**
17
+ * Returns the current layer state and a setter.
18
+ * Re-renders only when the own-state changes (shallow comparison performed by layer).
19
+ */
20
+ export declare function useChaynsHistoryState<T extends object = Record<string, unknown>>(): [
21
+ T | undefined,
22
+ (state: T, opts?: ChaynsHistoryNavigateOptions) => void
23
+ ];
24
+ /**
25
+ * Returns a stable `navigate` function for the nearest ChaynsHistoryLayer.
26
+ */
27
+ export declare function useChaynsHistoryNavigate(): (opts: {
28
+ route?: string | string[];
29
+ state?: Record<string, unknown>;
30
+ /** Switch the active child as part of this navigation. Auto-creates the child if needed. */
31
+ activeChild?: string | null;
32
+ /** Initial route/state to seed the child with when it is first activated. */
33
+ activeChildInit?: {
34
+ route?: string | string[];
35
+ state?: Record<string, unknown>;
36
+ };
37
+ } & ChaynsHistoryNavigateOptions) => Promise<ChaynsHistoryActionResult>;
38
+ /**
39
+ * Returns the current query params and a setter for the nearest ChaynsHistoryLayer.
40
+ * Setter replaces all params on this layer; merge manually if needed:
41
+ * `setParams({ ...params, newKey: 'val' })`.
42
+ * Re-renders only when params change.
43
+ */
44
+ export declare function useChaynsHistoryParams(): [
45
+ Record<string, string>,
46
+ (params: Record<string, string>, opts?: ChaynsHistoryNavigationCommitOptions) => void
47
+ ];
48
+ /**
49
+ * Returns the current hash fragment (without `#`) and a setter for the nearest ChaynsHistoryLayer.
50
+ * Pass `''` to explicitly clear the hash.
51
+ * Re-renders only when the hash changes.
52
+ */
53
+ export declare function useChaynsHistoryHash(): [string, (hash: string, opts?: ChaynsHistoryNavigationCommitOptions) => void];
54
+ export interface UseChaynsHistoryBlockOptions extends ChaynsHistoryBlockOptions {
55
+ /** Only register the block when true. Default: true. */
56
+ isEnabled?: boolean;
57
+ }
58
+ /**
59
+ * Registers a navigation blocker. The callback must return a Promise<boolean>:
60
+ * true = allow, false = block.
61
+ *
62
+ * The caller is responsible for providing a stable `callback` reference
63
+ * (e.g. via useCallback) — registrations only change when the reference changes.
64
+ * `scope` and `isBeforeUnload` are read when the block is registered; changes
65
+ * after mount are applied on the next registration cycle.
66
+ */
67
+ export declare function useChaynsHistoryBlock(callback: () => Promise<boolean>, opts?: UseChaynsHistoryBlockOptions): void;
68
+ /**
69
+ * Low-level subscription to `change` or `popstate` events on the nearest layer.
70
+ */
71
+ export declare function useChaynsHistoryEvent(type: 'change' | 'popstate', handler: (e: ChaynsHistoryLayerEvent) => void): void;
72
+ /**
73
+ * Returns the child layer with the given id, creating it on mount if it
74
+ * doesn't already exist. Does NOT destroy the layer on unmount — the caller
75
+ * must explicitly call `layer.destroyChildLayer(id)` to remove it.
76
+ */
77
+ export declare function useChaynsHistoryChildLayer(id: string): ChaynsHistoryLayer;
78
+ export interface UseChaynsHistoryActiveChildResult {
79
+ activeChildId: string | null;
80
+ setActiveChild: (id: string | null, init?: {
81
+ route?: string[];
82
+ state?: Record<string, unknown>;
83
+ }) => void;
84
+ }
85
+ /**
86
+ * Returns the active child id of the nearest layer and a setter.
87
+ */
88
+ export declare function useChaynsHistoryActiveChild(): UseChaynsHistoryActiveChildResult;
89
+ export { ChaynsHistoryLayerProvider, useChaynsHistoryLayerContext } from '../contexts/HistoryLayerContext';
@@ -19,3 +19,4 @@ export { useCustomCallbackFunction } from './useCustomCallbackFunction';
19
19
  export { useCustomFunction } from './useCustomFunction';
20
20
  export { useStyleSettings } from './useStyleSettings';
21
21
  export { useChaynsApiId } from './useChaynsApiId';
22
+ export { useChaynsHistoryLayer, useChaynsHistoryRoute, useChaynsHistoryParams, useChaynsHistoryHash, useChaynsHistoryState, useChaynsHistoryNavigate, useChaynsHistoryBlock, useChaynsHistoryEvent, useChaynsHistoryChildLayer, useChaynsHistoryActiveChild, type UseChaynsHistoryRouteResult, type UseChaynsHistoryActiveChildResult, type UseChaynsHistoryBlockOptions, } from './history';
@@ -1,6 +1,7 @@
1
1
  import React, { FC } from 'react';
2
2
  import { TypeSystem } from './module/ModuleHost';
3
3
  import { ChaynsApiDevice, ChaynsApiSite, ChaynsApiUser, ChaynsReactFunctions, ChaynsReactValues, IChaynsReact, Page } from '../types/IChaynsReact';
4
+ import { ChaynsHistoryLayer } from '../types/history';
4
5
  type ChaynsHostType = {
5
6
  type: `${'client' | 'server'}-${'iframe' | 'module'}`;
6
7
  iFrameProps?: {
@@ -26,6 +27,17 @@ type ChaynsHostType = {
26
27
  preventStagingReplacement?: boolean;
27
28
  dialog: ChaynsReactValues["dialog"];
28
29
  styleSettings?: ChaynsReactValues["styleSettings"];
30
+ /** History layer to provide to hosted children. Defaults to the root layer. */
31
+ historyLayer?: ChaynsHistoryLayer;
32
+ /**
33
+ * ID for this module's dedicated child history layer.
34
+ * When set, a child layer with this ID is created (or reused) from the parent
35
+ * `historyLayer` and passed to the module — giving the module its own routing
36
+ * namespace. Activate it with `layer.navigate({ activeChild: historyChildId })`.
37
+ */
38
+ historyChildId?: string;
39
+ /** Whether the history is disabled for the children */
40
+ isHistoryDisabled?: boolean;
29
41
  } & ({
30
42
  type: `${'client' | 'server'}-iframe`;
31
43
  src: string;
@@ -1,5 +1,6 @@
1
1
  import React, { FC } from 'react';
2
2
  import { ChaynsApiDevice, ChaynsApiSite, ChaynsApiUser, ChaynsReactFunctions, ChaynsReactValues, IChaynsReact, Page } from '../../types/IChaynsReact';
3
+ import type { ChaynsHistoryLayer } from '../../types/history';
3
4
  type HostIframeProps = {
4
5
  iFrameProps: {
5
6
  [key: string]: unknown;
@@ -23,6 +24,9 @@ type HostIframeProps = {
23
24
  preventStagingReplacement?: boolean;
24
25
  dialog: ChaynsReactValues["dialog"];
25
26
  styleSettings: ChaynsReactValues["styleSettings"];
27
+ historyLayer?: ChaynsHistoryLayer;
28
+ /** Whether the history is disabled for the children */
29
+ isHistoryDisabled?: boolean;
26
30
  };
27
31
  declare const HostIframe: FC<HostIframeProps>;
28
32
  export default HostIframe;
@@ -1,5 +1,6 @@
1
1
  import { FC, ReactNode } from 'react';
2
2
  import { ChaynsApiDevice, ChaynsApiSite, ChaynsApiUser, ChaynsReactFunctions, ChaynsReactValues, IChaynsReact, Page } from '../../types/IChaynsReact';
3
+ import type { ChaynsHistoryLayer } from '../../types/history';
3
4
  export type TypeSystem = {
4
5
  scope: string;
5
6
  url: string;
@@ -25,6 +26,9 @@ type ModulePropTypes = {
25
26
  dialog: ChaynsReactValues["dialog"];
26
27
  children?: ReactNode;
27
28
  styleSettings: ChaynsReactValues["styleSettings"];
29
+ historyLayer?: ChaynsHistoryLayer;
30
+ /** Whether the history is disabled for the children */
31
+ isHistoryDisabled?: boolean;
28
32
  };
29
33
  declare const ModuleHost: FC<ModulePropTypes>;
30
34
  export default ModuleHost;
@@ -1,21 +1,30 @@
1
1
  export { default as ChaynsProvider, type ChaynsProviderProps } from './components/ChaynsProvider';
2
- export { default as getDeviceInfo, getScreenSize, getClientDeviceInfo } from './util/deviceHelper';
2
+ export { default as getDeviceInfo, getScreenSize, getClientDeviceInfo } from './utils/deviceHelper';
3
3
  export { default as ChaynsHost } from './host/ChaynsHost';
4
4
  export { withCompatMode } from './components/withCompatMode';
5
5
  export * from './calls';
6
6
  export * from './hooks';
7
7
  export * from './components/WaitUntil';
8
8
  export * from './types/IChaynsReact';
9
- export * from './util/is';
9
+ export * from './types/history';
10
+ export * from './utils/is';
10
11
  export * from './constants';
11
12
  export { default as withHydrationBoundary } from './components/withHydrationBoundary';
12
13
  export { default as StaticChaynsApi } from './wrapper/StaticChaynsApi';
13
14
  export { default as loadComponent, loadModule } from './host/module/utils/loadComponent';
14
15
  export { default as DialogHandler } from './handler/DialogHandler';
16
+ export * from './handler/history';
17
+ export { initRootChaynsHistoryLayer, getOrInitRootChaynsHistoryLayer, type InitRootChaynsHistoryLayerOptions, type InitRootChaynsHistoryLayerResult } from './utils/history/rootLayer';
18
+ export { NavigationQueue } from './utils/history/NavigationQueue';
19
+ export { BlockRegistry } from './utils/history/BlockRegistry';
20
+ export { projectToUrl, parseFromUrl } from './utils/history/url';
21
+ export { projectToState, applyStateToTree, diffIncomingState, hasChaynsHistoryState } from './utils/history/stateProjector';
22
+ export { getChaynsHistoryActiveChain, findChaynsHistoryLayerById, isInChaynsHistoryActiveChain } from './utils/history/layerTree';
15
23
  export * as dialog from './calls/dialogs/index';
16
24
  export * from './plugins';
17
- export * from './util/initModuleFederationSharing';
18
- export * from './util/bindChaynsApi';
19
- export * from './util/appStorage';
20
- export * from './util/collectCssChunks';
25
+ export * from './utils/initModuleFederationSharing';
26
+ export * from './utils/bindChaynsApi';
27
+ export * from './utils/appStorage';
28
+ export * from './utils/collectCssChunks';
29
+ export * from './contexts';
21
30
  export { getChaynsApi } from './components/moduleWrapper';
@@ -1,6 +1,7 @@
1
1
  import { IBrowser, IEngine } from 'ua-parser-js';
2
2
  import DialogHandler from '../handler/DialogHandler';
3
3
  import { DialogButtonOld, SelectDialogItem } from './dialog';
4
+ import type { ChaynsHistoryLayer } from './history';
4
5
  export type DialogButton = {
5
6
  type: DialogButtonType;
6
7
  text: string;
@@ -311,6 +312,7 @@ export interface ChaynsReactValues {
311
312
  site: ChaynsApiSite;
312
313
  user: ChaynsApiUser | undefined;
313
314
  isAdminModeActive: boolean;
315
+ isHistoryDisabled?: boolean;
314
316
  pages: Page[];
315
317
  currentPage: {
316
318
  id: number;
@@ -465,6 +467,7 @@ export interface ChaynsReactFunctions {
465
467
  destination: string;
466
468
  isPermanent?: boolean;
467
469
  }) => Promise<void>;
470
+ getHistoryLayer(): ChaynsHistoryLayer;
468
471
  }
469
472
  export type ChaynsReactCustomFunctions = {
470
473
  [key: string]: (...args: any[]) => Promise<any>;
@@ -0,0 +1,74 @@
1
+ export type ChaynsHistoryNavigationCommitOptions = {
2
+ isReplace?: boolean;
3
+ };
4
+ export type ChaynsHistoryNavigateOptions = ChaynsHistoryNavigationCommitOptions & {
5
+ /** Query parameters to set on this layer. Replaces existing params for this layer. */
6
+ params?: Record<string, string>;
7
+ /** URL hash fragment (without leading `#`). Pass `''` to explicitly clear. */
8
+ hash?: string;
9
+ };
10
+ export type ChaynsHistoryBlockOptions = {
11
+ /** @default 'local' */
12
+ scope?: 'local' | 'global';
13
+ /** @default false */
14
+ isBeforeUnload?: boolean;
15
+ };
16
+ export type ChaynsHistoryLayerEvent = {
17
+ type: 'change' | 'popstate';
18
+ layerId: string;
19
+ segments: string[];
20
+ state: Record<string, unknown>;
21
+ params: Record<string, string>;
22
+ hash: string;
23
+ };
24
+ export type ChaynsHistoryActionResult = {
25
+ isOk: true;
26
+ } | {
27
+ isOk: false;
28
+ reason: 'blocked' | 'stale' | 'destroyed' | 'error';
29
+ error?: unknown;
30
+ };
31
+ export type ChaynsHistoryLayerStateNode = {
32
+ activeChild?: string;
33
+ childState?: ChaynsHistoryLayerStateNode;
34
+ /** @internal Reserved — managed by history core. */
35
+ __params?: Record<string, string>;
36
+ /** @internal Reserved — managed by history core. `undefined` = unset, `''` = explicit clear. */
37
+ __hash?: string;
38
+ [key: string]: unknown;
39
+ };
40
+ export interface ChaynsHistoryLayer {
41
+ readonly id: string;
42
+ readonly depth: number;
43
+ getSegmentCount(): number;
44
+ setSegmentCount(n: number): void;
45
+ createChildLayer(id: string): ChaynsHistoryLayer;
46
+ destroyChildLayer(id: string): void;
47
+ setActiveChild(id: string | null, init?: {
48
+ route?: string | string[];
49
+ state?: Record<string, unknown>;
50
+ }): Promise<ChaynsHistoryActionResult>;
51
+ getActiveChildId(): string | null;
52
+ getChildLayer(id: string): ChaynsHistoryLayer | undefined;
53
+ getRoute(): string[];
54
+ setRoute(route: string | string[], opts?: ChaynsHistoryNavigateOptions): void;
55
+ getParams(): Record<string, string>;
56
+ setParams(params: Record<string, string>, opts?: ChaynsHistoryNavigationCommitOptions): void;
57
+ getHash(): string;
58
+ setHash(hash: string, opts?: ChaynsHistoryNavigationCommitOptions): void;
59
+ getState<T extends object = Record<string, unknown>>(): T | undefined;
60
+ setState<T extends object>(state: T, opts?: ChaynsHistoryNavigateOptions): void;
61
+ navigate(opts: {
62
+ route?: string | string[];
63
+ state?: Record<string, unknown>;
64
+ /** Switch the active child as part of this navigation. Auto-creates the child if needed. */
65
+ activeChild?: string | null;
66
+ /** Initial route/state to seed the child with when it is first activated. */
67
+ activeChildInit?: {
68
+ route?: string | string[];
69
+ state?: Record<string, unknown>;
70
+ };
71
+ } & ChaynsHistoryNavigateOptions): Promise<ChaynsHistoryActionResult>;
72
+ addBlock(callback: () => Promise<boolean>, opts?: ChaynsHistoryBlockOptions): () => void;
73
+ addEventListener(type: 'popstate' | 'change', handler: (e: ChaynsHistoryLayerEvent) => void): () => void;
74
+ }
@@ -1,7 +1,7 @@
1
- export { default as getDeviceInfo, getScreenSize, getClientDeviceInfo } from './util/deviceHelper';
1
+ export { default as getDeviceInfo, getScreenSize, getClientDeviceInfo } from './utils/deviceHelper';
2
2
  export * from './calls';
3
3
  export * from './types/IChaynsReact';
4
- export * from './util/is';
4
+ export * from './utils/is';
5
5
  export { default as StaticChaynsApi } from './wrapper/StaticChaynsApi';
6
6
  export { default as DialogHandler } from './handler/DialogHandler';
7
7
  export * as dialog from './calls/dialogs/index';
@@ -0,0 +1,10 @@
1
+ type Listener<E> = (event: E) => void;
2
+ export declare class EventBus<E extends {
3
+ type: string;
4
+ }> {
5
+ private listeners;
6
+ on(type: E['type'], handler: Listener<E>): () => void;
7
+ emit(type: E['type'], event: E): void;
8
+ clear(): void;
9
+ }
10
+ export {};
@@ -1,4 +1,4 @@
1
- import { ModuleContextValueType } from '../constants';
1
+ import { ModuleContextValueType } from '../contexts';
2
2
  /**
3
3
  * Collects the css chunks from all modules rendered during SSR
4
4
  * @experimental Handling for async chunks is not final and subject to change.
@@ -0,0 +1,2 @@
1
+ export declare function shallowEqualArr(a: readonly unknown[], b: readonly unknown[]): boolean;
2
+ export declare function shallowEqualObj(a: Record<string, unknown>, b: Record<string, unknown>): boolean;
@@ -0,0 +1,45 @@
1
+ import type { ChaynsHistoryLayer } from '../../handler/history/HistoryLayer';
2
+ import type { ChaynsHistoryBlockOptions } from '../../types/history';
3
+ interface BlockEntry {
4
+ readonly id: string;
5
+ readonly callback: () => Promise<boolean>;
6
+ readonly opts: Required<ChaynsHistoryBlockOptions>;
7
+ }
8
+ export declare class BlockRegistry {
9
+ /** Per-layer block list. */
10
+ private readonly layerBlocks;
11
+ private readonly changeListeners;
12
+ /** Number of blocks with `isBeforeUnload: true`. When > 0, listener is attached. */
13
+ private beforeUnloadCount;
14
+ private readonly beforeUnloadHandler;
15
+ add(layer: ChaynsHistoryLayer, callback: () => Promise<boolean>, opts?: ChaynsHistoryBlockOptions): () => void;
16
+ remove(layerId: string, entry: BlockEntry): void;
17
+ /** Remove all blocks registered for a layer (called on destroy). */
18
+ removeAllForLayer(layerId: string): void;
19
+ subscribeToChanges(listener: () => void): () => void;
20
+ /**
21
+ * Collects all blocks applicable to a navigation targeting `targetLayer`.
22
+ *
23
+ * Rules:
24
+ * - `local` blocks: only those registered on `targetLayer`.
25
+ * - `global` blocks: those registered on `targetLayer` or any of its
26
+ * **active-chain descendants** (not inactive subtrees).
27
+ */
28
+ collectApplicableBlocks(targetLayer: ChaynsHistoryLayer): BlockEntry[];
29
+ hasActiveBlocks(rootLayer: ChaynsHistoryLayer): boolean;
30
+ checkActiveBlocks(rootLayer: ChaynsHistoryLayer): Promise<boolean>;
31
+ private collectActiveChainBlocks;
32
+ private collectGlobalFromActiveDescendants;
33
+ private collectFromActiveChain;
34
+ /**
35
+ * Runs all applicable block callbacks in parallel.
36
+ * Returns `true` if navigation is allowed (no block), `false` otherwise.
37
+ * Callbacks that throw or time out count as blocked (with dev-warn).
38
+ */
39
+ checkBlocks(targetLayer: ChaynsHistoryLayer): Promise<boolean>;
40
+ private runBlock;
41
+ private incrementBeforeUnload;
42
+ private decrementBeforeUnload;
43
+ private notifyChange;
44
+ }
45
+ export {};