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

@form-atoms/list-atom

v1.0.11

Published

<div align="center"> <img height="300" style="margin: 32px" src="./public/form-atoms-banner-transparent.png#gh-dark-mode-only"> <img width="180" style="margin: 32px" src="./public/form-atoms-field.svg#gh-light-mode-only"> <h1>list-atom extension for

Downloads

58

Readme

npm install jotai-effect @form-atoms/list-atom

Quick start

import { fromAtom, useForm, fieldAtom, InputField } from "form-atoms";
import { listAtom, List } from "@form-atoms/list-atom";

const environmentVariables = listAtom({
  name: "environment",
  value: [{ key: "GITHUB_SECRET", value: "<hash>" }],
  fields: ({ key, value }) => ({
    key: fieldAtom({ value: key }),
    value: fieldAtom({ value }),
  }),
});

const form = formAtom({ environmentVariables });

export const Form = () => {
  const { submit } = useForm(form);

  return (
    <form onSubmit={submit(console.log)}>
      <List atom={environmentVariables}>
        {({ fields }) => (
          <>
            <InputField
              atom={fields.key}
              render={(props) => (
                <>
                  <label>Variable Key</label>
                  <input {...props} />
                </>
              )}
            />
            <InputField
              atom={fields.value}
              render={(props) => (
                <>
                  <label>Variable Value</label>
                  <input {...props} />
                </>
              )}
            />
          </>
        )}
      </List>
    </form>
  );
};

Table of contents

| Atoms | Description | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | listAtom() | An atom that represents a list of form fields in a form. It manages state for the list, including the name, value, errors, dirty, validation and empty state. |

| Hooks | Description | | ------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | useListActions() | A hook that returns a add, remove & move actions, that can be used to interact with the list atom state. | | useList() | A hook that returns the list items ready to be rendred together with the list actions. |

| Components | Description | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | <List> | A component that render the individual items of listAtom with render props to render AddButton, RemoveButton and/or Empty slate. |

List atoms

listAtom()

An atom that represents a list of form fields in a form. It manages state for the list, including the name, value, errors, dirty, validation and empty state.

Arguments

| Name | Type | Required? | Description | | ------ | -------------------------------------------------- | --------- | ------------------------------------------------- | | config | ListAtomConfig<Fields, Value> | Yes | The initial state and configuration of the field. |

ListAtomConfig

export type ListAtomConfig<Fields extends FormFields, Value> = {
  /**
   * Optionally provide a name for the field that will be added
   * prefixed to inner fields
   * E.g. list name "contacts" and field name "email"
   * will have scoped name for the 4th item "contacts[3].email"
   */
  name?: string;
  /**
   * The initial array of values of the list
   */
  value: Value[];
  /**
   * A function to initialize the fields for each of the initial values.
   */
  fields: (value: Value) => Fields;
  /**
   * Error message the listAtom will have, when its items have nested errors.
   * It will be one of errors returned by the `useFieldErrors()` hook.
   */
  invalidItemError?: string;
  /**
   * A function that validates the value of the field any time
   * one of its atoms changes. It must either return an array of
   * string error messages or undefined. If it returns undefined,
   * the validation is "skipped" and the current errors in state
   * are retained.
   */
  validate?: (state: {
    /**
     * A Jotai getter that can read other atoms
     */
    get: Getter;
    /**
     * The current value of the field
     */
    value: Value;
    /**
     * The dirty state of the field
     */
    dirty: boolean;
    /**
     * The touched state of the field
     */
    touched: boolean;
    /**
     * The event that caused the validation. Either:
     *
     * - `"change"` - The value of the field has changed
     * - `"touch"` - The field has been touched
     * - `"blur"` - The field has been blurred
     * - `"submit"` - The form has been submitted
     * - `"user"` - A user/developer has triggered the validation
     */
    event: ValidateOn;
  }) => void | string[] | Promise<void | string[]>;
};

Returns

An extended FieldAtom:

export type ListAtom<Fields extends FormFields, Value> = ExtendFieldAtom<
  Value[],
  {
    /**
     * An atom indicating whether the list is empty.
     */
    empty: Atom<boolean>;
    /**
     * A splitAtom() instance from jotai/utils.
     * It handles adding, removing and moving of items in the list.
     * @internal
     */
    _splitList: WritableAtom<
      PrimitiveAtom<ListItemForm<Fields>>[],
      [SplitAtomAction<ListItemForm<Fields>>],
      void
    >;
    /**
     * An atom holding the list of forms of each item.
     * @internal
     */
    _formList: WritableAtom<
      ListItemForm<Fields>[],
      [typeof RESET | SetStateAction<ListItemForm<Fields>[]>],
      void
    >;
    /**
     * An atom holding the fields of the internal formAtom of each item.
     * @internal
     */
    _formFields: Atom<Fields[]>;
    buildItem(): ListItemForm<Fields>;
  }
