@cleanweb/react 1.0.4 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- package/build/base/index.js +18 -2
- 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/methods.js +8 -4
- package/build/base/state.d.ts +13 -7
- package/build/base/state.js +49 -21
- package/build/classy/class.d.ts +6 -0
- package/build/classy/class.js +11 -8
- package/build/classy/index.js +19 -3
- package/build/classy/instance.d.ts +39 -1
- package/build/classy/instance.js +61 -16
- package/build/classy/logic.d.ts +3 -3
- package/build/classy/logic.js +11 -7
- package/build/globals.d.ts +2 -0
- package/build/index.js +29 -1
- package/build/tsconfig.json +2 -2
- package/package.json +6 -1
package/build/base/index.js
CHANGED
@@ -1,2 +1,18 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
|
+
};
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
+
__exportStar(require("./state"), exports);
|
18
|
+
__exportStar(require("./methods"), exports);
|
@@ -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/methods.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
"use strict";
|
1
2
|
var __assign = (this && this.__assign) || function () {
|
2
3
|
__assign = Object.assign || function(t) {
|
3
4
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
@@ -9,16 +10,18 @@ var __assign = (this && this.__assign) || function () {
|
|
9
10
|
};
|
10
11
|
return __assign.apply(this, arguments);
|
11
12
|
};
|
12
|
-
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
14
|
+
exports.useMethods = exports.ComponentMethods = void 0;
|
15
|
+
var react_1 = require("react");
|
13
16
|
var ComponentMethods = /** @class */ (function () {
|
14
17
|
function ComponentMethods() {
|
15
18
|
}
|
16
19
|
return ComponentMethods;
|
17
20
|
}());
|
18
|
-
|
21
|
+
exports.ComponentMethods = ComponentMethods;
|
19
22
|
;
|
20
|
-
|
21
|
-
var methods = useMemo(function () {
|
23
|
+
var useMethods = function (Methods, state, props) {
|
24
|
+
var methods = (0, react_1.useMemo)(function () {
|
22
25
|
// See useLogic implementation for a discussion of this type assertion.
|
23
26
|
return new Methods();
|
24
27
|
}, []);
|
@@ -27,3 +30,4 @@ export var useMethods = function (Methods, state, props) {
|
|
27
30
|
// Return a gate object to "passthrough" all methods but filter out properties that should be private.
|
28
31
|
return __assign(__assign({}, methods), { props: undefined, state: undefined });
|
29
32
|
};
|
33
|
+
exports.useMethods = useMethods;
|
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,24 +1,47 @@
|
|
1
|
-
|
2
|
-
var
|
3
|
-
function
|
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.useMountState = exports.useCleanState = void 0;
|
15
|
+
var react_1 = require("react");
|
16
|
+
var CleanStateBase = /** @class */ (function () {
|
17
|
+
function CleanStateBase() {
|
4
18
|
var _this = this;
|
19
|
+
this.valueKeys = [];
|
5
20
|
this._values_ = {};
|
6
21
|
this._setters_ = {};
|
7
|
-
this.put = this._setters_;
|
8
22
|
this.putMany = function (newValues) {
|
9
23
|
Object.entries(newValues).forEach(function (_a) {
|
10
24
|
var key = _a[0], value = _a[1];
|
11
25
|
_this.put[key](value);
|
12
26
|
});
|
13
27
|
};
|
14
|
-
|
15
|
-
|
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;
|
16
39
|
Object.entries(stateAndSetters).forEach(function (_a) {
|
17
40
|
var key = _a[0], responseFromUseState = _a[1];
|
18
|
-
if (reservedKeys.includes(key))
|
41
|
+
if (_this.reservedKeys.includes(key))
|
19
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);
|
20
44
|
_this._values_[key] = responseFromUseState[0], _this._setters_[key] = responseFromUseState[1];
|
21
|
-
// this.put[key] = this._setters_[key];
|
22
45
|
var self = _this;
|
23
46
|
Object.defineProperty(_this, key, {
|
24
47
|
get: function () {
|
@@ -30,11 +53,14 @@ var _CleanState_ = /** @class */ (function () {
|
|
30
53
|
enumerable: true,
|
31
54
|
});
|
32
55
|
});
|
33
|
-
|
34
|
-
|
56
|
+
// return this;
|
57
|
+
};
|
58
|
+
return CleanStateBase;
|
35
59
|
}());
|
36
60
|
;
|
37
|
-
var
|
61
|
+
var a;
|
62
|
+
var CleanState = CleanStateBase;
|
63
|
+
var na = new CleanState();
|
38
64
|
/**
|
39
65
|
* Linters complain about the use of a React hook within a loop because:
|
40
66
|
* > By following this rule, you ensure that Hooks are called in the same order each time a component renders.
|
@@ -44,11 +70,13 @@ var _CleanState = _CleanState_;
|
|
44
70
|
* and it guarantees that the same useState calls will be made on every render in the exact same order.
|
45
71
|
* Therefore, it is safe to silence the linters, and required for this implementation to work smoothly.
|
46
72
|
*/
|
47
|
-
var retrieveState = useState;
|
48
|
-
|
73
|
+
var retrieveState = react_1.useState;
|
74
|
+
var useCleanState = function (_initialState, props) {
|
49
75
|
var initialState = typeof _initialState === 'function' ? _initialState(props) : _initialState;
|
76
|
+
// props?.s
|
77
|
+
var cleanState = (0, react_1.useMemo)(function () { return new CleanState(); }, []);
|
50
78
|
var stateKeys = Object.keys(initialState);
|
51
|
-
var initialCount = useState(stateKeys.length)[0];
|
79
|
+
var initialCount = (0, react_1.useState)(stateKeys.length)[0];
|
52
80
|
if (stateKeys.length !== initialCount) {
|
53
81
|
throw new Error('The keys in your state object must be consistent throughout your components lifetime. Look up "rules of hooks" for more context.');
|
54
82
|
}
|
@@ -57,25 +85,25 @@ export var useCleanState = function (_initialState, props) {
|
|
57
85
|
var key = stateKeys_1[_i];
|
58
86
|
stateAndSetters[key] = retrieveState(initialState[key]);
|
59
87
|
}
|
60
|
-
|
61
|
-
|
62
|
-
// so keeping the CleanState wrapper persistent may be unnecessary.
|
63
|
-
return new _CleanState(stateAndSetters);
|
88
|
+
CleanState.update.call(cleanState, stateAndSetters);
|
89
|
+
return cleanState;
|
64
90
|
};
|
91
|
+
exports.useCleanState = useCleanState;
|
65
92
|
/**
|
66
93
|
* Returns a value that is false before the component has been mounted,
|
67
94
|
* then true during all subsequent rerenders.
|
68
95
|
*/
|
69
|
-
|
96
|
+
var useMountState = function () {
|
70
97
|
/**
|
71
98
|
* This must not be a stateful value. It should not be the cause of a rerender.
|
72
99
|
* It merely provides information about the render count,
|
73
100
|
* without influencing that count itself.
|
74
101
|
* So `mounted` should never be set with `useState`.
|
75
102
|
*/
|
76
|
-
var mounted = useRef(false);
|
77
|
-
useEffect(function () {
|
103
|
+
var mounted = (0, react_1.useRef)(false);
|
104
|
+
(0, react_1.useEffect)(function () {
|
78
105
|
mounted.current = true;
|
79
106
|
}, []);
|
80
107
|
return mounted.current;
|
81
108
|
};
|
109
|
+
exports.useMountState = useMountState;
|
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
@@ -1,3 +1,4 @@
|
|
1
|
+
"use strict";
|
1
2
|
var __extends = (this && this.__extends) || (function () {
|
2
3
|
var extendStatics = function (d, b) {
|
3
4
|
extendStatics = Object.setPrototypeOf ||
|
@@ -13,9 +14,11 @@ var __extends = (this && this.__extends) || (function () {
|
|
13
14
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
14
15
|
};
|
15
16
|
})();
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
18
|
+
exports.ClassComponent = void 0;
|
19
|
+
var jsx_runtime_1 = require("react/jsx-runtime");
|
20
|
+
var react_1 = require("react");
|
21
|
+
var instance_1 = require("./instance");
|
19
22
|
/** Provide more useful stack traces for otherwise non-specific function names. */
|
20
23
|
var setFunctionName = function (func, newName) {
|
21
24
|
try {
|
@@ -40,10 +43,10 @@ var ClassComponent = /** @class */ (function (_super) {
|
|
40
43
|
if (!Component.getInitialState || !isClassComponentType)
|
41
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()`).');
|
42
45
|
var Wrapper = function (props) {
|
43
|
-
var
|
46
|
+
var _a = (0, instance_1.useInstance)(Component, props), Render = _a.Render, instanceId = _a.instanceId;
|
44
47
|
// Add calling component name to Render function name in stack traces.
|
45
|
-
useMemo(function () { return setFunctionName(Render, "".concat(Component.name, ".Render")); }, []);
|
46
|
-
return
|
48
|
+
(0, react_1.useMemo)(function () { return setFunctionName(Render, "".concat(Component.name, ".Render")); }, []);
|
49
|
+
return (0, jsx_runtime_1.jsx)(Render, {}, instanceId);
|
47
50
|
};
|
48
51
|
// Include calling component name in wrapper function name on stack traces.
|
49
52
|
var wrapperName = "ClassComponent".concat(Wrapper.name, " > ").concat(Component.name);
|
@@ -51,5 +54,5 @@ var ClassComponent = /** @class */ (function (_super) {
|
|
51
54
|
return Wrapper;
|
52
55
|
};
|
53
56
|
return ClassComponent;
|
54
|
-
}(ComponentInstance));
|
55
|
-
|
57
|
+
}(instance_1.ComponentInstance));
|
58
|
+
exports.ClassComponent = ClassComponent;
|
package/build/classy/index.js
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
|
+
};
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
+
__exportStar(require("./logic"), exports);
|
18
|
+
__exportStar(require("./instance"), exports);
|
19
|
+
__exportStar(require("./class"), exports);
|
@@ -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
@@ -1,3 +1,4 @@
|
|
1
|
+
"use strict";
|
1
2
|
var __extends = (this && this.__extends) || (function () {
|
2
3
|
var extendStatics = function (d, b) {
|
3
4
|
extendStatics = Object.setPrototypeOf ||
|
@@ -13,37 +14,79 @@ var __extends = (this && this.__extends) || (function () {
|
|
13
14
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
14
15
|
};
|
15
16
|
})();
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
18
|
+
exports.useInstance = exports.useMountCallbacks = exports.ComponentInstance = exports.noOp = void 0;
|
19
|
+
var react_1 = require("react");
|
20
|
+
var state_1 = require("../base/state");
|
21
|
+
var logic_1 = require("./logic");
|
22
|
+
var noOp = function () { };
|
23
|
+
exports.noOp = noOp;
|
20
24
|
var ComponentInstance = /** @class */ (function (_super) {
|
21
25
|
__extends(ComponentInstance, _super);
|
22
26
|
function ComponentInstance() {
|
23
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
|
+
*/
|
24
37
|
_this.beforeMount = function () { };
|
25
|
-
|
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
|
+
*/
|
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
|
+
*/
|
26
56
|
_this.beforeRender = function () { };
|
27
|
-
|
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
|
+
*/
|
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
|
+
*/
|
28
70
|
_this.cleanUp = function () { };
|
29
71
|
return _this;
|
30
72
|
}
|
31
73
|
return ComponentInstance;
|
32
|
-
}(ComponentLogic));
|
33
|
-
|
74
|
+
}(logic_1.ComponentLogic));
|
75
|
+
exports.ComponentInstance = ComponentInstance;
|
34
76
|
;
|
35
|
-
|
77
|
+
var useMountCallbacks = function (instance) {
|
36
78
|
var _a;
|
37
|
-
var mounted = useMountState();
|
79
|
+
var mounted = (0, state_1.useMountState)();
|
38
80
|
if (!mounted)
|
39
81
|
(_a = instance.beforeMount) === null || _a === void 0 ? void 0 : _a.call(instance);
|
40
|
-
useEffect(function () {
|
82
|
+
(0, react_1.useEffect)(function () {
|
41
83
|
var _a;
|
42
84
|
var mountHandlerCleanUp = (_a = instance.onMount) === null || _a === void 0 ? void 0 : _a.call(instance);
|
43
85
|
return function () {
|
44
86
|
var doCleanUp = function (runMountCleaners) {
|
45
87
|
var _a;
|
46
88
|
runMountCleaners === null || runMountCleaners === void 0 ? void 0 : runMountCleaners();
|
89
|
+
// onDismount? willUnmount?
|
47
90
|
(_a = instance.cleanUp) === null || _a === void 0 ? void 0 : _a.call(instance);
|
48
91
|
};
|
49
92
|
if (typeof mountHandlerCleanUp === 'function') {
|
@@ -55,14 +98,15 @@ export var useMountCallbacks = function (instance) {
|
|
55
98
|
};
|
56
99
|
}, []);
|
57
100
|
};
|
58
|
-
|
101
|
+
exports.useMountCallbacks = useMountCallbacks;
|
102
|
+
var useInstance = function (Component, props) {
|
59
103
|
var _a;
|
60
|
-
//
|
61
|
-
var instance = useLogic(Component, props);
|
104
|
+
// useHooks.
|
105
|
+
var instance = (0, logic_1.useLogic)(Component, props);
|
62
106
|
// beforeMount, onMount, cleanUp.
|
63
|
-
useMountCallbacks(instance);
|
107
|
+
(0, exports.useMountCallbacks)(instance);
|
64
108
|
(_a = instance.beforeRender) === null || _a === void 0 ? void 0 : _a.call(instance);
|
65
|
-
useEffect(function () {
|
109
|
+
(0, react_1.useEffect)(function () {
|
66
110
|
var _a;
|
67
111
|
var cleanupAfterRerender = (_a = instance.onRender) === null || _a === void 0 ? void 0 : _a.call(instance);
|
68
112
|
return function () {
|
@@ -79,3 +123,4 @@ export var useInstance = function (Component, props) {
|
|
79
123
|
});
|
80
124
|
return instance;
|
81
125
|
};
|
126
|
+
exports.useInstance = useInstance;
|
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
@@ -1,26 +1,30 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.useLogic = exports.ComponentLogic = void 0;
|
4
|
+
var react_1 = require("react");
|
5
|
+
var state_1 = require("../base/state");
|
3
6
|
var ComponentLogic = /** @class */ (function () {
|
4
7
|
function ComponentLogic() {
|
5
8
|
}
|
6
9
|
return ComponentLogic;
|
7
10
|
}());
|
8
|
-
|
11
|
+
exports.ComponentLogic = ComponentLogic;
|
9
12
|
;
|
10
|
-
|
13
|
+
var useLogic = function (Methods, props) {
|
11
14
|
var _a;
|
12
|
-
var state = useCleanState(Methods.getInitialState, props);
|
15
|
+
var state = (0, state_1.useCleanState)(Methods.getInitialState, props);
|
13
16
|
// There's apparently a bug? with Typescript that pegs the return type of "new Methods()" to "ComponentLogic<{}, {}, {}>",
|
14
17
|
// completely ignoring the type specified for Methods in the function's type definition.
|
15
18
|
// `new Methods()` should return whatever the InstanceType of TClass is, as that is the type explicitly specified for Methods.
|
16
19
|
// Ignoring the specified type to gin up something else and then complain about it is quite weird.
|
17
20
|
// Regardless, even when `extends ComponentLogicConstructor<TState, TProps, THooks>` is specified using generics instead of a set type,
|
18
21
|
// the issue persists. Which is absurd since this should ensure that InstanceType<Class> should exactly match ComponentLogic<TState, TProps, THooks>
|
19
|
-
var methods = useMemo(function () {
|
22
|
+
var methods = (0, react_1.useMemo)(function () {
|
20
23
|
return new Methods();
|
21
24
|
}, []);
|
22
25
|
methods.state = state;
|
23
26
|
methods.props = props;
|
24
|
-
methods.hooks = ((_a = methods.
|
27
|
+
methods.hooks = ((_a = methods.useHooks) === null || _a === void 0 ? void 0 : _a.call(methods)) || {};
|
25
28
|
return methods;
|
26
29
|
};
|
30
|
+
exports.useLogic = useLogic;
|
package/build/globals.d.ts
CHANGED
package/build/index.js
CHANGED
@@ -1 +1,29 @@
|
|
1
|
-
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
|
+
};
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
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.
|
package/build/tsconfig.json
CHANGED
@@ -23,8 +23,8 @@
|
|
23
23
|
"forceConsistentCasingInFileNames": true,
|
24
24
|
"incremental": false,
|
25
25
|
"esModuleInterop": true,
|
26
|
-
"module": "
|
27
|
-
"moduleResolution": "
|
26
|
+
"module": "NodeNext",
|
27
|
+
"moduleResolution": "NodeNext",
|
28
28
|
"resolveJsonModule": true,
|
29
29
|
"isolatedModules": true,
|
30
30
|
"jsx": "react-jsx",
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@cleanweb/react",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.6",
|
4
4
|
"description": "A suite of helpers for writing cleaner React function components.",
|
5
5
|
"engines": {
|
6
6
|
"node": ">=18"
|
@@ -10,6 +10,11 @@
|
|
10
10
|
".npmrc"
|
11
11
|
],
|
12
12
|
"main": "build/index.js",
|
13
|
+
".": {
|
14
|
+
"require": "./src/index.cjs",
|
15
|
+
"import": "./src/index.mjs"
|
16
|
+
},
|
17
|
+
"//type": "module",
|
13
18
|
"exports": {
|
14
19
|
".": "./build/index.js",
|
15
20
|
"./base": "./build/base/index.js",
|