@carbonorm/carbonreact 4.0.11 → 4.0.13

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@carbonorm/carbonreact",
3
3
  "license": "MIT",
4
- "version": "4.0.11",
4
+ "version": "4.0.13",
5
5
  "browser": "dist/index.umd.js",
6
6
  "module": "dist/index.esm.js",
7
7
  "main": "dist/index.cjs.js",
@@ -1,16 +1,16 @@
1
- import {clearCache} from "@carbonorm/carbonnode";
1
+ import { clearCache } from "@carbonorm/carbonnode";
2
2
  import changed from "hoc/changed";
3
- import {GlobalHistory} from "hoc/GlobalHistory";
3
+ import { GlobalHistory } from "hoc/GlobalHistory";
4
4
  import hexToRgb from "hoc/hexToRgb";
5
- import {Component, Context, createContext, ReactElement, ReactNode} from 'react';
6
- import {ToastContainer} from 'react-toastify';
5
+ import { Component, Context, createContext, ReactElement, ReactNode } from 'react';
6
+ import { ToastContainer } from 'react-toastify';
7
7
  import 'react-toastify/dist/ReactToastify.min.css';
8
8
  import BackendThrowable from 'components/Errors/BackendThrowable';
9
9
  import Nest from 'components/Nest/Nest';
10
- import {initialRestfulObjectsState, iRestfulObjectArrayTypes} from "variables/C6";
11
- import CarbonWebSocket, {iCarbonWebSocketProps} from "./components/WebSocket/CarbonWebSocket";
12
- import updateRestfulObjectArrays, {iUpdateRestfulObjectArrays} from "./hoc/updateRestfulObjectArrays";
13
- import deleteRestfulObjectArrays, {iDeleteRestfulObjectArrays} from "./hoc/deleteRestfulObjectArrays";
10
+ import { initialRestfulObjectsState, iRestfulObjectArrayTypes } from "variables/C6";
11
+ import CarbonWebSocket, { iCarbonWebSocketProps } from "./components/WebSocket/CarbonWebSocket";
12
+ import updateRestfulObjectArrays, { iUpdateRestfulObjectArrays } from "./hoc/updateRestfulObjectArrays";
13
+ import deleteRestfulObjectArrays, { iDeleteRestfulObjectArrays } from "./hoc/deleteRestfulObjectArrays";
14
14
 
15
15
 
16
16
  export type tStatefulApiData<T extends {
@@ -46,40 +46,32 @@ export function isJsonString(str: string) {
46
46
  return false;
47
47
  }
48
48
  return true;
49
-
50
49
  }
51
50
 
