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

feat(svelte-form): Add Svelte adapter #1247

Open
wants to merge 21 commits into
base: main
Choose a base branch
from

Conversation

dummdidumm
Copy link

This implements a Svelte adapter for the form package. API-wise it's somewhere inbetween Solid and React (createForm is used like Solid's, getting the field state from within a snippet is more like React). Added basic tests and two examples.

Superseeds #1107

43081j and others added 11 commits January 5, 2025 22:07
Absolutely untested, written without running it or trying it out in any
way. Just a very rough start written off the top of my head with the
help of various bits of docs.
- one Field component with a module script with createField in it
- createForm file
- bunch of types that pass along generics, closely modeled after the other adapters
- tests
Copy link

nx-cloud bot commented Mar 7, 2025

View your CI Pipeline Execution ↗ for commit f01a213.

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ❌ Failed 1m 57s View ↗
nx run-many --target=build --exclude=examples/** ✅ Succeeded 24s View ↗

☁️ Nx Cloud last updated this comment at 2025-03-21 22:20:22 UTC

@lachlancollins lachlancollins mentioned this pull request Mar 8, 2025
5 tasks
@43081j
Copy link

43081j commented Mar 8, 2025

Let me know if you want any help with this 👍 my pr went stale since I was in need of someone to pair/review with but I am still very much interested in landing this

],
"dependencies": {
"@tanstack/form-core": "workspace:*",
"@tanstack/svelte-store": "^0.7.0"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should come from workspace:* I think

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't part of the monorepo, so like this is the correct way

} from '@tanstack/form-core'
import { useStore } from '@tanstack/svelte-store'
import { onMount, type Snippet } from 'svelte'
import Field from './Field.svelte'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is really, really odd. importing the file we're in, from the file we're in

i'm surprised this did something. even if this somehow works, we really shouldn't be doing it imo

this is why createField and Field were originally separate

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why shouldn't we? This is valid JavaScript, you can self-import in ESM, it's part of the spec. This is just a different way of doing what the other adapters are doing, where they have Field and createField in the same file.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its basically a hacky workaround for the fact there's a circular dependency here (createField needs Field and vice versa), and in svelte the component is the module as a whole

ideally, we'd figure it out properly. though im not sure how off the top of my head

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you running into a problem with the circular ref? In general it's ok due to the way js imports work (e.g., you can import yourself), but ideally something we resolve.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im fully aware that this "works", its just not great for code quality/readability and is inconsistent with the rest of the codebase

also its a clear workaround for the circular dependency. you did this because you couldn't define Field in the file itself (since it is the file), whereas in all other integrations we would just have it in a named export

i disagree with doing it this way but will leave it up to other reviewers to decide

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're not gonna get a "clean" solution because there's a cyclic dependency here. So either you have a cyclic import or you have a self-import - I prefer the latter due to colocation.

extendedApi.createField = (props) =>
createField(() => {
return { ...props(), form: api }
}) as never
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how come you weren't able to type this properly? (i.e. without as never)

Copy link
Author

@dummdidumm dummdidumm Mar 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a comment; TS throws an error here that type instantiation is excessively deep (same as for Solid FWIW)

@Dreaming-Codes
Copy link

Is this ready for testing it in a project?

@niemyjski
Copy link

Is this ready for testing it in a project?

And if it is, would love to know if there is a nightly build :), Otherwise what is left / where we can help.

@JonathonRP
Copy link

Is this ready for testing it in a project?

what is left / where we can help.

I see an error in types that has an @ts/error with no actual error, and as someone else pointed that import failing. I think the reviews need to approve and best guess they will once those two failing tests pass from the fixes I mentioned...

id="form"
onsubmit={(e) => {
e.preventDefault()
e.stopPropagation()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we probably don't need to stop the propagation here. doesn't make much difference in these examples but would be good to avoid people thinking this is necessary

const target = e.target as HTMLInputElement
subField.handleChange(target.value)
}}
/>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it may be me missing something, but html doesn't use self-closing tags anymore (they're ignored). stuff like this should be a void tag (<input>)


import rootConfig from '../../eslint.config.js'

export default [...rootConfig]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you think there's opportunity here to enable svelte rules for the svelte files in here?

not in this PR, but we could open an issue to do it separately if you think that makes sense

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

honestly I don't care, Eslint isn't of much use in this repo in my opinion, so I'd rather just keep it as is

Copy link

@43081j 43081j Mar 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be clear, we were always going to keep it as it is in this pr. i was asking in case its worth us opening an issue to do it in a separate PR

not in this PR, but we could open an issue to do it separately

it may make sense for linting svelte sources since we'll have a few after this PR

@43081j
Copy link

43081j commented Mar 23, 2025

some of the CI failure seems unrelated, some eslint.config.js stuff from the react package

this all looks good other than the failing CI though 👍 i left a few very minor comments but nothing much

there's an unfortunate amount of any, unsafe casts (as never) and such. but there's not a huge amount we can do about them given the circular references and overly deep type inference

@43081j
Copy link

43081j commented Mar 27, 2025

i tried this out locally and dug around the types a bit etc, all seems pretty good

maybe we can get some kind of nightly build sorted soon

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.

7 participants