@cleanweb/react 2.0.1-beta.0 → 2.1.0-beta.0

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 (39) hide show
  1. package/build/base/index.d.ts +1 -0
  2. package/build/base/index.js +1 -0
  3. package/build/base/state/hook-types.d.ts +1 -0
  4. package/build/base/state/hooks.d.ts +0 -5
  5. package/build/base/state/hooks.js +1 -19
  6. package/build/base/state/index.d.ts +1 -1
  7. package/build/base/state/index.js +1 -2
  8. package/build/classy/class/index.d.ts +3 -22
  9. package/build/classy/class/index.js +20 -18
  10. package/build/classy/class/types/extractor.d.ts +3 -4
  11. package/build/classy/class/utils/rerender.js +13 -1
  12. package/build/classy/instance/index.d.ts +15 -45
  13. package/build/classy/instance/index.js +33 -42
  14. package/build/classy/instance/mount-callbacks.d.ts +2 -2
  15. package/build/classy/instance/mount-callbacks.js +3 -3
  16. package/build/classy/instance/types/hook.d.ts +6 -9
  17. package/build/classy/logic/index.d.ts +21 -15
  18. package/build/classy/logic/index.js +21 -30
  19. package/build/classy/logic/types/hook.d.ts +6 -13
  20. package/build/globals.d.ts +26 -0
  21. package/build/helpers/index.d.ts +1 -0
  22. package/build/helpers/index.js +17 -0
  23. package/build/helpers/mount-state.d.ts +5 -0
  24. package/build/helpers/mount-state.js +25 -0
  25. package/build/index.d.ts +2 -0
  26. package/build/index.js +3 -16
  27. package/package.json +3 -12
  28. package/build/classy/class/types/class/instance.d.ts +0 -12
  29. package/build/classy/class/types/class/instance.js +0 -2
  30. package/build/classy/class/types/class/static.d.ts +0 -9
  31. package/build/classy/class/types/class/static.js +0 -12
  32. package/build/classy/instance/types/instance.d.ts +0 -11
  33. package/build/classy/instance/types/instance.js +0 -2
  34. package/build/classy/instance/types/static.d.ts +0 -11
  35. package/build/classy/instance/types/static.js +0 -17
  36. package/build/classy/logic/types/instance.d.ts +0 -18
  37. package/build/classy/logic/types/instance.js +0 -2
  38. package/build/classy/logic/types/static.d.ts +0 -17
  39. package/build/classy/logic/types/static.js +0 -2
@@ -1,2 +1,3 @@
1
1
  export * from './state';
2
2
  export * from './methods';
3
+ export * from './merged-state';
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./state"), exports);
18
18
  __exportStar(require("./methods"), exports);
19
+ __exportStar(require("./merged-state"), exports);
@@ -2,6 +2,7 @@ import { CleanStateBase } from './class';
2
2
  export type TStateData = object & {
3
3
  [Key in keyof CleanStateBase<{}>]?: never;
4
4
  };
5
+ /** @see https://github.com/cleanjsweb/neat-react#clean-state */
5
6
  export type TCleanState<TState extends TStateData> = (CleanStateBase<TState> & Omit<TState, keyof CleanStateBase<{}>>);
6
7
  export type ExtractCleanStateData<YourCleanState extends CleanStateBase<{}>> = Omit<YourCleanState, keyof CleanStateBase<{}>>;
7
8
  type StateInitFunction = (...args: any[]) => object;
@@ -1,9 +1,4 @@
1
1
  import { TUseCleanState } from './hook-types';
2
- /**
3
- * Returns a value that is false before the component has been mounted,
4
- * then true during all subsequent rerenders.
5
- */
6
- export declare const useMountState: () => boolean;
7
2
  /**
8
3
  * Creates a state object, which includes the provided values, and helper methods for
9
4
  * updating those values and automatically rerendering your component's UI accordingly.
@@ -1,26 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useCleanState = exports.useMountState = void 0;
3
+ exports.useCleanState = void 0;
4
4
  var react_1 = require("react");
5
5
  var class_1 = require("./class");
6
- /**
7
- * Returns a value that is false before the component has been mounted,
8
- * then true during all subsequent rerenders.
9
- */
10
- var useMountState = function () {
11
- /**
12
- * This must not be a stateful value. It should not be the cause of a rerender.
13
- * It merely provides information about the render count,
14
- * without influencing that count itself.
15
- * So `mounted` should never be set with `useState`.
16
- */
17
- var mounted = (0, react_1.useRef)(false);
18
- (0, react_1.useEffect)(function () {
19
- mounted.current = true;
20
- }, []);
21
- return mounted.current;
22
- };
23
- exports.useMountState = useMountState;
24
6
  /**
25
7
  * Creates a state object, which includes the provided values, and helper methods for
26
8
  * updating those values and automatically rerendering your component's UI accordingly.
@@ -1,4 +1,4 @@
1
1
  import '../../globals';
2
2
  export { CleanState } from './class';
3
- export { useCleanState, useMountState } from './hooks';
3
+ export { useCleanState } from './hooks';
4
4
  export type { TCleanState, TStateData, ExtractCleanStateData } from './hook-types';
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useMountState = exports.useCleanState = exports.CleanState = void 0;
3
+ exports.useCleanState = exports.CleanState = void 0;
4
4
  require("../../globals");
5
5
  var class_1 = require("./class");
6
6
  Object.defineProperty(exports, "CleanState", { enumerable: true, get: function () { return class_1.CleanState; } });
7
7
  var hooks_1 = require("./hooks");
8
8
  Object.defineProperty(exports, "useCleanState", { enumerable: true, get: function () { return hooks_1.useCleanState; } });
9
- Object.defineProperty(exports, "useMountState", { enumerable: true, get: function () { return hooks_1.useMountState; } });
@@ -1,7 +1,5 @@
1
- import type { TStateData } from '../../base';
2
1
  import type { Extractor } from './types/extractor';
3
2
  import { ComponentInstance } from '../instance';
4
- type o = object;
5
3
  /**
6
4
  * A superset of {@link ComponentInstance} that allows defining your
7
5
  * component's JSX template directly inside the class.
@@ -10,7 +8,7 @@ type o = object;
10
8
  * making it easier to migrate older class components to the newer hooks-based system
11
9
  * with little to no changes to their existing semantics/implementation.
12
10
  */
