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
$button2 = new 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 () {
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 $pixelRatio;
protected string $styles = '';
protected bool $visible = true;
protected StateEnum $currentState = StateEnum::normal;
protected Viewport $viewport;
protected array $computedStyles = [];
protected Viewport $contentViewport;
public function __construct(
protected string $style = '',
) {}
public function setViewport(Viewport $viewport): void
{
$this->viewport = $viewport;
@ -83,9 +87,8 @@ abstract class Component
{
$this->computedStyles = StyleParser::parse($this->style)->getValidStyles(
MediaQueryEnum::normal,
StateEnum::normal,
$this->currentState,
);
if (isset($this->computedStyles[Margin::class]) && ($m = $this->computedStyles[Margin::class])) {
$this->viewport->x = (int) ($this->viewport->x + $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
{
// 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) {
$child->handleMouseMove($mouseX, $mouseY);
}

View File

@ -11,7 +11,7 @@ class Button extends Container
public function __construct(
public string $text = '',
public string $style = '',
string $style = '',
null|callable $onClick = null,
) {
parent::__construct($style);
@ -57,7 +57,6 @@ class Button extends Container
}
return true;
}
// Propagate to parent if click was outside 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_MIN_SIZE = 20;
public function __construct(
public string $style = '',
) {}
public function __construct(string $style = '')
{
parent::__construct($style);
}
public function layout(null|TextRenderer $textRenderer = null): void
{
@ -47,14 +48,18 @@ class Container extends Component
// Check if overflow is set (if yes, container should not auto-expand)
$overflow = $this->computedStyles[\PHPNative\Tailwind\Style\Overflow::class] ?? null;
$hasOverflowX = $overflow && in_array($overflow->x, [
\PHPNative\Tailwind\Style\OverflowEnum::scroll,
\PHPNative\Tailwind\Style\OverflowEnum::auto,
]);
$hasOverflowY = $overflow && in_array($overflow->y, [
\PHPNative\Tailwind\Style\OverflowEnum::scroll,
\PHPNative\Tailwind\Style\OverflowEnum::auto,
]);
$hasOverflowX =
$overflow &&
in_array($overflow->x, [
\PHPNative\Tailwind\Style\OverflowEnum::scroll,
\PHPNative\Tailwind\Style\OverflowEnum::auto,
]);
$hasOverflowY =
$overflow &&
in_array($overflow->y, [
\PHPNative\Tailwind\Style\OverflowEnum::scroll,
\PHPNative\Tailwind\Style\OverflowEnum::auto,
]);
// A container is a flex container if it has flex/flex-row/flex-col in style
// (but not flex-1, flex-auto, flex-none which make it a flex child)
@ -93,7 +98,7 @@ class Container extends Component
width: $this->contentViewport->width,
height: $this->contentViewport->height,
windowWidth: $this->contentViewport->windowWidth,
windowHeight: $this->contentViewport->windowHeight
windowHeight: $this->contentViewport->windowHeight,
);
$child->setViewport($childViewport);
@ -200,7 +205,7 @@ class Container extends Component
width: $size,
height: $this->contentViewport->height,
windowWidth: $this->contentViewport->windowWidth,
windowHeight: $this->contentViewport->windowHeight
windowHeight: $this->contentViewport->windowHeight,
);
$currentPosition += $size;
} else {
@ -211,7 +216,7 @@ class Container extends Component
width: $this->contentViewport->width,
height: $size,
windowWidth: $this->contentViewport->windowWidth,
windowHeight: $this->contentViewport->windowHeight
windowHeight: $this->contentViewport->windowHeight,
);
$currentPosition += $size;
}
@ -324,10 +329,10 @@ class Container extends Component
// Performance optimization: skip completely invisible children
$childViewport = $child->getViewport();
$isVisible =
$childViewport->x + $childViewport->width > $scissorX &&
$childViewport->x < $scissorX + $scissorW &&
$childViewport->y + $childViewport->height > $scissorY &&
$childViewport->y < $scissorY + $scissorH;
($childViewport->x + $childViewport->width) > $scissorX &&
$childViewport->x < ($scissorX + $scissorW) &&
($childViewport->y + $childViewport->height) > $scissorY &&
$childViewport->y < ($scissorY + $scissorH);
if ($isVisible) {
// Render - batches draw calls
@ -489,6 +494,7 @@ class Container extends Component
public function handleMouseMove(float $mouseX, float $mouseY): void
{
parent::handleMouseMove($mouseX, $mouseY);
if ($this->isDraggingScrollbarY) {
$deltaY = $mouseY - $this->dragStartY;
$scrollbarHeight = $this->contentViewport->height;