@cleanweb/react 1.0.10 → 1.1.1-beta.0
Sign up to get free protection for your applications and to get access to all the features.
- package/build/base/merged-state.js +2 -1
- package/build/base/methods.d.ts +1 -2
- package/build/base/methods.js +2 -2
- package/build/base/state.d.ts +16 -12
- package/build/base/state.js +57 -24
- package/build/classy/class.d.ts +7 -8
- package/build/classy/class.js +31 -11
- package/build/classy/instance.d.ts +14 -8
- package/build/classy/instance.js +60 -23
- package/build/classy/logic.d.ts +14 -5
- package/build/classy/logic.js +46 -10
- package/build/globals.d.ts +63 -52
- package/build/globals.js +22 -0
- package/build/globals.private.d.ts +48 -0
- package/build/globals.private.js +40 -0
- package/build/tsconfig.json +5 -2
- package/package.json +18 -2
@@ -26,7 +26,8 @@ var MergedState = /** @class */ (function () {
|
|
26
26
|
this.valueKeys = [];
|
27
27
|
this._initialValues_ = __assign({}, initialState);
|
28
28
|
this._values_ = __assign({}, initialState);
|
29
|
-
Object.keys(initialState).forEach(function (
|
29
|
+
Object.keys(initialState).forEach(function (_key) {
|
30
|
+
var key = _key;
|
30
31
|
if (_this.reservedKeys.includes(key)) {
|
31
32
|
throw new Error("The name \"".concat(key, "\" is reserved by CleanState and cannot be used to index state variables. Please use a different key."));
|
32
33
|
}
|
package/build/base/methods.d.ts
CHANGED
@@ -3,7 +3,6 @@ export declare class ComponentMethods<TState extends object, TProps extends obje
|
|
3
3
|
state: TCleanState<TState>;
|
4
4
|
props: TProps;
|
5
5
|
}
|
6
|
-
type
|
7
|
-
type UseMethods = <MethodsClass extends ComponentMethodsConstructor>(Methods: MethodsClass, state: InstanceType<MethodsClass>['state'], props: InstanceType<MethodsClass>['props']) => InstanceType<MethodsClass>;
|
6
|
+
type UseMethods = <TMethods extends ComponentMethods<any, any>>(Methods: Constructor<TMethods>, state: TMethods['state'], props: TMethods['props']) => TMethods;
|
8
7
|
export declare const useMethods: UseMethods;
|
9
8
|
export {};
|
package/build/base/methods.js
CHANGED
@@ -14,10 +14,10 @@ var useMethods = function (Methods, state, props) {
|
|
14
14
|
// causing the instance to be unexpectedly recreated in the middle of the components lifecycle.
|
15
15
|
// But useRef and useState values appear to always be preserved whenever this happens.
|
16
16
|
// So those two are the only cross-render-persistence methods we can consider safe.
|
17
|
-
var methods = (0, react_1.useMemo)(function () {
|
17
|
+
var methods = (0, react_1.useRef)((0, react_1.useMemo)(function () {
|
18
18
|
// See useLogic implementation for a discussion of this type assertion.
|
19
19
|
return new Methods();
|
20
|
-
}, []);
|
20
|
+
}, [])).current;
|
21
21
|
methods.state = state;
|
22
22
|
methods.props = props;
|
23
23
|
return methods;
|
package/build/base/state.d.ts
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
|
1
|
+
/**
|
2
|
+
* Returns a value that is false before the component has been mounted,
|
3
|
+
* then true during all subsequent rerenders.
|
4
|
+
*/
|
5
|
+
export declare const useMountState: () => boolean;
|
6
|
+
type PutState<TState extends object> = {
|
7
|
+
[Key in keyof TState]: React.Dispatch<React.SetStateAction<TState[Key]>>;
|
8
|
+
};
|
9
|
+
declare class CleanStateBase<TState extends Record<string, any>> {
|
2
10
|
reservedKeys: string[];
|
3
11
|
valueKeys: string[];
|
4
12
|
private _values_;
|
@@ -6,20 +14,16 @@ declare class CleanStateBase<TState extends object> {
|
|
6
14
|
private _setters_;
|
7
15
|
constructor(initialState: TState);
|
8
16
|
static update: <TState_1 extends object>(this: CleanStateBase<TState_1>) => void;
|
9
|
-
get put():
|
17
|
+
get put(): PutState<TState>;
|
10
18
|
get initialState(): TState;
|
11
19
|
putMany: (newValues: Partial<TState>) => void;
|
12
20
|
}
|
13
21
|
type TCleanStateInstance<TState extends object> = TState & CleanStateBase<TState>;
|
14
22
|
export type TCleanState<TState extends object> = TCleanStateInstance<TState>;
|
15
|
-
type
|
16
|
-
type
|
17
|
-
type
|
18
|
-
type
|
19
|
-
|
20
|
-
|
21
|
-
* Returns a value that is false before the component has been mounted,
|
22
|
-
* then true during all subsequent rerenders.
|
23
|
-
*/
|
24
|
-
export declare const useMountState: () => boolean;
|
23
|
+
export type TState<YourCleanState extends CleanStateBase<{}>> = Omit<YourCleanState, keyof CleanStateBase<{}>>;
|
24
|
+
type StateInitFunction = (...args: any[]) => object;
|
25
|
+
type StateInit = object | StateInitFunction;
|
26
|
+
type TInitialState<Initializer extends StateInit> = Initializer extends (...args: any[]) => (infer TState extends object) ? TState : Initializer;
|
27
|
+
type TUseCleanState = <TInit extends StateInit>(_initialState: TInit, ...props: TInit extends (...args: infer TProps extends any[]) => (infer TState extends object) ? TProps : []) => TCleanStateInstance<TInitialState<TInit>>;
|
28
|
+
export declare const useCleanState: TUseCleanState;
|
25
29
|
export {};
|
package/build/base/state.js
CHANGED
@@ -11,8 +11,26 @@ var __assign = (this && this.__assign) || function () {
|
|
11
11
|
return __assign.apply(this, arguments);
|
12
12
|
};
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
14
|
-
exports.
|
14
|
+
exports.useCleanState = exports.useMountState = void 0;
|
15
15
|
var react_1 = require("react");
|
16
|
+
/**
|
17
|
+
* Returns a value that is false before the component has been mounted,
|
18
|
+
* then true during all subsequent rerenders.
|
19
|
+
*/
|
20
|
+
var useMountState = function () {
|
21
|
+
/**
|
22
|
+
* This must not be a stateful value. It should not be the cause of a rerender.
|
23
|
+
* It merely provides information about the render count,
|
24
|
+
* without influencing that count itself.
|
25
|
+
* So `mounted` should never be set with `useState`.
|
26
|
+
*/
|
27
|
+
var mounted = (0, react_1.useRef)(false);
|
28
|
+
(0, react_1.useEffect)(function () {
|
29
|
+
mounted.current = true;
|
30
|
+
}, []);
|
31
|
+
return mounted.current;
|
32
|
+
};
|
33
|
+
exports.useMountState = useMountState;
|
16
34
|
var CleanStateBase = /** @class */ (function () {
|
17
35
|
function CleanStateBase(initialState) {
|
18
36
|
var _this = this;
|
@@ -81,7 +99,14 @@ var CleanStateBase = /** @class */ (function () {
|
|
81
99
|
var retrieveState = react_1.useState;
|
82
100
|
this.valueKeys.forEach(function (key) {
|
83
101
|
var _a;
|
84
|
-
|
102
|
+
// @todo Make state updates accessible immediately. Use state.staged to access the scheduled updates.
|
103
|
+
var setter;
|
104
|
+
// @todo Support SetStateAction callback signature in state.put(...);
|
105
|
+
_a = retrieveState(_this.initialState[key]), _this._values_[key] = _a[0], setter = _a[1];
|
106
|
+
_this._setters_[key] = (function (valueOrCallback) {
|
107
|
+
// this._staged_[key] = value;
|
108
|
+
setter(valueOrCallback);
|
109
|
+
});
|
85
110
|
});
|
86
111
|
/* Object.entries<TUseStateArray<TState>>(stateAndSetters).forEach(([key, responseFromUseState]) => {
|
87
112
|
[this._values_[key], this._setters_[key]] = responseFromUseState;
|
@@ -92,29 +117,37 @@ var CleanStateBase = /** @class */ (function () {
|
|
92
117
|
}());
|
93
118
|
;
|
94
119
|
var CleanState = CleanStateBase;
|
95
|
-
var useCleanState = function (_initialState
|
96
|
-
|
97
|
-
var
|
98
|
-
|
120
|
+
var useCleanState = function (_initialState) {
|
121
|
+
var props = [];
|
122
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
123
|
+
props[_i - 1] = arguments[_i];
|
124
|
+
}
|
125
|
+
var mounted = (0, exports.useMountState)();
|
126
|
+
var initialState = typeof _initialState === 'function'
|
127
|
+
? (0, react_1.useMemo)(function () { return _initialState.apply(void 0, props); }, [])
|
128
|
+
: _initialState;
|
129
|
+
;
|
130
|
+
var freshInstance = {};
|
131
|
+
if (!mounted)
|
132
|
+
freshInstance = new CleanState(initialState);
|
133
|
+
if (!freshInstance.put)
|
134
|
+
throw new Error('useCleanState failed to initialized a state instance.');
|
135
|
+
var cleanState = (0, react_1.useRef)(freshInstance).current;
|
99
136
|
CleanState.update.call(cleanState);
|
100
137
|
return cleanState;
|
101
138
|
};
|
102
139
|
exports.useCleanState = useCleanState;
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
}, []);
|
118
|
-
return mounted.current;
|
119
|
-
};
|
120
|
-
exports.useMountState = useMountState;
|
140
|
+
// Should be valid.
|
141
|
+
// useCleanState((a: number) => ({b: a.toString(), q: 1}), 6);
|
142
|
+
// useCleanState((a: boolean) => ({b: a.toString()}), true);
|
143
|
+
// useCleanState((a: number, c?: string) => ({ b: `${a}` }), 6);
|
144
|
+
// useCleanState((a: number, c?: string) => ({ b: `${a}` }), 6, 'word');
|
145
|
+
// useCleanState((a: number, c: string) => ({ b: a + c, f: true }), 6, 'text');
|
146
|
+
// useCleanState({ d: 5000 });
|
147
|
+
// Should fail.
|
148
|
+
// useCleanState((a: number) => ({b: a.toString(), q: 1}), 6, false);
|
149
|
+
// useCleanState((a: boolean) => ({b: a.toString()}));
|
150
|
+
// useCleanState((a: number, c?: string) => ({ b: `${a}` }), '6');
|
151
|
+
// useCleanState((a: number, c?: string) => ({ b: `${a}` }));
|
152
|
+
// useCleanState((a: number, c: string) => ({ b: a + c, f: true }), 6, 7);
|
153
|
+
// useCleanState({ d: 5000 }, true);
|
package/build/classy/class.d.ts
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
-
import type {
|
2
|
-
import type {
|
1
|
+
import type { VoidFunctionComponent } from 'react';
|
2
|
+
import type { TComponentClass } from './logic';
|
3
3
|
import { ComponentInstance } from './instance';
|
4
|
-
type
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
static FC:
|
4
|
+
type Extractor = <TComponent extends ClassComponent<object, object, object>>(this: TComponentClass<TComponent, typeof ClassComponent>, _Component?: TComponentClass<TComponent, typeof ClassComponent>) => VoidFunctionComponent;
|
5
|
+
export declare class ClassComponent<TState extends object = EmptyObject, TProps extends object = EmptyObject, THooks extends object = EmptyObject> extends ComponentInstance<TState, TProps, THooks> {
|
6
|
+
Render: VoidFunctionComponent<{}>;
|
7
|
+
static renderAs: 'component' | 'template';
|
8
|
+
static FC: Extractor;
|
9
9
|
}
|
10
|
-
type AnyFunction = (...args: any) => any;
|
11
10
|
interface HookWrapperProps<THookFunction extends AnyFunction> {
|
12
11
|
hook: THookFunction;
|
13
12
|
argumentsList: Parameters<THookFunction>;
|
package/build/classy/class.js
CHANGED
@@ -16,6 +16,7 @@ var __extends = (this && this.__extends) || (function () {
|
|
16
16
|
})();
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
18
18
|
exports.Use = exports.ClassComponent = void 0;
|
19
|
+
var jsx_runtime_1 = require("react/jsx-runtime");
|
19
20
|
var react_1 = require("react");
|
20
21
|
var instance_1 = require("./instance");
|
21
22
|
/** Provide more useful stack traces for otherwise non-specific function names. */
|
@@ -31,37 +32,56 @@ var setFunctionName = function (func, newName) {
|
|
31
32
|
console.warn(error);
|
32
33
|
}
|
33
34
|
};
|
35
|
+
// eslint-enable no-use-before-define
|
34
36
|
var ClassComponent = /** @class */ (function (_super) {
|
35
37
|
__extends(ClassComponent, _super);
|
36
38
|
function ClassComponent() {
|
37
39
|
return _super !== null && _super.apply(this, arguments) || this;
|
38
40
|
}
|
41
|
+
ClassComponent.renderAs = 'component';
|
39
42
|
ClassComponent.FC = function FC(_Component) {
|
40
|
-
var Component = _Component
|
43
|
+
var Component = _Component !== null && _Component !== void 0 ? _Component : this;
|
41
44
|
var isClassComponentType = Component.prototype instanceof ClassComponent;
|
42
45
|
if (!Component.getInitialState || !isClassComponentType)
|
43
46
|
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()`).');
|
44
|
-
var Wrapper = function (props) {
|
47
|
+
var Wrapper = function (props, context) {
|
45
48
|
var Render = (0, instance_1.useInstance)(Component, props).Render;
|
46
49
|
// Add calling component name to Render function name in stack traces.
|
47
|
-
(0, react_1.useMemo)(function () { return setFunctionName(Render, "".concat(Component.name, "
|
50
|
+
(0, react_1.useMemo)(function () { return setFunctionName(Render, "".concat(Component.name, ".Render")); }, [Render]);
|
48
51
|
/**
|
49
|
-
*
|
52
|
+
* Normally a component can update it's own state in the "before-render" stage to
|
53
|
+
* skip DOM updates and trigger and immediate rerun of the rendering with the new state.
|
54
|
+
*
|
55
|
+
* It may be impossible to do this within the body of Render, if we call it as JSX here,
|
50
56
|
* since technically, the Wrapper component owns the state and not the Render component.
|
51
|
-
*
|
52
|
-
|
53
|
-
|
54
|
-
|
57
|
+
* Using it as JSX establishes a component boundary, and React will throw an error if we try to set
|
58
|
+
* state in the "before-render" stage of `Render`, since it will be attempting to update it's parent's
|
59
|
+
* state (i.e `Wrapper` component) rather than it's own state.
|
60
|
+
*
|
61
|
+
* Consider using this as a function call instead of JSX to avoid that. This way, we avoid
|
62
|
+
* establishing a component boundary between `Wrapper` and `Render`.
|
63
|
+
*
|
64
|
+
* Although, since beforeRender() is called earlier from a hook, this is probably
|
65
|
+
* a non-issue. It will only force users to move their logic into `beforeRender` instead
|
66
|
+
* of doing it directly in `Render`. This might mean cleaner Render functions,
|
67
|
+
* so there's probably no real value lost if we keep the component boundary.
|
68
|
+
**/
|
69
|
+
if (Component.renderAs === 'template')
|
70
|
+
return Render({}, context);
|
71
|
+
// With the existence of useContext(),
|
72
|
+
// what exactly does the context argument to FunctionComponent represent?
|
73
|
+
// Do we need to find a way to pass that context value to <Render /> here?
|
74
|
+
return (0, jsx_runtime_1.jsx)(Render, {});
|
55
75
|
};
|
56
76
|
// Include calling component name in wrapper function name on stack traces.
|
57
|
-
setFunctionName(Wrapper, "".concat(Component.name, "
|
77
|
+
setFunctionName(Wrapper, "".concat(Component.name, " < Wrapper")); // ${Wrapper.name}
|
58
78
|
return Wrapper;
|
59
79
|
};
|
60
80
|
return ClassComponent;
|
61
81
|
}(instance_1.ComponentInstance));
|
62
82
|
exports.ClassComponent = ClassComponent;
|
63
|
-
var Use = function (
|
64
|
-
var useGenericHook =
|
83
|
+
var Use = function (params) {
|
84
|
+
var useGenericHook = params.hook, argumentsList = params.argumentsList, onUpdate = params.onUpdate;
|
65
85
|
var output = useGenericHook.apply(void 0, argumentsList);
|
66
86
|
(0, react_1.useEffect)(function () {
|
67
87
|
onUpdate(output);
|
@@ -1,9 +1,8 @@
|
|
1
|
-
import type {
|
1
|
+
import type { TComponentClass } from './logic';
|
2
2
|
import { ComponentLogic } from './logic';
|
3
|
-
type Obj = Record<string, any>;
|
4
3
|
type AsyncAllowedEffectCallback = () => Awaitable<IVoidFunction>;
|
5
4
|
export declare const noOp: () => void;
|
6
|
-
export declare class ComponentInstance<TState extends
|
5
|
+
export declare class ComponentInstance<TState extends object = EmptyObject, TProps extends object = EmptyObject, THooks extends object = EmptyObject> extends ComponentLogic<TState, TProps, THooks> {
|
7
6
|
/**
|
8
7
|
* Runs only _before_ first render, i.e before the component instance is mounted.
|
9
8
|
* Useful for logic that is involved in determining what to render.
|
@@ -48,10 +47,17 @@ export declare class ComponentInstance<TState extends Obj = {}, TProps extends O
|
|
48
47
|
*/
|
49
48
|
cleanUp: IVoidFunction;
|
50
49
|
}
|
51
|
-
type
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
50
|
+
type UseInstance = <TClass extends ComponentInstance<object, object, object>>(Class: TComponentClass<TClass>, ...props: valueof<TClass['props']> extends never ? ([] | [EmptyObject] | [TClass['props']]) : [TClass['props']]) => TClass;
|
51
|
+
/**
|
52
|
+
* To ensure successful type checking, the second parameter must be written with spread syntax.
|
53
|
+
* Likely because of the `exactOptionalPropertyTypes` config option turned on,
|
54
|
+
* and `UseInstance` using an empty tuple in its rest parameter type, attempting to simply
|
55
|
+
* retrieve the second argument directly causes an error when that argument is passed on to `useLogic`.
|
56
|
+
* But directly working with the rest array bypasses the problem. Also note that the issue persists even when
|
57
|
+
* the second param is given `{}` as a default follow to account for the empty tuple case. TypeScript
|
58
|
+
* just wants us to use the rest parameter explicitly by force.
|
59
|
+
*/
|
56
60
|
export declare const useInstance: UseInstance;
|
61
|
+
type UseMountCallbacks = <TInstance extends ComponentInstance<any, any, any>>(instance: TInstance) => void;
|
62
|
+
export declare const useMountCallbacks: UseMountCallbacks;
|
57
63
|
export {};
|
package/build/classy/instance.js
CHANGED
@@ -14,8 +14,17 @@ var __extends = (this && this.__extends) || (function () {
|
|
14
14
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
15
15
|
};
|
16
16
|
})();
|
17
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
18
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
19
|
+
if (ar || !(i in from)) {
|
20
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
21
|
+
ar[i] = from[i];
|
22
|
+
}
|
23
|
+
}
|
24
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
25
|
+
};
|
17
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
18
|
-
exports.
|
27
|
+
exports.useMountCallbacks = exports.useInstance = exports.ComponentInstance = exports.noOp = void 0;
|
19
28
|
var react_1 = require("react");
|
20
29
|
var state_1 = require("../base/state");
|
21
30
|
var logic_1 = require("./logic");
|
@@ -74,6 +83,56 @@ var ComponentInstance = /** @class */ (function (_super) {
|
|
74
83
|
}(logic_1.ComponentLogic));
|
75
84
|
exports.ComponentInstance = ComponentInstance;
|
76
85
|
;
|
86
|
+
/**
|
87
|
+
* To ensure successful type checking, the second parameter must be written with spread syntax.
|
88
|
+
* Likely because of the `exactOptionalPropertyTypes` config option turned on,
|
89
|
+
* and `UseInstance` using an empty tuple in its rest parameter type, attempting to simply
|
90
|
+
* retrieve the second argument directly causes an error when that argument is passed on to `useLogic`.
|
91
|
+
* But directly working with the rest array bypasses the problem. Also note that the issue persists even when
|
92
|
+
* the second param is given `{}` as a default follow to account for the empty tuple case. TypeScript
|
93
|
+
* just wants us to use the rest parameter explicitly by force.
|
94
|
+
*/
|
95
|
+
var useInstance = function (Component) {
|
96
|
+
var _a;
|
97
|
+
var args = [];
|
98
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
99
|
+
args[_i - 1] = arguments[_i];
|
100
|
+
}
|
101
|
+
// useHooks.
|
102
|
+
var instance = logic_1.useLogic.apply(void 0, __spreadArray([Component], args, false)); // Must spread rest parameter, rather than passing a single `props` argument directly.
|
103
|
+
/**
|
104
|
+
* Argument of type '
|
105
|
+
* [
|
106
|
+
(valueof<TClass["props"]> extends never
|
107
|
+
? [] | [CEmptyObject]
|
108
|
+
: [ TClass["props"] ]
|
109
|
+
)[0]
|
110
|
+
]
|
111
|
+
' is not assignable to parameter of type '
|
112
|
+
valueof<TClass["props"]> extends never
|
113
|
+
? [] | [CEmptyObject] // | [undefined]
|
114
|
+
: [ TClass["props"] ]
|
115
|
+
'
|
116
|
+
*/
|
117
|
+
// beforeMount, onMount, cleanUp.
|
118
|
+
// eslint-disable-next-line no-use-before-define
|
119
|
+
(0, exports.useMountCallbacks)(instance);
|
120
|
+
// beforeRender.
|
121
|
+
(_a = instance.beforeRender) === null || _a === void 0 ? void 0 : _a.call(instance);
|
122
|
+
// onRender.
|
123
|
+
(0, react_1.useEffect)(function () {
|
124
|
+
var _a;
|
125
|
+
var cleanupAfterRerender = (_a = instance.onRender) === null || _a === void 0 ? void 0 : _a.call(instance);
|
126
|
+
return function () {
|
127
|
+
if (typeof cleanupAfterRerender === 'function')
|
128
|
+
cleanupAfterRerender();
|
129
|
+
else
|
130
|
+
cleanupAfterRerender === null || cleanupAfterRerender === void 0 ? void 0 : cleanupAfterRerender.then(function (cleanUp) { return cleanUp === null || cleanUp === void 0 ? void 0 : cleanUp(); });
|
131
|
+
};
|
132
|
+
});
|
133
|
+
return instance;
|
134
|
+
};
|
135
|
+
exports.useInstance = useInstance;
|
77
136
|
var useMountCallbacks = function (instance) {
|
78
137
|
var _a;
|
79
138
|
var mounted = (0, state_1.useMountState)();
|
@@ -99,25 +158,3 @@ var useMountCallbacks = function (instance) {
|
|
99
158
|
}, []);
|
100
159
|
};
|
101
160
|
exports.useMountCallbacks = useMountCallbacks;
|
102
|
-
var useInstance = function (Component, props) {
|
103
|
-
var _a;
|
104
|
-
// useHooks.
|
105
|
-
var instance = (0, logic_1.useLogic)(Component, props);
|
106
|
-
// beforeMount, onMount, cleanUp.
|
107
|
-
(0, exports.useMountCallbacks)(instance);
|
108
|
-
// beforeRender.
|
109
|
-
(_a = instance.beforeRender) === null || _a === void 0 ? void 0 : _a.call(instance);
|
110
|
-
// onRender.
|
111
|
-
(0, react_1.useEffect)(function () {
|
112
|
-
var _a;
|
113
|
-
var cleanupAfterRerender = (_a = instance.onRender) === null || _a === void 0 ? void 0 : _a.call(instance);
|
114
|
-
return function () {
|
115
|
-
if (typeof cleanupAfterRerender === 'function')
|
116
|
-
cleanupAfterRerender();
|
117
|
-
else
|
118
|
-
cleanupAfterRerender === null || cleanupAfterRerender === void 0 ? void 0 : cleanupAfterRerender.then(function (cleanUp) { return cleanUp === null || cleanUp === void 0 ? void 0 : cleanUp(); });
|
119
|
-
};
|
120
|
-
});
|
121
|
-
return instance;
|
122
|
-
};
|
123
|
-
exports.useInstance = useInstance;
|
package/build/classy/logic.d.ts
CHANGED
@@ -1,13 +1,22 @@
|
|
1
|
-
import type { TCleanState } from '../base/state';
|
2
|
-
export declare class ComponentLogic<TState extends object, TProps extends object, THooks extends object> {
|
1
|
+
import type { TCleanState, TState } from '../base/state';
|
2
|
+
export declare class ComponentLogic<TState extends object = EmptyObject, TProps extends object = EmptyObject, THooks extends object = EmptyObject> {
|
3
3
|
state: TCleanState<TState>;
|
4
4
|
props: TProps;
|
5
5
|
hooks: THooks;
|
6
|
+
static getInitialState: IComponentClass['getInitialState'];
|
6
7
|
useHooks?: () => THooks;
|
7
8
|
}
|
8
|
-
|
9
|
-
|
9
|
+
type CnstPrm = ConstructorParameters<typeof ComponentLogic>;
|
10
|
+
export interface IComponentClass<Instance extends ComponentLogic = ComponentLogic> {
|
11
|
+
new (...params: CnstPrm): Instance;
|
12
|
+
getInitialState: (props?: Instance['props']) => TState<Instance['state']>;
|
10
13
|
}
|
11
|
-
type
|
14
|
+
export type ComponentClassStatics<Instance extends ComponentLogic<object, object, object>> = {
|
15
|
+
getInitialState: (props?: Instance['props']) => TState<Instance['state']>;
|
16
|
+
};
|
17
|
+
export type TComponentClass<Instance extends ComponentLogic<object, object, object>, Statics extends ComponentClassStatics<Instance> = ComponentClassStatics<Instance>, Params extends CnstPrm = CnstPrm> = Statics & Constructor<Instance, Params>;
|
18
|
+
export interface IEmpty extends EmptyObject {
|
19
|
+
}
|
20
|
+
type UseLogic = <CLogic extends ComponentLogic<object, object, object>>(Methods: TComponentClass<CLogic>, ...props: valueof<CLogic['props']> extends never ? ([] | [EmptyObject] | [CLogic['props']]) : [CLogic['props']]) => CLogic;
|
12
21
|
export declare const useLogic: UseLogic;
|
13
22
|
export {};
|
package/build/classy/logic.js
CHANGED
@@ -1,4 +1,20 @@
|
|
1
1
|
"use strict";
|
2
|
+
var __extends = (this && this.__extends) || (function () {
|
3
|
+
var extendStatics = function (d, b) {
|
4
|
+
extendStatics = Object.setPrototypeOf ||
|
5
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
6
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
7
|
+
return extendStatics(d, b);
|
8
|
+
};
|
9
|
+
return function (d, b) {
|
10
|
+
if (typeof b !== "function" && b !== null)
|
11
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
12
|
+
extendStatics(d, b);
|
13
|
+
function __() { this.constructor = d; }
|
14
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
15
|
+
};
|
16
|
+
})();
|
17
|
+
var _a;
|
2
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
19
|
exports.useLogic = exports.ComponentLogic = void 0;
|
4
20
|
var react_1 = require("react");
|
@@ -10,22 +26,42 @@ var ComponentLogic = /** @class */ (function () {
|
|
10
26
|
}());
|
11
27
|
exports.ComponentLogic = ComponentLogic;
|
12
28
|
;
|
29
|
+
testing: {
|
30
|
+
var A = (_a = /** @class */ (function (_super) {
|
31
|
+
__extends(C, _super);
|
32
|
+
function C() {
|
33
|
+
return _super !== null && _super.apply(this, arguments) || this;
|
34
|
+
}
|
35
|
+
return C;
|
36
|
+
}(ComponentLogic)),
|
37
|
+
_a.getInitialState = function () { return ({}); },
|
38
|
+
_a);
|
39
|
+
A.getInitialState();
|
40
|
+
}
|
41
|
+
;
|
13
42
|
var useLogic = function (Methods, props) {
|
14
|
-
var
|
43
|
+
var _b;
|
15
44
|
if (props === void 0) { props = {}; }
|
16
45
|
var state = (0, state_1.useCleanState)(Methods.getInitialState, props);
|
17
|
-
|
18
|
-
// completely ignoring the type specified for Methods in the function's type definition.
|
19
|
-
// `new Methods()` should return whatever the InstanceType of TClass is, as that is the type explicitly specified for Methods.
|
20
|
-
// Ignoring the specified type to gin up something else and then complain about it is quite weird.
|
21
|
-
// Regardless, even when `extends ComponentLogicConstructor<TState, TProps, THooks>` is specified using generics instead of a set type,
|
22
|
-
// the issue persists. Which is absurd since this should ensure that InstanceType<Class> should exactly match ComponentLogic<TState, TProps, THooks>
|
23
|
-
var methods = (0, react_1.useMemo)(function () {
|
46
|
+
var methods = (0, react_1.useRef)((0, react_1.useMemo)(function () {
|
24
47
|
return new Methods();
|
25
|
-
}, []);
|
48
|
+
}, [])).current;
|
26
49
|
methods.state = state;
|
27
50
|
methods.props = props;
|
28
|
-
methods.hooks = ((
|
51
|
+
methods.hooks = ((_b = methods.useHooks) === null || _b === void 0 ? void 0 : _b.call(methods)) || {};
|
29
52
|
return methods;
|
30
53
|
};
|
31
54
|
exports.useLogic = useLogic;
|
55
|
+
testing: {
|
56
|
+
var a = { b: '' };
|
57
|
+
var MyComponentLogic = /** @class */ (function (_super) {
|
58
|
+
__extends(MyComponentLogic, _super);
|
59
|
+
function MyComponentLogic() {
|
60
|
+
return _super !== null && _super.apply(this, arguments) || this;
|
61
|
+
}
|
62
|
+
MyComponentLogic.getInitialState = function () { return ({}); };
|
63
|
+
return MyComponentLogic;
|
64
|
+
}(ComponentLogic));
|
65
|
+
;
|
66
|
+
(0, exports.useLogic)(MyComponentLogic);
|
67
|
+
}
|
package/build/globals.d.ts
CHANGED
@@ -1,56 +1,67 @@
|
|
1
|
-
|
2
|
-
type Optional<
|
3
|
-
BaseType,
|
4
|
-
AllowNull extends boolean = true
|
5
|
-
> = (
|
6
|
-
AllowNull extends true
|
7
|
-
? BaseType | undefined | null
|
8
|
-
: BaseType | undefined
|
9
|
-
)
|
10
|
-
|
11
|
-
type Awaitable<Type> = Type | Promise<Type>;
|
12
|
-
|
13
|
-
type Constructor<
|
14
|
-
TInstance extends any = any,
|
15
|
-
TParams extends any[] = never[]
|
16
|
-
> = new (...args: TParams) => TInstance
|
17
|
-
|
18
|
-
|
19
1
|
/**
|
2
|
+
* @file
|
3
|
+
* This file is an "Ambient declarations file". The types defined here are available globally.
|
4
|
+
* More info here: https://stackoverflow.com/a/73389225/985454
|
5
|
+
*
|
6
|
+
* Don't use `import` and `export` in this file directly! It breaks ambience.
|
7
|
+
* To import external types in an ambient declarations file (this file) use the following:
|
8
|
+
*
|
20
9
|
* @example
|
21
|
-
*
|
22
|
-
*
|
23
|
-
*
|
10
|
+
* declare type React = typeof import('react');
|
11
|
+
*
|
12
|
+
* To contribute ambient declarations from any file, even non-ambient ones, use this:
|
13
|
+
*
|
14
|
+
* @example
|
15
|
+
* declare global {
|
16
|
+
* interface Window {
|
17
|
+
* ethereum: any
|
18
|
+
* }
|
24
19
|
* }
|
25
|
-
|
26
|
-
*/
|
27
|
-
declare
|
28
|
-
|
29
|
-
|
30
|
-
> = (...
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
}
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
}
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
20
|
+
**/
|
21
|
+
/** */
|
22
|
+
declare global {
|
23
|
+
type Optional<BaseType, AllowNull extends boolean = true> = (AllowNull extends true ? BaseType | undefined | null : BaseType | undefined);
|
24
|
+
type Awaitable<Type> = Type | Promise<Type>;
|
25
|
+
type Constructor<TInstance extends any = any, TParams extends any[] = never[]> = new (...args: TParams) => TInstance;
|
26
|
+
/**
|
27
|
+
* @example
|
28
|
+
* ```js
|
29
|
+
* const getNumber: AsyncFunction<number> = async () => {
|
30
|
+
* return 5;
|
31
|
+
* }
|
32
|
+
* ```
|
33
|
+
*/
|
34
|
+
type AsyncFunction<TReturnValue extends any = void, Params extends any[] = never[]> = (...params: Params) => Promise<TReturnValue>;
|
35
|
+
/**
|
36
|
+
* A function that takes no arguments and returns nothing.
|
37
|
+
* Pass a type argument to set whether `async` and/or `sync` functions are allowed.
|
38
|
+
*/
|
39
|
+
interface IVoidFunction<AsyncType extends 'async' | 'sync' | 'both' = 'both'> {
|
40
|
+
(): AsyncType extends 'async' ? Promise<void> : AsyncType extends 'sync' ? void : Promise<void> | void;
|
41
|
+
}
|
42
|
+
type AnyFunction = (...args: any) => any;
|
43
|
+
type FunctionType = AnyFunction;
|
44
|
+
type TFunction = AnyFunction;
|
45
|
+
interface Window {
|
46
|
+
}
|
47
|
+
namespace JSX {
|
48
|
+
interface IntrinsicElements {
|
49
|
+
}
|
50
|
+
}
|
51
|
+
namespace NodeJS {
|
52
|
+
interface ProcessEnv {
|
53
|
+
}
|
54
|
+
}
|
55
|
+
type __FromPrivateHelpers = typeof import('./globals.private');
|
56
|
+
type TEmptyObject1 = {
|
57
|
+
''?: never;
|
58
|
+
};
|
59
|
+
type TEmptyObject2 = Record<symbol, never>;
|
60
|
+
type EmptyObject = __FromPrivateHelpers['EmptyObject'];
|
61
|
+
type EmptyObject2 = __FromPrivateHelpers['EmptyObject2'];
|
62
|
+
type EmptyObject3 = __FromPrivateHelpers['EmptyObject3'];
|
63
|
+
type valueof<TObject> = TObject[keyof TObject];
|
64
|
+
interface T extends __FromPrivateHelpers {
|
65
|
+
}
|
56
66
|
}
|
67
|
+
export {};
|
package/build/globals.js
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
"use strict";
|
2
|
+
/**
|
3
|
+
* @file
|
4
|
+
* This file is an "Ambient declarations file". The types defined here are available globally.
|
5
|
+
* More info here: https://stackoverflow.com/a/73389225/985454
|
6
|
+
*
|
7
|
+
* Don't use `import` and `export` in this file directly! It breaks ambience.
|
8
|
+
* To import external types in an ambient declarations file (this file) use the following:
|
9
|
+
*
|
10
|
+
* @example
|
11
|
+
* declare type React = typeof import('react');
|
12
|
+
*
|
13
|
+
* To contribute ambient declarations from any file, even non-ambient ones, use this:
|
14
|
+
*
|
15
|
+
* @example
|
16
|
+
* declare global {
|
17
|
+
* interface Window {
|
18
|
+
* ethereum: any
|
19
|
+
* }
|
20
|
+
* }
|
21
|
+
**/
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
@@ -0,0 +1,48 @@
|
|
1
|
+
/**
|
2
|
+
* @file
|
3
|
+
* This file is created specifically to augment the declarations in
|
4
|
+
* [globals.d.ts]({@link ./globals.d.ts}).
|
5
|
+
*
|
6
|
+
* **You should not import this file directly.**
|
7
|
+
*/
|
8
|
+
/** */
|
9
|
+
declare const UniqueSecretSymbolKey: unique symbol;
|
10
|
+
declare class CEmptyObject {
|
11
|
+
[key: keyof any]: never;
|
12
|
+
}
|
13
|
+
declare class CEmptyObject2 {
|
14
|
+
[UniqueSecretSymbolKey]?: never;
|
15
|
+
}
|
16
|
+
declare class CEmptyObject3 {
|
17
|
+
/**
|
18
|
+
* It appears keys of the base `symbol` type are excluded from
|
19
|
+
* excess property checks. This is likely a bug in TypeScript.
|
20
|
+
* Even the "has no properties in common" error disappears if the
|
21
|
+
* value being placed into a variable has a key typed as `symbol`.
|
22
|
+
* This only applies to the base `symbol` type. Specifc `'unique symbol'`
|
23
|
+
* types are unaffected.
|
24
|
+
*
|
25
|
+
* @example
|
26
|
+
* // Consider the following object:
|
27
|
+
* const myUniqueSymbol = Symbol('lkjhgfc');
|
28
|
+
* let myObj = { [myUniqueSymbol]?: 'a string value' };
|
29
|
+
*
|
30
|
+
* // We can attempt to reassign `myObj` with the expectation that TS will
|
31
|
+
* // warn if any key other than `myUniqueSymbol` is used in the new object.
|
32
|
+
* // But this breaks in one specific scenario.
|
33
|
+
*
|
34
|
+
* // No excess property check when this is used as a key.
|
35
|
+
* // Error "no properties in common" also suppressed when this is used as a key.
|
36
|
+
* const differentBasicSymbol = Symbol('qwertiop[') as symbol;
|
37
|
+
* myObj = { [differentBasicSymbol]: 5 };
|
38
|
+
*
|
39
|
+
* // Errors emitted as expected when this is used as a key.
|
40
|
+
* const differentUniqueSymbol = Symbol('zxcvbnm');
|
41
|
+
* myObj = { [differentUniqueSymbol]: 5 };
|
42
|
+
*/
|
43
|
+
[key: symbol]: never;
|
44
|
+
}
|
45
|
+
export declare const EmptyObject: CEmptyObject;
|
46
|
+
export declare const EmptyObject2: CEmptyObject2;
|
47
|
+
export declare const EmptyObject3: CEmptyObject3;
|
48
|
+
export {};
|
@@ -0,0 +1,40 @@
|
|
1
|
+
"use strict";
|
2
|
+
/**
|
3
|
+
* @file
|
4
|
+
* This file is created specifically to augment the declarations in
|
5
|
+
* [globals.d.ts]({@link ./globals.d.ts}).
|
6
|
+
*
|
7
|
+
* **You should not import this file directly.**
|
8
|
+
*/
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
10
|
+
exports.EmptyObject3 = exports.EmptyObject2 = exports.EmptyObject = void 0;
|
11
|
+
/** */
|
12
|
+
var UniqueSecretSymbolKey = Symbol('asdfghjkliuytrewqaxcvb,nb');
|
13
|
+
var CEmptyObject = /** @class */ (function () {
|
14
|
+
function CEmptyObject() {
|
15
|
+
}
|
16
|
+
return CEmptyObject;
|
17
|
+
}());
|
18
|
+
var CEmptyObject2 = /** @class */ (function () {
|
19
|
+
function CEmptyObject2() {
|
20
|
+
}
|
21
|
+
return CEmptyObject2;
|
22
|
+
}());
|
23
|
+
var CEmptyObject3 = /** @class */ (function () {
|
24
|
+
function CEmptyObject3() {
|
25
|
+
}
|
26
|
+
return CEmptyObject3;
|
27
|
+
}());
|
28
|
+
exports.EmptyObject = new CEmptyObject();
|
29
|
+
exports.EmptyObject2 = new CEmptyObject2();
|
30
|
+
exports.EmptyObject3 = new CEmptyObject3();
|
31
|
+
testing: {
|
32
|
+
var mySymbol = Symbol('asdfgh');
|
33
|
+
var tt = {
|
34
|
+
// [mySymbol]: '' as never,
|
35
|
+
// [UniqueSecretSymbolKey]: '',
|
36
|
+
// '': '',
|
37
|
+
};
|
38
|
+
var TT = new CEmptyObject();
|
39
|
+
TT = tt;
|
40
|
+
}
|
package/build/tsconfig.json
CHANGED
@@ -28,10 +28,13 @@
|
|
28
28
|
"resolveJsonModule": true,
|
29
29
|
"isolatedModules": true,
|
30
30
|
"jsx": "react-jsx",
|
31
|
-
"strictNullChecks": true
|
31
|
+
"strictNullChecks": true,
|
32
|
+
"noImplicitAny": true,
|
33
|
+
"noUncheckedIndexedAccess": true,
|
34
|
+
"strictBindCallApply": true,
|
35
|
+
// "exactOptionalPropertyTypes": true
|
32
36
|
},
|
33
37
|
"include": [
|
34
|
-
"next-env.d.ts",
|
35
38
|
"**/*.ts",
|
36
39
|
"**/*.tsx"
|
37
40
|
],
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@cleanweb/react",
|
3
|
-
"version": "1.0
|
3
|
+
"version": "1.1.1-beta.0",
|
4
4
|
"description": "A suite of helpers for writing cleaner React function components.",
|
5
5
|
"engines": {
|
6
6
|
"node": ">=18"
|
@@ -34,8 +34,17 @@
|
|
34
34
|
"_": "",
|
35
35
|
"prepublishOnly": "npm run build",
|
36
36
|
"publish:patch": "npm version patch && npm publish",
|
37
|
+
"publish:minor": "npm version minor && npm publish",
|
38
|
+
"publish:major": "npm version major && npm publish",
|
39
|
+
"__": "/// Increment beta number for the current patch version. ///",
|
40
|
+
"publish:beta:current": "npm version prerelease --preid beta && npm publish --tag beta",
|
41
|
+
"___": "/// Create a beta.0 for a new patch/minor/major version ///",
|
42
|
+
"publish:beta:new-patch": "npm version prepatch --preid beta && npm publish --tag beta",
|
43
|
+
"publish:beta:new-minor": "npm version preminor --preid beta && npm publish --tag beta",
|
44
|
+
"publish:beta:new-major": "npm version premajor --preid beta && npm publish --tag beta",
|
45
|
+
"____": "",
|
37
46
|
"//postpublish": "cd ./mirror-pkg && npm publish && cd ..",
|
38
|
-
"
|
47
|
+
"______": "",
|
39
48
|
"test": "echo \"No tests ATM\""
|
40
49
|
},
|
41
50
|
"keywords": [
|
@@ -55,9 +64,16 @@
|
|
55
64
|
},
|
56
65
|
"license": "MIT",
|
57
66
|
"devDependencies": {
|
67
|
+
"@babel/eslint-parser": "^7.25.9",
|
68
|
+
"@babel/preset-typescript": "^7.26.0",
|
58
69
|
"@types/node": "20.14.10",
|
59
70
|
"@types/react": "^16",
|
71
|
+
"babel-preset-react-app": "^10.0.1",
|
60
72
|
"copyfiles": "^2.4.1",
|
73
|
+
"eslint": "^9.15.0",
|
74
|
+
"eslint-plugin-jsdoc": "^50.5.0",
|
75
|
+
"eslint-plugin-react": "^7.37.2",
|
76
|
+
"globals": "^15.12.0",
|
61
77
|
"rimraf": "^6.0.1",
|
62
78
|
"tsc-alias": "1.8.10",
|
63
79
|
"typescript": "^5.6.2"
|