Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 63 additions & 4 deletions docs/1-essentials/02-views.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,9 @@ Since `:isset` is a shorthand for `:if="isset()"`, it can be combined with `:els
<h1 :else>Title</h1>
```

#### `:foreach` and `:{:hl-keyword:forelse:}`
#### `{:hl-property::foreach:}` and `:{:hl-property:forelse:}`

The `:foreach` directive may be used to render the associated element multiple times based on the result of its expression. Combined with `:{:hl-keyword:forelse:}`, an empty state can be displayed when the data is empty.
The `{:hl-property::foreach:}` directive may be used to render the associated element multiple times based on the result of its expression. Combined with `:{:hl-property:forelse:}`, an empty state can be displayed when the data is empty.

```html
<li :foreach="$this->reports as $report">
Expand Down Expand Up @@ -249,26 +249,35 @@ The example above will only render the child `div` elements:
### Tag override with the `as` prop

The `as` attribute allows you to transform the rendered tag of one element into another. This takes place on an instance of `GenericElement`, so for example this code:

```html
<a as="button">My Link</a>
```

Would render

```html
<button>My Link</button>
```

The power behind this is when you use an `Expression` to determine the element.

Say for example, you wish to have a `<x-link>` component which renders as an `<a>` when the `$href` attribute is provided. In your view, use the component like so:

```html
<x-link href="https://tempestphp.com">Click to go to an awesome website</x-link>

<x-link>This is just a button</x-link>
```

In your `<x-link>` component, define:

```html
<a :as="$href ?? 'button'" :href="$href ?? ''"><x-slot /></a>
```
Your page will render two links, as follows

Your page will render two links, as follows:

```html
<a href="https://tempestphp.com">Click to go to an awesome website</a>

Expand Down Expand Up @@ -348,44 +357,57 @@ In previous releases (3.8.0 and prior), Tempest would attempt to *merge* these v
:::

Assume you have a `button`, like so, with a default set of classes present:

```html x-button.view.php
<button class="rounded-md px-2.5 py-1.5 text-sm">
<x-slot />
</button>
```

Now, in your page, you may utilise the element:

```html index.view.php
<x-button id="myBtn" style="color: red;" />
```

As these attributes automatically apply, your button will be converted to this:

```html
<button id="myBtn" style="color: red;" class="rounded-md px-2.5 py-1.5 text-sm" />
```

#### Disabling automatic fallthrough

Tempest will attempt to apply `{html}class`, `{html}style`, and `{html}id` automatically, when they are passed to a view component. For example:

```html index.view.php
<x-button id="myBtn" style="color: red;" />
```

With the above, Tempest will attempt to apply `{html}style`, and `{html}id` automatically. As `{html}class` isn't configured, it isn't applied.

In the view component itself, you can configure `{html}class`, `{html}style`, and `{html}id` to anything you want, and Tempest will not overwrite them. You can of course, also then use these classes however you want to use them:

```html x-button.view.php
<button :id="uniqid(($id ?? 'mybtn') . '_')" :class="$class ?? 'rounded-md px-2.5 py-1.5 text-sm'">
<x-slot />
</button>
```

When you use this version of `<x-button />`:

- `{html}id` will now default to `mybtn_(sequence generated by uniqid)`,
- `{html}style` will not appear automatically, as it was not supplied,
- `{html}class` will have a default, you can of course instead concatenate these strings, or use a CVA utility for smart class merging, or anything you want.

For example, pass one or more classes:

```html
<x-button id="myBtn" class="override" />
```

And you'll get

```html
<button class="override" id="myBtn_69cad27787c20"></button>
```
Expand All @@ -403,39 +425,51 @@ You cannot mix `ApplyAttribute` with automatic fallthrough attributes. Opting to
#### Excluding specific fallthrough attributes

To exclude specific attributes from falling through, configure your `button` view component like this:

```html x-button.view.php
<button :apply="$attributes->removeKeys(['id', 'style'])">
<x-slot />
</button>
```

:::info
The `removeKeys` method returns all key=>value pairs, except for those specified. You can also use the `filter` method if you need to use a closure to filter.
:::

Now, when utilising it in your page:

```html index.view.php
<x-button id="myBtn" style="color: red;" class="rounded-md px-2.5 py-1.5 text-sm" />
```

