@blac/react 2.0.5 → 2.0.6
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 +34 -141
- package/dist/index.cjs +25 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +24 -16
- package/dist/index.js.map +1 -1
- package/package.json +11 -5
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> ⚠️ **Warning:** This project is currently under active development. The API may change in future releases. Use with caution in production environments.
|
|
4
4
|
|
|
5
|
-
React integration for
|
|
5
|
+
React integration for BlaC with automatic re-render optimization.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -42,9 +42,7 @@ function Counter() {
|
|
|
42
42
|
}
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
##
|
|
46
|
-
|
|
47
|
-
### useBloc
|
|
45
|
+
## useBloc
|
|
48
46
|
|
|
49
47
|
Connects a component to a state container with automatic re-renders on state changes.
|
|
50
48
|
|
|
@@ -54,29 +52,26 @@ const [state, bloc, ref] = useBloc(MyBloc);
|
|
|
54
52
|
|
|
55
53
|
**Returns:** `[state, bloc, ref]`
|
|
56
54
|
|
|
57
|
-
- `state` - Current state
|
|
58
|
-
- `bloc` -
|
|
59
|
-
- `ref` -
|
|
55
|
+
- `state` - Current state snapshot
|
|
56
|
+
- `bloc` - Bloc instance (proxied for tracking; call methods on it)
|
|
57
|
+
- `ref` - Internal component ref (advanced usage)
|
|
60
58
|
|
|
61
|
-
|
|
59
|
+
### Tracking Modes
|
|
62
60
|
|
|
63
|
-
**Auto-tracking (default):**
|
|
61
|
+
**Auto-tracking (default):** Tracks accessed properties and getters.
|
|
64
62
|
|
|
65
63
|
```tsx
|
|
66
64
|
function UserProfile() {
|
|
67
|
-
const [state
|
|
68
|
-
|
|
69
|
-
// Only re-renders when state.name changes
|
|
70
|
-
// (state.email changes won't cause re-render)
|
|
65
|
+
const [state] = useBloc(UserBloc);
|
|
71
66
|
return <h1>{state.name}</h1>;
|
|
72
67
|
}
|
|
73
68
|
```
|
|
74
69
|
|
|
75
|
-
**Manual dependencies:**
|
|
70
|
+
**Manual dependencies:** Provide a dependency selector (disables auto-tracking).
|
|
76
71
|
|
|
77
72
|
```tsx
|
|
78
73
|
function Counter() {
|
|
79
|
-
const [state] = useBloc(
|
|
74
|
+
const [state] = useBloc(CounterCubit, {
|
|
80
75
|
dependencies: (state) => [state.count],
|
|
81
76
|
});
|
|
82
77
|
|
|
@@ -84,187 +79,85 @@ function Counter() {
|
|
|
84
79
|
}
|
|
85
80
|
```
|
|
86
81
|
|
|
87
|
-
**No tracking:**
|
|
82
|
+
**No tracking:** Re-render on any state change.
|
|
88
83
|
|
|
89
84
|
```tsx
|
|
90
85
|
function FullState() {
|
|
91
86
|
const [state] = useBloc(MyBloc, { autoTrack: false });
|
|
92
|
-
|
|
93
87
|
return <pre>{JSON.stringify(state)}</pre>;
|
|
94
88
|
}
|
|
95
89
|
```
|
|
96
90
|
|
|
97
|
-
|
|
91
|
+
### Options
|
|
98
92
|
|
|
99
93
|
```tsx
|
|
100
94
|
useBloc(MyBloc, {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
// Instance management
|
|
106
|
-
instanceId: 'unique-id', // Custom instance identifier
|
|
107
|
-
|
|
108
|
-
// Lifecycle callbacks
|
|
95
|
+
autoTrack: true,
|
|
96
|
+
dependencies: (state, bloc) => [state.count, bloc],
|
|
97
|
+
instanceId: 'editor-1',
|
|
109
98
|
onMount: (bloc) => console.log('Mounted', bloc),
|
|
110
99
|
onUnmount: (bloc) => console.log('Unmounted', bloc),
|
|
111
100
|
});
|
|
112
101
|
```
|
|
113
102
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
**Use cases:**
|
|
123
|
-
|
|
124
|
-
```tsx
|
|
125
|
-
// Stateless services (analytics, navigation, etc.)
|
|
126
|
-
function TrackButton() {
|
|
127
|
-
const analytics = useBlocActions(AnalyticsService);
|
|
128
|
-
|
|
129
|
-
return (
|
|
130
|
-
<button onClick={() => analytics.trackClick('button')}>Click me</button>
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Actions-only (no state subscription)
|
|
135
|
-
function IncrementButton() {
|
|
136
|
-
const counter = useBlocActions(CounterCubit);
|
|
137
|
-
|
|
138
|
-
return <button onClick={counter.increment}>+</button>;
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
#### Options
|
|
143
|
-
|
|
144
|
-
```tsx
|
|
145
|
-
useBlocActions(MyBloc, {
|
|
146
|
-
instanceId: 'unique-id', // Custom instance identifier
|
|
147
|
-
onMount: (bloc) => bloc.initialize(),
|
|
148
|
-
onUnmount: (bloc) => bloc.cleanup(),
|
|
149
|
-
});
|
|
150
|
-
```
|
|
103
|
+
| Option | Type | Description |
|
|
104
|
+
| -------------- | ---------------------------- | ------------------------------------ |
|
|
105
|
+
| `autoTrack` | `boolean` | Enable auto-tracking (default: true) |
|
|
106
|
+
| `dependencies` | `(state, bloc) => unknown[]` | Manual dependency selector |
|
|
107
|
+
| `instanceId` | `string \| number` | Custom instance identifier |
|
|
108
|
+
| `onMount` | `(bloc) => void` | Called when component mounts |
|
|
109
|
+
| `onUnmount` | `(bloc) => void` | Called when component unmounts |
|
|
151
110
|
|
|
152
111
|
## Instance Management
|
|
153
112
|
|
|
154
113
|
### Shared Instances (Default)
|
|
155
114
|
|
|
156
|
-
By default, all components using the same bloc class share one instance:
|
|
157
|
-
|
|
158
115
|
```tsx
|
|
159
|
-
function
|
|
160
|
-
|
|
161
|
-
// Uses shared instance
|
|
116
|
+
function A() {
|
|
117
|
+
useBloc(CounterCubit); // shared instance
|
|
162
118
|
}
|
|
163
119
|
|
|
164
|
-
function
|
|
165
|
-
|
|
166
|
-
// Uses same shared instance
|
|
120
|
+
function B() {
|
|
121
|
+
useBloc(CounterCubit); // same shared instance
|
|
167
122
|
}
|
|
168
123
|
```
|
|
169
124
|
|
|
170
125
|
### Isolated Instances
|
|
171
126
|
|
|
172
|
-
For component-scoped state, use the `@blac({ isolated: true })` decorator:
|
|
173
|
-
|
|
174
127
|
```tsx
|
|
175
128
|
import { Cubit, blac } from '@blac/core';
|
|
176
129
|
|
|
177
130
|
@blac({ isolated: true })
|
|
178
|
-
class FormCubit extends Cubit<FormState> {
|
|
179
|
-
// ...
|
|
180
|
-
}
|
|
131
|
+
class FormCubit extends Cubit<FormState> {}
|
|
181
132
|
|
|
182
133
|
function FormA() {
|
|
183
|
-
|
|
184
|
-
// Gets its own instance
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function FormB() {
|
|
188
|
-
const [state] = useBloc(FormCubit);
|
|
189
|
-
// Gets a different instance
|
|
134
|
+
useBloc(FormCubit); // unique instance per component
|
|
190
135
|
}
|
|
191
136
|
```
|
|
192
137
|
|
|
193
138
|
### Named Instances
|
|
194
139
|
|
|
195
|
-
Share instances across specific components with `instanceId`:
|
|
196
|
-
|
|
197
140
|
```tsx
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function EditorB() {
|
|
203
|
-
const [state] = useBloc(EditorCubit, { instanceId: 'editor-1' });
|
|
204
|
-
// Same instance as EditorA
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function EditorC() {
|
|
208
|
-
const [state] = useBloc(EditorCubit, { instanceId: 'editor-2' });
|
|
209
|
-
// Different instance
|
|
210
|
-
}
|
|
141
|
+
useBloc(EditorCubit, { instanceId: 'editor-1' });
|
|
142
|
+
useBloc(EditorCubit, { instanceId: 'editor-1' }); // same instance
|
|
143
|
+
useBloc(EditorCubit, { instanceId: 'editor-2' }); // different instance
|
|
211
144
|
```
|
|
212
145
|
|
|
213
146
|
## Configuration
|
|
214
147
|
|
|
215
|
-
Configure global
|
|
148
|
+
Configure global defaults:
|
|
216
149
|
|
|
217
150
|
```tsx
|
|
218
151
|
import { configureBlacReact } from '@blac/react';
|
|
219
152
|
|
|
220
153
|
configureBlacReact({
|
|
221
|
-
autoTrack: true,
|
|
154
|
+
autoTrack: true,
|
|
222
155
|
});
|
|
223
156
|
```
|
|
224
157
|
|
|
225
|
-
## API Reference
|
|
226
|
-
|
|
227
|
-
### useBloc
|
|
228
|
-
|
|
229
|
-
```tsx
|
|
230
|
-
function useBloc<T extends StateContainerConstructor>(
|
|
231
|
-
BlocClass: T,
|
|
232
|
-
options?: UseBlocOptions<T>,
|
|
233
|
-
): [ExtractState<T>, InstanceType<T>, ComponentRef];
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### useBlocActions
|
|
237
|
-
|
|
238
|
-
```tsx
|
|
239
|
-
function useBlocActions<T extends StateContainerConstructor>(
|
|
240
|
-
BlocClass: T,
|
|
241
|
-
options?: UseBlocActionsOptions<InstanceType<T>>,
|
|
242
|
-
): InstanceType<T>;
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
### UseBlocOptions
|
|
246
|
-
|
|
247
|
-
| Option | Type | Description |
|
|
248
|
-
| -------------- | ------------------ | ------------------------------------ |
|
|
249
|
-
| `autoTrack` | `boolean` | Enable auto-tracking (default: true) |
|
|
250
|
-
| `dependencies` | `(state) => any[]` | Manual dependency selector |
|
|
251
|
-
| `instanceId` | `string \| number` | Custom instance identifier |
|
|
252
|
-
| `onMount` | `(bloc) => void` | Called when component mounts |
|
|
253
|
-
| `onUnmount` | `(bloc) => void` | Called when component unmounts |
|
|
254
|
-
|
|
255
|
-
### UseBlocActionsOptions
|
|
256
|
-
|
|
257
|
-
| Option | Type | Description |
|
|
258
|
-
| ------------ | ------------------ | ------------------------------ |
|
|
259
|
-
| `instanceId` | `string \| number` | Custom instance identifier |
|
|
260
|
-
| `onMount` | `(bloc) => void` | Called when component mounts |
|
|
261
|
-
| `onUnmount` | `(bloc) => void` | Called when component unmounts |
|
|
262
|
-
|
|
263
158
|
## Compatibility
|
|
264
159
|
|
|
265
|
-
- React 18
|
|
266
|
-
- Works with React Compiler
|
|
267
|
-
- Supports concurrent rendering via `useSyncExternalStore`
|
|
160
|
+
- React 18+ (uses `useSyncExternalStore`)
|
|
268
161
|
|
|
269
162
|
## License
|
|
270
163
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
1
2
|
let react = require("react");
|
|
2
3
|
let _blac_adapter = require("@blac/adapter");
|
|
3
|
-
|
|
4
4
|
//#region src/utils/instance-keys.ts
|
|
5
5
|
/**
|
|
6
6
|
* Instance key generation utilities for React integration
|
|
@@ -25,11 +25,7 @@ function generateInstanceKey(componentRef, isIsolated, providedId) {
|
|
|
25
25
|
return componentRef.__blocInstanceId;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
//#endregion
|
|
30
|
-
//#region src/config.ts
|
|
31
|
-
const defaultConfig = { autoTrack: true };
|
|
32
|
-
let globalConfig = { ...defaultConfig };
|
|
28
|
+
let globalConfig = { autoTrack: true };
|
|
33
29
|
/**
|
|
34
30
|
* Configure global defaults for @blac/react hooks.
|
|
35
31
|
*
|
|
@@ -58,7 +54,6 @@ function configureBlacReact(config) {
|
|
|
58
54
|
function getBlacReactConfig() {
|
|
59
55
|
return globalConfig;
|
|
60
56
|
}
|
|
61
|
-
|
|
62
57
|
//#endregion
|
|
63
58
|
//#region src/useBloc.ts
|
|
64
59
|
function determineTrackingMode(options) {
|
|
@@ -104,17 +99,29 @@ function determineTrackingMode(options) {
|
|
|
104
99
|
function useBloc(BlocClass, options) {
|
|
105
100
|
const componentRef = (0, react.useRef)({});
|
|
106
101
|
const isIsolated = (0, _blac_adapter.isIsolatedClass)(BlocClass);
|
|
102
|
+
const depsRef = (0, react.useRef)(options?.dependencies);
|
|
103
|
+
depsRef.current = options?.dependencies;
|
|
104
|
+
const instanceId = options?.instanceId;
|
|
105
|
+
const autoTrack = options?.autoTrack;
|
|
106
|
+
const dependencies = options?.dependencies;
|
|
107
107
|
const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] = (0, react.useMemo)(() => {
|
|
108
|
-
const instanceKey = generateInstanceKey(componentRef.current, isIsolated,
|
|
108
|
+
const instanceKey = generateInstanceKey(componentRef.current, isIsolated, instanceId);
|
|
109
109
|
const instance = (0, _blac_adapter.acquire)(BlocClass, instanceKey);
|
|
110
|
-
const { useManualDeps, autoTrackEnabled } = determineTrackingMode(
|
|
110
|
+
const { useManualDeps, autoTrackEnabled } = determineTrackingMode({
|
|
111
|
+
autoTrack,
|
|
112
|
+
dependencies
|
|
113
|
+
});
|
|
111
114
|
let subscribeFn;
|
|
112
115
|
let getSnapshotFn;
|
|
113
116
|
let adapterState;
|
|
114
|
-
if (useManualDeps &&
|
|
117
|
+
if (useManualDeps && dependencies) {
|
|
115
118
|
adapterState = (0, _blac_adapter.manualDepsInit)(instance);
|
|
116
|
-
|
|
117
|
-
|
|
119
|
+
const stableConfig = { dependencies: (state, bloc) => {
|
|
120
|
+
const deps = depsRef.current;
|
|
121
|
+
return deps ? deps(state, bloc) : [];
|
|
122
|
+
} };
|
|
123
|
+
subscribeFn = (0, _blac_adapter.manualDepsSubscribe)(instance, adapterState, stableConfig);
|
|
124
|
+
getSnapshotFn = (0, _blac_adapter.manualDepsSnapshot)(instance, adapterState, stableConfig);
|
|
118
125
|
} else if (!autoTrackEnabled) {
|
|
119
126
|
adapterState = (0, _blac_adapter.noTrackInit)(instance);
|
|
120
127
|
subscribeFn = (0, _blac_adapter.noTrackSubscribe)(instance);
|
|
@@ -135,19 +142,21 @@ function useBloc(BlocClass, options) {
|
|
|
135
142
|
}, [
|
|
136
143
|
BlocClass,
|
|
137
144
|
isIsolated,
|
|
138
|
-
|
|
145
|
+
instanceId
|
|
139
146
|
]);
|
|
140
147
|
const state = (0, react.useSyncExternalStore)(subscribe, getSnapshot);
|
|
141
148
|
const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
|
|
142
149
|
const externalDepsManager = (0, react.useRef)(new _blac_adapter.ExternalDepsManager());
|
|
143
150
|
(0, react.useEffect)(() => {
|
|
151
|
+
const manager = externalDepsManager.current;
|
|
144
152
|
(0, _blac_adapter.disableGetterTracking)(adapterState, rawInstance);
|
|
145
|
-
|
|
153
|
+
manager.updateSubscriptions(adapterState.getterState, rawInstance, forceUpdate);
|
|
146
154
|
});
|
|
147
155
|
(0, react.useEffect)(() => {
|
|
156
|
+
const manager = externalDepsManager.current;
|
|
148
157
|
if (options?.onMount) options.onMount(bloc);
|
|
149
158
|
return () => {
|
|
150
|
-
|
|
159
|
+
manager.cleanup();
|
|
151
160
|
if (options?.onUnmount) options.onUnmount(bloc);
|
|
152
161
|
(0, _blac_adapter.release)(BlocClass, instanceKey);
|
|
153
162
|
if (isIsolated && !rawInstance.isDisposed) rawInstance.dispose();
|
|
@@ -159,8 +168,8 @@ function useBloc(BlocClass, options) {
|
|
|
159
168
|
componentRef
|
|
160
169
|
];
|
|
161
170
|
}
|
|
162
|
-
|
|
163
171
|
//#endregion
|
|
164
172
|
exports.configureBlacReact = configureBlacReact;
|
|
165
173
|
exports.useBloc = useBloc;
|
|
174
|
+
|
|
166
175
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["ExternalDepsManager"],"sources":["../src/utils/instance-keys.ts","../src/config.ts","../src/useBloc.ts"],"sourcesContent":["/**\n * Instance key generation utilities for React integration\n */\n\nimport { generateIsolatedKey } from '@blac/adapter';\nimport type { ComponentRef } from '../types';\n\n/**\n * Generate an instance key for a bloc\n *\n * Logic:\n * - If user provides instanceId, use it (convert number to string)\n * - If isolated, generate or reuse a unique key for this component\n * - Otherwise, return undefined (use default key)\n *\n * @param componentRef - React component reference (persists across remounts)\n * @param isIsolated - Whether the bloc is isolated\n * @param providedId - User-provided instance ID (from options)\n * @returns Instance key string or undefined for default\n */\nexport function generateInstanceKey(\n componentRef: ComponentRef,\n isIsolated: boolean,\n providedId?: string | number,\n): string | undefined {\n // User explicitly provided an ID - use it\n if (providedId !== undefined) {\n return typeof providedId === 'number' ? String(providedId) : providedId;\n }\n\n // Isolated bloc - generate unique key per component\n if (isIsolated) {\n if (!componentRef.__blocInstanceId) {\n componentRef.__blocInstanceId = generateIsolatedKey();\n }\n return componentRef.__blocInstanceId;\n }\n\n // Shared bloc - use default key (undefined)\n return undefined;\n}\n","/**\n * Global configuration for @blac/react\n */\n\nexport interface BlacReactConfig {\n /** Enable automatic property tracking via Proxy (default: true) */\n autoTrack: boolean;\n}\n\nconst defaultConfig: BlacReactConfig = {\n autoTrack: true,\n};\n\nlet globalConfig: BlacReactConfig = { ...defaultConfig };\n\n/**\n * Configure global defaults for @blac/react hooks.\n *\n * @example\n * ```ts\n * import { configureBlacReact } from '@blac/react';\n *\n * // Disable auto-tracking globally\n * configureBlacReact({\n * autoTrack: false\n * });\n * ```\n *\n * @param config - Partial configuration to merge with defaults\n */\nexport function configureBlacReact(config: Partial<BlacReactConfig>): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\n/**\n * Get the current global configuration.\n * @internal\n */\nexport function getBlacReactConfig(): BlacReactConfig {\n return globalConfig;\n}\n\n/**\n * Reset configuration to defaults (useful for testing).\n * @internal\n */\nexport function resetBlacReactConfig(): void {\n globalConfig = { ...defaultConfig };\n}\n","import {\n useMemo,\n useSyncExternalStore,\n useEffect,\n useRef,\n useReducer,\n} from 'react';\nimport {\n type ExtractState,\n type AdapterState,\n ExternalDepsManager,\n autoTrackSubscribe,\n manualDepsSubscribe,\n noTrackSubscribe,\n autoTrackSnapshot,\n manualDepsSnapshot,\n noTrackSnapshot,\n autoTrackInit,\n manualDepsInit,\n noTrackInit,\n disableGetterTracking,\n isIsolatedClass,\n type StateContainerConstructor,\n type InstanceState,\n acquire,\n release,\n} from '@blac/adapter';\nimport type { UseBlocOptions, UseBlocReturn, ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\nimport { getBlacReactConfig } from './config';\n\ninterface TrackingMode {\n useManualDeps: boolean;\n autoTrackEnabled: boolean;\n}\n\nfunction determineTrackingMode<TBloc extends StateContainerConstructor>(\n options?: UseBlocOptions<TBloc>,\n): TrackingMode {\n const globalConfig = getBlacReactConfig();\n const autoTrackEnabled =\n options?.autoTrack !== undefined\n ? options.autoTrack\n : globalConfig.autoTrack;\n\n return {\n useManualDeps: options?.dependencies !== undefined,\n autoTrackEnabled,\n };\n}\n\n/**\n * React hook that connects a component to a state container with automatic re-render on state changes.\n *\n * Supports three tracking modes:\n * - **Auto-tracking** (default): Automatically detects accessed state properties via Proxy\n * - **Manual dependencies**: Explicit dependency array like useEffect\n * - **No tracking**: Returns full state without optimization\n *\n * @template T - The state container constructor type (inferred from BlocClass)\n * @param BlocClass - The state container class to connect to\n * @param options - Configuration options for tracking mode and instance management\n * @returns Tuple with [state, bloc instance, ref]\n *\n * @example Basic usage\n * ```ts\n * const [state, myBloc, ref] = useBloc(MyBloc);\n * ```\n *\n * @example With manual dependencies\n * ```ts\n * const [state, myBloc] = useBloc(MyBloc, {\n * dependencies: (state) => [state.count]\n * });\n * ```\n *\n * @example With isolated instance\n * ```ts\n * const [state, myBloc] = useBloc(MyBloc, {\n * instanceId: 'unique-id'\n * });\n * ```\n */\nexport function useBloc<\n T extends StateContainerConstructor = StateContainerConstructor,\n>(\n BlocClass: T,\n options?: UseBlocOptions<T>,\n): UseBlocReturn<T, ExtractState<T>> {\n type TBloc = InstanceState<T>;\n\n const componentRef = useRef<ComponentRef>({});\n const isIsolated = isIsolatedClass(BlocClass);\n\n const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] =\n useMemo<\n readonly [\n TBloc,\n (callback: () => void) => () => void,\n () => ExtractState<T>,\n string | undefined,\n AdapterState<T>,\n TBloc,\n ]\n >(() => {\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n options?.instanceId,\n );\n\n const instance = acquire(BlocClass, instanceKey) as TBloc;\n\n const { useManualDeps, autoTrackEnabled } =\n determineTrackingMode(options);\n\n let subscribeFn: (callback: () => void) => () => void;\n let getSnapshotFn: () => ExtractState<T>;\n let adapterState: AdapterState<T>;\n\n if (useManualDeps && options?.dependencies) {\n adapterState = manualDepsInit(instance);\n subscribeFn = manualDepsSubscribe(instance, adapterState, {\n dependencies: options.dependencies,\n });\n getSnapshotFn = manualDepsSnapshot(instance, adapterState, {\n dependencies: options.dependencies,\n });\n } else if (!autoTrackEnabled) {\n adapterState = noTrackInit(instance);\n subscribeFn = noTrackSubscribe(instance);\n getSnapshotFn = noTrackSnapshot(instance);\n } else {\n adapterState = autoTrackInit(instance);\n subscribeFn = autoTrackSubscribe(instance, adapterState);\n getSnapshotFn = autoTrackSnapshot(instance, adapterState);\n }\n\n return [\n adapterState.proxiedBloc as TBloc,\n subscribeFn,\n getSnapshotFn,\n instanceKey,\n adapterState,\n instance,\n ];\n }, [BlocClass, isIsolated, options?.instanceId]);\n\n const state = useSyncExternalStore(subscribe, getSnapshot);\n\n const [, forceUpdate] = useReducer((x: number) => x + 1, 0);\n\n const externalDepsManager = useRef(new ExternalDepsManager());\n\n useEffect(() => {\n disableGetterTracking(adapterState, rawInstance);\n externalDepsManager.current.updateSubscriptions(\n adapterState.getterState,\n rawInstance,\n forceUpdate,\n );\n });\n\n useEffect(() => {\n if (options?.onMount) {\n options.onMount(bloc as InstanceType<T>);\n }\n\n return () => {\n externalDepsManager.current.cleanup();\n\n if (options?.onUnmount) {\n options.onUnmount(bloc as InstanceType<T>);\n }\n\n release(BlocClass, instanceKey);\n\n if (isIsolated && !rawInstance.isDisposed) {\n rawInstance.dispose();\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return [state, bloc, componentRef] as UseBlocReturn<T, ExtractState<T>>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,oBACd,cACA,YACA,YACoB;AAEpB,KAAI,eAAe,OACjB,QAAO,OAAO,eAAe,WAAW,OAAO,WAAW,GAAG;AAI/D,KAAI,YAAY;AACd,MAAI,CAAC,aAAa,iBAChB,cAAa,2DAAwC;AAEvD,SAAO,aAAa;;;;;;AC1BxB,MAAM,gBAAiC,EACrC,WAAW,MACZ;AAED,IAAI,eAAgC,EAAE,GAAG,eAAe;;;;;;;;;;;;;;;;AAiBxD,SAAgB,mBAAmB,QAAwC;AACzE,gBAAe;EAAE,GAAG;EAAc,GAAG;EAAQ;;;;;;AAO/C,SAAgB,qBAAsC;AACpD,QAAO;;;;;ACHT,SAAS,sBACP,SACc;CACd,MAAM,eAAe,oBAAoB;CACzC,MAAM,mBACJ,SAAS,cAAc,SACnB,QAAQ,YACR,aAAa;AAEnB,QAAO;EACL,eAAe,SAAS,iBAAiB;EACzC;EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCH,SAAgB,QAGd,WACA,SACmC;CAGnC,MAAM,iCAAoC,EAAE,CAAC;CAC7C,MAAM,gDAA6B,UAAU;CAE7C,MAAM,CAAC,MAAM,WAAW,aAAa,aAAa,cAAc,wCAUtD;EACN,MAAM,cAAc,oBAClB,aAAa,SACb,YACA,SAAS,WACV;EAED,MAAM,sCAAmB,WAAW,YAAY;EAEhD,MAAM,EAAE,eAAe,qBACrB,sBAAsB,QAAQ;EAEhC,IAAI;EACJ,IAAI;EACJ,IAAI;AAEJ,MAAI,iBAAiB,SAAS,cAAc;AAC1C,oDAA8B,SAAS;AACvC,wDAAkC,UAAU,cAAc,EACxD,cAAc,QAAQ,cACvB,CAAC;AACF,yDAAmC,UAAU,cAAc,EACzD,cAAc,QAAQ,cACvB,CAAC;aACO,CAAC,kBAAkB;AAC5B,iDAA2B,SAAS;AACpC,qDAA+B,SAAS;AACxC,sDAAgC,SAAS;SACpC;AACL,mDAA6B,SAAS;AACtC,uDAAiC,UAAU,aAAa;AACxD,wDAAkC,UAAU,aAAa;;AAG3D,SAAO;GACL,aAAa;GACb;GACA;GACA;GACA;GACA;GACD;IACA;EAAC;EAAW;EAAY,SAAS;EAAW,CAAC;CAElD,MAAM,wCAA6B,WAAW,YAAY;CAE1D,MAAM,GAAG,sCAA2B,MAAc,IAAI,GAAG,EAAE;CAE3D,MAAM,wCAA6B,IAAIA,mCAAqB,CAAC;AAE7D,4BAAgB;AACd,2CAAsB,cAAc,YAAY;AAChD,sBAAoB,QAAQ,oBAC1B,aAAa,aACb,aACA,YACD;GACD;AAEF,4BAAgB;AACd,MAAI,SAAS,QACX,SAAQ,QAAQ,KAAwB;AAG1C,eAAa;AACX,uBAAoB,QAAQ,SAAS;AAErC,OAAI,SAAS,UACX,SAAQ,UAAU,KAAwB;AAG5C,8BAAQ,WAAW,YAAY;AAE/B,OAAI,cAAc,CAAC,YAAY,WAC7B,aAAY,SAAS;;IAIxB,EAAE,CAAC;AAEN,QAAO;EAAC;EAAO;EAAM;EAAa"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["ExternalDepsManager"],"sources":["../src/utils/instance-keys.ts","../src/config.ts","../src/useBloc.ts"],"sourcesContent":["/**\n * Instance key generation utilities for React integration\n */\n\nimport { generateIsolatedKey } from '@blac/adapter';\nimport type { ComponentRef } from '../types';\n\n/**\n * Generate an instance key for a bloc\n *\n * Logic:\n * - If user provides instanceId, use it (convert number to string)\n * - If isolated, generate or reuse a unique key for this component\n * - Otherwise, return undefined (use default key)\n *\n * @param componentRef - React component reference (persists across remounts)\n * @param isIsolated - Whether the bloc is isolated\n * @param providedId - User-provided instance ID (from options)\n * @returns Instance key string or undefined for default\n */\nexport function generateInstanceKey(\n componentRef: ComponentRef,\n isIsolated: boolean,\n providedId?: string | number,\n): string | undefined {\n // User explicitly provided an ID - use it\n if (providedId !== undefined) {\n return typeof providedId === 'number' ? String(providedId) : providedId;\n }\n\n // Isolated bloc - generate unique key per component\n if (isIsolated) {\n if (!componentRef.__blocInstanceId) {\n componentRef.__blocInstanceId = generateIsolatedKey();\n }\n return componentRef.__blocInstanceId;\n }\n\n // Shared bloc - use default key (undefined)\n return undefined;\n}\n","/**\n * Global configuration for @blac/react\n */\n\nexport interface BlacReactConfig {\n /** Enable automatic property tracking via Proxy (default: true) */\n autoTrack: boolean;\n}\n\nconst defaultConfig: BlacReactConfig = {\n autoTrack: true,\n};\n\nlet globalConfig: BlacReactConfig = { ...defaultConfig };\n\n/**\n * Configure global defaults for @blac/react hooks.\n *\n * @example\n * ```ts\n * import { configureBlacReact } from '@blac/react';\n *\n * // Disable auto-tracking globally\n * configureBlacReact({\n * autoTrack: false\n * });\n * ```\n *\n * @param config - Partial configuration to merge with defaults\n */\nexport function configureBlacReact(config: Partial<BlacReactConfig>): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\n/**\n * Get the current global configuration.\n * @internal\n */\nexport function getBlacReactConfig(): BlacReactConfig {\n return globalConfig;\n}\n\n/**\n * Reset configuration to defaults (useful for testing).\n * @internal\n */\nexport function resetBlacReactConfig(): void {\n globalConfig = { ...defaultConfig };\n}\n","import {\n useMemo,\n useSyncExternalStore,\n useEffect,\n useRef,\n useReducer,\n} from 'react';\nimport {\n type ExtractState,\n type AdapterState,\n ExternalDepsManager,\n autoTrackSubscribe,\n manualDepsSubscribe,\n noTrackSubscribe,\n autoTrackSnapshot,\n manualDepsSnapshot,\n noTrackSnapshot,\n autoTrackInit,\n manualDepsInit,\n noTrackInit,\n disableGetterTracking,\n isIsolatedClass,\n type StateContainerConstructor,\n type InstanceState,\n acquire,\n release,\n} from '@blac/adapter';\nimport type { UseBlocOptions, UseBlocReturn, ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\nimport { getBlacReactConfig } from './config';\n\ninterface TrackingMode {\n useManualDeps: boolean;\n autoTrackEnabled: boolean;\n}\n\nfunction determineTrackingMode<TBloc extends StateContainerConstructor>(\n options?: Pick<UseBlocOptions<TBloc>, 'autoTrack' | 'dependencies'>,\n): TrackingMode {\n const globalConfig = getBlacReactConfig();\n const autoTrackEnabled =\n options?.autoTrack !== undefined\n ? options.autoTrack\n : globalConfig.autoTrack;\n\n return {\n useManualDeps: options?.dependencies !== undefined,\n autoTrackEnabled,\n };\n}\n\n/**\n * React hook that connects a component to a state container with automatic re-render on state changes.\n *\n * Supports three tracking modes:\n * - **Auto-tracking** (default): Automatically detects accessed state properties via Proxy\n * - **Manual dependencies**: Explicit dependency array like useEffect\n * - **No tracking**: Returns full state without optimization\n *\n * @template T - The state container constructor type (inferred from BlocClass)\n * @param BlocClass - The state container class to connect to\n * @param options - Configuration options for tracking mode and instance management\n * @returns Tuple with [state, bloc instance, ref]\n *\n * @example Basic usage\n * ```ts\n * const [state, myBloc, ref] = useBloc(MyBloc);\n * ```\n *\n * @example With manual dependencies\n * ```ts\n * const [state, myBloc] = useBloc(MyBloc, {\n * dependencies: (state) => [state.count]\n * });\n * ```\n *\n * @example With isolated instance\n * ```ts\n * const [state, myBloc] = useBloc(MyBloc, {\n * instanceId: 'unique-id'\n * });\n * ```\n */\nexport function useBloc<\n T extends StateContainerConstructor = StateContainerConstructor,\n>(\n BlocClass: T,\n options?: UseBlocOptions<T>,\n): UseBlocReturn<T, ExtractState<T>> {\n type TBloc = InstanceState<T>;\n\n const componentRef = useRef<ComponentRef>({});\n const isIsolated = isIsolatedClass(BlocClass);\n const depsRef = useRef(options?.dependencies);\n depsRef.current = options?.dependencies;\n const instanceId = options?.instanceId;\n const autoTrack = options?.autoTrack;\n const dependencies = options?.dependencies;\n\n const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] =\n useMemo<\n readonly [\n TBloc,\n (callback: () => void) => () => void,\n () => ExtractState<T>,\n string | undefined,\n AdapterState<T>,\n TBloc,\n ]\n >(() => {\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n instanceId,\n );\n\n const instance = acquire(BlocClass, instanceKey) as TBloc;\n\n const { useManualDeps, autoTrackEnabled } = determineTrackingMode({\n autoTrack,\n dependencies,\n });\n\n let subscribeFn: (callback: () => void) => () => void;\n let getSnapshotFn: () => ExtractState<T>;\n let adapterState: AdapterState<T>;\n\n if (useManualDeps && dependencies) {\n adapterState = manualDepsInit(instance);\n const stableConfig = {\n dependencies: (state: ExtractState<T>, bloc: InstanceState<T>) => {\n const deps = depsRef.current;\n return deps ? deps(state, bloc) : [];\n },\n };\n subscribeFn = manualDepsSubscribe(instance, adapterState, stableConfig);\n getSnapshotFn = manualDepsSnapshot(\n instance,\n adapterState,\n stableConfig,\n );\n } else if (!autoTrackEnabled) {\n adapterState = noTrackInit(instance);\n subscribeFn = noTrackSubscribe(instance);\n getSnapshotFn = noTrackSnapshot(instance);\n } else {\n adapterState = autoTrackInit(instance);\n subscribeFn = autoTrackSubscribe(instance, adapterState);\n getSnapshotFn = autoTrackSnapshot(instance, adapterState);\n }\n\n return [\n adapterState.proxiedBloc as TBloc,\n subscribeFn,\n getSnapshotFn,\n instanceKey,\n adapterState,\n instance,\n ];\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [BlocClass, isIsolated, instanceId]);\n\n const state = useSyncExternalStore(subscribe, getSnapshot);\n\n const [, forceUpdate] = useReducer((x: number) => x + 1, 0);\n\n const externalDepsManager = useRef(new ExternalDepsManager());\n\n useEffect(() => {\n const manager = externalDepsManager.current;\n disableGetterTracking(adapterState, rawInstance);\n manager.updateSubscriptions(\n adapterState.getterState,\n rawInstance,\n forceUpdate,\n );\n });\n\n useEffect(() => {\n const manager = externalDepsManager.current;\n if (options?.onMount) {\n options.onMount(bloc as InstanceType<T>);\n }\n\n return () => {\n manager.cleanup();\n\n if (options?.onUnmount) {\n options.onUnmount(bloc as InstanceType<T>);\n }\n\n release(BlocClass, instanceKey);\n\n if (isIsolated && !rawInstance.isDisposed) {\n rawInstance.dispose();\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return [state, bloc, componentRef] as UseBlocReturn<T, ExtractState<T>>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,oBACd,cACA,YACA,YACoB;AAEpB,KAAI,eAAe,KAAA,EACjB,QAAO,OAAO,eAAe,WAAW,OAAO,WAAW,GAAG;AAI/D,KAAI,YAAY;AACd,MAAI,CAAC,aAAa,iBAChB,cAAa,oBAAA,GAAA,cAAA,sBAAwC;AAEvD,SAAO,aAAa;;;ACtBxB,IAAI,eAAgC,EAHlC,WAAW,MAG2C;;;;;;;;;;;;;;;;AAiBxD,SAAgB,mBAAmB,QAAwC;AACzE,gBAAe;EAAE,GAAG;EAAc,GAAG;EAAQ;;;;;;AAO/C,SAAgB,qBAAsC;AACpD,QAAO;;;;ACHT,SAAS,sBACP,SACc;CACd,MAAM,eAAe,oBAAoB;CACzC,MAAM,mBACJ,SAAS,cAAc,KAAA,IACnB,QAAQ,YACR,aAAa;AAEnB,QAAO;EACL,eAAe,SAAS,iBAAiB,KAAA;EACzC;EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCH,SAAgB,QAGd,WACA,SACmC;CAGnC,MAAM,gBAAA,GAAA,MAAA,QAAoC,EAAE,CAAC;CAC7C,MAAM,cAAA,GAAA,cAAA,iBAA6B,UAAU;CAC7C,MAAM,WAAA,GAAA,MAAA,QAAiB,SAAS,aAAa;AAC7C,SAAQ,UAAU,SAAS;CAC3B,MAAM,aAAa,SAAS;CAC5B,MAAM,YAAY,SAAS;CAC3B,MAAM,eAAe,SAAS;CAE9B,MAAM,CAAC,MAAM,WAAW,aAAa,aAAa,cAAc,gBAAA,GAAA,MAAA,eAUtD;EACN,MAAM,cAAc,oBAClB,aAAa,SACb,YACA,WACD;EAED,MAAM,YAAA,GAAA,cAAA,SAAmB,WAAW,YAAY;EAEhD,MAAM,EAAE,eAAe,qBAAqB,sBAAsB;GAChE;GACA;GACD,CAAC;EAEF,IAAI;EACJ,IAAI;EACJ,IAAI;AAEJ,MAAI,iBAAiB,cAAc;AACjC,mBAAA,GAAA,cAAA,gBAA8B,SAAS;GACvC,MAAM,eAAe,EACnB,eAAe,OAAwB,SAA2B;IAChE,MAAM,OAAO,QAAQ;AACrB,WAAO,OAAO,KAAK,OAAO,KAAK,GAAG,EAAE;MAEvC;AACD,kBAAA,GAAA,cAAA,qBAAkC,UAAU,cAAc,aAAa;AACvE,oBAAA,GAAA,cAAA,oBACE,UACA,cACA,aACD;aACQ,CAAC,kBAAkB;AAC5B,mBAAA,GAAA,cAAA,aAA2B,SAAS;AACpC,kBAAA,GAAA,cAAA,kBAA+B,SAAS;AACxC,oBAAA,GAAA,cAAA,iBAAgC,SAAS;SACpC;AACL,mBAAA,GAAA,cAAA,eAA6B,SAAS;AACtC,kBAAA,GAAA,cAAA,oBAAiC,UAAU,aAAa;AACxD,oBAAA,GAAA,cAAA,mBAAkC,UAAU,aAAa;;AAG3D,SAAO;GACL,aAAa;GACb;GACA;GACA;GACA;GACA;GACD;IAEA;EAAC;EAAW;EAAY;EAAW,CAAC;CAEzC,MAAM,SAAA,GAAA,MAAA,sBAA6B,WAAW,YAAY;CAE1D,MAAM,GAAG,gBAAA,GAAA,MAAA,aAA2B,MAAc,IAAI,GAAG,EAAE;CAE3D,MAAM,uBAAA,GAAA,MAAA,QAA6B,IAAIA,cAAAA,qBAAqB,CAAC;AAE7D,EAAA,GAAA,MAAA,iBAAgB;EACd,MAAM,UAAU,oBAAoB;AACpC,GAAA,GAAA,cAAA,uBAAsB,cAAc,YAAY;AAChD,UAAQ,oBACN,aAAa,aACb,aACA,YACD;GACD;AAEF,EAAA,GAAA,MAAA,iBAAgB;EACd,MAAM,UAAU,oBAAoB;AACpC,MAAI,SAAS,QACX,SAAQ,QAAQ,KAAwB;AAG1C,eAAa;AACX,WAAQ,SAAS;AAEjB,OAAI,SAAS,UACX,SAAQ,UAAU,KAAwB;AAG5C,IAAA,GAAA,cAAA,SAAQ,WAAW,YAAY;AAE/B,OAAI,cAAc,CAAC,YAAY,WAC7B,aAAY,SAAS;;IAIxB,EAAE,CAAC;AAEN,QAAO;EAAC;EAAO;EAAM;EAAa"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useEffect, useMemo, useReducer, useRef, useSyncExternalStore } from "react";
|
|
2
2
|
import { ExternalDepsManager, acquire, autoTrackInit, autoTrackSnapshot, autoTrackSubscribe, disableGetterTracking, generateIsolatedKey, isIsolatedClass, manualDepsInit, manualDepsSnapshot, manualDepsSubscribe, noTrackInit, noTrackSnapshot, noTrackSubscribe, release } from "@blac/adapter";
|
|
3
|
-
|
|
4
3
|
//#region src/utils/instance-keys.ts
|
|
5
4
|
/**
|
|
6
5
|
* Instance key generation utilities for React integration
|
|
@@ -25,11 +24,7 @@ function generateInstanceKey(componentRef, isIsolated, providedId) {
|
|
|
25
24
|
return componentRef.__blocInstanceId;
|
|
26
25
|
}
|
|
27
26
|
}
|
|
28
|
-
|
|
29
|
-
//#endregion
|
|
30
|
-
//#region src/config.ts
|
|
31
|
-
const defaultConfig = { autoTrack: true };
|
|
32
|
-
let globalConfig = { ...defaultConfig };
|
|
27
|
+
let globalConfig = { autoTrack: true };
|
|
33
28
|
/**
|
|
34
29
|
* Configure global defaults for @blac/react hooks.
|
|
35
30
|
*
|
|
@@ -58,7 +53,6 @@ function configureBlacReact(config) {
|
|
|
58
53
|
function getBlacReactConfig() {
|
|
59
54
|
return globalConfig;
|
|
60
55
|
}
|
|
61
|
-
|
|
62
56
|
//#endregion
|
|
63
57
|
//#region src/useBloc.ts
|
|
64
58
|
function determineTrackingMode(options) {
|
|
@@ -104,17 +98,29 @@ function determineTrackingMode(options) {
|
|
|
104
98
|
function useBloc(BlocClass, options) {
|
|
105
99
|
const componentRef = useRef({});
|
|
106
100
|
const isIsolated = isIsolatedClass(BlocClass);
|
|
101
|
+
const depsRef = useRef(options?.dependencies);
|
|
102
|
+
depsRef.current = options?.dependencies;
|
|
103
|
+
const instanceId = options?.instanceId;
|
|
104
|
+
const autoTrack = options?.autoTrack;
|
|
105
|
+
const dependencies = options?.dependencies;
|
|
107
106
|
const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] = useMemo(() => {
|
|
108
|
-
const instanceKey = generateInstanceKey(componentRef.current, isIsolated,
|
|
107
|
+
const instanceKey = generateInstanceKey(componentRef.current, isIsolated, instanceId);
|
|
109
108
|
const instance = acquire(BlocClass, instanceKey);
|
|
110
|
-
const { useManualDeps, autoTrackEnabled } = determineTrackingMode(
|
|
109
|
+
const { useManualDeps, autoTrackEnabled } = determineTrackingMode({
|
|
110
|
+
autoTrack,
|
|
111
|
+
dependencies
|
|
112
|
+
});
|
|
111
113
|
let subscribeFn;
|
|
112
114
|
let getSnapshotFn;
|
|
113
115
|
let adapterState;
|
|
114
|
-
if (useManualDeps &&
|
|
116
|
+
if (useManualDeps && dependencies) {
|
|
115
117
|
adapterState = manualDepsInit(instance);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
+
const stableConfig = { dependencies: (state, bloc) => {
|
|
119
|
+
const deps = depsRef.current;
|
|
120
|
+
return deps ? deps(state, bloc) : [];
|
|
121
|
+
} };
|
|
122
|
+
subscribeFn = manualDepsSubscribe(instance, adapterState, stableConfig);
|
|
123
|
+
getSnapshotFn = manualDepsSnapshot(instance, adapterState, stableConfig);
|
|
118
124
|
} else if (!autoTrackEnabled) {
|
|
119
125
|
adapterState = noTrackInit(instance);
|
|
120
126
|
subscribeFn = noTrackSubscribe(instance);
|
|
@@ -135,19 +141,21 @@ function useBloc(BlocClass, options) {
|
|
|
135
141
|
}, [
|
|
136
142
|
BlocClass,
|
|
137
143
|
isIsolated,
|
|
138
|
-
|
|
144
|
+
instanceId
|
|
139
145
|
]);
|
|
140
146
|
const state = useSyncExternalStore(subscribe, getSnapshot);
|
|
141
147
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
142
148
|
const externalDepsManager = useRef(new ExternalDepsManager());
|
|
143
149
|
useEffect(() => {
|
|
150
|
+
const manager = externalDepsManager.current;
|
|
144
151
|
disableGetterTracking(adapterState, rawInstance);
|
|
145
|
-
|
|
152
|
+
manager.updateSubscriptions(adapterState.getterState, rawInstance, forceUpdate);
|
|
146
153
|
});
|
|
147
154
|
useEffect(() => {
|
|
155
|
+
const manager = externalDepsManager.current;
|
|
148
156
|
if (options?.onMount) options.onMount(bloc);
|
|
149
157
|
return () => {
|
|
150
|
-
|
|
158
|
+
manager.cleanup();
|
|
151
159
|
if (options?.onUnmount) options.onUnmount(bloc);
|
|
152
160
|
release(BlocClass, instanceKey);
|
|
153
161
|
if (isIsolated && !rawInstance.isDisposed) rawInstance.dispose();
|
|
@@ -159,7 +167,7 @@ function useBloc(BlocClass, options) {
|
|
|
159
167
|
componentRef
|
|
160
168
|
];
|
|
161
169
|
}
|
|
162
|
-
|
|
163
170
|
//#endregion
|
|
164
171
|
export { configureBlacReact, useBloc };
|
|
172
|
+
|
|
165
173
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/utils/instance-keys.ts","../src/config.ts","../src/useBloc.ts"],"sourcesContent":["/**\n * Instance key generation utilities for React integration\n */\n\nimport { generateIsolatedKey } from '@blac/adapter';\nimport type { ComponentRef } from '../types';\n\n/**\n * Generate an instance key for a bloc\n *\n * Logic:\n * - If user provides instanceId, use it (convert number to string)\n * - If isolated, generate or reuse a unique key for this component\n * - Otherwise, return undefined (use default key)\n *\n * @param componentRef - React component reference (persists across remounts)\n * @param isIsolated - Whether the bloc is isolated\n * @param providedId - User-provided instance ID (from options)\n * @returns Instance key string or undefined for default\n */\nexport function generateInstanceKey(\n componentRef: ComponentRef,\n isIsolated: boolean,\n providedId?: string | number,\n): string | undefined {\n // User explicitly provided an ID - use it\n if (providedId !== undefined) {\n return typeof providedId === 'number' ? String(providedId) : providedId;\n }\n\n // Isolated bloc - generate unique key per component\n if (isIsolated) {\n if (!componentRef.__blocInstanceId) {\n componentRef.__blocInstanceId = generateIsolatedKey();\n }\n return componentRef.__blocInstanceId;\n }\n\n // Shared bloc - use default key (undefined)\n return undefined;\n}\n","/**\n * Global configuration for @blac/react\n */\n\nexport interface BlacReactConfig {\n /** Enable automatic property tracking via Proxy (default: true) */\n autoTrack: boolean;\n}\n\nconst defaultConfig: BlacReactConfig = {\n autoTrack: true,\n};\n\nlet globalConfig: BlacReactConfig = { ...defaultConfig };\n\n/**\n * Configure global defaults for @blac/react hooks.\n *\n * @example\n * ```ts\n * import { configureBlacReact } from '@blac/react';\n *\n * // Disable auto-tracking globally\n * configureBlacReact({\n * autoTrack: false\n * });\n * ```\n *\n * @param config - Partial configuration to merge with defaults\n */\nexport function configureBlacReact(config: Partial<BlacReactConfig>): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\n/**\n * Get the current global configuration.\n * @internal\n */\nexport function getBlacReactConfig(): BlacReactConfig {\n return globalConfig;\n}\n\n/**\n * Reset configuration to defaults (useful for testing).\n * @internal\n */\nexport function resetBlacReactConfig(): void {\n globalConfig = { ...defaultConfig };\n}\n","import {\n useMemo,\n useSyncExternalStore,\n useEffect,\n useRef,\n useReducer,\n} from 'react';\nimport {\n type ExtractState,\n type AdapterState,\n ExternalDepsManager,\n autoTrackSubscribe,\n manualDepsSubscribe,\n noTrackSubscribe,\n autoTrackSnapshot,\n manualDepsSnapshot,\n noTrackSnapshot,\n autoTrackInit,\n manualDepsInit,\n noTrackInit,\n disableGetterTracking,\n isIsolatedClass,\n type StateContainerConstructor,\n type InstanceState,\n acquire,\n release,\n} from '@blac/adapter';\nimport type { UseBlocOptions, UseBlocReturn, ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\nimport { getBlacReactConfig } from './config';\n\ninterface TrackingMode {\n useManualDeps: boolean;\n autoTrackEnabled: boolean;\n}\n\nfunction determineTrackingMode<TBloc extends StateContainerConstructor>(\n options?: UseBlocOptions<TBloc>,\n): TrackingMode {\n const globalConfig = getBlacReactConfig();\n const autoTrackEnabled =\n options?.autoTrack !== undefined\n ? options.autoTrack\n : globalConfig.autoTrack;\n\n return {\n useManualDeps: options?.dependencies !== undefined,\n autoTrackEnabled,\n };\n}\n\n/**\n * React hook that connects a component to a state container with automatic re-render on state changes.\n *\n * Supports three tracking modes:\n * - **Auto-tracking** (default): Automatically detects accessed state properties via Proxy\n * - **Manual dependencies**: Explicit dependency array like useEffect\n * - **No tracking**: Returns full state without optimization\n *\n * @template T - The state container constructor type (inferred from BlocClass)\n * @param BlocClass - The state container class to connect to\n * @param options - Configuration options for tracking mode and instance management\n * @returns Tuple with [state, bloc instance, ref]\n *\n * @example Basic usage\n * ```ts\n * const [state, myBloc, ref] = useBloc(MyBloc);\n * ```\n *\n * @example With manual dependencies\n * ```ts\n * const [state, myBloc] = useBloc(MyBloc, {\n * dependencies: (state) => [state.count]\n * });\n * ```\n *\n * @example With isolated instance\n * ```ts\n * const [state, myBloc] = useBloc(MyBloc, {\n * instanceId: 'unique-id'\n * });\n * ```\n */\nexport function useBloc<\n T extends StateContainerConstructor = StateContainerConstructor,\n>(\n BlocClass: T,\n options?: UseBlocOptions<T>,\n): UseBlocReturn<T, ExtractState<T>> {\n type TBloc = InstanceState<T>;\n\n const componentRef = useRef<ComponentRef>({});\n const isIsolated = isIsolatedClass(BlocClass);\n\n const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] =\n useMemo<\n readonly [\n TBloc,\n (callback: () => void) => () => void,\n () => ExtractState<T>,\n string | undefined,\n AdapterState<T>,\n TBloc,\n ]\n >(() => {\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n options?.instanceId,\n );\n\n const instance = acquire(BlocClass, instanceKey) as TBloc;\n\n const { useManualDeps, autoTrackEnabled } =\n determineTrackingMode(options);\n\n let subscribeFn: (callback: () => void) => () => void;\n let getSnapshotFn: () => ExtractState<T>;\n let adapterState: AdapterState<T>;\n\n if (useManualDeps && options?.dependencies) {\n adapterState = manualDepsInit(instance);\n subscribeFn = manualDepsSubscribe(instance, adapterState, {\n dependencies: options.dependencies,\n });\n getSnapshotFn = manualDepsSnapshot(instance, adapterState, {\n dependencies: options.dependencies,\n });\n } else if (!autoTrackEnabled) {\n adapterState = noTrackInit(instance);\n subscribeFn = noTrackSubscribe(instance);\n getSnapshotFn = noTrackSnapshot(instance);\n } else {\n adapterState = autoTrackInit(instance);\n subscribeFn = autoTrackSubscribe(instance, adapterState);\n getSnapshotFn = autoTrackSnapshot(instance, adapterState);\n }\n\n return [\n adapterState.proxiedBloc as TBloc,\n subscribeFn,\n getSnapshotFn,\n instanceKey,\n adapterState,\n instance,\n ];\n }, [BlocClass, isIsolated, options?.instanceId]);\n\n const state = useSyncExternalStore(subscribe, getSnapshot);\n\n const [, forceUpdate] = useReducer((x: number) => x + 1, 0);\n\n const externalDepsManager = useRef(new ExternalDepsManager());\n\n useEffect(() => {\n disableGetterTracking(adapterState, rawInstance);\n externalDepsManager.current.updateSubscriptions(\n adapterState.getterState,\n rawInstance,\n forceUpdate,\n );\n });\n\n useEffect(() => {\n if (options?.onMount) {\n options.onMount(bloc as InstanceType<T>);\n }\n\n return () => {\n externalDepsManager.current.cleanup();\n\n if (options?.onUnmount) {\n options.onUnmount(bloc as InstanceType<T>);\n }\n\n release(BlocClass, instanceKey);\n\n if (isIsolated && !rawInstance.isDisposed) {\n rawInstance.dispose();\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return [state, bloc, componentRef] as UseBlocReturn<T, ExtractState<T>>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,oBACd,cACA,YACA,YACoB;AAEpB,KAAI,eAAe,OACjB,QAAO,OAAO,eAAe,WAAW,OAAO,WAAW,GAAG;AAI/D,KAAI,YAAY;AACd,MAAI,CAAC,aAAa,iBAChB,cAAa,mBAAmB,qBAAqB;AAEvD,SAAO,aAAa;;;;;;AC1BxB,MAAM,gBAAiC,EACrC,WAAW,MACZ;AAED,IAAI,eAAgC,EAAE,GAAG,eAAe;;;;;;;;;;;;;;;;AAiBxD,SAAgB,mBAAmB,QAAwC;AACzE,gBAAe;EAAE,GAAG;EAAc,GAAG;EAAQ;;;;;;AAO/C,SAAgB,qBAAsC;AACpD,QAAO;;;;;ACHT,SAAS,sBACP,SACc;CACd,MAAM,eAAe,oBAAoB;CACzC,MAAM,mBACJ,SAAS,cAAc,SACnB,QAAQ,YACR,aAAa;AAEnB,QAAO;EACL,eAAe,SAAS,iBAAiB;EACzC;EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCH,SAAgB,QAGd,WACA,SACmC;CAGnC,MAAM,eAAe,OAAqB,EAAE,CAAC;CAC7C,MAAM,aAAa,gBAAgB,UAAU;CAE7C,MAAM,CAAC,MAAM,WAAW,aAAa,aAAa,cAAc,eAC9D,cASQ;EACN,MAAM,cAAc,oBAClB,aAAa,SACb,YACA,SAAS,WACV;EAED,MAAM,WAAW,QAAQ,WAAW,YAAY;EAEhD,MAAM,EAAE,eAAe,qBACrB,sBAAsB,QAAQ;EAEhC,IAAI;EACJ,IAAI;EACJ,IAAI;AAEJ,MAAI,iBAAiB,SAAS,cAAc;AAC1C,kBAAe,eAAe,SAAS;AACvC,iBAAc,oBAAoB,UAAU,cAAc,EACxD,cAAc,QAAQ,cACvB,CAAC;AACF,mBAAgB,mBAAmB,UAAU,cAAc,EACzD,cAAc,QAAQ,cACvB,CAAC;aACO,CAAC,kBAAkB;AAC5B,kBAAe,YAAY,SAAS;AACpC,iBAAc,iBAAiB,SAAS;AACxC,mBAAgB,gBAAgB,SAAS;SACpC;AACL,kBAAe,cAAc,SAAS;AACtC,iBAAc,mBAAmB,UAAU,aAAa;AACxD,mBAAgB,kBAAkB,UAAU,aAAa;;AAG3D,SAAO;GACL,aAAa;GACb;GACA;GACA;GACA;GACA;GACD;IACA;EAAC;EAAW;EAAY,SAAS;EAAW,CAAC;CAElD,MAAM,QAAQ,qBAAqB,WAAW,YAAY;CAE1D,MAAM,GAAG,eAAe,YAAY,MAAc,IAAI,GAAG,EAAE;CAE3D,MAAM,sBAAsB,OAAO,IAAI,qBAAqB,CAAC;AAE7D,iBAAgB;AACd,wBAAsB,cAAc,YAAY;AAChD,sBAAoB,QAAQ,oBAC1B,aAAa,aACb,aACA,YACD;GACD;AAEF,iBAAgB;AACd,MAAI,SAAS,QACX,SAAQ,QAAQ,KAAwB;AAG1C,eAAa;AACX,uBAAoB,QAAQ,SAAS;AAErC,OAAI,SAAS,UACX,SAAQ,UAAU,KAAwB;AAG5C,WAAQ,WAAW,YAAY;AAE/B,OAAI,cAAc,CAAC,YAAY,WAC7B,aAAY,SAAS;;IAIxB,EAAE,CAAC;AAEN,QAAO;EAAC;EAAO;EAAM;EAAa"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/utils/instance-keys.ts","../src/config.ts","../src/useBloc.ts"],"sourcesContent":["/**\n * Instance key generation utilities for React integration\n */\n\nimport { generateIsolatedKey } from '@blac/adapter';\nimport type { ComponentRef } from '../types';\n\n/**\n * Generate an instance key for a bloc\n *\n * Logic:\n * - If user provides instanceId, use it (convert number to string)\n * - If isolated, generate or reuse a unique key for this component\n * - Otherwise, return undefined (use default key)\n *\n * @param componentRef - React component reference (persists across remounts)\n * @param isIsolated - Whether the bloc is isolated\n * @param providedId - User-provided instance ID (from options)\n * @returns Instance key string or undefined for default\n */\nexport function generateInstanceKey(\n componentRef: ComponentRef,\n isIsolated: boolean,\n providedId?: string | number,\n): string | undefined {\n // User explicitly provided an ID - use it\n if (providedId !== undefined) {\n return typeof providedId === 'number' ? String(providedId) : providedId;\n }\n\n // Isolated bloc - generate unique key per component\n if (isIsolated) {\n if (!componentRef.__blocInstanceId) {\n componentRef.__blocInstanceId = generateIsolatedKey();\n }\n return componentRef.__blocInstanceId;\n }\n\n // Shared bloc - use default key (undefined)\n return undefined;\n}\n","/**\n * Global configuration for @blac/react\n */\n\nexport interface BlacReactConfig {\n /** Enable automatic property tracking via Proxy (default: true) */\n autoTrack: boolean;\n}\n\nconst defaultConfig: BlacReactConfig = {\n autoTrack: true,\n};\n\nlet globalConfig: BlacReactConfig = { ...defaultConfig };\n\n/**\n * Configure global defaults for @blac/react hooks.\n *\n * @example\n * ```ts\n * import { configureBlacReact } from '@blac/react';\n *\n * // Disable auto-tracking globally\n * configureBlacReact({\n * autoTrack: false\n * });\n * ```\n *\n * @param config - Partial configuration to merge with defaults\n */\nexport function configureBlacReact(config: Partial<BlacReactConfig>): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\n/**\n * Get the current global configuration.\n * @internal\n */\nexport function getBlacReactConfig(): BlacReactConfig {\n return globalConfig;\n}\n\n/**\n * Reset configuration to defaults (useful for testing).\n * @internal\n */\nexport function resetBlacReactConfig(): void {\n globalConfig = { ...defaultConfig };\n}\n","import {\n useMemo,\n useSyncExternalStore,\n useEffect,\n useRef,\n useReducer,\n} from 'react';\nimport {\n type ExtractState,\n type AdapterState,\n ExternalDepsManager,\n autoTrackSubscribe,\n manualDepsSubscribe,\n noTrackSubscribe,\n autoTrackSnapshot,\n manualDepsSnapshot,\n noTrackSnapshot,\n autoTrackInit,\n manualDepsInit,\n noTrackInit,\n disableGetterTracking,\n isIsolatedClass,\n type StateContainerConstructor,\n type InstanceState,\n acquire,\n release,\n} from '@blac/adapter';\nimport type { UseBlocOptions, UseBlocReturn, ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\nimport { getBlacReactConfig } from './config';\n\ninterface TrackingMode {\n useManualDeps: boolean;\n autoTrackEnabled: boolean;\n}\n\nfunction determineTrackingMode<TBloc extends StateContainerConstructor>(\n options?: Pick<UseBlocOptions<TBloc>, 'autoTrack' | 'dependencies'>,\n): TrackingMode {\n const globalConfig = getBlacReactConfig();\n const autoTrackEnabled =\n options?.autoTrack !== undefined\n ? options.autoTrack\n : globalConfig.autoTrack;\n\n return {\n useManualDeps: options?.dependencies !== undefined,\n autoTrackEnabled,\n };\n}\n\n/**\n * React hook that connects a component to a state container with automatic re-render on state changes.\n *\n * Supports three tracking modes:\n * - **Auto-tracking** (default): Automatically detects accessed state properties via Proxy\n * - **Manual dependencies**: Explicit dependency array like useEffect\n * - **No tracking**: Returns full state without optimization\n *\n * @template T - The state container constructor type (inferred from BlocClass)\n * @param BlocClass - The state container class to connect to\n * @param options - Configuration options for tracking mode and instance management\n * @returns Tuple with [state, bloc instance, ref]\n *\n * @example Basic usage\n * ```ts\n * const [state, myBloc, ref] = useBloc(MyBloc);\n * ```\n *\n * @example With manual dependencies\n * ```ts\n * const [state, myBloc] = useBloc(MyBloc, {\n * dependencies: (state) => [state.count]\n * });\n * ```\n *\n * @example With isolated instance\n * ```ts\n * const [state, myBloc] = useBloc(MyBloc, {\n * instanceId: 'unique-id'\n * });\n * ```\n */\nexport function useBloc<\n T extends StateContainerConstructor = StateContainerConstructor,\n>(\n BlocClass: T,\n options?: UseBlocOptions<T>,\n): UseBlocReturn<T, ExtractState<T>> {\n type TBloc = InstanceState<T>;\n\n const componentRef = useRef<ComponentRef>({});\n const isIsolated = isIsolatedClass(BlocClass);\n const depsRef = useRef(options?.dependencies);\n depsRef.current = options?.dependencies;\n const instanceId = options?.instanceId;\n const autoTrack = options?.autoTrack;\n const dependencies = options?.dependencies;\n\n const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] =\n useMemo<\n readonly [\n TBloc,\n (callback: () => void) => () => void,\n () => ExtractState<T>,\n string | undefined,\n AdapterState<T>,\n TBloc,\n ]\n >(() => {\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n instanceId,\n );\n\n const instance = acquire(BlocClass, instanceKey) as TBloc;\n\n const { useManualDeps, autoTrackEnabled } = determineTrackingMode({\n autoTrack,\n dependencies,\n });\n\n let subscribeFn: (callback: () => void) => () => void;\n let getSnapshotFn: () => ExtractState<T>;\n let adapterState: AdapterState<T>;\n\n if (useManualDeps && dependencies) {\n adapterState = manualDepsInit(instance);\n const stableConfig = {\n dependencies: (state: ExtractState<T>, bloc: InstanceState<T>) => {\n const deps = depsRef.current;\n return deps ? deps(state, bloc) : [];\n },\n };\n subscribeFn = manualDepsSubscribe(instance, adapterState, stableConfig);\n getSnapshotFn = manualDepsSnapshot(\n instance,\n adapterState,\n stableConfig,\n );\n } else if (!autoTrackEnabled) {\n adapterState = noTrackInit(instance);\n subscribeFn = noTrackSubscribe(instance);\n getSnapshotFn = noTrackSnapshot(instance);\n } else {\n adapterState = autoTrackInit(instance);\n subscribeFn = autoTrackSubscribe(instance, adapterState);\n getSnapshotFn = autoTrackSnapshot(instance, adapterState);\n }\n\n return [\n adapterState.proxiedBloc as TBloc,\n subscribeFn,\n getSnapshotFn,\n instanceKey,\n adapterState,\n instance,\n ];\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [BlocClass, isIsolated, instanceId]);\n\n const state = useSyncExternalStore(subscribe, getSnapshot);\n\n const [, forceUpdate] = useReducer((x: number) => x + 1, 0);\n\n const externalDepsManager = useRef(new ExternalDepsManager());\n\n useEffect(() => {\n const manager = externalDepsManager.current;\n disableGetterTracking(adapterState, rawInstance);\n manager.updateSubscriptions(\n adapterState.getterState,\n rawInstance,\n forceUpdate,\n );\n });\n\n useEffect(() => {\n const manager = externalDepsManager.current;\n if (options?.onMount) {\n options.onMount(bloc as InstanceType<T>);\n }\n\n return () => {\n manager.cleanup();\n\n if (options?.onUnmount) {\n options.onUnmount(bloc as InstanceType<T>);\n }\n\n release(BlocClass, instanceKey);\n\n if (isIsolated && !rawInstance.isDisposed) {\n rawInstance.dispose();\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return [state, bloc, componentRef] as UseBlocReturn<T, ExtractState<T>>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,oBACd,cACA,YACA,YACoB;AAEpB,KAAI,eAAe,KAAA,EACjB,QAAO,OAAO,eAAe,WAAW,OAAO,WAAW,GAAG;AAI/D,KAAI,YAAY;AACd,MAAI,CAAC,aAAa,iBAChB,cAAa,mBAAmB,qBAAqB;AAEvD,SAAO,aAAa;;;ACtBxB,IAAI,eAAgC,EAHlC,WAAW,MAG2C;;;;;;;;;;;;;;;;AAiBxD,SAAgB,mBAAmB,QAAwC;AACzE,gBAAe;EAAE,GAAG;EAAc,GAAG;EAAQ;;;;;;AAO/C,SAAgB,qBAAsC;AACpD,QAAO;;;;ACHT,SAAS,sBACP,SACc;CACd,MAAM,eAAe,oBAAoB;CACzC,MAAM,mBACJ,SAAS,cAAc,KAAA,IACnB,QAAQ,YACR,aAAa;AAEnB,QAAO;EACL,eAAe,SAAS,iBAAiB,KAAA;EACzC;EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCH,SAAgB,QAGd,WACA,SACmC;CAGnC,MAAM,eAAe,OAAqB,EAAE,CAAC;CAC7C,MAAM,aAAa,gBAAgB,UAAU;CAC7C,MAAM,UAAU,OAAO,SAAS,aAAa;AAC7C,SAAQ,UAAU,SAAS;CAC3B,MAAM,aAAa,SAAS;CAC5B,MAAM,YAAY,SAAS;CAC3B,MAAM,eAAe,SAAS;CAE9B,MAAM,CAAC,MAAM,WAAW,aAAa,aAAa,cAAc,eAC9D,cASQ;EACN,MAAM,cAAc,oBAClB,aAAa,SACb,YACA,WACD;EAED,MAAM,WAAW,QAAQ,WAAW,YAAY;EAEhD,MAAM,EAAE,eAAe,qBAAqB,sBAAsB;GAChE;GACA;GACD,CAAC;EAEF,IAAI;EACJ,IAAI;EACJ,IAAI;AAEJ,MAAI,iBAAiB,cAAc;AACjC,kBAAe,eAAe,SAAS;GACvC,MAAM,eAAe,EACnB,eAAe,OAAwB,SAA2B;IAChE,MAAM,OAAO,QAAQ;AACrB,WAAO,OAAO,KAAK,OAAO,KAAK,GAAG,EAAE;MAEvC;AACD,iBAAc,oBAAoB,UAAU,cAAc,aAAa;AACvE,mBAAgB,mBACd,UACA,cACA,aACD;aACQ,CAAC,kBAAkB;AAC5B,kBAAe,YAAY,SAAS;AACpC,iBAAc,iBAAiB,SAAS;AACxC,mBAAgB,gBAAgB,SAAS;SACpC;AACL,kBAAe,cAAc,SAAS;AACtC,iBAAc,mBAAmB,UAAU,aAAa;AACxD,mBAAgB,kBAAkB,UAAU,aAAa;;AAG3D,SAAO;GACL,aAAa;GACb;GACA;GACA;GACA;GACA;GACD;IAEA;EAAC;EAAW;EAAY;EAAW,CAAC;CAEzC,MAAM,QAAQ,qBAAqB,WAAW,YAAY;CAE1D,MAAM,GAAG,eAAe,YAAY,MAAc,IAAI,GAAG,EAAE;CAE3D,MAAM,sBAAsB,OAAO,IAAI,qBAAqB,CAAC;AAE7D,iBAAgB;EACd,MAAM,UAAU,oBAAoB;AACpC,wBAAsB,cAAc,YAAY;AAChD,UAAQ,oBACN,aAAa,aACb,aACA,YACD;GACD;AAEF,iBAAgB;EACd,MAAM,UAAU,oBAAoB;AACpC,MAAI,SAAS,QACX,SAAQ,QAAQ,KAAwB;AAG1C,eAAa;AACX,WAAQ,SAAS;AAEjB,OAAI,SAAS,UACX,SAAQ,UAAU,KAAwB;AAG5C,WAAQ,WAAW,YAAY;AAE/B,OAAI,cAAc,CAAC,YAAY,WAC7B,aAAY,SAAS;;IAIxB,EAAE,CAAC;AAEN,QAAO;EAAC;EAAO;EAAM;EAAa"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blac/react",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Brendan Mullins <jsnanigans@gmail.com>",
|
|
6
6
|
"repository": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"bugs": {
|
|
13
13
|
"url": "https://github.com/jsnanigans/blac/issues"
|
|
14
14
|
},
|
|
15
|
+
"type": "module",
|
|
15
16
|
"main": "./dist/index.cjs",
|
|
16
17
|
"module": "./dist/index.js",
|
|
17
18
|
"types": "./dist/index.d.ts",
|
|
@@ -32,6 +33,9 @@
|
|
|
32
33
|
"README.md",
|
|
33
34
|
"LICENSE"
|
|
34
35
|
],
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
35
39
|
"sideEffects": false,
|
|
36
40
|
"keywords": [
|
|
37
41
|
"react",
|
|
@@ -43,11 +47,12 @@
|
|
|
43
47
|
"bloc-pattern"
|
|
44
48
|
],
|
|
45
49
|
"dependencies": {
|
|
46
|
-
"@blac/adapter": "2.0.
|
|
50
|
+
"@blac/adapter": "^2.0.6"
|
|
47
51
|
},
|
|
48
52
|
"peerDependencies": {
|
|
49
53
|
"@types/react": "^18.0.0 || ^19.0.0",
|
|
50
|
-
"react": "^18.0.0 || ^19.0.0"
|
|
54
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
55
|
+
"@blac/core": "^2.0.6"
|
|
51
56
|
},
|
|
52
57
|
"peerDependenciesMeta": {
|
|
53
58
|
"@types/react": {
|
|
@@ -75,9 +80,10 @@
|
|
|
75
80
|
"react-dom": "^19.1.1",
|
|
76
81
|
"tsdown": "^0.15.7",
|
|
77
82
|
"typescript": "^5.9.2",
|
|
83
|
+
"vite": "^7.1.10",
|
|
78
84
|
"publint": "^0.3.12",
|
|
79
85
|
"vitest": "3.2.4",
|
|
80
|
-
"@blac/core": "2.0.
|
|
86
|
+
"@blac/core": "2.0.6"
|
|
81
87
|
},
|
|
82
88
|
"scripts": {
|
|
83
89
|
"dev": "tsdown --watch",
|
|
@@ -93,7 +99,7 @@
|
|
|
93
99
|
"test:compiler": "vitest run --config vitest.config.compiler.ts",
|
|
94
100
|
"test:watch:compiler": "vitest --watch --config vitest.config.compiler.ts",
|
|
95
101
|
"test:both": "pnpm test && echo '\n\n=== Running tests WITH React Compiler ===\n' && pnpm test:compiler",
|
|
96
|
-
"verify": "publint",
|
|
102
|
+
"verify": "node ../../scripts/run-workspace-bin.mjs publint",
|
|
97
103
|
"typecheck": "tsc --noEmit",
|
|
98
104
|
"deploy": "pnpm publish --access public"
|
|
99
105
|
}
|