@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.
Files changed (93) hide show
  1. package/README.md +72 -0
  2. package/dist/data/component-categories.d.ts +7 -0
  3. package/dist/data/component-categories.js +48 -0
  4. package/dist/data/loaders.d.ts +22 -0
  5. package/dist/data/loaders.js +346 -0
  6. package/dist/docs/components/accordion.md +601 -0
  7. package/dist/docs/components/alert.md +233 -0
  8. package/dist/docs/components/badge.md +100 -0
  9. package/dist/docs/components/banner.md +231 -0
  10. package/dist/docs/components/button.md +324 -0
  11. package/dist/docs/components/checkbox.md +343 -0
  12. package/dist/docs/components/chip.md +199 -0
  13. package/dist/docs/components/datepicker.md +243 -0
  14. package/dist/docs/components/dialog.md +224 -0
  15. package/dist/docs/components/drawer.md +188 -0
  16. package/dist/docs/components/dropdown.md +291 -0
  17. package/dist/docs/components/file-upload.md +248 -0
  18. package/dist/docs/components/icon.md +142 -0
  19. package/dist/docs/components/image.md +161 -0
  20. package/dist/docs/components/index.md +151 -0
  21. package/dist/docs/components/input.md +407 -0
  22. package/dist/docs/components/link.md +249 -0
  23. package/dist/docs/components/notification.md +179 -0
  24. package/dist/docs/components/pagination.md +168 -0
  25. package/dist/docs/components/radio.md +221 -0
  26. package/dist/docs/components/scroll-to-top.md +90 -0
  27. package/dist/docs/components/select.md +239 -0
  28. package/dist/docs/components/skeleton.md +79 -0
  29. package/dist/docs/components/spinner.md +93 -0
  30. package/dist/docs/components/split-button.md +165 -0
  31. package/dist/docs/components/stepper.md +337 -0
  32. package/dist/docs/components/switch.md +144 -0
  33. package/dist/docs/components/tab.md +140 -0
  34. package/dist/docs/components/table.md +362 -0
  35. package/dist/docs/components/tag.md +243 -0
  36. package/dist/docs/components/textarea.md +190 -0
  37. package/dist/docs/components/tooltip.md +155 -0
  38. package/dist/docs/composables/alert.md +87 -0
  39. package/dist/docs/composables/asyncState.md +74 -0
  40. package/dist/docs/composables/base64.md +72 -0
  41. package/dist/docs/composables/breakpoints.md +129 -0
  42. package/dist/docs/composables/clipboard.md +108 -0
  43. package/dist/docs/composables/colorScheme.md +110 -0
  44. package/dist/docs/composables/confirmDialog.md +105 -0
  45. package/dist/docs/composables/containerScroll.md +89 -0
  46. package/dist/docs/composables/cookie.md +137 -0
  47. package/dist/docs/composables/debounce.md +69 -0
  48. package/dist/docs/composables/disclosure.md +69 -0
  49. package/dist/docs/composables/elementSize.md +84 -0
  50. package/dist/docs/composables/fetch.md +257 -0
  51. package/dist/docs/composables/fieldArray.md +104 -0
  52. package/dist/docs/composables/file.md +343 -0
  53. package/dist/docs/composables/focusTrap.md +87 -0
  54. package/dist/docs/composables/formPersistence.md +69 -0
  55. package/dist/docs/composables/formState.md +71 -0
  56. package/dist/docs/composables/formValidation.md +355 -0
  57. package/dist/docs/composables/format.md +107 -0
  58. package/dist/docs/composables/id.md +54 -0
  59. package/dist/docs/composables/index.md +112 -0
  60. package/dist/docs/composables/infiniteQuery.md +104 -0
  61. package/dist/docs/composables/intersectionObserver.md +64 -0
  62. package/dist/docs/composables/lazyQuery.md +68 -0
  63. package/dist/docs/composables/loading.md +91 -0
  64. package/dist/docs/composables/mutation.md +83 -0
  65. package/dist/docs/composables/notification.md +169 -0
  66. package/dist/docs/composables/pagination.md +109 -0
  67. package/dist/docs/composables/polling.md +76 -0
  68. package/dist/docs/composables/previous.md +58 -0
  69. package/dist/docs/composables/query.md +248 -0
  70. package/dist/docs/composables/raf.md +78 -0
  71. package/dist/docs/composables/scrollLock.md +46 -0
  72. package/dist/docs/composables/scrollToError.md +291 -0
  73. package/dist/docs/composables/scrollVisibility.md +60 -0
  74. package/dist/docs/composables/share.md +78 -0
  75. package/dist/docs/composables/slug.md +58 -0
  76. package/dist/docs/composables/stepper.md +117 -0
  77. package/dist/docs/composables/stepperForm.md +74 -0
  78. package/dist/docs/composables/sticky.md +91 -0
  79. package/dist/docs/composables/storage.md +193 -0
  80. package/dist/docs/composables/theme.md +252 -0
  81. package/dist/docs/composables/themePreset.md +62 -0
  82. package/dist/docs/composables/throttle.md +76 -0
  83. package/dist/docs/composables/timer.md +78 -0
  84. package/dist/docs/composables/toggle.md +55 -0
  85. package/dist/docs/guide/contributing.md +364 -0
  86. package/dist/docs/guide/design-tokens.md +29 -0
  87. package/dist/docs/guide/getting-started.md +181 -0
  88. package/dist/docs/guide/installation.md +287 -0
  89. package/dist/docs/guide/localization.md +132 -0
  90. package/dist/docs/guide/mcp.md +141 -0
  91. package/dist/index.d.ts +2 -0
  92. package/dist/index.js +177 -0
  93. package/package.json +48 -0
