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,205 @@
1
+ import { ChaynsHistoryLayer } from '../../handler/history/HistoryLayer';
2
+ import { NavigationQueue } from './NavigationQueue';
3
+ import { BlockRegistry } from './BlockRegistry';
4
+ import { findChaynsHistoryLayerById } from './layerTree';
5
+ import { projectToUrl, parseFromUrl } from './url';
6
+ import { projectToState, applyStateToTree, diffIncomingState, hasChaynsHistoryState } from './stateProjector';
7
+ import { silentGo, consumeSilent, incrementIdx, getCurrentIdx, syncCurrentIdxFromState } from './navigationIndex';
8
+ import { hasWindowHistory } from './window';
9
+ import { shallowEqualArr } from '../equality';
10
+ import { getSite } from '../../calls';
11
+ import { normalizeHistorySegments } from './segments';
12
+ import { NativeBackHandler } from './nativeBackHandling';
13
+ function getInitialPathname(overrideUrl) {
14
+ if (overrideUrl) {
15
+ try {
16
+ return new URL(overrideUrl).pathname;
17
+ } catch {}
18
+ return overrideUrl.startsWith('/') ? overrideUrl : `/${overrideUrl}`;
19
+ }
20
+ if (hasWindowHistory()) {
21
+ return window.location.pathname;
22
+ }
23
+ try {
24
+ const siteUrl = getSite().url;
25
+ if (siteUrl) return new URL(siteUrl).pathname;
26
+ } catch {}
27
+ return '/';
28
+ }
29
+ function resolveInitialSegments(overrideUrl, n) {
30
+ const pathname = getInitialPathname(overrideUrl);
31
+ const all = pathname.replace(/^\//, '').split('/').filter(Boolean);
32
+ const taken = all.slice(0, n);
33
+ while (taken.length < n) taken.push('');
34
+ return taken;
35
+ }
36
+ export function resolveSegmentsFrom(overrideUrl, startIndex) {
37
+ const pathname = getInitialPathname(overrideUrl);
38
+ const all = pathname.replace(/^\//, '').split('/').filter(Boolean);
39
+ return all.slice(startIndex);
40
+ }
41
+ export function initRootChaynsHistoryLayer(opts = {}) {
42
+ var _opts$segmentCount;
43
+ const blockRegistry = new BlockRegistry();
44
+ let queueRef = null;
45
+ const deps = {
46
+ getRoot: () => rootLayer,
47
+ getQueue: () => {
48
+ if (!queueRef) {
49
+ throw new Error('[chaynsHistory] NavigationQueue not initialized yet.');
50
+ }
51
+ return queueRef;
52
+ },
53
+ getBlockRegistry: () => blockRegistry
54
+ };
55
+ const rootLayer = new ChaynsHistoryLayer({
56
+ id: 'root',
57
+ parent: null,
58
+ deps,
59
+ segmentCount: (_opts$segmentCount = opts.segmentCount) !== null && _opts$segmentCount !== void 0 ? _opts$segmentCount : 0,
60
+ segments: opts.segmentCount ? resolveInitialSegments(opts.url, opts.segmentCount) : []
61
+ });
62
+ const nativeBackHandler = new NativeBackHandler({
63
+ rootLayer,
64
+ blockRegistry
65
+ });
66
+ const syncNativeHandling = nativeBackHandler.sync;
67
+ const queue = new NavigationQueue({
68
+ getRoot: () => rootLayer,
69
+ findLayer: id => findChaynsHistoryLayerById(rootLayer, id),
70
+ checkBlocks: target => blockRegistry.checkBlocks(target),
71
+ projectUrl: () => projectToUrl(rootLayer),
72
+ projectState: () => {
73
+ var _ref;
74
+ const existing = hasWindowHistory() ? {
75
+ ...((_ref = window.history.state) !== null && _ref !== void 0 ? _ref : {})
76
+ } : {};
77
+ delete existing.__chaynsHistory;
78
+ return projectToState(rootLayer, existing);
79
+ },
80
+ diffIncomingState: raw => diffIncomingState(rootLayer, raw),
81
+ applyIncomingState: raw => applyStateToTree(rootLayer, raw),
82
+ silentGo: delta => silentGo(delta),
83
+ getCurrentIdx: () => getCurrentIdx(),
84
+ incrementIdx: () => incrementIdx(),
85
+ onCommit: syncNativeHandling,
86
+ applyUrlSegments: () => {
87
+ if (!hasWindowHistory()) return {
88
+ changedLayerIds: new Set()
89
+ };
90
+ const {
91
+ perLayerSegments
92
+ } = parseFromUrl(window.location.pathname, rootLayer);
93
+ const changed = new Set();
94
+ for (const [id, segs] of perLayerSegments) {
95
+ const layer = findChaynsHistoryLayerById(rootLayer, id);
96
+ if (!layer) continue;
97
+ const normalizedSegs = normalizeHistorySegments(segs);
98
+ const prev = layer._getOwnSegments();
99
+ if (!shallowEqualArr(prev, normalizedSegs)) {
100
+ layer._setOwnSegmentsSilent(normalizedSegs);
101
+ changed.add(id);
102
+ }
103
+ }
104
+ return {
105
+ changedLayerIds: changed
106
+ };
107
+ }
108
+ });
109
+ queueRef = queue;
110
+ const existingState = hasWindowHistory() ? window.history.state : null;
111
+ syncCurrentIdxFromState(existingState);
112
+ if (!hasChaynsHistoryState(existingState)) {
113
+ var _opts$segmentCount2, _opts$url;
114
+ const segmentCount = (_opts$segmentCount2 = opts.segmentCount) !== null && _opts$segmentCount2 !== void 0 ? _opts$segmentCount2 : 0;
115
+ if (segmentCount > 0) {
116
+ const pathname = getInitialPathname(opts.url);
117
+ const all = pathname.replace(/^\//, '').split('/').filter(Boolean);
118
+ rootLayer._setBootstrapPool(all.slice(segmentCount));
119
+ } else {
120
+ rootLayer._setBootstrapUrlResolver(() => getInitialPathname(opts.url));
121
+ }
122
+ const rawUrl = (_opts$url = opts.url) !== null && _opts$url !== void 0 ? _opts$url : hasWindowHistory() ? window.location.href : null;
123
+ if (rawUrl) {
124
+ try {
125
+ const base = rawUrl.startsWith('http') ? rawUrl : `http://x${rawUrl.startsWith('/') ? rawUrl : '/' + rawUrl}`;
126
+ const parsed = new URL(base);
127
+ const params = {};
128
+ parsed.searchParams.forEach((v, k) => {
129
+ params[k] = v;
130
+ });
131
+ if (Object.keys(params).length > 0) rootLayer._setOwnParamsSilent(params);
132
+ const hash = parsed.hash.replace(/^#/, '');
133
+ if (hash) rootLayer._setOwnHashSilent(hash);
134
+ } catch {}
135
+ }
136
+ }
137
+ if (hasWindowHistory()) {
138
+ const existing = existingState;
139
+ if (!hasChaynsHistoryState(existing)) {
140
+ const foreign = {
141
+ ...(existing !== null && existing !== void 0 ? existing : {})
142
+ };
143
+ delete foreign.__chaynsHistory;
144
+ const initialState = projectToState(rootLayer, foreign);
145
+ const idx = getCurrentIdx();
146
+ window.history.replaceState({
147
+ ...initialState,
148
+ __chaynsHistory: {
149
+ ...initialState.__chaynsHistory,
150
+ __idx: idx
151
+ }
152
+ }, '', window.location.href);
153
+ } else {
154
+ applyStateToTree(rootLayer, existing);
155
+ if (syncCurrentIdxFromState(existing) === null) {
156
+ const foreign = {
157
+ ...(existing !== null && existing !== void 0 ? existing : {})
158
+ };
159
+ delete foreign.__chaynsHistory;
160
+ const currentState = projectToState(rootLayer, foreign);
161
+ const idx = getCurrentIdx();
162
+ window.history.replaceState({
163
+ ...currentState,
164
+ __chaynsHistory: {
165
+ ...currentState.__chaynsHistory,
166
+ __idx: idx
167
+ }
168
+ }, '', window.location.href);
169
+ }
170
+ }
171
+ blockRegistry.subscribeToChanges(syncNativeHandling);
172
+ window.addEventListener('popstate', event => {
173
+ syncCurrentIdxFromState(event.state);
174
+ if (consumeSilent()) {
175
+ syncNativeHandling();
176
+ return;
177
+ }
178
+ const raw = event.state;
179
+ if (!hasChaynsHistoryState(raw)) {
180
+ syncNativeHandling();
181
+ } else {
182
+ const skipBlockCheck = nativeBackHandler.consumeBypassFlag();
183
+ void queue.enqueue({
184
+ kind: 'popstate',
185
+ rawState: raw,
186
+ skipBlockCheck
187
+ }).finally(syncNativeHandling);
188
+ }
189
+ });
190
+ syncNativeHandling();
191
+ }
192
+ return {
193
+ rootLayer
194
+ };
195
+ }
196
+ let _rootLayerResult = null;
197
+ export function getOrInitRootChaynsHistoryLayer(url, segmentCount) {
198
+ if (!_rootLayerResult) {
199
+ _rootLayerResult = initRootChaynsHistoryLayer({
200
+ url,
201
+ segmentCount
202
+ });
203
+ }
204
+ return _rootLayerResult;
205
+ }
@@ -0,0 +1,7 @@
1
+ export const normalizeHistorySegments = segments => segments.filter(segment => segment.length > 0);
2
+ export const normalizeHistoryRouteInput = route => {
3
+ if (Array.isArray(route)) {
4
+ return normalizeHistorySegments([...route]);
5
+ }
6
+ return route.split('/').filter(Boolean);
7
+ };
@@ -0,0 +1,147 @@
1
+ import { shallowEqualObj } from '../equality';
2
+ const ROOT_KEY = '__chaynsHistory';
3
+ const SCHEMA_VERSION = 1;
4
+ function buildNode(layer) {
5
+ const node = {
6
+ ...layer._getOwnState()
7
+ };
8
+ const params = layer._getOwnParams();
9
+ if (Object.keys(params).length > 0) node.__params = {
10
+ ...params
11
+ };
12
+ const hash = layer._getOwnHash();
13
+ if (hash !== undefined) node.__hash = hash;
14
+ const activeChildId = layer.getActiveChildId();
15
+ if (activeChildId) {
16
+ node.activeChild = activeChildId;
17
+ const child = layer.getChildLayer(activeChildId);
18
+ if (child) {
19
+ node.childState = buildNode(child);
20
+ }
21
+ }
22
+ return node;
23
+ }
24
+ export function projectToState(root, existing = {}) {
25
+ const tree = buildNode(root);
26
+ return {
27
+ ...existing,
28
+ [ROOT_KEY]: {
29
+ v: SCHEMA_VERSION,
30
+ tree
31
+ }
32
+ };
33
+ }
34
+ function applyNode(layer, node) {
35
+ const {
36
+ activeChild,
37
+ childState,
38
+ __params,
39
+ __hash,
40
+ ...ownProps
41
+ } = node;
42
+ layer._setOwnStateSilent(ownProps);
43
+ layer._setOwnParamsSilent(__params !== null && __params !== void 0 ? __params : {});
44
+ layer._setOwnHashSilent('__hash' in node ? __hash : undefined);
45
+ if (activeChild !== undefined) {
46
+ layer._setActiveChildSilent(activeChild);
47
+ if (childState) {
48
+ const child = layer.getChildLayer(activeChild);
49
+ if (child) applyNode(child, childState);
50
+ }
51
+ } else {
52
+ layer._setActiveChildSilent(null);
53
+ }
54
+ }
55
+ export function applyStateToTree(root, raw) {
56
+ const node = extractNode(raw);
57
+ if (!node) return {
58
+ changedLayerIds: new Set()
59
+ };
60
+ const changedLayerIds = new Set();
61
+ applyNodeTracked(root, node, changedLayerIds);
62
+ return {
63
+ changedLayerIds
64
+ };
65
+ }
66
+ export function diffIncomingState(root, raw) {
67
+ const node = extractNode(raw);
68
+ if (!node) return {
69
+ changedLayerIds: new Set()
70
+ };
71
+ const changedLayerIds = new Set();
72
+ diffNodeTracked(root, node, changedLayerIds);
73
+ return {
74
+ changedLayerIds
75
+ };
76
+ }
77
+ function extractNode(raw) {
78
+ if (!raw || typeof raw !== 'object') return null;
79
+ const entry = raw[ROOT_KEY];
80
+ if (!entry || typeof entry !== 'object') return null;
81
+ const {
82
+ tree
83
+ } = entry;
84
+ return tree !== null && tree !== void 0 ? tree : null;
85
+ }
86
+ function applyNodeTracked(layer, node, changed) {
87
+ const {
88
+ activeChild,
89
+ childState,
90
+ __params,
91
+ __hash,
92
+ ...ownProps
93
+ } = node;
94
+ const prevState = layer._getOwnState();
95
+ const prevActiveChild = layer.getActiveChildId();
96
+ const prevParams = layer._getOwnParams();
97
+ const prevHash = layer._getOwnHash();
98
+ const incomingParams = __params !== null && __params !== void 0 ? __params : {};
99
+ const incomingHash = '__hash' in node ? __hash : undefined;
100
+ const ownPropsClean = ownProps;
101
+ const stateChanged = !shallowEqualObj(prevState, ownPropsClean);
102
+ const activeChildChanged = prevActiveChild !== (activeChild !== null && activeChild !== void 0 ? activeChild : null);
103
+ const paramsChanged = !shallowEqualObj(prevParams, incomingParams);
104
+ const hashChanged = prevHash !== incomingHash;
105
+ const child = activeChild ? layer.getChildLayer(activeChild) : undefined;
106
+ layer._setOwnStateSilent(ownPropsClean);
107
+ layer._setActiveChildSilent(activeChild !== null && activeChild !== void 0 ? activeChild : null);
108
+ layer._setOwnParamsSilent(incomingParams);
109
+ layer._setOwnHashSilent(incomingHash);
110
+ if (stateChanged || activeChildChanged || paramsChanged || hashChanged) {
111
+ changed.add(layer.id);
112
+ }
113
+ if (activeChild && childState) {
114
+ if (child) applyNodeTracked(child, childState, changed);
115
+ }
116
+ }
117
+ function diffNodeTracked(layer, node, changed) {
118
+ const {
119
+ activeChild,
120
+ childState,
121
+ __params,
122
+ __hash,
123
+ ...ownProps
124
+ } = node;
125
+ const prevState = layer._getOwnState();
126
+ const prevActiveChild = layer.getActiveChildId();
127
+ const prevParams = layer._getOwnParams();
128
+ const prevHash = layer._getOwnHash();
129
+ const incomingParams = __params !== null && __params !== void 0 ? __params : {};
130
+ const incomingHash = '__hash' in node ? __hash : undefined;
131
+ const ownPropsClean = ownProps;
132
+ const stateChanged = !shallowEqualObj(prevState, ownPropsClean);
133
+ const activeChildChanged = prevActiveChild !== (activeChild !== null && activeChild !== void 0 ? activeChild : null);
134
+ const paramsChanged = !shallowEqualObj(prevParams, incomingParams);
135
+ const hashChanged = prevHash !== incomingHash;
136
+ const child = activeChild ? layer.getChildLayer(activeChild) : undefined;
137
+ if (stateChanged || activeChildChanged || paramsChanged || hashChanged) {
138
+ changed.add(layer.id);
139
+ }
140
+ if (activeChild && childState) {
141
+ if (child) diffNodeTracked(child, childState, changed);
142
+ }
143
+ }
144
+ export { extractNode as _extractNode };
145
+ export function hasChaynsHistoryState(raw) {
146
+ return extractNode(raw) !== null;
147
+ }
@@ -0,0 +1,40 @@
1
+ import { getChaynsHistoryActiveChain } from './layerTree';
2
+ import { normalizeHistorySegments } from './segments';
3
+ export function projectToUrl(root) {
4
+ const chain = getChaynsHistoryActiveChain(root);
5
+ const parts = [];
6
+ const mergedParams = {};
7
+ let hash;
8
+ for (const layer of chain) {
9
+ for (const seg of normalizeHistorySegments(layer._getOwnSegments())) {
10
+ parts.push(seg);
11
+ }
12
+ Object.assign(mergedParams, layer._getOwnParams());
13
+ const layerHash = layer._getOwnHash();
14
+ if (layerHash !== undefined) hash = layerHash;
15
+ }
16
+ let url = '/' + parts.join('/');
17
+ const search = new URLSearchParams(mergedParams).toString();
18
+ if (search) url += '?' + search;
19
+ if (hash) url += '#' + hash;
20
+ return url;
21
+ }
22
+ export function parseFromUrl(url, root) {
23
+ const perLayerSegments = new Map();
24
+ const pathname = url.startsWith('/') ? url.slice(1) : url;
25
+ const all = pathname ? pathname.split('/') : [];
26
+ let offset = 0;
27
+ const chain = getChaynsHistoryActiveChain(root);
28
+ for (const layer of chain) {
29
+ const count = layer.getSegmentCount();
30
+ const slice = all.slice(offset, offset + count);
31
+ while (slice.length < count) slice.push('');
32
+ perLayerSegments.set(layer.id, slice);
33
+ offset += count;
34
+ }
35
+ const pendingSegments = offset < all.length ? all.slice(offset) : [];
36
+ return {
37
+ perLayerSegments,
38
+ pendingSegments
39
+ };
40
+ }
@@ -0,0 +1,3 @@
1
+ export function hasWindowHistory() {
2
+ return typeof window !== 'undefined' && typeof window.history !== 'undefined';
3
+ }
@@ -7,12 +7,12 @@ import { sendMessageToGroup, sendMessageToPage, sendMessageToUser } from '../cal
7
7
  import { DefaultLoginDialogOptions } from '../constants';
8
8
  import { DeviceLanguage } from '../constants/languages';
9
9
  import DialogHandler from '../handler/DialogHandler';
10
- import { addApiListener, dispatchApiEvent, removeApiListener } from '../helper/apiListenerHelper';
10
+ import { addApiListener, dispatchApiEvent, removeApiListener } from '../utils/apiListener';
11
11
  import { AppName, DialogButtonType, DialogType, Environment, Font, Gender, IconType, LoginState, RuntimeEnviroment, TappEvent } from '../types/IChaynsReact';
12
- import invokeAppCall from '../util/appCall';
13
- import { addAppStorageListener, clearAppStorage, isAppStorageAvailable, setAppStorageItem } from '../util/appStorage';
14
- import getDeviceInfo, { getScreenSize } from '../util/deviceHelper';
15
- import { isAppCallSupported } from '../util/is';
12
+ import invokeAppCall from '../utils/appCall';
13
+ import { addAppStorageListener, clearAppStorage, isAppStorageAvailable, setAppStorageItem } from '../utils/appStorage';
14
+ import getDeviceInfo, { getScreenSize } from '../utils/deviceHelper';
15
+ import { isAppCallSupported } from '../utils/is';
16
16
  export class AppWrapper {
17
17
  async loadStyleSettings(siteId) {
18
18
  try {
@@ -83,7 +83,7 @@ export class AppWrapper {
83
83
  runtimeEnvironment: RuntimeEnviroment.App
84
84
  },
85
85
  language: {
86
- site: AppInfo.Language || 'de',
86
+ site: language,
87
87
  translation: null,
88
88
  device: language,
89
89
  active: language
@@ -6,8 +6,9 @@ import getUserInfo from '../calls/getUserInfo';
6
6
  import { sendMessageToGroup, sendMessageToPage, sendMessageToUser } from '../calls/sendMessage';
7
7
  import { addVisibilityChangeListener, removeVisibilityChangeListener } from '../calls/visibilityChangeListener';
8
8
  import DialogHandler from '../handler/DialogHandler';
9
- import { setTappHeight } from '../util/heightHelper';
10
- import { initTransferNestedFunctions } from '../util/transferNestedFunctions';
9
+ import { FrameHistoryLayer } from '../handler/history/FrameHistoryLayer';
10
+ import { setTappHeight } from '../utils/heightHelper';
11
+ import { initTransferNestedFunctions } from '../utils/transferNestedFunctions';
11
12
  export class FrameWrapper {
12
13
  constructor() {
13
14
  _defineProperty(this, "resolve", null);
@@ -15,6 +16,7 @@ export class FrameWrapper {
15
16
  _defineProperty(this, "exposedCustomFunctions", {});
16
17
  _defineProperty(this, "exposedCustomFunctionNames", []);
17
18
  _defineProperty(this, "resizeListener", null);
19
+ _defineProperty(this, "_historyLayer", null);
18
20
  _defineProperty(this, "ready", new Promise(res => {
19
21
  this.resolve = res;
20
22
  }));
@@ -297,6 +299,12 @@ export class FrameWrapper {
297
299
  redirect: async options => {
298
300
  if (!this.initialized) await this.ready;
299
301
  return this.exposedFunctions.redirect(options);
302
+ },
303
+ getHistoryLayer: () => {
304
+ if (!this._historyLayer) {
305
+ throw new Error('[chaynsHistory] No history layer available. Ensure historyLayer prop is set on the parent HostIframe.');
306
+ }
307
+ return this._historyLayer;
300
308
  }
301
309
  });
302
310
  _defineProperty(this, "customFunctions", new Proxy({}, {
@@ -365,6 +373,31 @@ export class FrameWrapper {
365
373
  p[e] = (...args) => this.exposedCustomFunctions[e](...args.map(a => typeof a === 'function' ? comlink.proxy(a) : a));
366
374
  return p;
367
375
  }, {});
376
+ const exposedHistory = exposed.history;
377
+ if (exposedHistory) {
378
+ const initialState = await exposedHistory.getInitialState();
379
+ if (initialState) {
380
+ this._historyLayer = new FrameHistoryLayer({
381
+ setRoute: (route, opts) => exposedHistory.setRoute(route, opts),
382
+ setParams: (params, opts) => exposedHistory.setParams(params, opts),
383
+ setHash: (hash, opts) => exposedHistory.setHash(hash, opts),
384
+ setState: (state, opts) => exposedHistory.setState(state, opts),
385
+ navigate: opts => exposedHistory.navigate(opts),
386
+ setActiveChild: (id, init) => exposedHistory.setActiveChild(id, init),
387
+ setSegmentCount: n => exposedHistory.setSegmentCount(n),
388
+ addBlock: async (callback, opts) => {
389
+ const remoteUnsub = await exposedHistory.addBlock(comlink.proxy(callback), opts);
390
+ return () => void remoteUnsub();
391
+ }
392
+ }, initialState);
393
+ await exposedHistory.addChangeListener(comlink.proxy(e => {
394
+ this._historyLayer._applyAndEmit(e);
395
+ }));
396
+ await exposedHistory.addPopstateListener(comlink.proxy(e => {
397
+ this._historyLayer._applyAndEmit(e);
398
+ }));
399
+ }
400
+ }
368
401
  this.initialized = true;
369
402
  this.resolve(null);
370
403
  setTappHeight(this.functions.setHeight);
@@ -2,6 +2,7 @@ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object
2
2
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
3
3
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
4
4
  import DialogHandler from '../handler/DialogHandler';
5
+ import { getOrInitRootChaynsHistoryLayer } from '../utils/history/rootLayer';
5
6
  import { addVisibilityChangeListener, removeVisibilityChangeListener } from '../calls/visibilityChangeListener';
6
7
  import getUserInfo from '../calls/getUserInfo';
7
8
  import { sendMessageToGroup, sendMessageToPage, sendMessageToUser } from '../calls/sendMessage';
@@ -38,6 +39,7 @@ export class ModuleFederationWrapper {
38
39
  this.functions.createDialog = config => {
39
40
  return new DialogHandler(config, functions.openDialog, functions.closeDialog, functions.dispatchEventToDialogClient, functions.addDialogClientEventListener);
40
41
  };
42
+ this.functions.getHistoryLayer = () => getOrInitRootChaynsHistoryLayer().rootLayer;
41
43
  }
42
44
  async init() {
43
45
  return undefined;
@@ -3,7 +3,7 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
3
3
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
4
4
  import { moduleWrapper } from '../components/moduleWrapper';
5
5
  import { AppFlavor } from '../types/IChaynsReact';
6
- import getDeviceInfo from '../util/deviceHelper';
6
+ import getDeviceInfo from '../utils/deviceHelper';
7
7
  import { AppWrapper } from './AppWrapper';
8
8
  import { FrameWrapper } from './FrameWrapper';
9
9
  import { ModuleFederationWrapper } from './ModuleFederationWrapper';
@@ -74,6 +74,7 @@ class StaticChaynsApi {
74
74
  _defineProperty(this, "addAccessTokenChangeListener", void 0);
75
75
  _defineProperty(this, "removeAccessTokenChangeListener", void 0);
76
76
  _defineProperty(this, "redirect", void 0);
77
+ _defineProperty(this, "getHistoryLayer", void 0);
77
78
  _defineProperty(this, "ready", void 0);
78
79
  _defineProperty(this, "addDataListener", void 0);
79
80
  _defineProperty(this, "_wrapper", void 0);
@@ -227,6 +227,11 @@ export declare const addAnonymousAccount: () => Promise<import("../types/IChayns
227
227
  * @category User functions
228
228
  */
229
229
  export declare const getUser: () => import("../types/IChaynsReact").ChaynsApiUser | undefined;
230
+ /**
231
+ * Returns the innermost currently mounted HistoryLayer. Falls back to the
232
+ * root layer when called outside any HistoryLayerProvider.
233
+ */
234
+ export declare const getChaynsHistoryLayer: () => import("..").ChaynsHistoryLayer | null;
230
235
  export declare const getSite: () => ChaynsApiSite;
231
236
  export declare const getCurrentPage: () => {
232
237
  id: number;
@@ -1,5 +1,6 @@
1
1
  import React, { ReactNode } from 'react';
2
2
  import { ChaynsReactFunctions, ChaynsReactValues, IChaynsReact } from '../types/IChaynsReact';
3
+ import type { ChaynsHistoryLayer } from '../types/history';
3
4
  export type ChaynsProviderProps = {
4
5
  data?: ChaynsReactValues;
5
6
  functions?: ChaynsReactFunctions;
@@ -8,6 +9,26 @@ export type ChaynsProviderProps = {
8
9
  isModule?: boolean;
9
10
  children?: ReactNode;
10
11
  chaynsApiId?: string;
12
+ /**
13
+ * Explicit history layer to provide to the React subtree.
14
+ * When set this layer is used directly and no root layer is auto-initialised.
15
+ * Use this when the parent already owns a layer and wants to scope children to it.
16
+ */
17
+ historyLayer?: ChaynsHistoryLayer;
18
+ /**
19
+ * Initial history configuration for the root layer.
20
+ * Ignored when `layer` is provided explicitly.
21
+ * - `url`: Current page URL — browser defaults to `window.location.pathname`;
22
+ * for SSR pass the request URL (e.g. `req.url` or `router.asPath`).
23
+ * - `segmentCount`: Number of URL path segments this application claims.
24
+ * E.g. `segmentCount: 2` on `/shop/products/detail` → `getLayer().getRoute()` → `['shop', 'products']`.
25
+ */
26
+ history?: {
27
+ url?: string;
28
+ segmentCount?: number;
29
+ };
30
+ segmentCount?: number;
31
+ isHistoryDisabled?: boolean;
11
32
  };
12
33
  declare const ChaynsProvider: React.FC<ChaynsProviderProps>;
13
34
  export default ChaynsProvider;
@@ -1,3 +1 @@
1
- export * from './hydrationContext';
2
1
  export * from './DefaultLoginDialogOptions';
3
- export * from './moduleContext';
@@ -0,0 +1,33 @@
1
+ import React, { type FC, type ReactNode } from 'react';
2
+ import type { ChaynsHistoryLayer } from '../types/history';
3
+ export declare function pushChaynsHistoryLayer(layer: ChaynsHistoryLayer): void;
4
+ export declare function popChaynsHistoryLayer(layer: ChaynsHistoryLayer): void;
5
+ /** Returns the innermost currently mounted ChaynsHistoryLayer, or the root layer as fallback. */
6
+ export declare function getCurrentChaynsHistoryLayer(): ChaynsHistoryLayer | null;
7
+ declare const ChaynsHistoryLayerContext: React.Context<ChaynsHistoryLayer | null>;
8
+ export interface ChaynsHistoryLayerProviderProps {
9
+ layer: ChaynsHistoryLayer;
10
+ children: ReactNode;
11
+ }
12
+ /**
13
+ * Provides a ChaynsHistoryLayer to the React subtree **and** registers it on the
14
+ * module-level layer stack so that `getCurrentChaynsHistoryLayer()` (static / non-React
15
+ * call sites) also sees this layer as the current one.
16
+ *
17
+ * Use `ChaynsHistoryLayerOverrideProvider` instead if you only want to override the
18
+ * React context without affecting static call sites.
19
+ */
20
+ export declare const ChaynsHistoryLayerProvider: FC<ChaynsHistoryLayerProviderProps>;
21
+ /**
22
+ * Overrides the ChaynsHistoryLayer for the React subtree **only** — hooks such as
23
+ * `useChaynsHistoryLayer`, `useChaynsHistoryRoute`, `useChaynsHistoryNavigate`, etc. will resolve to the
24
+ * provided `layer`, but `getCurrentChaynsHistoryLayer()` (the static / non-React accessor
25
+ * that reads from the module-level layer stack) is left unchanged.
26
+ *
27
+ * This is useful when you need to scope history to a specific layer inside a
28
+ * React tree without affecting imperative call sites outside that tree.
29
+ */
30
+ export declare const ChaynsHistoryLayerOverrideProvider: FC<ChaynsHistoryLayerProviderProps>;
31
+ /** Returns the nearest ChaynsHistoryLayer from context, or null if none. */
32
+ export declare function useChaynsHistoryLayerContext(): ChaynsHistoryLayer | null;
33
+ export default ChaynsHistoryLayerContext;
@@ -0,0 +1,3 @@
1
+ export * from './hydrationContext';
2
+ export * from './moduleContext';
3
+ export * from './HistoryLayerContext';