@diphyx/harlemify 5.0.0 → 5.1.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 +31 -41
- package/dist/module.json +1 -1
- package/dist/runtime/composables/action.d.ts +16 -3
- package/dist/runtime/composables/action.js +47 -3
- package/dist/runtime/composables/model.d.ts +22 -0
- package/dist/runtime/composables/model.js +32 -0
- package/dist/runtime/composables/view.d.ts +33 -0
- package/dist/runtime/composables/view.js +54 -0
- package/dist/runtime/core/types/action.d.ts +2 -3
- package/dist/runtime/core/utils/action.js +2 -8
- package/dist/runtime/core/utils/base.d.ts +10 -0
- package/dist/runtime/core/utils/base.js +86 -1
- package/dist/runtime/index.d.ts +6 -1
- package/dist/runtime/index.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
> Factory-driven state management for Nuxt powered by [Harlem](https://harlemjs.com/)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Define your data **shape** once with Zod — get typed **models**, computed **views**, and async **actions** with a single `createStore` call.
|
|
6
6
|
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **SSR
|
|
7
|
+
- **Schema-first** — Define your data shape once, get TypeScript types and validation automatically
|
|
8
|
+
- **Reactive state** — Single items and collections with built-in mutations
|
|
9
|
+
- **Computed views** — Derived read-only state that updates when models change
|
|
10
|
+
- **API integration** — Declarative HTTP actions that fetch and commit data in one step
|
|
11
|
+
- **Status tracking** — Every action exposes loading, error, and status reactively
|
|
12
|
+
- **Concurrency control** — Block, skip, cancel, or allow parallel calls per action
|
|
13
|
+
- **Vue composables** — Reactive helpers for actions, models, and views in components
|
|
14
|
+
- **SSR ready** — Server-side rendering with automatic state hydration
|
|
15
15
|
|
|
16
16
|
## Install
|
|
17
17
|
|
|
@@ -19,37 +19,23 @@
|
|
|
19
19
|
npm install @diphyx/harlemify
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
## Setup
|
|
23
|
-
|
|
24
22
|
```typescript
|
|
25
23
|
// nuxt.config.ts
|
|
26
24
|
export default defineNuxtConfig({
|
|
27
25
|
modules: ["@diphyx/harlemify"],
|
|
28
|
-
harlemify: {
|
|
29
|
-
action: {
|
|
30
|
-
endpoint: "https://api.example.com",
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
26
|
});
|
|
34
27
|
```
|
|
35
28
|
|
|
36
29
|
## Usage
|
|
37
30
|
|
|
38
31
|
```typescript
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}),
|
|
47
|
-
name: factory.string(),
|
|
48
|
-
email: factory.email(),
|
|
49
|
-
};
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
export type User = ShapeInfer<typeof userShape>;
|
|
32
|
+
const userShape = shape((factory) => ({
|
|
33
|
+
id: factory.number().meta({
|
|
34
|
+
identifier: true,
|
|
35
|
+
}),
|
|
36
|
+
name: factory.string(),
|
|
37
|
+
email: factory.email(),
|
|
38
|
+
}));
|
|
53
39
|
|
|
54
40
|
export const userStore = createStore({
|
|
55
41
|
name: "users",
|
|
@@ -65,13 +51,17 @@ export const userStore = createStore({
|
|
|
65
51
|
users: from("list"),
|
|
66
52
|
};
|
|
67
53
|
},
|
|
68
|
-
action({ api
|
|
54
|
+
action({ api }) {
|
|
69
55
|
return {
|
|
70
|
-
list: api.get(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
56
|
+
list: api.get(
|
|
57
|
+
{
|
|
58
|
+
url: "/users",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
model: "list",
|
|
62
|
+
mode: ModelManyMode.SET,
|
|
63
|
+
},
|
|
64
|
+
),
|
|
75
65
|
};
|
|
76
66
|
},
|
|
77
67
|
});
|
|
@@ -79,15 +69,15 @@ export const userStore = createStore({
|
|
|
79
69
|
|
|
80
70
|
```vue
|
|
81
71
|
<script setup>
|
|
82
|
-
const {
|
|
72
|
+
const { execute, loading } = useStoreAction(userStore, "list");
|
|
73
|
+
const { data } = useStoreView(userStore, "users");
|
|
83
74
|
|
|
84
|
-
await
|
|
75
|
+
await execute();
|
|
85
76
|
</script>
|
|
86
77
|
|
|
87
78
|
<template>
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
<li v-for="user in view.users.value" :key="user.id">{{ user.name }}</li>
|
|
79
|
+
<ul v-if="!loading">
|
|
80
|
+
<li v-for="user in data.value" :key="user.id">{{ user.name }}</li>
|
|
91
81
|
</ul>
|
|
92
82
|
</template>
|
|
93
83
|
```
|
package/dist/module.json
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
import { type Ref } from "vue";
|
|
2
|
-
import { ActionStatus } from "../core/types/action.js";
|
|
3
|
-
export
|
|
1
|
+
import { type ComputedRef, type Ref } from "vue";
|
|
2
|
+
import { ActionStatus, type ActionCall, type ActionCallOptions } from "../core/types/action.js";
|
|
3
|
+
export interface UseStoreActionOptions {
|
|
4
|
+
isolated?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export type UseStoreAction<T> = {
|
|
7
|
+
execute: (options?: ActionCallOptions) => Promise<T>;
|
|
8
|
+
error: Readonly<Ref<Error | null>>;
|
|
9
|
+
status: Readonly<Ref<ActionStatus>>;
|
|
10
|
+
loading: ComputedRef<boolean>;
|
|
11
|
+
reset: () => void;
|
|
12
|
+
};
|
|
4
13
|
export declare function useIsolatedActionError(): Ref<Error | null>;
|
|
14
|
+
export declare function useIsolatedActionStatus(): Ref<ActionStatus>;
|
|
15
|
+
export declare function useStoreAction<A extends Record<string, ActionCall>, K extends keyof A & string, T = Awaited<ReturnType<A[K]>>>(store: {
|
|
16
|
+
action: A;
|
|
17
|
+
}, key: K, options?: UseStoreActionOptions): UseStoreAction<T>;
|
|
@@ -1,8 +1,52 @@
|
|
|
1
|
-
import { ref } from "vue";
|
|
1
|
+
import { ref, computed } from "vue";
|
|
2
2
|
import { ActionStatus } from "../core/types/action.js";
|
|
3
|
+
export function useIsolatedActionError() {
|
|
4
|
+
return ref(null);
|
|
5
|
+
}
|
|
3
6
|
export function useIsolatedActionStatus() {
|
|
4
7
|
return ref(ActionStatus.IDLE);
|
|
5
8
|
}
|
|
6
|
-
export function
|
|
7
|
-
|
|
9
|
+
export function useStoreAction(store, key, options) {
|
|
10
|
+
const action = store.action[key];
|
|
11
|
+
if (!action) {
|
|
12
|
+
throw new Error(`Action "${key}" not found in store`);
|
|
13
|
+
}
|
|
14
|
+
let error;
|
|
15
|
+
let status;
|
|
16
|
+
let loading;
|
|
17
|
+
let reset;
|
|
18
|
+
if (options?.isolated) {
|
|
19
|
+
const isolatedError = useIsolatedActionError();
|
|
20
|
+
const isolatedStatus = useIsolatedActionStatus();
|
|
21
|
+
error = isolatedError;
|
|
22
|
+
status = isolatedStatus;
|
|
23
|
+
loading = computed(() => {
|
|
24
|
+
return isolatedStatus.value === ActionStatus.PENDING;
|
|
25
|
+
});
|
|
26
|
+
reset = () => {
|
|
27
|
+
isolatedStatus.value = ActionStatus.IDLE;
|
|
28
|
+
isolatedError.value = null;
|
|
29
|
+
};
|
|
30
|
+
} else {
|
|
31
|
+
error = action.error;
|
|
32
|
+
status = action.status;
|
|
33
|
+
loading = action.loading;
|
|
34
|
+
reset = action.reset;
|
|
35
|
+
}
|
|
36
|
+
function execute(callOptions = {}) {
|
|
37
|
+
if (options?.isolated) {
|
|
38
|
+
callOptions.bind = {
|
|
39
|
+
status,
|
|
40
|
+
error
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return action(callOptions);
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
execute,
|
|
47
|
+
error,
|
|
48
|
+
status,
|
|
49
|
+
loading,
|
|
50
|
+
reset
|
|
51
|
+
};
|
|
8
52
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ModelCall, ModelOneCall, ModelManyCall, ModelOneCommit, ModelManyCommit, StoreModel, ModelDefinitions } from "../core/types/model.js";
|
|
2
|
+
export interface UseStoreModelOptions {
|
|
3
|
+
debounce?: number;
|
|
4
|
+
throttle?: number;
|
|
5
|
+
}
|
|
6
|
+
type UseStoreModelOne<C extends ModelOneCommit<any>> = {
|
|
7
|
+
set: C["set"];
|
|
8
|
+
reset: C["reset"];
|
|
9
|
+
patch: C["patch"];
|
|
10
|
+
};
|
|
11
|
+
type UseStoreModelMany<C extends ModelManyCommit<any>> = {
|
|
12
|
+
set: C["set"];
|
|
13
|
+
reset: C["reset"];
|
|
14
|
+
patch: C["patch"];
|
|
15
|
+
add: C["add"];
|
|
16
|
+
remove: C["remove"];
|
|
17
|
+
};
|
|
18
|
+
export type UseStoreModel<M extends ModelCall<any> = ModelCall<any>> = M extends ModelManyCall<infer S> ? UseStoreModelMany<ModelManyCommit<S>> : M extends ModelOneCall<infer S> ? UseStoreModelOne<ModelOneCommit<S>> : never;
|
|
19
|
+
export declare function useStoreModel<M extends StoreModel<ModelDefinitions>, K extends keyof M & string>(store: {
|
|
20
|
+
model: M;
|
|
21
|
+
}, key: K, options?: UseStoreModelOptions): UseStoreModel<M[K]>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { debounce, throttle } from "../core/utils/base.js";
|
|
2
|
+
function isMany(model) {
|
|
3
|
+
return "add" in model && typeof model.add === "function";
|
|
4
|
+
}
|
|
5
|
+
function wrapCommit(commit, options) {
|
|
6
|
+
if (options?.debounce) {
|
|
7
|
+
return debounce(commit, options.debounce);
|
|
8
|
+
}
|
|
9
|
+
if (options?.throttle) {
|
|
10
|
+
return throttle(commit, options.throttle);
|
|
11
|
+
}
|
|
12
|
+
return commit;
|
|
13
|
+
}
|
|
14
|
+
export function useStoreModel(store, key, options) {
|
|
15
|
+
const model = store.model[key];
|
|
16
|
+
if (!model) {
|
|
17
|
+
throw new Error(`Model "${key}" not found in store`);
|
|
18
|
+
}
|
|
19
|
+
let output = {
|
|
20
|
+
set: wrapCommit(model.set.bind(model), options),
|
|
21
|
+
reset: wrapCommit(model.reset.bind(model), options),
|
|
22
|
+
patch: wrapCommit(model.patch.bind(model), options)
|
|
23
|
+
};
|
|
24
|
+
if (isMany(model)) {
|
|
25
|
+
output = {
|
|
26
|
+
...output,
|
|
27
|
+
add: wrapCommit(model.add.bind(model), options),
|
|
28
|
+
remove: wrapCommit(model.remove.bind(model), options)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return output;
|
|
32
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ComputedRef, type WatchStopHandle } from "vue";
|
|
2
|
+
import type { ViewCall } from "../core/types/view.js";
|
|
3
|
+
export interface UseStoreViewTrackOptions {
|
|
4
|
+
deep?: boolean;
|
|
5
|
+
immediate?: boolean;
|
|
6
|
+
debounce?: number;
|
|
7
|
+
throttle?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface UseStoreViewOptions<T> {
|
|
10
|
+
proxy?: boolean;
|
|
11
|
+
default?: T;
|
|
12
|
+
}
|
|
13
|
+
export type UseStoreViewData<T> = {
|
|
14
|
+
value: T;
|
|
15
|
+
} & (T extends Record<string, unknown> ? {
|
|
16
|
+
[K in keyof T]: T[K];
|
|
17
|
+
} : Record<string, unknown>);
|
|
18
|
+
export type UseStoreViewProxy<T> = {
|
|
19
|
+
data: UseStoreViewData<T>;
|
|
20
|
+
track: (handler: (value: T) => void, options?: UseStoreViewTrackOptions) => WatchStopHandle;
|
|
21
|
+
};
|
|
22
|
+
export type UseStoreViewComputed<T> = {
|
|
23
|
+
data: ComputedRef<T>;
|
|
24
|
+
track: (handler: (value: T) => void, options?: UseStoreViewTrackOptions) => WatchStopHandle;
|
|
25
|
+
};
|
|
26
|
+
export declare function useStoreView<V extends Record<string, ViewCall>, K extends keyof V & string, T = V[K] extends ComputedRef<infer R> ? R : unknown>(store: {
|
|
27
|
+
view: V;
|
|
28
|
+
}, key: K, options: UseStoreViewOptions<T> & {
|
|
29
|
+
proxy: false;
|
|
30
|
+
}): UseStoreViewComputed<T>;
|
|
31
|
+
export declare function useStoreView<V extends Record<string, ViewCall>, K extends keyof V & string, T = V[K] extends ComputedRef<infer R> ? R : unknown>(store: {
|
|
32
|
+
view: V;
|
|
33
|
+
}, key: K, options?: UseStoreViewOptions<T>): UseStoreViewProxy<T>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { computed, watch } from "vue";
|
|
2
|
+
import { debounce, throttle, toReactiveProxy } from "../core/utils/base.js";
|
|
3
|
+
function resolveDefault(view, defaultValue) {
|
|
4
|
+
if (defaultValue === void 0) {
|
|
5
|
+
return view;
|
|
6
|
+
}
|
|
7
|
+
return computed(() => {
|
|
8
|
+
const value = view.value;
|
|
9
|
+
if (value == null) {
|
|
10
|
+
return defaultValue;
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function resolveData(source, proxy) {
|
|
16
|
+
if (proxy !== false) {
|
|
17
|
+
return toReactiveProxy(source);
|
|
18
|
+
}
|
|
19
|
+
return source;
|
|
20
|
+
}
|
|
21
|
+
export function useStoreView(store, key, options) {
|
|
22
|
+
if (!store.view[key]) {
|
|
23
|
+
throw new Error(`View "${key}" not found in store`);
|
|
24
|
+
}
|
|
25
|
+
const source = resolveDefault(store.view[key], options?.default);
|
|
26
|
+
const data = resolveData(source, options?.proxy);
|
|
27
|
+
function resolveCallback(callback, callbackOptions) {
|
|
28
|
+
if (callbackOptions?.debounce) {
|
|
29
|
+
return debounce(callback, callbackOptions.debounce);
|
|
30
|
+
}
|
|
31
|
+
if (callbackOptions?.throttle) {
|
|
32
|
+
return throttle(callback, callbackOptions.throttle);
|
|
33
|
+
}
|
|
34
|
+
return callback;
|
|
35
|
+
}
|
|
36
|
+
function track(handler, trackOptions) {
|
|
37
|
+
const callback = resolveCallback(handler, trackOptions);
|
|
38
|
+
const stop = watch(
|
|
39
|
+
source,
|
|
40
|
+
(value) => {
|
|
41
|
+
callback(value);
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
deep: trackOptions?.deep,
|
|
45
|
+
immediate: trackOptions?.immediate
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
return stop;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
data,
|
|
52
|
+
track
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -114,9 +114,8 @@ export interface ActionCallOptions {
|
|
|
114
114
|
}
|
|
115
115
|
export interface ActionCall<T = void> {
|
|
116
116
|
(options?: ActionCallOptions): Promise<T>;
|
|
117
|
-
readonly loading: ComputedRef<boolean>;
|
|
118
|
-
readonly status: Readonly<Ref<ActionStatus>>;
|
|
119
117
|
readonly error: Readonly<Ref<Error | null>>;
|
|
120
|
-
readonly
|
|
118
|
+
readonly status: Readonly<Ref<ActionStatus>>;
|
|
119
|
+
readonly loading: ComputedRef<boolean>;
|
|
121
120
|
reset: () => void;
|
|
122
121
|
}
|
|
@@ -204,7 +204,6 @@ export function createAction(definition, model, view) {
|
|
|
204
204
|
});
|
|
205
205
|
let currentController = null;
|
|
206
206
|
let abortController = null;
|
|
207
|
-
let globalData = null;
|
|
208
207
|
const globalError = ref(null);
|
|
209
208
|
const globalStatus = ref(ActionStatus.IDLE);
|
|
210
209
|
const loading = computed(() => {
|
|
@@ -270,7 +269,6 @@ export function createAction(definition, model, view) {
|
|
|
270
269
|
} else {
|
|
271
270
|
data = await executeHandler(definition, model, view);
|
|
272
271
|
}
|
|
273
|
-
globalData = data;
|
|
274
272
|
activeStatus.value = ActionStatus.SUCCESS;
|
|
275
273
|
definition.logger?.debug("Action success", {
|
|
276
274
|
action: definition.key
|
|
@@ -288,22 +286,18 @@ export function createAction(definition, model, view) {
|
|
|
288
286
|
return currentController;
|
|
289
287
|
}
|
|
290
288
|
const action = Object.assign(execute, {
|
|
291
|
-
get loading() {
|
|
292
|
-
return loading;
|
|
293
|
-
},
|
|
294
289
|
get error() {
|
|
295
290
|
return readonly(globalError);
|
|
296
291
|
},
|
|
297
292
|
get status() {
|
|
298
293
|
return readonly(globalStatus);
|
|
299
294
|
},
|
|
300
|
-
get
|
|
301
|
-
return
|
|
295
|
+
get loading() {
|
|
296
|
+
return loading;
|
|
302
297
|
},
|
|
303
298
|
reset() {
|
|
304
299
|
globalError.value = null;
|
|
305
300
|
globalStatus.value = ActionStatus.IDLE;
|
|
306
|
-
globalData = null;
|
|
307
301
|
}
|
|
308
302
|
});
|
|
309
303
|
return action;
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
export declare function trimStart(value: string, char: string): string;
|
|
2
2
|
export declare function trimEnd(value: string, char: string): string;
|
|
3
|
+
export declare function isObject(value: unknown): value is object;
|
|
3
4
|
export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
4
5
|
export declare function isEmptyRecord(record: Record<string, unknown> | undefined): record is undefined;
|
|
6
|
+
type ReferenceProxy<T> = {
|
|
7
|
+
value: T;
|
|
8
|
+
} & Record<string | symbol, unknown>;
|
|
9
|
+
export declare function toReactiveProxy<T>(reference: {
|
|
10
|
+
value: T;
|
|
11
|
+
}): ReferenceProxy<T>;
|
|
12
|
+
export declare function debounce<T extends (...args: any[]) => any>(callback: T, delay: number): T;
|
|
13
|
+
export declare function throttle<T extends (...args: any[]) => any>(callback: T, delay: number): T;
|
|
14
|
+
export {};
|
|
@@ -4,8 +4,11 @@ export function trimStart(value, char) {
|
|
|
4
4
|
export function trimEnd(value, char) {
|
|
5
5
|
return value.replace(new RegExp(`${char}+$`), "");
|
|
6
6
|
}
|
|
7
|
+
export function isObject(value) {
|
|
8
|
+
return value != null && typeof value === "object";
|
|
9
|
+
}
|
|
7
10
|
export function isPlainObject(value) {
|
|
8
|
-
if (!value
|
|
11
|
+
if (!isObject(value)) {
|
|
9
12
|
return false;
|
|
10
13
|
}
|
|
11
14
|
if (Array.isArray(value)) {
|
|
@@ -22,3 +25,85 @@ export function isEmptyRecord(record) {
|
|
|
22
25
|
}
|
|
23
26
|
return false;
|
|
24
27
|
}
|
|
28
|
+
export function toReactiveProxy(reference) {
|
|
29
|
+
function get(_target, prop) {
|
|
30
|
+
if (prop === "value") {
|
|
31
|
+
return reference.value;
|
|
32
|
+
}
|
|
33
|
+
if (!isObject(reference.value)) {
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
return reference.value[prop];
|
|
37
|
+
}
|
|
38
|
+
function has(_target, prop) {
|
|
39
|
+
if (prop === "value") {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
if (!isObject(reference.value)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return prop in reference.value;
|
|
46
|
+
}
|
|
47
|
+
function ownKeys() {
|
|
48
|
+
if (!isObject(reference.value)) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
return Reflect.ownKeys(reference.value);
|
|
52
|
+
}
|
|
53
|
+
function getOwnPropertyDescriptor(_target, prop) {
|
|
54
|
+
if (!isObject(reference.value) || !(prop in reference.value)) {
|
|
55
|
+
return void 0;
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
configurable: true,
|
|
59
|
+
enumerable: true,
|
|
60
|
+
value: reference.value[prop]
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return new Proxy(
|
|
64
|
+
{},
|
|
65
|
+
{
|
|
66
|
+
get,
|
|
67
|
+
has,
|
|
68
|
+
ownKeys,
|
|
69
|
+
getOwnPropertyDescriptor
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
export function debounce(callback, delay) {
|
|
74
|
+
let timer = null;
|
|
75
|
+
return (...args) => {
|
|
76
|
+
if (timer) {
|
|
77
|
+
clearTimeout(timer);
|
|
78
|
+
}
|
|
79
|
+
timer = setTimeout(() => {
|
|
80
|
+
timer = null;
|
|
81
|
+
callback(...args);
|
|
82
|
+
}, delay);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export function throttle(callback, delay) {
|
|
86
|
+
let lastCall = 0;
|
|
87
|
+
let timer = null;
|
|
88
|
+
return (...args) => {
|
|
89
|
+
const now = Date.now();
|
|
90
|
+
const remaining = delay - (now - lastCall);
|
|
91
|
+
if (remaining <= 0) {
|
|
92
|
+
if (timer) {
|
|
93
|
+
clearTimeout(timer);
|
|
94
|
+
timer = null;
|
|
95
|
+
}
|
|
96
|
+
lastCall = now;
|
|
97
|
+
callback(...args);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (timer) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
timer = setTimeout(() => {
|
|
104
|
+
lastCall = Date.now();
|
|
105
|
+
timer = null;
|
|
106
|
+
callback(...args);
|
|
107
|
+
}, remaining);
|
|
108
|
+
};
|
|
109
|
+
}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -9,5 +9,10 @@ export type { ViewDefinitionOptions } from "./core/types/view.js";
|
|
|
9
9
|
export { ActionStatus, ActionConcurrent, ActionApiMethod } from "./core/types/action.js";
|
|
10
10
|
export type { ActionCall, ActionCallOptions, ActionCallTransformerOptions, ActionCallBindOptions, ActionCallCommitOptions, ActionResolvedApi, } from "./core/types/action.js";
|
|
11
11
|
export { ActionApiError, ActionHandlerError, ActionCommitError, ActionConcurrentError } from "./core/utils/error.js";
|
|
12
|
-
export { useIsolatedActionStatus, useIsolatedActionError } from "./composables/action.js";
|
|
12
|
+
export { useIsolatedActionStatus, useIsolatedActionError, useStoreAction } from "./composables/action.js";
|
|
13
|
+
export type { UseStoreActionOptions, UseStoreAction } from "./composables/action.js";
|
|
14
|
+
export { useStoreModel } from "./composables/model.js";
|
|
15
|
+
export type { UseStoreModelOptions, UseStoreModel } from "./composables/model.js";
|
|
16
|
+
export { useStoreView } from "./composables/view.js";
|
|
17
|
+
export type { UseStoreViewOptions, UseStoreViewProxy, UseStoreViewComputed, UseStoreViewData, UseStoreViewTrackOptions, } from "./composables/view.js";
|
|
13
18
|
export type { RuntimeConfig } from "./config.js";
|
package/dist/runtime/index.js
CHANGED
|
@@ -4,4 +4,6 @@ export { ModelKind, ModelOneMode, ModelManyMode } from "./core/types/model.js";
|
|
|
4
4
|
export { ViewClone } from "./core/types/view.js";
|
|
5
5
|
export { ActionStatus, ActionConcurrent, ActionApiMethod } from "./core/types/action.js";
|
|
6
6
|
export { ActionApiError, ActionHandlerError, ActionCommitError, ActionConcurrentError } from "./core/utils/error.js";
|
|
7
|
-
export { useIsolatedActionStatus, useIsolatedActionError } from "./composables/action.js";
|
|
7
|
+
export { useIsolatedActionStatus, useIsolatedActionError, useStoreAction } from "./composables/action.js";
|
|
8
|
+
export { useStoreModel } from "./composables/model.js";
|
|
9
|
+
export { useStoreView } from "./composables/view.js";
|