52
- export interface iCarbonReactProps<P = {}, S extends iCarbonReactState = iCarbonReactState> {
51
+ abstract class CarbonReact<P = {}, S extends iCarbonReactState = iCarbonReactState> extends Component<{
53
52
  children?: ReactNode | ReactNode[],
54
53
  instanceId?: string,
55
54
  websocket?: Omit<iCarbonWebSocketProps<P, S>, "instance"> | false
56
- }
57
-
58
- abstract class CarbonReact<P = {}, S extends iCarbonReactState = iCarbonReactState> extends Component<iCarbonReactProps<P, S> & P, S> {
55
+ } & P, S> {
59
56
 
60
57
  private static persistentStateMap = new Map<string, { [key: string]: any; }>();
58
+ private static activeInstances = new Map<string, CarbonReact<any, any>>();
61
59
 
62
- // Context is for functional components to access the state of this class efficiently
63
60
  context: Context<S & iCarbonReactState> = createContext(this.state);
64
-
65
61
  protected target: typeof CarbonReact;
66
62
 
67
- // @link https://stackoverflow.com/questions/55029032/what-is-typescripts-thistype-used-for
68
63
  protected static _instance: ThisType<CarbonReact<any, any>>;
69
64
 
70
65
  static getInstance<T extends CarbonReact<any, any>>(): T {
71
66
  return this._instance as T;
72
67
  }
73
-
74
68
  static get instance() {
75
69
  return this.getInstance();
76
70
  }
77
-
78
71
  static set instance(instance: CarbonReact<any, any>) {
79
72
  this._instance = instance;
80
73
  }
81
74
 
82
- // these are public but the class is abstract
83
75
  public updateRestfulObjectArrays = <ObjectType extends { [key: string]: any; } = {}>
84
76
  (rest: Omit<iUpdateRestfulObjectArrays<ObjectType, S, P>, "instance">) => updateRestfulObjectArrays<ObjectType, S, P>({
85
77
  instance: this,
@@ -94,76 +86,57 @@ abstract class CarbonReact<P = {}, S extends iCarbonReactState = iCarbonReactSta
94
86
 
95
87
  static lastLocation = window.location.pathname;
96
88
 
97
- // @link https://github.com/welldone-software/why-did-you-render
98
- // noinspection JSUnusedGlobalSymbols
99
89
  static whyDidYouRender = true;
100
90
 
101
-
102
- protected constructor(props) {
103
-
91
+ protected constructor(props: {
92
+ children?: ReactNode | ReactNode[];
93
+ shouldStatePersist?: boolean | undefined;
94
+ websocket?: boolean | iCarbonWebSocketProps<P, S> | undefined;
95
+ instanceId?: string; // Optional instanceId from props
96
+ } & P) {
104
97
  super(props);
105
98
 
106
- if (!props.instanceId && (new.target as typeof CarbonReact)._instance) {
107
-
108
- // todo - instanceId being unique should solve this, but.... how
109
- // This is a singleton pattern, we can only have one instance of this class
110
- throw new Error(`${new.target.name} instance already exists! CarbonReact extended classes can only be referenced once in DOM`);
99
+ const target = new.target as typeof CarbonReact;
100
+ const identifier = props.instanceId || target.name;
111
101
 
102
+ if (CarbonReact.activeInstances.has(identifier)) {
103
+ throw new Error(`Instance with ID ${identifier} already exists! CarbonReact extended classes can only be referenced once in DOM with the same identifier.`);
112
104
  }
113
105
 
114
- (new.target as typeof CarbonReact).instance = (this);
115
-
116
- this.target = new.target;
106
+ CarbonReact.activeInstances.set(identifier, this);
117
107
 
108
+ this.target = target;
118
109
  console.log('CarbonORM TSX CONSTRUCTOR');
119
110
 
120
- // this is the magic that allows each class that's extends this to have a static instance - a singleton pattern
121
- // new.target is a meta-property introduced in ES6 that references the constructor that was directly invoked with the new keyword.
122
- Object.assign(new.target, {
111
+ Object.assign(target, {
123
112
  _instance: this
124
- })
125
-
126
- if (this.props.instanceId && CarbonReact.persistentStateMap.has(this.props.instanceId)) {
127
-
128
- this.state = CarbonReact.persistentStateMap.get(this.props.instanceId) as S & iCarbonReactState;
113
+ });
129
114
 
115
+ if (CarbonReact.persistentStateMap.has(identifier)) {
116
+ this.state = CarbonReact.persistentStateMap.get(identifier) as S & iCarbonReactState;
130
117
  } else {
131
-
132
- // This should only ever be done here, when the full state is being trashed.
133
- // todo - does this suck in context of multiple instances?
134
118
  clearCache({
135
119
  ignoreWarning: true
136
120
  });
137
-
138
121
  this.state = initialCarbonReactState as unknown as S & iCarbonReactState;
139
-
140
122
  }
141
123
 
142
- /** We can think of our app as having one state; this state.
143
- * Long-term, I'd like us to store this state to local storage and only load updates on reload...
144
- * Class based components are far easier to manage state in local storage and pass state down to children.
145
- * Children, if not faced with a local storage or other complexity should be a functional component. Functional
146
- * components' tend to be shorter syntactically and bonus points if it's stateless.
147
- **/
148
-
124
+ // Save the initial state to the persistent state map with the identifier
125
+ CarbonReact.persistentStateMap.set(identifier, this.state);
149
126
  }
150
127
 
151
-
152
128
  shouldComponentUpdate(
153
129
  nextProps: Readonly<P>,
154
130
  nextState: Readonly<S>,
155
131
  _nextContext: any): boolean {
156
132
 
157
- if (this.props.instanceId) {
158
- CarbonReact.persistentStateMap.set(this.props.instanceId, nextState);
159
- }
133
+ const identifier = this.props.instanceId || (this.constructor as typeof CarbonReact).name;
134
+ CarbonReact.persistentStateMap.set(identifier, nextState);
160
135
 
161
136
  changed(this.constructor.name + ' (C6Api)', 'props', this.props, nextProps);
162
-
163
137
  changed(this.constructor.name + ' (C6Api)', 'state', this.state, nextState);
164
138
 
165
- return true
166
-
139
+ return true;
167
140
  }
168
141
 
169
142
  componentDidUpdate(_prevProps: Readonly<P>, _prevState: Readonly<S>, _snapshot?: any) {
@@ -178,39 +151,39 @@ abstract class CarbonReact<P = {}, S extends iCarbonReactState = iCarbonReactSta
178
151
  }
179
152
 
180
153
  render(): ReactElement {
181
-
182
154
  console.log('CarbonORM TSX RENDER');
183
155
 
184
156
  const colorHex = '#' + Math.random().toString(16).slice(-6);
185
157
 
186
158
  console.log('%c color (' + colorHex + ')', 'color: ' + colorHex);
187
159
 
188
- const nest = <Nest position={'fixed'} backgroundColor={''} color={hexToRgb(colorHex)} count={100}/>;
160
+ const nest = <Nest position={'fixed'} backgroundColor={''} color={hexToRgb(colorHex)} count={100} />;
189
161
 
190
162
  if (this.state.backendThrowable.length > 0) {
191
-
192
163
  return <>
193
164
  {nest}
194
- <BackendThrowable instance={this}/>
165
+ <BackendThrowable instance={this} />
195
166
  </>;
196
-
197
167
  }
198
168
 
199
169
  const Context = this.context.Provider;
200
170
 
201
171
  return <>
202
- <GlobalHistory/>
172
+ <GlobalHistory />
203
173
  {this.props.websocket &&
204
174
  <CarbonWebSocket<P, S> {...(false !== this.props.websocket ? this.props.websocket : {})}
205
- instance={this}/>}
175
+ instance={this} />}
206
176
  <Context value={this.state}>
207
177
  {this.props.children}
208
178
  </Context>
209
- <ToastContainer/>
179
+ <ToastContainer />
210
180
  </>;
211
-
212
181
  }
213
182
 
183
+ componentWillUnmount() {
184
+ const identifier = this.props.instanceId || (this.constructor as typeof CarbonReact).name;
185
+ CarbonReact.activeInstances.delete(identifier);
186
+ }
214
187
  }
215
188
 
216
189
  export default CarbonReact;