13
- export declare class ClassComponent<TProps extends o = WeakEmptyObject, TState extends TStateData = WeakEmptyObject> extends ComponentInstance<TProps, TState> {
11
+ export declare class ClassComponent<TProps extends object = WeakEmptyObject> extends ComponentInstance<TProps> {
14
12
  /**
15
13
  * Analogous to {@link React.Component.render}. A function that returns
16
14
  * your component's JSX template.
@@ -28,7 +26,7 @@ export declare class ClassComponent<TProps extends o = WeakEmptyObject, TState e
28
26
  *
29
27
  * ******
30
28
  *
31
- * @example < caption>Using a template function that returns JSX.</ caption>
29
+ * @example <caption>Using a template function that returns JSX.</caption>
32
30
  *
33
31
  * ```tsx
34
32
  * template = () => {
@@ -42,7 +40,7 @@ export declare class ClassComponent<TProps extends o = WeakEmptyObject, TState e
42
40
  * }
43
41
  * ```
44
42
  */
45
- template: (context: this['templateContext']) => (React.JSX.Element | null);
43
+ template: (context: this['templateContext']) => JSX.Element | null;
46
44
  /**
47
45
  * Manually trigger a rerender of your component.
48
46
  * You should rarely ever need this. But if you are migrating
@@ -83,20 +81,3 @@ export declare class ClassComponent<TProps extends o = WeakEmptyObject, TState e
83
81
  static readonly FC: Extractor;
84
82
  }
85
83
  export { ClassComponent as Component };
86
- /** /
87
- testing: {
88
- const a: object = {b: ''};
89
-
90
- type t = keyof typeof a;
91
-
92
- class MyComponentLogic extends ClassComponent<{}, {a: ''}> {
93
- static getInitialState = () => ({a: '' as const});
94
- // a = () => this.hooks.a = '';
95
-
96
- useHooks = () => {
97
- this.state.a;
98
- };
99
- };
100
-
101
- const Template = MyComponentLogic.FC();
102
- }/**/
@@ -49,7 +49,7 @@ var ClassComponent = /** @class */ (function (_super) {
49
49
  *
50
50
  * ******
51
51
  *
52
- * @example < caption>Using a template function that returns JSX.</ caption>
52
+ * @example <caption>Using a template function that returns JSX.</caption>
53
53
  *
54
54
  * ```tsx
55
55
  * template = () => {
@@ -97,7 +97,7 @@ var ClassComponent = /** @class */ (function (_super) {
97
97
  ClassComponent.extract = function FC(_Component) {
98
98
  var Component = _Component !== null && _Component !== void 0 ? _Component : this;
99
99
  var isClassComponentType = Component.prototype instanceof _a;
100
- if (!Component.getInitialState || !isClassComponentType)
100
+ if (!isClassComponentType)
101
101
  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()`).');
102
102
  /*************************************
103
103
  * Begin Function Component *
@@ -128,20 +128,22 @@ var ClassComponent = /** @class */ (function (_super) {
128
128
  }(instance_1.ComponentInstance));
129
129
  exports.ClassComponent = ClassComponent;
130
130
  exports.Component = ClassComponent;
131
- /** /
131
+ /**/
132
132
  testing: {
133
- const a: object = {b: ''};
134
-
135
- type t = keyof typeof a;
136
-
137
- class MyComponentLogic extends ClassComponent<{}, {a: ''}> {
138
- static getInitialState = () => ({a: '' as const});
139
- // a = () => this.hooks.a = '';
140
-
141
- useHooks = () => {
142
- this.state.a;
143
- };
144
- };
145
-
146
- const Template = MyComponentLogic.FC();
147
- }/**/
133
+ var a = { b: '' };
134
+ var MyComponentLogic = /** @class */ (function (_super) {
135
+ __extends(MyComponentLogic, _super);
136
+ function MyComponentLogic() {
137
+ var _this = _super !== null && _super.apply(this, arguments) || this;
138
+ _this.getInitialState = function () { return ({ a: '' }); };
139
+ // a = () => this.hooks.a = '';
140
+ _this.useHooks = function () {
141
+ _this.state.a;
142
+ };
143
+ return _this;
144
+ }
145
+ return MyComponentLogic;
146
+ }(ClassComponent));
147
+ ;
148
+ var Template = MyComponentLogic.FC();
149
+ } /**/
@@ -1,6 +1,5 @@
1
1
  import type { VoidFunctionComponent } from 'react';
2
- import type { BaseClassComponent } from './class/instance';
3
- import type { IClassComponentConstructor } from './class/static';
4
- type BaseCCConstructor = IClassComponentConstructor<BaseClassComponent>;
5
- export type Extractor = <TComponent extends BaseCCConstructor>(this: TComponent & IClassComponentConstructor<InstanceType<TComponent>>, Component?: TComponent & IClassComponentConstructor<InstanceType<TComponent>>) => VoidFunctionComponent<InstanceType<TComponent>['props']>;
2
+ import type { ClassComponent } from '..';
3
+ type BaseCCConstructor = typeof ClassComponent<object>;
4
+ export type Extractor = <TComponentClass extends BaseCCConstructor>(this: TComponentClass, Component?: TComponentClass) => VoidFunctionComponent<InstanceType<TComponentClass>['props']>;
6
5
  export {};
@@ -1,11 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useRerender = void 0;
4
+ var mount_state_1 = require("../../../helpers/mount-state");
4
5
  var react_1 = require("react");
5
6
  var useRerender = function () {
7
+ var isMounted = (0, mount_state_1.useMountState)();
6
8
  // Skip the value, we don't need it. Grab just the setter function.
7
9
  var _a = (0, react_1.useState)(Date.now()), _forceRerender = _a[1];
8
- var rerender = function () { return _forceRerender(Date.now()); };
10
+ var rerender = function () {
11
+ if (isMounted()) {
12
+ _forceRerender(Date.now());
13
+ return;
14
+ }
15
+ setTimeout(function () {
16
+ if (!isMounted())
17
+ return;
18
+ _forceRerender(Date.now());
19
+ }, 1000);
20
+ };
9
21
  return rerender;
10
22
  };
11
23
  exports.useRerender = useRerender;
@@ -1,37 +1,36 @@
1
- import type { TStateData } from '../../base';
2
1
  import type { UseInstance } from './types/hook';
3
- import type { CIBaseType, IComponentInstance } from './types/instance';
4
- import type { IComponentInstanceClass } from './types/static';
5
2
  import { ComponentLogic } from '../../classy/logic';
6
3
  type AsyncAllowedEffectCallback = () => Awaitable<IVoidFunction>;
7
- type o = object;
8
4
  /** An empty function. It returns (void) without performing any operations. */
9
5
  export declare const noOp: () => void;
10
6
  /**
11
7
  * A superset of {@link ComponentLogic} that adds support for lifecycle methods.
12
8
  * This provides a declarative API for working with your React function component's lifecycle,
13
9
  * a simpler alternative to the imperative approach with `useEffect` and/or `useMemo`.
10
+ *
11
+ * @see https://github.com/cleanjsweb/neat-react#lifecycle-useinstance
14
12
  */
15
- export declare class ComponentInstance<TProps extends o = {}, TState extends TStateData = WeakEmptyObject> extends ComponentLogic.Class<TProps, TState> {
13
+ export declare class ComponentInstance<TProps extends object = {}> extends ComponentLogic<TProps> {
16
14
  /**
17
- * Runs only _before_ first render, i.e before the component instance is mounted.
18
- * Useful for logic that is involved in determining what to render.
15
+ * Runs only _before_ first render,
16
+ * i.e before the component instance is mounted.
19
17
  *
20
- * Updating local state from in here will abort the render cycle early, before changes are committed to the DOM,
21
- * and prompt React to immediately rerender the component with the updated state value(s).
18
+ * It is ignored on subsequent rerenders.
22
19
  *
23
- * Ignored on subsequent rerenders.
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 more details}.
24
22
  */
25
23
  beforeMount: IVoidFunction;
26
24
  /**
27
25
  * Runs only **_after_** first render, i.e after the component instance is mounted.
26
+ * It is ignored on subsequent rerenders.
28
27
  *
29
28
  * Should usually only be used for logic that does not directly take part in determining what to render, like
30
29
  * synchronize your component with some external system.
31
30
  *
32
- * Ignored on subsequent rerenders.
31
+ * @returns A cleanup function.
33
32
  *
34
- * Returns a cleanup function.
33
+ * Uses `useEffect()` under the hood.
35
34
  */
36
35
  onMount: AsyncAllowedEffectCallback;
37
36
  private _templateContext;
@@ -40,8 +39,8 @@ export declare class ComponentInstance<TProps extends o = {}, TState extends TSt
40
39
  * Runs _before_ every render cycle, including the first.
41
40
  * Useful for logic that is involved in determining what to render.
42
41
  *
43
- * Updating local state from in here will abort the render cycle early, before changes are committed to the DOM,
44
- * and prompt React to immediately rerender the component with the updated state value(s).
42
+ * PS: You can conditionally update state from here, but with certain caveats.
43
+ * {@link https://react.dev/reference/react/useState#storing-information-from-previous-renders | See the React docs for more details}.
45
44
  */
46
45
  beforeRender: () => object | void;
47
46
  /**
@@ -50,6 +49,8 @@ export declare class ComponentInstance<TProps extends o = {}, TState extends TSt
50
49
  * Should usually only be used for logic that does not directly take part in determining what to render, like
51
50
  * synchronize your component with some external system.
52
51
  *
52
+ * Uses `useEffect()` under the hood.
53
+ *
53
54
  * Returns a cleanup function.
54
55
  */
55
56
  onRender: AsyncAllowedEffectCallback;
@@ -60,35 +61,4 @@ export declare class ComponentInstance<TProps extends o = {}, TState extends TSt
60
61
  cleanUp: IVoidFunction;
61
62
  }
62
63
  export declare const useInstance: UseInstance;
63
- export declare namespace ComponentInstance {
64
- class Class<TProps extends object = {}, TState extends TStateData = WeakEmptyObject> extends ComponentInstance<TProps, TState> {
65
- }
66
- type Instance<Instance extends CIBaseType = Class> = IComponentInstance<Instance>;
67
- type ClassType<Instance extends CIBaseType = Class> = IComponentInstanceClass<Instance>;
68
- }
69
64
  export {};
70
- /** /
71
- testing: {
72
- class A extends ComponentInstance<{}, {}> {
73
- static getInitialState: (p?: object) => ({putan: ''});
74
- // k = this.props.o
75
- a = this.state['_initialValues_'];
76
-
77
- beforeRender = () => '';
78
-
79
- useHooks = () => {
80
- type a = typeof this._templateContext;
81
- };
82
- // hard empty has every key
83
- // weak empty has no key
84
- // weak empty is not assignable to hard empty
85
- }
86
-
87
- const a = useInstance(A, {o: ''});
88
- a.a;
89
-
90
- // a.props['o'];
91
- type bbbb = A['state'];
92
- type ttt = bbbb['put'];
93
- }
94
- /**/
@@ -26,38 +26,41 @@ exports.noOp = noOp;
26
26
  * A superset of {@link ComponentLogic} that adds support for lifecycle methods.
27
27
  * This provides a declarative API for working with your React function component's lifecycle,
28
28
  * a simpler alternative to the imperative approach with `useEffect` and/or `useMemo`.
29
+ *
30
+ * @see https://github.com/cleanjsweb/neat-react#lifecycle-useinstance
29
31
  */
30
32
  var ComponentInstance = /** @class */ (function (_super) {
31
33
  __extends(ComponentInstance, _super);
32
34
  function ComponentInstance() {
33
35
  var _this = _super !== null && _super.apply(this, arguments) || this;
34
36
  /**
35
- * Runs only _before_ first render, i.e before the component instance is mounted.
36
- * Useful for logic that is involved in determining what to render.
37
+ * Runs only _before_ first render,
38
+ * i.e before the component instance is mounted.
37
39
  *
38
- * Updating local state from in here will abort the render cycle early, before changes are committed to the DOM,
39
- * and prompt React to immediately rerender the component with the updated state value(s).
40
+ * It is ignored on subsequent rerenders.
40
41
  *
41
- * Ignored on subsequent rerenders.
42
+ * PS: You can conditionally update state from here, but with certain caveats.
43
+ * {@link https://react.dev/reference/react/useState#storing-information-from-previous-renders | See the React docs for more details}.
42
44
  */
43
45
  _this.beforeMount = function () { };
44
46
  /**
45
47
  * Runs only **_after_** first render, i.e after the component instance is mounted.
48
+ * It is ignored on subsequent rerenders.
46
49
  *
47
50
  * Should usually only be used for logic that does not directly take part in determining what to render, like
48
51
  * synchronize your component with some external system.
49
52
  *
50
- * Ignored on subsequent rerenders.
53
+ * @returns A cleanup function.
51
54
  *
52
- * Returns a cleanup function.
55
+ * Uses `useEffect()` under the hood.
53
56
  */
54
57
  _this.onMount = function () { return exports.noOp; };
55
58
  /**
56
59
  * Runs _before_ every render cycle, including the first.
57
60
  * Useful for logic that is involved in determining what to render.
58
61
  *
59
- * Updating local state from in here will abort the render cycle early, before changes are committed to the DOM,
60
- * and prompt React to immediately rerender the component with the updated state value(s).
62
+ * PS: You can conditionally update state from here, but with certain caveats.
63
+ * {@link https://react.dev/reference/react/useState#storing-information-from-previous-renders | See the React docs for more details}.
61
64
  */
62
65
  _this.beforeRender = function () { };
63
66
  /**
@@ -66,6 +69,8 @@ var ComponentInstance = /** @class */ (function (_super) {
66
69
  * Should usually only be used for logic that does not directly take part in determining what to render, like
67
70
  * synchronize your component with some external system.
68
71
  *
72
+ * Uses `useEffect()` under the hood.
73
+ *
69
74
  * Returns a cleanup function.
70
75
  */
71
76
  _this.onRender = function () { return exports.noOp; };
@@ -84,7 +89,7 @@ var ComponentInstance = /** @class */ (function (_super) {
84
89
  configurable: true
85
90
  });
86
91
  return ComponentInstance;
87
- }(logic_1.ComponentLogic.Class));
92
+ }(logic_1.ComponentLogic));
88
93
  exports.ComponentInstance = ComponentInstance;
89
94
  ;
90
95
  /*
@@ -143,39 +148,25 @@ var useInstance = function () {
143
148
  return instance;
144
149
  };
145
150
  exports.useInstance = useInstance;
146
- (function (ComponentInstance) {
147
- var Class = /** @class */ (function (_super) {
148
- __extends(Class, _super);
149
- function Class() {
150
- return _super !== null && _super.apply(this, arguments) || this;
151
+ /**/
152
+ testing: {
153
+ var A = /** @class */ (function (_super) {
154
+ __extends(A, _super);
155
+ function A() {
156
+ var _this = _super !== null && _super.apply(this, arguments) || this;
157
+ _this.getInitialState = function (p) { return ({ putan: '' }); };
158
+ // k = this.props.o
159
+ _this.am = _this.state['_initialValues_'];
160
+ _this.k = _this.am.putan;
161
+ _this.beforeRender = function () { return ({ g: '' }); };
162
+ _this.useHooks = function () {
163
+ return { j: 9 };
164
+ };
165
+ return _this;
151
166
  }
152
- return Class;
167
+ return A;
153
168
  }(ComponentInstance));
154
- ComponentInstance.Class = Class;
155
- ;
156
- })(ComponentInstance || (exports.ComponentInstance = ComponentInstance = {}));
157
- /** /
158
- testing: {
159
- class A extends ComponentInstance<{}, {}> {
160
- static getInitialState: (p?: object) => ({putan: ''});
161
- // k = this.props.o
162
- a = this.state['_initialValues_'];
163
-
164
- beforeRender = () => '';
165
-
166
- useHooks = () => {
167
- type a = typeof this._templateContext;
168
- };
169
- // hard empty has every key
170
- // weak empty has no key
171
- // weak empty is not assignable to hard empty
172
- }
173
-
174
- const a = useInstance(A, {o: ''});
175
- a.a;
176
-
177
- // a.props['o'];
178
- type bbbb = A['state'];
179
- type ttt = bbbb['put'];
169
+ var a = (0, exports.useInstance)(A, {});
170
+ a.am;
180
171
  }
181
172
  /**/
@@ -1,4 +1,4 @@
1
- import { CIBaseType, IComponentInstance } from './types/instance';
2
- type UseMountCallbacks = <TInstance extends IComponentInstance<CIBaseType>>(instance: TInstance) => void;
1
+ import { ComponentInstance } from '.';
2
+ type UseMountCallbacks = <TInstance extends ComponentInstance>(instance: TInstance) => void;
3
3
  export declare const useMountCallbacks: UseMountCallbacks;
4
4
  export {};
@@ -2,11 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useMountCallbacks = void 0;
4
4
  var react_1 = require("react");
5
- var state_1 = require("../../base/state");
5
+ var mount_state_1 = require("../../helpers/mount-state");
6
6
  var useMountCallbacks = function (instance) {
7
7
  var _a;
8
- var mounted = (0, state_1.useMountState)();
9
- if (!mounted)
8
+ var isMounted = (0, mount_state_1.useMountState)();
9
+ if (!isMounted())
10
10
  (_a = instance.beforeMount) === null || _a === void 0 ? void 0 : _a.call(instance);
11
11
  (0, react_1.useEffect)(function () {
12
12
  var _a;
@@ -1,16 +1,13 @@
1
- import type { CIBaseType, IComponentInstance } from './instance';
2
- import type { IComponentInstanceClass } from './static';
3
1
  import { ComponentInstance } from '..';
4
- type o = object;
5
- type UIClassParam = IComponentInstanceClass<IComponentInstance<CIBaseType>>;
6
- type UIProplessClassParam = IComponentInstanceClass<IComponentInstance<ComponentInstance<HardEmptyObject, o>>>;
2
+ type UIClassParam = typeof ComponentInstance<object>;
3
+ type UIProplessClassParam = typeof ComponentInstance<HardEmptyObject>;
7
4
  export type UseInstance = {
8
- <Class extends UIProplessClassParam>(Methods: Class & Constructor<InstanceType<Class>>): InstanceType<Class>;
9
- <Class extends UIClassParam>(Methods: Class & Constructor<InstanceType<Class>>, props: InstanceType<Class>['props']): InstanceType<Class>;
5
+ <Class extends UIProplessClassParam>(Methods: Class): InstanceType<Class>;
6
+ <Class extends UIClassParam>(Methods: Class, props: InstanceType<Class>['props']): InstanceType<Class>;
10
7
  };
11
8
  export type UIParams = [
12
- Class: IComponentInstanceClass<IComponentInstance<CIBaseType>>,
9
+ Class: typeof ComponentInstance,
13
10
  props?: object
14
11
  ];
15
- export type UIReturn = CIBaseType;
12
+ export type UIReturn = ComponentInstance;
16
13
  export {};
@@ -1,6 +1,4 @@
1
- import type { TCleanState, TStateData } from '../../base/state';
2
- import type { IComponentLogicClass } from './types/static';
3
- import type { CLBaseType, IComponentLogic } from './types/instance';
1
+ import type { TCleanState } from '../../base/state';
4
2
  import type { UseLogic } from './types/hook';
5
3
  export type HardEmpty = HardEmptyObject;
6
4
  export type WeakEmpty = WeakEmptyObject;
@@ -16,27 +14,35 @@ export type WeakEmpty = WeakEmptyObject;
16
14
  *
17
15
  * Call the {@link useLogic} hook inside your function component to instantiate the class.
18
16
  */
19
- export declare class ComponentLogic<TProps extends object = {}, TState extends TStateData = WeakEmpty> {
20
- readonly state: TCleanState<TState>;
17
+ export declare class ComponentLogic<TProps extends object = {}> {
18
+ /**
19
+ * A {@link TCleanState | `CleanState`} object.
20
+ * Holds all of your component's state,
21
+ * and methods for conveniently manipulating those values.
22
+ */
23
+ readonly state: TCleanState<ReturnType<this['getInitialState']>>;
24
+ /** The props pass into your component at the time of rendering. */
21
25
  readonly props: TProps;
26
+ /**
27
+ * Values received from the hooks your component consumes.
28
+ * This holds the latest copy of the object returned by
29
+ * {@link useHooks}.
30
+ */
22
31
  readonly hooks: ReturnType<this['useHooks']>;
23
32
  /**
24
33
  * Called before each instance of your component is mounted.
25
34
  * It receives the initial `props` object and should return
26
35
  * an object with the initial values for your component's state.
27
36
  */
28
- static getInitialState: (p?: any) => object;
37
+ getInitialState: (props?: TProps) => object;
29
38
  /**
30
- * Call React hooks and expose any values your component
31
- * needs by returning an object with said values. The returned
32
- * object will be accessible as `this.hooks`;
39
+ * Call React hooks from here. If your component needs
40
+ * access to values return from the hooks you call,
41
+ * expose those values by returning an object with said values.
42
+ *
43
+ * The returned object will be accessible as {@link hooks | `this.hooks`} within
44
+ * your component class.
33
45
  */
34
46
  useHooks: () => object | void;
35
47
  }
36
48
  export declare const useLogic: UseLogic;
37
- export declare namespace ComponentLogic {
38
- class Class<TProps extends object = {}, TState extends TStateData = WeakEmpty> extends ComponentLogic<TProps, TState> {
39
- }
40
- type Instance<Instance extends CLBaseType = Class> = IComponentLogic<Instance>;
41
- type ClassType<Instance extends CLBaseType = Class> = IComponentLogicClass<Instance>;
42
- }
@@ -33,20 +33,22 @@ var state_1 = require("../../base/state");
33
33
  */
34
34
  var ComponentLogic = /** @class */ (function () {
35
35
  function ComponentLogic() {
36
- // * PS: `p?: object` wierdly causes TS error in v^5.5.4; object is not assignable to the component's TProps.
37
36
  /**
38
- * Call React hooks and expose any values your component
39
- * needs by returning an object with said values. The returned
40
- * object will be accessible as `this.hooks`;
37
+ * Called before each instance of your component is mounted.
38
+ * It receives the initial `props` object and should return
39
+ * an object with the initial values for your component's state.
40
+ */
41
+ this.getInitialState = function (props) { return ({}); };
42
+ /**
43
+ * Call React hooks from here. If your component needs
44
+ * access to values return from the hooks you call,
45
+ * expose those values by returning an object with said values.
46
+ *
47
+ * The returned object will be accessible as {@link hooks | `this.hooks`} within
48
+ * your component class.
41
49
  */
42
50
  this.useHooks = function () { };
43
51
  }
44
- /**
45
- * Called before each instance of your component is mounted.
46
- * It receives the initial `props` object and should return
47
- * an object with the initial values for your component's state.
48
- */
49
- ComponentLogic.getInitialState = function (p) { return ({}); };
50
52
  return ComponentLogic;
51
53
  }());
52
54
  exports.ComponentLogic = ComponentLogic;
@@ -58,7 +60,6 @@ var useLogic = function () {
58
60
  args[_i] = arguments[_i];
59
61
  }
60
62
  var Logic = args[0], _b = args[1], props = _b === void 0 ? {} : _b;
61
- var state = (0, state_1.useCleanState)(Logic.getInitialState, props);
62
63
  var self = (0, react_1.useRef)((0, react_1.useMemo)(function () {
63
64
  return new Logic();
64
65
  }, [])).current;
@@ -71,23 +72,12 @@ var useLogic = function () {
71
72
  // @ts-expect-error
72
73
  self.props = (_propsProxy_ = props);
73
74
  // @ts-expect-error
74
- self.state = (_stateProxy_ = state);
75
+ self.state = (_stateProxy_ = (0, state_1.useCleanState)(self.getInitialState, props));
75
76
  // @ts-expect-error
76
77
  self.hooks = (_hooksProxy_ = (_a = self.useHooks()) !== null && _a !== void 0 ? _a : {});
77
78
  return self;
78
79
  };
79
80
  exports.useLogic = useLogic;
80
- (function (ComponentLogic) {
81
- var Class = /** @class */ (function (_super) {
82
- __extends(Class, _super);
83
- function Class() {
84
- return _super !== null && _super.apply(this, arguments) || this;
85
- }
86
- return Class;
87
- }(ComponentLogic));
88
- ComponentLogic.Class = Class;
89
- ;
90
- })(ComponentLogic || (exports.ComponentLogic = ComponentLogic = {}));
91
81
  /**/
92
82
  testing: {
93
83
  var a = { b: '' };
@@ -95,26 +85,27 @@ testing: {
95
85
  __extends(MyComponentLogic, _super);
96
86
  function MyComponentLogic() {
97
87
  var _this = _super !== null && _super.apply(this, arguments) || this;
98
- // b = this.state.put[''] + this.props.b;
88
+ _this.getInitialState = function () { return ({ b: 7 }); };
89
+ _this.b = function () { return 8 + _this.state.b; };
99
90
  _this.useHooks = function () { return ({ a: 'undefined' }); };
100
91
  return _this;
101
92
  }
102
- MyComponentLogic.getInitialState = function () { return ({ b: 7 }); };
103
93
  return MyComponentLogic;
104
- }(ComponentLogic.Class));
94
+ }(ComponentLogic));
105
95
  ;
106
- MyComponentLogic.getInitialState;
107
96
  var self_1 = (0, exports.useLogic)(MyComponentLogic);
108
97
  self_1.hooks;
109
98
  self_1.useHooks();
110
99
  var A = /** @class */ (function (_super) {
111
100
  __extends(C, _super);
112
101
  function C() {
113
- return _super !== null && _super.apply(this, arguments) || this;
102
+ var _this = _super !== null && _super.apply(this, arguments) || this;
103
+ _this.getInitialState = function () { return ({ a: 'l' }); };
104
+ _this.a = function () { return _this.state.a = ''; };
105
+ return _this;
114
106
  }
115
107
  return C;
116
- }(ComponentLogic.Class));
117
- A.getInitialState();
108
+ }(ComponentLogic));
118
109
  // const oa = {['a' as unknown as symbol]: 'boo'};
119
110
  var oa = (_a = {}, _a['a'] = 'boo', _a);
120
111
  (0, exports.useLogic)(A, oa);
@@ -1,24 +1,17 @@
1
1
  import type { ComponentLogic } from '..';
2
- import type { CLBaseType, IComponentLogic } from './instance';
3
- import type { IComponentLogicClass } from './static';
4
- /*************************************
5
- * # Utils *
6
- **************************************/
7
- /** */
8
- type o = object;
9
2
  /*************************************
10
3
  * # Hooks *
11
4
  **************************************/
12
5
  /** */
13
- type ULClassParam = IComponentLogicClass<IComponentLogic<CLBaseType>>;
14
- type ULProplessClassParam = IComponentLogicClass<IComponentLogic<ComponentLogic<HardEmptyObject, o>>>;
6
+ type ULClassParam = typeof ComponentLogic<object>;
7
+ type ULProplessClassParam = typeof ComponentLogic<HardEmptyObject>;
15
8
  export type UseLogic = {
16
- <Class extends ULProplessClassParam>(Methods: Class & Constructor<IComponentLogic<InstanceType<Class>>>): InstanceType<Class>;
17
- <Class extends ULClassParam>(Methods: Class & Constructor<IComponentLogic<InstanceType<Class>>>, props: InstanceType<Class>['props']): InstanceType<Class>;
9
+ <Class extends ULProplessClassParam>(Methods: Class): InstanceType<Class>;
10
+ <Class extends ULClassParam>(Methods: Class, props: InstanceType<Class>['props']): InstanceType<Class>;
18
11
  };
19
12
  export type ULParams = [
20
- Class: ComponentLogic.ClassType<ComponentLogic.Instance<CLBaseType>>,
13
+ Class: typeof ComponentLogic,
21
14
  props?: object
22
15
  ];
23
- export type ULReturn = CLBaseType;
16
+ export type ULReturn = ComponentLogic;
24
17
  export {};
@@ -34,11 +34,37 @@ declare global {
34
34
  type AnyFunction = (...args: any) => any;
35
35
  type FunctionType = AnyFunction;
36
36
  type TFunction = AnyFunction;
37
+ /** @deprecated Use {@link NonNullish} */
37
38
  type NotNullish = {};
39
+ type NonNullish = {};
38
40
  type NonPrimitive = object;
41
+ /**
42
+ * Describes an object that has no keys,
43
+ * except for a secret unique symbol key,
44
+ * whose value type is the union `never | undefuned`.
45
+ *
46
+ * Having a single key allows the object to throw type errors
47
+ * of the form:
48
+ * ```
49
+ * Type `A` has no properties in common with `WeakEmptyObject`.
50
+ * ```
51
+ * This may provide a slightly stricter type checking than simply
52
+ * using the non-nullish (`{}`) or non-primitive (`object`)
53
+ * built-in types.
54
+ *
55
+ * Note: `WeakEmptyObject` is not assignable to `HardEmptyObject`
56
+ * because it has a key whose value type includes `undefined`,
57
+ * but `HardEmptyObject` keys can only have a type of `never`.
58
+ */
39
59
  interface WeakEmptyObject {
40
60
  [UniqueSecretSymbolKey]?: never;
41
61
  }
62
+ /**
63
+ * Describes an object that can have any key, but all keys have
64
+ * a type of `never`. This effectively prevents any value
65
+ * from ever being stored on the object. The object is therefore
66
+ * guaranteed to always be empty.
67
+ */
42
68
  interface HardEmptyObject {
43
69
  [key: keyof any]: never;
44
70
  }
@@ -0,0 +1 @@
1
+ export * from './mount-state';
@@ -0,0 +1,17 @@
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("./mount-state"), exports);
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Returns a value that is false before the component has been mounted,
3
+ * then true during all subsequent rerenders.
4
+ */
5
+ export declare const useMountState: () => () => boolean;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useMountState = void 0;
4
+ var react_1 = require("react");
5
+ /**
6
+ * Returns a value that is false before the component has been mounted,
7
+ * then true during all subsequent rerenders.
8
+ */
9
+ var useMountState = function () {
10
+ /**
11
+ * This must not be a state value. It should not be the cause of a rerender.
12
+ * It merely provides information about the render count,
13
+ * without influencing that count itself.
14
+ * So `mounted` should never be set with `useState`.
15
+ */
16
+ var mounted = (0, react_1.useRef)(false);
17
+ (0, react_1.useEffect)(function () {
18
+ mounted.current = true;
19
+ return function () {
20
+ mounted.current = false;
21
+ };
22
+ }, []);
23
+ return function () { return mounted.current; };
24
+ };
25
+ exports.useMountState = useMountState;
package/build/index.d.ts CHANGED
@@ -1 +1,3 @@
1
1
  export * from './classy';
2
+ export * from './base';
3
+ export * from './helpers';
package/build/index.js CHANGED
@@ -15,25 +15,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./classy"), exports);
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,
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.
21
- // useCleanState => useState, separate call for each key
22
- // useMergedState => useState, same call for all keys
23
- // useMethods => useCallback
24
- // useLogic => useCallback + all other hook calls.
25
- // useInstance => useLogic + lifecycle methods.
26
- /*
27
- - Write usage doc
28
- - Push to git and publish to site
29
- - Follow-up personal post on class component inheritance can be published on GH Pages from profile repo.
30
- - Publish to NPM
31
- - Finalize package and repo names, then post to Twitter.
32
- */
18
+ __exportStar(require("./base"), exports);
19
+ __exportStar(require("./helpers"), exports);
33
20
  /*
34
21
  withFetchApi(baseUrl); To mimic axios.get and axios.post type calls.
35
22
  @cleanweb/mem-store - Release global-store package here.
36
- Use mem-store to cache requests in createApi(); Use md5 hashed url as key.
23
+ Use mem-store to cache requests in withFetchApi(); Use md5 hashed url+body as key.
37
24
  @todo Add simple persistence layer with indexed db.
38
25
  @cleanweb/subscribable - To publish changes in the data to subscribers.
39
26
  @cleanweb/reactive-data - To combine all 4.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cleanweb/react",
3
- "version": "2.0.1-beta.0",
3
+ "version": "2.1.0-beta.0",
4
4
  "description": "A suite of helpers for writing cleaner React function components.",
5
5
  "engines": {
6
6
  "node": ">=18"
@@ -16,18 +16,9 @@
16
16
  },
17
17
  "//type": "module",
18
18
  "exports": {
19
- ".": "./build/index.js",
19
+ ".": "./build/classy/index.js",
20
20
  "./base": "./build/base/index.js",
21
- "./classy": "./build/classy/index.js",
22
- "./state": "./build/base/state.js",
23
- "./state/merged": "./build/base/merged-state.js",
24
- "./methods": "./build/base/methods.js",
25
- "./logic": "./build/classy/logic/index.js",
26
- "./logic/*": "./build/classy/logic/*.js",
27
- "./instance": "./build/classy/instance/index.js",
28
- "./instance/*": "./build/classy/instance/*.js",
29
- "./class": "./build/classy/class/index.js",
30
- "./class/*": "./build/classy/class/*.js"
21
+ "./helpers": "./build/helpers/index.js"
31
22
  },
32
23
  "scripts": {
33
24
  "prebuild": "rimraf ./build",
@@ -1,12 +0,0 @@
1
- import type { ExtractCleanStateData } from '../../../../base';
2
- import type { InstanceOverrides as CIInstanceOverrides } from '../../../../classy/instance/types/instance';
3
- import { ClassComponent } from '../../../../classy/class';
4
- export type BaseClassComponent = ClassComponent<object, object>;
5
- export type CCBaseType = ClassComponent<object, object>;
6
- type CCFromSubType<SubType extends CCBaseType> = ClassComponent<SubType['props'], ExtractCleanStateData<SubType['state']>>;
7
- export interface InstanceOverrides<Instance extends CCBaseType = ClassComponent> extends CIInstanceOverrides<Instance> {
8
- }
9
- type BaseInstance<Instance extends CCBaseType = ClassComponent> = Omit<CCFromSubType<Instance>, keyof InstanceOverrides>;
10
- export interface IClassComponent<Instance extends CCBaseType = ClassComponent> extends BaseInstance<Instance>, InstanceOverrides<Instance> {
11
- }
12
- export {};
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,9 +0,0 @@
1
- import type { StaticOverrides as CIStaticOverrides } from '../../../../classy/instance/types/static';
2
- import type { CCBaseType } from './instance';
3
- import { ClassComponent } from '../..';
4
- export interface StaticOverrides<Instance extends CCBaseType = ClassComponent> extends CIStaticOverrides<Instance> {
5
- }
6
- type BaseStatics = Omit<typeof ClassComponent, 'prototype' | keyof StaticOverrides>;
7
- export interface IClassComponentConstructor<Instance extends CCBaseType = ClassComponent> extends BaseStatics, StaticOverrides<Instance> {
8
- }
9
- export {};
@@ -1,12 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- // type ComponentClassOwnStaticKeys = Exclude<
4
- // keyof typeof ClassComponent,
5
- // keyof IComponentInstanceClass
6
- // >;
7
- // type ComponentClassOwnStatics = {
8
- // [Key in ComponentClassOwnStaticKeys]: (typeof ClassComponent)[Key];
9
- // }
10
- // export interface ClassComponentConstructor<
11
- // Instance extends BaseClassComponent = ClassComponent
12
- // > extends Constructor<Instance>, ComponentClassOwnStatics, IComponentInstanceClass<Instance> {};
@@ -1,11 +0,0 @@
1
- import type { InstanceOverrides as CLInstanceOverrides } from '../../../classy/logic/types/instance';
2
- import type { ExtractCleanStateData } from '../../../base';
3
- import { ComponentInstance } from '../../../classy/instance';
4
- export type CIBaseType = Omit<ComponentInstance<object, object>, never>;
5
- type CIFromSubType<SubType extends CIBaseType> = ComponentInstance<SubType['props'], ExtractCleanStateData<SubType['state']>>;
6
- export interface InstanceOverrides<Instance extends CIBaseType = ComponentInstance> extends CLInstanceOverrides<Instance> {
7
- }
8
- type BaseInstance<Instance extends CIBaseType = ComponentInstance> = Omit<CIFromSubType<Instance>, keyof InstanceOverrides>;
9
- export interface IComponentInstance<Instance extends CIBaseType = ComponentInstance> extends BaseInstance<Instance>, InstanceOverrides<Instance> {
10
- }
11
- export {};
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,11 +0,0 @@
1
- import type { StaticOverrides as CLStaticOverrides } from '../../../classy/logic/types/static';
2
- import type { CIBaseType } from './instance';
3
- import { ComponentInstance } from '../../../classy/instance';
4
- /** */
5
- export interface StaticOverrides<Instance extends CIBaseType = ComponentInstance> extends CLStaticOverrides<Instance> {
6
- }
7
- type BaseStatics = Omit<typeof ComponentInstance, 'prototype' | keyof StaticOverrides>;
8
- export interface IComponentInstanceClass<Instance extends CIBaseType = ComponentInstance> extends BaseStatics, StaticOverrides<Instance> {
9
- }
10
- export {};
11
- /** */
@@ -1,17 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- /** */
4
- // type ComponentInstanceOwnStaticKeys = Exclude<
5
- // keyof typeof ComponentInstance,
6
- // keyof ComponentLogic.ClassType
7
- // >;
8
- // type ComponentInstanceOwnStatics = {
9
- // [Key in ComponentInstanceOwnStaticKeys]: (typeof ComponentInstance)[Key];
10
- // }
11
- // export interface IComponentInstanceClass<
12
- // Instance extends ComponentInstance<o, o> = ComponentInstance,
13
- // > extends
14
- // Constructor<IComponentInstance<Instance>>,
15
- // ComponentInstanceOwnStatics,
16
- // ComponentLogic.ClassType<Instance>
17
- // {};
@@ -1,18 +0,0 @@
1
- import type { ExtractCleanStateData } from '../../../base';
2
- import type { ComponentLogic } from '../../../classy/logic';
3
- /*************************************
4
- * # Utils *
5
- **************************************/
6
- /** */
7
- export type CLBaseType = ComponentLogic<object, object>;
8
- type CLFromSubType<SubType extends CLBaseType> = ComponentLogic<SubType['props'], ExtractCleanStateData<SubType['state']>>;
9
- /*************************************
10
- * # Instance Type *
11
- **************************************/
12
- /** */
13
- export interface InstanceOverrides<Instance extends CLBaseType = ComponentLogic> {
14
- }
15
- type BaseInstance<Instance extends CLBaseType = ComponentLogic> = Omit<CLFromSubType<Instance>, keyof InstanceOverrides>;
16
- export interface IComponentLogic<Instance extends CLBaseType = ComponentLogic> extends BaseInstance<Instance>, InstanceOverrides<Instance> {
17
- }
18
- export {};
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,17 +0,0 @@
1
- import type { ExtractCleanStateData } from '../../../base';
2
- import type { ComponentLogic } from '../../../classy/logic';
3
- import type { CLBaseType } from './instance';
4
- /*************************************
5
- * # Utils *
6
- **************************************/
7
- type o = object;
8
- /*************************************
9
- * # Class Static Side *
10
- **************************************/
11
- export interface StaticOverrides<Instance extends CLBaseType = ComponentLogic> extends Constructor<Instance> {
12
- getInitialState: (props?: Instance['props']) => ExtractCleanStateData<Instance['state']>;
13
- }
14
- type BaseStatics = Omit<typeof ComponentLogic, 'prototype' | keyof StaticOverrides>;
15
- export interface IComponentLogicClass<Instance extends ComponentLogic<o, o> = ComponentLogic> extends BaseStatics, StaticOverrides<Instance> {
16
- }
17
- export {};
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });