@blac/react 0.0.1 → 0.0.3

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.
@@ -1,7 +1,7 @@
1
- import { Blac, BlocBase, BlocClass } from 'blac';
2
- import React from 'react';
1
+ import { Blac, BlocBase, ValueType, BlocClass } from 'blac';
2
+ import React, { FC, ReactNode } from 'react';
3
3
 
4
- declare const BlacContext: React.Context<Blac | null>;
4
+ declare const BlacContext: React.Context<Blac<any, any> | null>;
5
5
 
6
6
  /**
7
7
  * Keep track of the hierarchy of Blac BlocProvider components, so that
@@ -14,16 +14,29 @@ interface ProviderItem {
14
14
  bloc: BlocBase<any>;
15
15
  }
16
16
 
17
- interface ExternalStore<S> {
17
+ declare const BlocProvider: FC<{
18
+ children?: ReactNode;
19
+ bloc: (() => BlocBase<any>) | BlocBase<any>;
20
+ debug?: boolean;
21
+ }>;
22
+
23
+ interface ExternalStore<B extends BlocBase<any>> {
18
24
  subscribe: (onStoreChange: () => void) => () => void;
19
- getSnapshot: () => S;
20
- getServerSnapshot?: () => S;
25
+ getSnapshot: () => ValueType<B>;
26
+ getServerSnapshot?: () => ValueType<B>;
21
27
  }
22
28
 
23
- type BlocHookData<T extends BlocBase<S>, S> = [value: S, instance: T];
24
- type BlocHookOptions<T extends BlocBase<S>, S> = {
29
+ type BlocHookData<B extends BlocBase<S>, S> = [
30
+ value: ValueType<B>,
31
+ instance: B
32
+ ];
33
+ interface BlocHookOptions {
34
+ /**
35
+ * Set to true if you want blac to automatically create a new instance of the bloc,
36
+ * for this to work, pass the unconstructed class to the hook. The constructor should not expect any arguments.
37
+ */
25
38
  create?: boolean;
26
- };
27
- declare const useBloc: <B extends BlocBase<S>, S>(bloc: BlocClass<B> | (() => B), options?: BlocHookOptions<B, S>) => BlocHookData<B, S>;
39
+ }
40
+ declare const useBloc: <B extends BlocBase<S>, S>(bloc: BlocClass<B> | (() => B), options?: BlocHookOptions) => BlocHookData<B, S>;
28
41
 
29
- export { BlacContext, BlocHookData, BlocHookOptions, ExternalStore, ProviderItem, useBloc };
42
+ export { BlacContext, BlocHookData, BlocHookOptions, BlocProvider, ExternalStore, ProviderItem, useBloc };
@@ -1,4 +1,4 @@
1
- import React, { useContext, createContext, useMemo, useSyncExternalStore } from 'react';
1
+ import React, { useContext, useMemo, useEffect, createContext, useSyncExternalStore } from 'react';
2
2
 
3
3
  /**
4
4
  * Keep track of the hierarchy of Blac BlocProvider components, so that
@@ -37,6 +37,9 @@ class BlacReact {
37
37
  // add the BlacReact instance to blac
38
38
  this.blac.addPluginKey(BlacReact.pluginKey, this);
39
39
  }
40
+ /**
41
+ * React hook to get the bloc instance from the nearest BlocProvider
42
+ */
40
43
  useLocalBlocContext() {
41
44
  return useContext(this.localContextProvider);
42
45
  }
@@ -44,6 +47,9 @@ class BlacReact {
44
47
  get LocalProvider() {
45
48
  return this._contextLocalProviderKey.Provider;
46
49
  }
50
+ /**
51
+ * React hook to get the id from the nearest BlocProvider
52
+ */
47
53
  useLocalProviderKey() {
48
54
  return useContext(this._contextLocalProviderKey);
49
55
  }
@@ -82,11 +88,61 @@ class BlacReact {
82
88
  }
83
89
  return undefined;
84
90
  }
