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(Table)!: allow passing all tanstack options as root props #3177

Draft
wants to merge 10 commits into
base: v3
Choose a base branch
from

Conversation

MuhammadM1998
Copy link
Contributor

πŸ”— Linked issue

#2441

❓ Type of change

  • πŸ“– Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • πŸ‘Œ Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

πŸ“š Description

As discussed in #3065, This PR allows the user to pass all accepted options to useVueTable. This has caveats discussed below, until then I'll leave it in draft.

This PR implements these points:

  • Removes the explicitly declared Tanstack options from props and instead introduces a tanstackOptions prop that accepts all the possible useVueTable options. This means the user can implement any Tanstack feature without waiting on the library to implement it.
  • Moves the previously passed options as defaults passed to defu with the first argument being the tanstackOptions prop to allow the user to override them if needed.
  • Adds getPaginationRowModel as a default to have pagination baked-in similar to sorting and the other common features we have as defaults.

Caveats:

This has 2 problems that needs to be addressed.

  • Moving the previously declared tanstack options from top-level props to tanstackOptions is a breaking change.
  • Now the behavior is not consistent. For example, the user would pass a ref to the top level sorting model value but pass options to the tanstack-options prop. which is not ideal.

I've tried doing the following to extend the Tanstack options as top-level props which would solve both of the above problems.

+ export type TableTanstackOptions<T> = Omit<TableOptionsWithReactiveData<T>, 'data' | 'columns' | 'getCoreRowModel'>

