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

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.

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