91
+ providerMounted(options) {
92
+ const { bloc, providerId, localProviderKey } = options;
93
+ let instance = undefined;
94
+ let destroyOnUnmount = true;
95
+ const isFunction = bloc instanceof Function;
96
+ const isLiveBloc = !isFunction &&
97
+ typeof bloc === 'object' &&
98
+ bloc?.isBlacLive;
99
+ if (isFunction) {
100
+ instance = bloc();
101
+ }
102
+ if (isLiveBloc) {
103
+ instance = bloc;
104
+ }
105
+ if (instance) {
106
+ this.addLocalBloc({
107
+ bloc: instance,
108
+ id: providerId,
109
+ parent: localProviderKey,
110
+ });
111
+ }
112
+ return { instance, destroyOnUnmount };
113
+ }
114
+ providerUnmounted(providerId) {
115
+ this.removeLocalBloc;
116
+ }
117
+ useLocalProvider = (options) => {
118
+ const [blocInstance, setBlocInstance] = React.useState(undefined);
119
+ const localProviderKey = this.useLocalProviderKey();
120
+ const providerId = useMemo(() => this.createProviderId(), []);
121
+ useEffect(() => {
122
+ const { instance, destroyOnUnmount } = this.providerMounted({
123
+ ...options,
124
+ localProviderKey,
125
+ providerId,
126
+ });
127
+ setBlocInstance(instance);
128
+ if (destroyOnUnmount)
129
+ return this.providerUnmounted(providerId);
130
+ }, []);
131
+ if (blocInstance)
132
+ return providerId;
133
+ };
85
134
  }
86
135
 
87
136
  const BlacContext = createContext(null);
88
137
 
89
- createContext(null);
138
+ const BlocProvider = ({ children, bloc, debug }) => {
139
+ const blacReact = BlacReact.getInstance();
140
+ const providerId = blacReact.useLocalProvider({ bloc, debug });
141
+ if (!providerId) {
142
+ return null;
143
+ }
144
+ return (React.createElement(blacReact.LocalProvider, { value: providerId }, children));
145
+ };
90
146
 
91
147
  const externalBlocStore = (bloc) => {
92
148
  return {
@@ -94,17 +150,14 @@ const externalBlocStore = (bloc) => {
94
150
  const unSub = bloc.onStateChange(listener);
95
151
  return () => {
96
152
  unSub();
97
- bloc.dispose();
98
153
  };
99
154
  },
100
155
  getSnapshot: () => bloc.state,
101
156
  };
102
157
  };
103
158
 
