@cleanweb/react 1.1.1-beta.2 → 1.1.1-beta.21
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/build/base/merged-state.d.ts +1 -0
- package/build/base/merged-state.js +4 -1
- package/build/base/methods.d.ts +24 -7
- package/build/base/methods.js +45 -81
- package/build/base/state.d.ts +14 -7
- package/build/base/state.js +8 -7
- package/build/classy/class.d.ts +106 -5
- package/build/classy/class.js +83 -17
- package/build/classy/instance.d.ts +17 -13
- package/build/classy/instance.js +58 -42
- package/build/classy/logic.d.ts +53 -19
- package/build/classy/logic.js +66 -52
- package/build/globals.d.ts +10 -32
- package/build/globals.js +2 -20
- package/build/index.d.ts +1 -1
- package/build/index.js +2 -1
- package/build/tsconfig.json +3 -1
- package/package.json +2 -2
- package/build/globals.private.d.ts +0 -48
- package/build/globals.private.js +0 -40
@@ -12,6 +12,7 @@ var __assign = (this && this.__assign) || function () {
|
|
12
12
|
};
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
14
14
|
exports.useMergedState = void 0;
|
15
|
+
require("../globals");
|
15
16
|
var react_1 = require("react");
|
16
17
|
var MergedState = /** @class */ (function () {
|
17
18
|
function MergedState(initialState) {
|
@@ -70,7 +71,9 @@ var MergedState = /** @class */ (function () {
|
|
70
71
|
return MergedState;
|
71
72
|
}());
|
72
73
|
var useMergedState = function (initialState) {
|
73
|
-
var cleanState = (0, react_1.useMemo)(function () {
|
74
|
+
var cleanState = (0, react_1.useMemo)(function () {
|
75
|
+
return new MergedState(initialState);
|
76
|
+
}, []);
|
74
77
|
MergedState.useRefresh.call(cleanState);
|
75
78
|
return cleanState;
|
76
79
|
};
|
package/build/base/methods.d.ts
CHANGED
@@ -1,8 +1,25 @@
|
|
1
|
-
import type { TCleanState } from './state';
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
import type { TCleanState, TStateData } from './state';
|
2
|
+
/**
|
3
|
+
* Base class for a class that holds methods intended for use in a function component.
|
4
|
+
* These methods will have access to the components state and props via
|
5
|
+
* `this.state` and `this.props` respectively.
|
6
|
+
*
|
7
|
+
* Call the {@link useMethods} hook inside your function component to instantiate the class.
|
8
|
+
*/
|
9
|
+
export declare class ComponentMethods<TProps extends object = {}, TState extends TStateData | null = null> {
|
10
|
+
readonly props: TProps;
|
11
|
+
state: TState extends TStateData ? TCleanState<TState> : null;
|
5
12
|
}
|
6
|
-
type UseMethods =
|
7
|
-
|
8
|
-
|
13
|
+
type UseMethods = {
|
14
|
+
<Class extends typeof ComponentMethods<object, object>>(Methods: Class & Constructor<InstanceType<Class>>, props: InstanceType<Class>['props'], state: InstanceType<Class>['state']): InstanceType<Class>;
|
15
|
+
<Class extends typeof ComponentMethods<object, null>>(Methods: Class & Constructor<InstanceType<Class>>, props: InstanceType<Class>['props'], state?: null): InstanceType<Class>;
|
16
|
+
<Class extends typeof ComponentMethods<HardEmptyObject, null>>(Methods: Class & Constructor<InstanceType<Class>>): InstanceType<Class>;
|
17
|
+
};
|
18
|
+
/**
|
19
|
+
* Returns an instance of the provided class,
|
20
|
+
* with the state and props arguments added as instance members.
|
21
|
+
*
|
22
|
+
* `state` must be an instance of `CleanState` created with {@link useCleanState}.
|
23
|
+
*/
|
24
|
+
declare const useMethods: UseMethods;
|
25
|
+
export { useMethods };
|
package/build/base/methods.js
CHANGED
@@ -1,58 +1,15 @@
|
|
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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
18
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
19
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
20
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
21
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
22
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
23
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
24
|
-
});
|
25
|
-
};
|
26
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
27
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
28
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
29
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
30
|
-
function step(op) {
|
31
|
-
if (f) throw new TypeError("Generator is already executing.");
|
32
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
33
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
34
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
35
|
-
switch (op[0]) {
|
36
|
-
case 0: case 1: t = op; break;
|
37
|
-
case 4: _.label++; return { value: op[1], done: false };
|
38
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
39
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
40
|
-
default:
|
41
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
42
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
43
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
44
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
45
|
-
if (t[2]) _.ops.pop();
|
46
|
-
_.trys.pop(); continue;
|
47
|
-
}
|
48
|
-
op = body.call(thisArg, _);
|
49
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
50
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
51
|
-
}
|
52
|
-
};
|
53
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
54
3
|
exports.useMethods = exports.ComponentMethods = void 0;
|
4
|
+
// Values
|
55
5
|
var react_1 = require("react");
|
6
|
+
/**
|
7
|
+
* Base class for a class that holds methods intended for use in a function component.
|
8
|
+
* These methods will have access to the components state and props via
|
9
|
+
* `this.state` and `this.props` respectively.
|
10
|
+
*
|
11
|
+
* Call the {@link useMethods} hook inside your function component to instantiate the class.
|
12
|
+
*/
|
56
13
|
var ComponentMethods = /** @class */ (function () {
|
57
14
|
function ComponentMethods() {
|
58
15
|
}
|
@@ -60,41 +17,48 @@ var ComponentMethods = /** @class */ (function () {
|
|
60
17
|
}());
|
61
18
|
exports.ComponentMethods = ComponentMethods;
|
62
19
|
;
|
63
|
-
|
64
|
-
|
65
|
-
|
20
|
+
/**
|
21
|
+
* Returns an instance of the provided class,
|
22
|
+
* with the state and props arguments added as instance members.
|
23
|
+
*
|
24
|
+
* `state` must be an instance of `CleanState` created with {@link useCleanState}.
|
25
|
+
*/
|
26
|
+
var useMethods = function () {
|
27
|
+
var args = [];
|
28
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
29
|
+
args[_i] = arguments[_i];
|
30
|
+
}
|
31
|
+
var Methods = args[0], _a = args[1], props = _a === void 0 ? {} : _a, state = args[2];
|
32
|
+
// Vite HMR seems to sometimes reinitialize useMemo calls after a hot update,
|
33
|
+
// causing the instance to be unexpectedly recreated in the middle of the component's lifecycle.
|
66
34
|
// But useRef and useState values appear to always be preserved whenever this happens.
|
67
35
|
// So those two are the only cross-render-persistence methods we can consider safe.
|
36
|
+
// @todo Provide a way for users to reflect updated methods code on the existing instance after HMR.
|
68
37
|
var methods = (0, react_1.useRef)((0, react_1.useMemo)(function () {
|
69
|
-
// See useLogic implementation for a discussion of this type assertion.
|
70
38
|
return new Methods();
|
71
39
|
}, [])).current;
|
72
|
-
methods.
|
73
|
-
|
40
|
+
/** A proxy variable to allow typechecking of the assignment to methods.props despite the need for "readonly" error suppression. */
|
41
|
+
var _propsProxy_;
|
42
|
+
// @ts-expect-error
|
43
|
+
methods.props = (_propsProxy_ = props);
|
44
|
+
if (state)
|
45
|
+
methods.state = state;
|
74
46
|
return methods;
|
75
47
|
};
|
76
48
|
exports.useMethods = useMethods;
|
77
|
-
testing: {
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
case 1:
|
94
|
-
useCleanState = (_a.sent()).useCleanState;
|
95
|
-
self = (0, exports.useMethods)(MyMethods, useCleanState({}), {});
|
96
|
-
return [2 /*return*/];
|
97
|
-
}
|
98
|
-
});
|
99
|
-
}); };
|
100
|
-
}
|
49
|
+
/*testing: {
|
50
|
+
let a = async () => {
|
51
|
+
const a: object = {b: ''};
|
52
|
+
|
53
|
+
type t = keyof typeof a;
|
54
|
+
|
55
|
+
class MyMethods extends ComponentMethods<WeakEmptyObject, null> {
|
56
|
+
// static getInitialState = () => ({});
|
57
|
+
};
|
58
|
+
|
59
|
+
const { useCleanState } = (await import('./state.js'));
|
60
|
+
|
61
|
+
const self = useMethods(MyMethods, {});
|
62
|
+
self.state;
|
63
|
+
}
|
64
|
+
}*/
|
package/build/base/state.d.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import '../globals';
|
1
2
|
/**
|
2
3
|
* Returns a value that is false before the component has been mounted,
|
3
4
|
* then true during all subsequent rerenders.
|
@@ -7,8 +8,8 @@ type PutState<TState extends object> = {
|
|
7
8
|
[Key in keyof TState]: React.Dispatch<React.SetStateAction<TState[Key]>>;
|
8
9
|
};
|
9
10
|
declare class CleanStateBase<TState extends Record<string, any>> {
|
10
|
-
reservedKeys: string[];
|
11
|
-
valueKeys: string[];
|
11
|
+
readonly reservedKeys: string[];
|
12
|
+
readonly valueKeys: string[];
|
12
13
|
private _values_;
|
13
14
|
private _initialValues_;
|
14
15
|
private _setters_;
|
@@ -16,14 +17,20 @@ declare class CleanStateBase<TState extends Record<string, any>> {
|
|
16
17
|
static update: <TState_1 extends object>(this: CleanStateBase<TState_1>) => void;
|
17
18
|
get put(): PutState<TState>;
|
18
19
|
get initialState(): TState;
|
19
|
-
putMany: (newValues: Partial<TState>) => void;
|
20
|
+
readonly putMany: (newValues: Partial<TState>) => void;
|
20
21
|
}
|
21
|
-
type
|
22
|
-
|
23
|
-
|
22
|
+
export type TStateData = object & {
|
23
|
+
[Key in keyof CleanStateBase<{}>]?: never;
|
24
|
+
};
|
25
|
+
export type TCleanState<TState extends TStateData> = (CleanStateBase<TState> & Omit<TState, keyof CleanStateBase<{}>>);
|
26
|
+
export type ExtractCleanStateData<YourCleanState extends CleanStateBase<{}>> = Omit<YourCleanState, keyof CleanStateBase<{}>>;
|
24
27
|
type StateInitFunction = (...args: any[]) => object;
|
25
28
|
type StateInit = object | StateInitFunction;
|
26
29
|
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 : []) =>
|
30
|
+
type TUseCleanState = <TInit extends StateInit>(_initialState: TInit, ...props: TInit extends (...args: infer TProps extends any[]) => (infer TState extends object) ? TProps : []) => TCleanState<TInitialState<TInit>>;
|
31
|
+
/**
|
32
|
+
* Creates a state object, which includes the provided values, and helper methods for
|
33
|
+
* updating those values and automatically rerendering your component's UI accordingly.
|
34
|
+
*/
|
28
35
|
export declare const useCleanState: TUseCleanState;
|
29
36
|
export {};
|
package/build/base/state.js
CHANGED
@@ -12,6 +12,7 @@ var __assign = (this && this.__assign) || function () {
|
|
12
12
|
};
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
14
14
|
exports.useCleanState = exports.useMountState = void 0;
|
15
|
+
require("../globals");
|
15
16
|
var react_1 = require("react");
|
16
17
|
/**
|
17
18
|
* Returns a value that is false before the component has been mounted,
|
@@ -117,22 +118,22 @@ var CleanStateBase = /** @class */ (function () {
|
|
117
118
|
}());
|
118
119
|
;
|
119
120
|
var CleanState = CleanStateBase;
|
121
|
+
/**
|
122
|
+
* Creates a state object, which includes the provided values, and helper methods for
|
123
|
+
* updating those values and automatically rerendering your component's UI accordingly.
|
124
|
+
*/
|
120
125
|
var useCleanState = function (_initialState) {
|
121
126
|
var props = [];
|
122
127
|
for (var _i = 1; _i < arguments.length; _i++) {
|
123
128
|
props[_i - 1] = arguments[_i];
|
124
129
|
}
|
125
|
-
var mounted = (0, exports.useMountState)();
|
126
130
|
var initialState = typeof _initialState === 'function'
|
127
131
|
? (0, react_1.useMemo)(function () { return _initialState.apply(void 0, props); }, [])
|
128
132
|
: _initialState;
|
129
133
|
;
|
130
|
-
var
|
131
|
-
|
132
|
-
|
133
|
-
if (!freshInstance.put)
|
134
|
-
throw new Error('useCleanState failed to initialized a state instance.');
|
135
|
-
var cleanState = (0, react_1.useRef)(freshInstance).current;
|
134
|
+
var cleanState = (0, react_1.useRef)((0, react_1.useMemo)(function () {
|
135
|
+
return new CleanState(initialState);
|
136
|
+
}, [])).current;
|
136
137
|
CleanState.update.call(cleanState);
|
137
138
|
return cleanState;
|
138
139
|
};
|
package/build/classy/class.d.ts
CHANGED
@@ -1,16 +1,117 @@
|
|
1
1
|
import type { VoidFunctionComponent } from 'react';
|
2
|
+
import type { TStateData } from '../base';
|
3
|
+
import type { IComponentInstanceClass } from './instance';
|
2
4
|
import { ComponentInstance } from './instance';
|
3
|
-
|
4
|
-
export declare
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
import { THooksBase } from './logic';
|
6
|
+
export declare const useRerender: () => () => void;
|
7
|
+
type ComponentClassParams = ConstructorParameters<typeof ClassComponent>;
|
8
|
+
type o = object;
|
9
|
+
export interface IComponentClass<Instance extends ClassComponent<o, o, THooksBase> = ClassComponent, Params extends ComponentClassParams = ComponentClassParams> extends IComponentInstanceClass<Instance, Params> {
|
10
|
+
}
|
11
|
+
type Extractor = <TComponent extends typeof ClassComponent<o, o, THooksBase>>(this: NonNullable<typeof _Component>, _Component?: TComponent & IComponentClass<InstanceType<TComponent>>) => VoidFunctionComponent<InstanceType<TComponent>['props']>;
|
12
|
+
type ReactTemplate = React.JSX.Element | null;
|
13
|
+
/**
|
14
|
+
* A superset of {@link ComponentInstance} that allows defining your
|
15
|
+
* component's JSX template directly inside the class.
|
16
|
+
*
|
17
|
+
* This is designed to closely resemble the old {@link React.Component} class,
|
18
|
+
* making it easier to migrate older class components to the newer hooks-based system
|
19
|
+
* with little to no changes to their existing semantics/implementation.
|
20
|
+
*/
|
21
|
+
export declare class ClassComponent<TProps extends o = WeakEmptyObject, TState extends TStateData = WeakEmptyObject, THooks extends THooksBase = void> extends ComponentInstance<TProps, TState, THooks> {
|
22
|
+
/**
|
23
|
+
* @deprecated An older alternative to {@link template}.
|
24
|
+
*
|
25
|
+
* Using this will add a component boundary between your JSX template
|
26
|
+
* and the function component returned from ClassComponent.FC();
|
27
|
+
*
|
28
|
+
* This means that from React's perspective, your template won't "own" the state and props it consumes.
|
29
|
+
* This could lead to subtle unexpected changes in behaviour.
|
30
|
+
*
|
31
|
+
* In most cases, you should use {@link template} instead, as it allows your class component
|
32
|
+
* to function more predictably as a single unit.
|
33
|
+
*/
|
34
|
+
Render?: VoidFunctionComponent<{}>;
|
35
|
+
/**
|
36
|
+
* Analogous to {@link React.Component.render}. A function that returns
|
37
|
+
* your component's JSX template.
|
38
|
+
*
|
39
|
+
* You should place most logic that would usually go here
|
40
|
+
* in {@link ComponentInstance.beforeRender | `beforeRender`} instead.
|
41
|
+
* This helps to separate concerns and keep the template itself clean.
|
42
|
+
*
|
43
|
+
* ******
|
44
|
+
*
|
45
|
+
* Ideally the template method should only be concerned with defining the HTML/JSX structure of
|
46
|
+
* your component's UI. This may include destructuring nested instance members
|
47
|
+
* into more easily accessible local variables, or some simple transformation of data from props/state
|
48
|
+
* into a more appropriate format for display.
|
49
|
+
*
|
50
|
+
* ******
|
51
|
+
*
|
52
|
+
* @example < caption>Using a template function that returns JSX.</ caption>
|
53
|
+
*
|
54
|
+
* ```tsx
|
55
|
+
* template = () => {
|
56
|
+
* const { title } = this.props;
|
57
|
+
*
|
58
|
+
* return (
|
59
|
+
* <h1>
|
60
|
+
* {this.props.title}
|
61
|
+
* </h1>
|
62
|
+
* );
|
63
|
+
* }
|
64
|
+
* ```
|
65
|
+
*/
|
66
|
+
template?: () => ReactTemplate;
|
67
|
+
/**
|
68
|
+
* Manually trigger a rerender of your component.
|
69
|
+
* You should rarely ever need this. But if you are migrating
|
70
|
+
* an older React.Component class, this should provide similar functionality
|
71
|
+
* to the {@link Component.forceUpdate | `forceUpdate`} method provided there.
|
72
|
+
*
|
73
|
+
* Note that the callback argument is currently not supported.
|
74
|
+
*/
|
75
|
+
readonly forceUpdate: VoidFunction;
|
76
|
+
/*************************************
|
77
|
+
* Function Component Extractor *
|
78
|
+
**************************************/
|
79
|
+
/**
|
80
|
+
* Extract a function component which can be used to render
|
81
|
+
* your ClassComponent just like any other component.
|
82
|
+
*
|
83
|
+
* Each JSX reference to this returned component will render with
|
84
|
+
* a separate instance of your class.
|
85
|
+
*
|
86
|
+
* So you only need to call `YourClassComponent.FC()` once, then use the returned
|
87
|
+
* function component as many times as you need.
|
88
|
+
*/
|
89
|
+
static readonly FC: Extractor;
|
8
90
|
}
|
9
91
|
interface HookWrapperProps<THookFunction extends AnyFunction> {
|
92
|
+
/**
|
93
|
+
* The React hook you which to consume.
|
94
|
+
* Render a separate instance of the `<Use />` component for each hook.
|
95
|
+
* You can also create a custom hook that combines multiple hooks,
|
96
|
+
* then use that wrapper hook with a single `<Use />` instance.
|
97
|
+
*/
|
10
98
|
hook: THookFunction;
|
99
|
+
/**
|
100
|
+
* An array containing the list of arguments
|
101
|
+
* to be passed to your hook, in the right order.
|
102
|
+
*/
|
11
103
|
argumentsList: Parameters<THookFunction>;
|
104
|
+
/**
|
105
|
+
* A callback that will be called with whatever value your hook returns.
|
106
|
+
* Use this to update your component's state with the value.
|
107
|
+
* This will allow your component to rerender whenever the hook returns a new value.
|
108
|
+
*/
|
12
109
|
onUpdate: (output: ReturnType<THookFunction>) => void;
|
13
110
|
}
|
14
111
|
type ClassComponentHookWrapper = <Hook extends AnyFunction>(props: HookWrapperProps<Hook>) => null;
|
112
|
+
/**
|
113
|
+
* A component you can use to consume hooks
|
114
|
+
* in a {@link Component | React.Component} class component.
|
115
|
+
*/
|
15
116
|
export declare const Use: ClassComponentHookWrapper;
|
16
117
|
export {};
|
package/build/classy/class.js
CHANGED
@@ -15,7 +15,7 @@ var __extends = (this && this.__extends) || (function () {
|
|
15
15
|
};
|
16
16
|
})();
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
18
|
-
exports.Use = exports.ClassComponent = void 0;
|
18
|
+
exports.Use = exports.ClassComponent = exports.useRerender = void 0;
|
19
19
|
var jsx_runtime_1 = require("react/jsx-runtime");
|
20
20
|
var react_1 = require("react");
|
21
21
|
var instance_1 = require("./instance");
|
@@ -32,22 +32,68 @@ var setFunctionName = function (func, newName) {
|
|
32
32
|
console.warn(error);
|
33
33
|
}
|
34
34
|
};
|
35
|
-
|
35
|
+
var useRerender = function () {
|
36
|
+
/*
|
37
|
+
* Skip the value, we don't need it.
|
38
|
+
* Grab just the setter function.
|
39
|
+
*/
|
40
|
+
var _a = (0, react_1.useState)(Date.now()), _forceRerender = _a[1];
|
41
|
+
var rerender = function () { return _forceRerender(Date.now()); };
|
42
|
+
return rerender;
|
43
|
+
};
|
44
|
+
exports.useRerender = useRerender;
|
45
|
+
;
|
46
|
+
/**
|
47
|
+
* A superset of {@link ComponentInstance} that allows defining your
|
48
|
+
* component's JSX template directly inside the class.
|
49
|
+
*
|
50
|
+
* This is designed to closely resemble the old {@link React.Component} class,
|
51
|
+
* making it easier to migrate older class components to the newer hooks-based system
|
52
|
+
* with little to no changes to their existing semantics/implementation.
|
53
|
+
*/
|
36
54
|
var ClassComponent = /** @class */ (function (_super) {
|
37
55
|
__extends(ClassComponent, _super);
|
38
56
|
function ClassComponent() {
|
39
57
|
return _super !== null && _super.apply(this, arguments) || this;
|
40
58
|
}
|
41
|
-
|
59
|
+
/*************************************
|
60
|
+
* Function Component Extractor *
|
61
|
+
**************************************/
|
62
|
+
// @todo Attempt using implicit `this` value to allow rendering <MyComponent.FC /> directly.
|
63
|
+
// const FC = (props) => { const self = useMemo(() => useInstance(this, props), {}); return self.template(); }
|
64
|
+
/**
|
65
|
+
* Extract a function component which can be used to render
|
66
|
+
* your ClassComponent just like any other component.
|
67
|
+
*
|
68
|
+
* Each JSX reference to this returned component will render with
|
69
|
+
* a separate instance of your class.
|
70
|
+
*
|
71
|
+
* So you only need to call `YourClassComponent.FC()` once, then use the returned
|
72
|
+
* function component as many times as you need.
|
73
|
+
*/
|
42
74
|
ClassComponent.FC = function FC(_Component) {
|
43
75
|
var Component = _Component !== null && _Component !== void 0 ? _Component : this;
|
44
76
|
var isClassComponentType = Component.prototype instanceof ClassComponent;
|
45
77
|
if (!Component.getInitialState || !isClassComponentType)
|
46
78
|
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()`).');
|
47
|
-
|
48
|
-
|
79
|
+
/*************************************
|
80
|
+
* Begin Function Component *
|
81
|
+
**************************************/
|
82
|
+
/** A class-based React function component created with (@cleanweb/react).ClassComponent */
|
83
|
+
var Wrapper = function (props) {
|
84
|
+
var instance = (0, instance_1.useInstance)(Component, props);
|
85
|
+
var Render = instance.Render, template = instance.template;
|
86
|
+
var _forceUpdate;
|
87
|
+
// @ts-expect-error (Cannot assign to 'forceUpdate' because it is a read-only property.ts(2540))
|
88
|
+
instance.forceUpdate = (_forceUpdate = (0, exports.useRerender)() // Moved this to separate line to allow TS errors. Use proxy local variable to regain some type checking for the assignment to `instance.forceUpdate`.
|
89
|
+
);
|
49
90
|
// Add calling component name to Render function name in stack traces.
|
50
|
-
(0, react_1.useMemo)(function () {
|
91
|
+
(0, react_1.useMemo)(function () {
|
92
|
+
if (typeof template === 'function')
|
93
|
+
setFunctionName(template, "".concat(Component.name, ".template"));
|
94
|
+
else if (typeof Render === 'function')
|
95
|
+
setFunctionName(Render, "".concat(Component.name, ".Render"));
|
96
|
+
}, [Render, template]);
|
51
97
|
/**
|
52
98
|
* Normally a component can update it's own state in the "before-render" stage to
|
53
99
|
* skip DOM updates and trigger and immediate rerun of the rendering with the new state.
|
@@ -58,28 +104,48 @@ var ClassComponent = /** @class */ (function (_super) {
|
|
58
104
|
* state in the "before-render" stage of `Render`, since it will be attempting to update it's parent's
|
59
105
|
* state (i.e `Wrapper` component) rather than it's own state.
|
60
106
|
*
|
61
|
-
*
|
107
|
+
* Users should favor using the `template()` method instead. This way, we avoid
|
62
108
|
* establishing a component boundary between `Wrapper` and `Render`.
|
63
109
|
*
|
64
110
|
* Although, since beforeRender() is called earlier from a hook, this is probably
|
65
111
|
* a non-issue. It will only force users to move their logic into `beforeRender` instead
|
66
|
-
* of doing it directly in `Render`.
|
67
|
-
*
|
112
|
+
* of doing it directly in `Render`. Even if `template` is being used, the `beforeRender` method
|
113
|
+
* is the preferred location for such logic to maintain a high level of separation of concerns,
|
114
|
+
* which is what this library exists to provide.
|
115
|
+
*
|
116
|
+
* So there's probably no real value lost with the component boundary. Users should just use
|
117
|
+
* `beforeRender` + `template`.
|
68
118
|
**/
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
119
|
+
switch (typeof template) {
|
120
|
+
case 'undefined':
|
121
|
+
if (typeof Render === 'function')
|
122
|
+
return (0, jsx_runtime_1.jsx)(Render, {});
|
123
|
+
else
|
124
|
+
throw new Error([
|
125
|
+
'A ClassComponent must have either a `template` or a `Render` property. But neither was found.',
|
126
|
+
'Add a `template: (JSX.Element | null);` member to your class, (or a `template` method that returns the same type).',
|
127
|
+
'Alternatively, add a `Render: FunctionComponent;` method.',
|
128
|
+
'\n\n',
|
129
|
+
'Expected `Render` to be a Function Component because `template` was `undefined`.',
|
130
|
+
"Instead got the following '".concat(typeof Render, "': $o"),
|
131
|
+
].join(' '), Render);
|
132
|
+
case 'function': return template();
|
133
|
+
default: return template;
|
134
|
+
}
|
75
135
|
};
|
76
|
-
|
77
|
-
|
136
|
+
/*************************************
|
137
|
+
* End Function Component *
|
138
|
+
**************************************/
|
139
|
+
setFunctionName(Wrapper, "$".concat(Component.name, "$"));
|
78
140
|
return Wrapper;
|
79
141
|
};
|
80
142
|
return ClassComponent;
|
81
143
|
}(instance_1.ComponentInstance));
|
82
144
|
exports.ClassComponent = ClassComponent;
|
145
|
+
/**
|
146
|
+
* A component you can use to consume hooks
|
147
|
+
* in a {@link Component | React.Component} class component.
|
148
|
+
*/
|
83
149
|
var Use = function (params) {
|
84
150
|
var useGenericHook = params.hook, argumentsList = params.argumentsList, onUpdate = params.onUpdate;
|
85
151
|
var output = useGenericHook.apply(void 0, argumentsList);
|
@@ -1,7 +1,15 @@
|
|
1
|
+
import type { TStateData } from '../base/state';
|
2
|
+
import type { THooksBase, IComponentLogicClass } from './logic';
|
1
3
|
import { ComponentLogic } from './logic';
|
2
4
|
type AsyncAllowedEffectCallback = () => Awaitable<IVoidFunction>;
|
5
|
+
/** An empty function. It returns (void) without performing any operations. */
|
3
6
|
export declare const noOp: () => void;
|
4
|
-
|
7
|
+
/**
|
8
|
+
* A superset of {@link ComponentLogic} that adds support for special lifecycle methods.
|
9
|
+
* This provides a declarative API for working with your React function component's lifecycle,
|
10
|
+
* a simpler alternative to the imperative approach with `useEffect` and/or `useMemo`.
|
11
|
+
*/
|
12
|
+
export declare class ComponentInstance<TProps extends o = {}, TState extends TStateData = WeakEmptyObject, THooks extends THooksBase = void> extends ComponentLogic<TProps, TState, THooks> {
|
5
13
|
/**
|
6
14
|
* Runs only _before_ first render, i.e before the component instance is mounted.
|
7
15
|
* Useful for logic that is involved in determining what to render.
|
@@ -46,17 +54,13 @@ export declare class ComponentInstance<TState extends object = EmptyObject, TPro
|
|
46
54
|
*/
|
47
55
|
cleanUp: IVoidFunction;
|
48
56
|
}
|
49
|
-
type
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
* just wants us to use the rest parameter explicitly by force.
|
58
|
-
*/
|
57
|
+
type o = object;
|
58
|
+
type InstanceClassParams = ConstructorParameters<typeof ComponentInstance<o, o, o>>;
|
59
|
+
export interface IComponentInstanceClass<Instance extends ComponentInstance<o, o, THooksBase> = ComponentInstance, Params extends InstanceClassParams = InstanceClassParams> extends IComponentLogicClass<Instance, Params> {
|
60
|
+
}
|
61
|
+
type UseInstance = {
|
62
|
+
<Class extends typeof ComponentInstance<HardEmptyObject, o, THooksBase>>(Methods: Class & IComponentInstanceClass<InstanceType<Class>>): InstanceType<Class>;
|
63
|
+
<Class extends typeof ComponentInstance<o, o, THooksBase>>(Methods: Class & IComponentInstanceClass<InstanceType<Class>>, props: InstanceType<Class>['props']): InstanceType<Class>;
|
64
|
+
};
|
59
65
|
export declare const useInstance: UseInstance;
|
60
|
-
type UseMountCallbacks = <TInstance extends ComponentInstance<any, any, any>>(instance: TInstance) => void;
|
61
|
-
export declare const useMountCallbacks: UseMountCallbacks;
|
62
66
|
export {};
|
package/build/classy/instance.js
CHANGED
@@ -14,22 +14,44 @@ 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
|
-
};
|
26
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
27
|
-
exports.
|
18
|
+
exports.useInstance = exports.ComponentInstance = exports.noOp = void 0;
|
28
19
|
var react_1 = require("react");
|
29
20
|
var state_1 = require("../base/state");
|
30
21
|
var logic_1 = require("./logic");
|
22
|
+
var useMountCallbacks = function (instance) {
|
23
|
+
var _a;
|
24
|
+
var mounted = (0, state_1.useMountState)();
|
25
|
+
if (!mounted)
|
26
|
+
(_a = instance.beforeMount) === null || _a === void 0 ? void 0 : _a.call(instance);
|
27
|
+
(0, react_1.useEffect)(function () {
|
28
|
+
var _a;
|
29
|
+
var mountHandlerCleanUp = (_a = instance.onMount) === null || _a === void 0 ? void 0 : _a.call(instance);
|
30
|
+
return function () {
|
31
|
+
var doCleanUp = function (runMountCleaners) {
|
32
|
+
var _a;
|
33
|
+
runMountCleaners === null || runMountCleaners === void 0 ? void 0 : runMountCleaners();
|
34
|
+
// onDismount? willUnmount?
|
35
|
+
(_a = instance.cleanUp) === null || _a === void 0 ? void 0 : _a.call(instance);
|
36
|
+
};
|
37
|
+
if (typeof mountHandlerCleanUp === 'function') {
|
38
|
+
doCleanUp(mountHandlerCleanUp);
|
39
|
+
}
|
40
|
+
else {
|
41
|
+
mountHandlerCleanUp === null || mountHandlerCleanUp === void 0 ? void 0 : mountHandlerCleanUp.then(doCleanUp);
|
42
|
+
}
|
43
|
+
};
|
44
|
+
}, []);
|
45
|
+
};
|
46
|
+
/** An empty function. It returns (void) without performing any operations. */
|
31
47
|
var noOp = function () { };
|
32
48
|
exports.noOp = noOp;
|
49
|
+
// @todo Use rollup. Insert globals.ts reference tag to all d.ts output files.
|
50
|
+
/**
|
51
|
+
* A superset of {@link ComponentLogic} that adds support for special lifecycle methods.
|
52
|
+
* This provides a declarative API for working with your React function component's lifecycle,
|
53
|
+
* a simpler alternative to the imperative approach with `useEffect` and/or `useMemo`.
|
54
|
+
*/
|
33
55
|
var ComponentInstance = /** @class */ (function (_super) {
|
34
56
|
__extends(ComponentInstance, _super);
|
35
57
|
function ComponentInstance() {
|
@@ -83,7 +105,8 @@ var ComponentInstance = /** @class */ (function (_super) {
|
|
83
105
|
}(logic_1.ComponentLogic));
|
84
106
|
exports.ComponentInstance = ComponentInstance;
|
85
107
|
;
|
86
|
-
|
108
|
+
;
|
109
|
+
/*
|
87
110
|
* To ensure successful type checking, the second parameter must be written with spread syntax.
|
88
111
|
* Likely because of the `exactOptionalPropertyTypes` config option turned on,
|
89
112
|
* and `UseInstance` using an empty tuple in its rest parameter type, attempting to simply
|
@@ -92,14 +115,15 @@ exports.ComponentInstance = ComponentInstance;
|
|
92
115
|
* the second param is given `{}` as a default follow to account for the empty tuple case. TypeScript
|
93
116
|
* just wants us to use the rest parameter explicitly by force.
|
94
117
|
*/
|
95
|
-
var useInstance = function (
|
118
|
+
var useInstance = function () {
|
96
119
|
var _a;
|
97
120
|
var args = [];
|
98
|
-
for (var _i =
|
99
|
-
args[_i
|
121
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
122
|
+
args[_i] = arguments[_i];
|
100
123
|
}
|
124
|
+
var Component = args[0], _b = args[1], props = _b === void 0 ? {} : _b;
|
101
125
|
// useHooks.
|
102
|
-
var instance =
|
126
|
+
var instance = (0, logic_1.useLogic)(Component, props);
|
103
127
|
/**
|
104
128
|
* Argument of type '
|
105
129
|
* [
|
@@ -115,8 +139,7 @@ var useInstance = function (Component) {
|
|
115
139
|
'
|
116
140
|
*/
|
117
141
|
// beforeMount, onMount, cleanUp.
|
118
|
-
|
119
|
-
(0, exports.useMountCallbacks)(instance);
|
142
|
+
useMountCallbacks(instance);
|
120
143
|
// beforeRender.
|
121
144
|
(_a = instance.beforeRender) === null || _a === void 0 ? void 0 : _a.call(instance);
|
122
145
|
// onRender.
|
@@ -133,28 +156,21 @@ var useInstance = function (Component) {
|
|
133
156
|
return instance;
|
134
157
|
};
|
135
158
|
exports.useInstance = useInstance;
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
else {
|
155
|
-
mountHandlerCleanUp === null || mountHandlerCleanUp === void 0 ? void 0 : mountHandlerCleanUp.then(doCleanUp);
|
156
|
-
}
|
157
|
-
};
|
158
|
-
}, []);
|
159
|
-
};
|
160
|
-
exports.useMountCallbacks = useMountCallbacks;
|
159
|
+
/*testing: {
|
160
|
+
class A extends ComponentInstance {
|
161
|
+
static getInitialState: (p?: object) => ({putan: ''});
|
162
|
+
// k = this.props.o
|
163
|
+
a = this.state['_initialValues_']
|
164
|
+
|
165
|
+
// hard empty has every key
|
166
|
+
// weak empty has no key
|
167
|
+
// weak empty is not assignable to hard empty
|
168
|
+
}
|
169
|
+
|
170
|
+
const p = {k: ''}
|
171
|
+
const a = useInstance(A, {o: ''});
|
172
|
+
|
173
|
+
// a.props['o'];
|
174
|
+
type bbbb = A['state'];
|
175
|
+
type ttt = bbbb['put'];
|
176
|
+
}*/
|
package/build/classy/logic.d.ts
CHANGED
@@ -1,23 +1,57 @@
|
|
1
|
-
import type { TCleanState,
|
1
|
+
import type { TCleanState, ExtractCleanStateData, TStateData } from '../base/state';
|
2
|
+
export type HardEmpty = HardEmptyObject;
|
3
|
+
export type WeakEmpty = WeakEmptyObject;
|
4
|
+
export type THooksBase = o | void;
|
2
5
|
type o = object;
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
/**
|
7
|
+
* Base class for a class that holds methods intended for use in a function component,
|
8
|
+
* as well as a static method for initializing state.
|
9
|
+
*
|
10
|
+
* These methods will have access to the components state and props via
|
11
|
+
* `this.state` and `this.props` respectively.
|
12
|
+
*
|
13
|
+
* The special {@link ComponentLogic.useHooks | useHooks} method allows you to consume
|
14
|
+
* React hooks within this class.
|
15
|
+
*
|
16
|
+
* Call the {@link useLogic} hook inside your function component to instantiate the class.
|
17
|
+
*/
|
18
|
+
export declare class ComponentLogic<
|
19
|
+
/** Describe the values your component expects to be passed as props. */
|
20
|
+
TProps extends object = {},
|
21
|
+
/** An object type that descibes your component's state. */
|
22
|
+
TState extends TStateData = WeakEmpty,
|
23
|
+
/** The object type returned by your component's {@link useHooks} method. */
|
24
|
+
THooks extends THooksBase = void> {
|
25
|
+
state: TCleanState<TState>;
|
26
|
+
readonly props: TProps;
|
27
|
+
readonly hooks: THooks extends object ? THooks : WeakEmptyObject;
|
28
|
+
/**
|
29
|
+
* Called before each instance of your component is mounted.
|
30
|
+
* It receives the initial `props` object and should return
|
31
|
+
* an object with the initial values for your component's state.
|
32
|
+
*/
|
33
|
+
static getInitialState: (p?: any) => object;
|
34
|
+
/**
|
35
|
+
* This allows you to seamlessly consume React hooks in
|
36
|
+
* your class component.
|
37
|
+
*
|
38
|
+
* It is called after state and props are updated on each render.
|
39
|
+
* Call any hooks (e.g `useEffect`) you which to consume inside this function.
|
40
|
+
*
|
41
|
+
* To expose any returned values from your hooks to the rest of your component,
|
42
|
+
* return an object that contains all the relevant values.
|
43
|
+
*
|
44
|
+
* This object will be accessible as `this.hooks` to the rest of your class.
|
45
|
+
*/
|
46
|
+
useHooks: THooks extends void ? undefined | (() => void | HardEmptyObject) : () => THooks;
|
9
47
|
}
|
10
|
-
type
|
11
|
-
export interface
|
12
|
-
|
13
|
-
getInitialState: (props?: Instance['props']) => TState<Instance['state']>;
|
48
|
+
type LogicClassParams = ConstructorParameters<typeof ComponentLogic>;
|
49
|
+
export interface IComponentLogicClass<Instance extends ComponentLogic<o, o, THooksBase> = ComponentLogic, Params extends LogicClassParams = LogicClassParams> extends Constructor<Instance, Params> {
|
50
|
+
getInitialState: (props?: Instance['props']) => ExtractCleanStateData<Instance['state']>;
|
14
51
|
}
|
15
|
-
|
16
|
-
|
52
|
+
type UseLogic = {
|
53
|
+
<Class extends typeof ComponentLogic<HardEmptyObject, o, THooksBase>>(Methods: Class & IComponentLogicClass<InstanceType<Class>>): InstanceType<Class>;
|
54
|
+
<Class extends typeof ComponentLogic<o, o, THooksBase>>(Methods: Class & IComponentLogicClass<InstanceType<Class>>, props: InstanceType<Class>['props']): InstanceType<Class>;
|
17
55
|
};
|
18
|
-
|
19
|
-
export
|
20
|
-
}
|
21
|
-
type UseLogic = <Class extends typeof ComponentLogic<object, object, object>, Instance extends InstanceType<Class> = InstanceType<Class>>(Methods: Class & Constructor<Instance>, ...props: valueof<Instance['props']> extends never ? ([] | [EmptyObject] | [Instance['props']]) : [Instance['props']]) => Instance;
|
22
|
-
export declare const useLogic: UseLogic;
|
23
|
-
export {};
|
56
|
+
declare const useLogic: UseLogic;
|
57
|
+
export { useLogic };
|
package/build/classy/logic.js
CHANGED
@@ -1,67 +1,81 @@
|
|
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;
|
18
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
19
3
|
exports.useLogic = exports.ComponentLogic = void 0;
|
20
4
|
var react_1 = require("react");
|
21
5
|
var state_1 = require("../base/state");
|
6
|
+
/**
|
7
|
+
* Base class for a class that holds methods intended for use in a function component,
|
8
|
+
* as well as a static method for initializing state.
|
9
|
+
*
|
10
|
+
* These methods will have access to the components state and props via
|
11
|
+
* `this.state` and `this.props` respectively.
|
12
|
+
*
|
13
|
+
* The special {@link ComponentLogic.useHooks | useHooks} method allows you to consume
|
14
|
+
* React hooks within this class.
|
15
|
+
*
|
16
|
+
* Call the {@link useLogic} hook inside your function component to instantiate the class.
|
17
|
+
*/
|
22
18
|
var ComponentLogic = /** @class */ (function () {
|
23
19
|
function ComponentLogic() {
|
24
20
|
}
|
21
|
+
/**
|
22
|
+
* Called before each instance of your component is mounted.
|
23
|
+
* It receives the initial `props` object and should return
|
24
|
+
* an object with the initial values for your component's state.
|
25
|
+
*/
|
26
|
+
ComponentLogic.getInitialState = function (p) { return ({}); };
|
25
27
|
return ComponentLogic;
|
26
28
|
}());
|
27
29
|
exports.ComponentLogic = ComponentLogic;
|
28
30
|
;
|
29
|
-
|
30
|
-
var
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
A.getInitialState();
|
40
|
-
}
|
41
|
-
;
|
42
|
-
var useLogic = function (Methods, props) {
|
43
|
-
var _b;
|
44
|
-
if (props === void 0) { props = {}; }
|
45
|
-
var state = (0, state_1.useCleanState)(Methods.getInitialState, props);
|
46
|
-
var methods = (0, react_1.useRef)((0, react_1.useMemo)(function () {
|
47
|
-
return new Methods();
|
31
|
+
var useLogic = function () {
|
32
|
+
var _a, _b;
|
33
|
+
var args = [];
|
34
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
35
|
+
args[_i] = arguments[_i];
|
36
|
+
}
|
37
|
+
var Logic = args[0], _c = args[1], props = _c === void 0 ? {} : _c;
|
38
|
+
var state = (0, state_1.useCleanState)(Logic.getInitialState, props);
|
39
|
+
var self = (0, react_1.useRef)((0, react_1.useMemo)(function () {
|
40
|
+
return new Logic();
|
48
41
|
}, [])).current;
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
42
|
+
/** A proxy variable to allow typechecking of the assignment to `self.props` despite the need for "readonly" error suppression. */
|
43
|
+
var _propsProxy_;
|
44
|
+
/** A proxy variable to allow typechecking of the assignment to `self.hooks` despite the need for "readonly" error suppression. */
|
45
|
+
var _hooksProxy_;
|
46
|
+
self.state = state;
|
47
|
+
// @ts-expect-error
|
48
|
+
self.props = (_propsProxy_ = props);
|
49
|
+
// @ts-expect-error
|
50
|
+
self.hooks = (_hooksProxy_ = (_b = (_a = self.useHooks) === null || _a === void 0 ? void 0 : _a.call(self)) !== null && _b !== void 0 ? _b : {} // @todo Improve UseLogic types to reflect that this may be undefined.
|
51
|
+
);
|
52
|
+
return self;
|
53
53
|
};
|
54
54
|
exports.useLogic = useLogic;
|
55
|
-
testing: {
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
}
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
;
|
66
|
-
|
67
|
-
|
55
|
+
/*testing: {
|
56
|
+
const a: object = {b: ''};
|
57
|
+
|
58
|
+
type t = keyof typeof a;
|
59
|
+
|
60
|
+
class MyComponentLogic extends ComponentLogic<{a: string}> {
|
61
|
+
static getInitialState = () => ({a: '' as const});
|
62
|
+
// b = this.state.put[''] + this.props.b;
|
63
|
+
};
|
64
|
+
|
65
|
+
type tt = keyof {};
|
66
|
+
|
67
|
+
MyComponentLogic.getInitialState
|
68
|
+
// const self = useLogic(MyComponentLogic);
|
69
|
+
|
70
|
+
|
71
|
+
const A = class C extends ComponentLogic {
|
72
|
+
// static getInitialState = () => ({a: 'l'});
|
73
|
+
// a = () => this.state.yyy = '';
|
74
|
+
}
|
75
|
+
|
76
|
+
A.getInitialState();
|
77
|
+
|
78
|
+
// const oa = {['a' as unknown as symbol]: 'boo'};
|
79
|
+
const oa = {['a']: 'boo'};
|
80
|
+
// const self = useLogic(A, oa);
|
81
|
+
}*/
|
package/build/globals.d.ts
CHANGED
@@ -1,24 +1,4 @@
|
|
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
|
-
*
|
9
|
-
* @example
|
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
|
-
* }
|
19
|
-
* }
|
20
|
-
**/
|
21
|
-
/** */
|
1
|
+
declare const UniqueSecretSymbolKey: unique symbol;
|
22
2
|
declare global {
|
23
3
|
type Optional<BaseType, AllowNull extends boolean = true> = (AllowNull extends true ? BaseType | undefined | null : BaseType | undefined);
|
24
4
|
type Awaitable<Type> = Type | Promise<Type>;
|
@@ -42,6 +22,15 @@ declare global {
|
|
42
22
|
type AnyFunction = (...args: any) => any;
|
43
23
|
type FunctionType = AnyFunction;
|
44
24
|
type TFunction = AnyFunction;
|
25
|
+
type NotNullish = {};
|
26
|
+
type NonPrimitive = object;
|
27
|
+
interface WeakEmptyObject {
|
28
|
+
[UniqueSecretSymbolKey]?: never;
|
29
|
+
}
|
30
|
+
interface HardEmptyObject {
|
31
|
+
[key: keyof any]: never;
|
32
|
+
}
|
33
|
+
type valueof<TObject> = TObject[keyof TObject];
|
45
34
|
interface Window {
|
46
35
|
}
|
47
36
|
namespace JSX {
|
@@ -52,16 +41,5 @@ declare global {
|
|
52
41
|
interface ProcessEnv {
|
53
42
|
}
|
54
43
|
}
|
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
|
-
}
|
66
44
|
}
|
67
45
|
export {};
|
package/build/globals.js
CHANGED
@@ -1,22 +1,4 @@
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
/////////////
|
4
|
+
var UniqueSecretSymbolKey = Symbol('asdfghjkliuytrewqaxcvb,nb');
|
package/build/index.d.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export * from
|
1
|
+
export * from './classy';
|
package/build/index.js
CHANGED
@@ -16,7 +16,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
17
17
|
__exportStar(require("./classy"), exports);
|
18
18
|
// PS: Document component inheritance pattern with lifecycle callback arrays and namespaces.
|
19
|
-
// Due to react's remounting behaviour, components must externally track when some logic has run,
|
19
|
+
// Due to react's remounting behaviour, components must externally track when some logic has run,
|
20
|
+
// if it really really must only ever run once per mounted instance. Tricky to get right for components that may have multiple instance rendered simultaneously at different parts of a page.
|
20
21
|
// useCleanState => useState, separate call for each key
|
21
22
|
// useMergedState => useState, same call for all keys
|
22
23
|
// useMethods => useCallback
|
package/build/tsconfig.json
CHANGED
@@ -32,13 +32,15 @@
|
|
32
32
|
"noImplicitAny": true,
|
33
33
|
"noUncheckedIndexedAccess": true,
|
34
34
|
"strictBindCallApply": true,
|
35
|
-
|
35
|
+
"exactOptionalPropertyTypes": true,
|
36
36
|
},
|
37
37
|
"include": [
|
38
|
+
// "**/[!globals].ts",
|
38
39
|
"**/*.ts",
|
39
40
|
"**/*.tsx"
|
40
41
|
],
|
41
42
|
"exclude": [
|
43
|
+
"**/globals.ts",
|
42
44
|
"node_modules/**/**.*",
|
43
45
|
"build/**/**.*",
|
44
46
|
"mirror-pkg/**/**.*"
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@cleanweb/react",
|
3
|
-
"version": "1.1.1-beta.
|
3
|
+
"version": "1.1.1-beta.21",
|
4
4
|
"description": "A suite of helpers for writing cleaner React function components.",
|
5
5
|
"engines": {
|
6
6
|
"node": ">=18"
|
@@ -30,7 +30,7 @@
|
|
30
30
|
"scripts": {
|
31
31
|
"prebuild": "rimraf ./build",
|
32
32
|
"build": "tsc && tsc-alias",
|
33
|
-
"postbuild": "copyfiles
|
33
|
+
"postbuild": "copyfiles tsconfig.json build",
|
34
34
|
"_": "",
|
35
35
|
"prepublishOnly": "npm run build",
|
36
36
|
"publish:patch": "npm version patch && npm publish",
|
@@ -1,48 +0,0 @@
|
|
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 {};
|
package/build/globals.private.js
DELETED
@@ -1,40 +0,0 @@
|
|
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
|
-
}
|