brew-js-react 0.5.7 → 0.6.0
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/README.md +1 -1
- package/dialog.d.ts +1 -1
- package/dialog.js +5 -7
- package/dist/brew-js-react.js +129 -100
- package/dist/brew-js-react.js.map +1 -1
- package/dist/brew-js-react.min.js +2 -2
- package/dist/brew-js-react.min.js.map +1 -1
- package/hooks.js +16 -23
- package/mixins/AnimateSequenceMixin.js +2 -2
- package/mixins/ClassNameMixin.js +3 -8
- package/mixins/FlyoutMixin.d.ts +4 -0
- package/mixins/FlyoutMixin.js +12 -7
- package/mixins/FlyoutToggleMixin.js +1 -1
- package/mixins/FocusStateMixin.js +1 -1
- package/mixins/LoadingStateMixin.js +1 -1
- package/mixins/ScrollableMixin.d.ts +8 -0
- package/mixins/ScrollableMixin.js +13 -3
- package/mixins/StatefulMixin.d.ts +9 -1
- package/mixins/StatefulMixin.js +41 -18
- package/package.json +3 -3
- package/view.js +34 -26
package/hooks.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createElement, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
-
import { ViewStateProvider, useMemoizedFunction, useObservableProperty,
|
|
2
|
+
import { ViewStateProvider, useMemoizedFunction, useObservableProperty, useValueTrigger } from "zeta-dom-react";
|
|
3
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
5
|
import { getQueryParam, setQueryParam } from "brew-js/util/common";
|
|
@@ -84,20 +84,15 @@ export function useRouteParam(name, defaultValue) {
|
|
|
84
84
|
const container = useViewContext();
|
|
85
85
|
const params = container.page.params;
|
|
86
86
|
const value = params[name] || '';
|
|
87
|
-
const
|
|
88
|
-
const forceUpdate = useUpdateTrigger();
|
|
87
|
+
const notifyChange = useValueTrigger(value);
|
|
89
88
|
useEffect(function () {
|
|
90
89
|
var setValue = function () {
|
|
91
|
-
|
|
92
|
-
if (current !== ref.current) {
|
|
93
|
-
forceUpdate();
|
|
94
|
-
}
|
|
90
|
+
notifyChange(container.page.params[name] || '');
|
|
95
91
|
};
|
|
96
92
|
// route parameter might be changed after state initialization and before useEffect hook is called
|
|
97
93
|
setValue();
|
|
98
94
|
return container.on('pagechange', setValue);
|
|
99
95
|
}, [name]);
|
|
100
|
-
ref.current = value;
|
|
101
96
|
if (defaultValue && container.active && (!value || (name === 'remainingSegments' && value === '/'))) {
|
|
102
97
|
app.navigate(app.route.getPath(extend({}, params, kv(name, defaultValue))), true);
|
|
103
98
|
}
|
|
@@ -129,22 +124,20 @@ export function useQueryParam(key, value, snapshotOnUpdate) {
|
|
|
129
124
|
}
|
|
130
125
|
var container = useViewContext();
|
|
131
126
|
var getParams = function () {
|
|
132
|
-
return mapObject(key === false ? value : kv(key, value), function (v, i) {
|
|
127
|
+
return freeze(mapObject(key === false ? value : kv(key, value), function (v, i) {
|
|
133
128
|
return getQueryParam(i, app.path) || v || '';
|
|
134
|
-
});
|
|
129
|
+
}));
|
|
135
130
|
};
|
|
136
|
-
var
|
|
131
|
+
var ref = useRef({});
|
|
137
132
|
useMemo(function () {
|
|
138
|
-
|
|
133
|
+
ref.current = getParams();
|
|
139
134
|
}, [key]);
|
|
140
|
-
var current =
|
|
141
|
-
var
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
state[1]([current]);
|
|
145
|
-
}
|
|
146
|
-
};
|
|
135
|
+
var current = ref.current;
|
|
136
|
+
var notifyChange = useValueTrigger(current, function (current, params) {
|
|
137
|
+
return equal(current, params) || !(ref.current = params);
|
|
138
|
+
});
|
|
147
139
|
var setParams = useMemoizedFunction(function (values) {
|
|
140
|
+
var current = ref.current;
|
|
148
141
|
if (key !== false) {
|
|
149
142
|
values = kv(key, isFunction(values) ? values(current[key]) : values);
|
|
150
143
|
} else if (isFunction(values)) {
|
|
@@ -159,19 +152,19 @@ export function useQueryParam(key, value, snapshotOnUpdate) {
|
|
|
159
152
|
if (snapshotOnUpdate) {
|
|
160
153
|
app.snapshot();
|
|
161
154
|
}
|
|
162
|
-
catchAsync(app.navigate(search + url.hash, true));
|
|
163
|
-
|
|
155
|
+
catchAsync(app.navigate((search || '?') + url.hash, true));
|
|
156
|
+
notifyChange(getParams());
|
|
164
157
|
}
|
|
165
158
|
}
|
|
166
159
|
});
|
|
167
160
|
useEffect(function () {
|
|
168
161
|
return app.watch('path', function () {
|
|
169
162
|
if (container.active) {
|
|
170
|
-
|
|
163
|
+
notifyChange(getParams());
|
|
171
164
|
}
|
|
172
165
|
});
|
|
173
166
|
}, [key]);
|
|
174
|
-
return [key !== false ? current[key] :
|
|
167
|
+
return [key !== false ? current[key] : current, setParams];
|
|
175
168
|
}
|
|
176
169
|
|
|
177
170
|
export function ViewStateContainer(props) {
|
|
@@ -31,9 +31,9 @@ definePrototype(AnimateSequenceMixin, AnimateMixin, {
|
|
|
31
31
|
var self = this;
|
|
32
32
|
AnimateSequenceMixinSuper.initElement.call(self, element, state);
|
|
33
33
|
if (self.selector) {
|
|
34
|
-
|
|
34
|
+
state.onDispose(watchElements(element, self.selector, function (addedNodes) {
|
|
35
35
|
$(addedNodes).attr('is-animate-sequence', '');
|
|
36
|
-
}));
|
|
36
|
+
}).dispose);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
});
|
package/mixins/ClassNameMixin.js
CHANGED
|
@@ -21,18 +21,13 @@ export default function ClassNameMixin(classNames) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
definePrototype(ClassNameMixin, StatefulMixin, {
|
|
24
|
-
initState: function () {
|
|
25
|
-
return {
|
|
26
|
-
element: null,
|
|
27
|
-
classNames: fill(this.classNames, false)
|
|
28
|
-
};
|
|
29
|
-
},
|
|
30
24
|
initElement: function (element, state) {
|
|
31
25
|
var self = this;
|
|
26
|
+
state.classNames = fill(self.classNames, false);
|
|
32
27
|
checkState(self, element, state);
|
|
33
|
-
watchOwnAttributes(element, 'class', function () {
|
|
28
|
+
state.onDispose(watchOwnAttributes(element, 'class', function () {
|
|
34
29
|
checkState(self, element, state, true);
|
|
35
|
-
});
|
|
30
|
+
}).dispose);
|
|
36
31
|
},
|
|
37
32
|
onLayoutEffect: function (element, state) {
|
|
38
33
|
setClass(element, state.classNames);
|
package/mixins/FlyoutMixin.d.ts
CHANGED
|
@@ -35,6 +35,10 @@ export interface FlyoutMixinOptions {
|
|
|
35
35
|
* Mixin should be created using {@link useFlyoutMixin} and applied to element by {@link Mixin.use}.
|
|
36
36
|
*/
|
|
37
37
|
export default class FlyoutMixin extends ClassNameMixin {
|
|
38
|
+
/**
|
|
39
|
+
* Gets the flyout element.
|
|
40
|
+
*/
|
|
41
|
+
readonly element: Element | null;
|
|
38
42
|
/**
|
|
39
43
|
* Gets whether the flyout is open.
|
|
40
44
|
*/
|
package/mixins/FlyoutMixin.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { definePrototype, extend, makeArray, pick } from "zeta-dom/util";
|
|
1
|
+
import { definePrototype, extend, makeArray, pick, throws } from "zeta-dom/util";
|
|
2
2
|
import { closeFlyout, openFlyout, toggleFlyout } from "brew-js/domAction";
|
|
3
3
|
import { app } from "../app.js";
|
|
4
4
|
import ClassNameMixin from "./ClassNameMixin.js";
|
|
@@ -25,6 +25,9 @@ export default function FlyoutMixin() {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
definePrototype(FlyoutMixin, ClassNameMixin, {
|
|
28
|
+
get element() {
|
|
29
|
+
return this.elements()[0] || null;
|
|
30
|
+
},
|
|
28
31
|
getOptions: function () {
|
|
29
32
|
var self = this;
|
|
30
33
|
var options = pick(self, ['closeOnBlur']);
|
|
@@ -57,19 +60,18 @@ definePrototype(FlyoutMixin, ClassNameMixin, {
|
|
|
57
60
|
});
|
|
58
61
|
},
|
|
59
62
|
open: function (value, source) {
|
|
60
|
-
return openFlyout(this.
|
|
63
|
+
return openFlyout(this.element, value, source, this.getOptions());
|
|
61
64
|
},
|
|
62
65
|
close: function (value) {
|
|
63
|
-
return closeFlyout(this.
|
|
66
|
+
return closeFlyout(this.element, value);
|
|
64
67
|
},
|
|
65
68
|
toggleSelf: function (source) {
|
|
66
|
-
return toggleFlyout(this.
|
|
69
|
+
return toggleFlyout(this.element, source, this.getOptions());
|
|
67
70
|
},
|
|
68
71
|
onOpen: function (callback) {
|
|
69
|
-
var element = this.elements()[0];
|
|
70
72
|
return this.onToggleState(function (opened) {
|
|
71
73
|
if (opened) {
|
|
72
|
-
|
|
74
|
+
callback(valueMap.get(this.element));
|
|
73
75
|
}
|
|
74
76
|
});
|
|
75
77
|
},
|
|
@@ -81,8 +83,11 @@ definePrototype(FlyoutMixin, ClassNameMixin, {
|
|
|
81
83
|
},
|
|
82
84
|
initElement: function (element, state) {
|
|
83
85
|
var self = this;
|
|
86
|
+
if (self.elements()[1]) {
|
|
87
|
+
throws('FlyoutMixin only supports single element');
|
|
88
|
+
}
|
|
84
89
|
FlyoutMixinSuper.initElement.call(self, element, state);
|
|
85
|
-
|
|
90
|
+
state.onDispose(app.on(element, {
|
|
86
91
|
flyoutshow: function (e) {
|
|
87
92
|
valueMap.set(element, e.data);
|
|
88
93
|
self.isFlyoutOpened = true;
|
|
@@ -32,7 +32,7 @@ definePrototype(FlyoutToggleMixin, ClassNameMixin, {
|
|
|
32
32
|
initElement: function (element, state) {
|
|
33
33
|
var self = this;
|
|
34
34
|
FlyoutToggleMixinSuper.initElement.call(self, element, state);
|
|
35
|
-
|
|
35
|
+
state.onDispose(dom.on(element, {
|
|
36
36
|
focusin: function () {
|
|
37
37
|
triggerFlyoutAction(self, state, 'focus', self.open, [null, dom.activeElement]);
|
|
38
38
|
},
|
|
@@ -23,7 +23,7 @@ definePrototype(FocusStateMixin, StatefulMixin, {
|
|
|
23
23
|
callback(arg || target);
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
|
-
|
|
26
|
+
state.onDispose(dom.on(element, {
|
|
27
27
|
focusin: function (e) {
|
|
28
28
|
state.focused = e.source;
|
|
29
29
|
setClass(element, 'focused', e.source);
|
|
@@ -16,7 +16,7 @@ definePrototype(LoadingStateMixin, ClassNameMixin, {
|
|
|
16
16
|
var self = this;
|
|
17
17
|
LoadingStateMixinSuper.initElement.call(self, element, state);
|
|
18
18
|
getDirectiveComponent(element).enableLoadingClass = true;
|
|
19
|
-
|
|
19
|
+
state.onDispose(subscribeAsync(element, function (loading) {
|
|
20
20
|
self.loading = loading || !!any(self.elements(), function (v) {
|
|
21
21
|
return v !== element && getClass(v, 'loading') === true;
|
|
22
22
|
});
|
|
@@ -52,6 +52,14 @@ export default class ScrollableMixin extends ClassNameMixin implements JQueryScr
|
|
|
52
52
|
* the element will act as content to be scrolled.
|
|
53
53
|
*/
|
|
54
54
|
readonly target: StaticAttributeMixin;
|
|
55
|
+
/**
|
|
56
|
+
* Gets the element with scrollable plugin enabled.
|
|
57
|
+
*/
|
|
58
|
+
readonly element: Element | null;
|
|
59
|
+
/**
|
|
60
|
+
* Gets the element which its scrolling position is currently controlled.
|
|
61
|
+
*/
|
|
62
|
+
readonly contentElement: Element | null;
|
|
55
63
|
/**
|
|
56
64
|
* Gets the index of the currently visible element matched by {@link ScrollableMixinOptions.pagedItemSelector} options.
|
|
57
65
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineHiddenProperty, definePrototype, each, extend } from "zeta-dom/util";
|
|
1
|
+
import { defineHiddenProperty, definePrototype, each, extend, throws } from "zeta-dom/util";
|
|
2
2
|
import { getDirectiveComponent } from "brew-js/directive";
|
|
3
3
|
import { app } from "../app.js";
|
|
4
4
|
import Mixin from "./Mixin.js";
|
|
@@ -15,6 +15,13 @@ export default function ScrollableMixin() {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
definePrototype(ScrollableMixin, ClassNameMixin, {
|
|
18
|
+
get element() {
|
|
19
|
+
return this.elements()[0] || null;
|
|
20
|
+
},
|
|
21
|
+
get contentElement() {
|
|
22
|
+
var element = this.element;
|
|
23
|
+
return element && getDirectiveComponent(element).scrollable.scrollTarget;
|
|
24
|
+
},
|
|
18
25
|
withOptions: function (options) {
|
|
19
26
|
this.options = options;
|
|
20
27
|
return this;
|
|
@@ -35,8 +42,11 @@ definePrototype(ScrollableMixin, ClassNameMixin, {
|
|
|
35
42
|
},
|
|
36
43
|
initElement: function (element, state) {
|
|
37
44
|
var self = this;
|
|
45
|
+
if (self.elements()[1]) {
|
|
46
|
+
throws('ScrollableMixin only supports single element');
|
|
47
|
+
}
|
|
38
48
|
ScrollableMixinSuper.initElement.call(self, element, state);
|
|
39
|
-
|
|
49
|
+
state.onDispose(app.on(element, {
|
|
40
50
|
scrollIndexChange: function (e) {
|
|
41
51
|
self.pageIndex = e.newIndex;
|
|
42
52
|
},
|
|
@@ -52,7 +62,7 @@ definePrototype(ScrollableMixin, ClassNameMixin, {
|
|
|
52
62
|
|
|
53
63
|
each('destroy enable disable setOptions setStickyPosition refresh scrollPadding stop scrollLeft scrollTop scrollBy scrollTo scrollByPage scrollToPage scrollToElement', function (i, v) {
|
|
54
64
|
defineHiddenProperty(ScrollableMixin.prototype, v, function () {
|
|
55
|
-
var obj = getDirectiveComponent(this.
|
|
65
|
+
var obj = getDirectiveComponent(this.element);
|
|
56
66
|
return obj.scrollable[v].apply(null, arguments);
|
|
57
67
|
});
|
|
58
68
|
});
|
|
@@ -9,6 +9,12 @@ export interface MixinState {
|
|
|
9
9
|
* Additional state.
|
|
10
10
|
*/
|
|
11
11
|
[x: string]: any;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Registers callback to clean up resources when the element is unmounted.
|
|
15
|
+
* @param callback A callback.
|
|
16
|
+
*/
|
|
17
|
+
onDispose(callback: Zeta.UnregisterCallback): void;
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
export interface MixinRef<T extends StatefulMixin = StatefulMixin> {
|
|
@@ -29,7 +35,7 @@ export default abstract class StatefulMixin<T extends MixinState = MixinState> e
|
|
|
29
35
|
* By default, existing values on the actual state object will be overwritten in subsequent update.
|
|
30
36
|
* To handle changes, overrides the {@link StatefulMixin.mergeState} method.
|
|
31
37
|
*/
|
|
32
|
-
protected get state(): Exclude<Partial<T>, 'element'>;
|
|
38
|
+
protected get state(): Exclude<Partial<T>, 'element' | 'onDispose'>;
|
|
33
39
|
|
|
34
40
|
/**
|
|
35
41
|
* Gets an array of mounted elements which this mixin has been applied.
|
|
@@ -37,12 +43,14 @@ export default abstract class StatefulMixin<T extends MixinState = MixinState> e
|
|
|
37
43
|
elements(): HTMLElement[];
|
|
38
44
|
/**
|
|
39
45
|
* Registers callback to clean up resources when the host component is unmounted.
|
|
46
|
+
* For individual element, use {@link MixinState.onDispose}.
|
|
40
47
|
* @param callback A callback.
|
|
41
48
|
*/
|
|
42
49
|
onDispose(callback: Zeta.UnregisterCallback): void;
|
|
43
50
|
|
|
44
51
|
/**
|
|
45
52
|
* Override this method to create state object with initial values.
|
|
53
|
+
* @deprecated Initialize state in {@link StatefulMixin.initElement} instead.
|
|
46
54
|
*/
|
|
47
55
|
protected initState(): T;
|
|
48
56
|
/**
|
package/mixins/StatefulMixin.js
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
|
-
import { combineFn, createPrivateStore, definePrototype, extend, keys,
|
|
1
|
+
import { arrRemove, combineFn, createPrivateStore, definePrototype, each, extend, keys, setImmediateOnce, throwNotFunction, watch } from "zeta-dom/util";
|
|
2
2
|
import Mixin from "./Mixin.js";
|
|
3
3
|
|
|
4
4
|
const _ = createPrivateStore();
|
|
5
|
+
const unmounted = new Set();
|
|
6
|
+
|
|
7
|
+
function disposeUnmountedStates() {
|
|
8
|
+
each(unmounted, function (i, v) {
|
|
9
|
+
combineFn(_(v).splice(0))();
|
|
10
|
+
});
|
|
11
|
+
unmounted.clear();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function MixinState(parent, element) {
|
|
15
|
+
_(this, [parent.delete.bind(parent, element)]);
|
|
16
|
+
parent.set(element, this);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
definePrototype(MixinState, {
|
|
20
|
+
onDispose: function (callback) {
|
|
21
|
+
_(this).push(throwNotFunction(callback));
|
|
22
|
+
}
|
|
23
|
+
});
|
|
5
24
|
|
|
6
25
|
function MixinRefImpl(mixin) {
|
|
7
26
|
this.mixin = mixin;
|
|
@@ -17,8 +36,8 @@ export default function StatefulMixin() {
|
|
|
17
36
|
Mixin.call(this);
|
|
18
37
|
_(this, {
|
|
19
38
|
pending: {},
|
|
20
|
-
elements:
|
|
21
|
-
states: new
|
|
39
|
+
elements: [],
|
|
40
|
+
states: new Map(),
|
|
22
41
|
flush: watch(this, false),
|
|
23
42
|
dispose: []
|
|
24
43
|
});
|
|
@@ -44,34 +63,35 @@ definePrototype(StatefulMixin, Mixin, {
|
|
|
44
63
|
var self = this;
|
|
45
64
|
var obj = _(self);
|
|
46
65
|
var newState = obj.pending;
|
|
47
|
-
var state;
|
|
66
|
+
var element, state;
|
|
48
67
|
return function (current) {
|
|
49
68
|
if (current) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
69
|
+
element = current;
|
|
70
|
+
state = obj.states.get(element) || new MixinState(obj.states, element);
|
|
71
|
+
obj.elements.push(element);
|
|
72
|
+
if (!state.element) {
|
|
73
|
+
self.initElement(element, extend(state, self.initState(), newState, { element }));
|
|
55
74
|
} else if (keys(newState)[0]) {
|
|
56
|
-
self.mergeState(
|
|
75
|
+
self.mergeState(element, state, newState);
|
|
57
76
|
}
|
|
58
|
-
self.onLayoutEffect(
|
|
59
|
-
|
|
77
|
+
self.onLayoutEffect(element, state);
|
|
78
|
+
unmounted.delete(state);
|
|
60
79
|
} else if (state) {
|
|
61
|
-
|
|
62
|
-
self.onBeforeUpdate(
|
|
63
|
-
obj.elements
|
|
80
|
+
unmounted.add(state);
|
|
81
|
+
self.onBeforeUpdate(element, state);
|
|
82
|
+
arrRemove(obj.elements, element);
|
|
64
83
|
}
|
|
84
|
+
setImmediateOnce(disposeUnmountedStates);
|
|
65
85
|
};
|
|
66
86
|
},
|
|
67
87
|
elements: function () {
|
|
68
|
-
return
|
|
88
|
+
return _(this).elements.slice();
|
|
69
89
|
},
|
|
70
90
|
onDispose: function (callback) {
|
|
71
91
|
_(this).dispose.push(callback);
|
|
72
92
|
},
|
|
73
93
|
initState: function () {
|
|
74
|
-
return {
|
|
94
|
+
return {};
|
|
75
95
|
},
|
|
76
96
|
initElement: function (element, state) {
|
|
77
97
|
},
|
|
@@ -87,9 +107,12 @@ definePrototype(StatefulMixin, Mixin, {
|
|
|
87
107
|
},
|
|
88
108
|
dispose: function () {
|
|
89
109
|
var state = _(this);
|
|
110
|
+
each(state.states, function (i, v) {
|
|
111
|
+
unmounted.add(v);
|
|
112
|
+
});
|
|
113
|
+
setImmediateOnce(disposeUnmountedStates);
|
|
90
114
|
combineFn(state.dispose.splice(0))();
|
|
91
115
|
state.flush();
|
|
92
|
-
state.states = {};
|
|
93
116
|
state.pending = {};
|
|
94
117
|
}
|
|
95
118
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brew-js-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"@misonou/react-dom-client": "^1.1.1",
|
|
16
16
|
"brew-js": ">=0.6.5",
|
|
17
17
|
"waterpipe": "^2.5.0",
|
|
18
|
-
"zeta-dom": ">=0.
|
|
19
|
-
"zeta-dom-react": ">=0.
|
|
18
|
+
"zeta-dom": ">=0.5.1",
|
|
19
|
+
"zeta-dom-react": ">=0.5.6"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
22
|
"react": ">=16.8.0",
|
package/view.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Component, Fragment, createContext, createElement, useContext, useEffect } from "react";
|
|
1
|
+
import { Component, Fragment, createContext, createElement, useContext, useEffect, useState } from "react";
|
|
2
2
|
import { useAsync } from "zeta-dom-react";
|
|
3
|
-
import dom from "zeta-dom/dom";
|
|
3
|
+
import dom, { reportError } from "zeta-dom/dom";
|
|
4
4
|
import { notifyAsync } from "zeta-dom/domLock";
|
|
5
5
|
import { ZetaEventContainer } from "zeta-dom/events";
|
|
6
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";
|
|
@@ -70,7 +70,7 @@ function ViewContext(view, page, parent) {
|
|
|
70
70
|
definePrototype(ViewContext, {
|
|
71
71
|
getChildren: function () {
|
|
72
72
|
return map(_(this).children, function (v) {
|
|
73
|
-
return v.
|
|
73
|
+
return v.currentContext;
|
|
74
74
|
});
|
|
75
75
|
},
|
|
76
76
|
on: function (event, handler) {
|
|
@@ -93,7 +93,7 @@ definePrototype(ErrorBoundary, Component, {
|
|
|
93
93
|
// emit error in next tick as ref callback may yet to be invoked
|
|
94
94
|
// if error is thrown synchronously in first render
|
|
95
95
|
setImmediate(function () {
|
|
96
|
-
|
|
96
|
+
reportError(error, self.context.container);
|
|
97
97
|
});
|
|
98
98
|
// ensure promise sent to beforepageload event is resolved
|
|
99
99
|
self.props.onComponentLoaded();
|
|
@@ -135,7 +135,7 @@ definePrototype(ViewContainer, Component, {
|
|
|
135
135
|
arrRemove(parent, self);
|
|
136
136
|
unwatch();
|
|
137
137
|
setImmediate(function () {
|
|
138
|
-
if (self.unmountView && !self.
|
|
138
|
+
if (self.unmountView && !self.currentContext.active) {
|
|
139
139
|
self.unmountView();
|
|
140
140
|
}
|
|
141
141
|
});
|
|
@@ -168,50 +168,53 @@ definePrototype(ViewContainer, Component, {
|
|
|
168
168
|
if (V && viewChanged) {
|
|
169
169
|
(self.unmountView || noop)(true);
|
|
170
170
|
|
|
171
|
-
var
|
|
171
|
+
var context = new ViewContext(V, app.page, self.context);
|
|
172
|
+
var state = routeMap.get(V);
|
|
172
173
|
var onComponentLoaded;
|
|
173
174
|
var promise = new Promise(function (resolve) {
|
|
174
175
|
onComponentLoaded = resolve;
|
|
175
176
|
});
|
|
176
177
|
var unmountView = onComponentLoaded;
|
|
177
178
|
var initElement = executeOnce(function (element) {
|
|
178
|
-
|
|
179
|
+
context.container = element;
|
|
179
180
|
promise.then(function () {
|
|
180
|
-
if (self.
|
|
181
|
+
if (self.currentContext === context) {
|
|
181
182
|
unmountView = function () {
|
|
182
183
|
self.prevView = self.currentView;
|
|
183
|
-
app.emit('pageleave', element, { pathname:
|
|
184
|
+
app.emit('pageleave', element, { pathname: context.page.path, view: V }, true);
|
|
184
185
|
animateOut(element, 'show').then(function () {
|
|
185
186
|
self.prevView = undefined;
|
|
186
187
|
self.forceUpdate();
|
|
187
188
|
});
|
|
188
189
|
};
|
|
189
190
|
animateIn(element, 'show', '[brew-view]', true);
|
|
190
|
-
app.emit('pageenter', element, { pathname:
|
|
191
|
+
app.emit('pageenter', element, { pathname: context.page.path, view: V }, true);
|
|
191
192
|
}
|
|
192
193
|
});
|
|
193
194
|
notifyAsync(element, promise);
|
|
194
195
|
});
|
|
195
|
-
var viewProps =
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
196
|
+
var viewProps = function () {
|
|
197
|
+
return freeze({
|
|
198
|
+
navigationType: event.navigationType,
|
|
199
|
+
viewContext: context,
|
|
200
|
+
viewData: context.page.data || {}
|
|
201
|
+
});
|
|
202
|
+
};
|
|
203
|
+
var view = createElement(StateContext.Provider, { key: state.id, value: context },
|
|
201
204
|
createElement(ViewStateContainer, null,
|
|
202
205
|
createElement('div', extend({}, self.props.rootProps, { ref: initElement, 'brew-view': '' }),
|
|
203
206
|
createElement(ErrorBoundary, { onComponentLoaded, viewProps }))));
|
|
204
|
-
extend(self, _(
|
|
205
|
-
|
|
207
|
+
extend(self, _(context), {
|
|
208
|
+
currentContext: context,
|
|
206
209
|
currentView: view,
|
|
207
210
|
currentViewComponent: V,
|
|
208
211
|
unmountView: executeOnce(function () {
|
|
209
212
|
self.setActive(false);
|
|
210
|
-
|
|
213
|
+
state.rendered--;
|
|
211
214
|
unmountView();
|
|
212
215
|
})
|
|
213
216
|
});
|
|
214
|
-
|
|
217
|
+
state.rendered++;
|
|
215
218
|
(event.waitFor || noop)(promise);
|
|
216
219
|
}
|
|
217
220
|
(self.setPage || noop)(app.page);
|
|
@@ -273,19 +276,24 @@ function createViewComponent(factory) {
|
|
|
273
276
|
factory = createElement.bind(null, factory);
|
|
274
277
|
}
|
|
275
278
|
return function fn(props) {
|
|
276
|
-
var
|
|
277
|
-
var
|
|
279
|
+
var viewContext = useContext(StateContext);
|
|
280
|
+
var viewProps = useState(props.viewProps);
|
|
281
|
+
var children = !promise && factory(viewProps[0]);
|
|
278
282
|
if (isThenable(children)) {
|
|
279
283
|
promise = children;
|
|
280
284
|
children = null;
|
|
281
285
|
catchAsync(promise);
|
|
282
286
|
}
|
|
283
287
|
var state = useAsync(function () {
|
|
284
|
-
return promise
|
|
285
|
-
return createElement(s.default, viewProps);
|
|
286
|
-
});
|
|
288
|
+
return promise;
|
|
287
289
|
}, !!promise)[1];
|
|
288
290
|
var loaded = !promise || !state.loading;
|
|
291
|
+
useEffect(function () {
|
|
292
|
+
// listen to property directly so that it is invoked after pagechange event handlers in actual component
|
|
293
|
+
return watch(viewContext, 'page', function () {
|
|
294
|
+
viewProps[1](props.viewProps);
|
|
295
|
+
});
|
|
296
|
+
}, []);
|
|
289
297
|
useEffect(function () {
|
|
290
298
|
if (loaded) {
|
|
291
299
|
setImmediate(props.onComponentLoaded);
|
|
@@ -294,7 +302,7 @@ function createViewComponent(factory) {
|
|
|
294
302
|
if (state.error) {
|
|
295
303
|
throw state.error;
|
|
296
304
|
}
|
|
297
|
-
return children || state.value
|
|
305
|
+
return children || (state.value ? createElement(state.value.default, viewProps[0]) : null);
|
|
298
306
|
};
|
|
299
307
|
}
|
|
300
308
|
|