npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

smol-forms

v0.1.0-nightly.3

Published

A small framework for forms in react

Downloads

23

Readme

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

| Property | Type | Default | Description | | ----------------- | ------------------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | initial | object | {} | The initial value for the entity to be bound. | | delay | number | 100 | the delay used by the debouncing function. | | onChange | SmolChangeCallback<T> | null | A callback for any changes made. This is debounced and is affected by the value of delay. | | onValidationError | (errors: ValidationErrors<T>) => void | null | A callback for when a validation error is detected | | adapter | BindAdapter<T, P> | defaultAdapter | It 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

| Property | Type | Description | | --------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | bind | Bind<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 | | emitFieldChange | SmolInputChangeHandler<T> | The change handler, you can use it at any time, more info here | | entity | object | The debounced value of the entity | | validate | (selector: keyof Entity\|'all'\|'touched', justTest?: boolean) => boolean | The validation function. It accepts 'all', 'touched' or any property name from the entity. | | errors | ValidationErrors<T> | The validation errors. It's a key and string[] dictionary. | | setErrors | Dispatch<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

| Property | Type | Description | | ----------------- | ---------------------------------- | ----------------------------------------------------------------------------------------- | | event | SmolChangeEvent | Is the event that triggered the last change | | value | any | The value for that change, can be overridden by configuration, by the eventMap function | | selector | keyof Entity | the property that was modified on this event | | cfg | MoreGenericConfigForBind<Entity> | the configuration bound to the field | | entity | Partial<Entity> | the current state of the entity | | prevEntity | Partial<Entity> | the previous state of the entity | | entityDisplay | Partial<Entity> | the current state of the entity fields display data | | prevEntityDisplay | Partial<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