brew-js-react 0.5.4 → 0.5.6

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/hooks.js CHANGED
@@ -1,7 +1,9 @@
1
- import { createElement, useEffect, useRef, useState } from "react";
2
- import { ViewStateProvider, useObservableProperty, useUpdateTrigger } from "zeta-dom-react";
3
- import { definePrototype, delay, each, extend, kv, setImmediateOnce, throwNotFunction, watch } from "zeta-dom/util";
1
+ import { createElement, useEffect, useMemo, useRef, useState } from "react";
2
+ import { ViewStateProvider, useMemoizedFunction, useObservableProperty, useUpdateTrigger } from "zeta-dom-react";
3
+ import { catchAsync, definePrototype, delay, each, equal, extend, freeze, isFunction, isPlainObject, keys, kv, mapObject, throwNotFunction } from "zeta-dom/util";
4
4
  import { ZetaEventContainer } from "zeta-dom/events";
5
+ import { getQueryParam, setQueryParam } from "brew-js/util/common";
6
+ import { parsePath } from "brew-js/util/path";
5
7
  import { app } from "./app.js";
6
8
  import { useViewContext } from "./view.js";
7
9
 
@@ -81,34 +83,23 @@ export function useAppReadyState() {
81
83
  export function useRouteParam(name, defaultValue) {
82
84
  const container = useViewContext();
83
85
  const params = container.page.params;
84
- const route = app.route;
85
86
  const value = params[name] || '';
86
87
  const ref = useRef(value);
87
88
  const forceUpdate = useUpdateTrigger();
88
89
  useEffect(function () {
89
90
  var setValue = function () {
90
- var current = route[name] || '';
91
+ var current = container.page.params[name] || '';
91
92
  if (current !== ref.current) {
92
- if (container.active) {
93
- ref.current = current;
94
- forceUpdate();
95
- } else {
96
- watch(container, 'active', setValue);
97
- }
93
+ forceUpdate();
98
94
  }
99
95
  };
100
96
  // route parameter might be changed after state initialization and before useEffect hook is called
101
97
  setValue();
102
- if (name in route) {
103
- return route.watch(name, function () {
104
- setImmediateOnce(setValue);
105
- });
106
- }
107
- console.error('Route parameter ' + name + ' does not exist');
108
- }, [name, defaultValue]);
98
+ return container.on('pagechange', setValue);
99
+ }, [name]);
109
100
  ref.current = value;
110
101
  if (defaultValue && container.active && (!value || (name === 'remainingSegments' && value === '/'))) {
111
- app.navigate(route.getPath(extend({}, params, kv(name, defaultValue))), true);
102
+ app.navigate(app.route.getPath(extend({}, params, kv(name, defaultValue))), true);
112
103
  }
113
104
  return value;
114
105
  }
@@ -130,6 +121,59 @@ export function useRouteState(key, defaultValue, snapshotOnUpdate) {
130
121
  return state;
131
122
  }
132
123
 
