Skip to content
New issue

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

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

Already on GitHub? # to your account

JSX compatible slots #2472

Closed
Tracked by #2547 ...
KaelWD opened this issue Feb 28, 2023 · 1 comment · Fixed by #2547 or #2568
Closed
Tracked by #2547 ...

JSX compatible slots #2472

KaelWD opened this issue Feb 28, 2023 · 1 comment · Fixed by #2547 or #2568
Labels
enhancement New feature or request

Comments

@KaelWD
Copy link

KaelWD commented Feb 28, 2023

I swear this used to work ages ago.

Vuetify defines slots as $props.$children and sets JSX.ElementChildrenAttribute to $children. Vue already comes with JSX.ElementAttributesProperty as $props so this works great in JSX:

// import { VMenu } from 'vuetify/components'
import type { DefineComponent, VNodeChild } from 'vue'

declare const VMenu: DefineComponent<{
  $children: {
    activator: (props: { isActive: boolean }) => VNodeChild
  }
}>

const el = (
  <VMenu>
    {{ activator: props => String(props.isActive) }}
  </VMenu>
)

Volar is only looking at $slots or children though, so we'd have to define our slot types twice for them to work with it.

export type ExtractComponentSlots<T> =
IsAny<T> extends true ? Record<string, any>
: T extends { ${slots}?: infer S } ? { [K in keyof S]-?: S[K] extends ((obj: infer O) => any) | undefined ? O : any }
: T extends { children?: infer S } ? { [K in keyof S]-?: S[K] extends ((obj: infer O) => any) | undefined ? O : any }
: Record<string, any>;

This also means that slots from .vue files only work in other .vue files and can't be used in JSX:

<script setup lang="ts"></script>

<template>
  <slot name="activator" :isActive="false" />
</template>
import Slots from './Slots.vue'

const el = (
  <Slots>
    {{ foo: props => props.isActive }} // expected boolean, got implicit any
  </Slots>
)

vuejs/core#7083 adds ElementChildrenAttribute to vue core.

Volar could check T[keyof JSX.ElementAttributesProperty][keyof JSX.ElementChildrenAttribute] to support any combination of these, and generate its own slots in $props somewhere so they can be used in JSX.

@KaelWD
Copy link
Author

KaelWD commented Feb 28, 2023

Adding $props: { $slots } to our types seems to work for most components, but because volar is using T['$slots'] instead of T['$props']['$slots'] it doesn't pick up any slots for components with generic props like VSelect.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
enhancement New feature or request
Projects
None yet
2 participants