@cleanweb/react 2.1.0 → 2.1.1-beta.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/build/base/merged-state.d.ts +4 -0
- package/build/base/merged-state.js +4 -0
- package/build/base/methods.d.ts +15 -5
- package/build/base/methods.js +74 -11
- package/build/base/state/class.d.ts +2 -0
- package/build/base/state/class.js +2 -5
- package/build/base/state/hook-types.d.ts +25 -1
- package/build/base/state/hooks.d.ts +8 -2
- package/build/base/state/hooks.js +8 -2
- package/build/base/state/index.d.ts +4 -0
- package/build/base/state/index.js +28 -1
- package/build/classy/class/index.d.ts +13 -3
- package/build/classy/class/index.js +11 -2
- package/build/classy/instance/index.d.ts +27 -5
- package/build/classy/instance/index.js +21 -8
- package/build/classy/instance/mount-callbacks.d.ts +1 -0
- package/build/classy/instance/mount-callbacks.js +1 -0
- package/build/classy/instance/types/hook.d.ts +3 -2
- package/build/classy/logic/index.d.ts +28 -6
- package/build/classy/logic/index.js +69 -12
- package/build/classy/logic/types/hook.d.ts +3 -4
- package/build/docs-src/api/base-classes.d.ts +3 -0
- package/build/docs-src/api/base-classes.js +9 -0
- package/build/docs-src/api/index.d.ts +13 -0
- package/build/docs-src/api/index.js +44 -0
- package/build/docs-src/api/references.d.ts +5 -0
- package/build/docs-src/api/references.js +31 -0
- package/build/globals.d.ts +7 -6
- package/build/helpers/hmr.d.ts +18 -0
- package/build/helpers/hmr.js +48 -0
- package/build/helpers/index.d.ts +11 -0
- package/build/helpers/index.js +14 -0
- package/build/helpers/rerender.d.ts +4 -0
- package/build/helpers/rerender.js +4 -0
- package/build/helpers/type-guards.d.ts +1 -0
- package/build/helpers/type-guards.js +9 -0
- package/package.json +11 -2
- /package/build/{classy/class → helpers}/use-component/index.d.ts +0 -0
- /package/build/{classy/class → helpers}/use-component/index.js +0 -0
- /package/build/{classy/class → helpers}/use-component/types.d.ts +0 -0
- /package/build/{classy/class → helpers}/use-component/types.js +0 -0
package/README.md
CHANGED
@@ -55,7 +55,7 @@ const Button = (props) => {
|
|
55
55
|
|
56
56
|
> **Note:** Each top-level key in your initial state object gets a separate call to `React.useState`, and `state.put[key]()` is a proxy for the setter function returned from `useState`. So using this hook is fundamentally the same as calling `useState` directly for each value. What `useCleanState` provides is a way to unify those values and a convenient API for updating them.
|
57
57
|
|
58
|
-
[Read the `useCleanState` docs]() for more details.
|
58
|
+
[Read the `useCleanState` docs](https://cleanjsweb.github.io/neat-react) for more details.
|
59
59
|
|
60
60
|
### Methods
|
61
61
|
The `useMethods` hook lets you manage the closures that your component uses in a separate class, keeping the body of the component clean and easier to read. With `useMethods`, your functions are not recreated on every render. Yet, every method of your component is guaranteed to always have access to the latest props and state without the need for a dependencty array.
|
@@ -12,5 +12,9 @@ declare class MergedState<TState extends object> {
|
|
12
12
|
constructor(initialState: TState);
|
13
13
|
putMany: (newValues: Partial<TState>) => void;
|
14
14
|
}
|
15
|
+
/**
|
16
|
+
* Similar to {@link useCleanState},
|
17
|
+
* but uses a single `useState` call for all keys.
|
18
|
+
*/
|
15
19
|
export declare const useMergedState: <TState extends object>(initialState: TState) => MergedState<TState> & TState;
|
16
20
|
export {};
|
@@ -70,6 +70,10 @@ var MergedState = /** @class */ (function () {
|
|
70
70
|
});
|
71
71
|
return MergedState;
|
72
72
|
}());
|
73
|
+
/**
|
74
|
+
* Similar to {@link useCleanState},
|
75
|
+
* but uses a single `useState` call for all keys.
|
76
|
+
*/
|
73
77
|
var useMergedState = function (initialState) {
|
74
78
|
var cleanState = (0, react_1.useRef)((0, react_1.useMemo)(function () {
|
75
79
|
return new MergedState(initialState);
|
package/build/base/methods.d.ts
CHANGED
@@ -1,6 +1,12 @@
|
|
1
|
+
/**
|
2
|
+
* @module ComponentMethods
|
3
|
+
*/
|
1
4
|
import type { TCleanState, TStateData } from './state';
|
2
5
|
/**
|
3
|
-
*
|
6
|
+
* @summary
|
7
|
+
* Base class for a class that holds methods for a function component.
|
8
|
+
*
|
9
|
+
* @remarks
|
4
10
|
* These methods will have access to the components state and props via
|
5
11
|
* `this.state` and `this.props` respectively.
|
6
12
|
*
|
@@ -8,18 +14,22 @@ import type { TCleanState, TStateData } from './state';
|
|
8
14
|
*/
|
9
15
|
export declare class ComponentMethods<TProps extends object = {}, TState extends TStateData | null = null> {
|
10
16
|
readonly props: TProps;
|
11
|
-
state: TState extends TStateData ? TCleanState<TState> : null;
|
17
|
+
readonly state: TState extends TStateData ? TCleanState<TState> : null;
|
18
|
+
_hmrPreserveKeys: Array<keyof this | (string & {})>;
|
19
|
+
_onHmrUpdate: <TInstance extends this>(oldInstance: TInstance) => void;
|
12
20
|
}
|
13
21
|
type UseMethods = {
|
14
22
|
<Class extends typeof ComponentMethods<object, object>>(Methods: Class & Constructor<InstanceType<Class>>, props: InstanceType<Class>['props'], state: InstanceType<Class>['state']): InstanceType<Class>;
|
15
23
|
<Class extends typeof ComponentMethods<object, null>>(Methods: Class & Constructor<InstanceType<Class>>, props: InstanceType<Class>['props'], state?: null): InstanceType<Class>;
|
16
|
-
<Class extends typeof ComponentMethods<
|
24
|
+
<Class extends typeof ComponentMethods<NeverObject, null>>(Methods: Class & Constructor<InstanceType<Class>>): InstanceType<Class>;
|
17
25
|
};
|
18
26
|
/**
|
27
|
+
* @summary
|
19
28
|
* Returns an instance of the provided class,
|
20
29
|
* with the state and props arguments added as instance members.
|
21
30
|
*
|
22
|
-
*
|
31
|
+
* @remarks
|
32
|
+
* `state` should be an instance of `CleanState` created with {@link useCleanState}.
|
23
33
|
*/
|
24
34
|
declare const useMethods: UseMethods;
|
25
35
|
export { useMethods };
|
@@ -29,7 +39,7 @@ export { useMethods };
|
|
29
39
|
|
30
40
|
type t = keyof typeof a;
|
31
41
|
|
32
|
-
class MyMethods extends ComponentMethods<
|
42
|
+
class MyMethods extends ComponentMethods<EmptyObject, null> {
|
33
43
|
// static getInitialState = () => ({});
|
34
44
|
};
|
35
45
|
|
package/build/base/methods.js
CHANGED
@@ -1,10 +1,27 @@
|
|
1
1
|
"use strict";
|
2
|
+
/**
|
3
|
+
* @module ComponentMethods
|
4
|
+
*/
|
5
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
6
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
7
|
+
if (ar || !(i in from)) {
|
8
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
9
|
+
ar[i] = from[i];
|
10
|
+
}
|
11
|
+
}
|
12
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
13
|
+
};
|
2
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
15
|
exports.useMethods = exports.ComponentMethods = void 0;
|
16
|
+
// JSDoc references
|
17
|
+
var helpers_1 = require("../helpers");
|
4
18
|
// Values
|
5
19
|
var react_1 = require("react");
|
6
20
|
/**
|
7
|
-
*
|
21
|
+
* @summary
|
22
|
+
* Base class for a class that holds methods for a function component.
|
23
|
+
*
|
24
|
+
* @remarks
|
8
25
|
* These methods will have access to the components state and props via
|
9
26
|
* `this.state` and `this.props` respectively.
|
10
27
|
*
|
@@ -12,16 +29,19 @@ var react_1 = require("react");
|
|
12
29
|
*/
|
13
30
|
var ComponentMethods = /** @class */ (function () {
|
14
31
|
function ComponentMethods() {
|
32
|
+
this._hmrPreserveKeys = [];
|
15
33
|
}
|
16
34
|
return ComponentMethods;
|
17
35
|
}());
|
18
36
|
exports.ComponentMethods = ComponentMethods;
|
19
37
|
;
|
20
38
|
/**
|
39
|
+
* @summary
|
21
40
|
* Returns an instance of the provided class,
|
22
41
|
* with the state and props arguments added as instance members.
|
23
42
|
*
|
24
|
-
*
|
43
|
+
* @remarks
|
44
|
+
* `state` should be an instance of `CleanState` created with {@link useCleanState}.
|
25
45
|
*/
|
26
46
|
var useMethods = function () {
|
27
47
|
var args = [];
|
@@ -33,16 +53,59 @@ var useMethods = function () {
|
|
33
53
|
// causing the instance to be unexpectedly recreated in the middle of the component's lifecycle.
|
34
54
|
// But useRef and useState values appear to always be preserved whenever this happens.
|
35
55
|
// So those two are the only cross-render-persistence methods we can consider safe.
|
36
|
-
//
|
37
|
-
|
38
|
-
|
39
|
-
}, [])
|
40
|
-
|
41
|
-
|
56
|
+
// In production, we only use the latestInstance the first time, and it's ignored every other time.
|
57
|
+
// This means changing the class at runtime will have no effect in production.
|
58
|
+
// latestInstance is only extracted into a separate variable for use in dev mode during HMR.
|
59
|
+
var latestInstance = (0, react_1.useMemo)(function () { return new Methods(); }, [Methods]);
|
60
|
+
var instanceRef = (0, react_1.useRef)(latestInstance);
|
61
|
+
if (process.env.NODE_ENV === 'development') {
|
62
|
+
var rerender_1 = (0, helpers_1.useRerender)();
|
63
|
+
(0, react_1.useEffect)(function () {
|
64
|
+
var _a;
|
65
|
+
if (instanceRef.current === latestInstance)
|
66
|
+
return;
|
67
|
+
console.log([
|
68
|
+
'HMR-updated component class detected.',
|
69
|
+
'Creating a new instance with the updated class.',
|
70
|
+
'All stateful values will be copied over.\n\n',
|
71
|
+
'Note that this mechanism only works in the `development` environment during HMR.',
|
72
|
+
'In production, the class argument will be ignored after the first render.\n\n',
|
73
|
+
'If this wasn\'t an HMR update, you should refactor your code to make sure',
|
74
|
+
'all clean-react hooks receive the same class object on every render.'
|
75
|
+
].join());
|
76
|
+
var oldInstance = instanceRef.current;
|
77
|
+
var hmrPreserveKeys = __spreadArray(__spreadArray([], ((_a = latestInstance._hmrPreserveKeys) !== null && _a !== void 0 ? _a : []), true), [
|
78
|
+
'state', 'props', 'hooks',
|
79
|
+
], false);
|
80
|
+
hmrPreserveKeys.forEach(function (_key) {
|
81
|
+
var key = _key;
|
82
|
+
// @ts-expect-error We're assigning to readonly properties. Also, Typescript doesn't know that the type of the left and right side will always match, due to the dynamic access.
|
83
|
+
latestInstance[key] = oldInstance[key];
|
84
|
+
});
|
85
|
+
latestInstance._onHmrUpdate(oldInstance);
|
86
|
+
Reflect.ownKeys(oldInstance).forEach(function (_key) {
|
87
|
+
var key = _key;
|
88
|
+
delete oldInstance[key];
|
89
|
+
});
|
90
|
+
Object.setPrototypeOf(oldInstance, latestInstance);
|
91
|
+
instanceRef.current = latestInstance;
|
92
|
+
rerender_1();
|
93
|
+
});
|
94
|
+
}
|
95
|
+
var methods = instanceRef.current;
|
96
|
+
/**
|
97
|
+
* A proxy variable to allow typechecking of the assignment
|
98
|
+
* to a readonly property,
|
99
|
+
* despite the need for "readonly" error suppression.
|
100
|
+
*/
|
101
|
+
var _propsProxy;
|
102
|
+
/** @see {@link _propsProxy} */
|
103
|
+
var _stateProxy;
|
104
|
+
// @ts-expect-error
|
105
|
+
methods.props = (_propsProxy = props);
|
42
106
|
// @ts-expect-error
|
43
|
-
methods.props = (_propsProxy_ = props);
|
44
107
|
if (state)
|
45
|
-
methods.state = state;
|
108
|
+
methods.state = (_stateProxy = state);
|
46
109
|
return methods;
|
47
110
|
};
|
48
111
|
exports.useMethods = useMethods;
|
@@ -52,7 +115,7 @@ exports.useMethods = useMethods;
|
|
52
115
|
|
53
116
|
type t = keyof typeof a;
|
54
117
|
|
55
|
-
class MyMethods extends ComponentMethods<
|
118
|
+
class MyMethods extends ComponentMethods<EmptyObject, null> {
|
56
119
|
// static getInitialState = () => ({});
|
57
120
|
};
|
58
121
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { ICleanStateClass, ICleanStateConstructor, PutState } from './class-types';
|
2
|
+
/** @internal */
|
2
3
|
export declare class CleanStateBase<TState extends Record<string, any>> {
|
3
4
|
readonly reservedKeys: string[];
|
4
5
|
readonly valueKeys: string[];
|
@@ -11,4 +12,5 @@ export declare class CleanStateBase<TState extends Record<string, any>> {
|
|
11
12
|
get initialState(): TState;
|
12
13
|
readonly putMany: (newValues: Partial<TState>) => void;
|
13
14
|
}
|
15
|
+
/** @internal */
|
14
16
|
export declare const CleanState: ICleanStateConstructor & ICleanStateClass;
|
@@ -13,6 +13,7 @@ var __assign = (this && this.__assign) || function () {
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
14
14
|
exports.CleanState = exports.CleanStateBase = void 0;
|
15
15
|
var react_1 = require("react");
|
16
|
+
/** @internal */
|
16
17
|
var CleanStateBase = /** @class */ (function () {
|
17
18
|
function CleanStateBase(initialState) {
|
18
19
|
var _this = this;
|
@@ -83,20 +84,16 @@ var CleanStateBase = /** @class */ (function () {
|
|
83
84
|
var _a;
|
84
85
|
// @todo Make state updates accessible immediately. Use state.staged to access the scheduled updates.
|
85
86
|
var setter;
|
86
|
-
// @todo Support SetStateAction callback signature in state.put(...);
|
87
87
|
_a = retrieveState(_this.initialState[key]), _this._values_[key] = _a[0], setter = _a[1];
|
88
88
|
_this._setters_[key] = (function (valueOrCallback) {
|
89
89
|
// this._staged_[key] = value;
|
90
90
|
setter(valueOrCallback);
|
91
91
|
});
|
92
92
|
});
|
93
|
-
/* Object.entries<TUseStateArray<TState>>(stateAndSetters).forEach(([key, responseFromUseState]) => {
|
94
|
-
[this._values_[key], this._setters_[key]] = responseFromUseState;
|
95
|
-
}); */
|
96
|
-
// return this;
|
97
93
|
};
|
98
94
|
return CleanStateBase;
|
99
95
|
}());
|
100
96
|
exports.CleanStateBase = CleanStateBase;
|
101
97
|
;
|
98
|
+
/** @internal */
|
102
99
|
exports.CleanState = CleanStateBase;
|
@@ -1,12 +1,36 @@
|
|
1
1
|
import { CleanStateBase } from './class';
|
2
|
+
/**
|
3
|
+
* Base type for an `initialState` object.
|
4
|
+
* It is a regular object type, with some reserved keys excluded.
|
5
|
+
*
|
6
|
+
* @_category Types
|
7
|
+
*/
|
2
8
|
export type TStateData = object & {
|
3
9
|
[Key in keyof CleanStateBase<{}>]?: never;
|
4
10
|
};
|
5
|
-
/**
|
11
|
+
/**
|
12
|
+
* Describes a `CleanState` object instantiated with an `initialState`
|
13
|
+
* object of type `TState`.
|
14
|
+
*
|
15
|
+
* @typeParam TState - The type of your `initialState` object.
|
16
|
+
*
|
17
|
+
* @_category Types
|
18
|
+
*/
|
6
19
|
export type TCleanState<TState extends TStateData> = (CleanStateBase<TState> & Omit<TState, keyof CleanStateBase<{}>>);
|
20
|
+
/**
|
21
|
+
* Takes a `TCleanState` type and returns the `initialState` type
|
22
|
+
* associated with the provided `TCleanState`.
|
23
|
+
*
|
24
|
+
* This is useful to isolated the type of your actual state data without
|
25
|
+
* any of the reserved keys provided by the Clean State utility.
|
26
|
+
*/
|
7
27
|
export type ExtractCleanStateData<YourCleanState extends CleanStateBase<{}>> = Omit<YourCleanState, keyof CleanStateBase<{}>>;
|
8
28
|
type StateInitFunction = (...args: any[]) => object;
|
9
29
|
type StateInit = object | StateInitFunction;
|
10
30
|
export type TInitialState<Initializer extends StateInit> = Initializer extends (...args: any[]) => (infer TState extends object) ? TState : Initializer;
|
31
|
+
/**
|
32
|
+
* @typeParam TInit - An initial state object, or a function that
|
33
|
+
* returns the initial state object.
|
34
|
+
*/
|
11
35
|
export type TUseCleanState = <TInit extends StateInit>(_initialState: TInit, ...props: TInit extends (...args: infer TProps extends any[]) => (infer TState extends object) ? TProps : []) => TCleanState<TInitialState<TInit>>;
|
12
36
|
export {};
|
@@ -1,6 +1,12 @@
|
|
1
1
|
import { TUseCleanState } from './hook-types';
|
2
2
|
/**
|
3
|
-
*
|
4
|
-
*
|
3
|
+
* @summary
|
4
|
+
* Creates a state object, which includes the provided values,
|
5
|
+
* as well as helper methods for updating those values and automatically
|
6
|
+
* rerendering your component's UI to reflect said updates.
|
7
|
+
*
|
8
|
+
* @remarks
|
9
|
+
* Uses {@link React.useState} under the hook, with a separate call
|
10
|
+
* to `useState` for each top-level key in the provided object.
|
5
11
|
*/
|
6
12
|
export declare const useCleanState: TUseCleanState;
|
@@ -4,8 +4,14 @@ exports.useCleanState = void 0;
|
|
4
4
|
var react_1 = require("react");
|
5
5
|
var class_1 = require("./class");
|
6
6
|
/**
|
7
|
-
*
|
8
|
-
*
|
7
|
+
* @summary
|
8
|
+
* Creates a state object, which includes the provided values,
|
9
|
+
* as well as helper methods for updating those values and automatically
|
10
|
+
* rerendering your component's UI to reflect said updates.
|
11
|
+
*
|
12
|
+
* @remarks
|
13
|
+
* Uses {@link React.useState} under the hook, with a separate call
|
14
|
+
* to `useState` for each top-level key in the provided object.
|
9
15
|
*/
|
10
16
|
var useCleanState = function (_initialState) {
|
11
17
|
var props = [];
|
@@ -1,4 +1,8 @@
|
|
1
|
+
/**
|
2
|
+
* @module CleanState
|
3
|
+
*/
|
1
4
|
import '../../globals';
|
2
5
|
export { CleanState } from './class';
|
3
6
|
export { useCleanState } from './hooks';
|
4
7
|
export type { TCleanState, TStateData, ExtractCleanStateData } from './hook-types';
|
8
|
+
export * as MergedState from '../../base/merged-state';
|
@@ -1,8 +1,35 @@
|
|
1
1
|
"use strict";
|
2
|
+
/**
|
3
|
+
* @module CleanState
|
4
|
+
*/
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
6
|
+
if (k2 === undefined) k2 = k;
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
10
|
+
}
|
11
|
+
Object.defineProperty(o, k2, desc);
|
12
|
+
}) : (function(o, m, k, k2) {
|
13
|
+
if (k2 === undefined) k2 = k;
|
14
|
+
o[k2] = m[k];
|
15
|
+
}));
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
18
|
+
}) : function(o, v) {
|
19
|
+
o["default"] = v;
|
20
|
+
});
|
21
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
22
|
+
if (mod && mod.__esModule) return mod;
|
23
|
+
var result = {};
|
24
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
25
|
+
__setModuleDefault(result, mod);
|
26
|
+
return result;
|
27
|
+
};
|
2
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.useCleanState = exports.CleanState = void 0;
|
29
|
+
exports.MergedState = exports.useCleanState = exports.CleanState = void 0;
|
4
30
|
require("../../globals");
|
5
31
|
var class_1 = require("./class");
|
6
32
|
Object.defineProperty(exports, "CleanState", { enumerable: true, get: function () { return class_1.CleanState; } });
|
7
33
|
var hooks_1 = require("./hooks");
|
8
34
|
Object.defineProperty(exports, "useCleanState", { enumerable: true, get: function () { return hooks_1.useCleanState; } });
|
35
|
+
exports.MergedState = __importStar(require("../../base/merged-state"));
|
@@ -1,14 +1,24 @@
|
|
1
1
|
import type { Extractor } from './types/extractor';
|
2
2
|
import { ComponentInstance } from '../instance';
|
3
|
+
import { TPropsBase } from '../logic';
|
3
4
|
/**
|
4
|
-
*
|
5
|
+
* @summary
|
6
|
+
* A modern class component for React that is fully compatible with
|
7
|
+
* React Hooks and all of React's latest features.
|
8
|
+
*
|
9
|
+
* It is a superset of {@link ComponentInstance} that allows defining your
|
5
10
|
* component's JSX template directly inside the class.
|
6
11
|
*
|
12
|
+
* @remarks
|
13
|
+
* In essence, this is a class wrapper around an underlying function component.
|
14
|
+
* It acts as syntactic sugar, allowing you to create a regular function
|
15
|
+
* component, while writing in an object-oriented format.
|
16
|
+
*
|
7
17
|
* This is designed to closely resemble the old {@link React.Component} class,
|
8
18
|
* making it easier to migrate older class components to the newer hooks-based system
|
9
19
|
* with little to no changes to their existing semantics/implementation.
|
10
20
|
*/
|
11
|
-
export declare class ClassComponent<TProps extends
|
21
|
+
export declare class ClassComponent<TProps extends TPropsBase = null> extends ComponentInstance<TProps> {
|
12
22
|
/**
|
13
23
|
* Analogous to {@link React.Component.render}. A function that returns
|
14
24
|
* your component's JSX template.
|
@@ -81,7 +91,7 @@ export declare class ClassComponent<TProps extends object = WeakEmptyObject> ext
|
|
81
91
|
static readonly FC: Extractor;
|
82
92
|
}
|
83
93
|
export { ClassComponent as Component };
|
84
|
-
export { Use } from '
|
94
|
+
export { Use } from '../../helpers/use-component';
|
85
95
|
/** /
|
86
96
|
testing: {
|
87
97
|
const a: object = {b: ''};
|
@@ -21,9 +21,18 @@ var instance_1 = require("../instance");
|
|
21
21
|
var function_name_1 = require("./utils/function-name");
|
22
22
|
var rerender_1 = require("../../helpers/rerender");
|
23
23
|
/**
|
24
|
-
*
|
24
|
+
* @summary
|
25
|
+
* A modern class component for React that is fully compatible with
|
26
|
+
* React Hooks and all of React's latest features.
|
27
|
+
*
|
28
|
+
* It is a superset of {@link ComponentInstance} that allows defining your
|
25
29
|
* component's JSX template directly inside the class.
|
26
30
|
*
|
31
|
+
* @remarks
|
32
|
+
* In essence, this is a class wrapper around an underlying function component.
|
33
|
+
* It acts as syntactic sugar, allowing you to create a regular function
|
34
|
+
* component, while writing in an object-oriented format.
|
35
|
+
*
|
27
36
|
* This is designed to closely resemble the old {@link React.Component} class,
|
28
37
|
* making it easier to migrate older class components to the newer hooks-based system
|
29
38
|
* with little to no changes to their existing semantics/implementation.
|
@@ -128,7 +137,7 @@ var ClassComponent = /** @class */ (function (_super) {
|
|
128
137
|
}(instance_1.ComponentInstance));
|
129
138
|
exports.ClassComponent = ClassComponent;
|
130
139
|
exports.Component = ClassComponent;
|
131
|
-
var use_component_1 = require("
|
140
|
+
var use_component_1 = require("../../helpers/use-component");
|
132
141
|
Object.defineProperty(exports, "Use", { enumerable: true, get: function () { return use_component_1.Use; } });
|
133
142
|
/** /
|
134
143
|
testing: {
|
@@ -1,8 +1,6 @@
|
|
1
1
|
import type { UseInstance } from './types/hook';
|
2
|
-
import { ComponentLogic } from '../../classy/logic';
|
2
|
+
import { ComponentLogic, type TPropsBase } from '../../classy/logic';
|
3
3
|
type AsyncAllowedEffectCallback = () => Awaitable<IVoidFunction>;
|
4
|
-
/** An empty function. It returns (void) without performing any operations. */
|
5
|
-
export declare const noOp: () => void;
|
6
4
|
/**
|
7
5
|
* A superset of {@link ComponentLogic} that adds support for lifecycle methods.
|
8
6
|
* This provides a declarative API for working with your React function component's lifecycle,
|
@@ -10,7 +8,7 @@ export declare const noOp: () => void;
|
|
10
8
|
*
|
11
9
|
* @see https://github.com/cleanjsweb/neat-react#lifecycle-useinstance
|
12
10
|
*/
|
13
|
-
export declare class ComponentInstance<TProps extends
|
11
|
+
export declare class ComponentInstance<TProps extends TPropsBase = null> extends ComponentLogic<TProps> {
|
14
12
|
/**
|
15
13
|
* Runs only _before_ first render,
|
16
14
|
* i.e before the component instance is mounted.
|
@@ -60,11 +58,35 @@ export declare class ComponentInstance<TProps extends object = NonPrimitive> ext
|
|
60
58
|
*/
|
61
59
|
cleanUp: IVoidFunction;
|
62
60
|
}
|
61
|
+
/**
|
62
|
+
* @summary
|
63
|
+
* Enables full separation of concerns between a React components template
|
64
|
+
* and all of the logic that drives it.
|
65
|
+
*
|
66
|
+
* Returns an instance that fully represents a logical instance
|
67
|
+
* of a rendered React component, with the exception of the JSX template itself.
|
68
|
+
*
|
69
|
+
* This means the all of your components logic and lifecycle handlers
|
70
|
+
* can be externalized from the function component itself,
|
71
|
+
* and defined in a separate class.
|
72
|
+
*
|
73
|
+
* @remarks
|
74
|
+
* The provided class should be a subclass of {@link ComponentInstance}.
|
75
|
+
*
|
76
|
+
* @privateRemarks
|
77
|
+
* To ensure successful type checking, the second parameter must be written with spread syntax.
|
78
|
+
* Likely because of the `exactOptionalPropertyTypes` config option turned on,
|
79
|
+
* and `UseInstance` using an empty tuple in its rest parameter type, attempting to simply
|
80
|
+
* retrieve the second argument directly causes an error when that argument is passed on to `useLogic`.
|
81
|
+
* But directly working with the rest array bypasses the problem. Also note that the issue persists even when
|
82
|
+
* the second param is given `{}` as a default follow to account for the empty tuple case. TypeScript
|
83
|
+
* just wants us to use the rest parameter explicitly by force.
|
84
|
+
*/
|
63
85
|
export declare const useInstance: UseInstance;
|
64
86
|
export {};
|
65
87
|
/** /
|
66
88
|
testing: {
|
67
|
-
class A extends ComponentInstance<
|
89
|
+
class A extends ComponentInstance<EmptyObject> {
|
68
90
|
getInitialState = (p?: object) => ({putan: ''});
|
69
91
|
// k = this.props.o
|
70
92
|
am = this.state['_initialValues_'];
|
@@ -15,13 +15,11 @@ var __extends = (this && this.__extends) || (function () {
|
|
15
15
|
};
|
16
16
|
})();
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
18
|
-
exports.useInstance = exports.ComponentInstance =
|
18
|
+
exports.useInstance = exports.ComponentInstance = void 0;
|
19
19
|
var react_1 = require("react");
|
20
20
|
var logic_1 = require("../../classy/logic");
|
21
21
|
var mount_callbacks_1 = require("./mount-callbacks");
|
22
|
-
|
23
|
-
var noOp = function () { };
|
24
|
-
exports.noOp = noOp;
|
22
|
+
var helpers_1 = require("../../helpers");
|
25
23
|
/**
|
26
24
|
* A superset of {@link ComponentLogic} that adds support for lifecycle methods.
|
27
25
|
* This provides a declarative API for working with your React function component's lifecycle,
|
@@ -54,7 +52,7 @@ var ComponentInstance = /** @class */ (function (_super) {
|
|
54
52
|
*
|
55
53
|
* Uses `useEffect()` under the hood.
|
56
54
|
*/
|
57
|
-
_this.onMount = function () { return
|
55
|
+
_this.onMount = function () { return helpers_1.noOp; };
|
58
56
|
/**
|
59
57
|
* Runs _before_ every render cycle, including the first.
|
60
58
|
* Useful for logic that is involved in determining what to render.
|
@@ -73,7 +71,7 @@ var ComponentInstance = /** @class */ (function (_super) {
|
|
73
71
|
*
|
74
72
|
* Returns a cleanup function.
|
75
73
|
*/
|
76
|
-
_this.onRender = function () { return
|
74
|
+
_this.onRender = function () { return helpers_1.noOp; };
|
77
75
|
/**
|
78
76
|
* Runs when the component is unmounted.
|
79
77
|
* It is called _after_ the cleanup function returned by onMount.
|
@@ -92,7 +90,22 @@ var ComponentInstance = /** @class */ (function (_super) {
|
|
92
90
|
}(logic_1.ComponentLogic));
|
93
91
|
exports.ComponentInstance = ComponentInstance;
|
94
92
|
;
|
95
|
-
|
93
|
+
/**
|
94
|
+
* @summary
|
95
|
+
* Enables full separation of concerns between a React components template
|
96
|
+
* and all of the logic that drives it.
|
97
|
+
*
|
98
|
+
* Returns an instance that fully represents a logical instance
|
99
|
+
* of a rendered React component, with the exception of the JSX template itself.
|
100
|
+
*
|
101
|
+
* This means the all of your components logic and lifecycle handlers
|
102
|
+
* can be externalized from the function component itself,
|
103
|
+
* and defined in a separate class.
|
104
|
+
*
|
105
|
+
* @remarks
|
106
|
+
* The provided class should be a subclass of {@link ComponentInstance}.
|
107
|
+
*
|
108
|
+
* @privateRemarks
|
96
109
|
* To ensure successful type checking, the second parameter must be written with spread syntax.
|
97
110
|
* Likely because of the `exactOptionalPropertyTypes` config option turned on,
|
98
111
|
* and `UseInstance` using an empty tuple in its rest parameter type, attempting to simply
|
@@ -150,7 +163,7 @@ var useInstance = function () {
|
|
150
163
|
exports.useInstance = useInstance;
|
151
164
|
/** /
|
152
165
|
testing: {
|
153
|
-
class A extends ComponentInstance<
|
166
|
+
class A extends ComponentInstance<EmptyObject> {
|
154
167
|
getInitialState = (p?: object) => ({putan: ''});
|
155
168
|
// k = this.props.o
|
156
169
|
am = this.state['_initialValues_'];
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useMountCallbacks = void 0;
|
4
4
|
var react_1 = require("react");
|
5
5
|
var mount_state_1 = require("../../helpers/mount-state");
|
6
|
+
/** @internal */
|
6
7
|
var useMountCallbacks = function (instance) {
|
7
8
|
var _a;
|
8
9
|
var isMounted = (0, mount_state_1.useMountState)();
|
@@ -1,6 +1,7 @@
|
|
1
|
+
import { TPropsBase } from '../../../classy/logic';
|
1
2
|
import { ComponentInstance } from '..';
|
2
|
-
type UIClassParam = typeof ComponentInstance<
|
3
|
-
type UIProplessClassParam = typeof ComponentInstance<
|
3
|
+
type UIClassParam = typeof ComponentInstance<NonNullable<TPropsBase>>;
|
4
|
+
type UIProplessClassParam = typeof ComponentInstance<null>;
|
4
5
|
export type UseInstance = {
|
5
6
|
<Class extends UIProplessClassParam>(Methods: Class): InstanceType<Class>;
|
6
7
|
<Class extends UIClassParam>(Methods: Class, props: InstanceType<Class>['props']): InstanceType<Class>;
|
@@ -1,7 +1,15 @@
|
|
1
1
|
import type { TCleanState } from '../../base/state';
|
2
2
|
import type { UseLogic } from './types/hook';
|
3
|
-
|
4
|
-
|
3
|
+
/**
|
4
|
+
* The base type for the props type argument.
|
5
|
+
* This is not the type the `props` property itself.
|
6
|
+
* It merely defines the type constraint for the type argument
|
7
|
+
* passed when extending any of the advanced external classes.
|
8
|
+
*
|
9
|
+
* It differs from the type of the actual props object
|
10
|
+
* in that it accepts null for components that don't take any props.
|
11
|
+
*/
|
12
|
+
export type TPropsBase = NonPrimitive | null;
|
5
13
|
/**
|
6
14
|
* Base class for a class that holds methods intended for use in a function component,
|
7
15
|
* as well as a static method for initializing state.
|
@@ -13,16 +21,22 @@ export type WeakEmpty = WeakEmptyObject;
|
|
13
21
|
* React hooks within this class.
|
14
22
|
*
|
15
23
|
* Call the {@link useLogic} hook inside your function component to instantiate the class.
|
24
|
+
*
|
25
|
+
* @typeParam TProps - {@include ./types/tprops.md}
|
26
|
+
*
|
27
|
+
* @group ComponentLogic
|
28
|
+
* @_category External Classes
|
16
29
|
*/
|
17
|
-
export declare class ComponentLogic<TProps extends
|
30
|
+
export declare class ComponentLogic<TProps extends TPropsBase = null> {
|
18
31
|
/**
|
19
32
|
* A {@link TCleanState | `CleanState`} object.
|
20
33
|
* Holds all of your component's state,
|
21
34
|
* and methods for conveniently manipulating those values.
|
35
|
+
* Initialiazed with the object returned from your `getInitialState` method.
|
22
36
|
*/
|
23
37
|
readonly state: TCleanState<ReturnType<this['getInitialState']>>;
|
24
|
-
/** The props
|
25
|
-
readonly props: TProps;
|
38
|
+
/** The props passed into your component at the time of rendering. */
|
39
|
+
readonly props: TProps extends null ? EmptyObject : TProps;
|
26
40
|
/**
|
27
41
|
* Values received from the hooks your component consumes.
|
28
42
|
* This holds the latest copy of the object returned by
|
@@ -34,7 +48,7 @@ export declare class ComponentLogic<TProps extends object = NonPrimitive> {
|
|
34
48
|
* It receives the initial `props` object and should return
|
35
49
|
* an object with the initial values for your component's state.
|
36
50
|
*/
|
37
|
-
getInitialState: (props?:
|
51
|
+
getInitialState: (props?: this["props"]) => object;
|
38
52
|
/**
|
39
53
|
* Call React hooks from here. If your component needs
|
40
54
|
* access to values return from the hooks you call,
|
@@ -44,7 +58,15 @@ export declare class ComponentLogic<TProps extends object = NonPrimitive> {
|
|
44
58
|
* your component class.
|
45
59
|
*/
|
46
60
|
useHooks: () => object | void;
|
61
|
+
_hmrPreserveKeys: Array<keyof this | (string & {})>;
|
62
|
+
_onHmrUpdate: <TInstance extends this>(oldInstance: TInstance) => void;
|
47
63
|
}
|
64
|
+
/**
|
65
|
+
* Returns an instance of the provided class, which holds methods for your component and
|
66
|
+
* encapsulates hook calls with the special {@link ComponentLogic.useHooks | `useHooks`} method.
|
67
|
+
*
|
68
|
+
* The class argument must be a subclass of {@link ComponentLogic}.
|
69
|
+
*/
|
48
70
|
export declare const useLogic: UseLogic;
|
49
71
|
/** /
|
50
72
|
testing: {
|
@@ -1,4 +1,13 @@
|
|
1
1
|
"use strict";
|
2
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
3
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
4
|
+
if (ar || !(i in from)) {
|
5
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
6
|
+
ar[i] = from[i];
|
7
|
+
}
|
8
|
+
}
|
9
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
10
|
+
};
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
12
|
exports.useLogic = exports.ComponentLogic = void 0;
|
4
13
|
var react_1 = require("react");
|
@@ -14,6 +23,11 @@ var state_1 = require("../../base/state");
|
|
14
23
|
* React hooks within this class.
|
15
24
|
*
|
16
25
|
* Call the {@link useLogic} hook inside your function component to instantiate the class.
|
26
|
+
*
|
27
|
+
* @typeParam TProps - {@include ./types/tprops.md}
|
28
|
+
*
|
29
|
+
* @group ComponentLogic
|
30
|
+
* @_category External Classes
|
17
31
|
*/
|
18
32
|
var ComponentLogic = /** @class */ (function () {
|
19
33
|
function ComponentLogic() {
|
@@ -32,11 +46,18 @@ var ComponentLogic = /** @class */ (function () {
|
|
32
46
|
* your component class.
|
33
47
|
*/
|
34
48
|
this.useHooks = function () { };
|
49
|
+
this._hmrPreserveKeys = [];
|
35
50
|
}
|
36
51
|
return ComponentLogic;
|
37
52
|
}());
|
38
53
|
exports.ComponentLogic = ComponentLogic;
|
39
54
|
;
|
55
|
+
/**
|
56
|
+
* Returns an instance of the provided class, which holds methods for your component and
|
57
|
+
* encapsulates hook calls with the special {@link ComponentLogic.useHooks | `useHooks`} method.
|
58
|
+
*
|
59
|
+
* The class argument must be a subclass of {@link ComponentLogic}.
|
60
|
+
*/
|
40
61
|
var useLogic = function () {
|
41
62
|
var _a;
|
42
63
|
var args = [];
|
@@ -44,21 +65,57 @@ var useLogic = function () {
|
|
44
65
|
args[_i] = arguments[_i];
|
45
66
|
}
|
46
67
|
var Logic = args[0], _b = args[1], props = _b === void 0 ? {} : _b;
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
var
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
68
|
+
// In production, we only use the latestInstance the first time, and it's ignored every other time.
|
69
|
+
// This means changing the class at runtime will have no effect in production.
|
70
|
+
// latestInstance is only extracted into a separate variable for use in dev mode during HMR.
|
71
|
+
var latestInstance = (0, react_1.useMemo)(function () { return new Logic(); }, [Logic]);
|
72
|
+
var instanceRef = (0, react_1.useRef)(latestInstance);
|
73
|
+
if (process.env.NODE_ENV === 'development') {
|
74
|
+
if (instanceRef.current !== latestInstance) {
|
75
|
+
console.log([
|
76
|
+
'HMR-updated component class detected.',
|
77
|
+
'Creating a new instance with the updated class.',
|
78
|
+
'All stateful values will be copied over.\n\n',
|
79
|
+
'Note that this mechanism only works in the `development` environment during HMR.',
|
80
|
+
'In production, the class argument will be ignored after the first render.\n\n',
|
81
|
+
'If this wasn\'t an HMR update, you should refactor your code to make sure',
|
82
|
+
'all clean-react hooks receive the same class object on every render.'
|
83
|
+
].join());
|
84
|
+
var oldInstance_1 = instanceRef.current;
|
85
|
+
var hmrPreserveKeys = __spreadArray(__spreadArray([], latestInstance._hmrPreserveKeys, true), [
|
86
|
+
'state', 'props', 'hooks',
|
87
|
+
], false);
|
88
|
+
hmrPreserveKeys.forEach(function (_key) {
|
89
|
+
var key = _key;
|
90
|
+
// @ts-expect-error We're assigning to readonly properties. Also, Typescript doesn't know that the type of the left and right side will always match, due to the dynamic access.
|
91
|
+
latestInstance[key] = oldInstance_1[key];
|
92
|
+
});
|
93
|
+
latestInstance._onHmrUpdate(oldInstance_1);
|
94
|
+
instanceRef.current = latestInstance;
|
95
|
+
Reflect.ownKeys(oldInstance_1).forEach(function (_key) {
|
96
|
+
var key = _key;
|
97
|
+
delete oldInstance_1[key];
|
98
|
+
});
|
99
|
+
Object.setPrototypeOf(oldInstance_1, latestInstance);
|
100
|
+
}
|
101
|
+
}
|
102
|
+
var self = instanceRef.current;
|
103
|
+
/**
|
104
|
+
* A proxy variable to allow typechecking of the assignment
|
105
|
+
* to a readonly property,
|
106
|
+
* despite the need for "readonly" error suppression.
|
107
|
+
*/
|
108
|
+
var _propsProxy;
|
109
|
+
/** @see {@link _propsProxy} */
|
110
|
+
var _stateProxy;
|
111
|
+
/** @see {@link _propsProxy} */
|
112
|
+
var _hooksProxy;
|
56
113
|
// @ts-expect-error
|
57
|
-
self.props = (
|
114
|
+
self.props = (_propsProxy = props);
|
58
115
|
// @ts-expect-error
|
59
|
-
self.state = (
|
116
|
+
self.state = (_stateProxy = (0, state_1.useCleanState)(self.getInitialState, props));
|
60
117
|
// @ts-expect-error
|
61
|
-
self.hooks = (
|
118
|
+
self.hooks = (_hooksProxy = (_a = self.useHooks()) !== null && _a !== void 0 ? _a : {});
|
62
119
|
return self;
|
63
120
|
};
|
64
121
|
exports.useLogic = useLogic;
|
@@ -1,10 +1,9 @@
|
|
1
|
-
import type { ComponentLogic } from '..';
|
1
|
+
import type { ComponentLogic, TPropsBase } from '..';
|
2
2
|
/*************************************
|
3
3
|
* # Hooks *
|
4
4
|
**************************************/
|
5
|
-
|
6
|
-
type
|
7
|
-
type ULProplessClassParam = typeof ComponentLogic<HardEmptyObject>;
|
5
|
+
type ULClassParam = typeof ComponentLogic<NonNullable<TPropsBase>>;
|
6
|
+
type ULProplessClassParam = typeof ComponentLogic<null>;
|
8
7
|
export type UseLogic = {
|
9
8
|
<Class extends ULProplessClassParam>(Methods: Class): InstanceType<Class>;
|
10
9
|
<Class extends ULClassParam>(Methods: Class, props: InstanceType<Class>['props']): InstanceType<Class>;
|
@@ -0,0 +1,9 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.ComponentInstance = exports.ComponentLogic = exports.ComponentMethods = void 0;
|
4
|
+
var methods_1 = require("../../base/methods");
|
5
|
+
Object.defineProperty(exports, "ComponentMethods", { enumerable: true, get: function () { return methods_1.ComponentMethods; } });
|
6
|
+
var logic_1 = require("../../classy/logic");
|
7
|
+
Object.defineProperty(exports, "ComponentLogic", { enumerable: true, get: function () { return logic_1.ComponentLogic; } });
|
8
|
+
var instance_1 = require("../../classy/instance");
|
9
|
+
Object.defineProperty(exports, "ComponentInstance", { enumerable: true, get: function () { return instance_1.ComponentInstance; } });
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/**
|
2
|
+
* API Reference
|
3
|
+
* @module API
|
4
|
+
*/
|
5
|
+
export { useCleanState } from '../../base/state';
|
6
|
+
export { useMethods } from '../../base/methods';
|
7
|
+
export { useLogic } from '../../classy/logic';
|
8
|
+
export { useInstance } from '../../classy/instance';
|
9
|
+
export { ClassComponent } from '../../classy/class';
|
10
|
+
/** @namespace */
|
11
|
+
export * as BaseClasses from './base-classes';
|
12
|
+
export * as Helpers from '../../helpers';
|
13
|
+
export * as References from './references';
|
@@ -0,0 +1,44 @@
|
|
1
|
+
"use strict";
|
2
|
+
/**
|
3
|
+
* API Reference
|
4
|
+
* @module API
|
5
|
+
*/
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
7
|
+
if (k2 === undefined) k2 = k;
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
11
|
+
}
|
12
|
+
Object.defineProperty(o, k2, desc);
|
13
|
+
}) : (function(o, m, k, k2) {
|
14
|
+
if (k2 === undefined) k2 = k;
|
15
|
+
o[k2] = m[k];
|
16
|
+
}));
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
19
|
+
}) : function(o, v) {
|
20
|
+
o["default"] = v;
|
21
|
+
});
|
22
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
23
|
+
if (mod && mod.__esModule) return mod;
|
24
|
+
var result = {};
|
25
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
26
|
+
__setModuleDefault(result, mod);
|
27
|
+
return result;
|
28
|
+
};
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
30
|
+
exports.References = exports.Helpers = exports.BaseClasses = exports.ClassComponent = exports.useInstance = exports.useLogic = exports.useMethods = exports.useCleanState = void 0;
|
31
|
+
var state_1 = require("../../base/state");
|
32
|
+
Object.defineProperty(exports, "useCleanState", { enumerable: true, get: function () { return state_1.useCleanState; } });
|
33
|
+
var methods_1 = require("../../base/methods");
|
34
|
+
Object.defineProperty(exports, "useMethods", { enumerable: true, get: function () { return methods_1.useMethods; } });
|
35
|
+
var logic_1 = require("../../classy/logic");
|
36
|
+
Object.defineProperty(exports, "useLogic", { enumerable: true, get: function () { return logic_1.useLogic; } });
|
37
|
+
var instance_1 = require("../../classy/instance");
|
38
|
+
Object.defineProperty(exports, "useInstance", { enumerable: true, get: function () { return instance_1.useInstance; } });
|
39
|
+
var class_1 = require("../../classy/class");
|
40
|
+
Object.defineProperty(exports, "ClassComponent", { enumerable: true, get: function () { return class_1.ClassComponent; } });
|
41
|
+
/** @namespace */
|
42
|
+
exports.BaseClasses = __importStar(require("./base-classes"));
|
43
|
+
exports.Helpers = __importStar(require("../../helpers"));
|
44
|
+
exports.References = __importStar(require("./references"));
|
@@ -0,0 +1,5 @@
|
|
1
|
+
export * as $CleanState from '../../base/state';
|
2
|
+
export * as $ComponentMethods from '../../base/methods';
|
3
|
+
export * as ComponentLogic from '../../classy/logic';
|
4
|
+
export * as ComponentInstance from '../../classy/instance';
|
5
|
+
export * as ClassComponent from '../../classy/class';
|
@@ -0,0 +1,31 @@
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
26
|
+
exports.ClassComponent = exports.ComponentInstance = exports.ComponentLogic = exports.$ComponentMethods = exports.$CleanState = void 0;
|
27
|
+
exports.$CleanState = __importStar(require("../../base/state"));
|
28
|
+
exports.$ComponentMethods = __importStar(require("../../base/methods"));
|
29
|
+
exports.ComponentLogic = __importStar(require("../../classy/logic"));
|
30
|
+
exports.ComponentInstance = __importStar(require("../../classy/instance"));
|
31
|
+
exports.ClassComponent = __importStar(require("../../classy/class"));
|
package/build/globals.d.ts
CHANGED
@@ -8,7 +8,7 @@ declare const UniqueSecretSymbolKey: unique symbol;
|
|
8
8
|
// '': '',
|
9
9
|
}
|
10
10
|
|
11
|
-
let TT:
|
11
|
+
let TT: EmptyObject = {};
|
12
12
|
TT = tt;
|
13
13
|
}/**/
|
14
14
|
declare global {
|
@@ -46,17 +46,17 @@ declare global {
|
|
46
46
|
* Having a single key allows the object to throw type errors
|
47
47
|
* of the form:
|
48
48
|
* ```
|
49
|
-
* Type `A` has no properties in common with `
|
49
|
+
* Type `A` has no properties in common with `EmptyObject`.
|
50
50
|
* ```
|
51
51
|
* This may provide a slightly stricter type checking than simply
|
52
52
|
* using the non-nullish (`{}`) or non-primitive (`object`)
|
53
53
|
* built-in types.
|
54
54
|
*
|
55
|
-
* Note: `
|
55
|
+
* Note: `EmptyObject` is not assignable to `NeverObject`
|
56
56
|
* because it has a key whose value type includes `undefined`,
|
57
|
-
* but `
|
57
|
+
* but `NeverObject` keys can only have a type of `never`.
|
58
58
|
*/
|
59
|
-
interface
|
59
|
+
interface EmptyObject {
|
60
60
|
[UniqueSecretSymbolKey]?: never;
|
61
61
|
}
|
62
62
|
/**
|
@@ -65,7 +65,7 @@ declare global {
|
|
65
65
|
* from ever being stored on the object. The object is therefore
|
66
66
|
* guaranteed to always be empty.
|
67
67
|
*/
|
68
|
-
interface
|
68
|
+
interface NeverObject {
|
69
69
|
[key: keyof any]: never;
|
70
70
|
}
|
71
71
|
type valueof<TObject> = TObject[keyof TObject];
|
@@ -77,6 +77,7 @@ declare global {
|
|
77
77
|
}
|
78
78
|
namespace NodeJS {
|
79
79
|
interface ProcessEnv {
|
80
|
+
NODE_ENV: 'development' | 'production' | 'test';
|
80
81
|
}
|
81
82
|
}
|
82
83
|
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
interface OoreInstanceForHMR {
|
2
|
+
hmrPreserveKeys?: Array<keyof this>;
|
3
|
+
hmrConstructorParams?: any[];
|
4
|
+
hmrWillUpdate: (newInstance: OoreInstanceForHMR) => void;
|
5
|
+
hmrDidUpdate: (oldInstance: OoreInstanceForHMR) => void;
|
6
|
+
}
|
7
|
+
interface OoreClassForHMR {
|
8
|
+
new (...params: any[]): OoreInstanceForHMR;
|
9
|
+
instances: InstanceType<OoreClassForHMR>[];
|
10
|
+
}
|
11
|
+
declare global {
|
12
|
+
interface Window {
|
13
|
+
handleOoreHmr: (Class: OoreClassForHMR, module: {
|
14
|
+
hot?: __WebpackModuleApi.Hot;
|
15
|
+
}, name?: string) => void;
|
16
|
+
}
|
17
|
+
}
|
18
|
+
export {};
|
@@ -0,0 +1,48 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
3
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
4
|
+
if (ar || !(i in from)) {
|
5
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
6
|
+
ar[i] = from[i];
|
7
|
+
}
|
8
|
+
}
|
9
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
10
|
+
};
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
12
|
+
// window.__OBJECT_ORIENTED_REACT__ = window.__OBJECT_ORIENTED_REACT__ || {};
|
13
|
+
if (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') {
|
14
|
+
window.handleOoreHmr = function (Class, module, name) {
|
15
|
+
var _a, _b;
|
16
|
+
var classKey = name || Class.name;
|
17
|
+
(_a = module.hot) === null || _a === void 0 ? void 0 : _a.dispose(function (data) {
|
18
|
+
data.ooreClasses[classKey] = { instances: Class.instances };
|
19
|
+
});
|
20
|
+
console.log('New module instances:', Class.instances.length);
|
21
|
+
var Classes = (_b = module.hot) === null || _b === void 0 ? void 0 : _b.data.ooreClasses;
|
22
|
+
if (!Classes[classKey]) {
|
23
|
+
console.warn([
|
24
|
+
"New component \"".concat(Class.name, "\" detected.\n\nIf this"),
|
25
|
+
'component was renamed, oore will be unable to match it',
|
26
|
+
'with the previous name, and a reload may be necessary.',
|
27
|
+
'You can pass the name argument to the hmr handler',
|
28
|
+
'to ensure a consistent identifier for your component',
|
29
|
+
'class across renames and therefore bypass this issue.',
|
30
|
+
].join(' '));
|
31
|
+
return;
|
32
|
+
}
|
33
|
+
var instances = Classes[classKey].instances;
|
34
|
+
instances.forEach(function (instance) {
|
35
|
+
var _a, _b, _c, _d;
|
36
|
+
var newInstance = new (Class.bind.apply(Class, __spreadArray([void 0], ((_a = instance.hmrConstructorParams) !== null && _a !== void 0 ? _a : []), false)))();
|
37
|
+
(_b = instance.hmrPreserveKeys) === null || _b === void 0 ? void 0 : _b.forEach(function (_key) {
|
38
|
+
var key = _key;
|
39
|
+
// @ts-expect-error Typescript doesn't realize that since both sides have the same key, the value type being assigned will always match the property type it's assigned to.
|
40
|
+
newInstance[key] = instance[key];
|
41
|
+
});
|
42
|
+
// instance.hotReplace(newInstance);
|
43
|
+
(_c = instance.hmrWillUpdate) === null || _c === void 0 ? void 0 : _c.call(instance, newInstance);
|
44
|
+
(_d = newInstance.hmrDidUpdate) === null || _d === void 0 ? void 0 : _d.call(newInstance, instance);
|
45
|
+
});
|
46
|
+
console.log('Updated module instances (max 3):', Class.instances.slice(0, 3));
|
47
|
+
};
|
48
|
+
}
|
package/build/helpers/index.d.ts
CHANGED
@@ -1,2 +1,13 @@
|
|
1
|
+
/**
|
2
|
+
* <!-- @ mergeModuleWith API -->
|
3
|
+
* @module Helpers
|
4
|
+
*/
|
1
5
|
export * from './mount-state';
|
2
6
|
export * from './rerender';
|
7
|
+
export * from './use-component';
|
8
|
+
export * from './type-guards';
|
9
|
+
/**
|
10
|
+
* An empty function.
|
11
|
+
* It returns (void) without performing any operations.
|
12
|
+
*/
|
13
|
+
export declare const noOp: () => void;
|
package/build/helpers/index.js
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
"use strict";
|
2
|
+
/**
|
3
|
+
* <!-- @ mergeModuleWith API -->
|
4
|
+
* @module Helpers
|
5
|
+
*/
|
2
6
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
7
|
if (k2 === undefined) k2 = k;
|
4
8
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
@@ -14,5 +18,15 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
18
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
19
|
};
|
16
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
21
|
+
exports.noOp = void 0;
|
17
22
|
__exportStar(require("./mount-state"), exports);
|
18
23
|
__exportStar(require("./rerender"), exports);
|
24
|
+
__exportStar(require("./use-component"), exports);
|
25
|
+
// export * from './hmr';
|
26
|
+
__exportStar(require("./type-guards"), exports);
|
27
|
+
/**
|
28
|
+
* An empty function.
|
29
|
+
* It returns (void) without performing any operations.
|
30
|
+
*/
|
31
|
+
var noOp = function () { };
|
32
|
+
exports.noOp = noOp;
|
@@ -3,6 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useRerender = void 0;
|
4
4
|
var mount_state_1 = require("../helpers/mount-state");
|
5
5
|
var react_1 = require("react");
|
6
|
+
/**
|
7
|
+
* Returns a function that can be called to manually trigger
|
8
|
+
* a rerender of your component.
|
9
|
+
*/
|
6
10
|
var useRerender = function () {
|
7
11
|
var isMounted = (0, mount_state_1.useMountState)();
|
8
12
|
// Skip the value, we don't need it. Grab just the setter function.
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const canIndex: (key: keyof any, targetObject: any) => key is keyof typeof targetObject;
|
@@ -0,0 +1,9 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.canIndex = void 0;
|
4
|
+
var canIndex = function (key, targetObject) {
|
5
|
+
return Reflect
|
6
|
+
.ownKeys(targetObject)
|
7
|
+
.includes(typeof key === 'number' ? "".concat(key) : key);
|
8
|
+
};
|
9
|
+
exports.canIndex = canIndex;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@cleanweb/react",
|
3
|
-
"version": "2.1.
|
3
|
+
"version": "2.1.1-beta.1",
|
4
4
|
"description": "A suite of helpers for writing cleaner React function components.",
|
5
5
|
"engines": {
|
6
6
|
"node": ">=18"
|
@@ -18,12 +18,15 @@
|
|
18
18
|
"exports": {
|
19
19
|
".": "./build/classy/index.js",
|
20
20
|
"./base": "./build/base/index.js",
|
21
|
-
"./helpers": "./build/helpers/index.js"
|
21
|
+
"./helpers": "./build/helpers/index.js",
|
22
|
+
"./all": "./build/index.js"
|
22
23
|
},
|
23
24
|
"scripts": {
|
24
25
|
"prebuild": "rimraf ./build",
|
25
26
|
"build": "tsc && tsc-alias",
|
27
|
+
"serve-docs": "serve docs",
|
26
28
|
"postbuild": "copyfiles tsconfig.json build",
|
29
|
+
"build:docs": "typedoc",
|
27
30
|
"_": "",
|
28
31
|
"prepublishOnly": "npm run build",
|
29
32
|
"publish:patch": "npm version patch && npm publish",
|
@@ -61,6 +64,7 @@
|
|
61
64
|
"@babel/preset-typescript": "^7.26.0",
|
62
65
|
"@types/node": "20.14.10",
|
63
66
|
"@types/react": "^16",
|
67
|
+
"@types/webpack-env": "^1.18.8",
|
64
68
|
"babel-preset-react-app": "^10.0.1",
|
65
69
|
"copyfiles": "^2.4.1",
|
66
70
|
"eslint": "^9.15.0",
|
@@ -68,7 +72,12 @@
|
|
68
72
|
"eslint-plugin-react": "^7.37.2",
|
69
73
|
"globals": "^15.12.0",
|
70
74
|
"rimraf": "^6.0.1",
|
75
|
+
"serve": "^14.2.4",
|
71
76
|
"tsc-alias": "1.8.10",
|
77
|
+
"typedoc": "latest",
|
78
|
+
"typedoc-plugin-coverage": "^3.4.1",
|
79
|
+
"typedoc-plugin-markdown": "^4.4.1",
|
80
|
+
"typedoc-plugin-mdn-links": "^4.0.13",
|
72
81
|
"typescript": "^5.6.2"
|
73
82
|
},
|
74
83
|
"peerDependencies": {
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|