Will result in:

```html
<button class="rounded-md px-2.5 py-1.5 text-sm" />
```

#### Including only specific fallthrough attributes

To include only specific attributes, configure your `button` view component like this:

```html x-button.view.php
<button :apply="$attributes->removeKeysExcept(['class', 'width', 'height'])">
<x-slot />
</button>
```

:::info
The `removeKeysExcept` method returns only the specified key=>value pairs. You can also use the `filter` method if you need to use a closure to filter.
:::

Now, when utilising it in your page:

```html index.view.php
<x-button id="myBtn" style="color: red;" class="rounded-md px-2.5 py-1.5 text-sm" width="1em" height="1em" />
```

Tempest will apply only the specified attributes:

```html
<button class="rounded-md px-2.5 py-1.5 text-sm" />
```
Expand All @@ -445,21 +479,27 @@ Tempest will apply only the specified attributes:
As the `ApplyAttribute` simply stringifies string and boolean values from the provided array, you can build the array however you like.

Consider this example `button`:
```php x-button.view.php

```html x-button.view.php
<?php
$apply = [
'class' => $class ?? null,
'href' => $href ?? '',
'target' => (isset($href) && str_contains($href, 'http')) ? '_blank' : null,
];
?>

<button :as="$apply['href'] !== '' ? 'a' : 'button'" :apply="$apply">{{ $label ?? '' }}</button>
```

Now, when utilising it in your page:

```html index.view.php
<x-button href="https://tempestphp.com" label="Tempest, the framework that gets out of your way" />
```

Tempest will spread the supplied attributes, and as we also used the `AsAttribute` to convert it to a `{html}a` when `$href` is populated, you will get a hyperlink:

```html
<a href="https://www.tempestphp.com" target="_blank">Tempest, the framework that gets out of your way</a>
```
Expand Down Expand Up @@ -586,10 +626,12 @@ To override this behaviour and manually control in which view component your slo
#### Extendable view component example using `define`

Let us assume you have an `x-container` view component, which is a `<div>` with formatting to act as a flex container for responsive sizing. You use this component repeatedly across your project, and it's effectively a macro to open and close the `<div>`; it doesn't have any slots or do anything special itself otherwise, with only a default `<x-slot/>` to render whatever it is given.

```html x-container.view.php
<div class="w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"><x-slot/></div>
```
Now, assume we have an `x-header` in which we wish to use the `x-container`. Our `x-header` wishes to place slots `left` and `right` inside it; `x-header` owns these slots and wishes to expose these slots at the callsite in case they need custom content. Using the `define` keyword tells Tempest to treat these slots as *defined* by `x-header` instead of as a *slot to fill* inside `x-container`. Using `name` here instead of `define` would mean that Tempest falls back to the AST, and treats them as if they are slots of `<x-container>`.

```html x-header.view.php
<header>
<x-slot name="top" />
Expand All @@ -607,17 +649,21 @@ Now, assume we have an `x-header` in which we wish to use the `x-container`. Our
<x-slot name="bottom" />
</header>
```

At the callsite, you still use the `name` attribute to define which slot you're placing content into:

```html callsite.view.php
<x-header>
<x-slot name="left">Some content I want to insert</x-slot>
</x-header>
```

This example would replace the default content `<x-header-left />` instead with the literal string `Some content I want to insert` - or whatever you provide.

#### Populating a child's name slot using `define`

You can also push content into a child's named slot, not just the default slot, by creating a `define`d slot as follows:

```html x-outer.view.php
<div class="outer">
<x-inner>
Expand All @@ -627,12 +673,15 @@ You can also push content into a child's named slot, not just the default slot,
</x-inner>
</div>
```

Again, the `define` keyword registers a `left` slot against the view component `<x-outer>` irrespective of it's position in the AST, and means that at the callsite:

```html outercallsite.view.php
<x-outer>
<x-slot name="left">My override</x-slot>
</x-outer>
```

And so, this places the literal string `My override` into `<x-innner>`'s `left` slot.

### Dynamic view components
Expand Down Expand Up @@ -757,7 +806,9 @@ This component provides the ability to inject any icon from the [Iconify](https:
```html
<x-icon name="material-symbols:php" class="size-4 text-indigo-400" />
```

will render

```html
<svg class="size-4 text-indigo-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
Expand All @@ -772,7 +823,9 @@ This component includes some optional props you can use to control width and hei
```html
<x-icon name="material-symbols:php" />
```

