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 🙏

© 2025 – Pkg Stats / Ryan Hefner

form-controller-lit

v2.3.0

Published

Реактивный контроллер для управления состоянием форм в Lit-приложениях.

Readme

Form Controller for Lit (v2)

NPM version

Form Controller for Lit — это мощный и гибкий реактивный контроллер для управления состоянием форм в Lit-приложениях. Он упрощает обработку значений, валидацию, отслеживание состояния полей и отправку данных.

Ключевые фичи v2

  • ✨ Директива field: Максимально чистые и декларативные шаблоны без повторяющегося кода.
  • ⚡ Гибридная валидация: Используйте всю мощь Zod для типобезопасной валидации или выберите гибкую ручную настройку.
  • 🧠 Умные режимы валидации: Полный контроль над UX с режимами onChange, onBlur, onSubmit и прогрессивным hybrid (по умолчанию). В режиме hybrid валидация срабатывает при blur, но переключается на onChange, если поле невалидно или форма была отправлена.
  • 🚀 Оптимизация с Debounce: Встроенная опция debounce для отложенной валидации.
  • 🎯 Декларативный API: Чистое и предсказуемое описание правил валидации.
  • 💪 Кастомные сообщения: Легко переопределяйте сообщения об ошибках.
  • 🏗️ DynamicForm Компонент: Готовый компонент для рендеринга форм на основе JSON-конфигурации и Zod схем. Подробнее в документации.

Установка

npm install form-controller-lit

Для использования валидации на основе Zod, вам также нужно установить zod:

npm install zod

Быстрый старт (с Zod и директивой field)

Это рекомендуемый способ использования. Он обеспечивает максимальную типобезопасность и самый чистый код шаблонов.

import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { FormController, field } from 'form-controller-lit'; // Импортируем директиву
import { z } from 'zod';

// 1. Определяем схему валидации и выводим тип
const formSchema = z.object({
  username: z.string().min(3, { message: 'Имя должно быть не менее 3 символов' }),
  email: z.string().email({ message: 'Неверный формат email' }),
});

type FormValues = z.infer<typeof formSchema>;

@customElement('my-zod-form')
export class MyZodForm extends LitElement {
  // 2. Инициализируем контроллер
  form = new FormController<FormValues>(this, {
    schema: formSchema,
    initialValues: {
      username: '',
      email: '',
    },
    validationMode: 'hybrid', // 'onChange' | 'onBlur' | 'onSubmit' | 'hybrid' (по умолчанию)
  });

  async submit(values: FormValues) {
    console.log('Отправка данных:', values);
    await new Promise(r => setTimeout(r, 1000));
  }

  render() {
    return html`
      <form @submit=${(e: Event) => {
        e.preventDefault();
        this.form.submit(this.submit);
      }}>
        <div>
          <label>Имя</label>
          <!-- 3. Используем директиву field -->
          <input ${field(this.form, 'username')} />
          ${this.form.touched.username && this.form.errors.username
            ? html`<small>${this.form.errors.username}</small>`
            : ''}
        </div>

        <div>
          <label>Email</label>
          <input ${field(this.form, 'email')} />
          ${this.form.touched.email && this.form.errors.email
            ? html`<small>${this.form.errors.email}</small>`
            : ''}
        </div>

        <button type="submit" ?disabled=${this.form.isSubmitting}>
          ${this.form.isSubmitting ? 'Отправка...' : 'Отправить'}
        </button>
      </form>
    `;
  }
}

Продвинутое использование

Ручная валидация

Если вам не нужен Zod, используйте ручную настройку через свойство data. Директива field работает и в этом режиме.

const form = new FormController(this, {
  data: {
    password: {
      initialValue: '',
      validate: {
        required: true,
        min: { value: 8, message: 'Пароль должен быть не менее 8 символов' },
        custom: (value) => !/[0-9]/.test(value) ? 'Пароль должен содержать хотя бы одну цифру.' : null,
      },
    },
  },
});

Встроенные правила: required, min, max, pattern, custom.

API

Опции конструктора

  • schema: Экземпляр схемы Zod.
  • initialValues: Объект с начальными значениями (обязателен при использовании schema).
  • data: Объект для ручной конфигурации полей.
  • debounce: (Опционально) Задержка в мс для валидации в режиме onChange.
  • validationMode: (Опционально) 'onChange', 'onBlur', 'onSubmit' или 'hybrid' (по умолчанию).

Основные свойства

  • values, errors, touched, isDirty, isValid, isSubmitting.

Основные методы и директивы

  • field(controller, fieldName): Директива для привязки элемента ввода к контроллеру. Автоматически управляет значением и событиями input и blur.
  • setFieldValue(fieldName, value): Устанавливает значение поля. (В основном используется внутри директивы field).
  • handleBlur(fieldName): Обрабатывает событие потери фокуса. (В основном используется внутри директивы field).
  • submit(callback): Запускает валидацию и вызывает callback с данными формы.
  • reset(): Сбрасывает форму.

Гайд по миграции с v1 на v2

Версия 2.0.0 вносит несколько обратно несовместимых изменений.

1. Изменение API валидации

validate теперь всегда является объектом.

Было (v1):

// 👎 Этот синтаксис больше не работает
validate: (value) => value.length > 0

Стало (v2): Используйте правило custom:

validate: {
  custom: (value) => value.length > 0 ? null : 'Поле не может быть пустым'
}

2. Регистрация полей в шаблоне (Важно!)

Вместо ручной привязки .value, @input и @blur теперь рекомендуется использовать директиву field.

Было (v1/v2 без директивы):

<input
  .value=${this.form.values.name}
  @input=${(e) => this.form.setFieldValue('name', e.target.value)}
  @blur=${() => this.form.handleBlur('name')}
/>

Стало (v2 с директивой):

import 'form-controller-lit/components/dynamicForm';
// ...
html`
  <input ${field(this.form, 'name')} />
`

Это изменение не является строго обязательным (старый способ все еще работает), но настоятельно рекомендуется для чистоты кода.