Skip to content
Open
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
1 change: 1 addition & 0 deletions resources/views/docs/mobile/4/edge-components/layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ The parser recognizes the classes listed below.
| Margin | `m-N`, `mx-N`, `my-N`, `mt-N`, `mr-N`, `mb-N`, `ml-N`, arbitrary `m-[N]` etc. |
| Gap | `gap-N`, `gap-[N]` (uniform — no `gap-x-*` or `gap-y-*`) |
| Position | `absolute`, `relative`, `top-N`, `right-N`, `bottom-N`, `left-N`, arbitrary `top-[N]` etc. |
| Anchor / origin | `anchor-{point}`, `origin-{point}` — where `{point}` is `center`, an edge (`top`/`right`/`bottom`/`left`) or a corner (`top-left`…`bottom-right`). See [Positioning](../the-basics/positioning#anchor-amp-origin) |
| Flex | `flex-1`, `flex-grow`, `flex-grow-0`, `flex-shrink`, `flex-shrink-0`, `flex-wrap`, `flex-nowrap`, `flex-wrap-reverse` |
| Items (cross-axis) | `items-start`, `items-center`, `items-end`, `items-stretch` |
| Justify (main-axis) | `justify-start`, `justify-center`, `justify-end`, `justify-between`, `justify-around`, `justify-evenly` |
Expand Down
49 changes: 39 additions & 10 deletions resources/views/docs/mobile/4/edge-components/stack.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,35 @@ Useful for badges, image overlays, floating labels, and layered UI effects.
Accepts any EDGE elements as children. Children are rendered in order, with later children appearing on top of earlier
ones.

Each child is **placed at its natural size and centered** in the stack's bounds. Give a child `w-full` or `h-full` to
force it to fill the stack.
Every child is positioned **absolutely** and placed at its natural size — you don't need `relative` on the stack or
`absolute` on the children. By default each child is **centered** in the stack's bounds. Give a child `w-full` or
`h-full` to force it to fill the stack.

The stack itself **sizes to its largest child** when you don't give it explicit dimensions, so a small overlaid
element (a badge, a dot) won't shrink the stack.

### Anchoring children

Move a child away from the centre with two points — one on the stack, one on the child:

- **`anchor`** — the point on the **stack** the child hooks onto.
- **`origin`** — the point **on the child** that lands there.

Both default to `center` and accept `center`, the four edges (`top`, `right`, `bottom`, `left`) and the four corners
(`top-left` … `bottom-right`) — as an attribute or an `anchor-*` / `origin-*` class. The child's `origin` point is
placed exactly on the stack's `anchor` point, so a child can sit on — or hang off — an edge or corner. See
[Positioning](../the-basics/positioning#anchor-amp-origin) for the full model.

@verbatim
```blade
<native:stack class="w-[56] h-[56]">
<native:image src="https://i.pravatar.cc/128?img=12" class="w-[56] h-[56] rounded-full" />
{{-- The dot's centre (origin default) sits on the stack's top-right corner. --}}
<native:column anchor="top-right"
class="w-[14] h-[14] rounded-full bg-green-500 border-2 border-white" />
</native:stack>
```
@endverbatim

## Supported Tailwind classes

Expand All @@ -46,19 +73,21 @@ Everything else from the shared list applies as on any element (`p-*`, `m-*`, `b

## Examples

### Avatar with centered badge
### Avatar with a corner status dot

@verbatim
```blade
<native:stack class="w-[56] h-[56]">
<native:column class="w-[56] h-[56] rounded-full bg-theme-surface-variant" />
<native:column class="w-[20] h-[20] bg-green-500 rounded-full border-2 border-white" />
<native:image src="https://i.pravatar.cc/128?img=12" class="w-[56] h-[56] rounded-full" />
{{-- The dot's centre sits on the avatar's bottom-right corner. --}}
<native:column anchor="bottom-right"
class="w-[16] h-[16] bg-green-500 rounded-full border-2 border-white" />
</native:stack>
```
@endverbatim

In a real app the base layer would typically be a `<native:image>` avatar (e.g.
`<native:image src="https://i.pravatar.cc/128?img=12" class="w-[56] h-[56] rounded-full" />`).
Set `origin` too if you want a different part of the badge on the corner — e.g. `anchor="top-right"
origin="top-right"` tucks the badge fully *inside* the corner instead of straddling it.

### Badge on an icon

Expand Down Expand Up @@ -89,9 +118,9 @@ In a real app the base layer would typically be a `<native:image>` avatar (e.g.

<aside>

For corner-anchored placement (e.g. a status dot pinned to the bottom-right of an avatar), wrap your content in a
`<native:column class="relative">` parent and use `<native:column class="absolute bottom-[0] right-[0]">` for the
anchored child. See [Positioning](../the-basics/positioning).
Because a child's `origin` can extend past the stack's `anchor`, a child **can draw outside the stack** on both iOS
and Android — handy for badges that poke over a corner. Nothing clips by default; clipping only applies when the
stack (or an ancestor) has rounded corners or is a scroll view. See [Positioning](../the-basics/positioning#anchor-amp-origin).

</aside>

Expand Down
96 changes: 81 additions & 15 deletions resources/views/docs/mobile/4/the-basics/positioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,96 @@ order: 190

Most layouts use the flex engine — children flow inside their parent column or row. For overlays like floating
action buttons, badges that hang off the edge of an avatar, or a "skip" button pinned to a corner, the framework
also supports CSS-style absolute positioning.
also supports CSS-style absolute positioning, plus a two-point **anchor / origin** model for precise placement.

## Tailwind classes
## Absolute positioning

Take an element out of flex flow and position it relative to its parent. You can use either Tailwind classes or
plain attributes — they are equivalent.

@verbatim
```blade
{{-- Tailwind classes --}}
<native:column class="absolute bottom-[20] right-[20]">
{{-- Pinned to the bottom-right corner of the parent --}}
</native:column>

{{-- The same thing as attributes --}}
<native:column absolute :bottom="20" :right="20">
...
</native:column>
```
@endverbatim

| Class | Attribute | Effect |
|---|---|---|
| `absolute` | `absolute` / `position="absolute"` | Take this element out of flex flow and position it against its parent |
| `relative` | `relative` / `position="relative"` | Default; element flows normally |
| `top-[N]` | `:top="N"` | Inset from the parent's top edge (dp) |
| `right-[N]` | `:right="N"` | Inset from the parent's right edge (dp) |
| `bottom-[N]` | `:bottom="N"` | Inset from the parent's bottom edge (dp) |
| `left-[N]` | `:left="N"` | Inset from the parent's left edge (dp) |

When an explicit class form and its attribute are both present (e.g. `class="top-4"` and `:top="99"`), the class
form wins.

### Inset convention

When `right` is set and `left` is unset, the child anchors to the parent's right edge offset by that amount. Same
for `bottom`. This mirrors CSS `position: absolute` shorthand. If both `left` and `right` are set, the child
stretches between them; likewise for `top` and `bottom`.

## Anchor & origin

For precise overlay placement, an absolutely-positioned child can align **two points** — one on the parent and one
on itself — instead of pinning to an edge:

- **`anchor`** — the point on the **parent** the child hooks onto.
- **`origin`** — the point **on the child** that lands on that parent point.

Both default to `center`, and both accept the same nine values (or the `anchor-*` / `origin-*` class form):

```
top-left top top-right
left center right
bottom-left bottom bottom-right
```

(`top` is an alias for `top-center`, `left` for `center-left`, and so on.)

The child is placed so its `origin` point sits exactly on the parent's `anchor` point:

@verbatim
```blade
{{-- The dot's CENTRE (origin defaults to center) sits on the parent's top-right
corner — so it straddles the corner, half inside and half outside. --}}
<native:column class="relative w-[56] h-[56]">
<native:image src="https://i.pravatar.cc/128?img=12" class="w-[56] h-[56] rounded-full" />
<native:column anchor="top-right"
class="absolute w-[14] h-[14] rounded-full bg-green-500 border-2 border-white" />
</native:column>

{{-- Give the child its own origin to change which part of it lands on the anchor.
Here the badge's bottom-left corner hooks the parent's top-right corner. --}}
<native:column absolute anchor="top-right" origin="bottom-left" class="...">
...
</native:column>
```
@endverbatim

- `absolute` - Take this element out of flex flow and position it relative to the nearest positioned ancestor
- `relative` - Default; element flows normally
- `top-[N]` - Inset from the parent's top edge (dp)
- `right-[N]` - Inset from the parent's right edge (dp)
- `bottom-[N]` - Inset from the parent's bottom edge (dp)
- `left-[N]` - Inset from the parent's left edge (dp)
`anchor` and `origin` apply to any absolutely-positioned child. Insets (`top`/`right`/`bottom`/`left`) still apply
on top as a nudge from the anchored position. A plain `absolute top-0 right-0` child with no `anchor`/`origin`
keeps the simple edge-inset behaviour described above.

## Anchor convention
<aside>

When `right-[N]` is set and `left-` is unset, the child anchors to the parent's right edge offset by N. Same for
`bottom-`. This mirrors CSS `position: absolute` shorthand.
Because the child's `origin` can extend past the parent's `anchor`, a child **can draw outside its container** — on
both iOS and Android. Nothing clips by default; clipping only kicks in when the container (or an ancestor) has
rounded corners or is a scroll view. For a badge that pokes out of a `rounded-full` avatar, keep the badge a
**sibling** of the avatar (inside a non-rounded parent), not a child of the rounded element. Touch targets that fall
outside the parent's bounds may not receive taps, so keep interactive overflow modest.

If both `left-` and `right-` are set, the child stretches between them. Likewise for `top-` and `bottom-`.
</aside>

## Common pattern: floating action button

Expand All @@ -56,8 +121,9 @@ Absolute children only occupy their placed bounds — siblings receive scroll an

<aside>

`<native:stack>` does **not** currently honor `position-type: absolute` for its children — it uses its own custom
Layout to center children at their natural size. Use a `<native:row>` or `<native:column>` as the parent when you
need absolute positioning.
A [`<native:stack>`](../edge-components/stack) positions **all** of its children absolutely with `anchor` / `origin`
(both defaulting to `center`), so it's the most convenient parent for overlays — you don't need `relative` on the
parent or `absolute` on the children. Use a `<native:row>` / `<native:column>` parent when you want a single
overlay on top of normal flowing content instead.

</aside>
Loading