@lomray/react-mobx-manager 2.0.0-beta.9 → 2.0.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.
- package/README.md +98 -55
- package/lib/context.d.ts +1 -3
- package/lib/context.js +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/manager-stream.d.ts +29 -0
- package/lib/manager-stream.js +1 -0
- package/lib/manager.d.ts +1 -1
- package/lib/manager.js +1 -1
- package/lib/on-change-listener.d.ts +1 -1
- package/lib/plugins/helpers.d.ts +43 -0
- package/lib/plugins/helpers.js +1 -0
- package/lib/plugins/vite/hydration-update-fix.d.ts +7 -0
- package/lib/plugins/vite/hydration-update-fix.js +1 -0
- package/lib/plugins/vite/id-generator.d.ts +15 -0
- package/lib/plugins/vite/id-generator.js +1 -0
- package/lib/plugins/vite/index.d.ts +7 -0
- package/lib/plugins/vite/index.js +1 -0
- package/lib/storages/async-storage.d.ts +1 -1
- package/lib/storages/local-storage.d.ts +1 -1
- package/lib/suspense-query.d.ts +28 -6
- package/lib/suspense-query.js +1 -1
- package/lib/{types-0ce7ddf0.d.ts → types-a8f9023c.d.ts} +3 -3
- package/lib/wakeup.d.ts +1 -1
- package/lib/with-stores.d.ts +1 -1
- package/logo.png +0 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
<h1 align='center'>Mobx stores manager for React</h1>
|
|
2
|
+
|
|
1
3
|
<p align="center">
|
|
2
|
-
<img src="
|
|
4
|
+
<img src="./logo.png" alt="Mobx stores manager logo" width="250" height="253">
|
|
3
5
|
</p>
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
### Key features:
|
|
6
8
|
|
|
7
9
|
- One way to escape state tree 🌲🌳🌴.
|
|
10
|
+
- Ready to use with Suspense.
|
|
11
|
+
- Support SSR.
|
|
12
|
+
- Support render to stream.
|
|
8
13
|
- Manage your Mobx stores like a boss - debug like a hacker.
|
|
9
14
|
- Simple idea - simple implementation.
|
|
10
15
|
- Small package size.
|
|
11
|
-
- Support render to stream.
|
|
12
16
|
- Support code splitting out of the box.
|
|
13
17
|
- Access stores from other stores.
|
|
14
18
|
- Can be a replacement for react context.
|
|
@@ -37,9 +41,10 @@
|
|
|
37
41
|
- [Manager](#manager)
|
|
38
42
|
- [withStores](#withstores)
|
|
39
43
|
- [StoreManagerProvider](#storemanagerprovider)
|
|
40
|
-
- [useStoreManagerContext](#
|
|
41
|
-
- [useStoreManagerParentContext](#
|
|
44
|
+
- [useStoreManagerContext](#usestoremanager)
|
|
45
|
+
- [useStoreManagerParentContext](#usestoremanagerparent)
|
|
42
46
|
- [Store](#store)
|
|
47
|
+
- [Example](#demo)
|
|
43
48
|
- [React Native Debug Plugin](#react-native-debug-plugin)
|
|
44
49
|
- [Bugs and feature requests](#bugs-and-feature-requests)
|
|
45
50
|
- [License](#license)
|
|
@@ -49,26 +54,68 @@
|
|
|
49
54
|
The React-mobx-manager package is distributed using [npm](https://www.npmjs.com/), the node package manager.
|
|
50
55
|
|
|
51
56
|
```
|
|
52
|
-
npm i --save @lomray/react-mobx-manager
|
|
57
|
+
npm i --save @lomray/react-mobx-manager @lomray/consistent-suspense
|
|
53
58
|
```
|
|
54
59
|
|
|
55
|
-
|
|
60
|
+
__NOTE:__ this package use [@lomray/consistent-suspense](https://github.com/Lomray-Software/consistent-suspense) for generate stable id's inside Suspense.
|
|
56
61
|
|
|
62
|
+
__Choose one of store id generating strategy__:
|
|
63
|
+
|
|
64
|
+
1. Configure your bundler to keep classnames and function names. Store id will be generated from class names (chose unique class names).
|
|
57
65
|
- **React:** (craco or webpack config, terser options)
|
|
58
66
|
```bash
|
|
59
67
|
terserOptions.keep_classnames = true;
|
|
60
68
|
terserOptions.keep_fnames = true;
|
|
61
69
|
```
|
|
62
70
|
|
|
63
|
-
- **React Native:** (metro bundler config)
|
|
71
|
+
- **React Native:** (metro bundler config: metro.config.js)
|
|
72
|
+
```js
|
|
73
|
+
module.exports = {
|
|
74
|
+
transformer: {
|
|
75
|
+
minifierConfig: {
|
|
76
|
+
keep_classnames: true,
|
|
77
|
+
keep_fnames: true,
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
}
|
|
64
81
|
```
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
82
|
+
2. Define `id` for each store.
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { makeObservable } from "mobx";
|
|
86
|
+
|
|
87
|
+
class MyStore {
|
|
88
|
+
/**
|
|
89
|
+
* Define unique store id
|
|
90
|
+
*/
|
|
91
|
+
static id = 'Unique-store-id';
|
|
92
|
+
|
|
93
|
+
constructor() {
|
|
94
|
+
makeObservable(this, {})
|
|
95
|
+
}
|
|
70
96
|
}
|
|
71
97
|
```
|
|
98
|
+
3. Use `Vite plugins`.
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { defineConfig } from 'vite';
|
|
102
|
+
import react from '@vitejs/plugin-react';
|
|
103
|
+
import MobxManager from '@lomray/react-mobx-manager/plugins/vite/index';
|
|
104
|
+
|
|
105
|
+
// https://vitejs.dev/config/
|
|
106
|
+
export default defineConfig({
|
|
107
|
+
/**
|
|
108
|
+
* Store id's will be generated automatically, just chill
|
|
109
|
+
*/
|
|
110
|
+
plugins: [react(), MobxManager()]
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Detect mobx store:
|
|
115
|
+
- by makeObservable or makeAutoObservable
|
|
116
|
+
- by @mobx-store jsdoc before class
|
|
117
|
+
*/
|
|
118
|
+
```
|
|
72
119
|
|
|
73
120
|
## Usage
|
|
74
121
|
|
|
@@ -77,24 +124,27 @@ Import `Manager, StoreManagerProvider` from `@lomray/react-mobx-manager` into yo
|
|
|
77
124
|
```typescript jsx
|
|
78
125
|
import React from 'react';
|
|
79
126
|
import ReactDOM from 'react-dom/client';
|
|
80
|
-
import '
|
|
127
|
+
import { ConsistentSuspenseProvider } from '@lomray/consistent-suspense';
|
|
81
128
|
import { Manager, StoreManagerProvider, MobxLocalStorage } from '@lomray/react-mobx-manager';
|
|
82
129
|
import App from './app';
|
|
83
130
|
import MyApiClient from './services/my-api-client';
|
|
131
|
+
import './index.css';
|
|
84
132
|
|
|
85
133
|
const apiClient = new MyApiClient();
|
|
86
134
|
const storeManager = new Manager({
|
|
87
135
|
storage: new MobxLocalStorage(), // optional: needs for persisting stores
|
|
88
|
-
storesParams: { apiClient }, // optional: we can provide our api client for access from the store
|
|
136
|
+
storesParams: { apiClient }, // optional: we can provide our api client for access from the each store
|
|
89
137
|
});
|
|
90
138
|
|
|
91
139
|
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
|
|
92
140
|
|
|
93
141
|
root.render(
|
|
94
142
|
<React.StrictMode>
|
|
95
|
-
<
|
|
96
|
-
<
|
|
97
|
-
|
|
143
|
+
<ConsistentSuspenseProvider> {/** required **/}
|
|
144
|
+
<StoreManagerProvider storeManager={storeManager} shouldInit>
|
|
145
|
+
<App />
|
|
146
|
+
</StoreManagerProvider>
|
|
147
|
+
</ConsistentSuspenseProvider>
|
|
98
148
|
</React.StrictMode>,
|
|
99
149
|
);
|
|
100
150
|
```
|
|
@@ -126,10 +176,10 @@ class UserStore {
|
|
|
126
176
|
static id = 'user';
|
|
127
177
|
|
|
128
178
|
/**
|
|
129
|
-
* You can also enable
|
|
179
|
+
* You can also enable behavior for global application stores
|
|
130
180
|
* Default: false
|
|
131
181
|
*/
|
|
132
|
-
static
|
|
182
|
+
static isGlobal = true;
|
|
133
183
|
|
|
134
184
|
/**
|
|
135
185
|
* Our state
|
|
@@ -198,16 +248,17 @@ const User: FC<TProps> = ({ userStore: { name } }) => {
|
|
|
198
248
|
export default withStores(User, stores);
|
|
199
249
|
```
|
|
200
250
|
|
|
201
|
-
[See app example](
|
|
251
|
+
[See app example](https://github.com/Lomray-Software/vite-template) for a better understanding.
|
|
202
252
|
|
|
203
253
|
## Support SSR
|
|
204
254
|
Does this library support SSR? Short answer - yes, but we need some steps to prepare our framework.
|
|
255
|
+
- Look at [Vite demo app](https://github.com/Lomray-Software/vite-template) for a better understanding.
|
|
205
256
|
- Look at [After.js (razzle) based project](https://github.com/Lomray-Software/microservices-dashboard/blob/staging/src/pages/user/index.tsx#L82) for a better understanding.
|
|
206
257
|
- Look at [NextJS example](https://github.com/Lomray-Software/nextjs-mobx-store-manager-example) for a better understanding (needs writing a wrapper).
|
|
207
258
|
|
|
208
259
|
## Important Tips
|
|
209
|
-
- Create **
|
|
210
|
-
- To get started, stick to the concept: Store for Component. Don't connect (through withStores) not
|
|
260
|
+
- Create **global** store only for e.g: application settings, logged user, theme, etc.
|
|
261
|
+
- To get started, stick to the concept: Store for Component. Don't connect (through withStores) not global store to several components.
|
|
211
262
|
|
|
212
263
|
## Documentation
|
|
213
264
|
|
|
@@ -253,10 +304,13 @@ const storeManager = new Manager({
|
|
|
253
304
|
*/
|
|
254
305
|
shouldRemoveInitState: true,
|
|
255
306
|
/**
|
|
256
|
-
*
|
|
257
|
-
* Default: false
|
|
307
|
+
* Configure store destroy timers
|
|
258
308
|
*/
|
|
259
|
-
|
|
309
|
+
destroyTimers: {
|
|
310
|
+
init: 500,
|
|
311
|
+
touched: 10000, // NOTE: set to max request timeout
|
|
312
|
+
unused: 1000,
|
|
313
|
+
},
|
|
260
314
|
}
|
|
261
315
|
});
|
|
262
316
|
|
|
@@ -277,7 +331,7 @@ const managerStores = storeManager.getStores();
|
|
|
277
331
|
/**
|
|
278
332
|
* Get specific store
|
|
279
333
|
*/
|
|
280
|
-
const store = storeManager.getStore(
|
|
334
|
+
const store = storeManager.getStore(SomeGlobalStore);
|
|
281
335
|
const store2 = storeManager.getStore(SomeStore, { contextId: 'necessary-context-id' });
|
|
282
336
|
|
|
283
337
|
/**
|
|
@@ -285,16 +339,11 @@ const store2 = storeManager.getStore(SomeStore, { contextId: 'necessary-context-
|
|
|
285
339
|
*/
|
|
286
340
|
const relations = storeManager.getStoresRelations();
|
|
287
341
|
|
|
288
|
-
/**
|
|
289
|
-
* Generate unique context id
|
|
290
|
-
*/
|
|
291
|
-
const contextId = storeManager.createContextId();
|
|
292
|
-
|
|
293
342
|
/**
|
|
294
343
|
* Manually create stores for component
|
|
295
344
|
* NOTE: 'withStores' wrapper use this method, probably you won't need it
|
|
296
345
|
*/
|
|
297
|
-
const stores = storeManager.createStores(['someStore', MyStore], 'parent-id', 'context-id', 'HomePage');
|
|
346
|
+
const stores = storeManager.createStores(['someStore', MyStore], 'parent-id', 'context-id', 'suspense-id', 'HomePage', { componentProp: 'test' });
|
|
298
347
|
|
|
299
348
|
/**
|
|
300
349
|
* Mount/Unmount simple stores to component
|
|
@@ -338,10 +387,10 @@ const storeClass = Manager.persistStore(class MyStore {}, 'my-store');
|
|
|
338
387
|
import { withStores } from '@lomray/react-mobx-manager';
|
|
339
388
|
|
|
340
389
|
/**
|
|
341
|
-
* Create and connect 'stores' to component
|
|
390
|
+
* Create and connect 'stores' to component with custom context id
|
|
342
391
|
* NOTE: In most cases, you don't need to pass a third argument (contextId).
|
|
343
392
|
*/
|
|
344
|
-
withStores(Component, stores, 'optional-context-id');
|
|
393
|
+
withStores(Component, stores, { customContextId: 'optional-context-id' });
|
|
345
394
|
|
|
346
395
|
const stores = { myStore: MyStore, anotherStore: AnotherStore };
|
|
347
396
|
```
|
|
@@ -361,27 +410,27 @@ import { StoreManagerProvider } from '@lomray/react-mobx-manager';
|
|
|
361
410
|
</StoreManagerProvider>
|
|
362
411
|
```
|
|
363
412
|
|
|
364
|
-
###
|
|
413
|
+
### useStoreManager
|
|
365
414
|
```typescript jsx
|
|
366
|
-
import {
|
|
415
|
+
import { useStoreManager } from '@lomray/react-mobx-manager';
|
|
367
416
|
|
|
368
417
|
const MyComponent: FC = () => {
|
|
369
418
|
/**
|
|
370
419
|
* Get store manager inside your function component
|
|
371
420
|
*/
|
|
372
|
-
const storeManager =
|
|
421
|
+
const storeManager = useStoreManager();
|
|
373
422
|
}
|
|
374
423
|
```
|
|
375
424
|
|
|
376
|
-
###
|
|
425
|
+
### useStoreManagerParent
|
|
377
426
|
```typescript jsx
|
|
378
|
-
import {
|
|
427
|
+
import { useStoreManagerParent } from '@lomray/react-mobx-manager';
|
|
379
428
|
|
|
380
429
|
const MyComponent: FC = () => {
|
|
381
430
|
/**
|
|
382
431
|
* Get parent context id
|
|
383
432
|
*/
|
|
384
|
-
const { parentId } =
|
|
433
|
+
const { parentId } = useStoreManagerParent();
|
|
385
434
|
}
|
|
386
435
|
```
|
|
387
436
|
|
|
@@ -398,10 +447,10 @@ class MyStore {
|
|
|
398
447
|
static id = 'user';
|
|
399
448
|
|
|
400
449
|
/**
|
|
401
|
-
* You can also enable
|
|
450
|
+
* You can also enable behavior for global application stores
|
|
402
451
|
* Default: false
|
|
403
452
|
*/
|
|
404
|
-
static
|
|
453
|
+
static isGlobal = true;
|
|
405
454
|
|
|
406
455
|
/**
|
|
407
456
|
* Store observable state
|
|
@@ -414,12 +463,12 @@ class MyStore {
|
|
|
414
463
|
/**
|
|
415
464
|
* @private
|
|
416
465
|
*/
|
|
417
|
-
private someParentStore: ClassReturnType<typeof SomeParentStore>;
|
|
466
|
+
private readonly someParentStore: ClassReturnType<typeof SomeParentStore>;
|
|
418
467
|
|
|
419
468
|
/**
|
|
420
469
|
* @constructor
|
|
421
470
|
*
|
|
422
|
-
* getStore - get parent store or
|
|
471
|
+
* getStore - get parent store or global store
|
|
423
472
|
* storeManager - access to store manager
|
|
424
473
|
* apiClient - your custom param, see 'storesParams' in Manager
|
|
425
474
|
*/
|
|
@@ -427,7 +476,7 @@ class MyStore {
|
|
|
427
476
|
this.apiClient = apiClient;
|
|
428
477
|
this.someParentStore = getStore(SomeParentStore);
|
|
429
478
|
|
|
430
|
-
// In case when store is't
|
|
479
|
+
// In case when store is't global you can get access to component props
|
|
431
480
|
console.log(componentProps);
|
|
432
481
|
|
|
433
482
|
makeObservable(this, {
|
|
@@ -445,14 +494,6 @@ class MyStore {
|
|
|
445
494
|
// do something
|
|
446
495
|
}
|
|
447
496
|
|
|
448
|
-
/**
|
|
449
|
-
* Define this method if you want to do something when a component with this store is mount
|
|
450
|
-
* @private
|
|
451
|
-
*/
|
|
452
|
-
private onMount(): void {
|
|
453
|
-
// do something
|
|
454
|
-
}
|
|
455
|
-
|
|
456
497
|
/**
|
|
457
498
|
* Define this method if you want to do something when a component with this store is unmount
|
|
458
499
|
* @private
|
|
@@ -476,9 +517,11 @@ Lifecycles:
|
|
|
476
517
|
- constructor
|
|
477
518
|
- wakeup (restore state from persisted store)
|
|
478
519
|
- init
|
|
479
|
-
- onMount
|
|
480
520
|
- onDestroy
|
|
481
521
|
|
|
522
|
+
## Demo
|
|
523
|
+
Explore [demo app](https://github.com/Lomray-Software/vite-template) to more understand.
|
|
524
|
+
|
|
482
525
|
## React Native debug plugin
|
|
483
526
|
For debug state, you can use [Reactotron debug plugin](https://github.com/Lomray-Software/reactotron-mobx-store-manager)
|
|
484
527
|
|
package/lib/context.d.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import { IConsistentSuspense } from '@lomray/consistent-suspense';
|
|
3
2
|
import React from 'react';
|
|
4
3
|
import { FC, ReactElement } from "react";
|
|
5
4
|
import Manager from "./manager.js";
|
|
6
|
-
import { TStores } from "./types-
|
|
5
|
+
import { TStores } from "./types-a8f9023c.js";
|
|
7
6
|
interface IStoreManagerProvider {
|
|
8
7
|
storeManager: Manager;
|
|
9
8
|
shouldInit?: boolean;
|
|
10
9
|
fallback?: ReactElement;
|
|
11
10
|
children?: React.ReactNode;
|
|
12
|
-
suspenseProvider?: Partial<IConsistentSuspense>;
|
|
13
11
|
}
|
|
14
12
|
interface IStoreManagerParentProvider {
|
|
15
13
|
parentId: string;
|
package/lib/context.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react");function t(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=t(e);const a=r.default.createContext({}),o=r.default.createContext("root"),n=({parentId:e,children:t,initStores:a})=>{const n=s();return a&&n.touchedStores(a),r.default.createElement(o.Provider,{value:e,children:t})},s=()=>e.useContext(a);exports.StoreManagerContext=a,exports.StoreManagerParentContext=o,exports.StoreManagerParentProvider=n,exports.StoreManagerProvider=({children:t,storeManager:o,fallback:s,shouldInit:u=!1})=>{const[l,c]=e.useState(!u);return e.useEffect((()=>{u&&o.init().then((()=>c(!0))).catch((e=>{console.error("Failed initialized store manager: ",e)}))}),[u,o]),r.default.createElement(a.Provider,{value:o},r.default.createElement(n,{parentId:"root"},l?t:s||t))},exports.useStoreManager=s,exports.useStoreManagerParent=()=>e.useContext(o);
|
package/lib/index.d.ts
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import Manager from "./manager.js";
|
|
2
|
+
/**
|
|
3
|
+
* Stream mobx manager stores
|
|
4
|
+
*/
|
|
5
|
+
declare class ManagerStream {
|
|
6
|
+
/**
|
|
7
|
+
* Already pushed preamble
|
|
8
|
+
*/
|
|
9
|
+
protected isPreamblePushed: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Mobx store manager
|
|
12
|
+
*/
|
|
13
|
+
protected manager: Manager;
|
|
14
|
+
/**
|
|
15
|
+
* @constructor
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* @constructor
|
|
19
|
+
*/
|
|
20
|
+
constructor(manager: Manager);
|
|
21
|
+
/**
|
|
22
|
+
* Return script with suspense stores to push on stream
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Return script with suspense stores to push on stream
|
|
26
|
+
*/
|
|
27
|
+
take(suspenseId: string): string | void;
|
|
28
|
+
}
|
|
29
|
+
export { ManagerStream as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";module.exports=class{constructor(e){Object.defineProperty(this,"isPreamblePushed",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"manager",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.manager=e}take(e){const s=this.manager.getSuspenseRelations().get(e);if(!(null==s?void 0:s.size))return;const i=JSON.stringify(this.manager.toJSON([...s])),t=this.isPreamblePushed?"":"<script>!window.mbxM && (window.mbxM = []);<\/script>";return this.isPreamblePushed||(this.isPreamblePushed=!0),`${t}<script>window.mbxM.push(${i});<\/script>`}};
|
package/lib/manager.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import StoreStatus from "./store-status.js";
|
|
2
|
-
import { IConstructableStore, IManagerOptions, IManagerParams, IStorage, IStore, IStoreParams, TInitStore, TStoreDefinition, TStores } from "./types-
|
|
2
|
+
import { IConstructableStore, IManagerOptions, IManagerParams, IStorage, IStore, IStoreParams, TInitStore, TStoreDefinition, TStores } from "./types-a8f9023c.js";
|
|
3
3
|
/**
|
|
4
4
|
* Mobx stores manager
|
|
5
5
|
*/
|
package/lib/manager.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("@lomray/event-manager"),t=require("mobx"),s=require("./events.js"),
|
|
1
|
+
"use strict";var e=require("@lomray/event-manager"),t=require("mobx"),s=require("./events.js"),r=require("./on-change-listener.js"),o=require("./store-status.js"),i=require("./wakeup.js");function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var a=n(e);class l{constructor({initState:e,storesParams:t,storage:s,options:r}={}){if(Object.defineProperty(this,"stores",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"storesRelations",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"initState",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"storage",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"persistData",{enumerable:!0,configurable:!0,writable:!0,value:{}}),Object.defineProperty(this,"storesParams",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"options",{enumerable:!0,configurable:!0,writable:!0,value:{shouldDisablePersist:!1,shouldRemoveInitState:!0}}),Object.defineProperty(this,"suspenseRelations",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"pushInitState",{enumerable:!0,configurable:!0,writable:!0,value:(e={})=>{for(const[t,s]of Object.entries(e))this.initState[t]=s}}),this.initState=e||{},this.storesParams=t||{},this.storage=s,Object.assign(this.options,r||{}),l.instance=this,"undefined"!=typeof window){const e=window.mbxM;window.mbxM={push:this.pushInitState},(Array.isArray(e)?e:[]).forEach(this.pushInitState)}}async init(){return this.storage&&(this.persistData=await this.storage.get()||{}),this}static get(){if(!l.instance)throw new Error("Store manager is not initialized.");return l.instance}getStores(){return this.stores}getStoresRelations(){return this.storesRelations}getSuspenseRelations(){return this.suspenseRelations}static getPersistedStoresIds(){return l.persistedStores}getStoreId(e,t={}){const{id:s,contextId:r,key:o}=t;if(s)return s;if(e.libStoreId)return e.libStoreId;let i=e.id||e.name||e.constructor.name;return e.isGlobal?i:(i=`${i}--${r}`,o?`${i}--${o}`:i)}getStore(e,t={}){const s=this.getStoreId(e,t);return this.stores.has(s)?this.stores.get(s):e.isGlobal?this.createStore(e,{id:s,contextId:"global",parentId:"root",suspenseId:"",componentName:"root-app",componentProps:{}}):this.lookupStore(s,t)}lookupStore(e,t){var s,r;const{contextId:o,parentId:i}=t,n=null===(s=e.split("--"))||void 0===s?void 0:s[0],{ids:a,parentId:l}=null!==(r=this.storesRelations.get(o))&&void 0!==r?r:{ids:new Set,parentId:i},u=[...a].filter((e=>e.startsWith(`${n}--`)));if(1===u.length)return this.stores.get(u[0]);if(u.length>1)console.error("Parent context has multiple stores with the same id, please pass key to getStore function.");else if(l&&"root"!==l)return this.lookupStore(e,{contextId:l})}createStore(e,t){const{id:r,contextId:i,parentId:n,suspenseId:l,componentName:u,componentProps:d}=t;if(this.stores.has(r))return this.stores.get(r);const h=new e({...this.storesParams,storeManager:this,getStore:(e,t={contextId:i,parentId:n})=>this.getStore(e,t),componentProps:d});return h.libStoreId=r,h.isGlobal=e.isGlobal,h.libStoreContextId=e.isGlobal?"global":i,h.libStoreParentId=e.isGlobal||!n||n===i?"root":n,h.libStoreSuspenseId=l,h.libStoreComponentName=u,this.setStoreStatus(h,e.isGlobal?o.inUse:o.init),this.prepareStore(h),a.default.publish(s.CREATE_STORE,{store:e}),h}createStores(e,t,s,r,o,i={}){return e.reduce(((e,[n,a])=>{const[l,u]="store"in a?[a.store,a.id]:[a,this.getStoreId(a,{key:n,contextId:s})];return{...e,[n]:this.createStore(l,{id:u,contextId:s,parentId:t,suspenseId:r,componentName:o,componentProps:i})}}),{})}prepareStore(e){var t,r,o;const i=e.libStoreId,n=e.libStoreContextId,u=e.libStoreSuspenseId,d=this.initState[i],h=this.persistData[i];if(this.stores.has(i))return;if(d&&Object.assign(e,d),"wakeup"in e&&l.persistedStores.has(i)&&(null===(t=e.wakeup)||void 0===t||t.call(e,{initState:d,persistedState:h})),l.persistedStores.has(i)&&"addOnChangeListener"in e){const t=null===(r=e.onDestroy)||void 0===r?void 0:r.bind(e),s=e.addOnChangeListener(e,this);e.onDestroy=()=>{null==s||s(),null==t||t()}}null===(o=e.init)||void 0===o||o.call(e),this.storesRelations.has(n)||this.storesRelations.set(n,{ids:new Set,parentId:e.libStoreParentId&&e.libStoreParentId!==n?e.libStoreParentId:"root",componentName:e.libStoreComponentName}),this.suspenseRelations.has(u)||this.suspenseRelations.set(u,new Set);const{ids:c}=this.storesRelations.get(n);this.stores.set(i,e),c.add(i),this.suspenseRelations.get(u).add(i),a.default.publish(s.ADD_STORE,{store:e})}removeStore(e){var t,r,o;const i=e.libStoreId,n=e.libStoreSuspenseId,{ids:l}=null!==(t=this.storesRelations.get(e.libStoreContextId))&&void 0!==t?t:{ids:new Set};this.stores.has(i)&&(this.stores.delete(i),l.delete(i),n&&(null===(r=this.suspenseRelations.get(n))||void 0===r?void 0:r.has(i))&&this.suspenseRelations.get(n).delete(i),l.size||this.storesRelations.delete(e.libStoreContextId),"onDestroy"in e&&(null===(o=e.onDestroy)||void 0===o||o.call(e)),a.default.publish(s.DELETE_STORE,{store:e}))}mountStores(e){const{shouldRemoveInitState:t}=this.options;return Object.values(e).forEach((e=>{const r=e.libStoreId;t&&this.initState[r]&&delete this.initState[r],this.setStoreStatus(e,o.inUse),a.default.publish(s.MOUNT_STORE,{store:e})})),()=>{Object.values(e).forEach((e=>{e.isGlobal||(this.setStoreStatus(e,o.unused),a.default.publish(s.UNMOUNT_STORE,{store:e}))}))}}touchedStores(e){Object.values(e).forEach((e=>{e.libStoreStatus!==o.init||e.isGlobal||this.setStoreStatus(e,o.touched)}))}setStoreStatus(e,t){const{destroyTimers:{init:s=500,touched:r=1e4,unused:i=1e3}={}}=this.options;e.libStoreStatus=t,clearTimeout(e.libDestroyTimer);let n=0;switch(t){case o.init:n=s;break;case o.touched:n=r;break;case o.unused:n=i}n&&(e.libDestroyTimer=setTimeout((()=>this.removeStore(e)),n))}toJSON(e){var t,s,r;const o={},i=null!==(t=null==e?void 0:e.reduce(((e,t)=>(this.stores.has(t)&&e.set(t,this.stores.get(t)),e)),new Map))&&void 0!==t?t:this.stores;for(const[e,t]of i.entries())o[e]=null!==(r=null===(s=t.toJSON)||void 0===s?void 0:s.call(t))&&void 0!==r?r:l.getObservableProps(t);return o}toPersistedJSON(){var e,t;const s={};for(const r of l.persistedStores){const o=this.stores.get(r);o&&(s[r]=null!==(t=null===(e=o.toJSON)||void 0===e?void 0:e.call(o))&&void 0!==t?t:l.getObservableProps(o))}return s}static getObservableProps(e){const s=t.toJS(e);return Object.entries(s).reduce(((s,[r,o])=>({...s,...t.isObservableProp(e,r)?{[r]:o}:{}})),{})}static persistStore(e,t){return l.persistedStores.has(t)?(console.warn(`Duplicate serializable store key: ${t}`),e):(l.persistedStores.add(t),e.libStoreId=t,"wakeup"in e.prototype||(e.prototype.wakeup=i.bind(e)),"addOnChangeListener"in e.prototype||(e.prototype.addOnChangeListener=r),e)}}Object.defineProperty(l,"persistedStores",{enumerable:!0,configurable:!0,writable:!0,value:new Set}),module.exports=l;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
type ICache = Map<string, {
|
|
2
|
+
storeId: string;
|
|
3
|
+
classname: string;
|
|
4
|
+
}>;
|
|
5
|
+
/**
|
|
6
|
+
* Load cached store id's by file name
|
|
7
|
+
*/
|
|
8
|
+
declare const loadCache: (isProd?: boolean) => ICache;
|
|
9
|
+
/**
|
|
10
|
+
* Save store id's cache
|
|
11
|
+
*/
|
|
12
|
+
declare const saveCache: (cache: ICache) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Get next letter
|
|
15
|
+
*/
|
|
16
|
+
declare const getNextLetter: (str?: string) => string;
|
|
17
|
+
/**
|
|
18
|
+
* Store is generator
|
|
19
|
+
*/
|
|
20
|
+
declare class Generator {
|
|
21
|
+
cache: ICache;
|
|
22
|
+
protected root: string;
|
|
23
|
+
protected lastId: string;
|
|
24
|
+
// keep last generated production store id (letter)
|
|
25
|
+
constructor(root: string, isProd?: boolean);
|
|
26
|
+
/**
|
|
27
|
+
* Inject store id
|
|
28
|
+
*/
|
|
29
|
+
injectId: (code: string, fileId: string) => string;
|
|
30
|
+
/**
|
|
31
|
+
* Get development id
|
|
32
|
+
*/
|
|
33
|
+
getDevId: (id: string, classname: string) => string;
|
|
34
|
+
/**
|
|
35
|
+
* Get production store id
|
|
36
|
+
*/
|
|
37
|
+
getProdId: () => string;
|
|
38
|
+
/**
|
|
39
|
+
* Try to find mobx store
|
|
40
|
+
*/
|
|
41
|
+
matchMobxStore: (code: string) => string | undefined;
|
|
42
|
+
}
|
|
43
|
+
export { saveCache, loadCache, getNextLetter, Generator };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}Object.defineProperty(exports,"__esModule",{value:!0});var t=e(require("node:fs"));const r=`${__dirname.split("node_modules")[0]}node_modules/.cache/@lomray/react-mobx-manager`,s=`${r}/store-ids.json`,a=(e=!1)=>{if(e&&t.default.existsSync(s)){const e=JSON.parse(t.default.readFileSync(s,{encoding:"utf-8"}));return new Map(e)}return new Map},i=(e="")=>{var t;const r=e.split(""),s=null!==(t=r.pop())&&void 0!==t?t:"`";if("z"===s)return[...r,"A"].join("");if("Z"===s){const e=r.pop();return e?[i([...r,e].join("")),"a"].join(""):"aa"}return[...r,String.fromCharCode(s.charCodeAt(0)+1)].join("")};exports.Generator=class{constructor(e,t=!1){Object.defineProperty(this,"cache",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"root",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"lastId",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"injectId",{enumerable:!0,configurable:!0,writable:!0,value:(e,t)=>{const{classname:r,storeId:s}=this.cache.get(t),a=new RegExp(`(class\\s${r}\\s+?{)`);return e.replace(a,`$1static id = '${s}';`)}}),Object.defineProperty(this,"getDevId",{enumerable:!0,configurable:!0,writable:!0,value:(e,t)=>`${e.replace(this.root,"").replace(/\/index.(js|ts|tsx)/,"").split("/").filter(Boolean).join("-")}-${t}`}),Object.defineProperty(this,"getProdId",{enumerable:!0,configurable:!0,writable:!0,value:()=>{const e=i(this.lastId),t=`S${e}`;return this.lastId=e,t}}),Object.defineProperty(this,"matchMobxStore",{enumerable:!0,configurable:!0,writable:!0,value:e=>{var t,r,s,a;const{classname:i}=null!==(r=null===(t=e.match(/class\s(?<classname>\w+)\s+?{(?!.*static\sid\s*=.*).+(makeObservable|makeAutoObservable)(?!.*persistStore\(\1.*)/s))||void 0===t?void 0:t.groups)&&void 0!==r?r:{};if(i)return i;const{classname:o}=null!==(a=null===(s=e.match(/(@mobx-store).+class\s(?<classname>\w+)\s+?{(?!.*static\sid\s*=.*).+}(?!.*persistStore.*)/s))||void 0===s?void 0:s.groups)&&void 0!==a?a:{};return o}}),this.root=e,this.cache=a(t)}},exports.getNextLetter=i,exports.loadCache=a,exports.saveCache=e=>{t.default.existsSync(r)||t.default.mkdirSync(r,{recursive:!0}),t.default.writeFileSync(s,JSON.stringify([...e.entries()],null,2),{encoding:"utf-8"})};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("node:path");module.exports=function(){return{name:"@lomray/react-mobx-manager-hydration-fix",transform(r,t){const n=e.extname(t).split("?")[0];if([".js",".ts",".tsx"].includes(n)&&r.includes("function useObserver"))return{code:r.replace(/(}\);[^f]+)(forceUpdate\(\);)/s,"$1/*$2*/"),map:{mappings:""}}}}};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
interface IPluginOptions {
|
|
3
|
+
root?: string;
|
|
4
|
+
isProd?: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Generate unique store id's
|
|
8
|
+
*
|
|
9
|
+
* Detect mobx store:
|
|
10
|
+
* - by makeObservable or makeAutoObservable
|
|
11
|
+
* - by @mobx-store jsdoc before class
|
|
12
|
+
* @constructor
|
|
13
|
+
*/
|
|
14
|
+
declare function IdGenerator({ root, isProd }?: IPluginOptions): Plugin;
|
|
15
|
+
export { IdGenerator as default, IPluginOptions };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("node:path"),r=require("node:process"),t=require("../helpers.js");module.exports=function({root:s=r.cwd(),isProd:a=!1}={}){const n=new t.Generator(s,a);return{name:"@lomray/react-mobx-manager-id-generator",transform(r,t){const s=e.extname(t).split("?")[0];if(t.includes("node_modules")||![".js",".ts",".tsx"].includes(s)||!/(makeObservable|makeAutoObservable)\(/.test(r))return;if(n.cache.has(t))return{code:n.injectId(r,t),map:{mappings:""}};const o=n.matchMobxStore(r);if(o){if(!n.cache.has(t)){const e=a?n.getProdId():n.getDevId(t,o);n.cache.set(t,{classname:o,storeId:e})}return{code:n.injectId(r,t),map:{mappings:""}}}},buildEnd(){a&&t.saveCache(n.cache)}}};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("node:process"),r=require("./hydration-update-fix.js"),t=require("./id-generator.js");function n(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach((function(t){if("default"!==t){var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,n.get?n:{enumerable:!0,get:function(){return e[t]}})}})),r.default=e,Object.freeze(r)}var o=n(e);const i=e=>"production"===e||"production"===o.env.NODE_ENV;module.exports=function(){let e;return[{...r(),apply:()=>!i()},{name:t().name,configResolved({root:r}){e=t({root:r,isProd:i()})},transform(...r){var t;return null===(t=e.transform)||void 0===t?void 0:t.call(this,...r)},buildEnd(...r){var t;null===(t=e.buildEnd)||void 0===t||t.call(this,...r)}}]};
|
package/lib/suspense-query.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TInitStore } from "./types-
|
|
1
|
+
import { TInitStore } from "./types-a8f9023c.js";
|
|
2
2
|
interface IPromise<TReturn> extends Promise<TReturn> {
|
|
3
3
|
status?: 'fulfilled' | 'pending' | 'rejected';
|
|
4
4
|
value?: TReturn;
|
|
@@ -6,6 +6,7 @@ interface IPromise<TReturn> extends Promise<TReturn> {
|
|
|
6
6
|
}
|
|
7
7
|
interface ISuspenseQueryParams {
|
|
8
8
|
fieldName?: string;
|
|
9
|
+
errorFields?: string[];
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
11
12
|
* Run request and cache promise
|
|
@@ -16,10 +17,6 @@ declare class SuspenseQuery {
|
|
|
16
17
|
* @private
|
|
17
18
|
*/
|
|
18
19
|
protected promise: Promise<any> | undefined;
|
|
19
|
-
/**
|
|
20
|
-
* @private
|
|
21
|
-
*/
|
|
22
|
-
protected error?: Error;
|
|
23
20
|
/**
|
|
24
21
|
* Target store
|
|
25
22
|
* @private
|
|
@@ -35,7 +32,32 @@ declare class SuspenseQuery {
|
|
|
35
32
|
/**
|
|
36
33
|
* @constructor
|
|
37
34
|
*/
|
|
38
|
-
constructor(store: TInitStore, { fieldName,
|
|
35
|
+
constructor(store: TInitStore, { fieldName, errorFields }?: ISuspenseQueryParams);
|
|
36
|
+
/**
|
|
37
|
+
* Error to json
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Error to json
|
|
41
|
+
*/
|
|
42
|
+
protected errorJson(e: any): void;
|
|
43
|
+
/**
|
|
44
|
+
* Assign custom error fields to error
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* Assign custom error fields to error
|
|
48
|
+
*/
|
|
49
|
+
protected jsonToError(e: Error, values: Record<string, any>): Error;
|
|
50
|
+
/**
|
|
51
|
+
* Detect if suspense is restored from server side:
|
|
52
|
+
* - throw error if exist
|
|
53
|
+
* - skip run suspense if already completed
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* Detect if suspense is restored from server side:
|
|
57
|
+
* - throw error if exist
|
|
58
|
+
* - skip run suspense if already completed
|
|
59
|
+
*/
|
|
60
|
+
protected isComplete(): boolean;
|
|
39
61
|
/**
|
|
40
62
|
* Run request
|
|
41
63
|
* Save request resolve status
|
package/lib/suspense-query.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("mobx");class r{constructor(t,{fieldName:i="
|
|
1
|
+
"use strict";var e=require("mobx");class r{constructor(t,{fieldName:i="sR",errorFields:s=["name","message"]}={}){var o;Object.defineProperty(this,"promise",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"store",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"params",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"query",{enumerable:!0,configurable:!0,writable:!0,value:t=>{const{fieldName:i}=this.params;if(!this.isComplete())return this.promise||(this.promise=t(),this.promise.then((()=>{e.runInAction((()=>{this.store[i]=!0}))}),(r=>{e.runInAction((()=>{this.errorJson(r),this.store[i]=r}))}))),r.run(this.promise)}}),this.store=t,this.params={fieldName:i,errorFields:s};const a=null===(o=t.init)||void 0===o?void 0:o.bind(t);t.init=()=>{this.isComplete(),null==a||a()},e.extendObservable(t,{[i]:!1},{[i]:e.observable})}errorJson(e){e.toJSON=()=>this.params.errorFields.reduce(((r,t)=>({...r,[t]:null==e?void 0:e[t]})),{})}jsonToError(e,r){return this.params.errorFields.forEach((t=>{e[t]=null==r?void 0:r[t]})),e}isComplete(){var e;const r=this.store[this.params.fieldName];if("boolean"!==typeof r)throw this.jsonToError(new Error(null!==(e=null==r?void 0:r.message)&&void 0!==e?e:null==r?void 0:r.name),r);return!0===r}}Object.defineProperty(r,"run",{enumerable:!0,configurable:!0,writable:!0,value:e=>{if(e){switch(e.status){case"fulfilled":return e.value;case"pending":throw e;case"rejected":throw e.reason;default:e.status="pending",e.then((r=>{e.status="fulfilled",e.value=r}),(r=>{e.status="rejected",e.reason=r}))}throw e}}}),module.exports=r;
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import Manager from "./manager.js";
|
|
3
3
|
import StoreStatus from "./store-status.js";
|
|
4
4
|
interface IWindowManager {
|
|
5
|
-
|
|
5
|
+
push: (state: Record<string, any>) => void;
|
|
6
6
|
}
|
|
7
7
|
declare global {
|
|
8
8
|
interface Window {
|
|
9
|
-
|
|
9
|
+
mbxM: Record<string, any>[] | IWindowManager;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
interface IConstructorParams<TProps = Record<string, any>> {
|
|
@@ -25,7 +25,7 @@ interface IStore extends IStoreLifecycle {
|
|
|
25
25
|
libStoreComponentName?: string;
|
|
26
26
|
libStoreStatus?: StoreStatus;
|
|
27
27
|
libDestroyTimer?: NodeJS.Timeout;
|
|
28
|
-
|
|
28
|
+
isGlobal?: boolean;
|
|
29
29
|
init?: () => void;
|
|
30
30
|
toJSON?: () => Record<string, any>;
|
|
31
31
|
}
|
package/lib/wakeup.d.ts
CHANGED
package/lib/with-stores.d.ts
CHANGED
package/logo.png
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lomray/react-mobx-manager",
|
|
3
|
-
"version": "2.0.0
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "This package provides Mobx stores manager for react.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"prepare": "husky install"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@lomray/consistent-suspense": "^1.
|
|
54
|
+
"@lomray/consistent-suspense": "^1.3.0",
|
|
55
55
|
"@lomray/event-manager": "^1.2.2"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
@@ -73,7 +73,8 @@
|
|
|
73
73
|
"rollup-plugin-ts": "^3.2.0",
|
|
74
74
|
"semantic-release": "^21.0.2",
|
|
75
75
|
"ttypescript": "^1.5.15",
|
|
76
|
-
"typescript": "^4.7.4"
|
|
76
|
+
"typescript": "^4.7.4",
|
|
77
|
+
"vite": "^4.4.4"
|
|
77
78
|
},
|
|
78
79
|
"peerDependencies": {
|
|
79
80
|
"hoist-non-react-statics": "^3.3.2",
|