@cleanweb/react 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- package/build/base/merged-state.d.ts +16 -0
- package/build/base/merged-state.js +79 -0
- package/build/base/methods.d.ts +2 -2
- package/build/base/state.d.ts +13 -7
- package/build/base/state.js +37 -14
- package/build/classy/class.d.ts +6 -0
- package/build/classy/class.js +2 -2
- package/build/classy/instance.d.ts +39 -1
- package/build/classy/instance.js +40 -1
- package/build/classy/logic.d.ts +3 -3
- package/build/classy/logic.js +1 -1
- package/build/globals.d.ts +2 -0
- package/build/index.js +12 -0
- package/package.json +1 -1
@@ -0,0 +1,16 @@
|
|
1
|
+
declare class MergedState<TState extends object> {
|
2
|
+
static refresh<TState extends object>(this: MergedState<TState>): void;
|
3
|
+
reservedKeys: string[];
|
4
|
+
valueKeys: string[];
|
5
|
+
private _initialValues_;
|
6
|
+
private _values_;
|
7
|
+
private setState;
|
8
|
+
private _setters_;
|
9
|
+
private useRetrieveState;
|
10
|
+
get put(): { [Key in keyof TState]: (value: TState[Key]) => void; };
|
11
|
+
get initialState(): TState;
|
12
|
+
constructor(initialState: TState);
|
13
|
+
putMany: (newValues: Partial<TState>) => void;
|
14
|
+
}
|
15
|
+
export declare const useMergedState: <TState extends object>(initialState: TState) => MergedState<TState> & TState;
|
16
|
+
export {};
|
@@ -0,0 +1,79 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
3
|
+
__assign = Object.assign || function(t) {
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
5
|
+
s = arguments[i];
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
7
|
+
t[p] = s[p];
|
8
|
+
}
|
9
|
+
return t;
|
10
|
+
};
|
11
|
+
return __assign.apply(this, arguments);
|
12
|
+
};
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
14
|
+
exports.useMergedState = void 0;
|
15
|
+
var react_1 = require("react");
|
16
|
+
var MergedState = /** @class */ (function () {
|
17
|
+
function MergedState(initialState) {
|
18
|
+
var _this = this;
|
19
|
+
this._initialValues_ = {};
|
20
|
+
this._values_ = {};
|
21
|
+
this._setters_ = {};
|
22
|
+
this.useRetrieveState = function () {
|
23
|
+
var _a;
|
24
|
+
_a = (0, react_1.useState)(_this.initialState), _this._values_ = _a[0], _this.setState = _a[1];
|
25
|
+
};
|
26
|
+
this.putMany = function (newValues) {
|
27
|
+
_this.setState(__assign(__assign({}, _this._values_), newValues));
|
28
|
+
};
|
29
|
+
this.reservedKeys = Object.keys(this);
|
30
|
+
this.valueKeys = [];
|
31
|
+
this._initialValues_ = __assign({}, initialState);
|
32
|
+
this._values_ = __assign({}, initialState);
|
33
|
+
Object.keys(initialState).forEach(function (key) {
|
34
|
+
if (_this.reservedKeys.includes(key)) {
|
35
|
+
throw new Error("The name \"".concat(key, "\" is reserved by CleanState and cannot be used to index state variables. Please use a different key."));
|
36
|
+
}
|
37
|
+
_this.valueKeys.push(key);
|
38
|
+
_this._setters_[key] = function (value) {
|
39
|
+
var _a;
|
40
|
+
// this._values_[key] = value;
|
41
|
+
_this.setState(__assign(__assign({}, _this._values_), (_a = {}, _a[key] = value, _a)));
|
42
|
+
};
|
43
|
+
var self = _this;
|
44
|
+
Object.defineProperty(_this, key, {
|
45
|
+
get: function () {
|
46
|
+
return self._values_[key];
|
47
|
+
},
|
48
|
+
set: function (value) {
|
49
|
+
self._setters_[key](value);
|
50
|
+
},
|
51
|
+
enumerable: true,
|
52
|
+
});
|
53
|
+
});
|
54
|
+
}
|
55
|
+
MergedState.refresh = function () {
|
56
|
+
this.useRetrieveState();
|
57
|
+
};
|
58
|
+
Object.defineProperty(MergedState.prototype, "put", {
|
59
|
+
get: function () {
|
60
|
+
return __assign({}, this._setters_);
|
61
|
+
},
|
62
|
+
enumerable: false,
|
63
|
+
configurable: true
|
64
|
+
});
|
65
|
+
Object.defineProperty(MergedState.prototype, "initialState", {
|
66
|
+
get: function () {
|
67
|
+
return __assign({}, this._initialValues_);
|
68
|
+
},
|
69
|
+
enumerable: false,
|
70
|
+
configurable: true
|
71
|
+
});
|
72
|
+
return MergedState;
|
73
|
+
}());
|
74
|
+
var useMergedState = function (initialState) {
|
75
|
+
var cleanState = (0, react_1.useMemo)(function () { return new MergedState(initialState); }, []);
|
76
|
+
MergedState.refresh.call(cleanState);
|
77
|
+
return cleanState;
|
78
|
+
};
|
79
|
+
exports.useMergedState = useMergedState;
|
package/build/base/methods.d.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
import type {
|
1
|
+
import type { TCleanState } from './state';
|
2
2
|
export declare class ComponentMethods<TState extends object, TProps extends object> {
|
3
|
-
state:
|
3
|
+
state: TCleanState<TState>;
|
4
4
|
props: TProps;
|
5
5
|
}
|
6
6
|
type ComponentMethodsConstructor = typeof ComponentMethods<any, any>;
|
package/build/base/state.d.ts
CHANGED
@@ -5,18 +5,24 @@ type TUseStateArray<TState extends object> = [
|
|
5
5
|
type TUseStateResponses<TState extends object> = {
|
6
6
|
[Key in keyof TState]: TUseStateArray<TState>;
|
7
7
|
};
|
8
|
-
declare class
|
8
|
+
declare class CleanStateBase<TState extends object> {
|
9
|
+
static update: ICleanStateClass['update'];
|
10
|
+
reservedKeys: string[];
|
11
|
+
valueKeys: string[];
|
9
12
|
private _values_;
|
10
13
|
private _setters_;
|
11
|
-
put: { [Key in keyof TState]: (value: TState[Key]) => void; };
|
12
|
-
constructor(
|
14
|
+
get put(): { [Key in keyof TState]: (value: TState[Key]) => void; };
|
15
|
+
constructor();
|
13
16
|
putMany: (newValues: Partial<TState>) => void;
|
14
17
|
}
|
15
|
-
type TCleanStateInstance<TState extends object> = TState &
|
16
|
-
|
17
|
-
|
18
|
+
type TCleanStateInstance<TState extends object> = TState & CleanStateBase<TState>;
|
19
|
+
interface ICleanStateClass {
|
20
|
+
update: <TState extends object>(this: CleanStateBase<TState>, stateAndSetters: TUseStateResponses<TState>) => void;
|
21
|
+
}
|
22
|
+
export type TCleanState<TState extends object> = TCleanStateInstance<TState>;
|
18
23
|
type Func = (...params: any[]) => any;
|
19
|
-
type UseCleanState = <
|
24
|
+
type UseCleanState = <TState extends object, TProps extends object = object>(_initialState: ((props?: TProps) => TState) | TState, // TStateObjOrFactory,
|
25
|
+
props?: typeof _initialState extends Func ? TProps : undefined) => TCleanState<TState>;
|
20
26
|
export declare const useCleanState: UseCleanState;
|
21
27
|
/**
|
22
28
|
* Returns a value that is false before the component has been mounted,
|
package/build/base/state.js
CHANGED
@@ -1,27 +1,47 @@
|
|
1
1
|
"use strict";
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
3
|
+
__assign = Object.assign || function(t) {
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
5
|
+
s = arguments[i];
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
7
|
+
t[p] = s[p];
|
8
|
+
}
|
9
|
+
return t;
|
10
|
+
};
|
11
|
+
return __assign.apply(this, arguments);
|
12
|
+
};
|
2
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
14
|
exports.useMountState = exports.useCleanState = void 0;
|
4
15
|
var react_1 = require("react");
|
5
|
-
var
|
6
|
-
function
|
16
|
+
var CleanStateBase = /** @class */ (function () {
|
17
|
+
function CleanStateBase() {
|
7
18
|
var _this = this;
|
19
|
+
this.valueKeys = [];
|
8
20
|
this._values_ = {};
|
9
21
|
this._setters_ = {};
|
10
|
-
this.put = this._setters_;
|
11
22
|
this.putMany = function (newValues) {
|
12
23
|
Object.entries(newValues).forEach(function (_a) {
|
13
24
|
var key = _a[0], value = _a[1];
|
14
25
|
_this.put[key](value);
|
15
26
|
});
|
16
27
|
};
|
17
|
-
|
18
|
-
|
28
|
+
this.reservedKeys = Object.keys(this);
|
29
|
+
}
|
30
|
+
Object.defineProperty(CleanStateBase.prototype, "put", {
|
31
|
+
get: function () {
|
32
|
+
return __assign({}, this._setters_);
|
33
|
+
},
|
34
|
+
enumerable: false,
|
35
|
+
configurable: true
|
36
|
+
});
|
37
|
+
CleanStateBase.update = function update(stateAndSetters) {
|
38
|
+
var _this = this;
|
19
39
|
Object.entries(stateAndSetters).forEach(function (_a) {
|
20
40
|
var key = _a[0], responseFromUseState = _a[1];
|
21
|
-
if (reservedKeys.includes(key))
|
41
|
+
if (_this.reservedKeys.includes(key))
|
22
42
|
throw new Error("The name \"".concat(key, "\" is reserved by CleanState and cannot be used to index state variables. Please use a different key."));
|
43
|
+
_this.valueKeys.push(key);
|
23
44
|
_this._values_[key] = responseFromUseState[0], _this._setters_[key] = responseFromUseState[1];
|
24
|
-
// this.put[key] = this._setters_[key];
|
25
45
|
var self = _this;
|
26
46
|
Object.defineProperty(_this, key, {
|
27
47
|
get: function () {
|
@@ -33,11 +53,14 @@ var _CleanState_ = /** @class */ (function () {
|
|
33
53
|
enumerable: true,
|
34
54
|
});
|
35
55
|
});
|
36
|
-
|
37
|
-
|
56
|
+
// return this;
|
57
|
+
};
|
58
|
+
return CleanStateBase;
|
38
59
|
}());
|
39
60
|
;
|
40
|
-
var
|
61
|
+
var a;
|
62
|
+
var CleanState = CleanStateBase;
|
63
|
+
var na = new CleanState();
|
41
64
|
/**
|
42
65
|
* Linters complain about the use of a React hook within a loop because:
|
43
66
|
* > By following this rule, you ensure that Hooks are called in the same order each time a component renders.
|
@@ -50,6 +73,8 @@ var _CleanState = _CleanState_;
|
|
50
73
|
var retrieveState = react_1.useState;
|
51
74
|
var useCleanState = function (_initialState, props) {
|
52
75
|
var initialState = typeof _initialState === 'function' ? _initialState(props) : _initialState;
|
76
|
+
// props?.s
|
77
|
+
var cleanState = (0, react_1.useMemo)(function () { return new CleanState(); }, []);
|
53
78
|
var stateKeys = Object.keys(initialState);
|
54
79
|
var initialCount = (0, react_1.useState)(stateKeys.length)[0];
|
55
80
|
if (stateKeys.length !== initialCount) {
|
@@ -60,10 +85,8 @@ var useCleanState = function (_initialState, props) {
|
|
60
85
|
var key = stateKeys_1[_i];
|
61
86
|
stateAndSetters[key] = retrieveState(initialState[key]);
|
62
87
|
}
|
63
|
-
|
64
|
-
|
65
|
-
// so keeping the CleanState wrapper persistent may be unnecessary.
|
66
|
-
return new _CleanState(stateAndSetters);
|
88
|
+
CleanState.update.call(cleanState, stateAndSetters);
|
89
|
+
return cleanState;
|
67
90
|
};
|
68
91
|
exports.useCleanState = useCleanState;
|
69
92
|
/**
|
package/build/classy/class.d.ts
CHANGED
@@ -5,6 +5,12 @@ type Obj = Record<string, any>;
|
|
5
5
|
type IComponentConstructor = ComponentInstanceConstructor<any, any, any> & typeof ClassComponent<any, any, any>;
|
6
6
|
export declare class ClassComponent<TState extends Obj, TProps extends Obj, THooks extends Obj> extends ComponentInstance<TState, TProps, THooks> {
|
7
7
|
Render: FunctionComponent<TProps>;
|
8
|
+
/**
|
9
|
+
* Use this to let React know whenever you would like all of your instance's state to be reset.
|
10
|
+
* When the value is changed, React will reset all state variables to their initial value the next time your component re-renders.
|
11
|
+
* @see https://react.dev/learn/you-might-not-need-an-effect#resetting-all-state-when-a-prop-changes
|
12
|
+
*/
|
13
|
+
instanceId?: string;
|
8
14
|
static FC: <IComponentType extends IComponentConstructor>(this: IComponentType, _Component?: IComponentType) => (props: InstanceType<IComponentType>["props"]) => JSX.Element;
|
9
15
|
}
|
10
16
|
export {};
|
package/build/classy/class.js
CHANGED
@@ -43,10 +43,10 @@ var ClassComponent = /** @class */ (function (_super) {
|
|
43
43
|
if (!Component.getInitialState || !isClassComponentType)
|
44
44
|
throw new Error('Attempted to initialize ClassComponent with invalid Class type. Either pass a class that extends ClassComponent to FC (e.g `export FC(MyComponent);`), or ensure it is called as a method on a ClassComponent constructor type (e.g `export MyComponent.FC()`).');
|
45
45
|
var Wrapper = function (props) {
|
46
|
-
var
|
46
|
+
var _a = (0, instance_1.useInstance)(Component, props), Render = _a.Render, instanceId = _a.instanceId;
|
47
47
|
// Add calling component name to Render function name in stack traces.
|
48
48
|
(0, react_1.useMemo)(function () { return setFunctionName(Render, "".concat(Component.name, ".Render")); }, []);
|
49
|
-
return (0, jsx_runtime_1.jsx)(Render, {});
|
49
|
+
return (0, jsx_runtime_1.jsx)(Render, {}, instanceId);
|
50
50
|
};
|
51
51
|
// Include calling component name in wrapper function name on stack traces.
|
52
52
|
var wrapperName = "ClassComponent".concat(Wrapper.name, " > ").concat(Component.name);
|
@@ -1,13 +1,51 @@
|
|
1
1
|
import type { ComponentLogicConstructor } from './logic';
|
2
2
|
import { ComponentLogic } from './logic';
|
3
3
|
type Obj = Record<string, any>;
|
4
|
-
type AsyncAllowedEffectCallback = () =>
|
4
|
+
type AsyncAllowedEffectCallback = () => Awaitable<IVoidFunction>;
|
5
5
|
export declare const noOp: () => void;
|
6
6
|
export declare class ComponentInstance<TState extends Obj = {}, TProps extends Obj = {}, THooks extends Obj = {}> extends ComponentLogic<TState, TProps, THooks> {
|
7
|
+
/**
|
8
|
+
* Runs only _before_ first render, i.e before the component instance is mounted.
|
9
|
+
* Useful for logic that is involved in determining what to render.
|
10
|
+
*
|
11
|
+
* Updating local state from in here will abort the render cycle early, before changes are committed to the DOM,
|
12
|
+
* and prompt React to immediately rerender the component with the updated state value(s).
|
13
|
+
*
|
14
|
+
* Ignored on subsequent rerenders.
|
15
|
+
*/
|
7
16
|
beforeMount: IVoidFunction;
|
17
|
+
/**
|
18
|
+
* Runs only **_after_** first render, i.e after the component instance is mounted.
|
19
|
+
*
|
20
|
+
* Should usually only be used for logic that does not directly take part in determining what to render, like
|
21
|
+
* synchronize your component with some external system.
|
22
|
+
*
|
23
|
+
* Ignored on subsequent rerenders.
|
24
|
+
*
|
25
|
+
* Returns a cleanup function.
|
26
|
+
*/
|
8
27
|
onMount: AsyncAllowedEffectCallback;
|
28
|
+
/**
|
29
|
+
* Runs _before_ every render cycle, including the first.
|
30
|
+
* Useful for logic that is involved in determining what to render.
|
31
|
+
*
|
32
|
+
* Updating local state from in here will abort the render cycle early, before changes are committed to the DOM,
|
33
|
+
* and prompt React to immediately rerender the component with the updated state value(s).
|
34
|
+
*/
|
9
35
|
beforeRender: IVoidFunction;
|
36
|
+
/**
|
37
|
+
* Runs **_after_** every render cycle, including the first.
|
38
|
+
*
|
39
|
+
* Should usually only be used for logic that does not directly take part in determining what to render, like
|
40
|
+
* synchronize your component with some external system.
|
41
|
+
*
|
42
|
+
* Returns a cleanup function.
|
43
|
+
*/
|
10
44
|
onRender: AsyncAllowedEffectCallback;
|
45
|
+
/**
|
46
|
+
* Runs when the component is unmounted.
|
47
|
+
* It is called _after_ the cleanup function returned by onMount.
|
48
|
+
*/
|
11
49
|
cleanUp: IVoidFunction;
|
12
50
|
}
|
13
51
|
type ComponentClassBaseType<TState extends Obj = {}, TProps extends Obj = {}, THooks extends Obj = {}> = ComponentLogicConstructor<TState, TProps, THooks> & Constructor<ComponentInstance<TState, TProps, THooks>>;
|
package/build/classy/instance.js
CHANGED
@@ -25,10 +25,48 @@ var ComponentInstance = /** @class */ (function (_super) {
|
|
25
25
|
__extends(ComponentInstance, _super);
|
26
26
|
function ComponentInstance() {
|
27
27
|
var _this = _super !== null && _super.apply(this, arguments) || this;
|
28
|
+
/**
|
29
|
+
* Runs only _before_ first render, i.e before the component instance is mounted.
|
30
|
+
* Useful for logic that is involved in determining what to render.
|
31
|
+
*
|
32
|
+
* Updating local state from in here will abort the render cycle early, before changes are committed to the DOM,
|
33
|
+
* and prompt React to immediately rerender the component with the updated state value(s).
|
34
|
+
*
|
35
|
+
* Ignored on subsequent rerenders.
|
36
|
+
*/
|
28
37
|
_this.beforeMount = function () { };
|
38
|
+
/**
|
39
|
+
* Runs only **_after_** first render, i.e after the component instance is mounted.
|
40
|
+
*
|
41
|
+
* Should usually only be used for logic that does not directly take part in determining what to render, like
|
42
|
+
* synchronize your component with some external system.
|
43
|
+
*
|
44
|
+
* Ignored on subsequent rerenders.
|
45
|
+
*
|
46
|
+
* Returns a cleanup function.
|
47
|
+
*/
|
29
48
|
_this.onMount = function () { return exports.noOp; };
|
49
|
+
/**
|
50
|
+
* Runs _before_ every render cycle, including the first.
|
51
|
+
* Useful for logic that is involved in determining what to render.
|
52
|
+
*
|
53
|
+
* Updating local state from in here will abort the render cycle early, before changes are committed to the DOM,
|
54
|
+
* and prompt React to immediately rerender the component with the updated state value(s).
|
55
|
+
*/
|
30
56
|
_this.beforeRender = function () { };
|
57
|
+
/**
|
58
|
+
* Runs **_after_** every render cycle, including the first.
|
59
|
+
*
|
60
|
+
* Should usually only be used for logic that does not directly take part in determining what to render, like
|
61
|
+
* synchronize your component with some external system.
|
62
|
+
*
|
63
|
+
* Returns a cleanup function.
|
64
|
+
*/
|
31
65
|
_this.onRender = function () { return exports.noOp; };
|
66
|
+
/**
|
67
|
+
* Runs when the component is unmounted.
|
68
|
+
* It is called _after_ the cleanup function returned by onMount.
|
69
|
+
*/
|
32
70
|
_this.cleanUp = function () { };
|
33
71
|
return _this;
|
34
72
|
}
|
@@ -48,6 +86,7 @@ var useMountCallbacks = function (instance) {
|
|
48
86
|
var doCleanUp = function (runMountCleaners) {
|
49
87
|
var _a;
|
50
88
|
runMountCleaners === null || runMountCleaners === void 0 ? void 0 : runMountCleaners();
|
89
|
+
// onDismount? willUnmount?
|
51
90
|
(_a = instance.cleanUp) === null || _a === void 0 ? void 0 : _a.call(instance);
|
52
91
|
};
|
53
92
|
if (typeof mountHandlerCleanUp === 'function') {
|
@@ -62,7 +101,7 @@ var useMountCallbacks = function (instance) {
|
|
62
101
|
exports.useMountCallbacks = useMountCallbacks;
|
63
102
|
var useInstance = function (Component, props) {
|
64
103
|
var _a;
|
65
|
-
//
|
104
|
+
// useHooks.
|
66
105
|
var instance = (0, logic_1.useLogic)(Component, props);
|
67
106
|
// beforeMount, onMount, cleanUp.
|
68
107
|
(0, exports.useMountCallbacks)(instance);
|
package/build/classy/logic.d.ts
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
import type {
|
1
|
+
import type { TCleanState } from '../base/state';
|
2
2
|
export declare class ComponentLogic<TState extends object, TProps extends object, THooks extends object> {
|
3
|
-
state:
|
3
|
+
state: TCleanState<TState>;
|
4
4
|
props: TProps;
|
5
5
|
hooks: THooks;
|
6
|
-
|
6
|
+
useHooks?: () => THooks;
|
7
7
|
}
|
8
8
|
export interface ComponentLogicConstructor<TState extends object, TProps extends object, THooks extends object> extends Constructor<ComponentLogic<TState, TProps, THooks>> {
|
9
9
|
getInitialState: (props?: TProps) => TState;
|
package/build/classy/logic.js
CHANGED
@@ -24,7 +24,7 @@ var useLogic = function (Methods, props) {
|
|
24
24
|
}, []);
|
25
25
|
methods.state = state;
|
26
26
|
methods.props = props;
|
27
|
-
methods.hooks = ((_a = methods.
|
27
|
+
methods.hooks = ((_a = methods.useHooks) === null || _a === void 0 ? void 0 : _a.call(methods)) || {};
|
28
28
|
return methods;
|
29
29
|
};
|
30
30
|
exports.useLogic = useLogic;
|
package/build/globals.d.ts
CHANGED
package/build/index.js
CHANGED
@@ -15,3 +15,15 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
15
15
|
};
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
17
17
|
__exportStar(require("./classy"), exports);
|
18
|
+
// PS: Document component inheritance pattern with lifecycle callback arrays and namespaces.
|
19
|
+
// Due to react's remounting behaviour, components must externally track when some logic has run, if it really really must only ever run once per mounted instance. Tricky to get right for components that may have multiple instance rendered simultaneously at different parts of a page.
|
20
|
+
// Note: There is an alternative clean-state implementation that uses a single useState call and passes the clean state instance.
|
21
|
+
// Then when a state setter is used, it mutates the cleanstate object, then calls setState on the updated cleanstate.
|
22
|
+
// But setState might ignore calls with the same object ref as the existing state value, so perhaps create a new cleanstate
|
23
|
+
// instance instead, spreading existing values with the changed values, and call setState with that.
|
24
|
+
// It could be more performant as it would remove the need for looping over Object.keys in useCleanState.
|
25
|
+
// Investigate this for a potential minor version update.
|
26
|
+
// useCleanState => useState
|
27
|
+
// useMethods => useCallback
|
28
|
+
// useLogic => useCallback + all other hook calls.
|
29
|
+
// useInstance => useLogic + lifecycle methods.
|