@sigrea/vue 0.2.1 → 0.3.1
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 +58 -21
- package/dist/index.cjs +5 -5
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +6 -6
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
# @sigrea/vue
|
|
2
2
|
|
|
3
|
-
`@sigrea/vue` adapts [@sigrea/core](https://www.npmjs.com/package/@sigrea/core)
|
|
3
|
+
`@sigrea/vue` adapts [@sigrea/core](https://www.npmjs.com/package/@sigrea/core) molecule modules and signals for Vue 3's Composition API. It aligns lifecycle scopes with component lifecycles, preserves deep reactivity, and provides composables for `<script setup>` and traditional setup functions.
|
|
4
4
|
|
|
5
5
|
- **Signal subscriptions.** `useSignal` subscribes to signals and computed values, returning a readonly ref that updates when they change.
|
|
6
6
|
- **Computed subscriptions.** `useComputed` subscribes to computed values, mirroring Vue's `computed` while tracking through Sigrea scopes.
|
|
7
7
|
- **Deep signal subscriptions.** `useDeepSignal` subscribes to deep signal objects and exposes them as mutable refs with automatic cleanup.
|
|
8
8
|
- **Two-way bindings.** `useMutableSignal` wraps primitive signals as `WritableComputedRef` for two-way bindings like `v-model`.
|
|
9
|
-
- **
|
|
9
|
+
- **Molecule lifecycles.** `useMolcule` mounts molecule factories and binds their lifecycles to Vue components.
|
|
10
10
|
|
|
11
11
|
## Table of Contents
|
|
12
12
|
|
|
13
13
|
- [Install](#install)
|
|
14
14
|
- [Quick Start](#quick-start)
|
|
15
15
|
- [Consume a Signal](#consume-a-signal)
|
|
16
|
-
- [Bridge Framework-Agnostic
|
|
16
|
+
- [Bridge Framework-Agnostic Molecules](#bridge-framework-agnostic-molecules)
|
|
17
17
|
- [Bind Writable Primitive Signals](#bind-writable-primitive-signals)
|
|
18
18
|
- [Bind Deep Reactive Objects](#bind-deep-reactive-objects)
|
|
19
19
|
- [API Reference](#api-reference)
|
|
@@ -21,8 +21,9 @@
|
|
|
21
21
|
- [useComputed](#usecomputed)
|
|
22
22
|
- [useDeepSignal](#usedeepsignal)
|
|
23
23
|
- [useMutableSignal](#usemutablesignal)
|
|
24
|
-
- [
|
|
24
|
+
- [useMolcule](#usemolcule)
|
|
25
25
|
- [Testing](#testing)
|
|
26
|
+
- [Handling Scope Cleanup Errors](#handling-scope-cleanup-errors)
|
|
26
27
|
- [Development](#development)
|
|
27
28
|
- [License](#license)
|
|
28
29
|
|
|
@@ -52,13 +53,13 @@ const value = useSignal(count);
|
|
|
52
53
|
</template>
|
|
53
54
|
```
|
|
54
55
|
|
|
55
|
-
### Bridge Framework-Agnostic
|
|
56
|
+
### Bridge Framework-Agnostic Molecules
|
|
56
57
|
|
|
57
58
|
```ts
|
|
58
|
-
//
|
|
59
|
-
import {
|
|
59
|
+
// CounterMolecule.ts
|
|
60
|
+
import { molecule, signal } from "@sigrea/core";
|
|
60
61
|
|
|
61
|
-
export const
|
|
62
|
+
export const CounterMolecule = molecule((props: { initialCount: number }) => {
|
|
62
63
|
const count = signal(props.initialCount);
|
|
63
64
|
|
|
64
65
|
const increment = () => {
|
|
@@ -76,11 +77,11 @@ export const CounterLogic = defineLogic<{ initialCount: number }>()((props) => {
|
|
|
76
77
|
```vue
|
|
77
78
|
<!-- Counter.vue -->
|
|
78
79
|
<script setup lang="ts">
|
|
79
|
-
import {
|
|
80
|
-
import {
|
|
80
|
+
import { useMolcule, useSignal } from "@sigrea/vue";
|
|
81
|
+
import { CounterMolecule } from "./CounterMolecule";
|
|
81
82
|
|
|
82
83
|
const props = defineProps<{ initialCount: number }>();
|
|
83
|
-
const counter =
|
|
84
|
+
const counter = useMolcule(CounterMolecule, props);
|
|
84
85
|
const value = useSignal(counter.count);
|
|
85
86
|
</script>
|
|
86
87
|
|
|
@@ -169,27 +170,24 @@ function useMutableSignal<T>(signal: Signal<T>): WritableComputedRef<T>
|
|
|
169
170
|
|
|
170
171
|
Wraps a Sigrea signal as a Vue `WritableComputedRef` for two-way bindings like `v-model`. Expects a writable signal created by `signal()`. Passing a readonly signal throws at runtime.
|
|
171
172
|
|
|
172
|
-
###
|
|
173
|
+
### useMolcule
|
|
173
174
|
|
|
174
175
|
```ts
|
|
175
|
-
function
|
|
176
|
-
|
|
177
|
-
...args:
|
|
178
|
-
):
|
|
176
|
+
function useMolcule<TReturn extends object, TProps = void>(
|
|
177
|
+
molecule: MoleculeFactory<TReturn, TProps>,
|
|
178
|
+
...args: MoleculeArgs<TProps>
|
|
179
|
+
): MoleculeInstance<TReturn>
|
|
179
180
|
```
|
|
180
181
|
|
|
181
|
-
Mounts a
|
|
182
|
+
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.
|
|
182
183
|
|
|
183
184
|
## Testing
|
|
184
185
|
|
|
185
186
|
```ts
|
|
186
187
|
// tests/Counter.test.ts
|
|
187
188
|
import { mount } from "@vue/test-utils";
|
|
188
|
-
import { cleanupLogics } from "@sigrea/core";
|
|
189
189
|
import Counter from "../components/Counter.vue";
|
|
190
190
|
|
|
191
|
-
afterEach(() => cleanupLogics());
|
|
192
|
-
|
|
193
191
|
it("increments and displays the updated count", async () => {
|
|
194
192
|
const wrapper = mount(Counter, {
|
|
195
193
|
props: { initialCount: 10 },
|
|
@@ -201,15 +199,54 @@ it("increments and displays the updated count", async () => {
|
|
|
201
199
|
});
|
|
202
200
|
```
|
|
203
201
|
|
|
202
|
+
## Handling Scope Cleanup Errors
|
|
203
|
+
|
|
204
|
+
For global error handling configuration, see [@sigrea/core - Handling Scope Cleanup Errors](https://github.com/sigrea/core#handling-scope-cleanup-errors).
|
|
205
|
+
|
|
206
|
+
In Vue apps, configure the handler in your application entry point before mounting:
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
// main.ts
|
|
210
|
+
import { setScopeCleanupErrorHandler } from "@sigrea/core";
|
|
211
|
+
import { createApp } from "vue";
|
|
212
|
+
import App from "./App.vue";
|
|
213
|
+
|
|
214
|
+
setScopeCleanupErrorHandler((error, context) => {
|
|
215
|
+
console.error(`Cleanup failed:`, error);
|
|
216
|
+
|
|
217
|
+
// Forward to monitoring service
|
|
218
|
+
if (typeof Sentry !== "undefined") {
|
|
219
|
+
Sentry.captureException(error, {
|
|
220
|
+
tags: { scopeId: context.scopeId, phase: context.phase },
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
createApp(App).mount("#app");
|
|
226
|
+
```
|
|
227
|
+
|
|
204
228
|
## Development
|
|
205
229
|
|
|
206
|
-
|
|
230
|
+
This repo targets Node.js 20 or later.
|
|
231
|
+
|
|
232
|
+
If you use mise:
|
|
233
|
+
|
|
234
|
+
- `mise trust -y` — trust `mise.toml` (first run only).
|
|
235
|
+
- `mise run ci` — run CI-equivalent checks locally.
|
|
236
|
+
- `mise run notes` — preview release notes (optional).
|
|
237
|
+
|
|
238
|
+
You can also run pnpm scripts directly:
|
|
207
239
|
|
|
208
240
|
- `pnpm install` — install dependencies.
|
|
209
241
|
- `pnpm test` — run the Vitest suite once (no watch).
|
|
242
|
+
- `pnpm typecheck` — run TypeScript type checking.
|
|
243
|
+
- `pnpm test:coverage` — collect coverage.
|
|
210
244
|
- `pnpm build` — compile via unbuild to produce dual CJS/ESM bundles.
|
|
245
|
+
- `pnpm cicheck` — run CI checks locally.
|
|
211
246
|
- `pnpm dev` — launch the playground counter demo.
|
|
212
247
|
|
|
248
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for workflow details.
|
|
249
|
+
|
|
213
250
|
## License
|
|
214
251
|
|
|
215
252
|
MIT — see [LICENSE](./LICENSE).
|
package/dist/index.cjs
CHANGED
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
const vue = require('vue');
|
|
4
4
|
const core = require('@sigrea/core');
|
|
5
5
|
|
|
6
|
-
function
|
|
6
|
+
function useMolcule(molecule, ...args) {
|
|
7
7
|
if (vue.getCurrentInstance() === null) {
|
|
8
8
|
throw new Error(
|
|
9
|
-
"
|
|
9
|
+
"useMolcule can only be used within a Vue component setup()."
|
|
10
10
|
);
|
|
11
11
|
}
|
|
12
|
-
const instance =
|
|
12
|
+
const instance = molecule(...args);
|
|
13
13
|
vue.onScopeDispose(() => {
|
|
14
|
-
core.
|
|
14
|
+
core.disposeMolecule(instance);
|
|
15
15
|
});
|
|
16
16
|
return instance;
|
|
17
17
|
}
|
|
@@ -85,7 +85,7 @@ function useMutableSignal(source) {
|
|
|
85
85
|
|
|
86
86
|
exports.useComputed = useComputed;
|
|
87
87
|
exports.useDeepSignal = useDeepSignal;
|
|
88
|
-
exports.
|
|
88
|
+
exports.useMolcule = useMolcule;
|
|
89
89
|
exports.useMutableSignal = useMutableSignal;
|
|
90
90
|
exports.useSignal = useSignal;
|
|
91
91
|
exports.useSnapshot = useSnapshot;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MoleculeFactory, MoleculeArgs, MoleculeInstance, Signal, ReadonlySignal, Computed, DeepSignal, SnapshotHandler } from '@sigrea/core';
|
|
2
2
|
import * as vue from 'vue';
|
|
3
3
|
import { DeepReadonly, ShallowRef } from 'vue';
|
|
4
4
|
|
|
5
|
-
declare function
|
|
5
|
+
declare function useMolcule<TReturn extends object, TProps = 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>>>;
|
|
@@ -21,4 +21,4 @@ declare function useSnapshot<T>(handler: SnapshotHandler<T>, options: UseSnapsho
|
|
|
21
21
|
mode: "mutable";
|
|
22
22
|
}): ShallowRef<T>;
|
|
23
23
|
|
|
24
|
-
export { useComputed, useDeepSignal,
|
|
24
|
+
export { useComputed, useDeepSignal, useMolcule, useMutableSignal, useSignal, useSnapshot };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MoleculeFactory, MoleculeArgs, MoleculeInstance, Signal, ReadonlySignal, Computed, DeepSignal, SnapshotHandler } from '@sigrea/core';
|
|
2
2
|
import * as vue from 'vue';
|
|
3
3
|
import { DeepReadonly, ShallowRef } from 'vue';
|
|
4
4
|
|
|
5
|
-
declare function
|
|
5
|
+
declare function useMolcule<TReturn extends object, TProps = 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>>>;
|
|
@@ -21,4 +21,4 @@ declare function useSnapshot<T>(handler: SnapshotHandler<T>, options: UseSnapsho
|
|
|
21
21
|
mode: "mutable";
|
|
22
22
|
}): ShallowRef<T>;
|
|
23
23
|
|
|
24
|
-
export { useComputed, useDeepSignal,
|
|
24
|
+
export { useComputed, useDeepSignal, useMolcule, useMutableSignal, useSignal, useSnapshot };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MoleculeFactory, MoleculeArgs, MoleculeInstance, Signal, ReadonlySignal, Computed, DeepSignal, SnapshotHandler } from '@sigrea/core';
|
|
2
2
|
import * as vue from 'vue';
|
|
3
3
|
import { DeepReadonly, ShallowRef } from 'vue';
|
|
4
4
|
|
|
5
|
-
declare function
|
|
5
|
+
declare function useMolcule<TReturn extends object, TProps = 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>>>;
|
|
@@ -21,4 +21,4 @@ declare function useSnapshot<T>(handler: SnapshotHandler<T>, options: UseSnapsho
|
|
|
21
21
|
mode: "mutable";
|
|
22
22
|
}): ShallowRef<T>;
|
|
23
23
|
|
|
24
|
-
export { useComputed, useDeepSignal,
|
|
24
|
+
export { useComputed, useDeepSignal, useMolcule, useMutableSignal, useSignal, useSnapshot };
|
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { getCurrentInstance, onScopeDispose, shallowRef, readonly, triggerRef, computed } from 'vue';
|
|
2
|
-
import {
|
|
2
|
+
import { disposeMolecule, createSignalHandler, createComputedHandler, createDeepSignalHandler } from '@sigrea/core';
|
|
3
3
|
|
|
4
|
-
function
|
|
4
|
+
function useMolcule(molecule, ...args) {
|
|
5
5
|
if (getCurrentInstance() === null) {
|
|
6
6
|
throw new Error(
|
|
7
|
-
"
|
|
7
|
+
"useMolcule can only be used within a Vue component setup()."
|
|
8
8
|
);
|
|
9
9
|
}
|
|
10
|
-
const instance =
|
|
10
|
+
const instance = molecule(...args);
|
|
11
11
|
onScopeDispose(() => {
|
|
12
|
-
|
|
12
|
+
disposeMolecule(instance);
|
|
13
13
|
});
|
|
14
14
|
return instance;
|
|
15
15
|
}
|
|
@@ -81,4 +81,4 @@ function useMutableSignal(source) {
|
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
export { useComputed, useDeepSignal,
|
|
84
|
+
export { useComputed, useDeepSignal, useMolcule, useMutableSignal, useSignal, useSnapshot };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sigrea/vue",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Vue adapter bindings for Sigrea
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "Vue adapter bindings for Sigrea molecule modules.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"packageManager": "pnpm@10.0.0",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"signals",
|
|
37
37
|
"reactivity",
|
|
38
38
|
"vue",
|
|
39
|
-
"
|
|
39
|
+
"molecule",
|
|
40
40
|
"typescript"
|
|
41
41
|
],
|
|
42
42
|
"scripts": {
|
|
@@ -49,10 +49,11 @@
|
|
|
49
49
|
"test:coverage": "vitest --coverage",
|
|
50
50
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
51
51
|
"format": "biome check .",
|
|
52
|
-
"format:fix": "biome check --write ."
|
|
52
|
+
"format:fix": "biome check --write .",
|
|
53
|
+
"cicheck": "pnpm test && pnpm typecheck && pnpm format:fix"
|
|
53
54
|
},
|
|
54
55
|
"peerDependencies": {
|
|
55
|
-
"@sigrea/core": "^0.3
|
|
56
|
+
"@sigrea/core": "^0.4.3",
|
|
56
57
|
"vue": "^3.4.0"
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|