104
- // B extends BlocBase<S>,
105
159
  const useBloc = (bloc, options = {}) => {
106
160
  const blacReact = BlacReact.getInstance();
107
- // const localCtxP = blacReact.useLocalBlocContext();
108
161
  const localProviderKey = blacReact.useLocalProviderKey();
109
162
  const blacInstance = useContext(BlacContext);
110
163
  const resolvedBloc = useMemo(() => {
@@ -148,5 +201,5 @@ const useBloc = (bloc, options = {}) => {
148
201
  return [state, resolvedBloc];
149
202
  };
150
203
 
151
- export { BlacContext, useBloc };
204
+ export { BlacContext, BlocProvider, useBloc };
152
205
  //# sourceMappingURL=blac-react.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"blac-react.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"blac-react.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -39,6 +39,9 @@ class BlacReact {
39
39
  // add the BlacReact instance to blac
40
40
  this.blac.addPluginKey(BlacReact.pluginKey, this);
41
41
  }
42
+ /**
43
+ * React hook to get the bloc instance from the nearest BlocProvider
44
+ */
42
45
  useLocalBlocContext() {
43
46
  return React.useContext(this.localContextProvider);
44
47
  }
@@ -46,6 +49,9 @@ class BlacReact {
46
49
  get LocalProvider() {
47
50
  return this._contextLocalProviderKey.Provider;
48
51
  }
52
+ /**
53
+ * React hook to get the id from the nearest BlocProvider
54
+ */
49
55
  useLocalProviderKey() {
50
56
  return React.useContext(this._contextLocalProviderKey);
51
57
  }
@@ -84,11 +90,61 @@ class BlacReact {
84
90
  }
85
91
  return undefined;
86
92
  }
93
+ providerMounted(options) {
94
+ const { bloc, providerId, localProviderKey } = options;
95
+ let instance = undefined;
96
+ let destroyOnUnmount = true;
97
+ const isFunction = bloc instanceof Function;
98
+ const isLiveBloc = !isFunction &&
99
+ typeof bloc === 'object' &&
100
+ bloc?.isBlacLive;
101
+ if (isFunction) {
102
+ instance = bloc();
103
+ }
104
+ if (isLiveBloc) {
105
+ instance = bloc;
106
+ }
107
+ if (instance) {
108
+ this.addLocalBloc({
109
+ bloc: instance,
110
+ id: providerId,
111
+ parent: localProviderKey,
112
+ });
113
+ }
114
+ return { instance, destroyOnUnmount };
115
+ }
116
+ providerUnmounted(providerId) {
117
+ this.removeLocalBloc;
118
+ }
119
+ useLocalProvider = (options) => {
120
+ const [blocInstance, setBlocInstance] = React.useState(undefined);
121
+ const localProviderKey = this.useLocalProviderKey();
122
+ const providerId = React.useMemo(() => this.createProviderId(), []);
123
+ React.useEffect(() => {
124
+ const { instance, destroyOnUnmount } = this.providerMounted({
125
+ ...options,
126
+ localProviderKey,
127
+ providerId,
128
+ });
129
+ setBlocInstance(instance);
130
+ if (destroyOnUnmount)
131
+ return this.providerUnmounted(providerId);
132
+ }, []);
133
+ if (blocInstance)
134
+ return providerId;
135
+ };
87
136
  }
88
137
 
89
138
  const BlacContext = React.createContext(null);
90
139
 
91
- React.createContext(null);
140
+ const BlocProvider = ({ children, bloc, debug }) => {
141
+ const blacReact = BlacReact.getInstance();
142
+ const providerId = blacReact.useLocalProvider({ bloc, debug });
143
+ if (!providerId) {
144
+ return null;
145
+ }
146
+ return (React.createElement(blacReact.LocalProvider, { value: providerId }, children));
147
+ };
92
148
 
93
149
  const externalBlocStore = (bloc) => {
94
150
  return {
@@ -96,17 +152,14 @@ const externalBlocStore = (bloc) => {
96
152
  const unSub = bloc.onStateChange(listener);
97
153
  return () => {
98
154
  unSub();
99
- bloc.dispose();
100
155
  };
101
156
  },
102
157
  getSnapshot: () => bloc.state,
103
158
  };
104
159
  };
105
160
 
106
- // B extends BlocBase<S>,
107
161
  const useBloc = (bloc, options = {}) => {
108
162
  const blacReact = BlacReact.getInstance();
109
- // const localCtxP = blacReact.useLocalBlocContext();
110
163
  const localProviderKey = blacReact.useLocalProviderKey();
111
164
  const blacInstance = React.useContext(BlacContext);
112
165
  const resolvedBloc = React.useMemo(() => {
@@ -151,5 +204,6 @@ const useBloc = (bloc, options = {}) => {
151
204
  };
152
205
 
153
206
  exports.BlacContext = BlacContext;
207
+ exports.BlocProvider = BlocProvider;
154
208
  exports.useBloc = useBloc;
155
209
  //# sourceMappingURL=blac-react.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"blac-react.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"blac-react.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blac/react",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "license": "MIT",
5
5
  "main": "dist/blac-react.js",
6
6
  "module": "dist/blac-react.esm.js",
@@ -18,6 +18,7 @@
18
18
  ],
19
19
  "scripts": {
20
20
  "dev": "vite",
21
+ "build:demo": "vite build",
21
22
  "build": "rollup -c rollup.config.lib.js",
22
23
  "prettier": "prettier --write ./src",
23
24
  "test": "vitest run",
@@ -28,9 +29,9 @@
28
29
  "blac": "*"
29
30
  },
30
31
  "devDependencies": {
31
- "@vitejs/plugin-react": "^3.1.0",
32
32
  "@types/react": "^18.0.28",
33
33
  "@types/react-dom": "^18.0.11",
34
+ "@vitejs/plugin-react": "^3.1.0",
34
35
  "react": "^18.2.0",
35
36
  "react-dom": "^18.2.0",
36
37
  "vite": "^4.1.4",
package/readme.md ADDED
@@ -0,0 +1,16 @@
1
+ # Blac for React
2
+
3
+ Demo [https://blac-react-demo.vercel.app/](https://blac-react-demo.vercel.app/)
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install blac-react
9
+ ```
10
+
11
+ ## Examples
12
+
13
+ - [Counter with Bloc](ui/examples/CounterWithBloc.tsx)
14
+ - [Counter with Cubit](ui/examples/CounterWithCubit.tsx)
15
+ - [Counter with Global State](ui/examples/CounterWithCubitGlobal.tsx)
16
+ - [Counters with Local State](ui/examples/CounterScoped.tsx)