diff --git a/packages/@headlessui-react/src/components/description/description.tsx b/packages/@headlessui-react/src/components/description/description.tsx index 893fa4f488..716a9b2813 100644 --- a/packages/@headlessui-react/src/components/description/description.tsx +++ b/packages/@headlessui-react/src/components/description/description.tsx @@ -8,7 +8,6 @@ import React, { // Types ElementType, ReactNode, - ContextType, } from 'react' import { Props } from '../../types' @@ -18,23 +17,35 @@ import { useIsoMorphicEffect } from '../../hooks/use-iso-morphic-effect' // --- -let DescriptionContext = createContext<{ - register(value: string): () => void - slot: Record -}>({ - register() { - return () => {} - }, - slot: {}, -}) +interface SharedData { + slot?: {} + name?: string + props?: {} +} + +let DescriptionContext = createContext< + ({ register(value: string): () => void } & SharedData) | null +>(null) function useDescriptionContext() { - return useContext(DescriptionContext) + let context = useContext(DescriptionContext) + if (context === null) { + let err = new Error( + 'You used a component, but it is not inside a relevant parent.' + ) + if (Error.captureStackTrace) Error.captureStackTrace(err, useDescriptionContext) + throw err + } + return context +} + +interface DescriptionProviderProps extends SharedData { + children: ReactNode } export function useDescriptions(): [ string | undefined, - (props: { children: ReactNode; slot?: Record }) => JSX.Element + (props: DescriptionProviderProps) => JSX.Element ] { let [descriptionIds, setDescriptionIds] = useState([]) @@ -44,10 +55,7 @@ export function useDescriptions(): [ // The provider component useMemo(() => { - return function DescriptionProvider(props: { - children: ReactNode - slot?: Record - }) { + return function DescriptionProvider(props: DescriptionProviderProps) { let register = useCallback((value: string) => { setDescriptionIds(existing => [...existing, value]) @@ -60,9 +68,9 @@ export function useDescriptions(): [ }) }, []) - let contextBag = useMemo>( - () => ({ register, slot: props.slot ?? {} }), - [register, props.slot] + let contextBag = useMemo( + () => ({ register, slot: props.slot, name: props.name, props: props.props }), + [register, props.slot, props.name, props.props] ) return ( @@ -84,18 +92,18 @@ type DescriptionPropsWeControl = 'id' export function Description( props: Props ) { - let { register, slot } = useDescriptionContext() + let context = useDescriptionContext() let id = `headlessui-description-${useId()}` - useIsoMorphicEffect(() => register(id), [id, register]) + useIsoMorphicEffect(() => context.register(id), [id, context.register]) let passThroughProps = props - let propsWeControl = { id } + let propsWeControl = { ...context.props, id } return render({ props: { ...passThroughProps, ...propsWeControl }, - slot, + slot: context.slot || {}, defaultTag: DEFAULT_DESCRIPTION_TAG, - name: 'Description', + name: context.name || 'Description', }) } diff --git a/packages/@headlessui-react/src/components/dialog/dialog.tsx b/packages/@headlessui-react/src/components/dialog/dialog.tsx index b2b192ae4c..32d2fcf9f1 100644 --- a/packages/@headlessui-react/src/components/dialog/dialog.tsx +++ b/packages/@headlessui-react/src/components/dialog/dialog.tsx @@ -264,7 +264,7 @@ let DialogRoot = forwardRefWithAs(function Dialog< - + {render({ props: { ...passthroughProps, ...propsWeControl }, slot, diff --git a/packages/@headlessui-react/src/components/label/label.tsx b/packages/@headlessui-react/src/components/label/label.tsx index af2d8bdd7a..d5a7cf9b82 100644 --- a/packages/@headlessui-react/src/components/label/label.tsx +++ b/packages/@headlessui-react/src/components/label/label.tsx @@ -17,17 +17,31 @@ import { useIsoMorphicEffect } from '../../hooks/use-iso-morphic-effect' // --- -let LabelContext = createContext<{ register(value: string): () => void }>({ - register() { - return () => {} - }, -}) +interface SharedData { + slot?: {} + name?: string + props?: {} +} + +let LabelContext = createContext<({ register(value: string): () => void } & SharedData) | null>( + null +) function useLabelContext() { - return useContext(LabelContext) + let context = useContext(LabelContext) + if (context === null) { + let err = new Error('You used a