@baklavue/mcp 1.0.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 +72 -0
- package/dist/data/component-categories.d.ts +7 -0
- package/dist/data/component-categories.js +48 -0
- package/dist/data/loaders.d.ts +22 -0
- package/dist/data/loaders.js +346 -0
- package/dist/docs/components/accordion.md +601 -0
- package/dist/docs/components/alert.md +233 -0
- package/dist/docs/components/badge.md +100 -0
- package/dist/docs/components/banner.md +231 -0
- package/dist/docs/components/button.md +324 -0
- package/dist/docs/components/checkbox.md +343 -0
- package/dist/docs/components/chip.md +199 -0
- package/dist/docs/components/datepicker.md +243 -0
- package/dist/docs/components/dialog.md +224 -0
- package/dist/docs/components/drawer.md +188 -0
- package/dist/docs/components/dropdown.md +291 -0
- package/dist/docs/components/file-upload.md +248 -0
- package/dist/docs/components/icon.md +142 -0
- package/dist/docs/components/image.md +161 -0
- package/dist/docs/components/index.md +151 -0
- package/dist/docs/components/input.md +407 -0
- package/dist/docs/components/link.md +249 -0
- package/dist/docs/components/notification.md +179 -0
- package/dist/docs/components/pagination.md +168 -0
- package/dist/docs/components/radio.md +221 -0
- package/dist/docs/components/scroll-to-top.md +90 -0
- package/dist/docs/components/select.md +239 -0
- package/dist/docs/components/skeleton.md +79 -0
- package/dist/docs/components/spinner.md +93 -0
- package/dist/docs/components/split-button.md +165 -0
- package/dist/docs/components/stepper.md +337 -0
- package/dist/docs/components/switch.md +144 -0
- package/dist/docs/components/tab.md +140 -0
- package/dist/docs/components/table.md +362 -0
- package/dist/docs/components/tag.md +243 -0
- package/dist/docs/components/textarea.md +190 -0
- package/dist/docs/components/tooltip.md +155 -0
- package/dist/docs/composables/alert.md +87 -0
- package/dist/docs/composables/asyncState.md +74 -0
- package/dist/docs/composables/base64.md +72 -0
- package/dist/docs/composables/breakpoints.md +129 -0
- package/dist/docs/composables/clipboard.md +108 -0
- package/dist/docs/composables/colorScheme.md +110 -0
- package/dist/docs/composables/confirmDialog.md +105 -0
- package/dist/docs/composables/containerScroll.md +89 -0
- package/dist/docs/composables/cookie.md +137 -0
- package/dist/docs/composables/debounce.md +69 -0
- package/dist/docs/composables/disclosure.md +69 -0
- package/dist/docs/composables/elementSize.md +84 -0
- package/dist/docs/composables/fetch.md +257 -0
- package/dist/docs/composables/fieldArray.md +104 -0
- package/dist/docs/composables/file.md +343 -0
- package/dist/docs/composables/focusTrap.md +87 -0
- package/dist/docs/composables/formPersistence.md +69 -0
- package/dist/docs/composables/formState.md +71 -0
- package/dist/docs/composables/formValidation.md +355 -0
- package/dist/docs/composables/format.md +107 -0
- package/dist/docs/composables/id.md +54 -0
- package/dist/docs/composables/index.md +112 -0
- package/dist/docs/composables/infiniteQuery.md +104 -0
- package/dist/docs/composables/intersectionObserver.md +64 -0
- package/dist/docs/composables/lazyQuery.md +68 -0
- package/dist/docs/composables/loading.md +91 -0
- package/dist/docs/composables/mutation.md +83 -0
- package/dist/docs/composables/notification.md +169 -0
- package/dist/docs/composables/pagination.md +109 -0
- package/dist/docs/composables/polling.md +76 -0
- package/dist/docs/composables/previous.md +58 -0
- package/dist/docs/composables/query.md +248 -0
- package/dist/docs/composables/raf.md +78 -0
- package/dist/docs/composables/scrollLock.md +46 -0
- package/dist/docs/composables/scrollToError.md +291 -0
- package/dist/docs/composables/scrollVisibility.md +60 -0
- package/dist/docs/composables/share.md +78 -0
- package/dist/docs/composables/slug.md +58 -0
- package/dist/docs/composables/stepper.md +117 -0
- package/dist/docs/composables/stepperForm.md +74 -0
- package/dist/docs/composables/sticky.md +91 -0
- package/dist/docs/composables/storage.md +193 -0
- package/dist/docs/composables/theme.md +252 -0
- package/dist/docs/composables/themePreset.md +62 -0
- package/dist/docs/composables/throttle.md +76 -0
- package/dist/docs/composables/timer.md +78 -0
- package/dist/docs/composables/toggle.md +55 -0
- package/dist/docs/guide/contributing.md +364 -0
- package/dist/docs/guide/design-tokens.md +29 -0
- package/dist/docs/guide/getting-started.md +181 -0
- package/dist/docs/guide/installation.md +287 -0
- package/dist/docs/guide/localization.md +132 -0
- package/dist/docs/guide/mcp.md +141 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +177 -0
- package/package.json +48 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# useInfiniteQuery
|
|
2
|
+
|
|
3
|
+
Composable for infinite scroll / cursor-based pagination. Fetches pages and accumulates them. Use with `useIntersectionObserver` for "load more" on scroll.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```vue
|
|
8
|
+
<script setup>
|
|
9
|
+
import { useInfiniteQuery } from "@baklavue/composables";
|
|
10
|
+
|
|
11
|
+
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({
|
|
12
|
+
queryKey: ["items"],
|
|
13
|
+
queryFn: ({ pageParam }) =>
|
|
14
|
+
fetch(`/api/items?cursor=${pageParam ?? ""}`).then((r) => r.json()),
|
|
15
|
+
initialPageParam: null,
|
|
16
|
+
getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined,
|
|
17
|
+
});
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<div>
|
|
22
|
+
<div v-for="(page, i) in data" :key="i">
|
|
23
|
+
<div v-for="item in page.items" :key="item.id">{{ item.name }}</div>
|
|
24
|
+
</div>
|
|
25
|
+
<button
|
|
26
|
+
:disabled="!hasNextPage || isFetchingNextPage"
|
|
27
|
+
@click="fetchNextPage()"
|
|
28
|
+
>
|
|
29
|
+
{{ isFetchingNextPage ? "Loading..." : "Load more" }}
|
|
30
|
+
</button>
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## With Intersection Observer
|
|
36
|
+
|
|
37
|
+
Load more when a sentinel element becomes visible:
|
|
38
|
+
|
|
39
|
+
```vue
|
|
40
|
+
<script setup>
|
|
41
|
+
import { useInfiniteQuery, useIntersectionObserver } from "@baklavue/composables";
|
|
42
|
+
|
|
43
|
+
const sentinel = ref(null);
|
|
44
|
+
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({
|
|
45
|
+
queryKey: ["items"],
|
|
46
|
+
queryFn: ({ pageParam }) =>
|
|
47
|
+
fetch(`/api/items?cursor=${pageParam ?? ""}`).then((r) => r.json()),
|
|
48
|
+
initialPageParam: null,
|
|
49
|
+
getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const isVisible = useIntersectionObserver(sentinel);
|
|
53
|
+
watch(isVisible, (visible) => {
|
|
54
|
+
if (visible && hasNextPage.value && !isFetchingNextPage.value) {
|
|
55
|
+
fetchNextPage();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<template>
|
|
61
|
+
<div>
|
|
62
|
+
<div v-for="(page, i) in data" :key="i">
|
|
63
|
+
<div v-for="item in page.items" :key="item.id">{{ item.name }}</div>
|
|
64
|
+
</div>
|
|
65
|
+
<div ref="sentinel" />
|
|
66
|
+
</div>
|
|
67
|
+
</template>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## API
|
|
71
|
+
|
|
72
|
+
### useInfiniteQuery
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
useInfiniteQuery<TData, TPageParam>(options): UseInfiniteQueryReturn<TData>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### Options
|
|
79
|
+
|
|
80
|
+
| Property | Type | Description |
|
|
81
|
+
| --- | --- | --- |
|
|
82
|
+
| `queryKey` | `MaybeRefOrGetter<QueryKey>` | Unique key for caching |
|
|
83
|
+
| `queryFn` | `(context: { queryKey, pageParam }) => Promise<TData>` | Async function that fetches a page |
|
|
84
|
+
| `initialPageParam` | `TPageParam` | Initial page param for first fetch |
|
|
85
|
+
| `getNextPageParam` | `(lastPage: TData) => TPageParam \| undefined` | Extract next page param |
|
|
86
|
+
| `getPreviousPageParam` | `(firstPage: TData) => TPageParam \| undefined` | For bidirectional infinite scroll |
|
|
87
|
+
| `enabled` | `MaybeRefOrGetter<boolean>` | If false, query won't run |
|
|
88
|
+
| `retry` | `number \| boolean` | Retries on error |
|
|
89
|
+
| `refetchOnWindowFocus` | `boolean` | Refetch when window regains focus |
|
|
90
|
+
| `refetchOnReconnect` | `boolean` | Refetch when network reconnects |
|
|
91
|
+
|
|
92
|
+
#### Return Value
|
|
93
|
+
|
|
94
|
+
| Property | Type | Description |
|
|
95
|
+
| --- | --- | --- |
|
|
96
|
+
| `data` | `Ref<TData[] \| null>` | Array of fetched pages |
|
|
97
|
+
| `error` | `Ref<Error \| null>` | Error if request failed |
|
|
98
|
+
| `isFetching` | `Ref<boolean>` | True while initial fetch or refetch |
|
|
99
|
+
| `isFetchingNextPage` | `Ref<boolean>` | True while fetching next page |
|
|
100
|
+
| `hasNextPage` | `Ref<boolean>` | True if more pages available |
|
|
101
|
+
| `hasPreviousPage` | `Ref<boolean>` | True if previous pages available |
|
|
102
|
+
| `fetchNextPage` | `() => Promise<void>` | Fetch the next page |
|
|
103
|
+
| `fetchPreviousPage` | `() => Promise<void>` | Fetch the previous page |
|
|
104
|
+
| `refetch` | `() => Promise<void>` | Refetch from first page |
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# useIntersectionObserver
|
|
2
|
+
|
|
3
|
+
Detects when a target element enters or leaves the viewport. Useful for lazy loading, scroll-triggered animations, and "in view" detection.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```vue
|
|
8
|
+
<template>
|
|
9
|
+
<div ref="target">
|
|
10
|
+
<p v-if="isVisible">This content is visible!</p>
|
|
11
|
+
</div>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup>
|
|
15
|
+
import { ref } from "vue";
|
|
16
|
+
import { useIntersectionObserver } from "@baklavue/composables";
|
|
17
|
+
|
|
18
|
+
const target = ref(null);
|
|
19
|
+
const isVisible = useIntersectionObserver(target, {
|
|
20
|
+
threshold: 0.5,
|
|
21
|
+
});
|
|
22
|
+
</script>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Lazy Loading
|
|
26
|
+
|
|
27
|
+
```vue
|
|
28
|
+
<template>
|
|
29
|
+
<div ref="target">
|
|
30
|
+
<img v-if="isVisible" :src="imageSrc" alt="Lazy loaded" />
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<script setup>
|
|
35
|
+
import { ref } from "vue";
|
|
36
|
+
import { useIntersectionObserver } from "@baklavue/composables";
|
|
37
|
+
|
|
38
|
+
const target = ref(null);
|
|
39
|
+
const isVisible = useIntersectionObserver(target, { threshold: 0 });
|
|
40
|
+
const imageSrc = ref("");
|
|
41
|
+
</script>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## API
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
useIntersectionObserver(
|
|
48
|
+
target: Ref<Element | null | undefined>,
|
|
49
|
+
options?: UseIntersectionObserverOptions
|
|
50
|
+
): Ref<boolean>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Options
|
|
54
|
+
|
|
55
|
+
| Property | Type | Default | Description |
|
|
56
|
+
| --- | --- | --- | --- |
|
|
57
|
+
| `root` | `Element \| Document \| null` | `null` | Root element (null = viewport) |
|
|
58
|
+
| `rootMargin` | `string` | `"0px"` | Margin around root |
|
|
59
|
+
| `threshold` | `number \| number[]` | `0` | Visibility threshold 0-1 |
|
|
60
|
+
| `immediate` | `boolean` | `true` | Start observing immediately |
|
|
61
|
+
|
|
62
|
+
### Return Value
|
|
63
|
+
|
|
64
|
+
Returns a `Ref<boolean>` that is `true` when the target is visible (intersecting).
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# useLazyQuery
|
|
2
|
+
|
|
3
|
+
Composable for lazy/on-demand queries. Does not fetch until `execute()` is called. Wraps `useQuery` with `enabled: false` initially.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```vue
|
|
8
|
+
<script setup>
|
|
9
|
+
import { ref } from "vue";
|
|
10
|
+
import { useLazyQuery } from "@baklavue/composables";
|
|
11
|
+
|
|
12
|
+
const userId = ref(1);
|
|
13
|
+
const { data, execute, isLoading } = useLazyQuery({
|
|
14
|
+
queryKey: () => ["user", userId.value],
|
|
15
|
+
queryFn: ({ queryKey }) =>
|
|
16
|
+
fetch(`/api/users/${queryKey[1]}`).then((r) => r.json()),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const handleLoad = () => execute();
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<div>
|
|
24
|
+
<button :disabled="isLoading" @click="handleLoad">Load User</button>
|
|
25
|
+
<div v-if="data">{{ data.name }}</div>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Await Result
|
|
31
|
+
|
|
32
|
+
`execute()` returns a promise that resolves when the fetch completes:
|
|
33
|
+
|
|
34
|
+
```vue
|
|
35
|
+
<script setup>
|
|
36
|
+
import { useLazyQuery } from "@baklavue/composables";
|
|
37
|
+
|
|
38
|
+
const { data, execute } = useLazyQuery({
|
|
39
|
+
queryKey: ["details"],
|
|
40
|
+
queryFn: () => fetch("/api/details").then((r) => r.json()),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const handleLoad = async () => {
|
|
44
|
+
await execute();
|
|
45
|
+
// data is now populated
|
|
46
|
+
};
|
|
47
|
+
</script>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## API
|
|
51
|
+
|
|
52
|
+
### useLazyQuery
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
useLazyQuery<T>(options: UseLazyQueryOptions<T>): UseLazyQueryReturn<T>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### Options
|
|
59
|
+
|
|
60
|
+
Same as `useQuery` except `enabled` is always `false` (query starts disabled).
|
|
61
|
+
|
|
62
|
+
#### Return Value
|
|
63
|
+
|
|
64
|
+
Same as `useQuery` plus:
|
|
65
|
+
|
|
66
|
+
| Property | Type | Description |
|
|
67
|
+
| --- | --- | --- |
|
|
68
|
+
| `execute` | `() => Promise<void>` | Execute the query. First call fetches, subsequent calls refetch. |
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# useLoading
|
|
2
|
+
|
|
3
|
+
A composable for generic loading state with optional delay to avoid flicker for fast operations. Use with BvSkeleton, BvSpinner, or loading overlays.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```vue
|
|
8
|
+
<template>
|
|
9
|
+
<div>
|
|
10
|
+
<BvSkeleton v-if="isLoading" variant="rectangle" />
|
|
11
|
+
<div v-else>{{ data }}</div>
|
|
12
|
+
<BvButton @click="fetchData" :loading="isLoading">Load</BvButton>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup>
|
|
17
|
+
import { BvButton, BvSkeleton } from "@baklavue/ui";
|
|
18
|
+
import { useLoading } from "@baklavue/composables";
|
|
19
|
+
|
|
20
|
+
const { isLoading, showLoading, hideLoading } = useLoading();
|
|
21
|
+
|
|
22
|
+
const fetchData = async () => {
|
|
23
|
+
showLoading();
|
|
24
|
+
try {
|
|
25
|
+
const res = await fetch("/api/data");
|
|
26
|
+
data.value = await res.json();
|
|
27
|
+
} finally {
|
|
28
|
+
hideLoading();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
</script>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## With Delay
|
|
35
|
+
|
|
36
|
+
```vue
|
|
37
|
+
<script setup>
|
|
38
|
+
import { useLoading } from "@baklavue/composables";
|
|
39
|
+
|
|
40
|
+
const { isLoading, showLoading, hideLoading } = useLoading({ delay: 200 });
|
|
41
|
+
|
|
42
|
+
// isLoading only becomes true after 200ms. Useful to avoid flicker for fast requests.
|
|
43
|
+
const quickFetch = async () => {
|
|
44
|
+
showLoading();
|
|
45
|
+
await api.getData();
|
|
46
|
+
hideLoading();
|
|
47
|
+
};
|
|
48
|
+
</script>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## With Async Wrapper
|
|
52
|
+
|
|
53
|
+
```vue
|
|
54
|
+
<script setup>
|
|
55
|
+
import { useLoading } from "@baklavue/composables";
|
|
56
|
+
|
|
57
|
+
const { isLoading, withLoading } = useLoading();
|
|
58
|
+
|
|
59
|
+
const handleSave = () =>
|
|
60
|
+
withLoading(async () => {
|
|
61
|
+
await api.save();
|
|
62
|
+
});
|
|
63
|
+
</script>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## API
|
|
67
|
+
|
|
68
|
+
### Return Value
|
|
69
|
+
|
|
70
|
+
| Property | Type | Description |
|
|
71
|
+
| --- | --- | --- |
|
|
72
|
+
| `isLoading` | `Ref<boolean>` | True when loading |
|
|
73
|
+
| `showLoading` | `() => void` | Start loading |
|
|
74
|
+
| `hideLoading` | `() => void` | Stop loading |
|
|
75
|
+
| `withLoading` | `(fn: () => Promise<T>) => Promise<T>` | Wraps async function with loading state |
|
|
76
|
+
|
|
77
|
+
### Options
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
interface UseLoadingOptions {
|
|
81
|
+
delay?: number; // ms before showing loading (default: 0)
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## TypeScript Support
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { useLoading, type UseLoadingOptions } from "@baklavue/composables";
|
|
89
|
+
|
|
90
|
+
const { isLoading, withLoading } = useLoading({ delay: 200 });
|
|
91
|
+
```
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# useMutation
|
|
2
|
+
|
|
3
|
+
Composable for mutations (POST/PUT/PATCH/DELETE) with explicit trigger. Pairs with `useQuery` for cache invalidation after mutations.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```vue
|
|
8
|
+
<script setup>
|
|
9
|
+
import { useMutation, useQueryClient } from "@baklavue/composables";
|
|
10
|
+
|
|
11
|
+
const queryClient = useQueryClient();
|
|
12
|
+
const { mutate, mutateAsync, isPending, data } = useMutation({
|
|
13
|
+
mutationFn: (user) =>
|
|
14
|
+
fetch("/api/users", {
|
|
15
|
+
method: "POST",
|
|
16
|
+
body: JSON.stringify(user),
|
|
17
|
+
headers: { "Content-Type": "application/json" },
|
|
18
|
+
}).then((r) => r.json()),
|
|
19
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["users"] }),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const handleCreate = () => mutate({ name: "John", email: "john@example.com" });
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<button :disabled="isPending" @click="handleCreate">
|
|
27
|
+
{{ isPending ? "Creating..." : "Create User" }}
|
|
28
|
+
</button>
|
|
29
|
+
</template>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## mutateAsync
|
|
33
|
+
|
|
34
|
+
Use `mutateAsync` when you need to await the result:
|
|
35
|
+
|
|
36
|
+
```vue
|
|
37
|
+
<script setup>
|
|
38
|
+
import { useMutation } from "@baklavue/composables";
|
|
39
|
+
|
|
40
|
+
const { mutateAsync } = useMutation({
|
|
41
|
+
mutationFn: (data) => fetch("/api/save", { method: "POST", body: JSON.stringify(data) }).then((r) => r.json()),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const handleSubmit = async () => {
|
|
45
|
+
try {
|
|
46
|
+
const result = await mutateAsync({ title: "New Post" });
|
|
47
|
+
router.push(`/posts/${result.id}`);
|
|
48
|
+
} catch (err) {
|
|
49
|
+
console.error(err);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
</script>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## API
|
|
56
|
+
|
|
57
|
+
### useMutation
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
useMutation<TData, TError, TVariables>(options): UseMutationReturn<TData, TVariables>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
#### Options
|
|
64
|
+
|
|
65
|
+
| Property | Type | Description |
|
|
66
|
+
| --- | --- | --- |
|
|
67
|
+
| `mutationFn` | `(variables: TVariables) => Promise<TData>` | Async function that performs the mutation |
|
|
68
|
+
| `onSuccess` | `(data: TData, variables: TVariables) => void` | Callback on success |
|
|
69
|
+
| `onError` | `(error: TError, variables: TVariables) => void` | Callback on error |
|
|
70
|
+
| `onSettled` | `(data, error, variables) => void` | Callback when mutation settles |
|
|
71
|
+
|
|
72
|
+
#### Return Value
|
|
73
|
+
|
|
74
|
+
| Property | Type | Description |
|
|
75
|
+
| --- | --- | --- |
|
|
76
|
+
| `data` | `Ref<TData \| null>` | Fetched data on success |
|
|
77
|
+
| `error` | `Ref<Error \| null>` | Error if mutation failed |
|
|
78
|
+
| `isPending` | `Ref<boolean>` | True while mutation is in flight |
|
|
79
|
+
| `isSuccess` | `Ref<boolean>` | True when mutation succeeded |
|
|
80
|
+
| `isError` | `Ref<boolean>` | True when mutation failed |
|
|
81
|
+
| `mutate` | `(variables: TVariables) => void` | Execute mutation (fire-and-forget) |
|
|
82
|
+
| `mutateAsync` | `(variables: TVariables) => Promise<TData>` | Execute mutation (returns promise) |
|
|
83
|
+
| `reset` | `() => void` | Reset state to initial |
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# useNotification
|
|
2
|
+
|
|
3
|
+
A composable for managing notifications programmatically.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```vue
|
|
8
|
+
<template>
|
|
9
|
+
<div>
|
|
10
|
+
<BvButton @click="showSuccess">Success</BvButton>
|
|
11
|
+
<BvButton @click="showError">Error</BvButton>
|
|
12
|
+
<BvButton @click="showWarning">Warning</BvButton>
|
|
13
|
+
<BvButton @click="showInfo">Info</BvButton>
|
|
14
|
+
<BvNotification />
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script setup>
|
|
19
|
+
import { BvButton, BvNotification } from "@baklavue/ui";
|
|
20
|
+
import { useNotification } from "@baklavue/composables";
|
|
21
|
+
|
|
22
|
+
const { success, error, warning, info } = useNotification();
|
|
23
|
+
|
|
24
|
+
const showSuccess = () => {
|
|
25
|
+
success({
|
|
26
|
+
caption: "Success!",
|
|
27
|
+
description: "Operation completed successfully",
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const showError = () => {
|
|
32
|
+
error({
|
|
33
|
+
caption: "Error",
|
|
34
|
+
description: "Something went wrong",
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const showWarning = () => {
|
|
39
|
+
warning({
|
|
40
|
+
caption: "Warning",
|
|
41
|
+
description: "Please check your input",
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const showInfo = () => {
|
|
46
|
+
info({
|
|
47
|
+
caption: "Info",
|
|
48
|
+
description: "This is an informational message",
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
</script>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Methods
|
|
55
|
+
|
|
56
|
+
### success
|
|
57
|
+
|
|
58
|
+
Shows a success notification.
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
success(options: NotificationOptions): void
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### error
|
|
65
|
+
|
|
66
|
+
Shows an error notification.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
error(options: NotificationOptions): void
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### warning
|
|
73
|
+
|
|
74
|
+
Shows a warning notification.
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
warning(options: NotificationOptions): void
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### info
|
|
81
|
+
|
|
82
|
+
Shows an info notification.
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
info(options: NotificationOptions): void
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Notification Options
|
|
89
|
+
|
|
90
|
+
Uses Baklava's `NotificationProps`. Key options:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
interface NotificationOptions {
|
|
94
|
+
caption?: string; // Notification title
|
|
95
|
+
description: string; // Notification message (required)
|
|
96
|
+
duration?: number;
|
|
97
|
+
permanent?: boolean;
|
|
98
|
+
primaryAction?: { label: string; onClick: () => void };
|
|
99
|
+
secondaryAction?: { label: string; onClick: () => void };
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Examples
|
|
104
|
+
|
|
105
|
+
### With Duration
|
|
106
|
+
|
|
107
|
+
```vue
|
|
108
|
+
<script setup>
|
|
109
|
+
import { useNotification } from "@baklavue/composables";
|
|
110
|
+
|
|
111
|
+
const { success } = useNotification();
|
|
112
|
+
|
|
113
|
+
const showNotification = () => {
|
|
114
|
+
success({
|
|
115
|
+
caption: "Saved",
|
|
116
|
+
description: "Your changes have been saved",
|
|
117
|
+
duration: 5, // Show for 5 seconds
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
</script>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### With Custom Message
|
|
124
|
+
|
|
125
|
+
```vue
|
|
126
|
+
<script setup>
|
|
127
|
+
import { useNotification } from '@baklavue/composables'
|
|
128
|
+
|
|
129
|
+
const { error } = useNotification()
|
|
130
|
+
|
|
131
|
+
const handleError = (err: Error) => {
|
|
132
|
+
error({
|
|
133
|
+
caption: 'Error',
|
|
134
|
+
description: err.message
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
</script>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Requirements
|
|
141
|
+
|
|
142
|
+
The `useNotification` composable requires a `<Notification />` component to be present in your component tree:
|
|
143
|
+
|
|
144
|
+
```vue
|
|
145
|
+
<template>
|
|
146
|
+
<div>
|
|
147
|
+
<!-- Your app content -->
|
|
148
|
+
<Notification />
|
|
149
|
+
</div>
|
|
150
|
+
</template>
|
|
151
|
+
|
|
152
|
+
<script setup>
|
|
153
|
+
import { Notification } from "@baklavue/ui";
|
|
154
|
+
</script>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## TypeScript Support
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
import { useNotification } from "@baklavue/composables";
|
|
161
|
+
|
|
162
|
+
const notification = useNotification();
|
|
163
|
+
|
|
164
|
+
// All methods are fully typed
|
|
165
|
+
notification.success({
|
|
166
|
+
caption: "Success",
|
|
167
|
+
description: "Done!",
|
|
168
|
+
});
|
|
169
|
+
```
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# usePagination
|
|
2
|
+
|
|
3
|
+
Pagination state for tables and lists. Provides `currentPage`, `pageSize`, `totalItems`, derived `totalPages`, `offset`, and a `slice` helper. Use with BvPagination or BvTable.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```vue
|
|
8
|
+
<template>
|
|
9
|
+
<BvPagination
|
|
10
|
+
v-model:current-page="currentPage"
|
|
11
|
+
:total-items="totalItems"
|
|
12
|
+
:page-size="pageSize"
|
|
13
|
+
/>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup>
|
|
17
|
+
import { computed, ref, watch } from "vue";
|
|
18
|
+
import { BvPagination } from "@baklavue/ui";
|
|
19
|
+
import { usePagination } from "@baklavue/composables";
|
|
20
|
+
|
|
21
|
+
const allItems = ref([/* ... */]);
|
|
22
|
+
|
|
23
|
+
const {
|
|
24
|
+
currentPage,
|
|
25
|
+
pageSize,
|
|
26
|
+
totalItems,
|
|
27
|
+
totalPages,
|
|
28
|
+
setPage,
|
|
29
|
+
setPageSize,
|
|
30
|
+
setTotalItems,
|
|
31
|
+
slice,
|
|
32
|
+
} = usePagination({
|
|
33
|
+
totalItems: 100,
|
|
34
|
+
pageSize: 10,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Sync totalItems when data changes
|
|
38
|
+
watch(allItems, (items) => setTotalItems(items.length), { immediate: true });
|
|
39
|
+
|
|
40
|
+
// Get items for current page
|
|
41
|
+
const pageItems = computed(() => slice(allItems.value));
|
|
42
|
+
</script>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## With BvTable
|
|
46
|
+
|
|
47
|
+
```vue
|
|
48
|
+
<template>
|
|
49
|
+
<BvTable
|
|
50
|
+
:columns="columns"
|
|
51
|
+
:data="pageData"
|
|
52
|
+
:pagination="{
|
|
53
|
+
currentPage,
|
|
54
|
+
totalItems,
|
|
55
|
+
itemsPerPage: pageSize,
|
|
56
|
+
}"
|
|
57
|
+
/>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<script setup>
|
|
61
|
+
import { computed, ref, watch } from "vue";
|
|
62
|
+
import { BvTable } from "@baklavue/ui";
|
|
63
|
+
import { usePagination } from "@baklavue/composables";
|
|
64
|
+
|
|
65
|
+
const allData = ref([/* ... */]);
|
|
66
|
+
const { currentPage, pageSize, totalItems, slice, setTotalItems } = usePagination({
|
|
67
|
+
pageSize: 10,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
watch(allData, (data) => setTotalItems(data.length), { immediate: true });
|
|
71
|
+
|
|
72
|
+
const pageData = computed(() => slice(allData.value));
|
|
73
|
+
</script>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## API
|
|
77
|
+
|
|
78
|
+
### Return Value
|
|
79
|
+
|
|
80
|
+
| Property | Type | Description |
|
|
81
|
+
| --- | --- | --- |
|
|
82
|
+
| `currentPage` | `Ref<number>` | Current page (1-based) |
|
|
83
|
+
| `pageSize` | `Ref<number>` | Items per page |
|
|
84
|
+
| `totalItems` | `Ref<number>` | Total item count |
|
|
85
|
+
| `totalPages` | `ComputedRef<number>` | Total pages |
|
|
86
|
+
| `offset` | `ComputedRef<number>` | Offset for current page |
|
|
87
|
+
| `setPage` | `(page: number) => void` | Set current page |
|
|
88
|
+
| `setPageSize` | `(size: number) => void` | Set items per page |
|
|
89
|
+
| `setTotalItems` | `(total: number) => void` | Set total items |
|
|
90
|
+
| `slice` | `<T>(arr: T[]) => T[]` | Slice array for current page |
|
|
91
|
+
|
|
92
|
+
### Options
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
interface UsePaginationOptions {
|
|
96
|
+
totalItems?: number; // Default: 0
|
|
97
|
+
pageSize?: number; // Default: 10
|
|
98
|
+
initialPage?: number; // Default: 1
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## TypeScript Support
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { usePagination, type UsePaginationOptions } from "@baklavue/composables";
|
|
106
|
+
|
|
107
|
+
const options: UsePaginationOptions = { totalItems: 50, pageSize: 5 };
|
|
108
|
+
const pagination = usePagination(options);
|
|
109
|
+
```
|