@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,355 @@
|
|
|
1
|
+
# useZodForm
|
|
2
|
+
|
|
3
|
+
A composable for form validation with [Zod](https://zod.dev) schemas. Supports lazy (validate on submit, then real-time) or eager (validate on every change) validation modes. Integrates with `useScrollToError` for scrolling to the first invalid field.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Install Zod in your project:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun add zod
|
|
11
|
+
# or: npm install zod
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Basic Usage
|
|
15
|
+
|
|
16
|
+
<div class="component-demo">
|
|
17
|
+
|
|
18
|
+
<ZodFormValidationDemo />
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
```vue
|
|
23
|
+
<template>
|
|
24
|
+
<form @submit.prevent="handleSubmit" style="max-width: 300px; display: flex; flex-direction: column; gap: 1rem;">
|
|
25
|
+
<div data-field="email">
|
|
26
|
+
<BvInput
|
|
27
|
+
v-model="form.email"
|
|
28
|
+
type="email"
|
|
29
|
+
label="Email"
|
|
30
|
+
:invalid-text="getError('email')"
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
<div data-field="password">
|
|
34
|
+
<BvInput
|
|
35
|
+
v-model="form.password"
|
|
36
|
+
type="password"
|
|
37
|
+
label="Password"
|
|
38
|
+
help-text="Must be at least 8 characters"
|
|
39
|
+
:invalid-text="getError('password')"
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
<BvButton type="submit">Submit</BvButton>
|
|
43
|
+
</form>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<script setup lang="ts">
|
|
47
|
+
import { BvButton, BvInput } from "@baklavue/ui";
|
|
48
|
+
import { useZodForm } from "@baklavue/composables";
|
|
49
|
+
import { ref } from "vue";
|
|
50
|
+
import { z } from "zod";
|
|
51
|
+
|
|
52
|
+
const form = ref({
|
|
53
|
+
email: "",
|
|
54
|
+
password: "",
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const schema = z.object({
|
|
58
|
+
email: z.string().min(1, "Email is required").email("Please enter a valid email"),
|
|
59
|
+
password: z.string().min(8, "Password must be at least 8 characters"),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const { validate, getError, scrollToFirstError } = useZodForm(schema, form, {
|
|
63
|
+
mode: "lazy",
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const handleSubmit = async () => {
|
|
67
|
+
const errors = await validate();
|
|
68
|
+
if (!errors) {
|
|
69
|
+
console.log("Form submitted:", form.value);
|
|
70
|
+
} else {
|
|
71
|
+
scrollToFirstError();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
</script>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Validation Modes
|
|
78
|
+
|
|
79
|
+
### Lazy (default)
|
|
80
|
+
|
|
81
|
+
Validates only when you call `validate()`. After the first validation, errors update in real time as the user types. Best for forms where you want to avoid showing errors until the user attempts to submit.
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
const { validate } = useZodForm(schema, form, { mode: "lazy" });
|
|
85
|
+
|
|
86
|
+
const handleSubmit = async () => {
|
|
87
|
+
const errors = await validate();
|
|
88
|
+
if (!errors) {
|
|
89
|
+
// submit
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Eager
|
|
95
|
+
|
|
96
|
+
Validates immediately when form data changes. Errors appear as soon as the user interacts with fields. Use for shorter forms or when you want immediate feedback.
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
const { validate } = useZodForm(schema, form, { mode: "eager" });
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## API
|
|
103
|
+
|
|
104
|
+
### Parameters
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
useZodForm(schema, data, options?)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
| Parameter | Type | Description |
|
|
111
|
+
| --- | --- | --- |
|
|
112
|
+
| `schema` | `ZodSchema \| Ref<ZodSchema> \| () => ZodSchema` | Zod schema (object, ref, or getter) |
|
|
113
|
+
| `data` | `Ref<T> \| Reactive<T> \| () => T` | Form data (ref, reactive, or getter) |
|
|
114
|
+
| `options` | `UseZodFormOptions` | Optional: `{ mode: 'lazy' \| 'eager', debounce?: number }` |
|
|
115
|
+
|
|
116
|
+
### Return Value
|
|
117
|
+
|
|
118
|
+
| Property | Type | Description |
|
|
119
|
+
| --- | --- | --- |
|
|
120
|
+
| `validate` | `() => Promise<FormErrors \| null>` | Runs validation. Returns errors or `null` if valid |
|
|
121
|
+
| `validateField` | `(path: string) => Promise<FormErrors \| null>` | Validates only the field at path (use on blur). Falls back to full validation if schema cannot be extracted |
|
|
122
|
+
| `errors` | `Ref<FormErrors>` | Reactive errors grouped by field path |
|
|
123
|
+
| `isValid` | `Ref<boolean>` | Whether the form is currently valid |
|
|
124
|
+
| `clearErrors` | `() => void` | Clears all errors |
|
|
125
|
+
| `reset` | `(initialValues?: unknown) => void` | Clears errors, touched fields, and optionally resets form data to initial values |
|
|
126
|
+
| `getError` | `(path: string) => string \| undefined` | Returns first error message for a field path |
|
|
127
|
+
| `getErrors` | `(path: string) => string[]` | Returns all error messages for a field path |
|
|
128
|
+
| `handleSubmit` | `(onSubmit: (data) => R \| Promise<R>) => Promise<R>` | Validates, then calls onSubmit with validated data if valid; otherwise scrolls to first error and rejects |
|
|
129
|
+
| `scrollToFirstError` | `(options?: ScrollToFirstErrorOptions) => ScrollToErrorResult` | Scrolls to first invalid field (requires `data-field` on wrapper). Returns `{ success: boolean }` |
|
|
130
|
+
| `setFieldValue` | `(path: string, value: unknown) => void` | Programmatically set a field value |
|
|
131
|
+
| `setErrors` | `(errors: FormErrors) => void` | Set errors (e.g. from server-side validation) |
|
|
132
|
+
| `setFieldError` | `(path: string, message: string) => void` | Set error for a single field |
|
|
133
|
+
| `initialValues` | `Ref<unknown>` | Snapshot of initial values (used for dirty check and reset) |
|
|
134
|
+
| `isDirty` | `Ref<boolean>` | Whether any field has changed from initial values |
|
|
135
|
+
| `dirtyFields` | `Ref<Record<string, boolean>>` | Per-field dirty state |
|
|
136
|
+
| `touched` | `Ref<boolean>` | Whether any field has been blurred |
|
|
137
|
+
| `touchedFields` | `Ref<Record<string, boolean>>` | Per-field touched state |
|
|
138
|
+
| `setFieldTouched` | `(path: string, value?: boolean) => void` | Mark a field as touched (e.g. on blur) |
|
|
139
|
+
| `isSubmitting` | `Ref<boolean>` | `true` while `handleSubmit` callback is running |
|
|
140
|
+
| `isSubmitted` | `Ref<boolean>` | `true` after first submit attempt |
|
|
141
|
+
| `submitCount` | `Ref<number>` | Number of submit attempts |
|
|
142
|
+
|
|
143
|
+
### UseZodFormOptions
|
|
144
|
+
|
|
145
|
+
| Option | Type | Default | Description |
|
|
146
|
+
| --- | --- | --- | --- |
|
|
147
|
+
| `mode` | `'lazy' \| 'eager'` | `'lazy'` | When to run validation |
|
|
148
|
+
| `debounce` | `number` | `0` | Debounce validation in ms for eager mode. Use for large forms |
|
|
149
|
+
|
|
150
|
+
## Scroll to First Error
|
|
151
|
+
|
|
152
|
+
Use `scrollToFirstError()` after validation fails to scroll to the first invalid field. Wrap each form control in an element with `data-field` matching the schema path:
|
|
153
|
+
|
|
154
|
+
```vue
|
|
155
|
+
<template>
|
|
156
|
+
<form @submit.prevent="handleSubmit">
|
|
157
|
+
<div data-field="email">
|
|
158
|
+
<BvInput v-model="form.email" :invalid-text="getError('email')" />
|
|
159
|
+
</div>
|
|
160
|
+
<div data-field="password">
|
|
161
|
+
<BvInput v-model="form.password" :invalid-text="getError('password')" />
|
|
162
|
+
</div>
|
|
163
|
+
<BvButton type="submit">Submit</BvButton>
|
|
164
|
+
</form>
|
|
165
|
+
</template>
|
|
166
|
+
|
|
167
|
+
<script setup lang="ts">
|
|
168
|
+
const { validate, getError, scrollToFirstError } = useZodForm(schema, form);
|
|
169
|
+
|
|
170
|
+
const handleSubmit = async () => {
|
|
171
|
+
const errors = await validate();
|
|
172
|
+
if (errors) {
|
|
173
|
+
scrollToFirstError();
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
</script>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
`scrollToFirstError` accepts the same options as [useScrollToError](/composables/scrollToError) (`scrollBehavior`, `block`, `shineClass`, `shineDuration`, `focus`, `focusDelay`, `scrollContainer`, `announce`, `scrollOffset`), plus `fieldSelector` to customize how field paths map to DOM selectors:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
scrollToFirstError({
|
|
183
|
+
fieldSelector: (path) => `[name="${path}"]`, // Use name attribute instead of data-field
|
|
184
|
+
scrollContainer: "[data-dialog-body]", // For forms inside modals
|
|
185
|
+
scrollOffset: { top: 80 }, // For fixed headers
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## handleSubmit
|
|
190
|
+
|
|
191
|
+
Use `handleSubmit(onSubmit)` to validate and submit in one call. If validation fails, it scrolls to the first error and rejects. If valid, it calls `onSubmit` with the validated (and possibly transformed) data:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
const { handleSubmit } = useZodForm(schema, form);
|
|
195
|
+
|
|
196
|
+
const onSubmit = () =>
|
|
197
|
+
handleSubmit(async (data) => {
|
|
198
|
+
await api.submit(data);
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
`handleSubmit` sets `isSubmitting` to `true` while the callback runs. Use it to disable the submit button:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
const { handleSubmit, isSubmitting } = useZodForm(schema, form);
|
|
206
|
+
|
|
207
|
+
const onSubmit = () =>
|
|
208
|
+
handleSubmit(async (data) => await api.submit(data));
|
|
209
|
+
|
|
210
|
+
// In template: <BvButton type="submit" :disabled="isSubmitting">Submit</BvButton>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
For additional loading overlay, combine with [useLoading](/composables/loading):
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
const { handleSubmit, isSubmitting } = useZodForm(schema, form);
|
|
217
|
+
const { withLoading } = useLoading();
|
|
218
|
+
|
|
219
|
+
const onSubmit = () =>
|
|
220
|
+
withLoading(() =>
|
|
221
|
+
handleSubmit(async (data) => await api.submit(data))
|
|
222
|
+
);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## reset
|
|
226
|
+
|
|
227
|
+
Use `reset()` to clear errors and optionally reset form data. Pass initial values when using a ref:
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
const { reset } = useZodForm(schema, form);
|
|
231
|
+
|
|
232
|
+
// Clear errors only
|
|
233
|
+
reset();
|
|
234
|
+
|
|
235
|
+
// Reset to initial values (when data is a ref)
|
|
236
|
+
reset({ email: "", password: "" });
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## On-Blur Validation
|
|
240
|
+
|
|
241
|
+
For field-level validation on blur, use `validateField`:
|
|
242
|
+
|
|
243
|
+
```vue
|
|
244
|
+
<div data-field="email">
|
|
245
|
+
<BvInput
|
|
246
|
+
v-model="form.email"
|
|
247
|
+
@blur="validateField('email')"
|
|
248
|
+
:invalid-text="getError('email')"
|
|
249
|
+
/>
|
|
250
|
+
</div>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Debounce (Eager Mode)
|
|
254
|
+
|
|
255
|
+
For large forms or expensive schemas in eager mode, add a debounce to avoid validating on every keystroke:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
const { validate } = useZodForm(schema, form, {
|
|
259
|
+
mode: "eager",
|
|
260
|
+
debounce: 300,
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Dirty & Touched State
|
|
265
|
+
|
|
266
|
+
`isDirty` and `dirtyFields` track whether the form has changed from its initial values. Useful for "unsaved changes" dialogs:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
const { isDirty } = useZodForm(schema, form);
|
|
270
|
+
|
|
271
|
+
// Before navigation
|
|
272
|
+
if (isDirty.value) {
|
|
273
|
+
showConfirmDialog("You have unsaved changes");
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
`touched` and `touchedFields` track which fields have been blurred. Call `setFieldTouched(path)` on blur to enable "show error only after touch" UX:
|
|
278
|
+
|
|
279
|
+
```vue
|
|
280
|
+
<BvInput
|
|
281
|
+
v-model="form.email"
|
|
282
|
+
@blur="setFieldTouched('email')"
|
|
283
|
+
:invalid-text="touchedFields.email ? getError('email') : undefined"
|
|
284
|
+
/>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Server-Side Errors
|
|
288
|
+
|
|
289
|
+
Use `setErrors` or `setFieldError` when the API returns validation errors:
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
const { setErrors, setFieldError } = useZodForm(schema, form);
|
|
293
|
+
|
|
294
|
+
try {
|
|
295
|
+
await api.submit(form.value);
|
|
296
|
+
} catch (err) {
|
|
297
|
+
if (err.response?.data?.errors) {
|
|
298
|
+
// Map API errors to FormErrors shape: { "path": ZodIssue[] }
|
|
299
|
+
setErrors(mapApiErrorsToFormErrors(err.response.data.errors));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
For a single field:
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
setFieldError("email", "This email is already registered");
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Nested Fields
|
|
311
|
+
|
|
312
|
+
For nested schema paths like `address.city`, use the dot notation in `getError`:
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
const schema = z.object({
|
|
316
|
+
address: z.object({
|
|
317
|
+
city: z.string().min(1, "City is required"),
|
|
318
|
+
}),
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// In template
|
|
322
|
+
getError("address.city");
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
```vue
|
|
326
|
+
<div data-field="address.city">
|
|
327
|
+
<BvInput v-model="form.address.city" :invalid-text="getError('address.city')" />
|
|
328
|
+
</div>
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## TypeScript Support
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
import {
|
|
335
|
+
useZodForm,
|
|
336
|
+
type FormErrors,
|
|
337
|
+
type InferFormData,
|
|
338
|
+
type ScrollToFirstErrorOptions,
|
|
339
|
+
type UseZodFormOptions,
|
|
340
|
+
} from "@baklavue/composables";
|
|
341
|
+
import { z } from "zod";
|
|
342
|
+
|
|
343
|
+
const schema = z.object({
|
|
344
|
+
email: z.string().email(),
|
|
345
|
+
password: z.string().min(8),
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
type FormData = z.infer<typeof schema>;
|
|
349
|
+
const form = ref<FormData>({ email: "", password: "" });
|
|
350
|
+
|
|
351
|
+
const { validate, errors, isValid, getError, handleSubmit } = useZodForm(
|
|
352
|
+
schema,
|
|
353
|
+
form,
|
|
354
|
+
);
|
|
355
|
+
```
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# useDateFormat & useNumberFormat
|
|
2
|
+
|
|
3
|
+
Composables for reactive, locale-aware date and number formatting using native `Intl.DateTimeFormat` and `Intl.NumberFormat`. No external date library required.
|
|
4
|
+
|
|
5
|
+
## useDateFormat
|
|
6
|
+
|
|
7
|
+
### Basic Usage
|
|
8
|
+
|
|
9
|
+
```vue
|
|
10
|
+
<template>
|
|
11
|
+
<span>{{ formatted }}</span>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup>
|
|
15
|
+
import { ref } from "vue";
|
|
16
|
+
import { useDateFormat } from "@baklavue/composables";
|
|
17
|
+
|
|
18
|
+
const date = ref(new Date());
|
|
19
|
+
const formatted = useDateFormat(date, { dateStyle: "medium" });
|
|
20
|
+
// "Feb 11, 2025"
|
|
21
|
+
</script>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### With Locale
|
|
25
|
+
|
|
26
|
+
```vue
|
|
27
|
+
<script setup>
|
|
28
|
+
import { useDateFormat } from "@baklavue/composables";
|
|
29
|
+
|
|
30
|
+
const formatted = useDateFormat(new Date(), {
|
|
31
|
+
year: "numeric",
|
|
32
|
+
month: "short",
|
|
33
|
+
day: "numeric",
|
|
34
|
+
locale: "tr-TR",
|
|
35
|
+
});
|
|
36
|
+
</script>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### API
|
|
40
|
+
|
|
41
|
+
| Argument | Type | Description |
|
|
42
|
+
| --- | --- | --- |
|
|
43
|
+
| `date` | `MaybeRefOrGetter<Date \| string \| number \| null \| undefined>` | Date to format |
|
|
44
|
+
| `options` | `UseDateFormatOptions` | Intl.DateTimeFormatOptions plus optional `locale` |
|
|
45
|
+
|
|
46
|
+
Returns: `ComputedRef<string>`
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## useNumberFormat
|
|
51
|
+
|
|
52
|
+
### Basic Usage
|
|
53
|
+
|
|
54
|
+
```vue
|
|
55
|
+
<template>
|
|
56
|
+
<span>{{ formatted }}</span>
|
|
57
|
+
</template>
|
|
58
|
+
|
|
59
|
+
<script setup>
|
|
60
|
+
import { ref } from "vue";
|
|
61
|
+
import { useNumberFormat } from "@baklavue/composables";
|
|
62
|
+
|
|
63
|
+
const price = ref(99.99);
|
|
64
|
+
const formatted = useNumberFormat(price, { style: "currency", currency: "USD" });
|
|
65
|
+
// "$99.99"
|
|
66
|
+
</script>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Decimal Formatting
|
|
70
|
+
|
|
71
|
+
```vue
|
|
72
|
+
<script setup>
|
|
73
|
+
import { useNumberFormat } from "@baklavue/composables";
|
|
74
|
+
|
|
75
|
+
const count = ref(1234);
|
|
76
|
+
const formatted = useNumberFormat(count, {
|
|
77
|
+
style: "decimal",
|
|
78
|
+
minimumFractionDigits: 2,
|
|
79
|
+
locale: "tr-TR",
|
|
80
|
+
});
|
|
81
|
+
</script>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### API
|
|
85
|
+
|
|
86
|
+
| Argument | Type | Description |
|
|
87
|
+
| --- | --- | --- |
|
|
88
|
+
| `value` | `MaybeRefOrGetter<number \| null \| undefined>` | Number to format |
|
|
89
|
+
| `options` | `UseNumberFormatOptions` | Intl.NumberFormatOptions plus optional `locale` |
|
|
90
|
+
|
|
91
|
+
Returns: `ComputedRef<string>`
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## TypeScript Support
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import {
|
|
99
|
+
useDateFormat,
|
|
100
|
+
useNumberFormat,
|
|
101
|
+
type UseDateFormatOptions,
|
|
102
|
+
type UseNumberFormatOptions,
|
|
103
|
+
} from "@baklavue/composables";
|
|
104
|
+
|
|
105
|
+
const formatted = useDateFormat(dateRef, { dateStyle: "long" });
|
|
106
|
+
const price = useNumberFormat(priceRef, { style: "currency", currency: "EUR" });
|
|
107
|
+
```
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# useId
|
|
2
|
+
|
|
3
|
+
A composable for generating stable unique IDs for use with accessibility attributes such as `aria-describedby`, `aria-labelledby`, and form labels.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```vue
|
|
8
|
+
<template>
|
|
9
|
+
<div>
|
|
10
|
+
<label :for="inputId">Name</label>
|
|
11
|
+
<input :id="inputId" type="text" />
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup>
|
|
16
|
+
import { useId } from "@baklavue/composables";
|
|
17
|
+
|
|
18
|
+
const inputId = useId();
|
|
19
|
+
</script>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Custom Prefix
|
|
23
|
+
|
|
24
|
+
```vue
|
|
25
|
+
<script setup>
|
|
26
|
+
import { useId } from "@baklavue/composables";
|
|
27
|
+
|
|
28
|
+
const dialogId = useId("dialog");
|
|
29
|
+
// dialogId.value = "dialog-1"
|
|
30
|
+
</script>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## API
|
|
34
|
+
|
|
35
|
+
### Return Value
|
|
36
|
+
|
|
37
|
+
Returns a `Ref<string>` — use `id.value` in script or `id` in template for the stable unique ID.
|
|
38
|
+
|
|
39
|
+
### Parameters
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
useId(prefix?: string)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
- `prefix` — Optional prefix for the ID. Default: `"bv"`
|
|
46
|
+
|
|
47
|
+
## TypeScript Support
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { useId } from "@baklavue/composables";
|
|
51
|
+
|
|
52
|
+
const id = useId();
|
|
53
|
+
// id is Ref<string>
|
|
54
|
+
```
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Composables
|
|
2
|
+
|
|
3
|
+
BaklaVue provides Vue 3 composables to enhance your application functionality.
|
|
4
|
+
|
|
5
|
+
## Available Composables
|
|
6
|
+
|
|
7
|
+
### UI & Feedback
|
|
8
|
+
|
|
9
|
+
- [Notification](/composables/notification) (`useNotification`) - Programmatically manage notifications
|
|
10
|
+
- [Confirm Dialog](/composables/confirmDialog) (`useConfirmDialog`) - Confirm/cancel dialog flow
|
|
11
|
+
- [Disclosure](/composables/disclosure) (`useDisclosure`) - Open/close state for Dialog, Drawer, Dropdown
|
|
12
|
+
- [Stepper](/composables/stepper) (`useStepper`) - Multi-step wizard state for BvStepper
|
|
13
|
+
- [Scroll Visibility](/composables/scrollVisibility) (`useScrollVisibility`) - Scroll-based visibility for scroll-to-top and sticky UI
|
|
14
|
+
- [Scroll Lock](/composables/scrollLock) (`useScrollLock`) - Lock body scroll when modals/drawers are open
|
|
15
|
+
- [Alert](/composables/alert) (`useAlert`) - Programmatic show/hide for inline BvAlert
|
|
16
|
+
- [Loading](/composables/loading) (`useLoading`) - Generic loading state with optional delay
|
|
17
|
+
- [Focus Trap](/composables/focusTrap) (`useFocusTrap`) - Trap focus within modals/dialogs
|
|
18
|
+
- [Id](/composables/id) (`useId`) - Stable unique IDs for accessibility attributes
|
|
19
|
+
|
|
20
|
+
### Forms
|
|
21
|
+
|
|
22
|
+
- [Form Validation](/composables/formValidation) (`useZodForm`) - Form validation with Zod schemas
|
|
23
|
+
- [Form State](/composables/formState) (`useFormState`) - Form dirty and touched state without validation
|
|
24
|
+
- [Field Array](/composables/fieldArray) (`useFieldArray`) - Dynamic array fields for forms
|
|
25
|
+
- [Form Persistence](/composables/formPersistence) (`useFormPersistence`) - Auto-save form data to localStorage/sessionStorage
|
|
26
|
+
- [Stepper Form](/composables/stepperForm) (`useStepperForm`) - Multi-step form validation with useStepper
|
|
27
|
+
- [Scroll to Error](/composables/scrollToError) (`useScrollToError`) - Scroll to element with validation error
|
|
28
|
+
|
|
29
|
+
### Data & Utilities
|
|
30
|
+
|
|
31
|
+
- [File](/composables/file) (`useFile`) - Parse, create, and download CSV, TSV, and JSON files
|
|
32
|
+
- [Clipboard](/composables/clipboard) (`useClipboard`) - Copy text to clipboard
|
|
33
|
+
- [Storage](/composables/storage) (`useLocalStorage` / `useSessionStorage`) - Reactive sync with localStorage and sessionStorage
|
|
34
|
+
- [Cookie](/composables/cookie) (`useCookie`) - Reactive sync with document.cookie
|
|
35
|
+
- [Share](/composables/share) (`useShare`) - Share text, URLs, or files via Web Share API
|
|
36
|
+
- [Base64](/composables/base64) (`useBase64`) - Convert Blob/File/ArrayBuffer/canvas to Base64
|
|
37
|
+
- [Previous](/composables/previous) (`usePrevious`) - Track previous value of a ref
|
|
38
|
+
- [Toggle](/composables/toggle) (`useToggle`) - Simple boolean toggle
|
|
39
|
+
- [DateFormat](/composables/format) (`useDateFormat`) - Reactive locale-aware date formatting
|
|
40
|
+
- [NumberFormat](/composables/format) (`useNumberFormat`) - Reactive locale-aware number/currency formatting
|
|
41
|
+
- [Slug](/composables/slug) (`useSlug`) - Convert string to URL-friendly slug
|
|
42
|
+
- [Async State](/composables/asyncState) (`useAsyncState`) - Generic async state (loading, error, data)
|
|
43
|
+
|
|
44
|
+
### Performance
|
|
45
|
+
|
|
46
|
+
- [Debounce](/composables/debounce) (`useDebounceFn` / `useDebouncedRef`) - Debounce function or ref value
|
|
47
|
+
- [Throttle](/composables/throttle) (`useThrottleFn` / `useThrottledRef`) - Throttle function or ref value
|
|
48
|
+
- [Timer](/composables/timer) (`useIntervalFn` / `useTimeoutFn`) - Pausable interval and cancellable timeout
|
|
49
|
+
- [Request Animation Frame](/composables/raf) (`useRafFn`) - Animation frame loop
|
|
50
|
+
|
|
51
|
+
### Browser APIs
|
|
52
|
+
|
|
53
|
+
- [Breakpoints](/composables/breakpoints) (`useBreakpoints`) - Responsive breakpoints (isMobile, isTablet, isDesktop)
|
|
54
|
+
- [Window Size](/composables/breakpoints#use-window-size) (`useWindowSize`) - Reactive viewport width and height
|
|
55
|
+
- [Intersection Observer](/composables/intersectionObserver) (`useIntersectionObserver`) - Detect element visibility in viewport
|
|
56
|
+
- [Element Size](/composables/elementSize) (`useElementSize`) - Reactive element dimensions via ResizeObserver
|
|
57
|
+
- [Container Scroll](/composables/containerScroll) (`useContainerScroll`) - Scroll position inside a scrollable div
|
|
58
|
+
- [Sticky](/composables/sticky) (`useSticky`) - Detect when sticky element is stuck
|
|
59
|
+
|
|
60
|
+
### Data Fetching
|
|
61
|
+
|
|
62
|
+
- [Fetch](/composables/fetch) (`useFetch`) - Reactive fetch with loading/error/data
|
|
63
|
+
- [Query](/composables/query) (`useQuery`) - Data fetching with caching, retries, and invalidation
|
|
64
|
+
- [Mutation](/composables/mutation) (`useMutation`) - Mutations (POST/PUT/DELETE) with cache invalidation
|
|
65
|
+
- [Infinite Query](/composables/infiniteQuery) (`useInfiniteQuery`) - Infinite scroll / cursor-based pagination
|
|
66
|
+
- [Lazy Query](/composables/lazyQuery) (`useLazyQuery`) - On-demand queries that fetch when execute() is called
|
|
67
|
+
- [Polling](/composables/polling) (`usePolling`) - Polling with fetch state (non-cached)
|
|
68
|
+
|
|
69
|
+
### Theme & Layout
|
|
70
|
+
|
|
71
|
+
- [Theme](/composables/theme) (`useBaklavaTheme`) - Overwrite Baklava colors (Vue preset or custom)
|
|
72
|
+
- [Color Scheme](/composables/colorScheme) (`useColorScheme`) - Light/dark/system with persistence
|
|
73
|
+
- [Theme Preset](/composables/themePreset) (`useThemePreset`) - Persist Baklava theme preset
|
|
74
|
+
- [Pagination](/composables/pagination) (`usePagination`) - Pagination state for tables and lists
|
|
75
|
+
|
|
76
|
+
## Usage Pattern
|
|
77
|
+
|
|
78
|
+
Composables follow Vue 3 Composition API patterns:
|
|
79
|
+
|
|
80
|
+
```vue
|
|
81
|
+
<script setup>
|
|
82
|
+
import { useNotification } from "@baklavue/composables";
|
|
83
|
+
|
|
84
|
+
const { success, error, warning, info } = useNotification();
|
|
85
|
+
|
|
86
|
+
// Use the composable methods
|
|
87
|
+
success({
|
|
88
|
+
caption: "Success!",
|
|
89
|
+
description: "Operation completed",
|
|
90
|
+
});
|
|
91
|
+
</script>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Importing Composables
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { useNotification } from "@baklavue/composables";
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## TypeScript Support
|
|
101
|
+
|
|
102
|
+
All composables are fully typed:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import type { ApplyThemeOptions } from "@baklavue/composables";
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Next Steps
|
|
109
|
+
|
|
110
|
+
- Explore individual composable documentation
|
|
111
|
+
- Check [API Reference](/api/) for detailed API
|
|
112
|
+
- See [Getting Started Guide](/guide/getting-started) for setup
|