will render

```html
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path
Expand All @@ -787,7 +840,9 @@ Firstly, you can set width and height using Tailwind or custom classes. As long
```html
<x-icon name="material-symbols:php" class="w-[24px] h-[24px] text-indigo-400" />
```

will render

```html
<svg class="w-[24px] h-[24px] text-indigo-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
Expand All @@ -802,7 +857,9 @@ Secondly, if you aren't using Tailwind, or wish to set for a single icon without
```html
<x-icon name="material-symbols:php" style="width: 24px; height: 24px;" />
```

will render

```html
<svg style="width: 24px; height: 24px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
Expand All @@ -817,7 +874,9 @@ Finally, you may provide the width and height properties directly with the props
```html
<x-icon name="material-symbols:php" width="24px" height="24px" />
```

will render

```html
<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24">
<path
Expand Down
4 changes: 3 additions & 1 deletion docs/1-essentials/05-discovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ Discovery comes with performance considerations. In production, it is always cac

To ensure that the discovery cache is up-to-date, add the `discovery:generate` command before any other Tempest command in your deployment pipeline.

```console ">_ ./tempest discovery:generate --no-interaction"
```console
./tempest discovery:generate --no-interaction

Clearing discovery cache <dim>.....................................</dim> <strong>2025-12-30 15:51:46</strong>
Clearing discovery cache <dim>.....................................</dim> <strong>DONE</strong>
Generating discovery cache using the `full` strategy <dim>.........</dim> <strong>2025-12-30 15:51:46</strong>
Expand Down
4 changes: 2 additions & 2 deletions docs/2-features/13-static-pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ The only thing left to do is to generate the static pages:

## Crawling for dead links

Optionally, you can instruct the static generate to crawl your pages to scan for dead links. This is done by passing the `--crawl` option to the `static:generate` command:
Optionally, you can instruct the static generate to crawl your pages to scan for dead links. This is done by passing the `--crawl` option to the `{txt}static:generate` command:

```console
<dim>./tempest static:generate --crawl</dim>
Expand All @@ -127,6 +127,6 @@ By default, the crawler will only check for internal dead links. If you want to

## Production

Static pages are generated in the `/public` directory, as `index.html` files. Most web servers will automatically serve these static pages for you without any additional setup.
Static pages are generated in the `{txt}/public` directory, as `index.html` files. Most web servers will automatically serve these static pages for you without any additional setup.

Note that static pages are meant to be generated as part of your deployment script. That means the `{txt}./tempest static:generate` command should be in your deployment pipeline.
2 changes: 1 addition & 1 deletion docs/3-packages/01-highlight.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: "Tempest's highlighter is a package for server-side, high-performan

Require `tempest/highlight` with composer:

```
```console
composer require tempest/highlight
```

Expand Down
2 changes: 1 addition & 1 deletion docs/3-packages/03-responsive-image.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: "A standalone package to render responsive images"

## Quickstart

```
```console
composer require tempest/responsive-image
```

Expand Down
2 changes: 1 addition & 1 deletion docs/3-packages/04-markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: "Fast and extensible Markdown in PHP"

## Quickstart

```sh
```console
composer require tempest/markdown
```

Expand Down
8 changes: 4 additions & 4 deletions docs/5-extra-topics/04-contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ Even though we release on a non-fixed schedule, we do assign deadlines to the `n

### Colors

<span class="swatch" style="--color: #1b1429">#1b1429</span>
<span class="swatch" style="--color: #29abe2">#29abe2</span>
<span class="swatch" style="--color: #00e7ff">#00e7ff</span>
<span class="swatch" style="--color: #0071bc">#0071bc</span>
- <span class="swatch" style="--color: #1b1429">#1b1429</span>
- <span class="swatch" style="--color: #29abe2">#29abe2</span>
- <span class="swatch" style="--color: #00e7ff">#00e7ff</span>
- <span class="swatch" style="--color: #0071bc">#0071bc</span>
Loading