@@ -0,0 +1,343 @@
1
+ # useFile
2
+
3
+ A composable for file parsing, creating, and downloading. Supports CSV, TSV, JSON, and Excel (.xlsx, .xls) formats with streaming, Zod validation, transforms, and preview. Accepts `File` or `Blob` for `parseFile`, `preview`, and `parseStream`. Uses PapaParse for RFC 4180-compliant CSV/TSV and SheetJS for Excel.
4
+
5
+ ## Basic Usage
6
+
7
+ ### Parse String
8
+
9
+ ```vue
10
+ <script setup lang="ts">
11
+ import { useFile } from "@baklavue/composables";
12
+
13
+ const { parse } = useFile();
14
+
15
+ const result = parse("name,age\nAlice,30\nBob,25", { format: "csv", header: true });
16
+ console.log(result.data); // [{ name: "Alice", age: "30" }, { name: "Bob", age: "25" }]
17
+ </script>
18
+ ```
19
+
20
+ ### Parse File
21
+
22
+ ```vue
23
+ <template>
24
+ <input type="file" accept=".csv,.tsv,.json,.xlsx,.xls" @change="handleFileUpload" />
25
+ </template>
26
+
27
+ <script setup lang="ts">
28
+ import { useFile } from "@baklavue/composables";
29
+
30
+ const { parseFile } = useFile();
31
+
32
+ const handleFileUpload = async (event: Event) => {
33
+ const file = (event.target as HTMLInputElement).files?.[0];
34
+ if (file) {
35
+ const result = await parseFile(file, { header: true });
36
+ console.log(result.data);
37
+ }
38
+ };
39
+ </script>
40
+ ```
41
+
42
+ ### Create CSV
43
+
44
+ ```vue
45
+ <script setup lang="ts">
46
+ import { useFile } from "@baklavue/composables";
47
+
48
+ const { create } = useFile();
49
+
50
+ const csv = create([
51
+ { name: "Alice", age: 30 },
52
+ { name: "Bob", age: 25 },
53
+ ]);
54
+ // Result: "name,age\nAlice,30\nBob,25"
55
+ </script>
56
+ ```
57
+
58
+ ### Download CSV
59
+
60
+ ```vue
61
+ <template>
62
+ <button @click="exportData">Export CSV</button>
63
+ </template>
64
+
65
+ <script setup lang="ts">
66
+ import { useFile } from "@baklavue/composables";
67
+
68
+ const { download } = useFile();
69
+
70
+ const data = [
71
+ { name: "Alice", age: 30 },
72
+ { name: "Bob", age: 25 },
73
+ ];
74
+
75
+ const exportData = () => {
76
+ download(data, "export.csv");
77
+ };
78
+ </script>
79
+ ```
80
+
81
+ ## Supported Formats
82
+
83
+ | Format | Parse | Create | Notes |
84
+ | --- | --- | --- | --- |
85
+ | CSV | Yes | Yes | RFC 4180, PapaParse |
86
+ | TSV | Yes | Yes | Tab-delimited, PapaParse |
87
+ | JSON | Yes | Yes | Built-in `JSON.parse` / `JSON.stringify` |
88
+ | Excel (.xlsx, .xls) | Yes | Yes | SheetJS; parse via `parseFile` only (binary format) |
89
+
90
+ Format is auto-detected from file extension when using `parseFile` or `preview`. For `Blob` (without filename), format is inferred from `blob.type` when possible; otherwise specify `format` in options.
91
+
92
+ **Limitations:** `parse()` and `parseStream` do not support Excel; use `parseFile()` instead.
93
+
94
+ ## Methods
95
+
96
+ ### parse
97
+
98
+ Parses a string synchronously. Returns `{ data, errors, meta }` (and `validationError` if Zod schema fails).
99
+
100
+ ```typescript
101
+ parse<T>(content: string, options?: FileParseOptions<T>): ParseResult<T> & { validationError?: z.ZodError }
102
+ ```
103
+
104
+ ### parseFile
105
+
106
+ Parses a File or Blob asynchronously. Format auto-detected from filename (File) or `blob.type` (Blob) when omitted.
107
+
108
+ ```typescript
109
+ parseFile<T>(file: File | Blob, options?: FileParseOptions<T>): Promise<ParseResult<T> & { validationError?: z.ZodError }>
110
+ ```
111
+
112
+ ### parseStream
113
+
114
+ Chunked parsing for large CSV/TSV files. Use `step` or `chunk` callbacks. Returns `{ abort }` to stop parsing. Does not support Excel; throws if format is xlsx/xls.
115
+
116
+ ```typescript
117
+ parseStream(file: File | Blob, options: {
118
+ format?: "csv" | "tsv";
119
+ step?: (result: ParseResult<unknown>, parser: Parser) => void;
120
+ chunk?: (result: ParseResult<unknown>, parser: Parser) => void;
121
+ transform?: (row: unknown) => unknown | null;
122
+ complete?: () => void;
123
+ error?: (err: Error) => void;
124
+ // ...header, dynamicTyping, skipEmptyLines
125
+ }): { abort: () => void }
126
+ ```
127
+
128
+ ### preview
129
+
130
+ Parses only the first N rows. Useful for quick inspection of large files.
131
+
132
+ ```typescript
133
+ preview<T>(file: File | Blob, options?: { rows?: number; format?: FileFormat; ... }): Promise<PreviewResult<T>>
134
+ ```
135
+
136
+ ### create
137
+
138
+ Creates a string from data. Supports CSV, TSV, JSON, and Excel (returns base64 for Excel).
139
+
140
+ ```typescript
141
+ create(data: FileData, options?: FileCreateOptions): string
142
+ ```
143
+
144
+ ### download
145
+
146
+ Creates a string and triggers a browser download. Adds UTF-8 BOM for CSV/TSV (Excel compatibility).
147
+
148
+ ```typescript
149
+ download(data: FileData, filename?: string, options?: FileCreateOptions): void
150
+ ```
151
+
152
+ ## Options
153
+
154
+ ### FileParseOptions
155
+
156
+ | Option | Type | Default | Description |
157
+ | --- | --- | --- | --- |
158
+ | `format` | `'csv' \| 'tsv' \| 'json' \| 'xlsx' \| 'xls'` | `'csv'` | File format |
159
+ | `delimiter` | `string` | auto (CSV) or `\t` (TSV) | Delimiter character |
160
+ | `header` | `boolean` | `false` | First row is header (returns array of objects) |
161
+ | `dynamicTyping` | `boolean` | `false` | Convert numbers and booleans to their types |
162
+ | `skipEmptyLines` | `boolean \| "greedy"` | `false` | Skip empty lines |
163
+ | `schema` | `z.ZodType` | — | Zod schema for validation |
164
+ | `transform` | `(row) => row \| null` | — | Transform each row; return `null` to skip |
165
+
166
+ ### FileCreateOptions
167
+
168
+ | Option | Type | Default | Description |
169
+ | --- | --- | --- | --- |
170
+ | `format` | `'csv' \| 'tsv' \| 'json' \| 'xlsx' \| 'xls'` | `'csv'` | Output format |
171
+ | `delimiter` | `string` | `","` or `"\t"` | Delimiter character |
172
+ | `header` | `boolean` | `true` | Include header row |
173
+ | `columns` | `string[]` | — | Column order for array of objects |
174
+ | `escapeFormulae` | `boolean` | `false` | Escape leading `=`, `+`, `-`, `@` to prevent CSV injection |
175
+
176
+ ## FileData Types
177
+
178
+ Accepted by `create` and `download`:
179
+
180
+ - **Array of objects:** `Record<string, unknown>[]` — keys become header row
181
+ - **Array of arrays:** `unknown[][]` — no header unless `header: true` with explicit `columns`
182
+ - **Explicit fields + data:** `{ fields: string[]; data: unknown[][] }` — for custom column order
183
+
184
+ ## Examples
185
+
186
+ ### Multi-Format (JSON, TSV, Excel)
187
+
188
+ ```vue
189
+ <script setup lang="ts">
190
+ import { useFile } from "@baklavue/composables";
191
+
192
+ const { parse, parseFile, create, download } = useFile();
193
+
194
+ // Parse JSON
195
+ const jsonResult = parse('[{"a":1},{"a":2}]', { format: "json" });
196
+
197
+ // Parse TSV
198
+ const tsvResult = parse("name\tage\nAlice\t30", { format: "tsv", header: true });
199
+
200
+ // Parse Excel file (use parseFile, not parse)
201
+ const excelResult = await parseFile(file, { format: "xlsx", header: true });
202
+
203
+ // Create and download Excel
204
+ const data = [{ name: "Alice", age: 30 }];
205
+ download(data, "export.xlsx", { format: "xlsx" });
206
+ </script>
207
+ ```
208
+
209
+ ### With Blob
210
+
211
+ ```vue
212
+ <script setup lang="ts">
213
+ import { useFile } from "@baklavue/composables";
214
+
215
+ const { parseFile } = useFile();
216
+
217
+ // Parse from Blob (e.g. from fetch response)
218
+ const response = await fetch("/api/export.csv");
219
+ const blob = await response.blob();
220
+ const result = await parseFile(blob, { format: "csv", header: true });
221
+ </script>
222
+ ```
223
+
224
+ ### With Zod Validation
225
+
226
+ ```vue
227
+ <script setup lang="ts">
228
+ import { useFile } from "@baklavue/composables";
229
+ import { z } from "zod";
230
+
231
+ const schema = z.array(z.object({ name: z.string(), age: z.number() }));
232
+ const { parseFile } = useFile();
233
+
234
+ const result = await parseFile(file, {
235
+ format: "csv",
236
+ header: true,
237
+ dynamicTyping: true,
238
+ schema,
239
+ });
240
+
241
+ if (result.validationError) {
242
+ console.error("Validation failed:", result.validationError);
243
+ } else {
244
+ console.log(result.data); // Typed as { name: string; age: number }[]
245
+ }
246
+ </script>
247
+ ```
248
+
249
+ ### With Transform
250
+
251
+ ```vue
252
+ <script setup lang="ts">
253
+ import { useFile } from "@baklavue/composables";
254
+
255
+ const { parse } = useFile();
256
+
257
+ const result = parse("name,age\nAlice,30\nBob,25", {
258
+ format: "csv",
259
+ header: true,
260
+ dynamicTyping: true,
261
+ transform: (row) => {
262
+ const r = row as { age: number };
263
+ return r.age >= 18 ? { ...r, adult: true } : null;
264
+ },
265
+ });
266
+ // Only rows with age >= 18, with adult: true added
267
+ </script>
268
+ ```
269
+
270
+ ### Preview First Rows
271
+
272
+ ```vue
273
+ <script setup lang="ts">
274
+ import { useFile } from "@baklavue/composables";
275
+
276
+ const { preview } = useFile();
277
+
278
+ const { data, truncated } = await preview(file, { rows: 10 });
279
+ console.log("First 10 rows:", data);
280
+ if (truncated) console.log("File has more rows");
281
+ </script>
282
+ ```
283
+
284
+ ### Streaming Large Files
285
+
286
+ ```vue
287
+ <script setup lang="ts">
288
+ import { useFile } from "@baklavue/composables";
289
+
290
+ const { parseStream } = useFile();
291
+
292
+ const { abort } = parseStream(file, {
293
+ format: "csv",
294
+ header: true,
295
+ step: (result, parser) => {
296
+ const row = result.data?.[0];
297
+ if (row) processRow(row);
298
+ },
299
+ complete: () => console.log("Done"),
300
+ });
301
+
302
+ // Call abort() to stop parsing
303
+ </script>
304
+ ```
305
+
306
+ ### With Formulae Escaping
307
+
308
+ ```vue
309
+ <script setup lang="ts">
310
+ import { useFile } from "@baklavue/composables";
311
+
312
+ const { download } = useFile();
313
+
314
+ download(
315
+ [{ formula: "=SUM(A1:A10)", value: 100 }],
316
+ "export.csv",
317
+ { escapeFormulae: true }
318
+ );
319
+ </script>
320
+ ```
321
+
322
+ ## TypeScript Support
323
+
324
+ ```typescript
325
+ import {
326
+ useFile,
327
+ type FileData,
328
+ type FileParseOptions,
329
+ type FileCreateOptions,
330
+ type ParseResult,
331
+ type ParseError,
332
+ type ParseMeta,
333
+ type PreviewResult,
334
+ } from "@baklavue/composables";
335
+
336
+ const { parse, parseFile, create, download } = useFile();
337
+
338
+ // Typed parse
339
+ const result = parse<{ name: string; age: number }>(
340
+ "name,age\nAlice,30",
341
+ { format: "csv", header: true, dynamicTyping: true }
342
+ );
343
+ ```
@@ -0,0 +1,87 @@
1
+ # useFocusTrap
2
+
3
+ A composable for trapping focus within a container (e.g. modals, dialogs). Tab cycles to next focusable element; Shift+Tab to previous. Prevents focus from escaping.
4
+
5
+ ## Basic Usage
6
+
7
+ ```vue
8
+ <template>
9
+ <BvDialog v-model:open="isOpen" caption="Dialog">
10
+ <div ref="dialogContentRef">
11
+ <p>Tab cycles within this dialog.</p>
12
+ <BvButton @click="close">Cancel</BvButton>
13
+ <BvButton variant="primary">Confirm</BvButton>
14
+ </div>
15
+ </BvDialog>
16
+ </template>
17
+
18
+ <script setup>
19
+ import { ref, watch } from "vue";
20
+ import { BvButton, BvDialog } from "@baklavue/ui";
21
+ import { useFocusTrap } from "@baklavue/composables";
22
+
23
+ const dialogContentRef = ref(null);
24
+ const isOpen = ref(false);
25
+
26
+ const { activate, deactivate } = useFocusTrap({
27
+ target: dialogContentRef,
28
+ active: isOpen,
29
+ });
30
+
31
+ watch(isOpen, (open) => {
32
+ if (open) activate();
33
+ else deactivate();
34
+ });
35
+ </script>
36
+ ```
37
+
38
+ ## Manual Activation
39
+
40
+ ```vue
41
+ <script setup>
42
+ import { ref } from "vue";
43
+ import { useFocusTrap } from "@baklavue/composables";
44
+
45
+ const containerRef = ref(null);
46
+ const { activate, deactivate, focusFirst, focusLast } = useFocusTrap({
47
+ target: containerRef,
48
+ initialFocus: true,
49
+ });
50
+
51
+ onMounted(() => {
52
+ activate();
53
+ });
54
+ </script>
55
+ ```
56
+
57
+ ## API
58
+
59
+ ### Return Value
60
+
61
+ | Property | Type | Description |
62
+ | --- | --- | --- |
63
+ | `activate` | `() => void` | Start trapping focus |
64
+ | `deactivate` | `() => void` | Stop trapping focus |
65
+ | `focusFirst` | `() => void` | Focus first focusable element |
66
+ | `focusLast` | `() => void` | Focus last focusable element |
67
+
68
+ ### Options
69
+
70
+ ```typescript
71
+ interface UseFocusTrapOptions {
72
+ target: Ref<HTMLElement | null>; // Container element
73
+ active?: Ref<boolean> | boolean; // Whether trap is active (default: true)
74
+ initialFocus?: boolean; // Focus first element when activated (default: true)
75
+ }
76
+ ```
77
+
78
+ ## TypeScript Support
79
+
80
+ ```typescript
81
+ import { useFocusTrap, type UseFocusTrapOptions } from "@baklavue/composables";
82
+
83
+ const { activate } = useFocusTrap({
84
+ target: dialogRef,
85
+ active: isOpen,
86
+ });
87
+ ```
@@ -0,0 +1,69 @@
1
+ # useFormPersistence
2
+
3
+ A composable for auto-saving form data to `localStorage` or `sessionStorage`. Useful for long forms, drafts, or preventing data loss on accidental navigation.
4
+
5
+ ## Basic Usage
6
+
7
+ ```vue
8
+ <script setup lang="ts">
9
+ import { useFormPersistence } from "@baklavue/composables";
10
+ import { ref } from "vue";
11
+
12
+ const form = ref({ email: "", message: "" });
13
+ useFormPersistence("contact-draft", form);
14
+ </script>
15
+ ```
16
+
17
+ Form data is automatically saved when the user types. On page load, if a draft exists in storage, it is restored.
18
+
19
+ ## API
20
+
21
+ ### Parameters
22
+
23
+ ```typescript
24
+ useFormPersistence(key, data, options?)
25
+ ```
26
+
27
+ | Parameter | Type | Description |
28
+ | --- | --- | --- |
29
+ | `key` | `string` | Storage key |
30
+ | `data` | `Ref<T> \| Reactive<T> \| () => T` | Form data (ref, reactive, or getter) |
31
+ | `options` | `UseFormPersistenceOptions` | Optional: `{ storage?: 'localStorage' \| 'sessionStorage', debounce?: number }` |
32
+
33
+ ### Return Value
34
+
35
+ | Property | Type | Description |
36
+ | --- | --- | --- |
37
+ | `clear` | `() => void` | Remove persisted data from storage |
38
+
39
+ ### Options
40
+
41
+ | Option | Type | Default | Description |
42
+ | --- | --- | --- | --- |
43
+ | `storage` | `'localStorage' \| 'sessionStorage'` | `'localStorage'` | Where to persist |
44
+ | `debounce` | `number` | `300` | Debounce writes in ms. Use `0` for immediate write |
45
+
46
+ ## Session vs Local Storage
47
+
48
+ - **localStorage**: Persists across browser sessions. Use for drafts the user might return to later.
49
+ - **sessionStorage**: Persists only for the current tab. Use for forms that should not persist after closing.
50
+
51
+ ```typescript
52
+ useFormPersistence("wizard-draft", form, {
53
+ storage: "sessionStorage",
54
+ debounce: 500,
55
+ });
56
+ ```
57
+
58
+ ## Clearing Draft
59
+
60
+ Call `clear()` when the form is successfully submitted:
61
+
62
+ ```typescript
63
+ const { clear } = useFormPersistence("contact-draft", form);
64
+
65
+ const onSubmit = async () => {
66
+ await api.submit(form.value);
67
+ clear();
68
+ };
69
+ ```
@@ -0,0 +1,71 @@
1
+ # useFormState
2
+
3
+ A lightweight composable for form dirty and touched state without validation. Use with plain ref form data or alongside [useZodForm](/composables/formValidation) when you need state tracking without Zod.
4
+
5
+ ## Basic Usage
6
+
7
+ ```vue
8
+ <script setup lang="ts">
9
+ import { useFormState } from "@baklavue/composables";
10
+ import { ref } from "vue";
11
+
12
+ const form = ref({ email: "", name: "" });
13
+ const { isDirty, dirtyFields, touched, touchedFields, setFieldTouched, setFieldValue, reset } = useFormState(form);
14
+
15
+ // Check before navigation
16
+ const beforeUnload = () => {
17
+ if (isDirty.value) {
18
+ return "You have unsaved changes";
19
+ }
20
+ };
21
+ </script>
22
+ ```
23
+
24
+ ## API
25
+
26
+ ### Parameters
27
+
28
+ ```typescript
29
+ useFormState(data, options?)
30
+ ```
31
+
32
+ | Parameter | Type | Description |
33
+ | --- | --- | --- |
34
+ | `data` | `Ref<T> \| Reactive<T> \| () => T` | Form data (ref, reactive, or getter) |
35
+ | `options` | `UseFormStateOptions` | Optional: `{ initialValues?: Ref \| () => T }` |
36
+
37
+ ### Return Value
38
+
39
+ | Property | Type | Description |
40
+ | --- | --- | --- |
41
+ | `isDirty` | `Ref<boolean>` | Whether any field has changed from initial values |
42
+ | `dirtyFields` | `Ref<Record<string, boolean>>` | Per-field dirty state |
43
+ | `touched` | `Ref<boolean>` | Whether any field has been blurred |
44
+ | `touchedFields` | `Ref<Record<string, boolean>>` | Per-field touched state |
45
+ | `setFieldTouched` | `(path: string, value?: boolean) => void` | Mark a field as touched |
46
+ | `setFieldValue` | `(path: string, value: unknown) => void` | Programmatically set a field value |
47
+ | `reset` | `(initialValues?: unknown) => void` | Reset touched state and optionally form data |
48
+ | `initialValues` | `Ref<unknown>` | Snapshot of initial values |
49
+
50
+ ## Unsaved Changes Warning
51
+
52
+ ```typescript
53
+ const { isDirty } = useFormState(form);
54
+
55
+ onBeforeRouteLeave((_to, _from, next) => {
56
+ if (isDirty.value) {
57
+ showConfirmDialog({
58
+ title: "Unsaved changes",
59
+ message: "Leave without saving?",
60
+ onConfirm: () => next(),
61
+ onCancel: () => next(false),
62
+ });
63
+ } else {
64
+ next();
65
+ }
66
+ });
67
+ ```
68
+
69
+ ## With useZodForm
70
+
71
+ `useZodForm` already provides `isDirty`, `dirtyFields`, `touched`, and `touchedFields`. Use `useFormState` when you have a form without Zod validation but still need dirty/touched tracking.