fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled

This commit is contained in:
2025-11-24 21:28:25 +01:00
parent 4eb7134853
commit 77abc65cd7
1327 changed files with 91915 additions and 9909 deletions

View File

@@ -11,9 +11,10 @@ This guide covers the integrated UI features available in LiveComponents, includ
1. [Tooltip System](#tooltip-system)
2. [Loading States & Skeleton Loading](#loading-states--skeleton-loading)
3. [UI Helper System](#ui-helper-system)
4. [Notification Component](#notification-component)
5. [Dialog & Modal Integration](#dialog--modal-integration)
6. [Best Practices](#best-practices)
4. [Event-Based UI Integration](#event-based-ui-integration)
5. [Notification Component](#notification-component)
6. [Dialog & Modal Integration](#dialog--modal-integration)
7. [Best Practices](#best-practices)
---
@@ -338,6 +339,332 @@ uiHelper.hideNotification('component-id');
---
## Event-Based UI Integration
### Overview
The Event-Based UI Integration system allows LiveComponents to trigger UI components (Toasts, Modals) by dispatching events from PHP actions. The JavaScript `UIEventHandler` automatically listens to these events and displays the appropriate UI components.
**Features**:
- Automatic UI component display from PHP events
- Type-safe event payloads
- Toast queue management
- Modal stack management
- Zero JavaScript code required in components
### Architecture
- **PHP Side**: Components dispatch events via `ComponentEventDispatcher`
- **JavaScript Side**: `UIEventHandler` listens to events and displays UI components
- **Integration**: Events are automatically dispatched after action execution
### Basic Usage with UIHelper
The `UIHelper` class provides convenient methods for dispatching UI events:
```php
<?php
declare(strict_types=1);
namespace App\Application\LiveComponents\Product;
use App\Framework\LiveComponents\Attributes\Action;
use App\Framework\LiveComponents\Attributes\LiveComponent;
use App\Framework\LiveComponents\ComponentEventDispatcher;
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
use App\Framework\LiveComponents\UI\UIHelper;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
#[LiveComponent('product-form')]
final readonly class ProductFormComponent implements LiveComponentContract
{
public function __construct(
public ComponentId $id,
public ProductFormState $state
) {
}
#[Action]
public function save(?ComponentEventDispatcher $events = null): ProductFormState
{
// ... save logic ...
// Show success toast
(new UIHelper($events))->successToast('Product saved successfully!');
return $this->state->withSaved();
}
#[Action]
public function delete(int $productId, ?ComponentEventDispatcher $events = null): ProductFormState
{
// Show confirmation dialog with action
(new UIHelper($events))->confirmDelete(
$this->id,
"product #{$productId}",
'doDelete',
['id' => $productId]
);
return $this->state;
}
#[Action]
public function doDelete(int $id): ProductFormState
{
// This action is automatically called when user confirms
// ... delete logic ...
return $this->state->withoutProduct($id);
}
}
```
### Toast Events
#### Show Toast
```php
use App\Framework\LiveComponents\UI\UIHelper;
#[Action]
public function save(?ComponentEventDispatcher $events = null): State
{
// Basic success toast
(new UIHelper($events))->successToast('Saved successfully!');
// Toast with custom duration
(new UIHelper($events))->infoToast('File uploaded', 7000);
// Using fluent interface for multiple toasts
(new UIHelper($events))
->infoToast('Processing...')
->successToast('Done!');
return $this->state;
}
```
**Toast Types**:
- `info` - Blue, informational message
- `success` - Green, success message
- `warning` - Orange, warning message
- `error` - Red, error message
**Positions**:
- `top-right` (default)
- `top-left`
- `bottom-right`
- `bottom-left`
#### Hide Toast
```php
#[Action]
public function dismissNotification(?ComponentEventDispatcher $events = null): State
{
$this->hideToast($events, 'global');
return $this->state;
}
```
### Modal Events
#### Show Modal
```php
use App\Framework\LiveComponents\UI\UIHelper;
use App\Framework\LiveComponents\Events\UI\Options\ModalOptions;
use App\Framework\LiveComponents\Events\UI\Enums\ModalSize;
#[Action]
public function showEditForm(int $userId, ?ComponentEventDispatcher $events = null): State
{
$formHtml = $this->renderEditForm($userId);
(new UIHelper($events))->modal(
$this->id,
'Edit User',
$formHtml,
ModalOptions::create()
->withSize(ModalSize::Large)
->withButtons([
['text' => 'Save', 'class' => 'btn-primary', 'action' => 'save'],
['text' => 'Cancel', 'class' => 'btn-secondary', 'action' => 'close']
])
);
return $this->state;
}
```
#### Show Confirmation Dialog
```php
use App\Framework\LiveComponents\UI\UIHelper;
#[Action]
public function requestDelete(int $id, ?ComponentEventDispatcher $events = null): State
{
(new UIHelper($events))->confirmDelete(
$this->id,
"item #{$id}",
'doDelete',
['id' => $id]
);
return $this->state;
}
```
**Note**: Confirmation dialogs return a result via the `modal:confirm:result` event. You can listen to this event in JavaScript to handle the confirmation:
```javascript
document.addEventListener('modal:confirm:result', (e) => {
const { componentId, confirmed } = e.detail;
if (confirmed) {
// User confirmed - execute action
LiveComponentManager.getInstance()
.executeAction(componentId, 'confirmDelete', { id: 123 });
}
});
```
#### Show Alert Dialog
```php
use App\Framework\LiveComponents\UI\UIHelper;
#[Action]
public function showError(?ComponentEventDispatcher $events = null): State
{
(new UIHelper($events))->alertError(
$this->id,
'Error',
'An error occurred while processing your request.'
);
return $this->state;
}
```
#### Close Modal
```php
use App\Framework\LiveComponents\UI\UIHelper;
#[Action]
public function closeModal(?ComponentEventDispatcher $events = null): State
{
(new UIHelper($events))->closeModal($this->id);
return $this->state;
}
```
### Manual Event Dispatching
If you prefer to dispatch events manually (without UIHelper):
```php
use App\Framework\LiveComponents\ComponentEventDispatcher;
use App\Framework\LiveComponents\Events\UI\ToastShowEvent;
#[Action]
public function save(?ComponentEventDispatcher $events = null): State
{
// ... save logic ...
if ($events !== null) {
// Option 1: Using Event classes (recommended)
$events->dispatchEvent(ToastShowEvent::success('Saved successfully!'));
// Option 2: Direct instantiation
$events->dispatchEvent(new ToastShowEvent(
message: 'Saved successfully!',
type: 'success',
duration: 5000
));
}
return $this->state;
}
```
### JavaScript Event Handling
The `UIEventHandler` automatically listens to these events and displays UI components. You can also listen to events manually:
```javascript
// Listen to toast events
document.addEventListener('toast:show', (e) => {
const { message, type, duration, position } = e.detail;
console.log(`Toast: ${message} (${type})`);
});
// Listen to modal events
document.addEventListener('modal:show', (e) => {
const { componentId, title, content } = e.detail;
console.log(`Modal shown: ${title}`);
});
// Listen to confirmation results
document.addEventListener('modal:confirm:result', (e) => {
const { componentId, confirmed } = e.detail;
if (confirmed) {
// Handle confirmation
}
});
```
### Toast Queue Management
The `ToastQueue` automatically manages multiple toasts:
- Maximum 5 toasts per position (configurable)
- Automatic stacking with spacing
- Oldest toast removed when limit reached
- Auto-dismiss with queue management
### Modal Stack Management
The `ModalManager` handles modal stacking using native `<dialog>` element:
- **Native `<dialog>` element**: Uses `showModal()` for true modal behavior
- **Automatic backdrop**: Native `::backdrop` pseudo-element
- **Automatic focus management**: Browser handles focus trapping
- **Automatic ESC handling**: Native `cancel` event
- **Z-index management**: Manual stacking for nested modals
- **Stack tracking**: Manages multiple open modals
#### Native `<dialog>` Benefits
The `<dialog>` element provides:
- **True modal behavior**: Blocks background interaction via `showModal()`
- **Native backdrop**: Automatic overlay with `::backdrop` pseudo-element
- **Automatic focus trapping**: Browser handles focus management
- **Automatic ESC handling**: Native `cancel` event
- **Better accessibility**: Native ARIA attributes and semantics
- **Better performance**: Native browser implementation
- **Wide browser support**: Chrome 37+, Firefox 98+, Safari 15.4+
The system uses native `<dialog>` features for optimal modal behavior and accessibility.
### Best Practices
1. **Use UIHelper**: Prefer the UIHelper class over manual event dispatching for type safety and convenience
2. **Component IDs**: Always provide component IDs for modals to enable proper management
3. **Toast Duration**: Use appropriate durations (5s for success, longer for errors)
4. **Modal Sizes**: Choose appropriate sizes (small for alerts, large for forms)
5. **Error Handling**: Always show user-friendly error messages
```php
// Good: Clear, user-friendly toast
(new UIHelper($events))->successToast('Product saved successfully!');
// Bad: Technical error message
(new UIHelper($events))->errorToast('SQL Error: INSERT failed');
```
---
## Notification Component
### Overview
@@ -519,18 +846,23 @@ final class UserSettings extends LiveComponent
### Modal with LiveComponent Content
```php
use App\Framework\LiveComponents\UI\UIHelper;
use App\Framework\LiveComponents\Events\UI\Options\ModalOptions;
use App\Framework\LiveComponents\Events\UI\Enums\ModalSize;
#[Action]
public function showUserModal(int $userId): void
public function showUserModal(int $userId, ?ComponentEventDispatcher $events = null): void
{
$userComponent = UserDetailsComponent::mount(
ComponentId::generate('user-details'),
userId: $userId
);
$this->uiHelper->showModal(
title: 'User Details',
content: $userComponent->render(),
size: 'medium'
(new UIHelper($events))->modal(
$this->id,
'User Details',
$userComponent->render(),
ModalOptions::create()->withSize(ModalSize::Medium)
);
}
```