- export interface TableProps<T> {
+ export interface TableProps<T> extends TableTanstackOptions<T> {

But the playground & docs crashes with the following error similar to the one mentioned in #2291

[@vue/compiler-sfc] Failed to resolve extends base type.
If this previously worked in 3.2, you can instruct the compiler to ignore this extend by adding /* @v
ue-ignore */ before it, for example:

interface Props extends /* @vue-ignore */ Base {}

When I use /* @vue-ignore */ the app works correctly but then the top level options are passed as attrs not props as mentioned in the error instruction, so no way to extract them and pass them useVueTable.

πŸ“ Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

Copy link

pkg-pr-new bot commented Jan 25, 2025

npm i https://pkg.pr.new/@nuxt/ui@3177

commit: e679c46

@MuhammadM1998 MuhammadM1998 mentioned this pull request Jan 27, 2025
11 tasks
@benjamincanac benjamincanac added the v3 #1289 label Jan 30, 2025
@MuhammadM1998 MuhammadM1998 force-pushed the refactor/table-tanstack branch from 6921dc1 to d8e4cfd Compare January 31, 2025 17:52
@MuhammadM1998
Copy link
Contributor Author

Hey @sandros94. I've tried both Dev Drive and WSL as you suggested and the same issue persists. Can you please take a look and share any ideas you have?

The errors happens when I extend the props with tanstackOptions, declaring a prop with the same type works fine.

// This Works
export interface TableProps<T> {
  tanstackOptions: TableTanstackOptions<T>, 
}
 
// This errors
export interface TableProps<T> extends TableTanstackOptions<T> {

image

@MuhammadM1998
Copy link
Contributor Author

After some digging, probably it's not supported yet vuejs/core#8482

@sandros94
Copy link
Collaborator

sandros94 commented Feb 1, 2025

I still think that this is completely unrelated to path length or anything on that topic.

I see this as two different issues, one related to types (the requirement of /* @vue-ignore */, that for some reason doesn't work for me) and another for correctly passing the table's related props to useVueTable. This latter one is easy to fix but I'm struggling with the first one.

Will update in a few minutes (famous last words)

@sandros94
Copy link
Collaborator

After some digging, probably it's not supported yet vuejs/core#8482

but if this was it (as Vue needs to compile the types, so they cannot be fully dynamic) why it works when dynamic types are passed to as tanstackOptions?: TableTanstackOptions<T> πŸ€”

@sandros94
Copy link
Collaborator

sandros94 commented Feb 1, 2025

Indeed the issue seems to be related to TableOptionsResolved from @tanstack/vue-table, and I still think it is unrelated to vue's compiler.

I found a potential fix, but before pushing it I want to double check it further

@MuhammadM1998
Copy link
Contributor Author

MuhammadM1998 commented Feb 1, 2025

but if this was it (as Vue needs to compile the types, so they cannot be fully dynamic) why it works when dynamic types are passed to as tanstackOptions?: TableTanstackOptions<T> πŸ€”

The problem is the intersection/union of TableProps & TableTanstackOptions. Using only one of them works fine, that's why it works when using tanstackOptions?: TableTanstackOptions<T> as we're using only one type

To confirm it further I tried extending the most basic type and I also got the same error.

export interface TableProps<T> extends { foo: 'bar' }

@sandros94
Copy link
Collaborator

sandros94 commented Feb 1, 2025

@MuhammadM1998 not really, take a look at 20307f4.

As you can see some of the FeatureOptions are commented out, I still haven't looked into which of them cause vue to error out, but I did notice some of them are dynamic types

Now I'm experimenting with the base options for those features that I currently commented out, as I suspect that the issue is more related to their functions.

I've also removed getPaginationRowModel, as it is more project dependent. As it easily breaks/forces pagination in context where a different configuration is needed (particularly via server-side pagination), updating docs rn.

@MuhammadM1998
Copy link
Contributor Author

Hmm I might be missing something I don't get why CoreOptions would work and not TableTanstackOptions πŸ€”

Another thing I noticed is you moved the table props to defu as last argument, wouldn't this ignore passed props by the user if it's already defined inside the component? For example, passing a custom onGlobalFilterChange to the component won't run as the declared onGlobalFilterChange in the component will always have a higher priority?

@sandros94
Copy link
Collaborator

Hmm I might be missing something I don't get why CoreOptions would work and not TableTanstackOptions πŸ€”

CoreOptions is the only part that fully works. It's the FeatureOptions, the other extend, that introduces many issues and breaks quite a few things here and there. For example my latest commit broke both selection and pagination

Another thing I noticed is you moved the table props to defu as last argument, wouldn't this ignore passed props by the user if it's already defined inside the component? For example, passing a custom onGlobalFilterChange to the component won't run as the declared onGlobalFilterChange in the component will always have a higher priority?

Yes indeed, and I'm probably going to revert it. The reason why I did move it is because it could easily break the various emits.

@MuhammadM1998
Copy link
Contributor Author

I get what you mean now. I'll try to test it and see if I catch anything. Thanks for the help πŸ™

@sandros94
Copy link
Collaborator

I'll try to test it and see if I catch anything. Thanks for the help πŸ™

I'm always happy to help where I can 😬

Personally, I'm still not fully convinced about having all the tanstack options as top-level props. I had to rely on /* @vue-ignore */ a bit too much for my liking, and potentially see us fixing strange issues or edge-cases due to some tanstack option being wrongly compiled by Vue's props (or just conflict with other). As you have noticed the errors don't help us, since they don't actually pinpoint the root cause.

@MuhammadM1998 let me know if you notice anything. In my limited experience with tanstack it does seem to work correctly now (although some types are missing due to the requirement of vue ignore mentioned).

@benjamincanac Are we sure that the DX we want to achieve is completely encapsulated within a single component? What about creating a wrapper composable for useVueTable (for example useTable) and then use its output directly within UTable? At that point we could also subdivide it in UTableH, UTableR and UTableD for more advanced uses.

Also, any particular reason why:

defineExpose({
tableApi
})
instead of just defineExpose(tableApi)? This way we could simplify the DX by providing table?.setPageIndex(p - 1) instead of table?.tableApi.setPageIndex(p - 1) (if we want to keep everything in a single component, without a dedicated composable)

@benjamincanac benjamincanac changed the title feat: allow passing all tanstack options to the table feat(Table)!: allow passing all tanstack options as root props Feb 3, 2025
@benjamincanac
Copy link
Member

Trying to catch-up here, is this ready for review? πŸ€”

@sandros94 This is how components are made in Nuxt UI v3, if you want a component for td, th, etc. it's more shadcn-vue philosophy I guess.

@benjamincanac
Copy link
Member

benjamincanac commented Feb 3, 2025

@sandros94 In my last commit, I've cleaned a bit and moved the tableApi in the defineExpose as you suggested 😊

@sandros94
Copy link
Collaborator

@sandros94 This is how components are made in Nuxt UI v3, if you want a component for td, th, etc. it's more shadcn-vue philosophy I guess.

Or Reka UI, but yes out scope of Nuxt UI

Trying to catch-up here, is this ready for review? πŸ€”

Technically speaking, yes.

What doesn't fully convince me is that quite a few useVueTable's options conflict with Vue's props compiler (those I checked only because are dynamic types and simply not supported). I don't know Tanstack deeply enough to understand if this could increase the maintenance complexity or be safe to do.

What I left untouched are all the defineModels. If we want to go with top-level props should we keep them? Currently useVueTable isn't reactive (except for the data)

@sandros94
Copy link
Collaborator

What I left untouched are all the defineModels. If we want to go with top-level props should we keep them? Currently useVueTable isn't reactive (except for the data)

Rethinking about this it shouldn't be a problem. Basically, talking out loud, the DX would become like:

  1. remove all current defineModule
  2. new props are only responsible for initializing the table (data and options)
  3. use the table's template ref to alter the data/options (eg.: hiding/showing/pinning columns) and provide the upstream functionalities as they got developed

@benjamincanac WDYT?

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

Successfully merging this pull request may close these issues.

3 participants