0.1.0-nightly.3 • Published 2 years ago

smol-forms v0.1.0-nightly.3

Weekly downloads
-
License
MIT
Repository
-
Last release
2 years ago

Welcome to smol-forms

HTML form elements work a bit differently from other DOM elements in React because form elements naturally keep some internal state. This small library has the goal of simplifying the binding of DOM, or non-DOM elements to a state while trying to provide clean and simple usage.

There are amazing frameworks that deal with these problems very well. This is just my try.

Under construction...

This is aimed to be a small and flexible forms lib.

Stay tuned for more.

Examples

Simplest use that I can think of with the hook

  const { bind, entity } =  useSmolForm<EntityType>();
  // ... save implementation
  return (<>
    <label for="fname">Name:</label>
    <br/>
    <input type="text"  name="fname" {...bind('name')} />
    <br/>
    <label for="age">Name:</label>
    <br/>
    <input type="text" name="age" {...bind.int('age')} />
    <br/>
    <label for="mmail">Last  name:</label>
    <br/>
    <input type="text"  name="mmail" {...bind({mainEmail: [isEmail]})} />
    <br/>
    <button onClick={() => save(entity)} />
  </>);

Simplest use that I can think of with the component

// ... save implementation
return (<SmolForm<EntityType>
  form={({ bind, entity }) => (
    <>
      <label for="fname">Name:</label>
      <br/>
      <input type="text"  name="fname" {...bind('name')} />
      <br/>
      <label for="age">Name:</label>
      <br/>
      <input type="text" name="age" {...bind.int('age')} />
      <br/>
      <label for="mmail">Last  name:</label>
      <br/>
      <input type="text"  name="mmail" {...bind({mainEmail: [isEmail]})} />
      <br/>
      <button  onClick={() => save(entity)} />
    </>
  )}
/>);

The API

There are two main ways to use smol-forms a hook, useSmolForm, and a component, SmolForm. The hook is the core, while the component encapsulates it and adds visual support. The choice between using smol-forms as a hook or as a component comes down to personal preference.

The useSmolForm hook

This hook is the central point of the lib. It concerns itself with entity validation, entity binding, and the entity value.

Props

PropertyTypeDefaultDescription
initialobject{}The initial value for the entity to be bound.
delaynumber100the delay used by the debouncing function.
onChangeSmolChangeCallback<T>nullA callback for any changes made. This is debounced and is affected by the value of delay.
onValidationError(errors: ValidationErrors<T>) => voidnullA callback for when a validation error is detected
adapterBindAdapter<T, P>defaultAdapterIt is an Anti-Corruption Layer. The interactions between the field and the engine are dealt with here. It has a minimal interface but can be heavily customized. For more, refer here.

Return

PropertyTypeDescription
bindBind<T, P>The bind function used for hmm..., "binding" the field to a given property, for more info, and how to adapt its behavior, please check it here
emitFieldChangeSmolInputChangeHandler<T>The change handler, you can use it at any time, more info here
entityobjectThe debounced value of the entity
validate(selector: keyof Entity\|'all'\|'touched', justTest?: boolean) => booleanThe validation function. It accepts 'all', 'touched' or any property name from the entity.
errorsValidationErrors<T>The validation errors. It's a key and string[] dictionary.
setErrorsDispatch<SetStateAction<ValidationErrors<T>>>A dispatch to set errors yourself.

The state bit

The debounced entity state

This ensures that neither time-consuming tasks nor callbacks are fired too often. As much of the framework is about the state synchronization, a lack of control here can create race conditions. The default delay is 100ms.

The state change callback onChange

Both hook and component have a callback for when the state is updated. The type, (args: SmolChangeCallbackArgs<Entity>) => void.

The args Object

PropertyTypeDescription
eventSmolChangeEventIs the event that triggered the last change
valueanyThe value for that change, can be overridden by configuration, by the eventMap function
selectorkeyof Entitythe property that was modified on this event
cfgMoreGenericConfigForBind<Entity>the configuration bound to the field
entityPartial<Entity>the current state of the entity
prevEntityPartial<Entity>the previous state of the entity
entityDisplayPartial<Entity>the current state of the entity fields display data
prevEntityDisplayPartial<Entity>the current state of the entity fields display data

The Validation bit

The goal is to support validation functions. The lib does come with some default validators, please check it here.
There are four different parts to interact with:

The validate function

Is returned from the hook, or the reference from the component, and it can trigger a state change saving the validation result, or just return the result (is valid or not).

It can be used to test a single property by the name, all properties from the entity, or only the touched ones.

// validating only the touched and updating the state
const allDirtyAreValid = validate('touched');

// testing if all fields are valid
const testAllFields = validate('all', true);

// testing only the property 'age' is valid
const testAllFields = validate('age', true);

Note, the validate function won't throw an exception if the field has no validator, or the property is not bound to a field. It'll simply return a null response as nothing was done.

The validation state

The state validation is just a dictionary with the same fields but arrays of strings with the description of the error found.

I reckon that the visual representation speaks volumes:

{
  id: 22,
  name: 'joe'
}
{
  id: [ 
    'This field is required!',
    'This field is a number!'
  ],
  name: [ 'this field is required' ],
}

The validation state change callback onValidationError

Both hook and component have a callback for when the error state is updated. The type is a (errors: ValidationErrors<Entity>) => void where errors is the validation state at that moment.

It will be triggered whenever the validation function is called.

If triggered by the onBlur event, the validation will be queued to be executed after the debounced delay, and that will trigger this callback afterward.

Built-in validators

under construction

0.0.2-nightly.41

2 years ago

0.0.2-nightly.40

2 years ago

0.0.2-nightly.54

2 years ago

0.0.2-nightly.43

2 years ago

0.0.2-nightly.42

2 years ago

0.0.2-nightly.38

2 years ago

0.0.2-nightly.37

2 years ago

0.0.2-nightly.39

2 years ago

0.1.0-nightly.2

2 years ago

0.0.2-nightly.45

2 years ago

0.1.0-nightly.1

2 years ago

0.0.2-nightly.44

2 years ago

0.0.2-nightly.33

2 years ago

0.0.2-nightly.36

2 years ago

0.1.0-nightly.3

2 years ago

0.0.2-nightly.46

2 years ago

0.0.2-nightly.35

2 years ago

0.0.2-nightly.20

2 years ago

0.0.2-nightly.7

2 years ago

0.0.2-nightly.5

2 years ago

0.0.2-nightly.0

2 years ago