Caputchin
Руководства по интеграции

Примеры фронтенд-интеграции

Виджет это стандартный пользовательский элемент, так что он работает в каждом фреймворке без обёртки для установки. Форма всегда одна и та же: загрузи пакет один раз (клиентская интеграция), отрендери <caputchin-widget sitekey="cpt_pub_..."> внутри своей формы и прочитай скрытое поле caputchin-token, которое он вставляет, когда посетитель проходит испытание. Для игры подставь <caputchin-game ... game="caputchin/games/leaf-memory">.

Примеры ниже различаются только синтаксисом каждого фреймворка и его одной особенностью работы с пользовательскими элементами.

Чистый HTML

Вставленное поле едет вместе с обычным POST формы, так что подключать ничего не надо:

<script src="https://cdn.jsdelivr.net/npm/@caputchin/widget@3/dist/widget.js"></script>

<form action="/contact" method="POST">
  <input name="email" type="email" required />
  <caputchin-widget sitekey="cpt_pub_..."></caputchin-widget>
  <button type="submit">Send</button>
</form>

React

Импортируй один раз при старте, затем читай поле из FormData при отправке:

import "@caputchin/widget";

export function ContactForm() {
  async function handleSubmit(e) {
    e.preventDefault();
    const data = new FormData(e.currentTarget);
    await fetch("/api/contact", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ email: data.get("email"), token: data.get("caputchin-token") }),
    });
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="email" type="email" required />
      <caputchin-widget sitekey="cpt_pub_..." />
      <button type="submit">Send</button>
    </form>
  );
}

Если ты используешь TypeScript с React, объяви оба элемента один раз, чтобы JSX их принимал:

// caputchin.d.ts
import type { DetailedHTMLProps, HTMLAttributes } from "react";
declare module "react" {
  namespace JSX {
    interface IntrinsicElements {
      "caputchin-widget": DetailedHTMLProps<HTMLAttributes<HTMLElement> & { sitekey: string }, HTMLElement>;
      "caputchin-game": DetailedHTMLProps<HTMLAttributes<HTMLElement> & { sitekey: string; game?: string; games?: string }, HTMLElement>;
    }
  }
}

Эта форма declare module "react" специфична для JSX React. В чистом TypeScript элементы это просто HTMLElement и не нуждаются в объявлении, а другие фреймворки ниже типизируют пользовательские элементы по-своему, так что этот блок нужен тебе только в проекте на React.

Vue

Скажи компилятору Vue, что теги caputchin- это пользовательские элементы, чтобы он не пытался разрешать их как компоненты:

// vite.config.js
export default {
  plugins: [vue({ template: { compilerOptions: { isCustomElement: (tag) => tag.startsWith("caputchin-") } } })],
};
<script setup>
import "@caputchin/widget";
function onSubmit(e) {
  const data = new FormData(e.target);
  // send data.get("caputchin-token") to your backend
}
</script>

<template>
  <form @submit.prevent="onSubmit">
    <input name="email" type="email" required />
    <caputchin-widget sitekey="cpt_pub_..."></caputchin-widget>
    <button type="submit">Send</button>
  </form>
</template>

Svelte

Svelte рендерит пользовательские элементы как есть, конфигурация не нужна:

<script>
  import "@caputchin/widget";
  function onSubmit(e) {
    const data = new FormData(e.currentTarget);
    // send data.get("caputchin-token") to your backend
  }
</script>

<form on:submit|preventDefault={onSubmit}>
  <input name="email" type="email" required />
  <caputchin-widget sitekey="cpt_pub_..."></caputchin-widget>
  <button type="submit">Send</button>
</form>

Angular

Добавь CUSTOM_ELEMENTS_SCHEMA в модуль или standalone-компонент, чтобы Angular разрешал неизвестный тег, и импортируй пакет один раз (в main.ts):

import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@caputchin/widget";

@Component({
  selector: "contact-form",
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `
    <form (submit)="onSubmit($event)">
      <input name="email" type="email" required />
      <caputchin-widget sitekey="cpt_pub_..."></caputchin-widget>
      <button type="submit">Send</button>
    </form>
  `,
})
export class ContactFormComponent {
  onSubmit(e: Event) {
    const data = new FormData(e.target as HTMLFormElement);
    // send data.get("caputchin-token") to your backend
  }
}

Next.js

Тот же код React работает. Пользовательский элемент рендерится как пустой тег во время серверного рендеринга и апгрейдится на клиенте, как только загружается пакет, так что особой обработки не нужно, кроме импорта @caputchin/widget в клиентском компоненте (или загрузки CDN-скрипта через next/script).

См. также

На этой странице