@fictjs/runtime 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fictjs/runtime",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Fict reactive runtime",
5
5
  "publishConfig": {
6
6
  "access": "public"
package/src/index.ts CHANGED
@@ -3,9 +3,11 @@
3
3
  // ============================================================================
4
4
 
5
5
  export { createSignal, createSelector, type Signal, $state } from './signal'
6
+ export { effectScope } from './signal'
6
7
  export { createStore, type Store } from './store'
7
8
  export { createMemo, type Memo, $memo } from './memo'
8
9
  export { createEffect, createRenderEffect, type Effect, $effect } from './effect'
10
+ export { createScope, runInScope, type ReactiveScope } from './scope'
9
11
  export {
10
12
  __fictUseContext,
11
13
  __fictPushContext,
package/src/scope.ts ADDED
@@ -0,0 +1,55 @@
1
+ import { isReactive, type MaybeReactive } from './binding'
2
+ import { createEffect } from './effect'
3
+ import { createRoot, onCleanup, registerRootCleanup } from './lifecycle'
4
+
5
+ export { effectScope } from './signal'
6
+
7
+ export interface ReactiveScope {
8
+ run<T>(fn: () => T): T
9
+ stop(): void
10
+ }
11
+
12
+ /**
13
+ * Create an explicit reactive scope that can contain effects/memos and be stopped manually.
14
+ * The scope registers with the current root for cleanup.
15
+ */
16
+ export function createScope(): ReactiveScope {
17
+ let dispose: (() => void) | null = null
18
+
19
+ const stop = () => {
20
+ if (dispose) {
21
+ dispose()
22
+ dispose = null
23
+ }
24
+ }
25
+
26
+ const run = <T>(fn: () => T): T => {
27
+ stop()
28
+ const { dispose: rootDispose, value } = createRoot(fn)
29
+ dispose = rootDispose
30
+ return value
31
+ }
32
+
33
+ registerRootCleanup(stop)
34
+ return { run, stop }
35
+ }
36
+
37
+ /**
38
+ * Run a block of reactive code inside a managed scope that follows a boolean flag.
39
+ * When the flag turns false, the scope is disposed and all contained effects/memos are cleaned up.
40
+ */
41
+ export function runInScope(flag: MaybeReactive<boolean>, fn: () => void): void {
42
+ const scope = createScope()
43
+ const evaluate = () => (isReactive(flag) ? (flag as () => boolean)() : !!flag)
44
+
45
+ createEffect(() => {
46
+ const enabled = evaluate()
47
+ if (enabled) {
48
+ scope.run(fn)
49
+ } else {
50
+ scope.stop()
51
+ }
52
+ })
53
+
54
+ onCleanup(scope.stop)
55
+ }
package/src/slim.ts CHANGED
@@ -9,6 +9,7 @@
9
9
  export { createSignal, createSelector, $state } from './signal'
10
10
  export { createMemo } from './memo'
11
11
  export { createEffect, createRenderEffect } from './effect'
12
+ export { effectScope, createScope, runInScope, type ReactiveScope } from './scope'
12
13
  export { batch, untrack } from './scheduler'
13
14
 
14
15
  // DOM rendering