native-document 1.0.294 → 1.0.295
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/router/Route.js +1 -1
- package/src/router/RouteGroupHelper.js +9 -3
- package/src/router/Router.js +15 -2
- package/src/router/RouterComponent.js +44 -20
- package/types/router.d.ts +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "native-document",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.295",
|
|
4
4
|
"description": "A reactive JavaScript framework that preserves native DOM simplicity without sacrificing modern features",
|
|
5
5
|
"author": "AfroCodeur <https://github.com/afrocodeur>",
|
|
6
6
|
"license": "MIT",
|
package/src/router/Route.js
CHANGED
|
@@ -47,7 +47,7 @@ export function Route($path, $component, $options = {}) {
|
|
|
47
47
|
const $shouldRebuild = $options.shouldRebuild || false;
|
|
48
48
|
const $paramsValidators = $options.with || {};
|
|
49
49
|
const $layout = $options.layout || null;
|
|
50
|
-
const $layouts = $options.layouts ||
|
|
50
|
+
const $layouts = $options.layouts || [];
|
|
51
51
|
|
|
52
52
|
const $params = {};
|
|
53
53
|
const $paramsNames = [];
|
|
@@ -58,8 +58,14 @@ export const RouteGroupHelper = {
|
|
|
58
58
|
return null;
|
|
59
59
|
},
|
|
60
60
|
layouts($groupTree) {
|
|
61
|
-
return $groupTree
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
return $groupTree.map(g => g.options?.layout).filter(Boolean);
|
|
62
|
+
},
|
|
63
|
+
watches($groupTree) {
|
|
64
|
+
return $groupTree.mpa((g) => {
|
|
65
|
+
if(!g.options?.layout || !g.options?.watch) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return { layout: g.options.layout, watch: g.options.watch };
|
|
69
|
+
}).filter(Boolean);
|
|
64
70
|
},
|
|
65
71
|
};
|
package/src/router/Router.js
CHANGED
|
@@ -25,6 +25,7 @@ export default function Router($options = {}) {
|
|
|
25
25
|
const $groupTree = [];
|
|
26
26
|
const $listeners = [];
|
|
27
27
|
const $currentState = { route: null, params: null, query: null, path: null, hash: null };
|
|
28
|
+
const $layoutWatches = new Map();
|
|
28
29
|
|
|
29
30
|
if($options.mode === 'hash') {
|
|
30
31
|
HashRouter.apply(this, []);
|
|
@@ -54,10 +55,14 @@ export default function Router($options = {}) {
|
|
|
54
55
|
*
|
|
55
56
|
* @param {string} path
|
|
56
57
|
* @param {Function} component
|
|
57
|
-
* @param {{name:?string, middlewares:Function[], shouldRebuild:Boolean, with: Object, layout: Function }} options
|
|
58
|
+
* @param {{name:?string, middlewares:Function[], shouldRebuild:Boolean, with: Object, layout: Function, watch?: string[] }} options
|
|
58
59
|
* @returns {this}
|
|
59
60
|
*/
|
|
60
61
|
this.add = function(path, component, options) {
|
|
62
|
+
if(options?.watch && !options?.layout) {
|
|
63
|
+
DebugManager.warn('Router', `'watch' ignored on route '${path}': requires a 'layout' defined at a group() level`);
|
|
64
|
+
}
|
|
65
|
+
|
|
61
66
|
const route = new Route(RouteGroupHelper.fullPath($groupTree, path), component, {
|
|
62
67
|
...options,
|
|
63
68
|
middlewares: RouteGroupHelper.fullMiddlewares($groupTree, options?.middlewares || []),
|
|
@@ -68,6 +73,7 @@ export default function Router($options = {}) {
|
|
|
68
73
|
...(options?.layout ? [options.layout] : []),
|
|
69
74
|
],
|
|
70
75
|
});
|
|
76
|
+
|
|
71
77
|
$routes.push(route);
|
|
72
78
|
if(route.name()) {
|
|
73
79
|
$routesByName[route.name()] = route;
|
|
@@ -84,6 +90,10 @@ export default function Router($options = {}) {
|
|
|
84
90
|
});
|
|
85
91
|
};
|
|
86
92
|
|
|
93
|
+
this.getLayoutWatches = function(layout) {
|
|
94
|
+
return $layoutWatches.get(layout);
|
|
95
|
+
};
|
|
96
|
+
|
|
87
97
|
/**
|
|
88
98
|
* Groups routes under a common path prefix with shared options.
|
|
89
99
|
*
|
|
@@ -104,7 +114,10 @@ export default function Router($options = {}) {
|
|
|
104
114
|
if(!Validator.isFunction(callback)) {
|
|
105
115
|
throw new RouterError('Callback must be a function');
|
|
106
116
|
}
|
|
107
|
-
$groupTree.push({suffix, options});
|
|
117
|
+
$groupTree.push({ suffix, options });
|
|
118
|
+
if(options.layout && options.watch) {
|
|
119
|
+
$layoutWatches.set(options.layout, options.watch);
|
|
120
|
+
}
|
|
108
121
|
callback();
|
|
109
122
|
$groupTree.pop();
|
|
110
123
|
return this;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Validator from '../core/utils/validator';
|
|
2
2
|
import {Anchor} from '../../elements';
|
|
3
3
|
import {ElementCreator} from '../core/wrappers/ElementCreator';
|
|
4
|
+
import {Observable} from 'native-document';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
*
|
|
@@ -12,7 +13,6 @@ export function RouterComponent(router, container) {
|
|
|
12
13
|
const $cache = new Map();
|
|
13
14
|
const $layoutCache = new WeakMap();
|
|
14
15
|
const $routeInstanceAnchors = new WeakMap();
|
|
15
|
-
let $currentLayout = null;
|
|
16
16
|
|
|
17
17
|
let $lastNodeInserted = null;
|
|
18
18
|
|
|
@@ -42,10 +42,6 @@ export function RouterComponent(router, container) {
|
|
|
42
42
|
const cleanContainer = () => {
|
|
43
43
|
container.nodeValue = '';
|
|
44
44
|
removeLastNodeInserted();
|
|
45
|
-
|
|
46
|
-
if($currentLayout) {
|
|
47
|
-
$currentLayout.remove();
|
|
48
|
-
}
|
|
49
45
|
};
|
|
50
46
|
|
|
51
47
|
const getNodeToInsert = (node) => {
|
|
@@ -56,7 +52,7 @@ export function RouterComponent(router, container) {
|
|
|
56
52
|
return nodeToInsert;
|
|
57
53
|
};
|
|
58
54
|
|
|
59
|
-
const updateContainerByLayout = (layouts, node, route, path) => {
|
|
55
|
+
const updateContainerByLayout = (layouts, node, route, path, routeContext) => {
|
|
60
56
|
|
|
61
57
|
const nodeToInsert = getNodeToInsert(node);
|
|
62
58
|
let matchDepth = 0;
|
|
@@ -69,6 +65,7 @@ export function RouterComponent(router, container) {
|
|
|
69
65
|
removeLastNodeInserted();
|
|
70
66
|
$lastNodeInserted = nodeToInsert;
|
|
71
67
|
$mountedChain[matchDepth - 1]?.anchor?.replaceContent(nodeToInsert);
|
|
68
|
+
updateLayoutParams(routeContext);
|
|
72
69
|
return;
|
|
73
70
|
}
|
|
74
71
|
|
|
@@ -85,21 +82,32 @@ export function RouterComponent(router, container) {
|
|
|
85
82
|
for(let i = layouts.length - 1; i >= matchDepth; i -= 1) {
|
|
86
83
|
const layout = layouts[i];
|
|
87
84
|
let cached = $layoutCache.get(layout);
|
|
85
|
+
let $watches = null;
|
|
88
86
|
if(!cached) {
|
|
87
|
+
const watches = router.getLayoutWatches(layout);
|
|
88
|
+
if(watches?.length) {
|
|
89
|
+
const watchesSource = {};
|
|
90
|
+
for(const name of watches) {
|
|
91
|
+
watchesSource[name] = routeContext.params[name];
|
|
92
|
+
}
|
|
93
|
+
$watches = Observable.object(watchesSource)
|
|
94
|
+
|
|
95
|
+
}
|
|
89
96
|
const anchor = getNodeAnchorForLayout(slot, `${path}:layout:${i}`);
|
|
90
|
-
const element = ElementCreator.getChild(layout(anchor));
|
|
91
|
-
cached = { element, anchor };
|
|
97
|
+
const element = ElementCreator.getChild(layout(anchor, { params: $watches }));
|
|
98
|
+
cached = { element, anchor, $watches };
|
|
92
99
|
$layoutCache.set(layout, cached);
|
|
93
100
|
}
|
|
94
101
|
else {
|
|
95
102
|
cached.anchor.replaceContent(slot);
|
|
96
103
|
}
|
|
97
104
|
|
|
98
|
-
newLayers.unshift({ layoutFn: layout, anchor: cached.anchor, element: cached.element });
|
|
105
|
+
newLayers.unshift({ layoutFn: layout, anchor: cached.anchor, element: cached.element, $watches: cached.$watches });
|
|
99
106
|
slot = cached.element;
|
|
100
107
|
}
|
|
101
108
|
|
|
102
109
|
$mountedChain = [...$mountedChainKeep, ...newLayers];
|
|
110
|
+
updateLayoutParams(routeContext);
|
|
103
111
|
|
|
104
112
|
if (matchDepth === 0) {
|
|
105
113
|
container.appendChild(newLayers[0].element);
|
|
@@ -109,12 +117,25 @@ export function RouterComponent(router, container) {
|
|
|
109
117
|
|
|
110
118
|
};
|
|
111
119
|
|
|
112
|
-
const
|
|
113
|
-
|
|
120
|
+
const updateLayoutParams = function(routeContext) {
|
|
121
|
+
for(let i = 0; i < $mountedChain.length; i++) {
|
|
122
|
+
const layer = $mountedChain[i];
|
|
123
|
+
if(!layer.$watches) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const watches = router.getLayoutWatches(layer.layoutFn);
|
|
127
|
+
|
|
128
|
+
for(const name of watches) {
|
|
129
|
+
layer.$watches[name]?.set(routeContext.params[name]);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
114
133
|
|
|
134
|
+
const updateContainer = function(node, route, path, routeContext) {
|
|
135
|
+
const layouts = route.layouts();
|
|
115
136
|
|
|
116
137
|
if(layouts.length) {
|
|
117
|
-
updateContainerByLayout(layouts, node, route, path);
|
|
138
|
+
updateContainerByLayout(layouts, node, route, path, routeContext);
|
|
118
139
|
return;
|
|
119
140
|
}
|
|
120
141
|
const nodeToInsert = getNodeToInsert(node);
|
|
@@ -135,9 +156,11 @@ export function RouterComponent(router, container) {
|
|
|
135
156
|
$lifecycles.get($currentPath)?.onLeave?.();
|
|
136
157
|
}
|
|
137
158
|
|
|
159
|
+
|
|
160
|
+
|
|
138
161
|
if($cache.has(path)) {
|
|
139
162
|
const cacheNode = $cache.get(path);
|
|
140
|
-
updateContainer(cacheNode, route);
|
|
163
|
+
updateContainer(cacheNode, route, path, { query, params });
|
|
141
164
|
|
|
142
165
|
$lifecycles.get(path)?.onEnter?.(params, query);
|
|
143
166
|
$currentPath = path;
|
|
@@ -145,19 +168,20 @@ export function RouterComponent(router, container) {
|
|
|
145
168
|
return;
|
|
146
169
|
}
|
|
147
170
|
const pathLifecycles = {};
|
|
171
|
+
const routeContext = {
|
|
172
|
+
params,
|
|
173
|
+
query,
|
|
174
|
+
onEnter: (cb) => { pathLifecycles.onEnter = cb; },
|
|
175
|
+
onLeave: (cb) => { pathLifecycles.onLeave = cb; },
|
|
176
|
+
};
|
|
148
177
|
$lifecycles.set(path, pathLifecycles);
|
|
149
178
|
|
|
150
179
|
|
|
151
180
|
|
|
152
181
|
const Component = route.component();
|
|
153
|
-
const node = Component(
|
|
154
|
-
params,
|
|
155
|
-
query,
|
|
156
|
-
onEnter: (cb) => { pathLifecycles.onEnter = cb; },
|
|
157
|
-
onLeave: (cb) => { pathLifecycles.onLeave = cb; },
|
|
158
|
-
});
|
|
182
|
+
const node = Component(routeContext);
|
|
159
183
|
$cache.set(path, node);
|
|
160
|
-
updateContainer(node, route, path);
|
|
184
|
+
updateContainer(node, route, path, routeContext);
|
|
161
185
|
|
|
162
186
|
pathLifecycles.onEnter?.(params, query);
|
|
163
187
|
$currentPath = path;
|
package/types/router.d.ts
CHANGED
|
@@ -44,7 +44,8 @@ export interface Router {
|
|
|
44
44
|
middlewares?: Function[];
|
|
45
45
|
shouldRebuild?: boolean;
|
|
46
46
|
with?: Record<string, string>;
|
|
47
|
-
layout?: (children: ValidChild) => ValidChild
|
|
47
|
+
layout?: (children: ValidChild) => ValidChild;
|
|
48
|
+
watch?: string[]
|
|
48
49
|
}): this;
|
|
49
50
|
notFound(page: (context: RouteContext) => HTMLElement | DocumentFragment): void;
|
|
50
51
|
|