@kdeveloper/kvark 0.6.1 → 0.6.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.
- package/README.md +13 -15
- package/dist/vue/index.d.mts +6 -4
- package/dist/vue/index.d.mts.map +1 -1
- package/dist/vue/index.mjs +10 -2
- package/dist/vue/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ function UserCard() {
|
|
|
75
75
|
|
|
76
76
|
### Vue 3
|
|
77
77
|
|
|
78
|
-
The same atoms and store work with `@kdeveloper/kvark/vue`. Composables mirror the React hooks; `useAtomValue` returns
|
|
78
|
+
The same atoms and store work with `@kdeveloper/kvark/vue`. Composables mirror the React hooks; `useAtomValue` returns an **awaitable** [`shallowRef`](https://vuejs.org/api/reactivity-advanced.html#shallowref) — use `.value` in `<script setup>` (templates unwrap refs automatically). The ref also implements `PromiseLike`, so `await useAtomValue(atom)` in an async `setup` suspends until the first `get` resolves — see [Suspense (Vue 3)](#suspense-vue-3).
|
|
79
79
|
|
|
80
80
|
Composables must run **inside** a `Provider` subtree. Put `useAtomValue` / `useAtom` in a child component (or a nested route), not in the same component that renders `Provider` without passing the store through a wrapper.
|
|
81
81
|
|
|
@@ -134,7 +134,7 @@ const store = createStore();
|
|
|
134
134
|
</template>
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
-
Unlike React
|
|
137
|
+
Unlike React, Vue’s `<Suspense>` only activates for **async** child components. Since `useAtomValue` and `useAtom` return `PromiseLike` refs, just **`await`** them in an async `setup` (or top-level `<script setup>`) to trigger Suspense — see [Suspense (Vue 3)](#suspense-vue-3).
|
|
138
138
|
|
|
139
139
|
## Core Concepts
|
|
140
140
|
|
|
@@ -417,11 +417,11 @@ const balance = await readBalance();
|
|
|
417
417
|
|
|
418
418
|
Same composable names and behaviour as React: `Provider`, `useStore`, `useAtomValue`, `useSetAtom`, `useAtom`, `useAtomContext`. Wrap your app (or subtree) with `Provider` and pass `:store="store"`.
|
|
419
419
|
|
|
420
|
-
`useAtomValue` / `useAtom` expose values as **shallow refs** — in script code use `.value`; in templates Vue unwraps refs for you.
|
|
420
|
+
`useAtomValue` / `useAtom` expose values as **awaitable shallow refs** (`PromiseLike`) — in script code use `.value`; in templates Vue unwraps refs for you. `await useAtomValue(atom)` in an async setup suspends until the atom's first `get` resolves, integrating with `<Suspense>`.
|
|
421
421
|
|
|
422
422
|
### Suspense (Vue 3)
|
|
423
423
|
|
|
424
|
-
Vue’s `<Suspense>` boundary applies to **async** components (e.g. **`async setup`** or [top-level `await` in `<script setup>`](https://vuejs.org/guide/built-ins/suspense.html#async-setup)), not to composables alone.
|
|
424
|
+
Vue’s `<Suspense>` boundary applies to **async** components (e.g. **`async setup`** or [top-level `await` in `<script setup>`](https://vuejs.org/guide/built-ins/suspense.html#async-setup)), not to composables alone. Because `useAtomValue` and `useAtom` return `PromiseLike` refs, you can simply `await` them to suspend until the first `get` resolves.
|
|
425
425
|
|
|
426
426
|
`atoms.ts`
|
|
427
427
|
|
|
@@ -440,12 +440,10 @@ export const slowAtom = atom({
|
|
|
440
440
|
|
|
441
441
|
```vue
|
|
442
442
|
<script setup lang="ts">
|
|
443
|
-
import { useAtomValue
|
|
443
|
+
import { useAtomValue } from "@kdeveloper/kvark/vue";
|
|
444
444
|
import { slowAtom } from "./atoms";
|
|
445
445
|
|
|
446
|
-
const
|
|
447
|
-
const value = useAtomValue(slowAtom);
|
|
448
|
-
await store.resolve(slowAtom);
|
|
446
|
+
const value = await useAtomValue(slowAtom);
|
|
449
447
|
</script>
|
|
450
448
|
|
|
451
449
|
<template>
|
|
@@ -479,7 +477,7 @@ const store = createStore();
|
|
|
479
477
|
</template>
|
|
480
478
|
```
|
|
481
479
|
|
|
482
|
-
Alternatively, use **`defineComponent({ async setup() { ... } })`** and `await
|
|
480
|
+
Alternatively, use **`defineComponent({ async setup() { ... } })`** and `await useAtomValue(slowAtom)` before returning the render function — the same pattern as in `test/vue/hooks.test.ts`. `useAtom` is also awaitable: `const [ref, set] = await useAtom(writableAtom)`.
|
|
483
481
|
|
|
484
482
|
## External Invalidation
|
|
485
483
|
|
|
@@ -608,12 +606,12 @@ type Writable = IsWritable<typeof countAtom>; // → true | false
|
|
|
608
606
|
|
|
609
607
|
## Package Structure
|
|
610
608
|
|
|
611
|
-
| Import | Contents
|
|
612
|
-
| -------------------------- |
|
|
613
|
-
| `@kdeveloper/kvark` | `atom`, `createStore`, all types
|
|
614
|
-
| `@kdeveloper/kvark/react` | `Provider`, `useStore`, `useAtomValue`, `useSetAtom`, `useAtom`, `useAtomContext`
|
|
615
|
-
| `@kdeveloper/kvark/vue` | `Provider`, `useStore`, `useAtomValue`, `useSetAtom`, `useAtom`, `useAtomContext`
|
|
616
|
-
| `@kdeveloper/kvark/family` | `atomFamily`, `stableFamilyKey`, re-exports `atom` / `createStore` and core types
|
|
609
|
+
| Import | Contents |
|
|
610
|
+
| -------------------------- | --------------------------------------------------------------------------------- |
|
|
611
|
+
| `@kdeveloper/kvark` | `atom`, `createStore`, all types |
|
|
612
|
+
| `@kdeveloper/kvark/react` | `Provider`, `useStore`, `useAtomValue`, `useSetAtom`, `useAtom`, `useAtomContext` |
|
|
613
|
+
| `@kdeveloper/kvark/vue` | `Provider`, `useStore`, `useAtomValue`, `useSetAtom`, `useAtom`, `useAtomContext` |
|
|
614
|
+
| `@kdeveloper/kvark/family` | `atomFamily`, `stableFamilyKey`, re-exports `atom` / `createStore` and core types |
|
|
617
615
|
|
|
618
616
|
The core (`@kdeveloper/kvark`) has **zero runtime dependencies**. **React** and **Vue** are optional peer dependencies — install the framework you use and import from `/react` or `/vue`.
|
|
619
617
|
|
package/dist/vue/index.d.mts
CHANGED
|
@@ -24,19 +24,21 @@ type ObservedValue<V> = {
|
|
|
24
24
|
isStale: boolean;
|
|
25
25
|
error: unknown;
|
|
26
26
|
};
|
|
27
|
-
|
|
27
|
+
type ThenableShallowRef<V> = Readonly<ShallowRef<V>> & PromiseLike<Readonly<ShallowRef<V>>>;
|
|
28
|
+
declare function useAtomValue<V>(atom: Atom<V>): ThenableShallowRef<V>;
|
|
28
29
|
declare function useAtomValue<V>(atom: Atom<V>, opts: {
|
|
29
30
|
observe: true;
|
|
30
|
-
}):
|
|
31
|
+
}): ThenableShallowRef<ObservedValue<V>>;
|
|
31
32
|
//#endregion
|
|
32
33
|
//#region src/vue/use-set-atom.d.ts
|
|
33
34
|
declare function useSetAtom<V, A extends readonly unknown[]>(atom: WritableAtom<V, A>): (...args: A) => Promise<void>;
|
|
34
35
|
//#endregion
|
|
35
36
|
//#region src/vue/use-atom.d.ts
|
|
36
|
-
|
|
37
|
+
type ThenableAtomTuple<V, A extends readonly unknown[]> = readonly [ThenableShallowRef<V>, (...args: A) => Promise<void>] & PromiseLike<readonly [ThenableShallowRef<V>, (...args: A) => Promise<void>]>;
|
|
38
|
+
declare function useAtom<V, A extends readonly unknown[]>(atom: WritableAtom<V, A>): ThenableAtomTuple<V, A>;
|
|
37
39
|
//#endregion
|
|
38
40
|
//#region src/vue/use-atom-context.d.ts
|
|
39
41
|
declare function useAtomContext<R>(callback: (ctx: StoreClient) => Promise<R>): () => Promise<R>;
|
|
40
42
|
//#endregion
|
|
41
|
-
export { Provider, useAtom, useAtomContext, useAtomValue, useSetAtom, useStore };
|
|
43
|
+
export { Provider, type ThenableShallowRef, useAtom, useAtomContext, useAtomValue, useSetAtom, useStore };
|
|
42
44
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/vue/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/vue/provider.ts","../../src/vue/use-atom-value.ts","../../src/vue/use-set-atom.ts","../../src/vue/use-atom.ts","../../src/vue/use-atom-context.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/vue/provider.ts","../../src/vue/use-atom-value.ts","../../src/vue/use-set-atom.ts","../../src/vue/use-atom.ts","../../src/vue/use-atom-context.ts"],"mappings":";;;;;cAKa,QAAA,QAAQ,eAAA,CAGgB,KAAA,CAHhB,gBAAA;;UAGQ,QAAA,CAAS,KAAA;;;sBAHjB,KAAA,CAAA,YAAA;;gIAGgB,KAAA,CAAA,gBAAA;;UAAR,QAAA,CAAS,KAAA;;;;iBAQtB,QAAA,CAAA,GAAY,KAAA;;;KCZvB,aAAA;EACH,KAAA,EAAO,CAAA;EACP,OAAA;EACA,KAAA;AAAA;AAAA,KAGU,kBAAA,MAAwB,QAAA,CAAS,UAAA,CAAW,CAAA,KAAM,WAAA,CAAY,QAAA,CAAS,UAAA,CAAW,CAAA;AAAA,iBAE9E,YAAA,GAAA,CAAgB,IAAA,EAAM,IAAA,CAAK,CAAA,IAAK,kBAAA,CAAmB,CAAA;AAAA,iBACnD,YAAA,GAAA,CACd,IAAA,EAAM,IAAA,CAAK,CAAA,GACX,IAAA;EAAQ,OAAA;AAAA,IACP,kBAAA,CAAmB,aAAA,CAAc,CAAA;;;iBCbpB,UAAA,iCAAA,CACd,IAAA,EAAM,YAAA,CAAa,CAAA,EAAG,CAAA,QACjB,IAAA,EAAM,CAAA,KAAM,OAAA;;;KCDd,iBAAA,8CACH,kBAAA,CAAmB,CAAA,OACf,IAAA,EAAM,CAAA,KAAM,OAAA,UAEhB,WAAA,WAAsB,kBAAA,CAAmB,CAAA,OAAQ,IAAA,EAAM,CAAA,KAAM,OAAA;AAAA,iBAE/C,OAAA,iCAAA,CACd,IAAA,EAAM,YAAA,CAAa,CAAA,EAAG,CAAA,IACrB,iBAAA,CAAkB,CAAA,EAAG,CAAA;;;iBCTR,cAAA,GAAA,CAAkB,QAAA,GAAW,GAAA,EAAK,WAAA,KAAgB,OAAA,CAAQ,CAAA,UAAW,OAAA,CAAQ,CAAA"}
|
package/dist/vue/index.mjs
CHANGED
|
@@ -61,7 +61,11 @@ function useAtomValue(atom, opts) {
|
|
|
61
61
|
result.value = derive(store.getSnapshot(atom));
|
|
62
62
|
}));
|
|
63
63
|
});
|
|
64
|
-
|
|
64
|
+
const ref = readonly(result);
|
|
65
|
+
return new Proxy(ref, { get(target, prop, receiver) {
|
|
66
|
+
if (prop === "then") return (onFulfilled, onRejected) => store.resolve(atom).then(() => ref, onRejected).then(onFulfilled);
|
|
67
|
+
return Reflect.get(target, prop, receiver);
|
|
68
|
+
} });
|
|
65
69
|
}
|
|
66
70
|
//#endregion
|
|
67
71
|
//#region src/vue/use-set-atom.ts
|
|
@@ -72,7 +76,11 @@ function useSetAtom(atom) {
|
|
|
72
76
|
//#endregion
|
|
73
77
|
//#region src/vue/use-atom.ts
|
|
74
78
|
function useAtom(atom) {
|
|
75
|
-
|
|
79
|
+
const value = useAtomValue(atom);
|
|
80
|
+
const setter = useSetAtom(atom);
|
|
81
|
+
return Object.assign([value, setter], { then(onFulfilled, onRejected) {
|
|
82
|
+
return Promise.resolve(value).then(() => [value, setter], onRejected).then(onFulfilled);
|
|
83
|
+
} });
|
|
76
84
|
}
|
|
77
85
|
//#endregion
|
|
78
86
|
//#region src/vue/use-atom-context.ts
|
package/dist/vue/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/vue/provider.ts","../../src/vue/use-atom-value.ts","../../src/vue/use-set-atom.ts","../../src/vue/use-atom.ts","../../src/vue/use-atom-context.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/vue/provider.ts","../../src/vue/use-atom-value.ts","../../src/vue/use-set-atom.ts","../../src/vue/use-atom.ts","../../src/vue/use-atom-context.ts"],"sourcesContent":["import { type InjectionKey, type PropType, defineComponent, inject, provide } from \"vue\";\nimport { Store } from \"@/internal/store.js\";\n\nconst StoreKey: InjectionKey<Store> = Symbol(\"kvark-store\");\n\nexport const Provider = defineComponent({\n name: \"KvarkProvider\",\n props: {\n store: { type: Object as PropType<Store>, required: true },\n },\n setup(props, { slots }) {\n provide(StoreKey, props.store);\n return () => slots[\"default\"]?.();\n },\n});\n\nexport function useStore(): Store {\n const store = inject(StoreKey);\n if (store == null) {\n throw new Error(\"useStore must be used within a <Provider>\");\n }\n return store;\n}\n","import { type ShallowRef, readonly, shallowRef, watchEffect } from \"vue\";\nimport type { Atom, AtomState } from \"@/internal/types.js\";\nimport { useStore } from \"@/vue/provider.js\";\n\ntype ObservedValue<V> = {\n value: V;\n isStale: boolean;\n error: unknown;\n};\n\nexport type ThenableShallowRef<V> = Readonly<ShallowRef<V>> & PromiseLike<Readonly<ShallowRef<V>>>;\n\nexport function useAtomValue<V>(atom: Atom<V>): ThenableShallowRef<V>;\nexport function useAtomValue<V>(\n atom: Atom<V>,\n opts: { observe: true },\n): ThenableShallowRef<ObservedValue<V>>;\nexport function useAtomValue<V>(\n atom: Atom<V>,\n opts?: { observe: true },\n): ThenableShallowRef<V | ObservedValue<V>> {\n const store = useStore();\n\n function derive(snapshot: AtomState<V>): V | ObservedValue<V> {\n if (snapshot.status === \"pending\") {\n void store.resolve(atom);\n if (opts?.observe === true) {\n return { value: undefined as V, isStale: false, error: undefined };\n }\n return undefined as V;\n }\n\n if (snapshot.status === \"stale\") {\n void store.resolve(atom);\n if (opts?.observe === true) {\n return { value: snapshot.value, isStale: true, error: undefined };\n }\n return snapshot.value;\n }\n\n if (snapshot.status === \"error\") {\n if (opts?.observe === true && snapshot.value !== undefined) {\n return { value: snapshot.value as V, isStale: false, error: snapshot.error };\n }\n throw snapshot.error;\n }\n\n // status === \"fresh\"\n if (opts?.observe === true) {\n return { value: snapshot.value, isStale: false, error: undefined };\n }\n return snapshot.value;\n }\n\n const result = shallowRef(derive(store.getSnapshot(atom)));\n\n watchEffect((onCleanup) => {\n const unsub = store.subscribe(atom, () => {\n result.value = derive(store.getSnapshot(atom));\n });\n onCleanup(unsub);\n });\n\n const ref = readonly(result) as Readonly<ShallowRef<V | ObservedValue<V>>>;\n\n return new Proxy(ref, {\n get(target, prop, receiver) {\n if (prop === \"then\") {\n return (onFulfilled?: (v: typeof ref) => unknown, onRejected?: (e: unknown) => unknown) =>\n store\n .resolve(atom)\n .then(() => ref, onRejected)\n .then(onFulfilled as never);\n }\n return Reflect.get(target, prop, receiver);\n },\n }) as ThenableShallowRef<V | ObservedValue<V>>;\n}\n","import type { WritableAtom } from \"@/internal/types.js\";\nimport { useStore } from \"@/vue/provider.js\";\n\nexport function useSetAtom<V, A extends readonly unknown[]>(\n atom: WritableAtom<V, A>,\n): (...args: A) => Promise<void> {\n const store = useStore();\n return (...args: A): Promise<void> => store.set(atom, ...args);\n}\n","import type { WritableAtom } from \"@/internal/types.js\";\nimport { type ThenableShallowRef, useAtomValue } from \"@/vue/use-atom-value.js\";\nimport { useSetAtom } from \"@/vue/use-set-atom.js\";\n\ntype ThenableAtomTuple<V, A extends readonly unknown[]> = readonly [\n ThenableShallowRef<V>,\n (...args: A) => Promise<void>,\n] &\n PromiseLike<readonly [ThenableShallowRef<V>, (...args: A) => Promise<void>]>;\n\nexport function useAtom<V, A extends readonly unknown[]>(\n atom: WritableAtom<V, A>,\n): ThenableAtomTuple<V, A> {\n const value = useAtomValue(atom);\n const setter = useSetAtom(atom);\n const tuple = [value, setter] as const;\n\n return Object.assign(tuple, {\n then(onFulfilled?: (v: typeof tuple) => unknown, onRejected?: (e: unknown) => unknown) {\n return Promise.resolve(value)\n .then(() => [value, setter] as const, onRejected)\n .then(onFulfilled as never);\n },\n }) as ThenableAtomTuple<V, A>;\n}\n","import type { StoreClient } from \"@/internal/store.js\";\nimport { useStore } from \"@/vue/provider.js\";\n\nexport function useAtomContext<R>(callback: (ctx: StoreClient) => Promise<R>): () => Promise<R> {\n const store = useStore();\n return (): Promise<R> => callback(store.getClient());\n}\n"],"mappings":";;AAGA,MAAM,WAAgC,OAAO,cAAc;AAE3D,MAAa,WAAW,gBAAgB;CACtC,MAAM;CACN,OAAO,EACL,OAAO;EAAE,MAAM;EAA2B,UAAU;EAAM,EAC3D;CACD,MAAM,OAAO,EAAE,SAAS;AACtB,UAAQ,UAAU,MAAM,MAAM;AAC9B,eAAa,MAAM,cAAc;;CAEpC,CAAC;AAEF,SAAgB,WAAkB;CAChC,MAAM,QAAQ,OAAO,SAAS;AAC9B,KAAI,SAAS,KACX,OAAM,IAAI,MAAM,4CAA4C;AAE9D,QAAO;;;;ACJT,SAAgB,aACd,MACA,MAC0C;CAC1C,MAAM,QAAQ,UAAU;CAExB,SAAS,OAAO,UAA8C;AAC5D,MAAI,SAAS,WAAW,WAAW;AAC5B,SAAM,QAAQ,KAAK;AACxB,OAAI,MAAM,YAAY,KACpB,QAAO;IAAE,OAAO,KAAA;IAAgB,SAAS;IAAO,OAAO,KAAA;IAAW;AAEpE;;AAGF,MAAI,SAAS,WAAW,SAAS;AAC1B,SAAM,QAAQ,KAAK;AACxB,OAAI,MAAM,YAAY,KACpB,QAAO;IAAE,OAAO,SAAS;IAAO,SAAS;IAAM,OAAO,KAAA;IAAW;AAEnE,UAAO,SAAS;;AAGlB,MAAI,SAAS,WAAW,SAAS;AAC/B,OAAI,MAAM,YAAY,QAAQ,SAAS,UAAU,KAAA,EAC/C,QAAO;IAAE,OAAO,SAAS;IAAY,SAAS;IAAO,OAAO,SAAS;IAAO;AAE9E,SAAM,SAAS;;AAIjB,MAAI,MAAM,YAAY,KACpB,QAAO;GAAE,OAAO,SAAS;GAAO,SAAS;GAAO,OAAO,KAAA;GAAW;AAEpE,SAAO,SAAS;;CAGlB,MAAM,SAAS,WAAW,OAAO,MAAM,YAAY,KAAK,CAAC,CAAC;AAE1D,cAAa,cAAc;AAIzB,YAHc,MAAM,UAAU,YAAY;AACxC,UAAO,QAAQ,OAAO,MAAM,YAAY,KAAK,CAAC;IAC9C,CACc;GAChB;CAEF,MAAM,MAAM,SAAS,OAAO;AAE5B,QAAO,IAAI,MAAM,KAAK,EACpB,IAAI,QAAQ,MAAM,UAAU;AAC1B,MAAI,SAAS,OACX,SAAQ,aAA0C,eAChD,MACG,QAAQ,KAAK,CACb,WAAW,KAAK,WAAW,CAC3B,KAAK,YAAqB;AAEjC,SAAO,QAAQ,IAAI,QAAQ,MAAM,SAAS;IAE7C,CAAC;;;;ACzEJ,SAAgB,WACd,MAC+B;CAC/B,MAAM,QAAQ,UAAU;AACxB,SAAQ,GAAG,SAA2B,MAAM,IAAI,MAAM,GAAG,KAAK;;;;ACGhE,SAAgB,QACd,MACyB;CACzB,MAAM,QAAQ,aAAa,KAAK;CAChC,MAAM,SAAS,WAAW,KAAK;AAG/B,QAAO,OAAO,OAFA,CAAC,OAAO,OAAO,EAED,EAC1B,KAAK,aAA4C,YAAsC;AACrF,SAAO,QAAQ,QAAQ,MAAM,CAC1B,WAAW,CAAC,OAAO,OAAO,EAAW,WAAW,CAChD,KAAK,YAAqB;IAEhC,CAAC;;;;ACpBJ,SAAgB,eAAkB,UAA8D;CAC9F,MAAM,QAAQ,UAAU;AACxB,cAAyB,SAAS,MAAM,WAAW,CAAC"}
|