Comunicazione tra Estensioni โ
Le estensioni KIMU possono comunicare tra loro usando diversi meccanismi, permettendo di creare applicazioni complesse e modulari.
๐ Meccanismi di Comunicazione โ
1. Eventi Custom (Event-driven) โ
2. Store Globale (State sharing) โ
3. DOM Events (Standard) โ
4. Callback Patterns โ
๐ก Comunicazione tramite Eventi Custom โ
Il pattern piรน pulito e decoupled per la comunicazione tra estensioni.
Estensione Sender (Invia Eventi) โ
typescript
@KimuComponent({
tag: 'message-sender',
name: 'Inviatore Messaggi',
icon: '๐ค'
})
export class MessageSender extends KimuComponentElement {
private messageText = '';
getData() {
return {
messageText: this.messageText,
onMessageChange: (event: Event) => {
const input = event.target as HTMLInputElement;
this.messageText = input.value;
this.refresh();
},
onSendMessage: () => {
if (this.messageText.trim()) {
// Invia evento custom con payload
this.dispatchEvent(new CustomEvent('kimu:message-sent', {
detail: {
message: this.messageText,
timestamp: Date.now(),
sender: 'message-sender'
},
bubbles: true // Permette la propagazione
}));
this.messageText = ''; // Reset
this.refresh();
}
}
};
}
}Template Sender:
html
<div class="message-sender">
<h3>๐ค Invia Messaggio</h3>
<input
type="text"
value="${messageText}"
@input=${onMessageChange}
placeholder="Scrivi un messaggio..."
>
<button @click=${onSendMessage} ?disabled=${!messageText.trim()}>
Invia
</button>
</div>Estensione Receiver (Riceve Eventi) โ
typescript
@KimuComponent({
tag: 'message-receiver',
name: 'Ricevitore Messaggi',
icon: '๐ฅ'
})
export class MessageReceiver extends KimuComponentElement {
private messages: Array<{message: string, timestamp: number, sender: string}> = [];
private eventListener?: (e: CustomEvent) => void;
onInit() {
// Crea il listener
this.eventListener = (e: CustomEvent) => {
this.messages.push(e.detail);
this.refresh();
};
// Ascolta eventi custom
document.addEventListener('kimu:message-sent', this.eventListener);
}
onDestroy() {
// Cleanup: rimuovi listener
if (this.eventListener) {
document.removeEventListener('kimu:message-sent', this.eventListener);
}
}
getData() {
return {
messages: this.messages,
messageCount: this.messages.length,
hasMessages: this.messages.length > 0,
onClearMessages: () => {
this.messages = [];
this.refresh();
}
};
}
}Template Receiver:
html
<div class="message-receiver">
<h3>๐ฅ Messaggi Ricevuti (${messageCount})</h3>
${hasMessages ? `
<div class="messages">
${messages.map(msg => `
<div class="message">
<strong>${msg.message}</strong>
<small>da ${msg.sender} - ${new Date(msg.timestamp).toLocaleTimeString()}</small>
</div>
`).join('')}
</div>
<button @click=${onClearMessages}>Cancella Tutti</button>
` : `
<p>Nessun messaggio ricevuto</p>
`}
</div>๐๏ธ Comunicazione tramite Store Globale โ
Usa il KimuStore per condividere stato persistente tra estensioni.
Store Writer (Scrive dati) โ
typescript
@KimuComponent({
tag: 'global-counter',
name: 'Contatore Globale',
icon: '๐'
})
export class GlobalCounter extends KimuComponentElement {
private currentValue = 0;
onInit() {
// Leggi valore iniziale dal store
const stored = (window as any).kimuStore?.get('globalCounter');
this.currentValue = stored || 0;
this.refresh();
}
getData() {
return {
currentValue: this.currentValue,
onIncrement: () => {
this.currentValue++;
this.saveToStore();
this.notifyChange();
},
onDecrement: () => {
this.currentValue--;
this.saveToStore();
this.notifyChange();
},
onReset: () => {
this.currentValue = 0;
this.saveToStore();
this.notifyChange();
}
};
}
private saveToStore() {
(window as any).kimuStore?.set('globalCounter', this.currentValue);
this.refresh();
}
private notifyChange() {
// Notifica altri componenti del cambiamento
document.dispatchEvent(new CustomEvent('kimu:store-updated', {
detail: { key: 'globalCounter', value: this.currentValue }
}));
}
}Store Reader (Legge dati) โ
typescript
@KimuComponent({
tag: 'counter-display',
name: 'Display Contatore',
icon: '๐'
})
export class CounterDisplay extends KimuComponentElement {
private globalValue = 0;
private history: number[] = [];
private storeListener?: (e: CustomEvent) => void;
onInit() {
// Leggi valore iniziale
this.globalValue = (window as any).kimuStore?.get('globalCounter') || 0;
// Ascolta cambiamenti del store
this.storeListener = (e: CustomEvent) => {
if (e.detail.key === 'globalCounter') {
this.history.push(this.globalValue); // Salva valore precedente
this.globalValue = e.detail.value;
this.refresh();
}
};
document.addEventListener('kimu:store-updated', this.storeListener);
this.refresh();
}
onDestroy() {
if (this.storeListener) {
document.removeEventListener('kimu:store-updated', this.storeListener);
}
}
getData() {
return {
globalValue: this.globalValue,
history: this.history.slice(-5), // Ultimi 5 valori
trend: this.calculateTrend(),
onSyncFromStore: () => {
this.globalValue = (window as any).kimuStore?.get('globalCounter') || 0;
this.refresh();
}
};
}
private calculateTrend(): string {
if (this.history.length === 0) return 'stabile';
const lastValue = this.history[this.history.length - 1];
return this.globalValue > lastValue ? '๐ crescita' :
this.globalValue < lastValue ? '๐ calo' :
'โก๏ธ stabile';
}
}๐ฏ Best Practices per la Comunicazione โ
1. Naming Convention per Eventi โ
typescript
// โ
Buono: namespace con prefisso
'kimu:message-sent'
'kimu:user-logged-in'
'kimu:data-updated'
// โ Evita: nomi generici
'message'
'update'
'change'2. Gestione Memoria (Cleanup) โ
typescript
export class MyExtension extends KimuComponentElement {
private eventListener?: (e: CustomEvent) => void;
onInit() {
this.eventListener = (e) => this.handleEvent(e);
document.addEventListener('my-event', this.eventListener);
}
onDestroy() {
// โ
Sempre pulire i listener!
if (this.eventListener) {
document.removeEventListener('my-event', this.eventListener);
}
}
}3. Struttura Payload Consistente โ
typescript
// โ
Payload strutturato
{
detail: {
type: 'user-action',
payload: { userId: 123, action: 'login' },
timestamp: Date.now(),
source: 'auth-component'
}
}4. Error Handling โ
typescript
onInit() {
document.addEventListener('kimu:data-request', (e: CustomEvent) => {
try {
this.handleDataRequest(e.detail);
} catch (error) {
console.error('Error handling data request:', error);
// Invia evento di errore
document.dispatchEvent(new CustomEvent('kimu:error', {
detail: { error: error.message, source: 'data-handler' }
}));
}
});
}๐ Pattern Avanzati โ
Hub di Comunicazione Centralizzato โ
typescript
@KimuComponent({
tag: 'message-hub',
name: 'Hub Messaggi',
internal: true // Nascosto all'utente
})
export class MessageHub extends KimuComponentElement {
private subscribers = new Map<string, Function[]>();
onInit() {
// Registra l'hub globalmente
(window as any).kimuMessageHub = this;
}
subscribe(eventType: string, callback: Function) {
if (!this.subscribers.has(eventType)) {
this.subscribers.set(eventType, []);
}
this.subscribers.get(eventType)!.push(callback);
}
unsubscribe(eventType: string, callback: Function) {
const callbacks = this.subscribers.get(eventType);
if (callbacks) {
const index = callbacks.indexOf(callback);
if (index > -1) {
callbacks.splice(index, 1);
}
}
}
publish(eventType: string, data: any) {
const callbacks = this.subscribers.get(eventType);
if (callbacks) {
callbacks.forEach(callback => callback(data));
}
}
getData() {
return {
activeSubscriptions: Array.from(this.subscribers.keys()),
totalSubscribers: Array.from(this.subscribers.values())
.reduce((sum, arr) => sum + arr.length, 0)
};
}
}๐ Prossimi Passi โ
- Template Avanzati - UI complesse per comunicazioni
- Ciclo di Vita - Gestire comunicazioni nel lifecycle
- Best Practices - Pattern scalabili e manutenibili