unovue / radix-vue

Vue port of Radix UI Primitives. An open-source UI component library for building high-quality, accessible design systems and web apps.
https://radix-vue.com
MIT License
3.65k stars 226 forks source link

[Feature]: Add option for radix-vue/nuxt to only auto-import certain components #479

Closed madebyfabian closed 1 year ago

madebyfabian commented 1 year ago

Describe the feature

Hi there! Thank you all again for the awesome work on this project.

I am currently using it to create a reusable ui library inside a project. I want to add some props (mostly tailwind classes) to some of the components. And then a user should have them all auto-imported.

But most of the Radix Components can just be used as-is. (e.g. DialogRoot, etc.)

I tried to find a solution so that a user can do stuff like this:

<template>
  <DialogRoot>
    <DialogTrigger />
    <DialogPortal>
      <DialogOverlay />
      <DialogContent>
        <DialogTitle />
        <DialogDescription />
        <DialogClose />
      </DialogContent>
    </DialogPortal>
  </DialogRoot>
</template>

where the DialogRoot, DialogTrigger, DialogPortal is auto-imported from radix-vue, and the others such as DialogOverlay, DialogContent, DialogTitle, DialogDescription, DialogClose are auto-imported because I defined them in my project, e.g. under components/Dialog/DialogOverlay.vue.

Alternatives

import { DialogClose, DialogRoot, DialogTrigger } from 'radix-vue'

export default defineNuxtPlugin(nuxtApp => {
  nuxtApp.vueApp.component('DialogRoot', DialogRoot)
  nuxtApp.vueApp.component('DialogTrigger', DialogTrigger)
  nuxtApp.vueApp.component('DialogPortal', DialogPortal)
})
<template> 
  <DialogRoot> <!-- <- type unknown -->

But that would be much boilerplate.

---

Maybe there is an alternative to this that I haven't checked out yet. But I guess the easiest thing would be to have a configuration to only explicitly import certain components of the nuxt module. 

### Additional information

- [ ] I intend to submit a PR for this feature.
- [ ] I have already implemented and/or tested this feature.
madebyfabian commented 1 year ago

Discussion on Discord: https://discord.com/channels/473401852243869706/1168164792633143326/1168164792633143326

zernonia commented 1 year ago

Hey @madebyfabian .. this is a good feature to have! For large project with many components might ran into issue with duplicated imports. In order to provide much more configuration to devs.. we can:

  1. Add options to import desired component:

    // nuxt.config.ts
    'radix': {
    components: {
    dialog: true,
    alertDialog: true
    } // only imported `true` component will be imported, if `components: true` all components will be imported
    }
  2. We can add prefix to imported components:

    // nuxt.config.ts
    'radix': {
    components: {
    ...
    },
    prefix: "Ui"  // components will be imported as `UiDialog`, `UiDialogTrigger`
    }
madebyfabian commented 1 year ago

@zernonia Yeah, I see the prefix Option is already working.

Regarding your first solution though, that would be great for users in general, though in my case, it won't work. Since I only need a few components from the dialog to be auto imported.

So in my case, I guess it makes sense to build my own nuxt module based on https://github.com/radix-vue/radix-vue/blob/main/packages/plugins/src/nuxt/index.ts

zernonia commented 1 year ago

Icic.. I wonder why plugin approach doesn't infer the types correctly tho.. have you tried restarting the IDE or run nuxi prepare to generate the component.d.ts?

export default defineNuxtPlugin(nuxtApp => {
  nuxtApp.vueApp.component('DialogRoot', DialogRoot)
  nuxtApp.vueApp.component('DialogTrigger', DialogTrigger)
  nuxtApp.vueApp.component('DialogPortal', DialogPortal)
})
madebyfabian commented 1 year ago

@zernonia Yeah I was wondering too. I removed the .nuxt folder, re-generated the d.ts, restarted the IDE, but it's still type unknown. I am not sure if this is a nuxt issue, generally not supporting typed components when importing via plugin, or if this normally should work and it's something with radix-vue

enkot commented 1 year ago

@madebyfabian The easiest way it to create Nuxt module and select what you need:

// modules/radix.ts
import { addComponent, defineNuxtModule } from '@nuxt/kit'

const components = [
  'DialogTrigger',
  'DialogPortal',
  'DialogRoot'
]

export default defineNuxtModule({
  setup() {
    for (const component of components) {
      addComponent({
        name: component, // or `Ui${component}`,
        export: component,
        filePath: 'radix-vue'
      })
    }
  }
})
madebyfabian commented 1 year ago

@enkot thanks! Yes that's exactly what I ended up doing 😊