sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
76.8k stars 3.98k forks source link

Svelte 5: Allow passing `use` and `transition` to components #11452

Closed rChaoz closed 2 weeks ago

rChaoz commented 2 weeks ago

Describe the problem

It's difficult to apply transitions/animations/actions to components. Sometimes libraries offer support for applying transitions - like Skeleton with dynamic transitions, but this requires quite some work for every component library author, and many times it's not there. More often than not you end up having to use a wrapper div:

<div transition:slide use:action>
    <Component />
</div>

This isn't ideal (might cause issues with layouts, selectors or such) and the transition/action would work perfectly fine applied to the root component element.

Describe the proposed solution

Add a standardized way to pass transitions/animations/actions to components, which can then apply them on an element (or even another component). An idea of how that might look like:

<script>
    let { a, b, ...restProps} = $props()
    const { in, out } = $transitions()
    const actions = $actions()
</script>

<div in:in out:out use:actions {...restProps}>
    ...
</div>

For example, when a component is used like so:

<Component in:slide={slideProps} out:fade={otherProps} use:action1={action1Props} use:action2={action2Props} />

Then $transitions() would return an object constructed like so:

const transitions = {
    in(node) {
        return slide(node, slideProps)
    },
    out(node) {
        return fade(otherProps)
    }
}

And actions like so:

const actions = (node) {
    action1(node, action1Props)
    action2(node, action2Props)
}

Importance

would make my life easier

7nik commented 2 weeks ago

It already was proposed multiple times: #7477, #7244, #6771, #5775, #5218, #5140.

How is your proposal better than passing action and transition via props? REPL

rChaoz commented 2 weeks ago

I think the major difference is that now there is a non-breaking way to implement it (using runes), instead of the ways proposed before (props with special names). It's fitting to add something like this in a major version, and I think the fact it was proposed so many times (once with a lot of likes too) means it would be a loved feature.

How is your proposal better than passing action and transition via props?

I think that having a standardized way to do this would be great, and it would motivate component library authors to actually allow transitions/actions, or even animations on their components (I can't find even one that allows all three).

I also think it reduces boilerplate, especially if it's implemented using a single rune, like so:

<script>
    const { in, out, actions, animation } = $directives()
</script>

<div in:in out:out use:actions animate:animation>...</div>

or even like this if you want to allow/forward all directives

<script>
    const directives = $directives()
</script>

<div apply:directives>...</div>

(but I think this is getting a little out of scope and has more issues - the idea is the same)

It really reduces the amount of code needed for both the component author and the user, especially if you want to use transitions or animations with props, multiple actions, etc. Finally, I just think it's natural - I'm sure every svelte user has tried at some point to use a transition on a component to then be met with an error (or maybe it's just me).

7nik commented 2 weeks ago

The dev team repeatedly demonstrated that they aren't interested in this feature, especially when a simple workaround exists.

Another problem is that it can be used only on components where authors declared the forwarding, while the wrapper approach works with any component.

Rich-Harris commented 2 weeks ago

We have some ideas for how to tackle this problem post-5.0, but it won't look like this. Will share more when we can, but in the meantime I'll close this to save people from spending energy on something we're not going to pursue.