/home/mip/mip/public/vendor/laravel-filemanager/files/folder-1/821668/nunomaduro.zip
PK �8]E_> I I termwind/LICENSE.mdnu ȯ�� The MIT License (MIT)
Copyright (c) Nuno Maduro <enunomaduro@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
PK �8]��5�*$ *$ termwind/src/Termwind.phpnu �[��� <?php
declare(strict_types=1);
namespace Termwind;
use Closure;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Termwind\Components\Element;
use Termwind\Exceptions\InvalidChild;
/**
* @internal
*/
final class Termwind
{
/**
* The implementation of the output.
*/
private static OutputInterface|null $renderer;
/**
* Sets the renderer implementation.
*/
public static function renderUsing(OutputInterface|null $renderer): void
{
self::$renderer = $renderer ?? new ConsoleOutput();
}
/**
* Creates a div element instance.
*
* @param array<int, Element|string>|string $content
* @param array<string, mixed> $properties
*/
public static function div(array|string $content = '', string $styles = '', array $properties = []): Components\Div
{
$content = self::prepareElements($content, $styles);
return Components\Div::fromStyles(
self::getRenderer(), $content, $styles, $properties
);
}
/**
* Creates a paragraph element instance.
*
* @param array<int, Element|string>|string $content
* @param array<string, mixed> $properties
*/
public static function paragraph(array|string $content = '', string $styles = '', array $properties = []): Components\Paragraph
{
$content = self::prepareElements($content, $styles);
return Components\Paragraph::fromStyles(
self::getRenderer(), $content, $styles, $properties
);
}
/**
* Creates a span element instance with the given style.
*
* @param array<int, Element|string>|string $content
* @param array<string, mixed> $properties
*/
public static function span(array|string $content = '', string $styles = '', array $properties = []): Components\Span
{
$content = self::prepareElements($content, $styles);
return Components\Span::fromStyles(
self::getRenderer(), $content, $styles, $properties
);
}
/**
* Creates an element instance with raw content.
*
* @param array<int, Element|string>|string $content
*/
public static function raw(array|string $content = ''): Components\Raw
{
return Components\Raw::fromStyles(
self::getRenderer(), $content
);
}
/**
* Creates an anchor element instance with the given style.
*
* @param array<int, Element|string>|string $content
* @param array<string, mixed> $properties
*/
public static function anchor(array|string $content = '', string $styles = '', array $properties = []): Components\Anchor
{
$content = self::prepareElements($content, $styles);
return Components\Anchor::fromStyles(
self::getRenderer(), $content, $styles, $properties
);
}
/**
* Creates an unordered list instance.
*
* @param array<int, string|Element> $content
* @param array<string, mixed> $properties
*/
public static function ul(array $content = [], string $styles = '', array $properties = []): Components\Ul
{
$ul = Components\Ul::fromStyles(
self::getRenderer(), '', $styles, $properties
);
$content = self::prepareElements(
$content,
$styles,
static function ($li) use ($ul): string|Element {
if (is_string($li)) {
return $li;
}
if (! $li instanceof Components\Li) {
throw new InvalidChild('Unordered lists only accept `li` as child');
}
return match (true) {
$li->hasStyle('list-none') => $li,
$ul->hasStyle('list-none') => $li->addStyle('list-none'),
$ul->hasStyle('list-square') => $li->addStyle('list-square'),
$ul->hasStyle('list-disc') => $li->addStyle('list-disc'),
default => $li->addStyle('list-none'),
};
}
);
return $ul->setContent($content);
}
/**
* Creates an ordered list instance.
*
* @param array<int, string|Element> $content
* @param array<string, mixed> $properties
*/
public static function ol(array $content = [], string $styles = '', array $properties = []): Components\Ol
{
$ol = Components\Ol::fromStyles(
self::getRenderer(), '', $styles, $properties
);
$index = 0;
$content = self::prepareElements(
$content,
$styles,
static function ($li) use ($ol, &$index): string|Element {
if (is_string($li)) {
return $li;
}
if (! $li instanceof Components\Li) {
throw new InvalidChild('Ordered lists only accept `li` as child');
}
return match (true) {
$li->hasStyle('list-none') => $li->addStyle('list-none'),
$ol->hasStyle('list-none') => $li->addStyle('list-none'),
$ol->hasStyle('list-decimal') => $li->addStyle('list-decimal-'.(++$index)),
default => $li->addStyle('list-none'),
};
}
);
return $ol->setContent($content);
}
/**
* Creates a list item instance.
*
* @param array<int, Element|string>|string $content
* @param array<string, mixed> $properties
*/
public static function li(array|string $content = '', string $styles = '', array $properties = []): Components\Li
{
$content = self::prepareElements($content, $styles);
return Components\Li::fromStyles(
self::getRenderer(), $content, $styles, $properties
);
}
/**
* Creates a description list instance.
*
* @param array<int, string|Element> $content
* @param array<string, mixed> $properties
*/
public static function dl(array $content = [], string $styles = '', array $properties = []): Components\Dl
{
$content = self::prepareElements(
$content,
$styles,
static function ($element): string|Element {
if (is_string($element)) {
return $element;
}
if (! $element instanceof Components\Dt && ! $element instanceof Components\Dd) {
throw new InvalidChild('Description lists only accept `dt` and `dd` as children');
}
return $element;
}
);
return Components\Dl::fromStyles(
self::getRenderer(), $content, $styles, $properties
);
}
/**
* Creates a description term instance.
*
* @param array<int, Element|string>|string $content
* @param array<string, mixed> $properties
*/
public static function dt(array|string $content = '', string $styles = '', array $properties = []): Components\Dt
{
$content = self::prepareElements($content, $styles);
return Components\Dt::fromStyles(
self::getRenderer(), $content, $styles, $properties
);
}
/**
* Creates a description details instance.
*
* @param array<int, Element|string>|string $content
* @param array<string, mixed> $properties
*/
public static function dd(array|string $content = '', string $styles = '', array $properties = []): Components\Dd
{
$content = self::prepareElements($content, $styles);
return Components\Dd::fromStyles(
self::getRenderer(), $content, $styles, $properties
);
}
/**
* Creates a horizontal rule instance.
*
* @param array<string, mixed> $properties
*/
public static function hr(string $styles = '', array $properties = []): Components\Hr
{
return Components\Hr::fromStyles(
self::getRenderer(), '', $styles, $properties
);
}
/**
* Creates an break line element instance.
*
* @param array<string, mixed> $properties
*/
public static function breakLine(string $styles = '', array $properties = []): Components\BreakLine
{
return Components\BreakLine::fromStyles(
self::getRenderer(), '', $styles, $properties
);
}
/**
* Gets the current renderer instance.
*/
public static function getRenderer(): OutputInterface
{
return self::$renderer ??= new ConsoleOutput();
}
/**
* Convert child elements to a string.
*
* @param array<int, string|Element>|string $elements
* @return array<int, string|Element>
*/
private static function prepareElements($elements, string $styles = '', Closure|null $callback = null): array
{
if ($callback === null) {
$callback = static fn ($element): string|Element => $element;
}
$elements = is_array($elements) ? $elements : [$elements];
return array_map($callback, $elements);
}
}
PK �8]�,��m �m $ termwind/src/ValueObjects/Styles.phpnu �[��� <?php
declare(strict_types=1);
namespace Termwind\ValueObjects;
use Closure;
use Termwind\Actions\StyleToMethod;
use Termwind\Components\Element;
use Termwind\Components\Hr;
use Termwind\Components\Li;
use Termwind\Components\Ol;
use Termwind\Components\Ul;
use Termwind\Enums\Color;
use Termwind\Exceptions\ColorNotFound;
use Termwind\Exceptions\InvalidStyle;
use Termwind\Repositories\Styles as StyleRepository;
use function Termwind\terminal;
/**
* @internal
*/
final class Styles
{
/**
* Finds all the styling on a string.
*/
public const STYLING_REGEX = "/\<[\w=#\/\;,:.&,%?-]+\>|\\e\[\d+m/";
/** @var array<int, string> */
private array $styles = [];
private ?Element $element = null;
/**
* Creates a Style formatter instance.
*
* @param array<string, mixed> $properties
* @param array<string, Closure(string, array<string, string|int>, array<string, int[]>): string> $textModifiers
* @param array<string, Closure(string, array<string, string|int>): string> $styleModifiers
* @param string[] $defaultStyles
*/
final public function __construct(
private array $properties = [
'colors' => [],
'options' => [],
'isFirstChild' => false,
],
private array $textModifiers = [],
private array $styleModifiers = [],
private array $defaultStyles = []
) {
}
/**
* @param Element $element
* @return $this
*/
public function setElement(Element $element): self
{
$this->element = $element;
return $this;
}
/**
* Gets default styles.
*
* @return string[]
*/
public function defaultStyles(): array
{
return $this->defaultStyles;
}
/**
* Gets the element's style properties.
*
* @return array<string, mixed>
*/
final public function getProperties(): array
{
return $this->properties;
}
/**
* Sets the element's style properties.
*
* @param array<string, mixed> $properties
*/
public function setProperties(array $properties): self
{
$this->properties = $properties;
return $this;
}
/**
* Sets the styles to the element.
*/
final public function setStyle(string $style): self
{
$this->styles = array_unique(array_merge($this->styles, [$style]));
return $this;
}
/**
* Checks if the element has the style.
*/
final public function hasStyle(string $style): bool
{
return in_array($style, $this->styles, true);
}
/**
* Adds a style to the element.
*/
final public function addStyle(string $style): self
{
return StyleToMethod::multiple($this, $style);
}
/**
* Inherit styles from given Styles object.
*/
final public function inheritFromStyles(self $styles): self
{
foreach (['ml', 'mr', 'pl', 'pr', 'width', 'minWidth', 'maxWidth', 'spaceY', 'spaceX'] as $style) {
$this->properties['parentStyles'][$style] = array_merge(
$this->properties['parentStyles'][$style] ?? [],
$styles->properties['parentStyles'][$style] ?? []
);
$this->properties['parentStyles'][$style][] = $styles->properties['styles'][$style] ?? 0;
}
$this->properties['parentStyles']['justifyContent'] = $styles->properties['styles']['justifyContent'] ?? false;
foreach (['bg', 'fg'] as $colorType) {
$value = (array) ($this->properties['colors'][$colorType] ?? []);
$parentValue = (array) ($styles->properties['colors'][$colorType] ?? []);
if ($value === [] && $parentValue !== []) {
$this->properties['colors'][$colorType] = $styles->properties['colors'][$colorType];
}
}
if (! is_null($this->properties['options']['bold'] ?? null) ||
! is_null($styles->properties['options']['bold'] ?? null)) {
$this->properties['options']['bold'] = $this->properties['options']['bold']
?? $styles->properties['options']['bold']
?? false;
}
return $this;
}
/**
* Adds a background color to the element.
*/
final public function bg(string $color, int $variant = 0): self
{
return $this->with(['colors' => [
'bg' => $this->getColorVariant($color, $variant),
]]);
}
/**
* Adds a bold style to the element.
*/
final public function fontBold(): self
{
return $this->with(['options' => [
'bold' => true,
]]);
}
/**
* Removes the bold style on the element.
*/
final public function fontNormal(): self
{
return $this->with(['options' => [
'bold' => false,
]]);
}
/**
* Adds a bold style to the element.
*/
final public function strong(): self
{
$this->styleModifiers[__METHOD__] = static fn ($text): string => sprintf("\e[1m%s\e[0m", $text);
return $this;
}
/**
* Adds an italic style to the element.
*/
final public function italic(): self
{
$this->styleModifiers[__METHOD__] = static fn ($text): string => sprintf("\e[3m%s\e[0m", $text);
return $this;
}
/**
* Adds an underline style.
*/
final public function underline(): self
{
$this->styleModifiers[__METHOD__] = static fn ($text): string => sprintf("\e[4m%s\e[0m", $text);
return $this;
}
/**
* Adds the given margin left to the element.
*/
final public function ml(int $margin): self
{
return $this->with(['styles' => [
'ml' => $margin,
]]);
}
/**
* Adds the given margin right to the element.
*/
final public function mr(int $margin): self
{
return $this->with(['styles' => [
'mr' => $margin,
]]);
}
/**
* Adds the given margin bottom to the element.
*/
final public function mb(int $margin): self
{
return $this->with(['styles' => [
'mb' => $margin,
]]);
}
/**
* Adds the given margin top to the element.
*/
final public function mt(int $margin): self
{
return $this->with(['styles' => [
'mt' => $margin,
]]);
}
/**
* Adds the given horizontal margin to the element.
*/
final public function mx(int $margin): self
{
return $this->with(['styles' => [
'ml' => $margin,
'mr' => $margin,
]]);
}
/**
* Adds the given vertical margin to the element.
*/
final public function my(int $margin): self
{
return $this->with(['styles' => [
'mt' => $margin,
'mb' => $margin,
]]);
}
/**
* Adds the given margin to the element.
*/
final public function m(int $margin): self
{
return $this->my($margin)->mx($margin);
}
/**
* Adds the given padding left to the element.
*/
final public function pl(int $padding): static
{
return $this->with(['styles' => [
'pl' => $padding,
]]);
}
/**
* Adds the given padding right.
*/
final public function pr(int $padding): static
{
return $this->with(['styles' => [
'pr' => $padding,
]]);
}
/**
* Adds the given horizontal padding.
*/
final public function px(int $padding): self
{
return $this->pl($padding)->pr($padding);
}
/**
* Adds the given padding top.
*/
final public function pt(int $padding): static
{
return $this->with(['styles' => [
'pt' => $padding,
]]);
}
/**
* Adds the given padding bottom.
*/
final public function pb(int $padding): static
{
return $this->with(['styles' => [
'pb' => $padding,
]]);
}
/**
* Adds the given vertical padding.
*/
final public function py(int $padding): self
{
return $this->pt($padding)->pb($padding);
}
/**
* Adds the given padding.
*/
final public function p(int $padding): self
{
return $this->pt($padding)->pr($padding)->pb($padding)->pl($padding);
}
/**
* Adds the given vertical margin to the childs, ignoring the first child.
*/
final public function spaceY(int $space): self
{
return $this->with(['styles' => [
'spaceY' => $space,
]]);
}
/**
* Adds the given horizontal margin to the childs, ignoring the first child.
*/
final public function spaceX(int $space): self
{
return $this->with(['styles' => [
'spaceX' => $space,
]]);
}
/**
* Adds a border on top of each element.
*/
final public function borderT(int $width = 1): self
{
if (! $this->element instanceof Hr) {
throw new InvalidStyle('`border-t` can only be used on an "hr" element.');
}
$this->styleModifiers[__METHOD__] = function ($text, $styles): string {
$length = $this->getLength($text);
if ($length < 1) {
$margins = (int) ($styles['ml'] ?? 0) + ($styles['mr'] ?? 0);
return str_repeat('─', self::getParentWidth($this->properties['parentStyles'] ?? []) - $margins);
}
return str_repeat('─', $length);
};
return $this;
}
/**
* Adds a text alignment or color to the element.
*/
final public function text(string $value, int $variant = 0): self
{
if (in_array($value, ['left', 'right', 'center'], true)) {
return $this->with(['styles' => [
'text-align' => $value,
]]);
}
return $this->with(['colors' => [
'fg' => $this->getColorVariant($value, $variant),
]]);
}
/**
* Truncates the text of the element.
*/
final public function truncate(int $limit = 0, string $end = '…'): self
{
$this->textModifiers[__METHOD__] = function ($text, $styles) use ($limit, $end): string {
$width = $styles['width'] ?? 0;
if (is_string($width)) {
$width = self::calcWidthFromFraction(
$width,
$styles,
$this->properties['parentStyles'] ?? []
);
}
[, $paddingRight, , $paddingLeft] = $this->getPaddings();
$width -= $paddingRight + $paddingLeft;
$limit = $limit > 0 ? $limit : $width;
if ($limit === 0) {
return $text;
}
$limit -= mb_strwidth($end, 'UTF-8');
if ($this->getLength($text) <= $limit) {
return $text;
}
return rtrim(self::trimText($text, $limit).$end);
};
return $this;
}
/**
* Forces the width of the element.
*/
final public function w(int|string $width): static
{
return $this->with(['styles' => [
'width' => $width,
]]);
}
/**
* Forces the element width to the full width of the terminal.
*/
final public function wFull(): static
{
return $this->w('1/1');
}
/**
* Removes the width set on the element.
*/
final public function wAuto(): static
{
return $this->with(['styles' => [
'width' => null,
]]);
}
/**
* Defines a minimum width of an element.
*/
final public function minW(int|string $width): static
{
return $this->with(['styles' => [
'minWidth' => $width,
]]);
}
/**
* Defines a maximum width of an element.
*/
final public function maxW(int|string $width): static
{
return $this->with(['styles' => [
'maxWidth' => $width,
]]);
}
/**
* Makes the element's content uppercase.
*/
final public function uppercase(): self
{
$this->textModifiers[__METHOD__] = static fn ($text): string => mb_strtoupper($text, 'UTF-8');
return $this;
}
/**
* Makes the element's content lowercase.
*/
final public function lowercase(): self
{
$this->textModifiers[__METHOD__] = static fn ($text): string => mb_strtolower($text, 'UTF-8');
return $this;
}
/**
* Makes the element's content capitalize.
*/
final public function capitalize(): self
{
$this->textModifiers[__METHOD__] = static fn ($text): string => mb_convert_case($text, MB_CASE_TITLE, 'UTF-8');
return $this;
}
/**
* Makes the element's content in snakecase.
*/
final public function snakecase(): self
{
$this->textModifiers[__METHOD__] = static fn ($text): string => mb_strtolower(
(string) preg_replace(['/([a-z\d])([A-Z])/', '/([^_])([A-Z][a-z])/'], '$1_$2', $text),
'UTF-8'
);
return $this;
}
/**
* Makes the element's content with a line through.
*/
final public function lineThrough(): self
{
$this->styleModifiers[__METHOD__] = static fn ($text): string => sprintf("\e[9m%s\e[0m", $text);
return $this;
}
/**
* Makes the element's content invisible.
*/
final public function invisible(): self
{
$this->styleModifiers[__METHOD__] = static fn ($text): string => sprintf("\e[8m%s\e[0m", $text);
return $this;
}
/**
* Do not display element's content.
*/
final public function hidden(): self
{
return $this->with(['styles' => [
'display' => 'hidden',
]]);
}
/**
* Makes a line break before the element's content.
*/
final public function block(): self
{
return $this->with(['styles' => [
'display' => 'block',
]]);
}
/**
* Makes an element eligible to work with flex-1 element's style.
*/
final public function flex(): self
{
return $this->with(['styles' => [
'display' => 'flex',
]]);
}
/**
* Makes an element grow and shrink as needed, ignoring the initial size.
*/
final public function flex1(): self
{
return $this->with(['styles' => [
'flex-1' => true,
]]);
}
/**
* Justifies childs along the element with an equal amount of space between.
*/
final public function justifyBetween(): self
{
return $this->with(['styles' => [
'justifyContent' => 'between',
]]);
}
/**
* Justifies childs along the element with an equal amount of space between
* each item and half around.
*/
final public function justifyAround(): self
{
return $this->with(['styles' => [
'justifyContent' => 'around',
]]);
}
/**
* Justifies childs along the element with an equal amount of space around each item.
*/
final public function justifyEvenly(): self
{
return $this->with(['styles' => [
'justifyContent' => 'evenly',
]]);
}
/**
* Justifies childs along the center of the container’s main axis.
*/
final public function justifyCenter(): self
{
return $this->with(['styles' => [
'justifyContent' => 'center',
]]);
}
/**
* Repeats the string given until it fills all the content.
*/
final public function contentRepeat(string $string): self
{
$string = preg_replace("/\[?'?([^'|\]]+)'?\]?/", '$1', $string) ?? '';
$this->textModifiers[__METHOD__] = static fn (): string => str_repeat($string, (int) floor(terminal()->width() / mb_strlen($string, 'UTF-8')));
return $this->with(['styles' => [
'contentRepeat' => true,
]]);
}
/**
* Prepends text to the content.
*/
final public function prepend(string $string): self
{
$this->textModifiers[__METHOD__] = static fn ($text): string => $string.$text;
return $this;
}
/**
* Appends text to the content.
*/
final public function append(string $string): self
{
$this->textModifiers[__METHOD__] = static fn ($text): string => $text.$string;
return $this;
}
/**
* Prepends the list style type to the content.
*/
final public function list(string $type, int $index = 0): self
{
if (! $this->element instanceof Ul && ! $this->element instanceof Ol && ! $this->element instanceof Li) {
throw new InvalidStyle(sprintf(
'Style list-none cannot be used with %s',
$this->element !== null ? $this->element::class : 'unknown element'
));
}
if (! $this->element instanceof Li) {
return $this;
}
return match ($type) {
'square' => $this->prepend('▪ '),
'disc' => $this->prepend('• '),
'decimal' => $this->prepend(sprintf('%d. ', $index)),
default => $this,
};
}
/**
* Adds the given properties to the element.
*
* @param array<string, mixed> $properties
*/
public function with(array $properties): self
{
$this->properties = array_replace_recursive($this->properties, $properties);
return $this;
}
/**
* Sets the href property to the element.
*/
final public function href(string $href): self
{
$href = str_replace('%', '%%', $href);
return $this->with(['href' => array_filter([$href])]);
}
/**
* Formats a given string.
*/
final public function format(string $content): string
{
foreach ($this->textModifiers as $modifier) {
$content = $modifier(
$content,
$this->properties['styles'] ?? [],
$this->properties['parentStyles'] ?? []
);
}
$content = $this->applyWidth($content);
foreach ($this->styleModifiers as $modifier) {
$content = $modifier($content, $this->properties['styles'] ?? []);
}
return $this->applyStyling($content);
}
/**
* Get the format string including required styles.
*/
private function getFormatString(): string
{
$styles = [];
/** @var array<int, string> $href */
$href = $this->properties['href'] ?? [];
if ($href !== []) {
$styles[] = sprintf('href=%s', array_pop($href));
}
$colors = $this->properties['colors'] ?? [];
foreach ($colors as $option => $content) {
if (in_array($option, ['fg', 'bg'], true)) {
$content = is_array($content) ? array_pop($content) : $content;
$styles[] = "$option=$content";
}
}
$options = $this->properties['options'] ?? [];
if ($options !== []) {
$options = array_keys(array_filter(
$options, fn ($option) => $option === true
));
$styles[] = count($options) > 0
? 'options='.implode(',', $options)
: 'options=,';
}
// If there are no styles we don't need extra tags
if ($styles === []) {
return '%s%s%s%s%s';
}
return '%s<'.implode(';', $styles).'>%s%s%s</>%s';
}
/**
* Get the margins applied to the element.
*
* @return array{0: int, 1: int, 2: int, 3: int}
*/
private function getMargins(): array
{
$isFirstChild = (bool) $this->properties['isFirstChild'];
$spaceY = $this->properties['parentStyles']['spaceY'] ?? [];
$spaceY = ! $isFirstChild ? end($spaceY) : 0;
$spaceX = $this->properties['parentStyles']['spaceX'] ?? [];
$spaceX = ! $isFirstChild ? end($spaceX) : 0;
return [
$spaceY > 0 ? $spaceY : $this->properties['styles']['mt'] ?? 0,
$this->properties['styles']['mr'] ?? 0,
$this->properties['styles']['mb'] ?? 0,
$spaceX > 0 ? $spaceX : $this->properties['styles']['ml'] ?? 0,
];
}
/**
* Get the paddings applied to the element.
*
* @return array{0: int, 1: int, 2: int, 3: int}
*/
private function getPaddings(): array
{
return [
$this->properties['styles']['pt'] ?? 0,
$this->properties['styles']['pr'] ?? 0,
$this->properties['styles']['pb'] ?? 0,
$this->properties['styles']['pl'] ?? 0,
];
}
/**
* It applies the correct width for the content.
*/
private function applyWidth(string $content): string
{
$styles = $this->properties['styles'] ?? [];
$minWidth = $styles['minWidth'] ?? -1;
$width = max($styles['width'] ?? -1, $minWidth);
$maxWidth = $styles['maxWidth'] ?? 0;
if ($width < 0) {
return $content;
}
if ($width === 0) {
return '';
}
if (is_string($width)) {
$width = self::calcWidthFromFraction(
$width,
$styles,
$this->properties['parentStyles'] ?? []
);
}
if ($maxWidth > 0) {
$width = min($styles['maxWidth'], $width);
}
$width -= ($styles['pl'] ?? 0) + ($styles['pr'] ?? 0);
$length = $this->getLength($content);
preg_match_all("/\n+/", $content, $matches);
$width *= count($matches[0] ?? []) + 1;
$width += mb_strlen($matches[0][0] ?? '', 'UTF-8');
if ($length <= $width) {
$space = $width - $length;
return match ($styles['text-align'] ?? '') {
'right' => str_repeat(' ', $space).$content,
'center' => str_repeat(' ', (int) floor($space / 2)).$content.str_repeat(' ', (int) ceil($space / 2)),
default => $content.str_repeat(' ', $space),
};
}
return self::trimText($content, $width);
}
/**
* It applies the styling for the content.
*/
private function applyStyling(string $content): string
{
$display = $this->properties['styles']['display'] ?? 'inline';
if ($display === 'hidden') {
return '';
}
$isFirstChild = (bool) $this->properties['isFirstChild'];
[$marginTop, $marginRight, $marginBottom, $marginLeft] = $this->getMargins();
[$paddingTop, $paddingRight, $paddingBottom, $paddingLeft] = $this->getPaddings();
$content = (string) preg_replace('/\r[ \t]?/', "\n",
(string) preg_replace(
'/\n/',
str_repeat(' ', $marginRight + $paddingRight)
."\n".
str_repeat(' ', $marginLeft + $paddingLeft),
$content)
);
$formatted = sprintf(
$this->getFormatString(),
str_repeat(' ', $marginLeft),
str_repeat(' ', $paddingLeft),
$content,
str_repeat(' ', $paddingRight),
str_repeat(' ', $marginRight),
);
$empty = str_replace(
$content,
str_repeat(' ', $this->getLength($content)),
$formatted
);
$items = [];
if (in_array($display, ['block', 'flex'], true) && ! $isFirstChild) {
$items[] = "\n";
}
if ($marginTop > 0) {
$items[] = str_repeat("\n", $marginTop);
}
if ($paddingTop > 0) {
$items[] = $empty."\n";
}
$items[] = $formatted;
if ($paddingBottom > 0) {
$items[] = "\n".$empty;
}
if ($marginBottom > 0) {
$items[] = str_repeat("\n", $marginBottom);
}
return implode('', $items);
}
/**
* Get the length of the text provided without the styling tags.
*/
public function getLength(string $text = null): int
{
return mb_strlen(preg_replace(
self::STYLING_REGEX,
'',
$text ?? $this->element?->toString() ?? ''
) ?? '', 'UTF-8');
}
/**
* Get the length of the element without margins.
*/
public function getInnerWidth(): int
{
$innerLength = $this->getLength();
[, $marginRight, , $marginLeft] = $this->getMargins();
return $innerLength - $marginLeft - $marginRight;
}
/**
* Get the constant variant color from Color class.
*/
private function getColorVariant(string $color, int $variant): string
{
if ($variant > 0) {
$color .= '-'.$variant;
}
if (StyleRepository::has($color)) {
return StyleRepository::get($color)->getColor();
}
$colorConstant = mb_strtoupper(str_replace('-', '_', $color), 'UTF-8');
if (! defined(Color::class."::$colorConstant")) {
throw new ColorNotFound($colorConstant);
}
return constant(Color::class."::$colorConstant");
}
/**
* Calculates the width based on the fraction provided.
*
* @param array<string, int> $styles
* @param array<string, array<int, int|string>> $parentStyles
*/
private static function calcWidthFromFraction(string $fraction, array $styles, array $parentStyles): int
{
$width = self::getParentWidth($parentStyles);
preg_match('/(\d+)\/(\d+)/', $fraction, $matches);
if (count($matches) !== 3 || $matches[2] === '0') {
throw new InvalidStyle(sprintf('Style [%s] is invalid.', "w-$fraction"));
}
/** @@phpstan-ignore-next-line */
$width = (int) floor($width * $matches[1] / $matches[2]);
$width -= ($styles['ml'] ?? 0) + ($styles['mr'] ?? 0);
return $width;
}
/**
* Gets the width of the parent element.
*
* @param array<string, array<int|string>> $styles
*/
public static function getParentWidth(array $styles): int
{
$width = terminal()->width();
foreach ($styles['width'] ?? [] as $index => $parentWidth) {
$minWidth = (int) $styles['minWidth'][$index];
$maxWidth = (int) $styles['maxWidth'][$index];
$margins = (int) $styles['ml'][$index] + (int) $styles['mr'][$index];
$parentWidth = max($parentWidth, $minWidth);
if ($parentWidth < 1) {
$parentWidth = $width;
} elseif (is_int($parentWidth)) {
$parentWidth += $margins;
}
preg_match('/(\d+)\/(\d+)/', (string) $parentWidth, $matches);
$width = count($matches) !== 3
? (int) $parentWidth
: (int) floor($width * $matches[1] / $matches[2]); //@phpstan-ignore-line
if ($maxWidth > 0) {
$width = min($maxWidth, $width);
}
$width -= $margins;
$width -= (int) $styles['pl'][$index] + (int) $styles['pr'][$index];
}
return $width;
}
/**
* It trims the text properly ignoring all escape codes and
* `<bg;fg;options>` tags.
*/
private static function trimText(string $text, int $width): string
{
preg_match_all(self::STYLING_REGEX, $text, $matches, PREG_OFFSET_CAPTURE);
$text = rtrim(mb_strimwidth(preg_replace(self::STYLING_REGEX, '', $text) ?? '', 0, $width, '', 'UTF-8'));
foreach ($matches[0] ?? [] as [$part, $index]) {
$text = substr($text, 0, $index).$part.substr($text, $index, null);
}
return $text;
}
}
PK �8]K�"�o o "