@uppy/svelte: fix props reactivity (#5991)

The fix in #5872 was not enough

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Fix props reactivity in Svelte components by updating plugin options
reactively and add example + tests validating Dashboard/StatusBar prop
changes.
> 
> - **Svelte components (@uppy/svelte)**:
> - **Reactivity fix**: In `components/Dashboard.svelte`,
`DashboardModal.svelte`, and `StatusBar.svelte`, switch reactive updates
from `uppy.setOptions(...)` to `plugin?.setOptions(...)` to ensure
`props` changes are applied.
> - **Examples/Tests**:
> - Add `examples/sveltekit/src/components/test/props-reactivity.svelte`
demonstrating toggling `props` for `Dashboard` and `StatusBar`.
> - Extend `examples/sveltekit/test/index.test.ts` with tests verifying
Dashboard `ariaDisabled` toggles and StatusBar `hideUploadButton`
reactivity.
> - **Changeset**:
>   - Patch release for `"@uppy/svelte"` noting props reactivity fix.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
5a9c4ef00f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
This commit is contained in:
Merlijn Vos 2025-10-01 16:16:47 +02:00 committed by GitHub
parent 8d4045e82a
commit da754b7fa4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 56 additions and 3 deletions

View file

@ -0,0 +1,5 @@
---
"@uppy/svelte": patch
---
Fix props reactivity. Now when the value of a prop you pass to a component changes, it is actually picked up.

View file

@ -0,0 +1,23 @@
<script lang="ts">
import Uppy from '@uppy/core'
import Dashboard from '@uppy/svelte/dashboard'
import StatusBar from '@uppy/svelte/status-bar'
import '@uppy/core/css/style.css'
import '@uppy/dashboard/css/style.css'
import '@uppy/status-bar/css/style.css'
const uppy = new Uppy()
uppy.addFile(new File(['hello world'], 'hello.txt'))
let disabled = false
let hideUploadButton = false
</script>
<main class="p-5 max-w-xl mx-auto">
<button onclick={() => (disabled = !disabled)}>Toggle dashboard</button>
<Dashboard props={{disabled: disabled}} uppy={uppy} />
<button onclick={() => (hideUploadButton = !hideUploadButton)}>Toggle statusbar</button>
<div id="statusbar-container">
<StatusBar props={{ hideUploadButton }} uppy={uppy} />
</div>
</main>

View file

@ -1,6 +1,7 @@
import { userEvent } from '@vitest/browser/context'
import { describe, expect, test } from 'vitest'
import { render } from 'vitest-browser-svelte'
import PropsReactivity from '../src/components/test/props-reactivity.svelte'
import App from '../src/routes/+page.svelte'
const createMockFile = (name: string, type: string, size: number = 1024) => {
@ -124,3 +125,27 @@ describe('RemoteSource Component', () => {
await expect.element(loginButton).toBeInTheDocument()
})
})
test('Dashboard reacts to prop changes', async () => {
const screen = render(PropsReactivity)
const toggleButton = screen.getByText('Toggle dashboard')
const dashboard = screen.container.querySelector('.uppy-Dashboard')
expect(dashboard).toBeTruthy()
expect(dashboard?.ariaDisabled).toEqual('false')
await userEvent.click(toggleButton)
expect(dashboard?.ariaDisabled).toEqual('true')
})
test('StatusBar reacts to prop changes', async () => {
const screen = render(PropsReactivity)
const toggleButton = screen.getByText('Toggle statusbar')
expect(
screen.container.querySelector('#statusbar-container .uppy-c-btn-primary'),
).toBeVisible()
await userEvent.click(toggleButton)
expect(
screen.container.querySelector('#statusbar-container .uppy-c-btn-primary'),
).toEqual(null)
})

View file

@ -40,7 +40,7 @@ $: {
...props,
target: container,
} satisfies DashboardOptions<M, B>;
uppy.setOptions(options);
plugin?.setOptions(options);
}
</script>

View file

@ -42,7 +42,7 @@ $: {
...props,
target: container,
} satisfies DashboardOptions<M, B>;
uppy.setOptions(options);
plugin?.setOptions(options);
}
$: {
if (open && !lastOpen) {

View file

@ -35,7 +35,7 @@ $: {
...props,
target: container,
} satisfies StatusBarOptions;
uppy.setOptions(options);
plugin?.setOptions(options);
}
</script>