brew-js-react 0.2.4 → 0.2.7
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/dist/brew-js-react.js +104 -98
- package/dist/brew-js-react.js.map +1 -1
- package/dist/brew-js-react.min.js +1 -1
- package/dist/brew-js-react.min.js.map +1 -1
- package/hooks.js +119 -113
- package/include/brew-js/util/path.js +1 -0
- package/mixins/FlyoutMixin.d.ts +1 -1
- package/mixins/FlyoutMixin.js +6 -6
- package/mixins/StatefulMixin.js +6 -6
- package/package.json +2 -2
- package/view.js +225 -233
package/view.js
CHANGED
|
@@ -1,233 +1,225 @@
|
|
|
1
|
-
import React, { useRef } from "react";
|
|
2
|
-
import { useAsync } from "zeta-dom-react";
|
|
3
|
-
import dom from "./include/zeta-dom/dom.js";
|
|
4
|
-
import { notifyAsync } from "./include/zeta-dom/domLock.js";
|
|
5
|
-
import { any,
|
|
6
|
-
import { animateIn, animateOut } from "./include/brew-js/anim.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
var
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
self.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
self
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
var
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export function
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
return
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export function
|
|
211
|
-
var
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
return app.
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export function navigateTo(view, params) {
|
|
228
|
-
return app.navigate(linkTo(view, params));
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
export function redirectTo(view, params) {
|
|
232
|
-
return app.navigate(linkTo(view, params), true);
|
|
233
|
-
}
|
|
1
|
+
import React, { useRef } from "react";
|
|
2
|
+
import { combineRef, useAsync } from "zeta-dom-react";
|
|
3
|
+
import dom from "./include/zeta-dom/dom.js";
|
|
4
|
+
import { notifyAsync } from "./include/zeta-dom/domLock.js";
|
|
5
|
+
import { any, combineFn, defineObservableProperty, definePrototype, each, exclude, executeOnce, extend, grep, isFunction, keys, makeArray, map, noop, pick, randomId, setImmediate, single, watch } from "./include/zeta-dom/util.js";
|
|
6
|
+
import { animateIn, animateOut } from "./include/brew-js/anim.js";
|
|
7
|
+
import { removeQueryAndHash } from "./include/brew-js/util/path.js";
|
|
8
|
+
import { app } from "./app.js";
|
|
9
|
+
import { ViewStateContainer } from "./hooks.js";
|
|
10
|
+
|
|
11
|
+
const root = dom.root;
|
|
12
|
+
const routeMap = new Map();
|
|
13
|
+
const usedParams = {};
|
|
14
|
+
const sortedViews = [];
|
|
15
|
+
const StateContext = React.createContext(Object.freeze({ active: true }));
|
|
16
|
+
|
|
17
|
+
function ViewContainer() {
|
|
18
|
+
React.Component.apply(this, arguments);
|
|
19
|
+
this.stateId = history.state;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
definePrototype(ViewContainer, React.Component, {
|
|
23
|
+
componentDidMount: function () {
|
|
24
|
+
/** @type {any} */
|
|
25
|
+
var self = this;
|
|
26
|
+
self.componentWillUnmount = combineFn(
|
|
27
|
+
watch(app.route, function () {
|
|
28
|
+
self.setActive(self.getViewComponent() === self.currentViewComponent);
|
|
29
|
+
}),
|
|
30
|
+
app.on('beforepageload', function (e) {
|
|
31
|
+
self.waitFor = e.waitFor;
|
|
32
|
+
self.stateId = history.state;
|
|
33
|
+
self.forceUpdate();
|
|
34
|
+
})
|
|
35
|
+
);
|
|
36
|
+
},
|
|
37
|
+
componentDidCatch: function (error) {
|
|
38
|
+
dom.emit('error', this.parentElement || root, { error }, true);
|
|
39
|
+
},
|
|
40
|
+
render: function () {
|
|
41
|
+
/** @type {any} */
|
|
42
|
+
var self = this;
|
|
43
|
+
if (history.state !== self.stateId) {
|
|
44
|
+
return self.lastChild || null;
|
|
45
|
+
}
|
|
46
|
+
var V = self.getViewComponent();
|
|
47
|
+
if (V) {
|
|
48
|
+
// ensure the current path actually corresponds to the matched view
|
|
49
|
+
// when some views are not included in the list of allowed views
|
|
50
|
+
var targetPath = linkTo(V, getCurrentParams(V, true));
|
|
51
|
+
if (targetPath !== removeQueryAndHash(app.path)) {
|
|
52
|
+
app.navigate(targetPath, true);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (V && V !== self.currentViewComponent) {
|
|
56
|
+
var prevElement = self.currentElement;
|
|
57
|
+
if (prevElement) {
|
|
58
|
+
self.setActive(false);
|
|
59
|
+
self.prevView = self.currentView;
|
|
60
|
+
self.currentElement = undefined;
|
|
61
|
+
app.emit('pageleave', prevElement, { pathname: self.currentPath }, true);
|
|
62
|
+
animateOut(prevElement, 'show').then(function () {
|
|
63
|
+
self.prevView = undefined;
|
|
64
|
+
self.forceUpdate();
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
var resolve;
|
|
68
|
+
var promise = new Promise(function (resolve_) {
|
|
69
|
+
resolve = resolve_;
|
|
70
|
+
});
|
|
71
|
+
var state = { view: V };
|
|
72
|
+
var view = React.createElement(StateContext.Provider, { key: routeMap.get(V).id, value: state },
|
|
73
|
+
React.createElement(ViewStateContainer, null,
|
|
74
|
+
React.createElement(V, {
|
|
75
|
+
rootProps: self.props.rootProps,
|
|
76
|
+
onComponentLoaded: executeOnce(function (element) {
|
|
77
|
+
self.currentElement = element;
|
|
78
|
+
self.parentElement = element.parentElement;
|
|
79
|
+
setImmediate(function () {
|
|
80
|
+
resolve();
|
|
81
|
+
animateIn(element, 'show');
|
|
82
|
+
app.emit('pageenter', element, { pathname: app.path }, true);
|
|
83
|
+
});
|
|
84
|
+
})
|
|
85
|
+
})));
|
|
86
|
+
extend(self, {
|
|
87
|
+
currentPath: app.path,
|
|
88
|
+
currentView: view,
|
|
89
|
+
currentViewComponent: V,
|
|
90
|
+
setActive: defineObservableProperty(state, 'active', true, true)
|
|
91
|
+
});
|
|
92
|
+
(self.waitFor || noop)(promise);
|
|
93
|
+
notifyAsync(self.parentElement || root, promise);
|
|
94
|
+
}
|
|
95
|
+
var child = React.createElement(React.Fragment, null, self.prevView, self.currentView);
|
|
96
|
+
self.lastChild = child;
|
|
97
|
+
return child;
|
|
98
|
+
},
|
|
99
|
+
getViewComponent: function () {
|
|
100
|
+
var props = this.props;
|
|
101
|
+
return any(props.views, isViewMatched) || props.defaultView;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
function getCurrentParams(view, includeAll, params) {
|
|
106
|
+
var state = routeMap.get(view);
|
|
107
|
+
if (!state.maxParams) {
|
|
108
|
+
var matchers = exclude(state.matchers, ['remainingSegments']);
|
|
109
|
+
var matched = map(app.routes, function (v) {
|
|
110
|
+
var route = app.parseRoute(v);
|
|
111
|
+
var matched = route.length && !any(matchers, function (v, i) {
|
|
112
|
+
var pos = route.params[i];
|
|
113
|
+
return (v ? !(pos >= 0) : pos < route.minLength) || (!isFunction(v) && !route.match(i, v));
|
|
114
|
+
});
|
|
115
|
+
return matched ? route : null;
|
|
116
|
+
});
|
|
117
|
+
if (matched[1]) {
|
|
118
|
+
matched = grep(matched, function (v) {
|
|
119
|
+
return !single(v.params, function (v, i) {
|
|
120
|
+
return usedParams[i] && !matchers[i];
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (matched[0]) {
|
|
125
|
+
var last = matched.slice(-1)[0];
|
|
126
|
+
state.maxParams = keys(extend.apply(0, [{}].concat(matched.map(function (v) {
|
|
127
|
+
return v.params;
|
|
128
|
+
}))));
|
|
129
|
+
state.minParams = map(last.params, function (v, i) {
|
|
130
|
+
return state.params[i] || v >= last.minLength ? null : i;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return pick(params || app.route, includeAll ? state.maxParams : state.minParams);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function sortViews(a, b) {
|
|
138
|
+
return (routeMap.get(b) || {}).matchCount - (routeMap.get(a) || {}).matchCount;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function matchViewParams(view, route) {
|
|
142
|
+
var params = routeMap.get(view);
|
|
143
|
+
return !!params && !single(params.matchers, function (v, i) {
|
|
144
|
+
var value = route[i] || '';
|
|
145
|
+
return isFunction(v) ? !v(value) : (v || '') !== value;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function useViewContainerState() {
|
|
150
|
+
return React.useContext(StateContext);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function isViewMatched(view) {
|
|
154
|
+
return matchViewParams(view, app.route);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function matchView(path, views) {
|
|
158
|
+
var route = app.route;
|
|
159
|
+
if (typeof path === 'string') {
|
|
160
|
+
route = route.parse(path);
|
|
161
|
+
} else {
|
|
162
|
+
views = path;
|
|
163
|
+
}
|
|
164
|
+
views = views ? makeArray(views).sort(sortViews) : sortedViews;
|
|
165
|
+
return any(views, function (v) {
|
|
166
|
+
return matchViewParams(v, route);
|
|
167
|
+
}) || undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function registerView(factory, routeParams) {
|
|
171
|
+
var Component = function (props) {
|
|
172
|
+
var state = useAsync(factory);
|
|
173
|
+
var ref = useRef();
|
|
174
|
+
if (state[0] || state[1].error) {
|
|
175
|
+
(props.onComponentLoaded || noop)(ref.current);
|
|
176
|
+
}
|
|
177
|
+
return React.createElement('div', extend({}, props.rootProps, {
|
|
178
|
+
ref: combineRef(ref, state[1].elementRef),
|
|
179
|
+
children: state[0] && React.createElement(state[0].default)
|
|
180
|
+
}));
|
|
181
|
+
};
|
|
182
|
+
routeParams = extend({}, routeParams);
|
|
183
|
+
each(routeParams, function (i, v) {
|
|
184
|
+
usedParams[i] = true;
|
|
185
|
+
if (v instanceof RegExp) {
|
|
186
|
+
routeParams[i] = v.test.bind(v);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
routeMap.set(Component, {
|
|
190
|
+
id: randomId(),
|
|
191
|
+
matchCount: keys(routeParams).length,
|
|
192
|
+
matchers: routeParams,
|
|
193
|
+
params: pick(routeParams, function (v) {
|
|
194
|
+
return typeof v === 'string';
|
|
195
|
+
})
|
|
196
|
+
});
|
|
197
|
+
sortedViews.push(Component);
|
|
198
|
+
sortedViews.sort(sortViews);
|
|
199
|
+
return Component;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function renderView() {
|
|
203
|
+
var views = makeArray(arguments);
|
|
204
|
+
var rootProps = isFunction(views[0]) ? {} : views.shift();
|
|
205
|
+
var defaultView = views[0];
|
|
206
|
+
views.sort(sortViews);
|
|
207
|
+
return React.createElement(ViewContainer, { rootProps, views, defaultView });
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function linkTo(view, params) {
|
|
211
|
+
var state = routeMap.get(view);
|
|
212
|
+
if (!state) {
|
|
213
|
+
return '/';
|
|
214
|
+
}
|
|
215
|
+
var newParams = extend(getCurrentParams(view), getCurrentParams(view, true, params), state.params);
|
|
216
|
+
return app.route.getPath(newParams);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function navigateTo(view, params) {
|
|
220
|
+
return app.navigate(linkTo(view, params));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function redirectTo(view, params) {
|
|
224
|
+
return app.navigate(linkTo(view, params), true);
|
|
225
|
+
}
|