@cleanweb/oore 2.0.0-alpha.15 → 2.0.0-alpha.18
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/_cjs/base/index.d.ts +3 -0
- package/build/_cjs/base/index.js +19 -0
- package/build/_cjs/base/merged-state.d.ts +20 -0
- package/build/_cjs/base/merged-state.js +61 -0
- package/build/_cjs/base/methods.d.ts +58 -0
- package/build/_cjs/base/methods.js +95 -0
- package/build/_cjs/base/state/class-types.d.ts +20 -0
- package/build/_cjs/base/state/class-types.js +2 -0
- package/build/_cjs/base/state/class.d.ts +69 -0
- package/build/_cjs/base/state/class.js +129 -0
- package/build/_cjs/base/state/hook-types.d.ts +32 -0
- package/build/_cjs/base/state/hook-types.js +2 -0
- package/build/_cjs/base/state/hooks.d.ts +12 -0
- package/build/_cjs/base/state/hooks.js +41 -0
- package/build/_cjs/base/state/index.d.ts +9 -0
- package/build/_cjs/base/state/index.js +35 -0
- package/build/_cjs/classy/class/index.d.ts +128 -0
- package/build/_cjs/classy/class/index.js +174 -0
- package/build/_cjs/classy/class/types/extractor.d.ts +5 -0
- package/build/_cjs/classy/class/types/extractor.js +2 -0
- package/build/_cjs/classy/class/utils/function-name.d.ts +2 -0
- package/build/_cjs/classy/class/utils/function-name.js +17 -0
- package/build/_cjs/classy/index.d.ts +3 -0
- package/build/_cjs/classy/index.js +19 -0
- package/build/_cjs/classy/instance/index.d.ts +144 -0
- package/build/_cjs/classy/instance/index.js +177 -0
- package/build/_cjs/classy/instance/mount-callbacks.d.ts +5 -0
- package/build/_cjs/classy/instance/mount-callbacks.js +30 -0
- package/build/_cjs/classy/instance/types/hook.d.ts +13 -0
- package/build/_cjs/classy/instance/types/hook.js +2 -0
- package/build/_cjs/classy/logic/index.d.ts +116 -0
- package/build/_cjs/classy/logic/index.js +123 -0
- package/build/_cjs/classy/logic/types/hook.d.ts +16 -0
- package/build/_cjs/classy/logic/types/hook.js +2 -0
- package/build/_cjs/docs-src/api/base-classes.d.ts +3 -0
- package/build/_cjs/docs-src/api/base-classes.js +9 -0
- package/build/_cjs/docs-src/api/index.d.ts +13 -0
- package/build/_cjs/docs-src/api/index.js +44 -0
- package/build/_cjs/docs-src/api/references.d.ts +5 -0
- package/build/_cjs/docs-src/api/references.js +31 -0
- package/build/_cjs/helpers/errors.d.ts +10 -0
- package/build/_cjs/helpers/errors.js +21 -0
- package/build/_cjs/helpers/index.d.ts +13 -0
- package/build/_cjs/helpers/index.js +31 -0
- package/build/_cjs/helpers/mount-state.d.ts +5 -0
- package/build/_cjs/helpers/mount-state.js +25 -0
- package/build/_cjs/helpers/rerender.d.ts +24 -0
- package/build/_cjs/helpers/rerender.js +42 -0
- package/build/_cjs/helpers/type-guards.d.ts +1 -0
- package/build/_cjs/helpers/type-guards.js +8 -0
- package/build/_cjs/helpers/use-component/index.d.ts +6 -0
- package/build/_cjs/helpers/use-component/index.js +17 -0
- package/build/_cjs/helpers/use-component/types.d.ts +22 -0
- package/build/_cjs/helpers/use-component/types.js +2 -0
- package/build/_cjs/index.d.ts +3 -0
- package/build/_cjs/index.js +19 -0
- package/build/_cjs/slots/hook.d.ts +20 -0
- package/build/_cjs/slots/hook.js +143 -0
- package/build/_cjs/slots/index.d.ts +1 -0
- package/build/_cjs/slots/index.js +17 -0
- package/build/_cjs/slots/types.d.ts +131 -0
- package/build/_cjs/slots/types.js +2 -0
- package/build/base/merged-state.js +30 -53
- package/build/base/methods.d.ts +2 -3
- package/build/base/methods.js +18 -23
- package/build/base/state/class.js +45 -68
- package/build/base/state/hooks.js +6 -10
- package/build/classy/class/index.d.ts +15 -2
- package/build/classy/class/index.js +96 -83
- package/build/classy/class/utils/function-name.js +1 -1
- package/build/classy/instance/index.d.ts +1 -1
- package/build/classy/instance/index.js +57 -82
- package/build/classy/instance/mount-callbacks.js +8 -8
- package/build/classy/logic/index.js +21 -26
- package/build/globals.d.ts +130 -83
- package/build/helpers/errors.js +1 -1
- package/build/helpers/index.js +1 -1
- package/build/helpers/mount-state.js +6 -6
- package/build/helpers/rerender.js +12 -12
- package/build/helpers/type-guards.js +2 -2
- package/build/helpers/use-component/index.js +5 -5
- package/build/index.d.ts +0 -1
- package/build/slots/hook.js +28 -36
- package/build/tsconfig.json +5 -6
- package/package.json +31 -11
- package/build/globals.js +0 -4
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { TPropsBase } from '../logic';
|
|
3
|
+
import type { Extractor } from './types/extractor';
|
|
4
|
+
import { ComponentInstance } from '../instance';
|
|
5
|
+
/**
|
|
6
|
+
* @summary
|
|
7
|
+
* A modern class component for React that is fully compatible with
|
|
8
|
+
* React Hooks and all of React's latest features.
|
|
9
|
+
*
|
|
10
|
+
* It is a superset of {@link ComponentInstance} that allows defining your
|
|
11
|
+
* component's JSX template directly inside the class.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* In essence, this is a class wrapper around an underlying function component.
|
|
15
|
+
* It acts as syntactic sugar, allowing you to create a regular function
|
|
16
|
+
* component, while writing in an object-oriented format.
|
|
17
|
+
*
|
|
18
|
+
* This is designed to closely resemble the old {@link React.Component} class,
|
|
19
|
+
* making it easier to migrate older class components to the newer hooks-based system
|
|
20
|
+
* with little to no changes to their existing semantics/implementation.
|
|
21
|
+
*/
|
|
22
|
+
export declare class ClassComponent<TProps extends TPropsBase = null> extends ComponentInstance<TProps> {
|
|
23
|
+
/**
|
|
24
|
+
* Analogous to {@link React.Component.render}. A function that returns
|
|
25
|
+
* your component's JSX template.
|
|
26
|
+
*
|
|
27
|
+
* ******
|
|
28
|
+
*
|
|
29
|
+
* Ideally the template method should only be concerned with defining the HTML/JSX structure of
|
|
30
|
+
* your component's UI.
|
|
31
|
+
*
|
|
32
|
+
* If you need to transform some data for display,
|
|
33
|
+
* do so in [beforeRender]({@link ComponentInstance.beforeRender}),
|
|
34
|
+
* and return an object with transformed data that can be rendered directly.
|
|
35
|
+
*
|
|
36
|
+
* The returned object will be passed to your template method
|
|
37
|
+
* as a `context` object.
|
|
38
|
+
*
|
|
39
|
+
* ******
|
|
40
|
+
*
|
|
41
|
+
* @example Using a template function that returns JSX.
|
|
42
|
+
*
|
|
43
|
+
* ```tsx
|
|
44
|
+
* beforeRender = () => {
|
|
45
|
+
* return {
|
|
46
|
+
* title: `My Site | ${this.props.title}`,
|
|
47
|
+
* };
|
|
48
|
+
* }
|
|
49
|
+
* template = (ctx) => {
|
|
50
|
+
* return (
|
|
51
|
+
* <h1>
|
|
52
|
+
* {ctx.title}
|
|
53
|
+
* </h1>
|
|
54
|
+
* <p>{this.props.description}</p>
|
|
55
|
+
* );
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
template: (context: this['templateContext']) => JSX.Element | null;
|
|
60
|
+
/**
|
|
61
|
+
* Manually trigger a rerender of your component.
|
|
62
|
+
* You should rarely ever need this. But if you are migrating
|
|
63
|
+
* an older React.Component class, this should provide similar functionality
|
|
64
|
+
* to the {@link React.Component.forceUpdate | `forceUpdate`} method provided there.
|
|
65
|
+
*
|
|
66
|
+
* Note that the callback argument is currently not supported.
|
|
67
|
+
*/
|
|
68
|
+
readonly forceUpdate: VoidFunction;
|
|
69
|
+
/**
|
|
70
|
+
* A standard React function component that works like any
|
|
71
|
+
* other function component and can be rendered as JSX.
|
|
72
|
+
* \`<MyComponent.FC />\`
|
|
73
|
+
*/
|
|
74
|
+
static _FC<T extends typeof ClassComponent>(this: T, props: InstanceType<T>['props']): JSX.Element | null;
|
|
75
|
+
static _BoundFC: typeof this._FC | undefined;
|
|
76
|
+
static get FC(): typeof ClassComponent._FC;
|
|
77
|
+
/*************************************
|
|
78
|
+
* Function Component Extractor *
|
|
79
|
+
**************************************/
|
|
80
|
+
/**
|
|
81
|
+
* Extract a Function Component (FC) which can be used to render
|
|
82
|
+
* your ClassComponent just like any other React component.
|
|
83
|
+
*
|
|
84
|
+
* Each JSX reference to the returned component will render with
|
|
85
|
+
* a separate instance of your class.
|
|
86
|
+
*
|
|
87
|
+
* So you only need to call `YourClassComponent.extract()` (or `*.FC()`) once,
|
|
88
|
+
* then use the returned function component as many times as you need.
|
|
89
|
+
*
|
|
90
|
+
* It is recommended to store this returned value as a static member of
|
|
91
|
+
* your ClassComponent. While this value may be given any name, the name
|
|
92
|
+
* RC (for "React Component") is the recommended convention.
|
|
93
|
+
*
|
|
94
|
+
* @example <caption>Calling `extract` in your ClassComponent</caption>
|
|
95
|
+
* class Button extends ClassComponent {
|
|
96
|
+
* static readonly RC = this.extract(); // or this.FC();
|
|
97
|
+
* // Because of the static keyword, `this` here refers to the class itself, same as calling `Button.extract()`.
|
|
98
|
+
* }
|
|
99
|
+
*
|
|
100
|
+
* // Render with `<Button.RC />`, or export RC to use the component in other files.
|
|
101
|
+
* export default Button.RC;
|
|
102
|
+
*/
|
|
103
|
+
static readonly extract: Extractor;
|
|
104
|
+
/**
|
|
105
|
+
* A standard React function component that works like any
|
|
106
|
+
* other function component and can be rendered as JSX.
|
|
107
|
+
* \`<MyComponent.RC />\`
|
|
108
|
+
*/
|
|
109
|
+
static readonly RC: React.VoidFunctionComponent<object | EmptyObject>;
|
|
110
|
+
}
|
|
111
|
+
export { ClassComponent as Component };
|
|
112
|
+
/** /
|
|
113
|
+
testing: {
|
|
114
|
+
const a: object = {b: ''};
|
|
115
|
+
|
|
116
|
+
type t = keyof typeof a;
|
|
117
|
+
|
|
118
|
+
class MyComponentLogic extends ClassComponent<{a: ''}> {
|
|
119
|
+
getInitialState = () => ({a: '' as const});
|
|
120
|
+
// a = () => this.hooks.a = '';
|
|
121
|
+
|
|
122
|
+
useHooks = () => {
|
|
123
|
+
this.state.a;
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const Template = MyComponentLogic.FC();
|
|
128
|
+
}/**/
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.Component = exports.ClassComponent = void 0;
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const instance_1 = require("../instance");
|
|
7
|
+
const function_name_1 = require("./utils/function-name");
|
|
8
|
+
const rerender_1 = require("../../helpers/rerender");
|
|
9
|
+
/**
|
|
10
|
+
* @summary
|
|
11
|
+
* A modern class component for React that is fully compatible with
|
|
12
|
+
* React Hooks and all of React's latest features.
|
|
13
|
+
*
|
|
14
|
+
* It is a superset of {@link ComponentInstance} that allows defining your
|
|
15
|
+
* component's JSX template directly inside the class.
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* In essence, this is a class wrapper around an underlying function component.
|
|
19
|
+
* It acts as syntactic sugar, allowing you to create a regular function
|
|
20
|
+
* component, while writing in an object-oriented format.
|
|
21
|
+
*
|
|
22
|
+
* This is designed to closely resemble the old {@link React.Component} class,
|
|
23
|
+
* making it easier to migrate older class components to the newer hooks-based system
|
|
24
|
+
* with little to no changes to their existing semantics/implementation.
|
|
25
|
+
*/
|
|
26
|
+
class ClassComponent extends instance_1.ComponentInstance {
|
|
27
|
+
constructor() {
|
|
28
|
+
super(...arguments);
|
|
29
|
+
/**
|
|
30
|
+
* Analogous to {@link React.Component.render}. A function that returns
|
|
31
|
+
* your component's JSX template.
|
|
32
|
+
*
|
|
33
|
+
* ******
|
|
34
|
+
*
|
|
35
|
+
* Ideally the template method should only be concerned with defining the HTML/JSX structure of
|
|
36
|
+
* your component's UI.
|
|
37
|
+
*
|
|
38
|
+
* If you need to transform some data for display,
|
|
39
|
+
* do so in [beforeRender]({@link ComponentInstance.beforeRender}),
|
|
40
|
+
* and return an object with transformed data that can be rendered directly.
|
|
41
|
+
*
|
|
42
|
+
* The returned object will be passed to your template method
|
|
43
|
+
* as a `context` object.
|
|
44
|
+
*
|
|
45
|
+
* ******
|
|
46
|
+
*
|
|
47
|
+
* @example Using a template function that returns JSX.
|
|
48
|
+
*
|
|
49
|
+
* ```tsx
|
|
50
|
+
* beforeRender = () => {
|
|
51
|
+
* return {
|
|
52
|
+
* title: `My Site | ${this.props.title}`,
|
|
53
|
+
* };
|
|
54
|
+
* }
|
|
55
|
+
* template = (ctx) => {
|
|
56
|
+
* return (
|
|
57
|
+
* <h1>
|
|
58
|
+
* {ctx.title}
|
|
59
|
+
* </h1>
|
|
60
|
+
* <p>{this.props.description}</p>
|
|
61
|
+
* );
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
this.template = () => null;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A standard React function component that works like any
|
|
69
|
+
* other function component and can be rendered as JSX.
|
|
70
|
+
* \`<MyComponent.FC />\`
|
|
71
|
+
*/
|
|
72
|
+
static _FC(props) {
|
|
73
|
+
const instance = (0, instance_1.useInstance)(this, props);
|
|
74
|
+
const { template, templateContext } = instance;
|
|
75
|
+
let _forceUpdate;
|
|
76
|
+
// @ts-expect-error (Cannot assign to 'forceUpdate' because it is a read-only property.ts(2540))
|
|
77
|
+
instance.forceUpdate = (_forceUpdate = (0, rerender_1.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`.
|
|
78
|
+
);
|
|
79
|
+
// Add calling component name to template function name in stack traces.
|
|
80
|
+
(0, react_1.useMemo)(() => {
|
|
81
|
+
(0, function_name_1.setFunctionName)(template, `${this.name}.template`);
|
|
82
|
+
}, [template]);
|
|
83
|
+
return template(templateContext);
|
|
84
|
+
}
|
|
85
|
+
;
|
|
86
|
+
static get FC() {
|
|
87
|
+
if (this._BoundFC)
|
|
88
|
+
return this._BoundFC;
|
|
89
|
+
return this._BoundFC = this._FC.bind(this);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.ClassComponent = ClassComponent;
|
|
93
|
+
exports.Component = ClassComponent;
|
|
94
|
+
_a = ClassComponent;
|
|
95
|
+
(() => {
|
|
96
|
+
(0, function_name_1.setFunctionName)(_a._FC, `$${_a.name}$`);
|
|
97
|
+
})();
|
|
98
|
+
/*************************************
|
|
99
|
+
* Function Component Extractor *
|
|
100
|
+
**************************************/
|
|
101
|
+
/**
|
|
102
|
+
* Extract a Function Component (FC) which can be used to render
|
|
103
|
+
* your ClassComponent just like any other React component.
|
|
104
|
+
*
|
|
105
|
+
* Each JSX reference to the returned component will render with
|
|
106
|
+
* a separate instance of your class.
|
|
107
|
+
*
|
|
108
|
+
* So you only need to call `YourClassComponent.extract()` (or `*.FC()`) once,
|
|
109
|
+
* then use the returned function component as many times as you need.
|
|
110
|
+
*
|
|
111
|
+
* It is recommended to store this returned value as a static member of
|
|
112
|
+
* your ClassComponent. While this value may be given any name, the name
|
|
113
|
+
* RC (for "React Component") is the recommended convention.
|
|
114
|
+
*
|
|
115
|
+
* @example <caption>Calling `extract` in your ClassComponent</caption>
|
|
116
|
+
* class Button extends ClassComponent {
|
|
117
|
+
* static readonly RC = this.extract(); // or this.FC();
|
|
118
|
+
* // Because of the static keyword, `this` here refers to the class itself, same as calling `Button.extract()`.
|
|
119
|
+
* }
|
|
120
|
+
*
|
|
121
|
+
* // Render with `<Button.RC />`, or export RC to use the component in other files.
|
|
122
|
+
* export default Button.RC;
|
|
123
|
+
*/
|
|
124
|
+
ClassComponent.extract = function FC(_Component, properties) {
|
|
125
|
+
const Component = _Component !== null && _Component !== void 0 ? _Component : this;
|
|
126
|
+
const isClassComponentType = Component.prototype instanceof _a;
|
|
127
|
+
if (!isClassComponentType)
|
|
128
|
+
throw new Error('Attempted to initialize ClassComponent with invalid Class type. Either pass, as an argument to FC(), a class that extends ClassComponent (e.g `export FC(MyComponent);`), or ensure FC() is called as a method on a ClassComponent constructor type (e.g `export MyComponent.FC()`).');
|
|
129
|
+
/*************************************
|
|
130
|
+
* Begin Function Component *
|
|
131
|
+
**************************************/
|
|
132
|
+
/** A class-based, React function component created with `@cleanweb/oore`. {@link ClassComponent} */
|
|
133
|
+
const Wrapper = (props) => {
|
|
134
|
+
const instance = (0, instance_1.useInstance)(Component, props);
|
|
135
|
+
const { template, templateContext } = instance;
|
|
136
|
+
let _forceUpdate;
|
|
137
|
+
// @ts-expect-error (Cannot assign to 'forceUpdate' because it is a read-only property.ts(2540))
|
|
138
|
+
instance.forceUpdate = (_forceUpdate = (0, rerender_1.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`.
|
|
139
|
+
);
|
|
140
|
+
// Add calling component name to template function name in stack traces.
|
|
141
|
+
(0, react_1.useMemo)(() => {
|
|
142
|
+
(0, function_name_1.setFunctionName)(template, `${Component.name}.template`);
|
|
143
|
+
}, [template]);
|
|
144
|
+
return template(templateContext);
|
|
145
|
+
};
|
|
146
|
+
/**************************************
|
|
147
|
+
* 👆🏼 End Function Component *
|
|
148
|
+
**************************************/
|
|
149
|
+
(0, function_name_1.setFunctionName)(Wrapper, `$${Component.name}$`);
|
|
150
|
+
return Object.assign(Wrapper, properties);
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* A standard React function component that works like any
|
|
154
|
+
* other function component and can be rendered as JSX.
|
|
155
|
+
* \`<MyComponent.RC />\`
|
|
156
|
+
*/
|
|
157
|
+
ClassComponent.RC = _a.extract();
|
|
158
|
+
/** /
|
|
159
|
+
testing: {
|
|
160
|
+
const a: object = {b: ''};
|
|
161
|
+
|
|
162
|
+
type t = keyof typeof a;
|
|
163
|
+
|
|
164
|
+
class MyComponentLogic extends ClassComponent<{a: ''}> {
|
|
165
|
+
getInitialState = () => ({a: '' as const});
|
|
166
|
+
// a = () => this.hooks.a = '';
|
|
167
|
+
|
|
168
|
+
useHooks = () => {
|
|
169
|
+
this.state.a;
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const Template = MyComponentLogic.FC();
|
|
174
|
+
}/**/
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { VoidFunctionComponent } from 'react';
|
|
2
|
+
import type { ClassComponent } from '..';
|
|
3
|
+
type BaseCCConstructor = typeof ClassComponent<object>;
|
|
4
|
+
export type Extractor = <TComponentClass extends BaseCCConstructor, TProperties extends {} = {}>(this: TComponentClass, Component?: TComponentClass | null, properties?: TProperties) => NonNullable<TProperties> & VoidFunctionComponent<InstanceType<TComponentClass>['props']>;
|
|
5
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setFunctionName = void 0;
|
|
4
|
+
/** Provide more useful stack traces for otherwise non-specific function names. */
|
|
5
|
+
const setFunctionName = (func, newName) => {
|
|
6
|
+
try {
|
|
7
|
+
// Must use try block, as `name` is not configurable on older browsers, and may yield a TypeError.
|
|
8
|
+
Object.defineProperty(func, 'name', {
|
|
9
|
+
writable: true,
|
|
10
|
+
value: newName,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
console.warn(error);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
exports.setFunctionName = setFunctionName;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./logic"), exports);
|
|
18
|
+
__exportStar(require("./instance"), exports);
|
|
19
|
+
__exportStar(require("./class"), exports);
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { UseInstance } from './types/hook';
|
|
2
|
+
import type { TPropsBase } from '../../classy/logic';
|
|
3
|
+
import { ComponentLogic } from '../../classy/logic';
|
|
4
|
+
type AsyncAllowedEffectCallback = () => Awaitable<IVoidFunction | void>;
|
|
5
|
+
/**
|
|
6
|
+
* A superset of {@link ComponentLogic} that adds support for lifecycle methods.
|
|
7
|
+
* This provides a declarative API for working with your React function component's lifecycle,
|
|
8
|
+
* a simpler alternative to the imperative approach with `useEffect` and/or `useMemo`.
|
|
9
|
+
*
|
|
10
|
+
* @see https://github.com/cleanjsweb/neat-react#lifecycle-useinstance
|
|
11
|
+
*/
|
|
12
|
+
export declare class ComponentInstance<TProps extends TPropsBase = null> extends ComponentLogic<TProps> {
|
|
13
|
+
/**
|
|
14
|
+
* Runs only _before_ the first render,
|
|
15
|
+
* i.e before the component instance is mounted.
|
|
16
|
+
*
|
|
17
|
+
* It is ignored on subsequent rerenders.
|
|
18
|
+
* Uses `useMemo()` under the hood.
|
|
19
|
+
*
|
|
20
|
+
* PS: You can conditionally update state from here, but with certain caveats.
|
|
21
|
+
* {@link https://react.dev/reference/react/useState#storing-information-from-previous-renders | See the React docs for details}.
|
|
22
|
+
*/
|
|
23
|
+
beforeMount: IVoidFunction;
|
|
24
|
+
/**
|
|
25
|
+
* Runs only **_after_** the first render, i.e after the component instance is mounted.
|
|
26
|
+
* It is ignored on subsequent rerenders.
|
|
27
|
+
*
|
|
28
|
+
* Should usually only be used for logic that does not directly take part in determining what to render, like
|
|
29
|
+
* logging and analytics.
|
|
30
|
+
*
|
|
31
|
+
* @returns A cleanup function.
|
|
32
|
+
*
|
|
33
|
+
* Uses `useEffect()` under the hood.
|
|
34
|
+
*/
|
|
35
|
+
onMount: AsyncAllowedEffectCallback;
|
|
36
|
+
/**
|
|
37
|
+
* Stores the object returned by {@link beforeRender}.
|
|
38
|
+
* @see {@link templateContext}
|
|
39
|
+
*/
|
|
40
|
+
private _templateContext;
|
|
41
|
+
/**
|
|
42
|
+
* Exposes the object returned by {@link beforeRender}.
|
|
43
|
+
*
|
|
44
|
+
* This is useful when you need to render some state or props
|
|
45
|
+
* in a transformed format. Put the transformation logic
|
|
46
|
+
* in {@link beforeRender} to the keep the main
|
|
47
|
+
* function component body clean.
|
|
48
|
+
*
|
|
49
|
+
* ******
|
|
50
|
+
*
|
|
51
|
+
* @example <caption>Using `templateContext`.</caption>
|
|
52
|
+
*
|
|
53
|
+
* ```tsx
|
|
54
|
+
* class MyComponentLogic extends ComponentInstance {
|
|
55
|
+
* beforeRender = () => {
|
|
56
|
+
* const title = `My Site | ${this.props.title}`;
|
|
57
|
+
* return { title };
|
|
58
|
+
* }
|
|
59
|
+
* }
|
|
60
|
+
* const MyComponent = (props) => {
|
|
61
|
+
* const self = useInstance(MyComponentLogic, props);
|
|
62
|
+
* const { templateContext: ctx, state } = self;
|
|
63
|
+
*
|
|
64
|
+
* return (
|
|
65
|
+
* <h1>
|
|
66
|
+
* {ctx.title}
|
|
67
|
+
* </h1>
|
|
68
|
+
* <p>{props.description}</p>
|
|
69
|
+
* );
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
get templateContext(): ReturnType<this["beforeRender"]>;
|
|
74
|
+
/**
|
|
75
|
+
* Runs _before_ every render cycle, including the first.
|
|
76
|
+
* Useful for logic that is involved in determining what to render.
|
|
77
|
+
*
|
|
78
|
+
* It runs in the same way as logic placed directly into the
|
|
79
|
+
* function component body preceding the return statement.
|
|
80
|
+
*
|
|
81
|
+
* This is the ideal place to transform data for display.
|
|
82
|
+
* Return the transformed data in an object, and the object will
|
|
83
|
+
* availble as [`self.templateContext`]({@link templateContext})
|
|
84
|
+
* for use in your JSX template.
|
|
85
|
+
*
|
|
86
|
+
* PS: You can conditionally update state from here, but with certain caveats.
|
|
87
|
+
* {@link https://react.dev/reference/react/useState#storing-information-from-previous-renders | See the React docs for details}.
|
|
88
|
+
*/
|
|
89
|
+
beforeRender: () => any;
|
|
90
|
+
/**
|
|
91
|
+
* Runs **_after_** every render cycle, including the first.
|
|
92
|
+
*
|
|
93
|
+
* Should usually only be used for logic that does not directly take part in determining what to render,
|
|
94
|
+
* like logging and analytics.
|
|
95
|
+
*
|
|
96
|
+
* Uses `useEffect()` under the hood.
|
|
97
|
+
*
|
|
98
|
+
* @returns A cleanup function.
|
|
99
|
+
*/
|
|
100
|
+
onRender: AsyncAllowedEffectCallback;
|
|
101
|
+
/**
|
|
102
|
+
* Runs when the component is unmounted.
|
|
103
|
+
* It is called _after_ the cleanup function returned by onMount.
|
|
104
|
+
*/
|
|
105
|
+
cleanUp: IVoidFunction;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Enables full separation of concerns between a React component's template
|
|
109
|
+
* and all of the logic that drives it.
|
|
110
|
+
*
|
|
111
|
+
* Returns an object that fully represents a logical instance
|
|
112
|
+
* of the rendered React component, with the exception of the JSX template itself.
|
|
113
|
+
*
|
|
114
|
+
* This means that all of your component's logic and lifecycle handlers
|
|
115
|
+
* can be externalized from the function component itself,
|
|
116
|
+
* and defined in a separate class.
|
|
117
|
+
*
|
|
118
|
+
* The provided class should be a subclass of {@link ComponentInstance}.
|
|
119
|
+
*/
|
|
120
|
+
export declare const useInstance: UseInstance;
|
|
121
|
+
export {};
|
|
122
|
+
/** /
|
|
123
|
+
testing: {
|
|
124
|
+
class A extends ComponentInstance<EmptyObject> {
|
|
125
|
+
getInitialState = (p?: object) => ({putan: ''});
|
|
126
|
+
// k = this.props.o
|
|
127
|
+
am = this.state['_initialValues_'];
|
|
128
|
+
k = this.am.putan;
|
|
129
|
+
|
|
130
|
+
beforeRender = () => ({g: ''});
|
|
131
|
+
|
|
132
|
+
useHooks = () => {
|
|
133
|
+
return {j: 9};
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const a = useInstance(A, {});
|
|
138
|
+
a.am;
|
|
139
|
+
|
|
140
|
+
// a.props['o'];
|
|
141
|
+
type bbbb = A['state'];
|
|
142
|
+
type ttt = bbbb['put'];
|
|
143
|
+
}
|
|
144
|
+
/**/
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useInstance = exports.ComponentInstance = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const logic_1 = require("../../classy/logic");
|
|
6
|
+
const mount_callbacks_1 = require("./mount-callbacks");
|
|
7
|
+
const helpers_1 = require("../../helpers");
|
|
8
|
+
/**
|
|
9
|
+
* A superset of {@link ComponentLogic} that adds support for lifecycle methods.
|
|
10
|
+
* This provides a declarative API for working with your React function component's lifecycle,
|
|
11
|
+
* a simpler alternative to the imperative approach with `useEffect` and/or `useMemo`.
|
|
12
|
+
*
|
|
13
|
+
* @see https://github.com/cleanjsweb/neat-react#lifecycle-useinstance
|
|
14
|
+
*/
|
|
15
|
+
class ComponentInstance extends logic_1.ComponentLogic {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments);
|
|
18
|
+
/**
|
|
19
|
+
* Runs only _before_ the first render,
|
|
20
|
+
* i.e before the component instance is mounted.
|
|
21
|
+
*
|
|
22
|
+
* It is ignored on subsequent rerenders.
|
|
23
|
+
* Uses `useMemo()` under the hood.
|
|
24
|
+
*
|
|
25
|
+
* PS: You can conditionally update state from here, but with certain caveats.
|
|
26
|
+
* {@link https://react.dev/reference/react/useState#storing-information-from-previous-renders | See the React docs for details}.
|
|
27
|
+
*/
|
|
28
|
+
this.beforeMount = () => { };
|
|
29
|
+
/**
|
|
30
|
+
* Runs only **_after_** the first render, i.e after the component instance is mounted.
|
|
31
|
+
* It is ignored on subsequent rerenders.
|
|
32
|
+
*
|
|
33
|
+
* Should usually only be used for logic that does not directly take part in determining what to render, like
|
|
34
|
+
* logging and analytics.
|
|
35
|
+
*
|
|
36
|
+
* @returns A cleanup function.
|
|
37
|
+
*
|
|
38
|
+
* Uses `useEffect()` under the hood.
|
|
39
|
+
*/
|
|
40
|
+
this.onMount = () => helpers_1.noOp;
|
|
41
|
+
/**
|
|
42
|
+
* Runs _before_ every render cycle, including the first.
|
|
43
|
+
* Useful for logic that is involved in determining what to render.
|
|
44
|
+
*
|
|
45
|
+
* It runs in the same way as logic placed directly into the
|
|
46
|
+
* function component body preceding the return statement.
|
|
47
|
+
*
|
|
48
|
+
* This is the ideal place to transform data for display.
|
|
49
|
+
* Return the transformed data in an object, and the object will
|
|
50
|
+
* availble as [`self.templateContext`]({@link templateContext})
|
|
51
|
+
* for use in your JSX template.
|
|
52
|
+
*
|
|
53
|
+
* PS: You can conditionally update state from here, but with certain caveats.
|
|
54
|
+
* {@link https://react.dev/reference/react/useState#storing-information-from-previous-renders | See the React docs for details}.
|
|
55
|
+
*/
|
|
56
|
+
this.beforeRender = () => ({});
|
|
57
|
+
/**
|
|
58
|
+
* Runs **_after_** every render cycle, including the first.
|
|
59
|
+
*
|
|
60
|
+
* Should usually only be used for logic that does not directly take part in determining what to render,
|
|
61
|
+
* like logging and analytics.
|
|
62
|
+
*
|
|
63
|
+
* Uses `useEffect()` under the hood.
|
|
64
|
+
*
|
|
65
|
+
* @returns A cleanup function.
|
|
66
|
+
*/
|
|
67
|
+
this.onRender = () => helpers_1.noOp;
|
|
68
|
+
/**
|
|
69
|
+
* Runs when the component is unmounted.
|
|
70
|
+
* It is called _after_ the cleanup function returned by onMount.
|
|
71
|
+
*/
|
|
72
|
+
this.cleanUp = () => { };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Exposes the object returned by {@link beforeRender}.
|
|
76
|
+
*
|
|
77
|
+
* This is useful when you need to render some state or props
|
|
78
|
+
* in a transformed format. Put the transformation logic
|
|
79
|
+
* in {@link beforeRender} to the keep the main
|
|
80
|
+
* function component body clean.
|
|
81
|
+
*
|
|
82
|
+
* ******
|
|
83
|
+
*
|
|
84
|
+
* @example <caption>Using `templateContext`.</caption>
|
|
85
|
+
*
|
|
86
|
+
* ```tsx
|
|
87
|
+
* class MyComponentLogic extends ComponentInstance {
|
|
88
|
+
* beforeRender = () => {
|
|
89
|
+
* const title = `My Site | ${this.props.title}`;
|
|
90
|
+
* return { title };
|
|
91
|
+
* }
|
|
92
|
+
* }
|
|
93
|
+
* const MyComponent = (props) => {
|
|
94
|
+
* const self = useInstance(MyComponentLogic, props);
|
|
95
|
+
* const { templateContext: ctx, state } = self;
|
|
96
|
+
*
|
|
97
|
+
* return (
|
|
98
|
+
* <h1>
|
|
99
|
+
* {ctx.title}
|
|
100
|
+
* </h1>
|
|
101
|
+
* <p>{props.description}</p>
|
|
102
|
+
* );
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
get templateContext() {
|
|
107
|
+
return this._templateContext;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.ComponentInstance = ComponentInstance;
|
|
111
|
+
;
|
|
112
|
+
/**
|
|
113
|
+
* Enables full separation of concerns between a React component's template
|
|
114
|
+
* and all of the logic that drives it.
|
|
115
|
+
*
|
|
116
|
+
* Returns an object that fully represents a logical instance
|
|
117
|
+
* of the rendered React component, with the exception of the JSX template itself.
|
|
118
|
+
*
|
|
119
|
+
* This means that all of your component's logic and lifecycle handlers
|
|
120
|
+
* can be externalized from the function component itself,
|
|
121
|
+
* and defined in a separate class.
|
|
122
|
+
*
|
|
123
|
+
* The provided class should be a subclass of {@link ComponentInstance}.
|
|
124
|
+
*/
|
|
125
|
+
const useInstance = (...args) => {
|
|
126
|
+
var _a;
|
|
127
|
+
const [Component, props = {}] = args;
|
|
128
|
+
// useHooks.
|
|
129
|
+
const instance = (0, logic_1.useLogic)(Component, props);
|
|
130
|
+
// beforeMount, onMount, cleanUp.
|
|
131
|
+
(0, mount_callbacks_1.useMountCallbacks)(instance);
|
|
132
|
+
// beforeRender.
|
|
133
|
+
/**
|
|
134
|
+
* A proxy variable to allow typechecking of the assignment
|
|
135
|
+
* to `self.templateContext` despite the need for "readonly" error suppression.
|
|
136
|
+
*/
|
|
137
|
+
let _templateContextProxy_;
|
|
138
|
+
// @ts-expect-error Assigning to a readonly property.
|
|
139
|
+
instance._templateContext = (_templateContextProxy_ = (_a = instance.beforeRender) === null || _a === void 0 ? void 0 : _a.call(instance));
|
|
140
|
+
// onRender.
|
|
141
|
+
(0, react_1.useEffect)(() => {
|
|
142
|
+
var _a;
|
|
143
|
+
const cleanupAfterRerender = (_a = instance.onRender) === null || _a === void 0 ? void 0 : _a.call(instance);
|
|
144
|
+
return () => {
|
|
145
|
+
if (typeof cleanupAfterRerender === 'function')
|
|
146
|
+
cleanupAfterRerender();
|
|
147
|
+
else
|
|
148
|
+
cleanupAfterRerender === null || cleanupAfterRerender === void 0 ? void 0 : cleanupAfterRerender.then((cleanUp) => cleanUp === null || cleanUp === void 0 ? void 0 : cleanUp());
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
// class FormValues<TValues> extends BrowserMemStore<TValues> {}
|
|
152
|
+
return instance;
|
|
153
|
+
};
|
|
154
|
+
exports.useInstance = useInstance;
|
|
155
|
+
/** /
|
|
156
|
+
testing: {
|
|
157
|
+
class A extends ComponentInstance<EmptyObject> {
|
|
158
|
+
getInitialState = (p?: object) => ({putan: ''});
|
|
159
|
+
// k = this.props.o
|
|
160
|
+
am = this.state['_initialValues_'];
|
|
161
|
+
k = this.am.putan;
|
|
162
|
+
|
|
163
|
+
beforeRender = () => ({g: ''});
|
|
164
|
+
|
|
165
|
+
useHooks = () => {
|
|
166
|
+
return {j: 9};
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const a = useInstance(A, {});
|
|
171
|
+
a.am;
|
|
172
|
+
|
|
173
|
+
// a.props['o'];
|
|
174
|
+
type bbbb = A['state'];
|
|
175
|
+
type ttt = bbbb['put'];
|
|
176
|
+
}
|
|
177
|
+
/**/
|