@aidapt/caity-chat
v3.5.2
Published
Interfaccia di chat embeddabile distribuita come **Web Component standard** (`<caity-chat>`). Funziona in qualsiasi pagina o framework — senza dipendere da React lato consumer — e renderizza tutta la UI dentro uno **Shadow DOM**, così gli stili della chat
Readme
@aidapt/caity-chat
Interfaccia di chat embeddabile distribuita come Web Component standard (<caity-chat>).
Funziona in qualsiasi pagina o framework — senza dipendere da React lato consumer — e renderizza
tutta la UI dentro uno Shadow DOM, così gli stili della chat e quelli della pagina ospite non
collidono mai. Supporta streaming dei messaggi, allegati e template personalizzabili.
Installazione
npm i @aidapt/caity-chatEsistono due modalità di distribuzione, da scegliere in base a com'è costruito il progetto host:
| Modalità | Quando usarla |
|---|---|
| NPM + bundler | Progetti con build step (React, Next.js, Angular, Vue, Svelte…) |
| <script> UMD | Pagine server-rendered (HTML puro, PHP, WordPress, Joomla…) |
Quick start
Con un bundler (NPM)
Registra l'elemento una sola volta all'avvio dell'app. defineCaityChat() è una funzione da
chiamare (non un import a side-effect), così il tree-shaking del bundler non può eliminare la
registrazione.
// App React: importa dall'entry principale (react/react-dom sono peerDependencies)
import { defineCaityChat } from '@aidapt/caity-chat'
defineCaityChat()// Vue / Angular / Svelte / vanilla con bundler: l'entry /standalone include il proprio React
import { defineCaityChat } from '@aidapt/caity-chat/standalone'
defineCaityChat()Poi inserisci il tag nel markup:
<caity-chat app="il-tuo-app-id" token="bearer-token" lang="it"></caity-chat>Con <script type="module"> ESM (consigliato)
Nessun build step, con code-splitting: i renderer pesanti (mermaid, katex, abcjs)
vengono scaricati on demand dalla cartella chunks/ solo quando un messaggio li usa.
Il carico iniziale è ~4× più leggero rispetto alla UMD. caity-chat.es.js e chunks/
devono essere serviti dalla stessa directory.
<caity-chat app="il-tuo-app-id" token="bearer-token"></caity-chat>
<script type="module" src="https://chat.caity.aidapt.io/2.4.0/caity-chat.es.js"></script>Con <script> UMD
Nessun build step: un singolo file che si auto-registra ed espone il global CaityChat.
Include tutto (anche i renderer pesanti): usalo solo se non puoi usare type="module".
<caity-chat app="il-tuo-app-id" token="bearer-token"></caity-chat>
<script src="https://chat.caity.aidapt.io/2.4.0/caity-chat.umd.js"></script>Configurazione (attributi)
| Attributo | Descrizione |
|---|---|
| app | (obbligatorio) Identificatore dell'applicazione passato all'endpoint di setup. |
| token | Token di autenticazione (Bearer). |
| lang | Lingua dei messaggi (es. it, en). |
| aspect | Aspect lato client (JSON). |
| aspect-fallback | Aspect di cortesia/fallback (JSON). |
| data-theme | Tema (es. dark). |
| api-url | (opzionale, sconsigliato) URL base dell'API. Se omesso usa il default di produzione. |
Gli attributi possono cambiare a runtime: l'elemento riallinea lo stato internamente. In
particolare, cambiare app resetta sessione e messaggi.
Eventi
⚠️ Asimmetria importante. Negli eventi emessi il payload è in
event.detail; negli eventi ricevuti il payload va annidato in{ detail: { data: { … } } }.
const chat = document.querySelector('caity-chat')
// Ascolta i messaggi emessi
chat.addEventListener('caity-on-message', (e) => console.log('Nuovo messaggio:', e.detail))
// Controlla la chat dall'esterno: imposta il testo e invialo
chat.dispatchEvent(new CustomEvent('caity-change-input', { detail: { data: { message: 'Ciao!' } } }))
chat.dispatchEvent(new CustomEvent('caity-send-input', { detail: { data: {} } }))Eventi principali — emessi: caity-on-message, caity-on-connect, caity-on-session-change,
caity-on-feedback, caity-on-receive-setup, caity-on-receive-history, caity-on-error,
caity-on-link-navigate.
Ricevuti: caity-change-session, caity-add-metadata, caity-change-input, caity-send-input,
caity-lock-chat, caity-unlock-chat. Elenco completo con i payload in
docs/integrations/README.md.
Guide per piattaforma
| Piattaforma | Guida | |---|---| | React | docs/integrations/react.md | | Next.js | docs/integrations/nextjs.md | | Angular | docs/integrations/angular.md | | Vue 3 | docs/integrations/vue.md | | Svelte / SvelteKit | docs/integrations/svelte.md | | WordPress | docs/integrations/wordpress.md | | HTML / PHP / Joomla / CMS | docs/integrations/vanilla-html.md |
Approfondimenti: panoramica integrazioni · connection service personalizzato.
Personalizzazione (template)
L'interno della chat è suddiviso in slot (caity-user-message, caity-header, …)
sovrascrivibili. In React si usa il componente CustomTemplate; negli altri ambienti si registra
una funzione globale di render. Vedi docs/integrations/react.md e
l'elenco slot in src/types/caity-jsx.ts.
Risoluzione problemi
Tooltip o popup spostati rispetto al loro elemento
Sintomo: i tooltip (es. "Utile" sui pulsanti di feedback) o altri elementi flottanti della chat compaiono lontani dal punto in cui dovrebbero stare, tipicamente traslati verso il basso/destra.
Causa: questi elementi usano position: fixed, che è relativo al viewport solo se nessun
antenato del tag <caity-chat> crea un containing block. Se un antenato nella pagina ospite ha
transform, translate, scale, filter, backdrop-filter, perspective,
will-change: transform o contain: paint/layout, il posizionamento diventa relativo a
quell'elemento e tutto risulta spostato del suo offset. Lo Shadow DOM isola gli stili, ma non
protegge da questo: è una regola del layout CSS che attraversa il confine del componente.
Diagnosi: incolla questo snippet nella console della pagina; elenca gli antenati del widget che creano un containing block (il colpevole è il più vicino al widget):
let el = document.querySelector('caity-chat')?.parentElement;
while (el) {
const s = getComputedStyle(el);
const hits = [];
if (s.transform !== 'none') hits.push(`transform: ${s.transform}`);
if (s.translate && s.translate !== 'none') hits.push(`translate: ${s.translate}`);
if (s.scale && s.scale !== 'none') hits.push(`scale: ${s.scale}`);
if (s.rotate && s.rotate !== 'none') hits.push(`rotate: ${s.rotate}`);
if (s.filter !== 'none') hits.push(`filter: ${s.filter}`);
if (s.backdropFilter && s.backdropFilter !== 'none') hits.push(`backdrop-filter: ${s.backdropFilter}`);
if (s.perspective !== 'none') hits.push(`perspective: ${s.perspective}`);
if (/transform|filter|perspective/.test(s.willChange)) hits.push(`will-change: ${s.willChange}`);
if (/layout|paint|strict|content/.test(s.contain)) hits.push(`contain: ${s.contain}`);
if (hits.length) console.log(el, hits);
el = el.parentElement;
}Per conferma: in DevTools disabilita la proprietà segnalata e passa il mouse su un pulsante della chat — se il tooltip torna al suo posto, è quello il colpevole.
Workaround (in ordine di preferenza):
- Metti
<caity-chat>fuori dal sottoalbero trasformato, idealmente figlio diretto di<body>. È la soluzione standard per i widget overlay e protegge anche da futuri cambi di CSS della pagina. Va fatto nel markup fin dall'inizio: spostare il nodo a runtime conappendChildscatena disconnect/reconnect del custom element e la chat si resetta. - Sostituisci il transform con un posizionamento equivalente: se l'antenato usa
transform: translate(...)per piazzare o centrare il contenitore, ottieni lo stesso layout contop/left/margino flex/grid, e il containing block sparisce. - Se è un'animazione d'ingresso (fade/slide della sezione): il
transformspesso resta applicato a fine animazione per via dianimation-fill-mode: forwardso di una classe che rimane. Fai in modo che a riposo la proprietà venga rimossa (es. togli la classe suanimationend). Vale anche perwill-change: transformmesso "per performance": crea il containing block anche senza transform attivo e a riposo va tolto.
Unico caso senza soluzione CSS: pagina interamente scalata con transform: scale(...) (zoom
globale). Lì l'unica opzione è la n. 1.
Sviluppo
npm run dev # dev server (porta 5175)
npm run build # build di produzione + generazione schema
npm run build:lib # build delle librerie (entry principale + standalone)
npm run lint # ESLint
npm run format # Prettier