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

callbag-form

v0.3.0

Published

Framework agnostic form management with callbags

Downloads

4

Readme

callbag-form

Framework agnostic form management based on callbags

tests coverage version

npm i callbag-form

callbag-form provides a simple method for managing forms and validation in TypeScript / JavaScript. Provides a state containing the form data, sources emitting form validity, error report, and whether form data has changed.

import form, { required, isEmail, isStrongPassword, isSame, isTrue } from 'callbag-form'


const registration = form({
  name: ['', { required }],                                 // 👉 name is required
  email: ['', { required, isEmail }],                       // 👉 email is required and must be an email
  password: ['', isStrongPassword()],                       // 👉 password must be a strong password
  passwordRepeat: ['', { match: isSame(f => f?.password) }] // 👉 password repeat must be the same with password
  agreeToS: [false, { isTrue }]                             // 👉 must have agreed to tos 
})

// 👉 read/write form data
registration.data.get()
registration.data.set({ ... })

// 👉 form data is a callbage
pipe(registration.data, subscribe(console.log))

// 👉 form data is a state
registration.data.sub('email').set(...)
pipe(registration.data.sub('agreeToS'), subscribe(console.log))

// 👉 track validity
pipe(registration.valid, subscribe(console.log))

// 👉 check if email has errors
pipe(registration.errors, map(e => e.email.hasErrors))

// 👉 check if email format has issues
pipe(registration.errors, map(e => e.email.isEmail))

// 👉 check if password has a special character (validator included in `isStrongPassword()`):
pipe(registration.errors, map(e => e.password.hasSpecialChar))

// 👉 check if password-repeat matches:
pipe(registration.errors, map(e => e.passwordRepeat.match))

⚡ Checkout a real-life example using callbag-jsx.

👉 You can also provide your own source of data:

const registration = form(source, {
  name: { required },
  email: { required, isEmail },
  password: isStrongPassword(),
  passwordRepeat: { match: isSame(f => f?.password)) },
  agreeToS: { isTrue }
})

Installation

Install via NPM (or Yarn):

npm i callbag-form

Or use via CDNs:

<script type="module">
  import form from 'https://unpkg.com/callbag-form/dist/bundles/callbag-form.es.min.js'
  
  // ...
</script>

Validators

Validators in callbag-form are simple functions which return true or false with given value:

export function required(t) {
  return isNotNull(t) && (
    (t as any).length === undefined
    || (t as any).length > 0
  )
}

👉 Validators are assumed to be synchronous and computationally inexpensive. Computationally expensive and/or async validators are rare and so can be accounted for specifically.

Validators can also take into account the whole form data:

export function isSame(selector) {
  return (value, form) => value === selector(form)
}

callbag-form comes with a handful of validators that are commonly used:

required            // 👉 checks if value is not null and not empty string / array
isTrue              // 👉 checks if value is true
doesMatch(regex)    // 👉 checks if value matches given regexp
isUrl               // 👉 checks if value is a proper URL (https only, regexp check)
isEmail             // 👉 checks if value is a proper email (regexp check)
hasMinLength(n)     // 👉 checks if value (string or array) has at least length of n
isSame(selector)    // 👉 checks if value equals return result of the selector (which is provided the form data)
hasUpperCase        // 👉 checks if value has at-least one upper case character
hasLowerCase        // 👉 checks if value has at-least one lower case character
hasDigit            // 👉 checks if value has at-least one digit character
hasSpecialChar      // 👉 checks if value has at-least one special character

There is also isStrongPassword(), which provides a bundle of validation functions:

export function isStrongPassword() {
  return {
    required,
    hasUpperCase,
    hasLowerCase,
    hasDigit,
    hasSpecialChar,
    length: hasMinLength(8)
  }
}

Change Tracking

Forms can also track whether the data has actually changed. Enable that by calling .track():

form.track()

Then set checkpoints using .checkpoint() method (for example when data is synced with server):

form.checkpoint()

The form data will be now compared to the last checkpoint:

// 👉 check whether form data has changed since last checkpoint:
pipe(form.changed, subscribe(console.log))

Don't forget to cleanup the form tracking subscription. You can do that either by calling .dispose():

form.dispose()

Or by calling the callback returned by .track():

const dispose = form.track()

// ...

dispose()

This means you can easily track forms in callbag-jsx using tracking:

export function MyComponent(_, renderer) {

  const myForm = form(...)
  this.track(myForm.track())

  // ...
  
  return <> ... </>
}

Contribution

There are no contribution guidelines or issue templates currently, so just be nice (and also note that this is REALLY early stage). Useful commands for development / testing:

git clone https://github.com/loreanvictor/callbag-form.git
npm i                   # --> install dependencies
npm start               # --> run `samples/index.tsx` on `localhost:3000`
npm test                # --> run all tests
npm run cov:view        # --> run tests and display the code coverage report