124
+ export function useQueryParam(key, value, snapshotOnUpdate) {
125
+ if (isPlainObject(key)) {
126
+ snapshotOnUpdate = value;
127
+ value = key;
128
+ key = false;
129
+ }
130
+ var container = useViewContext();
131
+ var getParams = function () {
132
+ return mapObject(key === false ? value : kv(key, value), function (v, i) {
133
+ return getQueryParam(i, app.path) || v || '';
134
+ });
135
+ };
136
+ var state = useState([]);
137
+ useMemo(function () {
138
+ state[0].splice(0, 2, getParams());
139
+ }, [key]);
140
+ var current = state[0][0];
141
+ var trackChanges = function (values) {
142
+ if (!equal(values, current)) {
143
+ extend(current, values);
144
+ state[1]([current]);
145
+ }
146
+ };
147
+ var setParams = useMemoizedFunction(function (values) {
148
+ if (key !== false) {
149
+ values = kv(key, isFunction(values) ? values(current[key]) : values);
150
+ } else if (isFunction(values)) {
151
+ values = values(extend({}, current));
152
+ }
153
+ if (container.active) {
154
+ var url = parsePath(app.path);
155
+ var search = keys(values).reduce(function (v, i) {
156
+ return values[i] !== current[i] ? setQueryParam(i, values[i] || null, v) : v;
157
+ }, url.search);
158
+ if (search !== url.search) {
159
+ if (snapshotOnUpdate) {
160
+ app.snapshot();
161
+ }
162
+ catchAsync(app.navigate(search + url.hash, true));
163
+ trackChanges(getParams());
164
+ }
165
+ }
166
+ });
167
+ useEffect(function () {
168
+ return app.watch('path', function () {
169
+ if (container.active) {
170
+ trackChanges(getParams());
171
+ }
172
+ });
173
+ }, [key]);
174
+ return [key !== false ? current[key] : (state[0][1] || (state[0][1] = freeze(extend({}, current)))), setParams];
175
+ }
176
+
133
177
  export function ViewStateContainer(props) {
134
178
  const cache = useState({})[0];
135
179
  const container = useViewContextWithEffect(function (cur) {
package/mixin.js CHANGED
@@ -27,15 +27,15 @@ function createUseFunction(ctor) {
27
27
  };
28
28
  }
29
29
 
30
- export const useAnimateMixin = createUseFunction(AnimateMixin);
31
- export const useAnimateSequenceMixin = createUseFunction(AnimateSequenceMixin);
32
- export const useClassNameToggleMixin = createUseFunction(ClassNameToggleMixin);
33
- export const useFlyoutMixin = createUseFunction(FlyoutMixin);
34
- export const useFocusStateMixin = createUseFunction(FocusStateMixin);
35
- export const useLoadingStateMixin = createUseFunction(LoadingStateMixin);
36
- export const useScrollableMixin = createUseFunction(ScrollableMixin);
37
- export const useScrollIntoViewMixin = createUseFunction(ScrollIntoViewMixin);
38
- export const useUnmanagedClassNameMixin = createUseFunction(UnmanagedClassNameMixin);
30
+ export const useAnimateMixin = /*#__PURE__*/ createUseFunction(AnimateMixin);
31
+ export const useAnimateSequenceMixin = /*#__PURE__*/ createUseFunction(AnimateSequenceMixin);
32
+ export const useClassNameToggleMixin = /*#__PURE__*/ createUseFunction(ClassNameToggleMixin);
33
+ export const useFlyoutMixin = /*#__PURE__*/ createUseFunction(FlyoutMixin);
34
+ export const useFocusStateMixin = /*#__PURE__*/ createUseFunction(FocusStateMixin);
35
+ export const useLoadingStateMixin = /*#__PURE__*/ createUseFunction(LoadingStateMixin);
36
+ export const useScrollableMixin = /*#__PURE__*/ createUseFunction(ScrollableMixin);
37
+ export const useScrollIntoViewMixin = /*#__PURE__*/ createUseFunction(ScrollIntoViewMixin);
38
+ export const useUnmanagedClassNameMixin = /*#__PURE__*/ createUseFunction(UnmanagedClassNameMixin);
39
39
 
40
40
  export function useMixin(ctor) {
41
41
  return useSingleton(function () {
@@ -1,5 +1,5 @@
1
1
  import { definePrototype, extend, makeArray, pick } from "zeta-dom/util";
2
- import { closeFlyout, isFlyoutOpen, openFlyout } from "brew-js/domAction";
2
+ import { closeFlyout, openFlyout } from "brew-js/domAction";
3
3
  import { app } from "../app.js";
4
4
  import ClassNameMixin from "./ClassNameMixin.js";
5
5
  import FlyoutToggleMixin from "./FlyoutToggleMixin.js";
@@ -57,11 +57,7 @@ definePrototype(FlyoutMixin, ClassNameMixin, {
57
57
  });
58
58
  },
59
59
  open: function (value, source) {
60
- var element = this.elements()[0];
61
- if (!isFlyoutOpen(element)) {
62
- valueMap.set(element, value);
63
- }
64
- return openFlyout(element, source, this.getOptions());
60
+ return openFlyout(this.elements()[0], value, source, this.getOptions());
65
61
  },
66
62
  close: function (value) {
67
63
  return closeFlyout(this.elements()[0], value);
@@ -84,6 +80,17 @@ definePrototype(FlyoutMixin, ClassNameMixin, {
84
80
  var self = this;
85
81
  FlyoutMixinSuper.initElement.call(self, element, state);
86
82
  self.onDispose(app.on(element, {
83
+ flyoutshow: function (e) {
84
+ valueMap.set(element, e.data);
85
+ self.isFlyoutOpened = true;
86
+ self.visible = true;
87
+ },
88
+ flyoutclose: function () {
89
+ self.isFlyoutOpened = false;
90
+ },
91
+ flyouthide: function () {
92
+ self.visible = false;
93
+ },
87
94
  animationstart: function () {
88
95
  self.animating = true;
89
96
  },
@@ -91,14 +98,5 @@ definePrototype(FlyoutMixin, ClassNameMixin, {
91
98
  self.animating = false;
92
99
  },
93
100
  }, true));
94
- },
95
- onClassNameUpdated: function (element, prevState, state) {
96
- var self = this;
97
- var isFlyoutOpened = isFlyoutOpen(element);
98
- if (!isFlyoutOpened) {
99
- valueMap.delete(element);
100
- }
101
- self.visible = state.open;
102
- self.isFlyoutOpened = isFlyoutOpened;
103
101
  }
104
102
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brew-js-react",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -13,7 +13,7 @@
13
13
  "repository": "github:misonou/brew-js-react",
14
14
  "dependencies": {
15
15
  "@misonou/react-dom-client": "^1.1.1",
16
- "brew-js": ">=0.6.2",
16
+ "brew-js": ">=0.6.5",
17
17
  "waterpipe": "^2.5.0",
18
18
  "zeta-dom": ">=0.4.10",
19
19
  "zeta-dom-react": ">=0.4.14"
@@ -27,7 +27,7 @@
27
27
  "@babel/preset-env": "^7.16.11",
28
28
  "@babel/preset-react": "^7.16.7",
29
29
  "@jest/globals": "^26.6.2",
30
- "@misonou/build-utils": "^1.1.2",
30
+ "@misonou/build-utils": "^1.1.3",
31
31
  "@misonou/test-utils": "^1.0.3",
32
32
  "@testing-library/dom": "^8.11.3",
33
33
  "@testing-library/react": "^12.1.2",
package/view.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ /// <reference path="./brew.d.ts" />
2
+
1
3
  import { useRouteState } from "./hooks";
2
4
 
3
5
  export type ViewComponentRootProps = React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
@@ -16,14 +18,35 @@ export interface ViewContextEventMap {
16
18
  }
17
19
 
18
20
  export interface ViewContext extends Zeta.ZetaEventDispatcher<ViewContextEventMap, ViewContext> {
21
+ /**
22
+ * Gets the parent view context, or `null` if there is no parent context.
23
+ */
24
+ readonly parent: ViewContext | null;
25
+ /**
26
+ * Gets the HTML element associated with this view.
27
+ */
19
28
  readonly container: HTMLElement;
29
+ /**
30
+ * Gets the rendered view component.
31
+ */
20
32
  readonly view: ViewComponent<any>;
33
+ /**
34
+ * Gets whether the view is active.
35
+ *
36
+ * A rendered view becomes inactive if the view will be replaced by another view, or parent container will be unmounted.
37
+ * It may also be temporarily inactive during navigation.
38
+ */
21
39
  readonly active: boolean;
22
40
  /**
23
41
  * Gets information of current page that rendered the view.
24
42
  * Unlike {@link Brew.WithRouter.page}, it will not change when user has navigated away and the current view is going to unmount.
25
43
  */
26
44
  readonly page: Brew.PageInfo;
45
+
46
+ /**
47
+ * Gets view contexts rendered under this view container.
48
+ */
49
+ getChildren(): ViewContext[];
27
50
  }
28
51
 
29
52
  export interface ViewProps<S = {}> {
@@ -97,6 +120,12 @@ export function registerErrorView(component: React.ComponentType<ErrorViewProps>
97
120
  */
98
121
  export function isViewMatched(view: ViewComponent<any>): boolean;
99
122
 
123
+ /**
124
+ * Returns whether a registered view component is currently being rendered.
125
+ * @param view A view component returned from {@link registerView}.
126
+ */
127
+ export function isViewRendered(view: ViewComponent<any>): boolean;
128
+
100
129
  /**
101
130
  * Gets the view component that matches the current path within all registered views.
102
131
  * However it does not imply if the view is in fact being rendered.
@@ -110,6 +139,13 @@ export function matchView(): ViewComponent<any> | undefined;
110
139
  */
111
140
  export function matchView(views: ViewComponent<any>[]): ViewComponent<any> | undefined;
112
141
 
142
+ /**
143
+ * Gets the view component that matches the current path within the given set of views.
144
+ * However it does not imply if the view is in fact being rendered.
145
+ * @param views A list of view components.
146
+ */
147
+ export function matchView(...views: ViewComponent<any>[]): ViewComponent<any> | undefined;
148
+
113
149
  /**
114
150
  * Gets the view component that matches the specified path.
115
151
  * @param path A valid path that could navigate to.
@@ -123,6 +159,13 @@ export function matchView(path: string): ViewComponent<any> | undefined;
123
159
  */
124
160
  export function matchView(path: string, views: ViewComponent<any>[]): ViewComponent<any> | undefined;
125
161
 
162
+ /**
163
+ * Gets the view component that matches the specified path, within the given set of views.
164
+ * @param path A valid path that could navigate to.
165
+ * @param views A list of view components.
166
+ */
167
+ export function matchView(path: string, ...views: ViewComponent<any>[]): ViewComponent<any> | undefined;
168
+
126
169
  /**
127
170
  * Renders view by matching current route state against registered route parameters of each supplied views.
128
171
  * @param args A list of view components created by {@link registerView}.
package/view.js CHANGED
@@ -3,7 +3,7 @@ import { useAsync } from "zeta-dom-react";
3
3
  import dom from "zeta-dom/dom";
4
4
  import { notifyAsync } from "zeta-dom/domLock";
5
5
  import { ZetaEventContainer } from "zeta-dom/events";
6
- import { any, arrRemove, catchAsync, combineFn, createPrivateStore, defineObservableProperty, defineOwnProperty, definePrototype, each, exclude, executeOnce, extend, freeze, grep, isFunction, isThenable, isUndefinedOrNull, keys, makeArray, map, noop, pick, randomId, resolveAll, setImmediate, single, throwNotFunction, watch } from "zeta-dom/util";
6
+ import { any, arrRemove, catchAsync, createPrivateStore, defineObservableProperty, defineOwnProperty, definePrototype, each, exclude, executeOnce, extend, freeze, grep, isArray, isFunction, isThenable, isUndefinedOrNull, keys, makeArray, map, noop, pick, randomId, resolveAll, setImmediate, single, throwNotFunction, watch } from "zeta-dom/util";
7
7
  import { animateIn, animateOut } from "brew-js/anim";
8
8
  import { removeQueryAndHash } from "brew-js/util/path";
9
9
  import { app, onAppInit } from "./app.js";
@@ -15,7 +15,7 @@ const routeMap = new Map();
15
15
  const usedParams = {};
16
16
  const sortedViews = [];
17
17
  const emitter = new ZetaEventContainer();
18
- const rootContext = freeze(extend(new ViewContext(null, null), { container: root }));
18
+ const rootContext = freeze(extend(new ViewContext(), { container: root }));
19
19
  const rootState = _(rootContext);
20
20
  const StateContext = React.createContext(rootContext);
21
21
 
@@ -48,13 +48,13 @@ onAppInit(function () {
48
48
  });
49
49
  });
50
50
 
51
- function ViewContext(view, page) {
51
+ function ViewContext(view, page, parent) {
52
52
  var self = this;
53
- watch(self, true);
54
- defineOwnProperty(self, 'view', view, true);
53
+ defineOwnProperty(self, 'view', view || null, true);
54
+ defineOwnProperty(self, 'parent', parent || null, true);
55
55
  _(self, {
56
56
  children: [],
57
- setPage: defineObservableProperty(self, 'page', page, true),
57
+ setPage: defineObservableProperty(self, 'page', page || null, true),
58
58
  setActive: defineObservableProperty(self, 'active', !!page, true)
59
59
  });
60
60
  watch(self, 'page', function (page, previousPage) {
@@ -63,6 +63,11 @@ function ViewContext(view, page) {
63
63
  }
64
64
 
65
65
  definePrototype(ViewContext, {
66
+ getChildren: function () {
67
+ return map(_(this).children, function (v) {
68
+ return v.currentState;
69
+ });
70
+ },
66
71
  on: function (event, handler) {
67
72
  return emitter.add(this, event, handler);
68
73
  }
@@ -85,6 +90,8 @@ definePrototype(ErrorBoundary, React.Component, {
85
90
  setImmediate(function () {
86
91
  dom.emit('error', self.context.container, { error }, true);
87
92
  });
93
+ // ensure promise sent to beforepageload event is resolved
94
+ self.props.onComponentLoaded();
88
95
  }
89
96
  },
90
97
  render: function () {
@@ -111,18 +118,25 @@ function ViewContainer() {
111
118
  ViewContainer.contextType = StateContext;
112
119
 
113
120
  definePrototype(ViewContainer, React.Component, {
121
+ setActive: noop,
114
122
  componentDidMount: function () {
115
123
  var self = this;
116
124
  var parent = _(self.context).children;
125
+ var unwatch = watch(app.route, function () {
126
+ self.setActive(self.getViewComponent() === self.currentViewComponent);
127
+ });
128
+ self.componentWillUnmount = function () {
129
+ self.setActive(false);
130
+ arrRemove(parent, self);
131
+ unwatch();
132
+ setImmediate(function () {
133
+ if (self.unmountView && !self.currentState.active) {
134
+ self.unmountView();
135
+ }
136
+ });
137
+ };
117
138
  parent.push(self);
118
- self.componentWillUnmount = combineFn(
119
- watch(app.route, function () {
120
- (self.setActive || noop)(self.getViewComponent() === self.currentViewComponent);
121
- }),
122
- function () {
123
- arrRemove(parent, self);
124
- }
125
- );
139
+ self.setActive(true);
126
140
  },
127
141
  render: function () {
128
142
  /** @type {any} */
@@ -140,40 +154,39 @@ definePrototype(ViewContainer, React.Component, {
140
154
  if (V && (viewChanged || !(self.children || '')[0])) {
141
155
  // ensure the current path actually corresponds to the matched view
142
156
  // when some views are not included in the list of allowed views
143
- var targetPath = resolvePath(V, getCurrentParams(V, true));
157
+ var targetPath = resolvePath(V, app.route);
144
158
  if (targetPath !== removeQueryAndHash(app.path)) {
145
159
  app.navigate(targetPath, true);
146
160
  return;
147
161
  }
148
162
  }
149
163
  if (V && viewChanged) {
150
- var prevElement = self.currentElement;
151
- if (prevElement) {
152
- self.setActive(false);
153
- self.prevView = self.currentView;
154
- self.currentElement = undefined;
155
- app.emit('pageleave', prevElement, { pathname: self.currentPath }, true);
156
- animateOut(prevElement, 'show').then(function () {
157
- self.prevView = undefined;
158
- self.forceUpdate();
159
- });
160
- }
161
- (self.cancelPrevious || noop)();
164
+ (self.unmountView || noop)(true);
162
165
 
166
+ var state = new ViewContext(V, app.page, self.context);
163
167
  var onComponentLoaded;
164
168
  var promise = new Promise(function (resolve) {
165
169
  onComponentLoaded = resolve;
166
170
  });
171
+ var unmountView = onComponentLoaded;
167
172
  var initElement = executeOnce(function (element) {
168
- self.currentElement = element;
169
173
  state.container = element;
170
174
  promise.then(function () {
171
- animateIn(element, 'show', '[brew-view]', true);
172
- app.emit('pageenter', element, { pathname: app.path }, true);
175
+ if (self.currentState === state) {
176
+ unmountView = function () {
177
+ self.prevView = self.currentView;
178
+ app.emit('pageleave', element, { pathname: state.page.path, view: V }, true);
179
+ animateOut(element, 'show').then(function () {
180
+ self.prevView = undefined;
181
+ self.forceUpdate();
182
+ });
183
+ };
184
+ animateIn(element, 'show', '[brew-view]', true);
185
+ app.emit('pageenter', element, { pathname: state.page.path, view: V }, true);
186
+ }
173
187
  });
174
188
  notifyAsync(element, promise);
175
189
  });
176
- var state = new ViewContext(V, app.page);
177
190
  var viewProps = freeze({
178
191
  navigationType: event.navigationType,
179
192
  viewContext: state,
@@ -184,11 +197,16 @@ definePrototype(ViewContainer, React.Component, {
184
197
  React.createElement('div', extend({}, self.props.rootProps, { ref: initElement, 'brew-view': '' }),
185
198
  React.createElement(ErrorBoundary, { onComponentLoaded, viewProps }))));
186
199
  extend(self, _(state), {
187
- cancelPrevious: onComponentLoaded,
188
- currentPath: app.path,
200
+ currentState: state,
189
201
  currentView: view,
190
- currentViewComponent: V
202
+ currentViewComponent: V,
203
+ unmountView: executeOnce(function () {
204
+ self.setActive(false);
205
+ routeMap.get(V).rendered--;
206
+ unmountView();
207
+ })
191
208
  });
209
+ routeMap.get(V).rendered++;
192
210
  (event.waitFor || noop)(promise);
193
211
  }
194
212
  (self.setPage || noop)(app.page);
@@ -199,7 +217,7 @@ definePrototype(ViewContainer, React.Component, {
199
217
  }
200
218
  });
201
219
 
202
- function getCurrentParams(view, includeAll, params) {
220
+ function getCurrentParams(view, params) {
203
221
  var state = routeMap.get(view);
204
222
  if (!state.maxParams) {
205
223
  var matchers = exclude(state.matchers, ['remainingSegments']);
@@ -228,7 +246,7 @@ function getCurrentParams(view, includeAll, params) {
228
246
  });
229
247
  }
230
248
  }
231
- return pick(params || app.route, includeAll ? state.maxParams : state.minParams);
249
+ return extend(pick(app.route, state.minParams), params && pick(params, state.maxParams), state.params);
232
250
  }
233
251
 
234
252
  function sortViews(a, b) {
@@ -262,11 +280,14 @@ function createViewComponent(factory) {
262
280
  return React.createElement(s.default, viewProps);
263
281
  });
264
282
  }, !!promise)[1];
265
- if (!promise || !state.loading) {
266
- props.onComponentLoaded();
267
- if (state.error) {
268
- throw state.error;
283
+ var loaded = !promise || !state.loading;
284
+ React.useEffect(function () {
285
+ if (loaded) {
286
+ setImmediate(props.onComponentLoaded);
269
287
  }
288
+ }, [loaded]);
289
+ if (state.error) {
290
+ throw state.error;
270
291
  }
271
292
  return children || state.value || React.createElement(React.Fragment);
272
293
  };
@@ -280,14 +301,17 @@ export function isViewMatched(view) {
280
301
  return matchViewParams(view, app.route);
281
302
  }
282
303
 
283
- export function matchView(path, views) {
304
+ export function isViewRendered(view) {
305
+ return !!(routeMap.get(view) || '').rendered;
306
+ }
307
+
308
+ export function matchView() {
309
+ var views = makeArray(arguments);
284
310
  var route = app.route;
285
- if (typeof path === 'string') {
286
- route = route.parse(path);
287
- } else {
288
- views = path;
311
+ if (typeof views[0] === 'string') {
312
+ route = route.parse(views.shift());
289
313
  }
290
- views = views ? makeArray(views).sort(sortViews) : sortedViews;
314
+ views = views[0] ? (isArray(views[0]) ? makeArray(views[0]) : views).sort(sortViews) : sortedViews;
291
315
  return any(views, function (v) {
292
316
  return matchViewParams(v, route);
293
317
  }) || undefined;
@@ -304,6 +328,7 @@ export function registerView(factory, routeParams) {
304
328
  });
305
329
  routeMap.set(Component, {
306
330
  id: randomId(),
331
+ rendered: 0,
307
332
  matchCount: keys(routeParams).length,
308
333
  matchers: routeParams,
309
334
  params: pick(routeParams, function (v) {
@@ -333,12 +358,10 @@ export function renderView() {
333
358
  }
334
359
 
335
360
  export function resolvePath(view, params) {
336
- var state = routeMap.get(view);
337
- if (!state) {
361
+ if (!routeMap.has(view)) {
338
362
  return '/';
339
363
  }
340
- var newParams = extend(getCurrentParams(view), getCurrentParams(view, true, params || {}), state.params);
341
- return app.route.getPath(newParams);
364
+ return app.route.getPath(getCurrentParams(view, params));
342
365
  }
343
366
 
344
367
  export function linkTo(view, params) {