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
5 changes: 5 additions & 0 deletions .changeset/hip-papayas-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@geajs/core': major
---

Introduce <Teleport> component with zero-reset re-parenting and robust event delegation support.
80 changes: 80 additions & 0 deletions .cursor/skills/gea-framework/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- [Event Handling](#event-handling)
- [Conditional Rendering](#conditional-rendering)
- [List Rendering](#list-rendering)
- [Teleport](#teleport)
- [Multiple Stores](#multiple-stores)
- [Store Composition](#store-composition)
- [Computed Values](#computed-values)
Expand Down Expand Up @@ -635,6 +636,85 @@ Callbacks inside `.map()` use event delegation — the framework resolves which

---

## Teleport

Teleport renders content in a different part of the DOM tree while keeping it logically part of your component. Useful for modals, tooltips, and overlays that need to escape parent styling or z-index context.

### Import

```ts
import type { TeleportProps } from '@geajs/core'
```

### Basic Usage

```jsx
export default class App extends Component {
showModal = false

template() {
return (
<div class="app">
<button onclick={() => this.showModal = true}>Open Modal</button>

<Teleport to-selector="#modal-root">
<div class={`modal ${this.showModal ? 'visible' : 'hidden'}`}>
<h2>Modal Title</h2>
<p>This content is rendered in #modal-root!</p>
<button onclick={() => this.showModal = false}>Close</button>
</div>
</Teleport>
</div>
)
}
}
```

### Props

| Prop | Type | Required | Description |
| --- | --- | --- | --- |
| `to-selector` | `string` | Yes | CSS selector for target element |
| `disabled` | `boolean` | No | Prevents teleporting when `true` |

### Features

- **Zero-Reset**: Component state preserved during teleporting
- **Event Delegation**: Event handlers work normally on teleported content
- **Reactivity**: Content moves when `to-selector` changes
- **Conditional**: Use `disabled` prop to toggle teleporting
- **Cleanup**: Automatic cleanup on component disposal

### Examples

```jsx
// Conditional teleport
<Teleport to-selector="#sidebar" disabled={!this.showSidebar}>
<SidebarContent />
</Teleport>

// Dynamic target
<Teleport to-selector={this.isMobile ? '#mobile-root' : '#desktop-root'}>
<ResponsiveContent />
</Teleport>

// Multiple teleports
<Teleport to-selector="#notifications">
<Toast message={this.message} />
</Teleport>
<Teleport to-selector="#modals">
<ConfirmDialog />
</Teleport>
```

### Target Requirements

- Target element must exist in DOM when component renders
- If target not found, warning is logged and content stays in place
- Targets can be anywhere in document, including outside app root

---

## Multiple Stores

### When to Split Stores
Expand Down
100 changes: 100 additions & 0 deletions docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,106 @@ Supported gestures: `tap`, `longTap`, `swipeRight`, `swipeLeft`, `swipeUp`, `swi

---

## Teleport

### Import

```ts
import type { TeleportProps } from '@geajs/core'
```

### Usage

Teleport renders content in a different part of the DOM tree while keeping it logically part of your component. This is useful for modals, tooltips, and other UI elements that need to escape their parent's styling or z-index context.

```jsx
import { Component } from '@geajs/core'

export default class App extends Component {
showModal = false

template() {
return (
<div class="app">
<button onclick={() => this.showModal = true}>Open Modal</button>

<Teleport to-selector="#modal-root">
<div class={`modal ${this.showModal ? 'visible' : 'hidden'}`}>
<h2>Modal Title</h2>
<p>This content is rendered in #modal-root, not here!</p>
<button onclick={() => this.showModal = false}>Close</button>
</div>
</Teleport>
</div>
)
}
}
```

### Props

| Prop | Type | Required | Description |
| --- | --- | --- | --- |
| `to-selector` | `string` | Yes | CSS selector for target element where content should be teleported |
| `disabled` | `boolean` | No | When `true`, prevents teleporting and keeps content in original location |

### Features

- **Zero-Reset**: Component state is preserved during teleporting
- **Event Delegation**: Event handlers work normally on teleported content
- **Reactivity**: When `to-selector` changes, content is moved to the new target
- **Conditional**: Use `disabled` prop to toggle teleporting on/off
- **Cleanup**: Teleported content is automatically cleaned up when component is disposed

### Examples

```jsx
// Basic teleport
<Teleport to-selector="#modal-root">
<Modal />
</Teleport>

// Conditional teleport
<Teleport to-selector="#sidebar" disabled={!this.showSidebar}>
<SidebarContent />
</Teleport>

// Dynamic target
<Teleport to-selector={this.isMobile ? '#mobile-container' : '#desktop-container'}>
<ResponsiveContent />
</Teleport>

// Multiple teleports
<div>
<Teleport to-selector="#modals">
<ConfirmDialog />
</Teleport>
<Teleport to-selector="#notifications">
<Toast message={this.message} />
</Teleport>
</div>
```

### Target Element Requirements

- The target element must exist in the DOM when the component renders
- If the target is not found, a warning is logged and content remains in its original location
- Target elements can be anywhere in the document, including outside the Gea root

### TypeScript

```ts
import type { TeleportProps } from '@geajs/core'

// Type-safe teleport props
const teleportProps: TeleportProps = {
'to-selector': '#modal-root',
disabled: false
}
```

---

## Project Setup

### Vite Configuration
Expand Down
Loading