@sigrea/vue 0.4.0 → 0.5.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 +51 -14
- package/dist/index.cjs +19 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +21 -3
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -57,20 +57,36 @@ const value = useSignal(count);
|
|
|
57
57
|
|
|
58
58
|
```ts
|
|
59
59
|
// CounterMolecule.ts
|
|
60
|
-
import { molecule, signal } from "@sigrea/core";
|
|
60
|
+
import { molecule, readonly, signal } from "@sigrea/core";
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
type CounterProps = {
|
|
63
|
+
initialCount: number;
|
|
64
|
+
initialStep: number;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const CounterMolecule = molecule((props: CounterProps) => {
|
|
63
68
|
const count = signal(props.initialCount);
|
|
69
|
+
const step = signal(props.initialStep);
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
71
|
+
function setStep(next: number) {
|
|
72
|
+
step.value = next;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function increment() {
|
|
76
|
+
count.value += step.value;
|
|
77
|
+
}
|
|
68
78
|
|
|
69
|
-
|
|
79
|
+
function reset() {
|
|
70
80
|
count.value = props.initialCount;
|
|
71
|
-
}
|
|
81
|
+
}
|
|
72
82
|
|
|
73
|
-
return {
|
|
83
|
+
return {
|
|
84
|
+
count: readonly(count),
|
|
85
|
+
step: readonly(step),
|
|
86
|
+
setStep,
|
|
87
|
+
increment,
|
|
88
|
+
reset,
|
|
89
|
+
};
|
|
74
90
|
});
|
|
75
91
|
```
|
|
76
92
|
|
|
@@ -80,16 +96,23 @@ export const CounterMolecule = molecule((props: { initialCount: number }) => {
|
|
|
80
96
|
import { useMolecule, useSignal } from "@sigrea/vue";
|
|
81
97
|
import { CounterMolecule } from "./CounterMolecule";
|
|
82
98
|
|
|
83
|
-
const props = defineProps<{ initialCount: number }>();
|
|
84
|
-
|
|
85
|
-
const
|
|
99
|
+
const props = defineProps<{ initialCount: number; initialStep: number }>();
|
|
100
|
+
|
|
101
|
+
const counter = useMolecule(CounterMolecule, {
|
|
102
|
+
initialCount: props.initialCount,
|
|
103
|
+
initialStep: props.initialStep,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const count = useSignal(counter.count);
|
|
107
|
+
const step = useSignal(counter.step);
|
|
86
108
|
</script>
|
|
87
109
|
|
|
88
110
|
<template>
|
|
89
111
|
<div>
|
|
90
|
-
<span>{{
|
|
112
|
+
<span>{{ count }}</span>
|
|
91
113
|
<button @click="counter.increment">Increment</button>
|
|
92
114
|
<button @click="counter.reset">Reset</button>
|
|
115
|
+
<button @click="counter.setStep(step + 1)">Step +</button>
|
|
93
116
|
</div>
|
|
94
117
|
</template>
|
|
95
118
|
```
|
|
@@ -122,7 +145,7 @@ const model = useMutableSignal(count);
|
|
|
122
145
|
import { deepSignal } from "@sigrea/core";
|
|
123
146
|
import { useDeepSignal } from "@sigrea/vue";
|
|
124
147
|
|
|
125
|
-
const profile = deepSignal({ name: "
|
|
148
|
+
const profile = deepSignal({ name: "Mendako" });
|
|
126
149
|
const model = useDeepSignal(profile);
|
|
127
150
|
</script>
|
|
128
151
|
|
|
@@ -173,7 +196,7 @@ Wraps a Sigrea signal as a Vue `WritableComputedRef` for two-way bindings like `
|
|
|
173
196
|
### useMolecule
|
|
174
197
|
|
|
175
198
|
```ts
|
|
176
|
-
function useMolecule<TReturn extends object, TProps = void>(
|
|
199
|
+
function useMolecule<TReturn extends object, TProps extends object | void = void>(
|
|
177
200
|
molecule: MoleculeFactory<TReturn, TProps>,
|
|
178
201
|
...args: MoleculeArgs<TProps>
|
|
179
202
|
): MoleculeInstance<TReturn>
|
|
@@ -181,6 +204,20 @@ function useMolecule<TReturn extends object, TProps = void>(
|
|
|
181
204
|
|
|
182
205
|
Mounts a molecule factory and returns its MoleculeInstance. Sigrea augments the molecule with lifecycle metadata: `onMount` callbacks run after the component mounts, and `onUnmount` callbacks run before it unmounts.
|
|
183
206
|
|
|
207
|
+
**KeepAlive Support**
|
|
208
|
+
|
|
209
|
+
When used inside Vue's `<KeepAlive>`, molecule side effects are automatically managed for optimal resource efficiency:
|
|
210
|
+
|
|
211
|
+
- **On deactivation** (`onDeactivated`): `watch` effects and ongoing work are paused via `unmountMolecule`. The molecule instance itself remains alive, preserving its internal state.
|
|
212
|
+
- **On reactivation** (`onActivated`): Side effects resume via `mountMolecule`, allowing watches and subscriptions to pick up where they left off.
|
|
213
|
+
- **On final unmount**: The molecule is fully disposed via `disposeMolecule`, releasing all resources.
|
|
214
|
+
|
|
215
|
+
This design prevents unnecessary computation and subscriptions while components are cached but invisible, reducing CPU and memory usage without losing state.
|
|
216
|
+
|
|
217
|
+
**Props Handling**
|
|
218
|
+
|
|
219
|
+
Props are treated as an initial snapshot. Updating component props does not recreate the molecule instance or update the snapshot; model dynamic values via signals or explicit molecule methods (for example, `setStep`).
|
|
220
|
+
|
|
184
221
|
## Testing
|
|
185
222
|
|
|
186
223
|
```ts
|
package/dist/index.cjs
CHANGED
|
@@ -9,7 +9,25 @@ function useMolecule(molecule, ...args) {
|
|
|
9
9
|
"useMolecule can only be used within a Vue component setup()."
|
|
10
10
|
);
|
|
11
11
|
}
|
|
12
|
-
const
|
|
12
|
+
const props = args.length === 0 ? void 0 : args[0];
|
|
13
|
+
if (props !== void 0 && (typeof props !== "object" || props === null)) {
|
|
14
|
+
throw new TypeError("useMolecule props must be an object.");
|
|
15
|
+
}
|
|
16
|
+
const snapshot = props === void 0 ? void 0 : { ...vue.toRaw(props) };
|
|
17
|
+
const moleculeArgs = snapshot === void 0 ? [] : [snapshot];
|
|
18
|
+
const instance = molecule(...moleculeArgs);
|
|
19
|
+
vue.onMounted(() => {
|
|
20
|
+
core.mountMolecule(instance);
|
|
21
|
+
});
|
|
22
|
+
vue.onActivated(() => {
|
|
23
|
+
core.mountMolecule(instance);
|
|
24
|
+
});
|
|
25
|
+
vue.onDeactivated(() => {
|
|
26
|
+
core.unmountMolecule(instance);
|
|
27
|
+
});
|
|
28
|
+
vue.onBeforeUnmount(() => {
|
|
29
|
+
core.unmountMolecule(instance);
|
|
30
|
+
});
|
|
13
31
|
vue.onScopeDispose(() => {
|
|
14
32
|
core.disposeMolecule(instance);
|
|
15
33
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ import { MoleculeFactory, MoleculeArgs, MoleculeInstance, Signal, ReadonlySignal
|
|
|
2
2
|
import * as vue from 'vue';
|
|
3
3
|
import { DeepReadonly, ShallowRef } from 'vue';
|
|
4
4
|
|
|
5
|
-
declare function useMolecule<TReturn extends object, TProps = void>(molecule: MoleculeFactory<TReturn, TProps>, ...args: MoleculeArgs<TProps>): MoleculeInstance<TReturn>;
|
|
5
|
+
declare function useMolecule<TReturn extends object, TProps extends object | void = void>(molecule: MoleculeFactory<TReturn, TProps>, ...args: MoleculeArgs<TProps>): MoleculeInstance<TReturn>;
|
|
6
6
|
|
|
7
7
|
type ReadableSignal<T> = Signal<T> | ReadonlySignal<T>;
|
|
8
8
|
declare function useSignal<T>(source: ReadableSignal<T>): Readonly<vue.Ref<vue.DeepReadonly<T>, vue.DeepReadonly<T>>>;
|
package/dist/index.d.mts
CHANGED
|
@@ -2,7 +2,7 @@ import { MoleculeFactory, MoleculeArgs, MoleculeInstance, Signal, ReadonlySignal
|
|
|
2
2
|
import * as vue from 'vue';
|
|
3
3
|
import { DeepReadonly, ShallowRef } from 'vue';
|
|
4
4
|
|
|
5
|
-
declare function useMolecule<TReturn extends object, TProps = void>(molecule: MoleculeFactory<TReturn, TProps>, ...args: MoleculeArgs<TProps>): MoleculeInstance<TReturn>;
|
|
5
|
+
declare function useMolecule<TReturn extends object, TProps extends object | void = void>(molecule: MoleculeFactory<TReturn, TProps>, ...args: MoleculeArgs<TProps>): MoleculeInstance<TReturn>;
|
|
6
6
|
|
|
7
7
|
type ReadableSignal<T> = Signal<T> | ReadonlySignal<T>;
|
|
8
8
|
declare function useSignal<T>(source: ReadableSignal<T>): Readonly<vue.Ref<vue.DeepReadonly<T>, vue.DeepReadonly<T>>>;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { MoleculeFactory, MoleculeArgs, MoleculeInstance, Signal, ReadonlySignal
|
|
|
2
2
|
import * as vue from 'vue';
|
|
3
3
|
import { DeepReadonly, ShallowRef } from 'vue';
|
|
4
4
|
|
|
5
|
-
declare function useMolecule<TReturn extends object, TProps = void>(molecule: MoleculeFactory<TReturn, TProps>, ...args: MoleculeArgs<TProps>): MoleculeInstance<TReturn>;
|
|
5
|
+
declare function useMolecule<TReturn extends object, TProps extends object | void = void>(molecule: MoleculeFactory<TReturn, TProps>, ...args: MoleculeArgs<TProps>): MoleculeInstance<TReturn>;
|
|
6
6
|
|
|
7
7
|
type ReadableSignal<T> = Signal<T> | ReadonlySignal<T>;
|
|
8
8
|
declare function useSignal<T>(source: ReadableSignal<T>): Readonly<vue.Ref<vue.DeepReadonly<T>, vue.DeepReadonly<T>>>;
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { getCurrentInstance, onScopeDispose, shallowRef, readonly, triggerRef, computed } from 'vue';
|
|
2
|
-
import { disposeMolecule, createSignalHandler, createComputedHandler, createDeepSignalHandler } from '@sigrea/core';
|
|
1
|
+
import { getCurrentInstance, toRaw, onMounted, onActivated, onDeactivated, onBeforeUnmount, onScopeDispose, shallowRef, readonly, triggerRef, computed } from 'vue';
|
|
2
|
+
import { mountMolecule, unmountMolecule, disposeMolecule, createSignalHandler, createComputedHandler, createDeepSignalHandler } from '@sigrea/core';
|
|
3
3
|
|
|
4
4
|
function useMolecule(molecule, ...args) {
|
|
5
5
|
if (getCurrentInstance() === null) {
|
|
@@ -7,7 +7,25 @@ function useMolecule(molecule, ...args) {
|
|
|
7
7
|
"useMolecule can only be used within a Vue component setup()."
|
|
8
8
|
);
|
|
9
9
|
}
|
|
10
|
-
const
|
|
10
|
+
const props = args.length === 0 ? void 0 : args[0];
|
|
11
|
+
if (props !== void 0 && (typeof props !== "object" || props === null)) {
|
|
12
|
+
throw new TypeError("useMolecule props must be an object.");
|
|
13
|
+
}
|
|
14
|
+
const snapshot = props === void 0 ? void 0 : { ...toRaw(props) };
|
|
15
|
+
const moleculeArgs = snapshot === void 0 ? [] : [snapshot];
|
|
16
|
+
const instance = molecule(...moleculeArgs);
|
|
17
|
+
onMounted(() => {
|
|
18
|
+
mountMolecule(instance);
|
|
19
|
+
});
|
|
20
|
+
onActivated(() => {
|
|
21
|
+
mountMolecule(instance);
|
|
22
|
+
});
|
|
23
|
+
onDeactivated(() => {
|
|
24
|
+
unmountMolecule(instance);
|
|
25
|
+
});
|
|
26
|
+
onBeforeUnmount(() => {
|
|
27
|
+
unmountMolecule(instance);
|
|
28
|
+
});
|
|
11
29
|
onScopeDispose(() => {
|
|
12
30
|
disposeMolecule(instance);
|
|
13
31
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sigrea/vue",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Vue adapter bindings for Sigrea molecule modules.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -53,23 +53,25 @@
|
|
|
53
53
|
"cicheck": "pnpm test && pnpm typecheck && pnpm format:fix"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@sigrea/core": "^0.
|
|
56
|
+
"@sigrea/core": "^0.5.0",
|
|
57
57
|
"vue": "^3.4.0"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@biomejs/biome": "1.9.4",
|
|
61
|
+
"@sigrea/core": "^0.5.0",
|
|
61
62
|
"@vitejs/plugin-vue": "^5.1.4",
|
|
62
|
-
"@vue/test-utils": "^2.4.0",
|
|
63
63
|
"@vitest/coverage-v8": "^3.2.4",
|
|
64
|
+
"@vue/test-utils": "^2.4.0",
|
|
65
|
+
"baseline-browser-mapping": "^2.9.13",
|
|
64
66
|
"changelogen": "^0.6.2",
|
|
67
|
+
"jsdom": "^24.1.3",
|
|
65
68
|
"lefthook": "1.13.6",
|
|
66
69
|
"tsx": "^4.20.5",
|
|
67
70
|
"typescript": "5.9.3",
|
|
68
71
|
"unbuild": "3.6.1",
|
|
69
72
|
"vite": "^5.4.6",
|
|
70
73
|
"vitest": "^3.2.4",
|
|
71
|
-
"vue": "^3.4.0"
|
|
72
|
-
"jsdom": "^24.1.3"
|
|
74
|
+
"vue": "^3.4.0"
|
|
73
75
|
},
|
|
74
76
|
"pnpm": {
|
|
75
77
|
"onlyBuiltDependencies": [
|