Git Product home page Git Product logo

xstate-form's Introduction

xstate-form

Alpha

This module is currently in alpha

  • Under continuous develoment
  • API is not guaranteed
  • Rapid prototyping may cause bugs and/or inconsistencies

React example

This core library is in parallel development with a React example repo which also contains a useFormMachine hook.

API

The current create form api looks like this

import { form, fields } from 'xstate-form';

const machine = form({
  id: 'myAwesomeForm',
  fields: [
    fields.text({ name: 'username' }),
    fields.text({ name: 'password' }),
    // ...
    fields.submit({ name: 'submitForm' }),
  ],
  initialValues: {
    username: 'jaetask',
    password: 'ThisIsTheWay',
  },
});

The machine const is now an xstate compliant machine configuration object that can be passed to useMachine or interpret. The various form fields e.g. (form.text()) return a state object with default event handling, actions and state transitions.

Here's an example of the text state node. simplified for berevity

{
  id: name,
  type: 'parallel',
  states: {
    focus: {
      initial: 'unfocused',
      states: {
        focused: {
          on: {
            BLUR: {},
            CHANGE: {},
            FOCUS: {},
          },
        },
        unfocused: {
          on: {
            FOCUS: {},
          },
        },
      },
    },
    enable: {
      // ...
    },
    visible: {
      // ...
    },
    valid: {
      // ...
    },
    meta: {
      field: {
        type: 'text',
      },
    },
  },
});

note: we don't currently use the meta.field.type but think this is a good idea for future use, form generation, testing etc

  • Fields are named via StateNode.id, allows referencing in actions
  • Ticket to allow passing meta data to fields

Validation

Validation API currently in flux

Currently loking at a way to make all fields self validate and post status back to parent. Fields as Actors


Form validation works via a simple JS function, (this enables any validation library, including Yup to be used by the user). There is a ticket to add Yup integration by default via validationSchema

import { form, fields } from 'xstate-form';

const machine = form({
  id: 'myAwesomeForm',
  validate: (values, event, meta, name) => {
    const errors = {};
    if (values.username.match(/[0-9]+/g)) {
      errors.username = 'Username cannot include a number';
    }
    if (values.password.length <= 8) {
      errors.password = 'Password must be > 8 chars';
    }
    return errors;
  },
  fields: [
    fields.text({ name: 'username' }),
    fields.text({ name: 'password' }),
    // ...
    fields.submit({ name: 'submitForm' }),
  ],
  initialValues: {
    username: 'jaetask',
    password: 'ThisIsTheWay',
  },
});

Validation works on every CHANGE, FOCUS and BLUR event, this is similar to other form libraries, there will also be a VALIDATE method to explicitly trigger validation yourself. see ticket

80/20 Rule

There are probably as many forms as programmers

The desire is to keep the API as clean as possible, so we will always use the 80/20 rule when deciding on features. If a request fits 80% of usecases then it will be considered.

The API is a set of composable functions to help you build an xstate machine to handle forms. The idea is to take what you need and leave the rest, if you need an unsupported feature, feel free to copy/modify one of ours and roll your own for that specific scenario.

This approach should keep the API light, clean and easy to use.

Typescript

This is my first typescript project, please ignore the any params at the moment, especially during rapid prototyping, the API will get stricter over time, promise ๐Ÿ˜‚.

xstate-form's People

Contributors

jaetask avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

xstate-form's Issues

Validation.

Provide a method for each field to handle VALID & INVALID events.

There are rules when validating

  • A field will only become invalid, if touched
    This does not include blur as it's perfectly acceptable to tab to an item and not change it's value, without invalidating.

  • RESET events clear the field and its validation status.

Validation will occur on every event, if a field moves from disabled to enabled (where validation would not have been applied), then it will become invalidated at that moment in time.

Validation will be done via a function that accepts, (c,e,m), the function must return an object in agreed syntax. We will use Yup for this initially, but users can roll their own if they like.

Eventually, we will provide a method to control exactly when validation occurs by a validate action. but more about that later, once the default validation is done.

Separate touched and pristine logic

touched is not the same as pristine

touched is when a field has had focus and been blurred

  • is untouched by default
  • is untouched on RESET
  • is touched on first BLUR

pristine is when a field has been edited

  • is pristine by default
  • is pristine on FOCUS
  • is pristine on RESET
  • is dirty on any CHANGE, SELECT etc That is different from default value

More similar shape to XState?

Instead of:

import { form, fields } from 'xstate-form';

const machine = form({
  id: 'myAwesomeForm',
  validate: (values, event, meta, name) => {
    const errors = {};
    if (values.username.match(/[0-9]+/g)) {
      errors.username = 'Username cannot include a number';
    }
    if (values.password.length <= 8) {
      errors.password = 'Password must be > 8 chars';
    }
    return errors;
  },
  fields: {
    username: fields.text('username'),
    password: fields.text('password'),
    // ...
    submitForm: fields.submit('submitForm'),
  },
  initialValues: {
    username: 'jaetask',
    password: 'ThisIsTheWay',
  },
});

Maybe this? More verbose, but reduces jumping around if you're adding 1 new field.

import { form, fields } from 'xstate-form';
const [ text, password, submit ] = fields

const machine = form({
  id: 'myAwesomeForm',
  fields: {
    username: text({
      label: 'Username',
      validate: valPassword,
      // all HTML attributes should be echoed; easier to learn & in case HTML is used vs JSX
      required: true,
      value: 'jaetask',
    }),
    password: password({
      label: 'Password',
      validate: valPassword,
      required: true,
      value: 'ThisIsTheWay',
    }),
    submitForm: submit({
      label: 'Submit Form',
      validate: valForm,
    }),
  },
  validations: {
    valUsername: (value)=>{
      if (value..match(/[0-9]+/g)) {
        return 'Username cannot include a number'
    }},
    valPassword: (value)=>{
      if (value..length <= 8) {
       return 'Password must be > 8 chars';
    }},
    valForm: (requiredValues)=>{
      requiredValues.map...//check all values exist for required
        return 'Please fill required fields'
    }},
  },
});

Not sure if the validation should be broken out like I have it or inlined.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.