This commit is contained in:
Thomas Peterson 2025-10-23 10:14:41 +02:00
parent f3dd92d85b
commit 9f2b88e0eb
5 changed files with 79 additions and 26 deletions

View File

@ -34,7 +34,7 @@ $mainContainer->addComponent($button1);
// Button with different padding // Button with different padding
$button2 = new Button( $button2 = new Button(
text: 'Another Button', text: 'Another Button',
style: 'm-5 p-15 bg-green-500 rounded-lg', style: 'm-5 p-15 bg-green-500 hover:bg-green-200 rounded-lg',
onClick: function () { onClick: function () {
echo 'test2'; echo 'test2';
}, },

View File

@ -0,0 +1,26 @@
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use PHPNative\Framework\Application;
use PHPNative\Ui\Widget\Button;
use PHPNative\Ui\Widget\Container;
use PHPNative\Ui\Widget\Label;
// Check PHP version
if (PHP_VERSION_ID < 80100) {
die("This demo requires PHP 8.1+ for Fiber support.\nYour version: " . PHP_VERSION . "\n");
}
$app = new Application('Button Example', 800, 600);
// Button with different padding
$button2 = new Button(
text: 'Another Button',
style: 'm-5 p-15 hover:bg-green-200',
onClick: function () {
echo 'test2';
},
);
$app->setRoot($button2);
$app->run();

View File

@ -16,15 +16,19 @@ abstract class Component
protected $window; protected $window;
protected $pixelRatio; protected $pixelRatio;
protected string $styles = '';
protected bool $visible = true; protected bool $visible = true;
protected StateEnum $currentState = StateEnum::normal;
protected Viewport $viewport; protected Viewport $viewport;
protected array $computedStyles = []; protected array $computedStyles = [];
protected Viewport $contentViewport; protected Viewport $contentViewport;
public function __construct(
protected string $style = '',
) {}
public function setViewport(Viewport $viewport): void public function setViewport(Viewport $viewport): void
{ {
$this->viewport = $viewport; $this->viewport = $viewport;
@ -83,9 +87,8 @@ abstract class Component
{ {
$this->computedStyles = StyleParser::parse($this->style)->getValidStyles( $this->computedStyles = StyleParser::parse($this->style)->getValidStyles(
MediaQueryEnum::normal, MediaQueryEnum::normal,
StateEnum::normal, $this->currentState,
); );
if (isset($this->computedStyles[Margin::class]) && ($m = $this->computedStyles[Margin::class])) { if (isset($this->computedStyles[Margin::class]) && ($m = $this->computedStyles[Margin::class])) {
$this->viewport->x = (int) ($this->viewport->x + $m->left); $this->viewport->x = (int) ($this->viewport->x + $m->left);
$this->viewport->width = max(0, ($this->viewport->width - $m->right) - $m->left); $this->viewport->width = max(0, ($this->viewport->width - $m->right) - $m->left);
@ -185,7 +188,26 @@ abstract class Component
*/ */
public function handleMouseMove(float $mouseX, float $mouseY): void public function handleMouseMove(float $mouseX, float $mouseY): void
{ {
// Default implementation: propagate to children // Check if mouse is over this component
$isMouseOver =
$mouseX >= $this->viewport->x &&
$mouseX <= ($this->viewport->x + $this->viewport->width) &&
$mouseY >= $this->viewport->y &&
$mouseY <= ($this->viewport->y + $this->viewport->height);
// Update state based on mouse position
$previousState = $this->currentState;
$this->currentState = $isMouseOver ? StateEnum::hover : StateEnum::normal;
// Recompute styles if state changed
if ($previousState !== $this->currentState) {
$this->computedStyles = StyleParser::parse($this->style)->getValidStyles(
MediaQueryEnum::normal,
$this->currentState,
);
}
// Propagate to children
foreach ($this->children as $child) { foreach ($this->children as $child) {
$child->handleMouseMove($mouseX, $mouseY); $child->handleMouseMove($mouseX, $mouseY);
} }

View File

@ -11,7 +11,7 @@ class Button extends Container
public function __construct( public function __construct(
public string $text = '', public string $text = '',
public string $style = '', string $style = '',
null|callable $onClick = null, null|callable $onClick = null,
) { ) {
parent::__construct($style); parent::__construct($style);
@ -57,7 +57,6 @@ class Button extends Container
} }
return true; return true;
} }
// Propagate to parent if click was outside button // Propagate to parent if click was outside button
return parent::handleMouseClick($mouseX, $mouseY, $button); return parent::handleMouseClick($mouseX, $mouseY, $button);
} }

View File

@ -33,9 +33,10 @@ class Container extends Component
private const SCROLLBAR_WIDTH = 12; private const SCROLLBAR_WIDTH = 12;
private const SCROLLBAR_MIN_SIZE = 20; private const SCROLLBAR_MIN_SIZE = 20;
public function __construct( public function __construct(string $style = '')
public string $style = '', {
) {} parent::__construct($style);
}
public function layout(null|TextRenderer $textRenderer = null): void public function layout(null|TextRenderer $textRenderer = null): void
{ {
@ -47,11 +48,15 @@ class Container extends Component
// Check if overflow is set (if yes, container should not auto-expand) // Check if overflow is set (if yes, container should not auto-expand)
$overflow = $this->computedStyles[\PHPNative\Tailwind\Style\Overflow::class] ?? null; $overflow = $this->computedStyles[\PHPNative\Tailwind\Style\Overflow::class] ?? null;
$hasOverflowX = $overflow && in_array($overflow->x, [ $hasOverflowX =
$overflow &&
in_array($overflow->x, [
\PHPNative\Tailwind\Style\OverflowEnum::scroll, \PHPNative\Tailwind\Style\OverflowEnum::scroll,
\PHPNative\Tailwind\Style\OverflowEnum::auto, \PHPNative\Tailwind\Style\OverflowEnum::auto,
]); ]);
$hasOverflowY = $overflow && in_array($overflow->y, [ $hasOverflowY =
$overflow &&
in_array($overflow->y, [
\PHPNative\Tailwind\Style\OverflowEnum::scroll, \PHPNative\Tailwind\Style\OverflowEnum::scroll,
\PHPNative\Tailwind\Style\OverflowEnum::auto, \PHPNative\Tailwind\Style\OverflowEnum::auto,
]); ]);
@ -93,7 +98,7 @@ class Container extends Component
width: $this->contentViewport->width, width: $this->contentViewport->width,
height: $this->contentViewport->height, height: $this->contentViewport->height,
windowWidth: $this->contentViewport->windowWidth, windowWidth: $this->contentViewport->windowWidth,
windowHeight: $this->contentViewport->windowHeight windowHeight: $this->contentViewport->windowHeight,
); );
$child->setViewport($childViewport); $child->setViewport($childViewport);
@ -200,7 +205,7 @@ class Container extends Component
width: $size, width: $size,
height: $this->contentViewport->height, height: $this->contentViewport->height,
windowWidth: $this->contentViewport->windowWidth, windowWidth: $this->contentViewport->windowWidth,
windowHeight: $this->contentViewport->windowHeight windowHeight: $this->contentViewport->windowHeight,
); );
$currentPosition += $size; $currentPosition += $size;
} else { } else {
@ -211,7 +216,7 @@ class Container extends Component
width: $this->contentViewport->width, width: $this->contentViewport->width,
height: $size, height: $size,
windowWidth: $this->contentViewport->windowWidth, windowWidth: $this->contentViewport->windowWidth,
windowHeight: $this->contentViewport->windowHeight windowHeight: $this->contentViewport->windowHeight,
); );
$currentPosition += $size; $currentPosition += $size;
} }
@ -324,10 +329,10 @@ class Container extends Component
// Performance optimization: skip completely invisible children // Performance optimization: skip completely invisible children
$childViewport = $child->getViewport(); $childViewport = $child->getViewport();
$isVisible = $isVisible =
$childViewport->x + $childViewport->width > $scissorX && ($childViewport->x + $childViewport->width) > $scissorX &&
$childViewport->x < $scissorX + $scissorW && $childViewport->x < ($scissorX + $scissorW) &&
$childViewport->y + $childViewport->height > $scissorY && ($childViewport->y + $childViewport->height) > $scissorY &&
$childViewport->y < $scissorY + $scissorH; $childViewport->y < ($scissorY + $scissorH);
if ($isVisible) { if ($isVisible) {
// Render - batches draw calls // Render - batches draw calls
@ -489,6 +494,7 @@ class Container extends Component
public function handleMouseMove(float $mouseX, float $mouseY): void public function handleMouseMove(float $mouseX, float $mouseY): void
{ {
parent::handleMouseMove($mouseX, $mouseY);
if ($this->isDraggingScrollbarY) { if ($this->isDraggingScrollbarY) {
$deltaY = $mouseY - $this->dragStartY; $deltaY = $mouseY - $this->dragStartY;
$scrollbarHeight = $this->contentViewport->height; $scrollbarHeight = $this->contentViewport->height;