@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,84 @@
|
|
|
1
|
+
# useElementSize
|
|
2
|
+
|
|
3
|
+
A composable for reactive element width and height using ResizeObserver. Useful for layout calculations, charts, responsive containers, and dynamic sizing based on element dimensions.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```vue
|
|
8
|
+
<template>
|
|
9
|
+
<div ref="target">Content</div>
|
|
10
|
+
<p>Width: {{ width }}px, Height: {{ height }}px</p>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup>
|
|
14
|
+
import { ref } from "vue";
|
|
15
|
+
import { useElementSize } from "@baklavue/composables";
|
|
16
|
+
|
|
17
|
+
const target = ref<HTMLElement | null>(null);
|
|
18
|
+
const { width, height } = useElementSize(target);
|
|
19
|
+
</script>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Options
|
|
23
|
+
|
|
24
|
+
```vue
|
|
25
|
+
<script setup>
|
|
26
|
+
import { ref } from "vue";
|
|
27
|
+
import { useElementSize } from "@baklavue/composables";
|
|
28
|
+
|
|
29
|
+
const target = ref<HTMLElement | null>(null);
|
|
30
|
+
const { width, height } = useElementSize(target, {
|
|
31
|
+
initialWidth: 0,
|
|
32
|
+
initialHeight: 0,
|
|
33
|
+
});
|
|
34
|
+
</script>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
| Option | Type | Default | Description |
|
|
38
|
+
| --- | --- | --- | --- |
|
|
39
|
+
| `initialWidth` | `number` | `0` | Initial width when no element is observed |
|
|
40
|
+
| `initialHeight` | `number` | `0` | Initial height when no element is observed |
|
|
41
|
+
|
|
42
|
+
## With Charts
|
|
43
|
+
|
|
44
|
+
```vue
|
|
45
|
+
<template>
|
|
46
|
+
<div ref="chartContainer" class="chart-wrapper">
|
|
47
|
+
<canvas :width="width" :height="height" />
|
|
48
|
+
</div>
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
<script setup>
|
|
52
|
+
import { ref } from "vue";
|
|
53
|
+
import { useElementSize } from "@baklavue/composables";
|
|
54
|
+
|
|
55
|
+
const chartContainer = ref<HTMLElement | null>(null);
|
|
56
|
+
const { width, height } = useElementSize(chartContainer);
|
|
57
|
+
</script>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## API
|
|
61
|
+
|
|
62
|
+
### Parameters
|
|
63
|
+
|
|
64
|
+
- `target` — `Ref<Element | null | undefined>` — Ref to the element to observe
|
|
65
|
+
- `options` — Optional `UseElementSizeOptions`
|
|
66
|
+
|
|
67
|
+
### Return Value
|
|
68
|
+
|
|
69
|
+
| Property | Type | Description |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| `width` | `Ref<number>` | Element content width |
|
|
72
|
+
| `height` | `Ref<number>` | Element content height |
|
|
73
|
+
|
|
74
|
+
## TypeScript Support
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import {
|
|
78
|
+
useElementSize,
|
|
79
|
+
type UseElementSizeOptions,
|
|
80
|
+
} from "@baklavue/composables";
|
|
81
|
+
|
|
82
|
+
const target = ref<HTMLElement | null>(null);
|
|
83
|
+
const { width, height } = useElementSize(target);
|
|
84
|
+
```
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# useFetch
|
|
2
|
+
|
|
3
|
+
Reactive fetch with loading state, error handling, and abort support. Axios-like API with method, headers, body, params, baseURL, interceptors, retries, and refetch triggers.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```vue
|
|
8
|
+
<script setup>
|
|
9
|
+
import { useFetch } from "@baklavue/composables";
|
|
10
|
+
|
|
11
|
+
const { data, error, isFetching, execute } = useFetch("/api/users", {
|
|
12
|
+
immediate: true,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// Refetch manually
|
|
16
|
+
const refresh = () => execute();
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<div v-if="isFetching">Loading...</div>
|
|
21
|
+
<div v-else-if="error">Error: {{ error.message }}</div>
|
|
22
|
+
<div v-else-if="data">{{ data }}</div>
|
|
23
|
+
</template>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## POST Request
|
|
27
|
+
|
|
28
|
+
```vue
|
|
29
|
+
<script setup>
|
|
30
|
+
import { useFetch } from "@baklavue/composables";
|
|
31
|
+
|
|
32
|
+
const { data, error, isFetching, execute } = useFetch("/api/users", {
|
|
33
|
+
method: "POST",
|
|
34
|
+
body: { name: "John", email: "john@example.com" },
|
|
35
|
+
immediate: false,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const createUser = () => execute();
|
|
39
|
+
</script>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Base URL and Params
|
|
43
|
+
|
|
44
|
+
Use `baseURL` and `params` for a cleaner API:
|
|
45
|
+
|
|
46
|
+
```vue
|
|
47
|
+
<script setup>
|
|
48
|
+
import { useFetch } from "@baklavue/composables";
|
|
49
|
+
|
|
50
|
+
const { data } = useFetch("/users", {
|
|
51
|
+
baseURL: "https://api.example.com",
|
|
52
|
+
params: { page: 1, limit: 10 },
|
|
53
|
+
});
|
|
54
|
+
</script>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Preconfigured Instance (createFetch)
|
|
58
|
+
|
|
59
|
+
Create a reusable fetch instance with default options, similar to `axios.create()`:
|
|
60
|
+
|
|
61
|
+
```vue
|
|
62
|
+
<script setup>
|
|
63
|
+
import { createFetch } from "@baklavue/composables";
|
|
64
|
+
|
|
65
|
+
const useApiFetch = createFetch({
|
|
66
|
+
baseURL: "/api",
|
|
67
|
+
headers: { "X-Custom-Header": "value" },
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// All requests use baseURL and headers
|
|
71
|
+
const { data } = useApiFetch("/users", { params: { page: 1 } });
|
|
72
|
+
</script>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Auth Interceptor
|
|
76
|
+
|
|
77
|
+
Use `beforeFetch` to add auth or modify the request:
|
|
78
|
+
|
|
79
|
+
```vue
|
|
80
|
+
<script setup>
|
|
81
|
+
import { createFetch } from "@baklavue/composables";
|
|
82
|
+
|
|
83
|
+
const token = ref("your-jwt-token");
|
|
84
|
+
|
|
85
|
+
const useAuthFetch = createFetch({
|
|
86
|
+
beforeFetch: ({ options }) => {
|
|
87
|
+
(options.headers as Record<string, string>)["Authorization"] =
|
|
88
|
+
`Bearer ${token.value}`;
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const { data } = useAuthFetch("/me");
|
|
93
|
+
</script>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Reactive URL
|
|
97
|
+
|
|
98
|
+
Pass a getter function for reactive URLs (e.g. when URL depends on route params):
|
|
99
|
+
|
|
100
|
+
```vue
|
|
101
|
+
<script setup>
|
|
102
|
+
import { useFetch } from "@baklavue/composables";
|
|
103
|
+
|
|
104
|
+
const userId = ref("1");
|
|
105
|
+
const { data, execute } = useFetch(
|
|
106
|
+
() => `https://api.example.com/users/${userId.value}`,
|
|
107
|
+
{ immediate: true }
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
watch(userId, () => execute());
|
|
111
|
+
</script>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Retry
|
|
115
|
+
|
|
116
|
+
Configure retries for transient failures (network errors, 5xx). By default only GET retries; set `retryOnNonIdempotent: true` for POST/PUT/PATCH:
|
|
117
|
+
|
|
118
|
+
```vue
|
|
119
|
+
<script setup>
|
|
120
|
+
import { useFetch } from "@baklavue/composables";
|
|
121
|
+
|
|
122
|
+
const { data, error } = useFetch("/api/users", {
|
|
123
|
+
retry: 3,
|
|
124
|
+
retryDelay: (attempt) => 1000 * 2 ** attempt,
|
|
125
|
+
});
|
|
126
|
+
</script>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Refetch Triggers
|
|
130
|
+
|
|
131
|
+
Opt-in refetch on window focus or network reconnect:
|
|
132
|
+
|
|
133
|
+
```vue
|
|
134
|
+
<script setup>
|
|
135
|
+
import { useFetch } from "@baklavue/composables";
|
|
136
|
+
|
|
137
|
+
const { data } = useFetch("/api/config", {
|
|
138
|
+
refetchOnWindowFocus: true,
|
|
139
|
+
refetchOnReconnect: true,
|
|
140
|
+
});
|
|
141
|
+
</script>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Refetch on URL Change
|
|
145
|
+
|
|
146
|
+
When using a reactive URL getter, auto-refetch when the URL changes:
|
|
147
|
+
|
|
148
|
+
```vue
|
|
149
|
+
<script setup>
|
|
150
|
+
import { useFetch } from "@baklavue/composables";
|
|
151
|
+
|
|
152
|
+
const userId = ref("1");
|
|
153
|
+
const { data } = useFetch(
|
|
154
|
+
() => `https://api.example.com/users/${userId.value}`,
|
|
155
|
+
{ refetchOnUrlChange: true }
|
|
156
|
+
);
|
|
157
|
+
</script>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Execute with Overrides
|
|
161
|
+
|
|
162
|
+
Pass dynamic url, body, or params at execute time:
|
|
163
|
+
|
|
164
|
+
```vue
|
|
165
|
+
<script setup>
|
|
166
|
+
import { useFetch } from "@baklavue/composables";
|
|
167
|
+
|
|
168
|
+
const { data, execute } = useFetch("/api/users", {
|
|
169
|
+
method: "POST",
|
|
170
|
+
immediate: false,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const createUser = (name: string) =>
|
|
174
|
+
execute({ body: { name }, throwOnFailed: true });
|
|
175
|
+
</script>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Error Interceptor
|
|
179
|
+
|
|
180
|
+
Use `onFetchError` to log, transform, or handle errors:
|
|
181
|
+
|
|
182
|
+
```vue
|
|
183
|
+
<script setup>
|
|
184
|
+
import { useFetch } from "@baklavue/composables";
|
|
185
|
+
|
|
186
|
+
const { data, error } = useFetch("/api/users", {
|
|
187
|
+
onFetchError: ({ response, error }) => {
|
|
188
|
+
console.error("Fetch failed:", response?.status, error.message);
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
</script>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Manual Execute
|
|
195
|
+
|
|
196
|
+
Set `immediate: false` to prevent the request from firing until `execute()` is called:
|
|
197
|
+
|
|
198
|
+
```vue
|
|
199
|
+
<script setup>
|
|
200
|
+
import { useFetch } from "@baklavue/composables";
|
|
201
|
+
|
|
202
|
+
const { data, execute } = useFetch("/api/users", {
|
|
203
|
+
immediate: false,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const loadUsers = () => execute();
|
|
207
|
+
</script>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## API
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
useFetch<T>(
|
|
214
|
+
url: string | (() => string),
|
|
215
|
+
options?: UseFetchOptions
|
|
216
|
+
): UseFetchReturn<T>
|
|
217
|
+
|
|
218
|
+
createFetch(defaultOptions: UseFetchOptions): (url, options?) => UseFetchReturn<T>
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Options
|
|
222
|
+
|
|
223
|
+
| Property | Type | Default | Description |
|
|
224
|
+
| --- | --- | --- | --- |
|
|
225
|
+
| `immediate` | `boolean` | `true` | Run fetch immediately on creation |
|
|
226
|
+
| `initialData` | `unknown` | `null` | Initial data before request completes |
|
|
227
|
+
| `timeout` | `number` | `0` | Timeout in ms to abort (0 = no timeout) |
|
|
228
|
+
| `method` | `'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'` | `'GET'` | HTTP method |
|
|
229
|
+
| `headers` | `Record<string, string>` | `{}` | Request headers |
|
|
230
|
+
| `body` | `unknown` | - | Request body (JSON, FormData, string, etc.) |
|
|
231
|
+
| `params` | `Record<string, string \| number \| boolean \| array>` | - | URL query params |
|
|
232
|
+
| `baseURL` | `string` | - | Base URL prepended to relative URLs |
|
|
233
|
+
| `validateStatus` | `(status: number) => boolean` | `200-299` | Custom status validation |
|
|
234
|
+
| `beforeFetch` | `(ctx: { url, options }) => void \| Promise<void>` | - | Hook to modify request before fetch |
|
|
235
|
+
| `afterFetch` | `(ctx: { response, data }) => unknown \| Promise<unknown>` | - | Hook to transform response data |
|
|
236
|
+
| `onFetchError` | `(ctx: { response, error }) => void \| Promise<void>` | - | Hook called on fetch error |
|
|
237
|
+
| `retry` | `number \| boolean` | `0` | Number of retries (or false for none) |
|
|
238
|
+
| `retryDelay` | `number \| (attempt, error) => number` | exponential backoff | Delay between retries |
|
|
239
|
+
| `retryCondition` | `(error, response) => boolean` | network/5xx | When to retry |
|
|
240
|
+
| `retryOnNonIdempotent` | `boolean` | `false` | Retry POST/PUT/PATCH/DELETE |
|
|
241
|
+
| `refetchOnWindowFocus` | `boolean` | `false` | Refetch when window regains focus |
|
|
242
|
+
| `refetchOnReconnect` | `boolean` | `false` | Refetch when network reconnects |
|
|
243
|
+
| `refetchOnUrlChange` | `boolean` | `false` | Refetch when URL (getter) changes |
|
|
244
|
+
| `responseType` | `'json' \| 'text' \| 'blob' \| 'arraybuffer'` | auto | Response parsing |
|
|
245
|
+
| `credentials` | `RequestCredentials` | - | CORS credentials |
|
|
246
|
+
|
|
247
|
+
### Return Value
|
|
248
|
+
|
|
249
|
+
| Property | Type | Description |
|
|
250
|
+
| --- | --- | --- |
|
|
251
|
+
| `data` | `Ref<T \| null>` | Response data on success |
|
|
252
|
+
| `error` | `Ref<Error \| null>` | Error if request failed |
|
|
253
|
+
| `statusCode` | `Ref<number \| null>` | HTTP status of last response |
|
|
254
|
+
| `isFetching` | `Ref<boolean>` | True while request is in flight |
|
|
255
|
+
| `isFinished` | `Ref<boolean>` | True when request has finished |
|
|
256
|
+
| `execute` | `(options?) => Promise<void>` | Execute manually; pass `{ url?, body?, params?, throwOnFailed? }` for overrides |
|
|
257
|
+
| `abort` | `() => void` | Abort the current request |
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# useFieldArray
|
|
2
|
+
|
|
3
|
+
A composable for dynamic array fields in forms (tags, addresses, line items). Provides stable keys for list rendering and keeps form data in sync.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```vue
|
|
8
|
+
<script setup lang="ts">
|
|
9
|
+
import { useFieldArray } from "@baklavue/composables";
|
|
10
|
+
import { ref } from "vue";
|
|
11
|
+
|
|
12
|
+
const form = ref({ tags: [] as string[] });
|
|
13
|
+
const tagsRef = computed({
|
|
14
|
+
get: () => form.value.tags,
|
|
15
|
+
set: (v) => { form.value = { ...form.value, tags: v }; },
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const { fields, push, remove, insert } = useFieldArray(tagsRef);
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<div v-for="field in fields" :key="field.key">
|
|
23
|
+
<input v-model="field.value" />
|
|
24
|
+
<button type="button" @click="remove(field.index)">Remove</button>
|
|
25
|
+
</div>
|
|
26
|
+
<button type="button" @click="push('')">Add</button>
|
|
27
|
+
</template>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## With Object Items
|
|
31
|
+
|
|
32
|
+
```vue
|
|
33
|
+
<script setup lang="ts">
|
|
34
|
+
const form = ref({ items: [{ name: "", qty: 0 }] });
|
|
35
|
+
const itemsRef = computed({
|
|
36
|
+
get: () => form.value.items,
|
|
37
|
+
set: (v) => { form.value = { ...form.value, items: v }; },
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const { fields, push, remove } = useFieldArray(itemsRef);
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<template>
|
|
44
|
+
<div v-for="field in fields" :key="field.key">
|
|
45
|
+
<input v-model="field.value.name" placeholder="Name" />
|
|
46
|
+
<input v-model.number="field.value.qty" type="number" placeholder="Qty" />
|
|
47
|
+
<button type="button" @click="remove(field.index)">Remove</button>
|
|
48
|
+
</div>
|
|
49
|
+
<button type="button" @click="push({ name: '', qty: 0 })">Add item</button>
|
|
50
|
+
</template>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## API
|
|
54
|
+
|
|
55
|
+
### Parameters
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
useFieldArray(arrayRef, options?)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
| Parameter | Type | Description |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| `arrayRef` | `Ref<T[]>` | Ref to the array (or writable computed) |
|
|
64
|
+
| `options` | `UseFieldArrayOptions<T>` | Optional: `{ keyName?: keyof T \| (item, index) => string }` |
|
|
65
|
+
|
|
66
|
+
### Return Value
|
|
67
|
+
|
|
68
|
+
| Property | Type | Description |
|
|
69
|
+
| --- | --- | --- |
|
|
70
|
+
| `fields` | `Ref<FieldArrayField<T>[]>` | Array of `{ key, value, index }` for v-for |
|
|
71
|
+
| `push` | `(value: T) => void` | Append item |
|
|
72
|
+
| `remove` | `(index: number) => void` | Remove item at index |
|
|
73
|
+
| `insert` | `(index: number, value: T) => void` | Insert item at index |
|
|
74
|
+
| `move` | `(fromIndex: number, toIndex: number) => void` | Reorder items |
|
|
75
|
+
| `replace` | `(values: T[]) => void` | Replace entire array |
|
|
76
|
+
| `reset` | `(values?: T[]) => void` | Reset to values or empty array |
|
|
77
|
+
|
|
78
|
+
### Custom Keys
|
|
79
|
+
|
|
80
|
+
Use `keyName` when items have a unique identifier:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const { fields } = useFieldArray(itemsRef, {
|
|
84
|
+
keyName: "id", // or: (item, index) => item.id
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## With useZodForm
|
|
89
|
+
|
|
90
|
+
Use with [useZodForm](/composables/formValidation) for validation of array fields:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
const schema = z.object({
|
|
94
|
+
items: z.array(z.object({
|
|
95
|
+
name: z.string().min(1),
|
|
96
|
+
qty: z.number().min(1),
|
|
97
|
+
})),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const form = useZodForm(schema, formData);
|
|
101
|
+
const { fields, push, remove } = useFieldArray(itemsRef);
|
|
102
|
+
|
|
103
|
+
// In template, use data-field for scroll-to-error: data-field="items.0.name"
|
|
104
|
+
```
|