@maz-ui/mcp 5.0.0-beta.47 → 5.0.0-beta.49

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/dist/mcp.mjs CHANGED
@@ -7,7 +7,7 @@ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
7
7
  import { resolve, join, dirname } from 'node:path';
8
8
  import { fileURLToPath } from 'node:url';
9
9
 
10
- const version = "5.0.0-beta.46";
10
+ const version = "5.0.0-beta.48";
11
11
 
12
12
  class MetadataExtractor {
13
13
  extract(name, type, content, manualTags = []) {
@@ -177,15 +177,26 @@ Inject extra attributes onto the rendered `<svg>` (or onto the inlined raw SVG)
177
177
  <MazIcon :icon="MazStar" :svg-attributes="{ 'data-testid': 'star', fill: 'currentColor' }" />
178
178
  ```
179
179
 
180
- ## SSR — base URL for relative URLs
180
+ ## SSR
181
181
 
182
- When you render `MazIcon icon="/icons/star.svg"` on the server, `fetch('/icons/star.svg')` cannot resolve without a host. Provide a base URL via Vue's `provide` to fix this:
182
+ Components, raw SVG strings and SVG `data:` URIs (e.g. a small `?url` import inlined by Vite) are always part of the server HTML, without any request.
183
+
184
+ The server never waits for the network to render a URL icon:
185
+
186
+ - once the server has the SVG in its cache, it inlines it;
187
+ - otherwise, it renders an empty placeholder reserving the icon box and fetches the SVG in the background for the next renders. The client loads the icon in the placeholder.
188
+
189
+ A relative URL (`/icons/star.svg`, from your `public/` directory) can only be fetched by the server with an absolute base URL, see below.
190
+
191
+ ## Base URL for relative URLs
192
+
193
+ Prefix every relative URL icon by providing a base URL via Vue's `provide`. An absolute base also lets the server fetch them:
183
194
 
184
195
  ```ts
185
196
  import { createApp } from 'vue'
186
197
 
187
198
  const app = createApp(App)
188
- app.provide('mazIconPath', 'https://your-app.com')
199
+ app.provide('mazIconPath', 'https://cdn.your-app.com')
189
200
  ```
190
201
 
191
202
  In Nuxt, set `mazUi.general.defaultMazIconPath` in `nuxt.config` and `@maz-ui/nuxt` wires the provide for you.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: useFormValidator
3
- description: Vue composables for form validation with Valibot - useFormValidator and useFormField provide a flexible and typed approach to handle form validation in your Vue applications.
3
+ description: Vue composables for form validation with any Standard Schema library (Valibot, Zod, ArkType...) - useFormValidator and useFormField provide a flexible and typed approach to handle form validation in your Vue applications.
4
4
  ---
5
5
 
6
6
  # {{ $frontmatter.title }}
@@ -9,7 +9,7 @@ description: Vue composables for form validation with Valibot - useFormValidator
9
9
 
10
10
  ## Introduction
11
11
 
12
- `useFormValidator` and `useFormField` are two Vue composables that work together to provide powerful form validation using [Valibot](https://valibot.dev/guides/introduction/).
12
+ `useFormValidator` and `useFormField` are two Vue composables that work together to provide powerful form validation. They are **validation library agnostic**: any library implementing [Standard Schema](https://standardschema.dev) works out of the box, like [Valibot](https://valibot.dev), [Zod](https://zod.dev) or [ArkType](https://arktype.io). See [Validation Libraries](#validation-libraries).
13
13
 
14
14
  - **useFormValidator**: Initializes form validation for your entire form. Use it in your form's parent component.
15
15
  - **useFormField**: Manages individual field validation states. Use it when you need fine-grained control over a field or when fields are in child components.
@@ -23,6 +23,24 @@ description: Vue composables for form validation with Valibot - useFormValidator
23
23
 
24
24
  ## Quick Start
25
25
 
26
+ Install the validation library of your choice (Valibot is used in most examples of this page):
27
+
28
+ ::: code-group
29
+
30
+ ```bash [valibot]
31
+ pnpm add valibot
32
+ ```
33
+
34
+ ```bash [zod]
35
+ pnpm add zod
36
+ ```
37
+
38
+ ```bash [arktype]
39
+ pnpm add arktype
40
+ ```
41
+
42
+ :::
43
+
26
44
  Here's the simplest form you can create with `useFormValidator`:
27
45
 
28
46
  <ComponentDemo>
@@ -104,6 +122,186 @@ const onSubmit = handleSubmit((data) => {
104
122
  </template>
105
123
  </ComponentDemo>
106
124
 
125
+ ## Validation Libraries
126
+
127
+ `useFormValidator` relies on [Standard Schema](https://standardschema.dev), a common interface shared by the main validation libraries. Maz-UI does not ship any validation library: install the one you prefer and pass its schemas. Valibot, Zod and ArkType are declared as optional peer dependencies of `maz-ui`, so your package manager warns you if the installed version is not supported.
128
+
129
+ | Library | Supported versions |
130
+ |---------|--------------------|
131
+ | [Valibot](https://valibot.dev) | `>=1.0.0 <2.0.0` |
132
+ | [Zod](https://zod.dev) | `>=3.24.0 <5.0.0` (v3 and v4) |
133
+ | [ArkType](https://arktype.io) | `>=2.0.0 <3.0.0` |
134
+ | [Others](https://standardschema.dev/#what-schema-libraries-implement-the-spec) | Any library implementing Standard Schema V1 |
135
+
136
+ The `schema` option is always a **plain object** where each key is a field name and each value is a schema of your library. Do not wrap it with `object()` / `z.object()`.
137
+
138
+ ### Same form, different libraries
139
+
140
+ ::: code-group
141
+
142
+ ```ts [valibot]
143
+ import { useFormValidator } from 'maz-ui/composables'
144
+ import { email, minLength, nonEmpty, pipe, string } from 'valibot'
145
+
146
+ const { model, errorMessages, handleSubmit } = useFormValidator({
147
+ schema: {
148
+ email: pipe(string(), nonEmpty('Email is required'), email('Invalid email')),
149
+ password: pipe(string(), minLength(8, 'Min 8 characters')),
150
+ },
151
+ })
152
+ ```
153
+
154
+ ```ts [zod]
155
+ import { useFormValidator } from 'maz-ui/composables'
156
+ import { z } from 'zod'
157
+
158
+ const { model, errorMessages, handleSubmit } = useFormValidator({
159
+ schema: {
160
+ email: z.string().min(1, 'Email is required').pipe(z.email('Invalid email')),
161
+ password: z.string().min(8, 'Min 8 characters'),
162
+ },
163
+ })
164
+ ```
165
+
166
+ ```ts [arktype]
167
+ import { type } from 'arktype'
168
+ import { useFormValidator } from 'maz-ui/composables'
169
+
170
+ const { model, errorMessages, handleSubmit } = useFormValidator({
171
+ schema: {
172
+ email: type('string.email'),
173
+ password: type('string >= 8'),
174
+ },
175
+ })
176
+ ```
177
+
178
+ :::
179
+
180
+ ### Live example with Zod
181
+
182
+ <ComponentDemo>
183
+ <form class="maz:flex maz:flex-col maz:gap-4" @submit="onSubmitZod">
184
+ <MazInput
185
+ v-model="zodModel.username"
186
+ label="Username"
187
+ :hint="zodErrors.username"
188
+ :error="!!zodErrors.username"
189
+ :success="zodStates.username.valid"
190
+ />
191
+ <MazInput
192
+ v-model="zodModel.age"
193
+ label="Age"
194
+ type="number"
195
+ :hint="zodErrors.age"
196
+ :error="!!zodErrors.age"
197
+ :success="zodStates.age.valid"
198
+ />
199
+ <MazBtn type="submit" :loading="zodSubmitting">
200
+ Submit
201
+ </MazBtn>
202
+ </form>
203
+
204
+ <template #code>
205
+
206
+ ```vue
207
+ <script lang="ts" setup>
208
+ import { useFormValidator } from 'maz-ui/composables'
209
+ import { z } from 'zod'
210
+
211
+ const schema = {
212
+ username: z.string().min(1, 'Username is required').min(3, 'Min 3 characters'),
213
+ age: z.number({ error: 'Age is required' }).min(18, 'Min 18').max(100, 'Max 100'),
214
+ }
215
+
216
+ const {
217
+ model,
218
+ errorMessages,
219
+ fieldsStates,
220
+ isSubmitting,
221
+ handleSubmit,
222
+ } = useFormValidator({ schema })
223
+
224
+ const onSubmit = handleSubmit((data) => {
225
+ // data is typed as { username: string, age: number }
226
+ console.log('Form submitted:', data)
227
+ })
228
+ </script>
229
+
230
+ <template>
231
+ <form @submit="onSubmit">
232
+ <MazInput
233
+ v-model="model.username"
234
+ label="Username"
235
+ :hint="errorMessages.username"
236
+ :error="!!errorMessages.username"
237
+ :success="fieldsStates.username.valid"
238
+ />
239
+ <MazInput
240
+ v-model="model.age"
241
+ label="Age"
242
+ type="number"
243
+ :hint="errorMessages.age"
244
+ :error="!!errorMessages.age"
245
+ :success="fieldsStates.age.valid"
246
+ />
247
+ <MazBtn type="submit" :loading="isSubmitting">
248
+ Submit
249
+ </MazBtn>
250
+ </form>
251
+ </template>
252
+ ```
253
+
254
+ </template>
255
+ </ComponentDemo>
256
+
257
+ ### Mixing libraries
258
+
259
+ Each field is validated by its own schema, so you can mix libraries in the same form (useful during a progressive migration from one library to another):
260
+
261
+ ```ts
262
+ import { useFormValidator } from 'maz-ui/composables'
263
+ import { email, pipe, string } from 'valibot'
264
+ import { z } from 'zod'
265
+
266
+ const { model } = useFormValidator({
267
+ schema: {
268
+ email: pipe(string(), email('Invalid email')),
269
+ age: z.number().min(18, 'Min 18'),
270
+ },
271
+ })
272
+ ```
273
+
274
+ ### Custom schema
275
+
276
+ You can also write your own validator by implementing the `StandardSchemaV1` interface (exported by `maz-ui/composables`). `validate` can be synchronous or return a `Promise`:
277
+
278
+ ```ts
279
+ import type { StandardSchemaV1 } from 'maz-ui/composables'
280
+ import { useFormValidator } from 'maz-ui/composables'
281
+
282
+ const frenchZipCode: StandardSchemaV1<string, string> = {
283
+ '~standard': {
284
+ version: 1,
285
+ vendor: 'my-app',
286
+ validate: value =>
287
+ typeof value === 'string' && /^\d{5}$/.test(value)
288
+ ? { value }
289
+ : { issues: [{ message: 'Invalid zip code' }] },
290
+ },
291
+ }
292
+
293
+ const { model } = useFormValidator({
294
+ schema: { zipCode: frenchZipCode },
295
+ })
296
+ ```
297
+
298
+ ### Good to know
299
+
300
+ - **Empty values**: `undefined` and `null` field values are validated as an empty string (`''`). To make a field required, use a length rule (`nonEmpty()` with Valibot, `.min(1)` with Zod). An optional field with a format rule (email, URL...) has to accept the empty string explicitly, for example `z.email().or(z.literal(''))` with Zod or `union([literal(''), pipe(string(), email())])` with Valibot.
301
+ - **Error messages**: `errorMessages` contains the message of the first issue of each field, whatever the library.
302
+ - **Issues type**: `errors` and `fieldsStates[field].errors` are typed as `ValidationIssues`, the Standard Schema issue shape (`message` and `path`). At runtime, they are the native issues of your library, so you can cast them to access library specific properties (for example `BaseIssue<unknown>` from Valibot or `z.core.$ZodIssue` from Zod).
303
+ - **Type inference**: the `model` type (input) and the `handleSubmit` payload type (output, after transformations) are inferred from the schemas whatever the library.
304
+
107
305
  ## Understanding Form State
108
306
 
109
307
  `useFormValidator` returns several reactive values to help you manage your form:
@@ -699,7 +897,7 @@ const { value, errorMessage, hasError, validationEvents } = useFormField<string>
699
897
 
700
898
  ## TypeScript Type Inference
701
899
 
702
- The form model is automatically typed based on your schema:
900
+ The form model is automatically typed based on your schema, whatever the validation library:
703
901
 
704
902
  ```ts
705
903
  const schema = {
@@ -745,7 +943,23 @@ const { value: email } = useFormField<string>('email', {
745
943
 
746
944
  ## Async Validation
747
945
 
748
- Use Valibot's `pipeAsync` and `checkAsync` for async validations like checking username availability:
946
+ Async validations (like checking username availability) are supported by every library: Valibot's `pipeAsync` and `checkAsync`, Zod's async `refine`, etc. The example below uses Valibot, here is the Zod equivalent of the schema:
947
+
948
+ ```ts
949
+ import { z } from 'zod'
950
+
951
+ const schema = {
952
+ username: z
953
+ .string()
954
+ .min(1, 'Username is required')
955
+ .min(3, 'Min 3 characters')
956
+ .refine(async (value) => {
957
+ // Simulate API call
958
+ await new Promise(resolve => setTimeout(resolve, 2000))
959
+ return value !== 'taken'
960
+ }, 'Username is already taken'),
961
+ }
962
+ ```
749
963
 
750
964
  <ComponentDemo>
751
965
  <div class="maz:mb-4">
@@ -1065,7 +1279,7 @@ If your custom component isn't detected for blur events, add `data-interactive`:
1065
1279
 
1066
1280
  ```ts
1067
1281
  useFormValidator<TSchema>({
1068
- schema: TSchema, // Valibot validation schema (required)
1282
+ schema: TSchema, // Object of Standard Schema field schemas: Valibot, Zod, ArkType... (required)
1069
1283
  model?: Ref<Model>, // External model ref (optional)
1070
1284
  defaultValues?: DeepPartial<Model>, // Initial values (optional)
1071
1285
  options?: {
@@ -1140,6 +1354,14 @@ useFormField<FieldType>(
1140
1354
  ### Types
1141
1355
 
1142
1356
  ```ts
1357
+ // Standard Schema issue (https://standardschema.dev)
1358
+ interface ValidationIssue {
1359
+ readonly message: string
1360
+ readonly path?: ReadonlyArray<PropertyKey | { readonly key: PropertyKey }>
1361
+ }
1362
+
1363
+ type ValidationIssues = ValidationIssue[]
1364
+
1143
1365
  interface FormValidatorOptions<Model> {
1144
1366
  mode?: 'eager' | 'lazy' | 'aggressive' | 'blur' | 'progressive'
1145
1367
  throttledFields?: Partial<Record<keyof Model, number | true>>
@@ -1252,9 +1474,29 @@ import {
1252
1474
  pipeAsync,
1253
1475
  checkAsync,
1254
1476
  } from 'valibot'
1477
+ import { z } from 'zod'
1255
1478
 
1256
1479
  const toast = useToast()
1257
1480
 
1481
+ // Zod Demo
1482
+ const zodSchema = {
1483
+ username: z.string().min(1, 'Username is required').min(3, 'Min 3 characters'),
1484
+ age: z.number({ error: 'Age is required' }).min(18, 'Min 18').max(100, 'Max 100'),
1485
+ }
1486
+
1487
+ const {
1488
+ model: zodModel,
1489
+ errorMessages: zodErrors,
1490
+ fieldsStates: zodStates,
1491
+ isSubmitting: zodSubmitting,
1492
+ handleSubmit: handleZod,
1493
+ } = useFormValidator({ schema: zodSchema })
1494
+
1495
+ const onSubmitZod = handleZod(async (data) => {
1496
+ await sleep(1000)
1497
+ toast.success(`Welcome ${data.username} (${data.age})!`, { position: 'top' })
1498
+ })
1499
+
1258
1500
  // Quick Start Demo
1259
1501
  const quickStartSchema = {
1260
1502
  email: pipe(string(), nonEmpty('Email is required'), email('Invalid email')),
@@ -86,7 +86,8 @@ The MCP server is read-only — it ships docs, not code edits — so the assista
86
86
  9. **`MazAvatar` size scale fixed.** A CSS-unit `size` now renders at its real value (`size="2rem"` is a 32px avatar, it was ~96px before). Multiply your unit values by 3 to keep the same render, or switch to a `MazSize` keyword (`'mini' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'`). The upgrade tool does the ×3 rewrite for you on static values.
87
87
  10. Rename **`MazPullToRefresh`**'s `on-click` prop to `on-refresh` (handled by the upgrade tool).
88
88
  11. Replace bare **`from 'maz-ui'`** utility imports with **`from '@maz-ui/utils'`** (the root re-export of utils was removed; handled by the upgrade tool). Components/composables/directives/plugins stay on their subpaths; types remain importable from `maz-ui`.
89
- 12. That's it for most apps. Everything else is opt-in.
89
+ 12. If you use **`useFormValidator` / `useFormField`** with Valibot, add **`valibot`** to your own dependencies (it is no longer installed by `maz-ui`). The composables now accept any [Standard Schema](https://standardschema.dev) library (Valibot, Zod, ArkType...).
90
+ 13. That's it for most apps. Everything else is opt-in.
90
91
 
91
92
  ## Prerequisites
92
93
 
@@ -642,6 +643,48 @@ import type { MazColor, MazSize } from 'maz-ui'
642
643
 
643
644
  `maz-ui` and its `@maz-ui/*` packages ship **ESM only** (no CommonJS build). This was already the case in v4, but if you consume the library from a CommonJS context (old Jest without ESM, `require()`), use a bundler/test runner with ESM support (Vitest, Jest ≥ 29 with ESM, or native `import`).
644
645
 
646
+ ### 20. `useFormValidator`: validation library agnostic (Standard Schema)
647
+
648
+ `useFormValidator` and `useFormField` no longer depend on Valibot. They accept any library implementing [Standard Schema](https://standardschema.dev): Valibot (>= 1.0), Zod (>= 3.24), ArkType (>= 2.0), or your own validator. Your existing Valibot schemas keep working as is: same validation, same error messages, same inferred types for `model` and the `handleSubmit` payload.
649
+
650
+ ```ts
651
+ // v4 and v5 - unchanged
652
+ import { pipe, string, minLength } from 'valibot'
653
+ useFormValidator({ schema: { name: pipe(string(), minLength(3)) } })
654
+
655
+ // v5 - Zod (or mix both in the same schema)
656
+ import { z } from 'zod'
657
+ useFormValidator({ schema: { name: z.string().min(3) } })
658
+ ```
659
+
660
+ What can break:
661
+
662
+ **`valibot` is no longer a dependency of `maz-ui`.** Valibot, Zod and ArkType are now declared as optional peer dependencies (`valibot >=1.0.0 <2.0.0`, `zod >=3.24.0 <5.0.0`, `arktype >=2.0.0 <3.0.0`). If your app imports `valibot` without declaring it (it was installed transitively), add it:
663
+
664
+ ```bash
665
+ pnpm add valibot
666
+ ```
667
+
668
+ **Issue types are now the Standard Schema ones.** `ValidationIssues` (returned by `errors`, `fieldsStates[field].errors`, `useFormField().errors` and the `onError` payload of `handleSubmit`) is now typed as an array of `{ message: string, path?: ... }` instead of Valibot's `BaseIssue<unknown>`. Only TypeScript is affected: at runtime, the issues are still the native Valibot objects. If you read Valibot specific properties (`kind`, `type`, `input`, `expected`, `received`, `requirement`...), cast the issue:
669
+
670
+ ```ts
671
+ import type { BaseIssue } from 'valibot'
672
+
673
+ // v4
674
+ const type = errors.value.email[0].type
675
+
676
+ // v5
677
+ const type = (errors.value.email[0] as BaseIssue<unknown>).type
678
+ ```
679
+
680
+ **`FormSchema` values are typed as `StandardSchemaV1`.** If you typed a schema object with `FormSchema<Model>` and then read Valibot specific properties of its entries (`schema.email.type`, `schema.email.pipe`...), declare the object with `as const satisfies FormSchema<Model>` or without annotation, so TypeScript keeps the Valibot types.
681
+
682
+ ```bash
683
+ # Find usages to check
684
+ rg "useFormValidator|useFormField" src/
685
+ rg "from 'valibot'" src/
686
+ ```
687
+
645
688
  ## Informational changes (probably no action needed)
646
689
 
647
690
  ### Theme colors are now emitted as OKLCh
package/docs/src/index.md CHANGED
@@ -465,7 +465,7 @@ description: Build amazing interfaces with Maz-UI - standalone components & tool
465
465
  </div>
466
466
  <h3 class="maz:text-base maz:font-semibold">useFormValidator</h3>
467
467
  <p class="maz:dark:text-gray-300 maz:text-muted maz:text-sm">
468
- A Vue composable designed to simplify form validation using Valibot as the validation library. Offers a flexible and typed approach to handle form validation.
468
+ A Vue composable designed to simplify form validation with any Standard Schema library (Valibot, Zod, ArkType...). Offers a flexible and typed approach to handle form validation.
469
469
  </p>
470
470
  <div class="maz:flex-1"></div>
471
471
  <MazBtn color="surface" outlined size="sm" block href="/composables/use-form-validator">Discover</MazBtn>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@maz-ui/mcp",
3
3
  "type": "module",
4
- "version": "5.0.0-beta.47",
4
+ "version": "5.0.0-beta.49",
5
5
  "description": "Maz-UI ModelContextProtocol Client",
6
6
  "author": "Louis Mazel <me@loicmazuel.com>",
7
7
  "license": "MIT",
@@ -43,7 +43,7 @@
43
43
  "dependencies": {
44
44
  "@maz-ui/utils": "5.0.0-beta.46",
45
45
  "@modelcontextprotocol/sdk": "^1.32.0",
46
- "maz-ui": "5.0.0-beta.47"
46
+ "maz-ui": "5.0.0-beta.49"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@maz-ui/eslint-config": "5.0.0-beta.47",