brew-js-react 0.5.7 → 0.6.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.
- package/README.md +1 -1
- package/dialog.d.ts +1 -1
- package/dialog.js +8 -10
- package/dist/brew-js-react.js +157 -122
- 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/mixin.d.ts +1 -1
- package/mixins/AnimateSequenceMixin.js +2 -2
- package/mixins/ClassNameMixin.js +3 -8
- package/mixins/FlyoutMixin.d.ts +19 -6
- package/mixins/FlyoutMixin.js +26 -9
- package/mixins/FlyoutToggleMixin.d.ts +12 -5
- package/mixins/FlyoutToggleMixin.js +3 -3
- 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 +44 -43
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) {
|
package/mixin.d.ts
CHANGED
|
@@ -56,7 +56,7 @@ export function useScrollIntoViewMixin(): ScrollIntoViewMixin;
|
|
|
56
56
|
* Returns a mixin that provides methods controlling the applied element as a flyout.
|
|
57
57
|
* @param options A dictionary specifying options.
|
|
58
58
|
*/
|
|
59
|
-
export function useFlyoutMixin(options?: FlyoutMixinOptions): FlyoutMixin
|
|
59
|
+
export function useFlyoutMixin<S = any, R = any>(options?: FlyoutMixinOptions): FlyoutMixin<S, R>;
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* Returns a mixin that enables intro and/or outro animation for applied elements.
|
|
@@ -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
|
@@ -4,6 +4,8 @@ import Mixin from "./Mixin";
|
|
|
4
4
|
import { AnimationEffect } from "./AnimateMixin";
|
|
5
5
|
import { useFlyoutMixin } from "../mixin";
|
|
6
6
|
|
|
7
|
+
export type HintedType<T> = T | {} | number | string | boolean | symbol | bigint | null | undefined;
|
|
8
|
+
|
|
7
9
|
export interface FlyoutMixinOptions {
|
|
8
10
|
/**
|
|
9
11
|
* Whether flyout is modal.
|
|
@@ -34,7 +36,11 @@ export interface FlyoutMixinOptions {
|
|
|
34
36
|
*
|
|
35
37
|
* Mixin should be created using {@link useFlyoutMixin} and applied to element by {@link Mixin.use}.
|
|
36
38
|
*/
|
|
37
|
-
export default class FlyoutMixin extends ClassNameMixin {
|
|
39
|
+
export default class FlyoutMixin<S = any, R = any> extends ClassNameMixin {
|
|
40
|
+
/**
|
|
41
|
+
* Gets the flyout element.
|
|
42
|
+
*/
|
|
43
|
+
readonly element: Element | null;
|
|
38
44
|
/**
|
|
39
45
|
* Gets whether the flyout is open.
|
|
40
46
|
*/
|
|
@@ -52,7 +58,7 @@ export default class FlyoutMixin extends ClassNameMixin {
|
|
|
52
58
|
* Gets a {@link FlyoutToggleMixin} object that when applied to an element,
|
|
53
59
|
* clicking that element will toggle the flyout.
|
|
54
60
|
*/
|
|
55
|
-
readonly toggle: FlyoutToggleMixin
|
|
61
|
+
readonly toggle: FlyoutToggleMixin<S, R>;
|
|
56
62
|
/**
|
|
57
63
|
* Whether flyout content, or what element, by specifying CSS selector, will be initially focused.
|
|
58
64
|
* Default is `true` if source element is not an text input element.
|
|
@@ -73,7 +79,7 @@ export default class FlyoutMixin extends ClassNameMixin {
|
|
|
73
79
|
* Adds a listener to handle the opening of the flyout.
|
|
74
80
|
* @param callback Callback to be called, receiving value passed to {@link FlyoutMixin.open}.
|
|
75
81
|
*/
|
|
76
|
-
onOpen(callback: (state:
|
|
82
|
+
onOpen(callback: (state: HintedType<S>) => void): Zeta.UnregisterCallback;
|
|
77
83
|
/**
|
|
78
84
|
* Adds a listener to monitor the opening and closing of the flyout.
|
|
79
85
|
* It differs from {@link FlyoutMixin.onVisibilityChanged} that the callback is called immediately when the flyout is being closed.
|
|
@@ -92,17 +98,24 @@ export default class FlyoutMixin extends ClassNameMixin {
|
|
|
92
98
|
* @param source Source element that triggered the flyout.
|
|
93
99
|
* @returns A promise that resolves when the flyout is being closed.
|
|
94
100
|
*/
|
|
95
|
-
open(state?:
|
|
101
|
+
open(state?: S, source?: Element): Promise<HintedType<R>>;
|
|
96
102
|
/**
|
|
97
103
|
* Closes the flyout.
|
|
98
104
|
* @param state Value to be sent to the promise returned by {@link FlyoutMixin.open}.
|
|
99
105
|
* @returns A promise that resolves after closing animation completes.
|
|
100
106
|
*/
|
|
101
|
-
close(state?:
|
|
107
|
+
close(state?: R): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Toggles the flyout.
|
|
110
|
+
* @param source Source element which triggered the flyout.
|
|
111
|
+
* @returns A promise that resolves when the flyout is being closed.
|
|
112
|
+
*/
|
|
113
|
+
toggleSelf(source?: Element): Promise<HintedType<R>>;
|
|
102
114
|
/**
|
|
103
115
|
* Toggles the flyout.
|
|
116
|
+
* @param flag Whether the flyout should be open or closed.
|
|
104
117
|
* @param source Source element which triggered the flyout.
|
|
105
118
|
* @returns A promise that resolves when the flyout is being closed.
|
|
106
119
|
*/
|
|
107
|
-
toggleSelf(source?: Element): Promise<
|
|
120
|
+
toggleSelf(flag: boolean, source?: Element): Promise<HintedType<R>>;
|
|
108
121
|
}
|
package/mixins/FlyoutMixin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { definePrototype, extend, makeArray, pick } from "zeta-dom/util";
|
|
2
|
-
import { closeFlyout, openFlyout, toggleFlyout } from "brew-js/domAction";
|
|
1
|
+
import { definePrototype, extend, makeArray, pick, resolve, throws } from "zeta-dom/util";
|
|
2
|
+
import { closeFlyout, isFlyoutOpen, openFlyout, toggleFlyout } 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";
|
|
@@ -7,6 +7,14 @@ import FlyoutToggleMixin from "./FlyoutToggleMixin.js";
|
|
|
7
7
|
const FlyoutMixinSuper = ClassNameMixin.prototype;
|
|
8
8
|
const valueMap = new WeakMap();
|
|
9
9
|
|
|
10
|
+
function toggleSelf(self, flag, value, source) {
|
|
11
|
+
if (!flag && !isFlyoutOpen(self.element)) {
|
|
12
|
+
return resolve();
|
|
13
|
+
}
|
|
14
|
+
var options = self.getOptions();
|
|
15
|
+
return flag ? openFlyout(self.element, value, source, options) : toggleFlyout(self.element, source, options);
|
|
16
|
+
}
|
|
17
|
+
|
|
10
18
|
export default function FlyoutMixin() {
|
|
11
19
|
var self = this;
|
|
12
20
|
ClassNameMixin.call(self, ['open', 'closing', 'visible', 'tweening-in', 'tweening-out']);
|
|
@@ -25,6 +33,9 @@ export default function FlyoutMixin() {
|
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
definePrototype(FlyoutMixin, ClassNameMixin, {
|
|
36
|
+
get element() {
|
|
37
|
+
return this.elements()[0] || null;
|
|
38
|
+
},
|
|
28
39
|
getOptions: function () {
|
|
29
40
|
var self = this;
|
|
30
41
|
var options = pick(self, ['closeOnBlur']);
|
|
@@ -57,19 +68,22 @@ definePrototype(FlyoutMixin, ClassNameMixin, {
|
|
|
57
68
|
});
|
|
58
69
|
},
|
|
59
70
|
open: function (value, source) {
|
|
60
|
-
return
|
|
71
|
+
return toggleSelf(this, true, value, source);
|
|
61
72
|
},
|
|
62
73
|
close: function (value) {
|
|
63
|
-
return closeFlyout(this.
|
|
74
|
+
return closeFlyout(this.element, value);
|
|
64
75
|
},
|
|
65
|
-
toggleSelf: function (source) {
|
|
66
|
-
|
|
76
|
+
toggleSelf: function (flag, source) {
|
|
77
|
+
if (typeof flag !== 'boolean') {
|
|
78
|
+
source = flag;
|
|
79
|
+
flag = !isFlyoutOpen(this.element);
|
|
80
|
+
}
|
|
81
|
+
return toggleSelf(this, flag, undefined, source);
|
|
67
82
|
},
|
|
68
83
|
onOpen: function (callback) {
|
|
69
|
-
var element = this.elements()[0];
|
|
70
84
|
return this.onToggleState(function (opened) {
|
|
71
85
|
if (opened) {
|
|
72
|
-
|
|
86
|
+
callback(valueMap.get(this.element));
|
|
73
87
|
}
|
|
74
88
|
});
|
|
75
89
|
},
|
|
@@ -81,8 +95,11 @@ definePrototype(FlyoutMixin, ClassNameMixin, {
|
|
|
81
95
|
},
|
|
82
96
|
initElement: function (element, state) {
|
|
83
97
|
var self = this;
|
|
98
|
+
if (self.elements()[1]) {
|
|
99
|
+
throws('FlyoutMixin only supports single element');
|
|
100
|
+
}
|
|
84
101
|
FlyoutMixinSuper.initElement.call(self, element, state);
|
|
85
|
-
|
|
102
|
+
state.onDispose(app.on(element, {
|
|
86
103
|
flyoutshow: function (e) {
|
|
87
104
|
valueMap.set(element, e.data);
|
|
88
105
|
self.isFlyoutOpened = true;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import ClassNameMixin from "./ClassNameMixin";
|
|
2
|
-
import FlyoutMixin from "./FlyoutMixin";
|
|
2
|
+
import FlyoutMixin, { HintedType } from "./FlyoutMixin";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Enables applied element as toggle buttons for the associated flyout.
|
|
6
6
|
*
|
|
7
7
|
* Instances of this mixin is exposed by {@link FlyoutMixin.toggle}.
|
|
8
8
|
*/
|
|
9
|
-
export default class FlyoutToggleMixin extends ClassNameMixin {
|
|
9
|
+
export default class FlyoutToggleMixin<S = any, R = any> extends ClassNameMixin {
|
|
10
10
|
/**
|
|
11
11
|
* Specifies the condition on when the flyout should toggle. It can be either:
|
|
12
12
|
*
|
|
@@ -24,17 +24,24 @@ export default class FlyoutToggleMixin extends ClassNameMixin {
|
|
|
24
24
|
* @param source Source element that triggered the flyout.
|
|
25
25
|
* @returns A promise that resolves when the flyout is being closed.
|
|
26
26
|
*/
|
|
27
|
-
open(state?:
|
|
27
|
+
open(state?: S, source?: Element): Promise<HintedType<R>>;
|
|
28
28
|
/**
|
|
29
29
|
* Closes the associated flyout.
|
|
30
30
|
* @param state Value to be sent to the promise returned by {@link FlyoutMixin.open}.
|
|
31
31
|
* @returns A promise that resolves after closing animation completes.
|
|
32
32
|
*/
|
|
33
|
-
close(state?:
|
|
33
|
+
close(state?: R): Promise<void>;
|
|
34
34
|
/**
|
|
35
35
|
* Toggles the associated flyout.
|
|
36
36
|
* @param source Source element which triggered the flyout.
|
|
37
37
|
* @returns A promise that resolves when the flyout is being closed.
|
|
38
38
|
*/
|
|
39
|
-
toggle(source?: Element): Promise<
|
|
39
|
+
toggle(source?: Element): Promise<HintedType<R>>;
|
|
40
|
+
/**
|
|
41
|
+
* Toggles the associated flyout.
|
|
42
|
+
* @param flag Whether the flyout should be open or closed.
|
|
43
|
+
* @param source Source element which triggered the flyout.
|
|
44
|
+
* @returns A promise that resolves when the flyout is being closed.
|
|
45
|
+
*/
|
|
46
|
+
toggle(flag: boolean, source?: Element): Promise<HintedType<R>>;
|
|
40
47
|
}
|
|
@@ -26,13 +26,13 @@ definePrototype(FlyoutToggleMixin, ClassNameMixin, {
|
|
|
26
26
|
close: function (value) {
|
|
27
27
|
return this.flyoutMixin.close(value);
|
|
28
28
|
},
|
|
29
|
-
toggle: function (source) {
|
|
30
|
-
return this.flyoutMixin.toggleSelf(source);
|
|
29
|
+
toggle: function (flag, source) {
|
|
30
|
+
return this.flyoutMixin.toggleSelf(flag, source);
|
|
31
31
|
},
|
|
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.1",
|
|
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",
|