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

hubspot-form

v0.0.32

Published

An internal form library designed to integrate into our hubspot React Extension UI projects. This package simplifies nested form creation by using a config-driven approach, making it easy to manage and validate forms by scope.

Downloads

876

Readme

OWM hubspot form config

An internal form library designed to integrate into our hubspot React Extension UI projects. This package simplifies nested form creation by using a config-driven approach, making it easy to manage and validate forms by scope.

To Install the package, run:

npm install @hubspot-form

Understanding Form-config concepts

  // formState is a dictionary
  const formState = {
    // user_info is a scope on formState dictionary
    user_info: {
      fields: {
        first_name: createField({
          name: first_name,
          type: text
        }),
        // array field
        addresses: [
          {
            fields: {
              type: createField({
                name: type,
                type: select,
                options: [
                  { label: "Permanent", value: "Permanent" },
                  { label: "Mailing", value: "Mailing" }
                ]
              }),
              street: createField({
                name: street,
                type: text,
              }),
              unit_n: createField({
                name: unit_n,
                type: text,
                required: false,
              })
            },
            // nested scope validation
            scope_validation: {
              isValid: false,
            }
          }
        ],
      },
      // user_info scope validation
      scope_validation: {
        isValid: false,
      }
    }
  }

  // UI usage
  <Scope name="user_info">
    <CustomInput name="first_name">
      {formState.user_info.fields.addresses.map((address, index) => (
        <>
          <Scope name="fields.addresses" index={index}>
            <CustomInput name="type">
            <CustomInput name="street">
            <CustomInput name="unit_n">
          </Scope>
          <Button onClick={() => {
            // remove address item
            handleDeleteItem(
              {
                scope: "user_info.fields.",
                name: "addresses",
                index
              }
            )
          }}>
            Remove Address
          </Button>
        </>
      ))}

      <Button onClick={() => {
        handleNewItem(
          {
            scope: "user_info.fields",
            name: "addresses",
            data: {}
          }
        )
      }}>
        Add new Address
      </Button>
  </Scope>

  <Button
    isDisabled={!isValidScope(formState, "user_info")}
    onClick={() => {
      const { data } = handleSubmit()
      // { first_name: "John Doe", addresses: [] }
  }}>
    Add new Address
  </Button>

Understanding FormConfig features

// feature functions:
import {
  createField,
  handleNewItem,
  handleUpdateField,
  handleResetScope,
  handleDeleteItem,
  handleSubmit,
  isScopeValid,
} from '@owm-hubspot-form';

// create fields fn is necessary to create a new
// this function will infer FormField type.
first_name: createField({
  name: "first_name",
  type: "text",
  label: "First Name",
  defaultValue: contact?.first_name,
  validate: (value) => {},
  visibility: (state, scope, parent) => {},
  rules: {
    minDigits: 0,
    maxDigits: 0,
    isEmai: true
  },
}),

// handleNewItem fn will add a item in one array field:
// on this function we are adding a new task on scope "board",
// field > in-progress which is an array of tasks
handleNewItem({
  scope: "board",
  name: "in-progress",
  data: {
    task: "new task",
    priority: "2",
    id: new Date().toString()
  }
})


// handleUpdateField is used to update field properties dynamically
// in this example we are updating last_name on scope user_info
// to be dynamically required.
handleUpdateField({
  scope: "user_info",
  name: "last_name",
  data: {
    ...user_info.fields.middle_name,
    required: true,
  }
})

// Fn is required to reset the fields values on that particular scope
handleResetScope({
  scope: "user_info",
});


// handleSubmit fn will return all your scope values with:
// data: {properties: { first_name: "value" }}
const response = handleSubmit()


// handleInputChange fn will return all your scope values with:
// data: {properties: { first_name: "value" }}
handleInputChange({
  scope:, // string
  name, // string
  value, // fieldValues
});

Creating first Panel Steps

import React, { useEffect, useState } from "react";
import {
  FormProvider,
  createField,
  type FormState,
  handleSubmit
} from '@owm-hubspot-form';

const MOCKED_USER_DATA = {
  first_name: "John"
  middle_name: null,
  last_name: "Doe",
  banks: [
    {
      id: new Date(),
      institution: "",
      account: "",
      transit_n: ""
      agenc_n: "",
    }
  ]:
}

// Create your first scope config "user_info" to support your mocked data

const getUserInfoFields = (contact: typeof MOCKED_USER_DATA) => {
  return {
    fields: {
      // normal field
      first_name: createField({
        name: "first_name",
        type: "text",
        defaultValue: contact?.first_name
      }),
      // not required field
      middle_name: createField({
        name: "middle_name",
        type: "text",
        required: false,
        defaultValue: contact?.middle_name
      }),
      // visibility field by "scope"
      last_name: createField({
        name: "last_name",
        type: "text",
        required: false,
        defaultValue: contact?.last_name
        visibility: (state, scope) => {
          // state is your whole form config obj
          // scope is your current scope fields "user_info"
          return scope.fields.first_name.value
        }
      }),
      // array field on scope
      // here you could loop your banks data and returns the array of items
      banks: [
        {
          fields: {
            institution: createField({
              name: "institution",
              type: "text",
            }),
            account: createField({
              name: "account",
              type: "text",
            })
            transit_n: createField({
              name: "transit_n",
              type: "text",
              // example of validation
              validate: (value => {
                if(value && value?.length >= 6 ) {
                  return "Value should have max: 6 digits"
                }
              })
            })
            agency_n: createField({
              name: "agency_n",
              type: "text",
              validate: (value => {
                if(value && value?.length >= 4) {
                  return "Value should have max: 4 digits"
                }
              }),
              // rules feature is still in dev mode, for now it does not validate the field, you should use validate fn above
              rules: {
                minDigits: 1,
                maxDigits: 5,
                isEmail: true,
              }
            })
          },

          // Scope validation means that:
          // If all Field has value, is visible or it's not required
          // we validate the scope.
          scope_validation: {
            isValid: false,
          }
        }
      ],

      // This scope relies on "banks" to be validated as banks is part of the scope
      scope_validation: {
        isValid: false,
      }
    }
  }
}

// configure your scopes types like this:
type FormConfig= {
  user_info = ReturnType<typeof getUserInfoFields>;
  // you can have more scope as needed
}

// Now, let's display make use of the form on the page.

const MyPanel = () => {
  const [formState, setFormState] = useState<FormState<FormConfig>>();

   const initFormState = async () => {
    // await contact fetching
    const response = MOCKED_USER_DATA

    // set USER_INFO scope to the state, with pre-filled fields based on response
    setFormState({
      user_info: getUserInfoFields(response)
    });
  };

  useEffect(() => {
    initFormState()
  }, [])

  return(
     <FormProvider<FormConfig> initialConfig={formState}>
        <FormContext.Consumer>
          {(formContext: IFormContextProps<FormConfig>) => {
          const { formState } = formContext;
          return (
            <>
              <Scope name="user_info" index={0}>
                <CustomInput name="first_name" />
                <CustomInput name="middle_name" />
                <CustomInput name="last_name" />
                // here you can loop and pass the index on scope
                <Scope name="fields.banks" index={0}>
                  <CustomInput name="institution" />
                  <CustomInput name="account" />
                  <CustomInput name="transit_n" />
                  <CustomInput name="agency_n" />
                </Scope>
              </Scope>

              <Button type="button" isDisabled={!isFormScopeValid(formState,['user_info'])} onClick={async () => {
                  // handleSubmit will return:
                  // data: { properties: [field]: value }
                  const formData = handleSubmit();
                  await submit(formData)
                }}
              >
              Submit
              </Button>
            </>
          )}}
        </FormContext.Consumer>
     </FormProvider>
  );
};

export default MyPanel;