Skip to content

Commit

Permalink
chore: updated docs and improved external errors type
Browse files Browse the repository at this point in the history
  • Loading branch information
victorgarciaesgi committed Dec 14, 2024
1 parent 6005d84 commit 474b124
Show file tree
Hide file tree
Showing 14 changed files with 94 additions and 76 deletions.
25 changes: 20 additions & 5 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const AdvancedUsage: (DefaultTheme.NavItemWithLink | DefaultTheme.NavItemChildre
{ text: 'Using metadata from rules', link: '/advanced-usage/rule-metadata' },
{ text: 'Rules operators', link: '/advanced-usage/rules-operators' },
{ text: 'Validation helpers', link: '/advanced-usage/validations-helpers' },
{ text: 'Usage with Zod', link: '/advanced-usage/usage-with-zod' },
{ text: 'Async validation', link: '/advanced-usage/async-validation' },
];

const Typescript: (DefaultTheme.NavItemWithLink | DefaultTheme.NavItemChildren)[] = [
Expand All @@ -60,6 +60,17 @@ const Typescript: (DefaultTheme.NavItemWithLink | DefaultTheme.NavItemChildren)[
},
];

const Integrations: (DefaultTheme.NavItemWithLink | DefaultTheme.NavItemChildren)[] = [
{
text: 'Nuxt',
link: '/integrations/nuxt',
},
{
text: 'Zod',
link: '/integrations/zod',
},
];

const Examples: DefaultTheme.NavItemWithLink[] = [{ text: 'Simple form example', link: '/examples/simple' }];

