Skip to content

Commit

Permalink
Merge pull request #9 from ueberBrot/chore-refactor-docs
Browse files Browse the repository at this point in the history
Improve documentation
  • Loading branch information
gutentag2012 authored Apr 8, 2024
2 parents 1ba34f0 + 9b5b53f commit 55eda09
Show file tree
Hide file tree
Showing 12 changed files with 56 additions and 113 deletions.
3 changes: 1 addition & 2 deletions docs/guide/array-fields.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Array Fields

In many cases using arrays in forms is necessary and hard to manage.
You need to keep of the changes to each item and the array itself to know if an item was added, removed or swapped.
In many cases, using arrays in forms is necessary but hard to manage. You need to keep track of the changes to each item and the array itself to know if an item was added, removed, or swapped.

## Data Representation

Expand Down
15 changes: 7 additions & 8 deletions docs/guide/basic-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ field.data.value = "New Name"
## Form Submission

A form is not complete without a submit-handler.
To add one, add the onSubmit method to the form options.
To add one, add the `onSubmit` method to the form options.

```ts
const form = new FormLogic<FormValues>({
Expand Down Expand Up @@ -124,8 +124,9 @@ to convert the error to a valid format.

## Accessing Data

There are several different ways to access the form data.
Your choice will depend on the use case.
There are several ways to access form data in this library, each suited for different scenarios.

We'll explore these methods and discuss when each approach might be most beneficial.

### Through Fields

Expand Down Expand Up @@ -196,13 +197,11 @@ you will subscribe to every change within the form data.

## Add Validation

A crucial part of forms is validation.
You can either add validation to the whole form or to a single field.
Validation is essential for forms as it safeguards data integrity and provides a smooth user experience. This library offers two approaches to validation: form-level and field-level.

### Field Validation

Adding validation to a single field might be the simplest and most common way to validate a form.
You can add a validation function to the field options.
Adding validation rules directly to individual fields is a common and straightforward approach. This library allows you to define a validation function within the field options.

```ts
const field = form.getOrCreateField("name", {
Expand Down Expand Up @@ -276,7 +275,7 @@ please refer to the [Validation Guide](/guide/validation).

## Add Transformation

In many cases, you have data in your form that has a type which cannot be used by your application.
In many cases, you have data in your form that has a type incompatible with your application.
A common example is numbers, which are stored as such in the form,
but are needed as string in the application (e.g., in an input field).
The users of the transformed values are called bindings in this context.
Expand Down
37 changes: 12 additions & 25 deletions docs/guide/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,13 @@ let's take a look at what to keep in mind when working with the core components

## Form

A form is the main part of the library.
It is the single source of truth for the form data,
it holds all the references to the data of each field and the data that is not controlled by a field.
The form is the core component of this library. It acts as **the single source of truth** for all form data. It holds references to both the data of each field and any data not controlled by a specific field.

Besides owning the data,
the form is also alone responsible for the submission of the form data
and can handle validation on the complete form data.
In addition to managing the data, the form is solely responsible for submitting form data and can handle validation for the complete form data.

With these functionalities the form is able to work without the need for any fields.
All the core functionalities can be accessed through the form instance.
These functionalities allow the form to function independently of any fields. All core features can be accessed through the form instance itself.

Nested data will be stored as nested signals,
that way the form can guarantee that each change to a value will only affect subscribers to the child value.
You would access nested data like this:
Nested data is stored using nested signals. This approach ensures that any changes to a value only affect subscribers to the specific child value. You would access nested data in the following way:

```ts
import {FormLogic} from "./FormLogic";
Expand All @@ -41,26 +34,20 @@ Only use the `.value` prop if you want to subscribe to changes of that value, ot

## Field

A field is a wrapper around a single piece of data within the form.
A field acts as a wrapper for a single piece of data within the form.
It is responsible for storing field-specific state and handling logic like validation and transformation.

Fields are meant
to be used as a way to ease the interaction with the form
and reduce the amount of long chaining for forms with deeply nested data.
Fields are designed to simplify interaction with the form and reduce the need for long method chaining when working with forms containing deeply nested data.

Once a field is created, it takes control of the data assigned to it.
It does not store the data itself but rather a reference to the data in the form.
The field value is now connected to the field lifecycle and will be removed from the form when the field is removed.
This behavior can be configured, but by default, the field will destroy the connected data when it is unmounted.
When you create a field, it takes control of the referenced data within the form. It doesn't store the data directly but rather a reference to it. This connects the field value to the field's lifecycle. Any data associated with the field will be removed from the form when the field itself is removed. This behavior can be customized, but by default, the field will delete the referenced data when it's unmounted.

## Arrays

Arrays are mostly handled like every other nested field,
it can be accessed through its path string, and every value is wrapped in a signal.
Most UI libraries, however, need some sort of unique identifier for items in an array
to keep track of whether an item is added,
removed or moved.
For that reason this library adds a unique `key` identifier to each array signal created.
Arrays are mostly handled like every other nested field.
It can be accessed through its path string, and every value is wrapped in a signal.
However, most UI libraries require unique identifiers for array items
to track whether an item is added, removed or moved.
To address this, this library automatically adds a unique `key` identifier to each array signal.

So be aware when using arrays and keep in mind, that the raw data has to be accessed through the `.data` prop.

Expand Down
3 changes: 1 addition & 2 deletions docs/guide/dynamic-objects.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Dymamic Objects

In some cases, you may want to have a dynamic object structure, where the keys are not known in advance.
This library handles those scenarios as if they were static objects, but exposes some helper functions
In some cases, you may want to have a dynamic object structure, where the keys are not known in advance. This library handles these scenarios as if they were static objects, but exposes some helper functions for working with them.

## Helper Functions

Expand Down
8 changes: 1 addition & 7 deletions docs/guide/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,7 @@ If you want to use a schema validation library you can also install the correspo

## Creating your first form

This is how you would create a simple registration form with a name and email field would look like.
This example also includes validation using the Zod library.

In a real world project, you would then probably connect the state of the form to a UI, this is not covered in this
example.
Check out the [React quickstart guide](/guide/react/quickstart#creating-your-first-form) for an example with the React
bindings.
This is what a simple registration form with a name and email field would look like. This example also includes validation using the Zod library. Connecting the form state to a UI is not covered here. For an example with React bindings, check out the [React quickstart guide](/guide/react/quickstart#creating-your-first-form).

::: code-group

Expand Down
21 changes: 7 additions & 14 deletions docs/guide/react/basic-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,7 @@ export default function MyForm() {
```

::: tip
It is recommended
to create your custom `input` component that takes the field signal as a prop to optimize the re-renders.
If you use the `nameField.data.value` in the main component, it will re-render the whole component on every change.
To optimize re-renders, create a custom `input` component that receives the field signal as a prop. Using `nameField.data.value` directly in the main component triggers a full re-render on every change.
:::

::: info
Expand Down Expand Up @@ -93,9 +91,9 @@ export default function MyForm() {
```

::: danger WARNING
You cannot subscribe to a signal value from within an arrow function.
So you will not be able to use `field.data.value` directly in the main component,
but rather have to create a child component that subscribes to the signal.
You cannot subscribe to a signal value within an arrow function.
This means using `field.data.value` directly in the main component is not possible.
To access the signal value, you'll need to create a child component that subscribes to the signal.
:::

If you want to avoid this pitfall, you can use the `FieldProvider` component and consume the fields context in a child
Expand Down Expand Up @@ -129,7 +127,7 @@ export default function MyForm() {

The basic principles of form submission are the same as in the core library.

It is recommended to use a default html `form` element to wrap your form and hook into the `onSubmit` event.
It is recommended to use a default HTML `form` element to wrap your form and hook into the `onSubmit` event.

```tsx {10-13,17-18}
export default function MyForm() {
Expand Down Expand Up @@ -159,8 +157,7 @@ export default function MyForm() {

The basic principles of accessing data are the same as in the core library.

Additionally, it is important to note, that you can always use the `useFormContext` and `useFieldContext` hooks to
access the form and field data.
Additionally, you can always use the `useFormContext` and `useFieldContext` hooks to access form and field data directly.

::: info
You can only use these hooks from children of the `FormProvider` or `FieldProvider` components.
Expand Down Expand Up @@ -191,11 +188,7 @@ export default function MyForm() {

## Add Transformation

The basic principles of adding transformation are the same as in the core library.

So adding transformation to a field is as simple
as adding the `transformFromBinding` and `transformToBinding` options to the field
and using the `transformedData` property of the field.
The basic principles of transforming data are the same as in the core library. To add a transformation to a field, use the `transformFromBinding` and `transformToBinding` options. You can then access the transformed data using the `transformedData` property of the field.

```tsx {8-9,12}
export default function MyForm() {
Expand Down
3 changes: 1 addition & 2 deletions docs/guide/react/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ If you want to use a schema validation library you can also install the correspo

## Creating your first form

This is how you would create a simple registration form with a name and email field would look like.
This example also includes validation using the Zod library.
This code snippet demonstrates a simple registration form with `name`, `email`, and `password` fields. The example utilizes Zod for validation.

::: tip
Just like in this example it is advised to create your own input components, that accept signals as props.
Expand Down
29 changes: 11 additions & 18 deletions docs/guide/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,10 @@ It is not possible to disable the validation on submit.

## Async Validation

This library also allows for async validation by default.
To do that, pass an asynchronous function to the `validatorAsync` option.
It follows the same rules as the synchronous validation, but instead of returning a string,
it returns a promise that resolves to a string or `undefined`.
It also receives an `AbortSignal` as a second argument, which can be used to cancel the validation.
This library also supports asynchronous validation out of the box.
To enable it, pass an asynchronous function to the `validatorAsync` option.
It follows the same rules as synchronous validation, but instead of returning a `string` directly, it returns a promise that resolves to either a `string` or `undefined`.
The asynchronous function also receives an `AbortSignal` as a second argument, which allows you to cancel the validation in progress.
If the signal is aborted, the validation is considered canceled and all errors are discarded.

::: info
Expand Down Expand Up @@ -113,19 +112,19 @@ const form = new FormLogic({
```

::: info
The abortSignal of the validator is also aborted if there is a new debounced validation.
The `abortSignal` of the `validator` is also aborted if there is a new debounced validation.
That means, with this example, you will only see the error message after 1500ms after the last validation.
:::

## Deep Validation

As mentioned before, the form will run onChange validation on every nested change.
As mentioned before, the form will run `onChange` validation on every nested change.
Fields, however, only run validation if the direct value is changed.
So if you have a field that has an array value, it only runs validation if elements are added, removed or swapped.
No validation will be run if the value of an array item is changed.
So, if you have a field that has an array value, it only runs validation if elements are added, removed or swapped.
No validation is run if the value of an item within the array is changed.

This library allows you to listen to those deep changes
and trigger an onChange validation on a parent if a nested value changes.
and trigger an `onChange` validation on a parent if a nested value changes.
To do that, you can set the `validateOnNestedChange` option to `true` when creating a new field.

```ts
Expand Down Expand Up @@ -154,15 +153,9 @@ So even a change 5 levels deep will trigger the validation of the parent.

## Validation Mixins

Sometimes you have to validate a field relative to the value of another field.
Many libraries struggle with this issue and usually require you to have validation on a common parent.
This library solves the issue with validation mixins,
which allow you to add any other value from the form to the validation function.
Sometimes, you have to validate a field relative to the value of another field. Many libraries struggle with this issue and usually require you to have validation on a common parent. This library solves the issue with validation mixins, which allow you to add any other value from the form to the validation function.

To do that, add the paths as an array to the `validateMixin` option when creating a new field.
This will transform the input of the validator to a tuple,
where the first value is the value of the field,
and the other values are the values provided by the paths in the same order.
To do that, add the paths as an array to the `validateMixin` option when creating a new field. This will transform the input of the validator to a tuple, where the first value is the value of the field, and the other values are the values provided by the paths in the same order.

```ts
import {FormLogic} from '@formsignals/form-core';
Expand Down
Loading

0 comments on commit 55eda09

Please sign in to comment.