# Component Communication Guide

## Overview

This guide establishes our preferred patterns for component communication in Vue.js applications, with a focus on maintainability, type safety, and developer experience.

## Core Principle: Function Props Over $emit

**Preference**: Use function props for business logic and data operations, reserve $emit for DOM-like events.

### Why Function Props?

1. **Better TypeScript Support**: Full type checking of parameters and return values
2. **Superior IDE Navigation**: Ctrl+click takes you directly to implementation
3. **Explicit Contracts**: Clear declaration of what functions a component needs
4. **Easier Testing**: Simple to mock and test in isolation
5. **Flexibility**: Can pass any function, not just event handlers

### When to Use $emit

1. **DOM-like Events**: `@click`, `@input`, `@submit`, `@change`
2. **Lifecycle Events**: `@mounted`, `@before-unmount`, `@updated`
3. **Form Validation**: `@validation-error`, `@validation-success`
4. **Event Bubbling**: When events need to bubble through multiple components
5. **Vue DevTools Integration**: When you want events visible in DevTools timeline

## Implementation Patterns

### Function Props Pattern

```typescript
// Child Component
@Component({
  name: "MyComponent"
})
export default class MyComponent extends Vue {
  @Prop({ required: true }) onSave!: (data: SaveData) => Promise<void>;
  @Prop({ required: true }) onCancel!: () => void;
  @Prop({ required: false }) onValidate?: (data: FormData) => boolean;

  async handleSave() {
    const data = this.collectFormData();
    await this.onSave(data);
  }

  handleCancel() {
    this.onCancel();
  }
}
```

```vue
<!-- Parent Template -->
<MyComponent
  :on-save="handleSave"
  :on-cancel="handleCancel"
  :on-validate="validateForm"
/>
```

### $emit Pattern (for DOM-like events)

```typescript
// Child Component
@Component({
  name: "FormComponent"
})
export default class FormComponent extends Vue {
  @Emit("submit")
  handleSubmit() {
    return this.formData;
  }

  @Emit("input")
  handleInput(value: string) {
    return value;
  }
}
```

```vue
<!-- Parent Template -->
<FormComponent
  @submit="handleFormSubmit"
  @input="handleInputChange"
/>
```

## Automatic Code Generation Guidelines

### Component Template Generation

When generating component templates, follow these patterns:

#### Function Props Template

```vue
<template>
  <div class="component-name">
    <!-- Component content -->
    <button @click="handleAction">
      {{ buttonText }}
    </button>
  </div>
</template>

<script lang="ts">
import { Component, Vue, Prop } from "vue-facing-decorator";

@Component({
  name: "ComponentName"
})
export default class ComponentName extends Vue {
  @Prop({ required: true }) onAction!: () => void;
  @Prop({ required: true }) buttonText!: string;
  @Prop({ required: false }) disabled?: boolean;

  handleAction() {
    if (!this.disabled) {
      this.onAction();
    }
  }
}
</script>
```

#### $emit Template (for DOM events)

```vue
<template>
  <div class="component-name">
    <!-- Component content -->
    <button @click="handleClick">
      {{ buttonText }}
    </button>
  </div>
</template>

<script lang="ts">
import { Component, Vue, Prop, Emit } from "vue-facing-decorator";

@Component({
  name: "ComponentName"
})
export default class ComponentName extends Vue {
  @Prop({ required: true }) buttonText!: string;
  @Prop({ required: false }) disabled?: boolean;

  @Emit("click")
  handleClick() {
    return { disabled: this.disabled };
  }
}
</script>
```

### Code Generation Rules

#### 1. Function Props for Business Logic

- **Data operations**: Save, delete, update, validate
- **Navigation**: Route changes, modal opening/closing
- **State management**: Store actions, state updates
- **API calls**: Data fetching, form submissions

#### 2. $emit for User Interactions

- **Click events**: Button clicks, link navigation
- **Form events**: Input changes, form submissions
- **Lifecycle events**: Component mounting, unmounting
- **UI events**: Focus, blur, scroll, resize

#### 3. Naming Conventions

**Function Props:**

```typescript
// Action-oriented names
onSave: (data: SaveData) => Promise<void>
onDelete: (id: string) => Promise<void>
onUpdate: (item: Item) => void
onValidate: (data: FormData) => boolean
onNavigate: (route: string) => void
```

**$emit Events:**

```typescript
// Event-oriented names
@click: (event: MouseEvent) => void
@input: (value: string) => void
@submit: (data: FormData) => void
@focus: (event: FocusEvent) => void
@mounted: () => void
```

### TypeScript Integration

#### Function Prop Types

```typescript
// Define reusable function types
interface SaveHandler {
  (data: SaveData): Promise<void>;
}

interface ValidationHandler {
  (data: FormData): boolean;
}

// Use in components
@Prop({ required: true }) onSave!: SaveHandler;
@Prop({ required: true }) onValidate!: ValidationHandler;
```

#### Event Types

```typescript
// Define event payload types
interface ClickEvent {
  target: HTMLElement;
  timestamp: number;
}

@Emit("click")
handleClick(): ClickEvent {
  return {
    target: this.$el,
    timestamp: Date.now()
  };
}
```

## Testing Guidelines

### Function Props Testing

```typescript
// Easy to mock and test
const mockOnSave = jest.fn();
const wrapper = mount(MyComponent, {
  propsData: {
    onSave: mockOnSave
  }
});

await wrapper.vm.handleSave();
expect(mockOnSave).toHaveBeenCalledWith(expectedData);
```

### $emit Testing

```typescript
// Requires event simulation
const wrapper = mount(MyComponent);
await wrapper.find('button').trigger('click');
expect(wrapper.emitted('click')).toBeTruthy();
```

## Migration Strategy

### From $emit to Function Props

1. **Identify business logic events** (not DOM events)
2. **Add function props** to component interface
3. **Update parent components** to pass functions
4. **Remove $emit decorators** and event handlers
5. **Update tests** to use function mocks

### Example Migration

**Before ($emit):**

```typescript
@Emit("save")
handleSave() {
  return this.formData;
}
```

**After (Function Props):**

```typescript
@Prop({ required: true }) onSave!: (data: FormData) => void;

handleSave() {
  this.onSave(this.formData);
}
```

## Best Practices Summary

1. **Use function props** for business logic, data operations, and complex interactions
2. **Use $emit** for DOM-like events, lifecycle events, and simple user interactions
3. **Be consistent** within your codebase
4. **Document your patterns** for team alignment
5. **Consider TypeScript** when choosing between approaches
6. **Test both patterns** appropriately

## Code Generation Templates

### Component Generator Input

```typescript
interface ComponentSpec {
  name: string;
  props: Array<{
    name: string;
    type: string;
    required: boolean;
    isFunction: boolean;
  }>;
  events: Array<{
    name: string;
    payloadType?: string;
  }>;
  template: string;
}
```

### Generated Output

```typescript
// Generator should automatically choose function props vs $emit
// based on the nature of the interaction (business logic vs DOM event)
```

This guide ensures consistent, maintainable component communication patterns across the application.