>;

⇗ Back to top

Hooks

useListActions()

A hook that returns a add, remove & move actions, that can be used to interact with the list atom state.

Arguments

| Name | Type | Required? | Description | | -------- | -------------------------------------------- | --------- | ----------------------------------------------------------------------------------- | | listAtom | ListAtom<Fields extends FormFields, Value> | Yes | The atom that stores the list's state | | options | UseAtomOptions | No | Options that are forwarded to the useAtom, useAtomValue, and useSetAtom hooks |

Returns

export type UseListActions<Fields extends FormFields> = {
  /**
   * Removes the item from the list.
   *
   * @param item - An item from the listAtom's splitList array.
   */
  remove: (item: ListItem<Fields>) => void;
  /**
   * Appends a new item to the list by default, when no 'before' position is used.
   * Optionally the item can be initialized, with the 'fields' argument.
   *
   * @param before - An item from the listAtom's splitList array.
   * @param fields - A custom initialized fieldAtoms matching the Fields shape of the list.
   */
  add: (
    before?: ListItem<Fields> | undefined,
    fields?: Fields | undefined,
  ) => void;
  /**
   * Moves the item to the end of the list, or where specified when the 'before' is defined.
   *
   * @param item - A splitList item to be moved.
   * @param before - A splitList item before which to place the moved item.
   */
  move: (item: ListItem<Fields>, before?: ListItem<Fields> | undefined) => void;
};

⇗ Back to top

useList()

A hook that returns the list items ready to be rendred together with the list actions.

Arguments

| Name | Type | Required? | Description | | -------- | -------------------------------------------- | --------- | ----------------------------------------------------------------------------------- | | listAtom | ListAtom<Fields extends FormFields, Value> | Yes | The atom that stores the list's state | | options | UseAtomOptions | No | Options that are forwarded to the useAtom, useAtomValue, and useSetAtom hooks |

Returns

export type UseList<Fields extends FormFields> = UseListActions<Fields> & {
  /**
   * Resolved value from the list.empty atom.
   */
  isEmpty: boolean;
  items: {
    /**
     * The item from the internal splitList.
     */
    item: ListItem<Fields>;
    /**
     * Stable React key prop derived from atom id.
     */
    key: string;
    /**
     * The form fields of the current item.
     */
    fields: Fields;
    /**
     * A function to remove the current item from the list.
     */
    remove: () => void;
    /**
     * A helper function to move the item to the previous index in the list.
     */
    moveUp: () => void;
    /**
     * A helper function to move the item to the next index in the list.
     */
    moveDown: () => void;
  };
};

⇗ Back to top

Components

<List>

Props

| Name | Type | Required? | Description | | ------------ | ----------------------------------------------------- | --------- | ------------------------------------------------------------------------- | | atom | ListAtom<FormFields, Value> | Yes | A list atom | | children | (props: ListItemProps) => JSX.Element | Yes | A render prop | | initialValue | Value[] | No | A value to (re)initialize the listAtom | | RemoveButton | FunctionComponent<{remove: () => void}> | no | A render prop receiving remove function for each individual list item | | AddButton | FunctionComponent<{add: (fields?: Fields) => void}> | No | A render prop to render a button adding new items to the end of the list | | Empty | FunctionComponent | No | A render prop to render a blank slate when there are no items in the list | | store | AtomStore | No | A Jotai store |

Render Props

Your children render prop will receive the following props:

type ListItemProps<Fields extends FormFields> = {
  /**
   * The fields of current item, as returned from the builder function.
   */
  fields: Fields;
  /**
   * The item from the internal splitList.
   */
  item: ListItem<Fields>;
  /**
   * The index of the current item.
   */
  index: number;
  /**
   * Total count of items in the list.
   */
  count: number;
  /**
   * Append a new item to the end of the list.
   * When called with current item, it will be prepend with a new item.
   */
  add: (before?: ListItem<Fields>) => void;
  /**
   * Removes the current item.
   */
  remove: () => void;
  /**
   * Moves the current item one slot up in the list.
   * When called for the first item, the action is no-op.
   */
  moveUp: () => void;
  /**
   * Moves the current item one slot down in the list.
   * When called for the last item, the item moves to the start of the list.
   */
  moveDown: () => void;
  /**
   * A component with an onClick handler bound to remove the current item from the list.
   */
  RemoveButton: FunctionComponent;
};

⇗ Back to top

Let's see what's in this listAtom

atom in atoms

⇗ Back to top

LICENSE

MIT