🔧 %s
Component: %s
Render Time: %.2fms
Memory: %s
Cache: %s
%s %s %s
HTML; private const PANEL_STYLES = <<<'CSS' position: relative; border: 2px solid #ff6b6b; border-radius: 4px; margin: 8px 0; font-family: monospace; font-size: 12px; background: #fff; box-shadow: 0 2px 8px rgba(0,0,0,0.1); CSS; /** * Render debug panel for component * * @param ComponentId $componentId Component identifier * @param string $componentName Human-readable component name * @param string $className Full component class name * @param float $renderTimeMs Render time in milliseconds * @param LiveComponentState|null $state Component state object * @param CompiledComponentMetadata|null $metadata Component metadata * @param bool $cacheHit Whether cache was hit * @return string Debug panel HTML */ public function render( ComponentId $componentId, string $componentName, string $className, float $renderTimeMs, ?LiveComponentState $state = null, ?CompiledComponentMetadata $metadata = null, bool $cacheHit = false ): string { // Format sections $stateSection = $this->renderStateSection($state); $actionsSection = $this->renderActionsSection($metadata); $metadataSection = $this->renderMetadataSection($metadata); return sprintf( self::PANEL_TEMPLATE, htmlspecialchars($componentId->toString()), self::PANEL_STYLES, htmlspecialchars($componentName), htmlspecialchars($className), $renderTimeMs, $this->formatMemoryUsage(memory_get_usage()), $this->formatCacheStatus($cacheHit), $stateSection, $actionsSection, $metadataSection ); } /** * Render state section */ private function renderStateSection(?LiveComponentState $state): string { if ($state === null) { return ''; } $stateData = $state->toArray(); $stateJson = json_encode($stateData, JSON_PRETTY_PRINT); return sprintf( '
State:
%s
', htmlspecialchars($stateJson ?: '{}') ); } /** * Render actions section */ private function renderActionsSection(?CompiledComponentMetadata $metadata): string { if ($metadata === null || empty($metadata->actions)) { return ''; } $actionsList = array_map( fn ($action) => htmlspecialchars($action->name), $metadata->actions ); return sprintf( '
Actions: %s
', implode(', ', $actionsList) ); } /** * Render metadata section */ private function renderMetadataSection(?CompiledComponentMetadata $metadata): string { if ($metadata === null) { return ''; } $propertyCount = count($metadata->properties); $actionCount = count($metadata->actions); return sprintf( '
Metadata: %d properties, %d actions
', $propertyCount, $actionCount ); } /** * Format memory usage */ private function formatMemoryUsage(int $bytes): string { $units = ['B', 'KB', 'MB', 'GB']; $bytes = max($bytes, 0); $pow = floor(($bytes > 0 ? log($bytes) : 0) / log(1024)); $pow = min($pow, count($units) - 1); $bytes /= (1 << (10 * $pow)); return round($bytes, 2) . ' ' . $units[$pow]; } /** * Format cache status */ private function formatCacheStatus(bool $cacheHit): string { return $cacheHit ? '✅ HIT' : '❌ MISS'; } /** * Render inline styles for debug panel * * Should be included once in the page head. */ public function renderStyles(): string { return <<<'CSS' CSS; } /** * Check if debug panel should be rendered * * Only render in development environment. */ public static function shouldRender(): bool { return getenv('APP_ENV') === 'development' || getenv('LIVECOMPONENT_DEBUG') === 'true'; } }