@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.
Files changed (86) hide show
  1. package/build/_cjs/base/index.d.ts +3 -0
  2. package/build/_cjs/base/index.js +19 -0
  3. package/build/_cjs/base/merged-state.d.ts +20 -0
  4. package/build/_cjs/base/merged-state.js +61 -0
  5. package/build/_cjs/base/methods.d.ts +58 -0
  6. package/build/_cjs/base/methods.js +95 -0
  7. package/build/_cjs/base/state/class-types.d.ts +20 -0
  8. package/build/_cjs/base/state/class-types.js +2 -0
  9. package/build/_cjs/base/state/class.d.ts +69 -0
  10. package/build/_cjs/base/state/class.js +129 -0
  11. package/build/_cjs/base/state/hook-types.d.ts +32 -0
  12. package/build/_cjs/base/state/hook-types.js +2 -0
  13. package/build/_cjs/base/state/hooks.d.ts +12 -0
  14. package/build/_cjs/base/state/hooks.js +41 -0
  15. package/build/_cjs/base/state/index.d.ts +9 -0
  16. package/build/_cjs/base/state/index.js +35 -0
  17. package/build/_cjs/classy/class/index.d.ts +128 -0
  18. package/build/_cjs/classy/class/index.js +174 -0
  19. package/build/_cjs/classy/class/types/extractor.d.ts +5 -0
  20. package/build/_cjs/classy/class/types/extractor.js +2 -0
  21. package/build/_cjs/classy/class/utils/function-name.d.ts +2 -0
  22. package/build/_cjs/classy/class/utils/function-name.js +17 -0
  23. package/build/_cjs/classy/index.d.ts +3 -0
  24. package/build/_cjs/classy/index.js +19 -0
  25. package/build/_cjs/classy/instance/index.d.ts +144 -0
  26. package/build/_cjs/classy/instance/index.js +177 -0
  27. package/build/_cjs/classy/instance/mount-callbacks.d.ts +5 -0
  28. package/build/_cjs/classy/instance/mount-callbacks.js +30 -0
  29. package/build/_cjs/classy/instance/types/hook.d.ts +13 -0
  30. package/build/_cjs/classy/instance/types/hook.js +2 -0
  31. package/build/_cjs/classy/logic/index.d.ts +116 -0
  32. package/build/_cjs/classy/logic/index.js +123 -0
  33. package/build/_cjs/classy/logic/types/hook.d.ts +16 -0
  34. package/build/_cjs/classy/logic/types/hook.js +2 -0
  35. package/build/_cjs/docs-src/api/base-classes.d.ts +3 -0
  36. package/build/_cjs/docs-src/api/base-classes.js +9 -0
  37. package/build/_cjs/docs-src/api/index.d.ts +13 -0
  38. package/build/_cjs/docs-src/api/index.js +44 -0
  39. package/build/_cjs/docs-src/api/references.d.ts +5 -0
  40. package/build/_cjs/docs-src/api/references.js +31 -0
  41. package/build/_cjs/helpers/errors.d.ts +10 -0
  42. package/build/_cjs/helpers/errors.js +21 -0
  43. package/build/_cjs/helpers/index.d.ts +13 -0
  44. package/build/_cjs/helpers/index.js +31 -0
  45. package/build/_cjs/helpers/mount-state.d.ts +5 -0
  46. package/build/_cjs/helpers/mount-state.js +25 -0
  47. package/build/_cjs/helpers/rerender.d.ts +24 -0
  48. package/build/_cjs/helpers/rerender.js +42 -0
  49. package/build/_cjs/helpers/type-guards.d.ts +1 -0
  50. package/build/_cjs/helpers/type-guards.js +8 -0
  51. package/build/_cjs/helpers/use-component/index.d.ts +6 -0
  52. package/build/_cjs/helpers/use-component/index.js +17 -0
  53. package/build/_cjs/helpers/use-component/types.d.ts +22 -0
  54. package/build/_cjs/helpers/use-component/types.js +2 -0
  55. package/build/_cjs/index.d.ts +3 -0
  56. package/build/_cjs/index.js +19 -0
  57. package/build/_cjs/slots/hook.d.ts +20 -0
  58. package/build/_cjs/slots/hook.js +143 -0
  59. package/build/_cjs/slots/index.d.ts +1 -0
  60. package/build/_cjs/slots/index.js +17 -0
  61. package/build/_cjs/slots/types.d.ts +131 -0
  62. package/build/_cjs/slots/types.js +2 -0
  63. package/build/base/merged-state.js +30 -53
  64. package/build/base/methods.d.ts +2 -3
  65. package/build/base/methods.js +18 -23
  66. package/build/base/state/class.js +45 -68
  67. package/build/base/state/hooks.js +6 -10
  68. package/build/classy/class/index.d.ts +15 -2
  69. package/build/classy/class/index.js +96 -83
  70. package/build/classy/class/utils/function-name.js +1 -1
  71. package/build/classy/instance/index.d.ts +1 -1
  72. package/build/classy/instance/index.js +57 -82
  73. package/build/classy/instance/mount-callbacks.js +8 -8
  74. package/build/classy/logic/index.js +21 -26
  75. package/build/globals.d.ts +130 -83
  76. package/build/helpers/errors.js +1 -1
  77. package/build/helpers/index.js +1 -1
  78. package/build/helpers/mount-state.js +6 -6
  79. package/build/helpers/rerender.js +12 -12
  80. package/build/helpers/type-guards.js +2 -2
  81. package/build/helpers/use-component/index.js +5 -5
  82. package/build/index.d.ts +0 -1
  83. package/build/slots/hook.js +28 -36
  84. package/build/tsconfig.json +5 -6
  85. package/package.json +31 -11
  86. 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,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ /** Provide more useful stack traces for otherwise non-specific function names. */
2
+ export declare const setFunctionName: (func: FunctionType, newName: string) => void;
@@ -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,3 @@
1
+ export * from './logic';
2
+ export * from './instance';
3
+ export * from './class';
@@ -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
+ /**/
@@ -0,0 +1,5 @@
1
+ import { ComponentInstance } from '.';
2
+ type UseMountCallbacks = <TInstance extends ComponentInstance>(instance: TInstance) => void;
3
+ /** @internal */
4
+ export declare const useMountCallbacks: UseMountCallbacks;
5
+ export {};