[Feature request] Add Vue support for abstracting components #643
matthew-dean
started this conversation in
General
Replies: 2 comments 2 replies
-
In "Some solutions": what about using a render function? Somewhat related: #479 |
Beta Was this translation helpful? Give feedback.
0 replies
-
Can you explain how this would solve the abstraction problem? That is, getting a child's props and their defaults to set on the abstracted component? |
Beta Was this translation helpful? Give feedback.
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Use case
In our components, it's common for us to "abstract" other libraries UI components to do things like adjust the patterns or simplify the APIs. In some other UI frameworks, this is somewhat trivial. However, in Vue, this is exceptionally difficult.
Example
Here's a very simplified use case. Let's say we want to abstract a
Dialog
component, and default to using itsmodal
set to true.A naive implementation, like above, has several problems immediately:
<Dialog>
will be identical to invoking<Dialog>
directly, because we've used the same type. However, this is entirely incorrect.The biggest problem
The main problem is the lack of exposure of defaults through TypeScript, and lack of consistent exposure of default
props
even on the component itself. Part of the reason is the long-standing Vue bug (or, if you like, a very inconsistent type behavior done on purpose) that infersfalse
from an optional boolean property. This means that, given the same TypeScript definition to 2 components, the resulting value will be different.For example, if
Dialog
has a boolean property that is optional, but a default value oftrue
,MyDialog
will explicitly set that boolean to false, which means that value passed to Dialog isfalse
, which means it is defined, which means it doesn't get set its default value.The problem is beyond booleans though. There's really no consistent way to "expose up" the defaults and define that on the abstracted component. Sometimes there is a
props
property on the component export, but PrimeVue components, for example, have props under anextends
key.Meaning, my props definition looks like:
The slot problem
Vue slots also become very difficult to pass through. The pattern for even setting a single "default" on a component can get very verbose. For example:
Ideally, there would be a way to just say "use these same slots".
The events problem
Events are also tricky, because Vue 3 removed
$listeners
, thus you can no longer write:There's now no longer a good way to pass through events, and they usually must be explicitly declared and "bubbled up".
(I know the documentation says that $attrs can be used as a substitute for $props in this case, but I've never gotten this to work consistently, or at all, especially with TypeScript + defineProps & defineEmits.)
Some solutions?
I don't really have any specific way to fix this, except maybe something like:
EDIT: I figured out that the Options API has this capability and like a few features of the Options API, it's just not present / possible in the Composition API at all. So a much simpler alternative would be exposing the
extends
property of a component, like this:Solution 2
Other ideas welcome.
Beta Was this translation helpful? Give feedback.
All reactions