const Troubleshooting: DefaultTheme.NavItemWithLink[] = [
Expand Down Expand Up @@ -95,7 +106,6 @@ export default defineConfig({
text: 'Introduction',
items: [
{ text: 'Getting Started', link: '/introduction/' },
{ text: 'Integrations', link: '/introduction/integrations' },
{ text: 'Comparisons', link: '/introduction/comparisons' },
],
collapsed: false,
Expand All @@ -113,17 +123,22 @@ export default defineConfig({
{
text: 'Advanced Usage',
items: AdvancedUsage,
collapsed: false,
collapsed: true,
},
{
text: 'Integrations',
items: Integrations,
collapsed: true,
},
{
text: 'Examples',
items: Examples,
collapsed: false,
collapsed: true,
},
{
text: 'Troubleshooting',
items: Troubleshooting,
collapsed: false,
collapsed: true,
},
],
socialLinks: [{ icon: 'github', link: 'https://github.com/victorgarciaesgi/regle' }],
Expand Down
6 changes: 5 additions & 1 deletion docs/.vitepress/theme/custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ iframe {
flex-flow: row wrap;
align-items: center;
gap: 8px;

.delete {
cursor: pointer;
}
}
}
}
Expand Down Expand Up @@ -182,7 +186,7 @@ iframe {

.password-strength {
margin: 8px 8px 0 8px;
width: 150px;
width: 170px;
height: 4px;
border-radius: 4px;
border: 1px solid var(--vp-c-border);
Expand Down
8 changes: 8 additions & 0 deletions docs/src/advanced-usage/async-validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: Async validations
---


# Async validation

TODO
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
---
title: Integrations
title: Nuxt
---

# Integrations


## Nuxt <span data-title="nuxt"></span>
# Nuxt <span data-title="nuxt"></span>

Adding the Nuxt module enables auto-imports for selected exports.

Expand Down Expand Up @@ -58,28 +56,3 @@ The following exports will become globally available in your Nuxt application:
- `@regle/zod` (if present)
- useZodRegle



## Zod <span data-title="zod"></span>

Regle offers an adapter for [Zod](https://zod.dev/). You can use any zod object schema to validate your state. It offers the same DX as using `@regle/rules`.

Check [documentation for Zod](/advanced-usage/usage-with-zod)

::: code-group
```sh [pnpm]
pnpm add @regle/zod
```

```sh [npm]
npm install @regle/zod
```

```sh [yarn]
yarn add @regle/zod
```

```sh [bun]
bun add @regle/zod
```
:::
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,17 @@ title: Zod
<script setup>
import QuickUsage from '../parts/components/zod/QuickUsage.vue';
import ComputedSchema from '../parts/components/zod/ComputedSchema.vue';

</script>

# Usage with Zod

## Prerequisites
# Zod <span data-title="zod"></span>

- `zod` version `3` or higher.
Regle offers an adapter for [Zod](https://zod.dev/). You can use any zod object schema to validate your state. It offers the same DX as using `@regle/rules`.

## Prerequisites

## Installation
- `zod` version `3.x`

::: code-group

```sh [pnpm]
pnpm add @regle/zod
```
Expand All @@ -37,6 +34,7 @@ bun add @regle/zod
:::



## Usage


Expand Down Expand Up @@ -125,3 +123,4 @@ async function submit() {
}

```

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<label>Required</label>
</div>

<div v-if="form.collection.length > 1" @click="form.collection.splice(index, 1)"></div>
<div v-if="form.collection.length > 1" class="delete" @click="form.collection.splice(index, 1)">🗑️</div>
</div>

<ul v-if="item.$fields.name.$errors.length">
Expand Down Expand Up @@ -51,7 +51,9 @@ function shuffle(arr: any[], options?: any) {
var shuffleAll = options && options.shuffleAll;
var result = arr.slice();
var i = arr.length, rand, temp;
var i = arr.length,
rand,
temp;
while (--i > 0) {
do {
Expand All @@ -63,7 +65,7 @@ function shuffle(arr: any[], options?: any) {
result[rand] = temp;
}
}
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
placeholder="Type an item value"
/>

<div v-if="form.collection.length > 1" @click="form.collection.splice(index, 1)"></div>
<div v-if="form.collection.length > 1" class="delete" @click="form.collection.splice(index, 1)">🗑️</div>
</div>

<ul v-if="item.$fields.name.$errors.length">
Expand Down Expand Up @@ -48,7 +48,9 @@ function shuffle(arr: any[], options?: any) {
var shuffleAll = options && options.shuffleAll;
var result = arr.slice();
var i = arr.length, rand, temp;
var i = arr.length,
rand,
temp;
while (--i > 0) {
do {
Expand All @@ -61,7 +63,7 @@ function shuffle(arr: any[], options?: any) {
result[rand] = temp;
}
}
return result;
}
Expand Down
4 changes: 2 additions & 2 deletions docs/src/parts/components/collections/ValidatingArray.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
placeholder="Type an item value"
/>

<div v-if="form.collection.length > 1" @click="form.collection.splice(index, 1)"></div>
<div v-if="form.collection.length > 1" class="delete" @click="form.collection.splice(index, 1)">🗑️</div>
</div>

<ul v-if="item.$fields.name.$errors.length">
Expand All @@ -25,7 +25,7 @@
{{ error }}
</li>
</ul>

<div class="button-list">
<button type="button" @click="form.collection.push({ name: '' })">🆕 Add item</button>
<button type="button" @click="r$.$resetAll">Reset</button>
Expand Down
2 changes: 1 addition & 1 deletion docs/src/parts/components/modifiers/ExternalErrors.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
</li>
</ul>
</div>

<div>
<button type="button" @click="submit">Submit</button>
<button type="button" @click="r$.$clearExternalErrors">Reset Errors</button>
Expand Down
25 changes: 14 additions & 11 deletions docs/src/troubleshooting/reactivity.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,55 +11,58 @@ When using `useRegle` with a getter function or a computed property, Regle autom
To illustrate the issue, consider the following example:

```ts twoslash
// @noErrors
const form = ref({
items: [] as {weight: number}[]
})
//---cut---
import { ref, computed } from 'vue';
import { withMessage } from '@regle/rules';
import {type Maybe, type RegleComputedRules} from '@regle/core';

const condition = ref(false)

const weight = (greeting: string) => {
return withMessage(value => {
return value > 1 && condition.value === true
return withMessage((value: Maybe<number>) => {
return !!value && value > 1 && condition.value === true
}, `Weight must be greater than 1, ${greeting}`)
}

const rules = computed(() => {
return {
items: {
$each: item => ({
$each: (item) => ({
weight: {
weight: weight('Hello World')
}
})
}
}
} satisfies RegleComputedRules<typeof form>
})
```

In the above example, the `weight` rule depends on the `condition` ref, which is not tracked by Regle because it is inside a function and Vue cannot collect the reference. To fix this, you can either use the `withParams` wrapper or use the `createRule` function which automatically tracks dependencies for you.

```ts twoslash
// @noErrors
import { ref } from 'vue';
import { withParams, withMessage } from '@regle/rules';
import { createRule } from '@regle/core';
import { createRule, type Maybe } from '@regle/core';

const condition = ref(false)

// Usage with `withParams`
const weight1 = (greeting: string) => {
return withMessage(
withParams(value => {
return value > 1 && condition.value === true
withParams((value: Maybe<number>) => {
return !!value && value > 1 && condition.value === true
}, [condition]),
`Weight must be greater than 1, ${greeting}`
)
}

// Usage with `createRule`
const weight2 = createRule({
validator(value: Maybe<number | string>, greeting: string, condition: boolean) {
return value > 1 && condition === true
validator(value: Maybe<number>, greeting: string, condition: boolean) {
return !!value && value > 1 && condition === true
},

message: ({ $params: [greeting] }) => {
Expand Down
26 changes: 19 additions & 7 deletions packages/core/src/types/rules/rule.errors.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,42 @@ import type { MaybeRef, UnwrapNestedRefs } from 'vue';
import type { ReglePartialRuleTree } from './rule.declaration.types';
import type { DeepSafeFormState, SafeFieldProperty } from '../core';
import type { ExtendOnlyRealRecord, Maybe, Prettify } from '../utils';
import type { PartialObjectDeep } from 'type-fest/source/partial-deep';

export type RegleErrorTree<TState = MaybeRef<Record<string, any> | any[]>> = {
readonly [K in keyof UnwrapNestedRefs<TState>]: RegleValidationErrors<UnwrapNestedRefs<TState>[K]>;
};

export type RegleExternalErrorTree<TState = Record<string, any> | any[]> = PartialDeep<
RegleErrorTree<TState>,
{ recurseIntoArrays: true }
>;
export type RegleExternalErrorTree<TState = MaybeRef<Record<string, any> | any[]>> = {
readonly [K in keyof UnwrapNestedRefs<TState>]?: RegleValidationErrors<UnwrapNestedRefs<TState>[K], true>;
};

export type RegleValidationErrors<TState extends Record<string, any> | any[] | unknown = never> =
export type RegleValidationErrors<
TState extends Record<string, any> | any[] | unknown = never,
TExternal extends boolean = false,
> =
NonNullable<TState> extends Array<infer U extends Record<string, any>>
? RegleCollectionErrors<U>
? TExternal extends false
? RegleCollectionErrors<U>
: RegleExternalCollectionErrors<U>
: NonNullable<TState> extends Date | File
? string[]
: NonNullable<TState> extends Record<string, any>
? RegleErrorTree<TState>
? TExternal extends false
? RegleErrorTree<TState>
: RegleExternalErrorTree<TState>
: string[];

export type RegleCollectionErrors<TState extends Record<string, any>> = {
readonly $self: string[];
readonly $each: RegleValidationErrors<TState>[];
};

export type RegleExternalCollectionErrors<TState extends Record<string, any>> = {
readonly $self?: string[];
readonly $each?: RegleValidationErrors<TState, true>[];
};

/** @internal */
export type $InternalRegleCollectionErrors = {
readonly $self?: string[];
Expand Down
1 change: 0 additions & 1 deletion packages/nuxt/test/nuxt.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { describe, it, expect } from 'vitest';
import { fileURLToPath } from 'node:url';
import { setup, $fetch } from '@nuxt/test-utils/e2e';
import { createResolver } from '@nuxt/kit';

describe('ssr', async () => {
await setup({
Expand Down
Loading

0 comments on commit 474b124

Please sign in to comment.