Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: alternative single key attachments #15091

Draft
wants to merge 14 commits into
base: attachments-2
Choose a base branch
from

Conversation

Not-Jayden
Copy link
Contributor

Before submitting the PR, please make sure you do the following

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • Prefix your PR title with feat:, fix:, chore:, or docs:.
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.
  • If this PR changes code within packages/svelte/src, add a changeset (npx changeset).

Tests and linting

  • Run the tests with pnpm test and lint the project with pnpm lint

Copy link

changeset-bot bot commented Jan 22, 2025

⚠️ No Changeset found

Latest commit: 8a6810d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Contributor

Playground

pnpm add https://pkg.pr.new/svelte@15091

@Not-Jayden Not-Jayden changed the title refactor: alternative single attachments refactor: alternative single key attachments Jan 22, 2025
@Not-Jayden
Copy link
Contributor Author

Not-Jayden commented Jan 25, 2025

This PR's a mess of me flailing around the compiler, but me exploring the idea of the comment left in #15000

Again: this is about types. It makes no sense to reserve space for future symbol usages (by using createAttachmentKey) when the necessary index type would make those future usages impossible anyway.

Ahh I completely forgot about the index signature type limitations, that's very unfortunate 😕

I think there's probably still a workable solution for a single unique Attachments symbol (Symbol.for('svelte.attachments')) that accepts an array of attachments.

For component attachments, it would look something like:

<script lang="ts">
  import { Attachments, type AttachmentFunction, attach } from 'svelte/attachments';

  let { 
    // Can support extracting just the attachments to a single variable via the `Attachments` key if desired
    // [Attachments]: attachments = [],
    ...props,
  }: { 
    [Attachments]?: AttachmentFunction[] 
  } = $props();
</script>;

<input type="text" {...props}  />
<!-- or for the destructured case -->
<input type="text" attach(...attachments) />

I think the biggest drawback of doing this is it becomes very easy to unintentionally override all the attachments when spreading two objects together. To prevent this I'd probably suggest some special handling for how attachments are merged compared to normal properties on components/elements, and maybe even provide a mergeProps() utility like Vue and Solid.

Something like:

<script lang="ts">
  import { Attachments, type AttachmentFunction } from 'svelte/attachments';
  import { autoSelect, tooltip } from './attachments.js';
  import { mergeProps } from 'svelte';

  const baseProps = {
    [Attachments]: [autoSelect],
  };

  const otherProps = {
    [Attachments]: [tooltip('Enter your name')], 
  };

  // ⚠️ Potential footgun case - `Attachments` is overwritten by otherProps (normal JS behaviour)
  const spreadProps = { ...baseProps, ...otherProps }; 

 // Manually merging attachments by spreading inside $$Attachments
  const manualMergeProps = {
    ...baseProps,
    ...otherProps,
    [Attachments]: [...baseProps[Attachments], ...otherProps[Attachments]]
  };

  // Maybe - Introduce mergeProps convenience utility that combines attachments (and potentially merge other things like events/classes??)
  const mergedProps = mergeProps(baseProps, otherProps);
</script>

<!-- Spreading baseProps and otherProps separately, both arrays attachments should be applied -->
<input type="text" {...baseProps} {...otherProps} />

<!-- ⚠️ Attachments will be overwritten, only tooltip from otherProps will remain -->
<input type="text" {...{ ...baseProps, ...otherProps }} />

<!-- Calling inline attach() will also merge with the other attachments -->
<input type="text" {...mergedProps} attach(tooltip("Now there's two of us!")) />

The basic single spread case is at least working in this PR now (REPL), but still need to figure out how to get attachments from component prop spreads and get the spread merging behaviour working.

Unsure if/when I'll get around to completing this as I'm very out of my depth in the compiler logic, and also unsure if there's any desire for this approach, but will leave this up in draft for the time being.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant