diff --git a/doc/component-communication-guide.md b/doc/component-communication-guide.md new file mode 100644 index 00000000..1fad5968 --- /dev/null +++ b/doc/component-communication-guide.md @@ -0,0 +1,314 @@ +# 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; + @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 + + +``` + +### $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 + + +``` + +## Automatic Code Generation Guidelines + +### Component Template Generation + +When generating component templates, follow these patterns: + +#### Function Props Template +```vue + + + +``` + +#### $emit Template (for DOM events) +```vue + + + +``` + +### 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 +onDelete: (id: string) => Promise +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; +} + +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. \ No newline at end of file diff --git a/src/components/UsageLimitsSection.vue b/src/components/UsageLimitsSection.vue index 8eecf9a2..d867b164 100644 --- a/src/components/UsageLimitsSection.vue +++ b/src/components/UsageLimitsSection.vue @@ -81,7 +81,7 @@