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
55 changes: 55 additions & 0 deletions .changeset/hungry-things-retire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
"@stackoverflow/stacks-svelte": minor
---

Migrate `Popover`, `PopoverReference`, `PopoverContent`, and `PopoverCloseButton` components to use Svelte 5 runes API

BREAKING CHANGES:

**Popover component:**
- Slot props (`let:visible`, `let:open`, `let:close`) are not available anymore. Snippet parameters should be used instead: `{#snippet children({ visible, open, close })}...{/snippet}`
- `on:open` and `on:close` events are not available anymore. The new callback props should be used instead: `onopen`, `onclose`.

**PopoverCloseButton component:**
- `on:click` event forwarding is not available anymore. The new callback prop should be used instead: `onclick`.

**Migration examples:**

```svelte
<!-- Before (Svelte 4 API) -->
<Popover
id="my-popover"
on:open={() => console.log('opened')}
on:close={() => console.log('closed')}
let:visible
let:close
>
<PopoverReference>
<button>Trigger</button>
</PopoverReference>
<PopoverContent>
<p>Content here</p>
<PopoverCloseButton on:click={handleClick} />
</PopoverContent>
<p>Visible: {visible}</p>
</Popover>

<!-- After (Svelte 5 API) -->
<Popover
id="my-popover"
onopen={() => console.log('opened')}
onclose={() => console.log('closed')}
>
{#snippet children({ visible, close })}
<PopoverReference>
<button>Trigger</button>
</PopoverReference>
<PopoverContent>
<p>Content here</p>
<PopoverCloseButton onclick={handleClick} />
</PopoverContent>
<p>Visible: {visible}</p>
{/snippet}
</Popover>
```

Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
</script>

<script lang="ts">
let visible = false;
let lastEvent: string;
let visible = $state(false);
let lastEvent = $state("");

const onToggle = (e: Event) => {
const target = e.target as HTMLInputElement;
Expand Down Expand Up @@ -152,12 +152,13 @@
<div class="hmn3 d-flex flex__center">
<Popover id="inline" placement="top">
<p class="ws3">
This is is a paragraph <PopoverReference
><span role="button" class="s-link"
This is is a paragraph <PopoverReference>
<span role="button" class="s-link"
>containing a button styled as a link that wraps across
two lines</span
></PopoverReference
>. It shows the benefit of using floating ui inline middleware.
>
</PopoverReference>. It shows the benefit of using floating ui
inline middleware.
</p>
<PopoverContent>Here I am</PopoverContent>
</Popover>
Expand All @@ -170,7 +171,9 @@
<PopoverReference>
<Button weight="filled">Trigger</Button>
</PopoverReference>
<PopoverContent>Here I am<PopoverCloseButton /></PopoverContent>
<PopoverContent>
Here I am<PopoverCloseButton />
</PopoverContent>
</Popover>
</div>
</Story>
Expand All @@ -182,27 +185,28 @@
placement="right"
dismissible={false}
trapFocus={true}
let:close
>
<PopoverReference>
<Button weight="filled">Trigger</Button>
</PopoverReference>
<PopoverContent>
<p class="d-flex fd-column g16">
The focus is now trapped in the popover.
<TextInput size="sm" id="name" label="Name"></TextInput>
<TextInput size="sm" id="surname" label="Surname"
></TextInput>
<Button
type="submit"
weight="filled"
onclick={() => close()}
>
Submit
</Button>
<PopoverCloseButton />
</p>
</PopoverContent>
{#snippet children({ close })}
<PopoverReference>
<Button weight="filled">Trigger</Button>
</PopoverReference>
<PopoverContent>
<p class="d-flex fd-column g16">
The focus is now trapped in the popover.
<TextInput size="sm" id="name" label="Name"></TextInput>
<TextInput size="sm" id="surname" label="Surname"
></TextInput>
<Button
type="submit"
weight="filled"
onclick={() => close()}
>
Submit
</Button>
<PopoverCloseButton />
</p>
</PopoverContent>
{/snippet}
</Popover>
</div>
</Story>
Expand All @@ -224,7 +228,7 @@
id="popover-visibility-control"
type="checkbox"
checked={visible}
on:click={onToggle}
onclick={onToggle}
/>
</div>
</div>
Expand All @@ -241,7 +245,9 @@
</button>
<Popover id="external-reference" placement="bottom">
<PopoverReference elementId="external-reference-element" />
<PopoverContent>Here I am<PopoverCloseButton /></PopoverContent>
<PopoverContent>
Here I am<PopoverCloseButton />
</PopoverContent>
</Popover>
</div>
</Story>
Expand All @@ -251,15 +257,16 @@
<Popover
id="events"
placement="right"
on:open={() => (lastEvent = "opened")}
on:close={() => (lastEvent = "closed")}
let:visible
onopen={() => (lastEvent = "opened")}
onclose={() => (lastEvent = "closed")}
>
<PopoverReference>
<Button weight="filled">Trigger</Button>
</PopoverReference>
<PopoverContent>Here I am</PopoverContent>
<p class="mt12">Visible: {visible}</p>
{#snippet children({ visible })}
<PopoverReference>
<Button weight="filled">Trigger</Button>
</PopoverReference>
<PopoverContent>Here I am</PopoverContent>
<p class="mt12">Visible: {visible}</p>
{/snippet}
</Popover>
<p>Last Event: {lastEvent}</p>
</div>
Expand Down
Loading