Skip to content

Commit

Permalink
use HTMLElement for generic DOM node types (#3169)
Browse files Browse the repository at this point in the history
We keep specific types for elements with special meaning, such as
`HTMLButtonElement`, `HTMLLabelElement` or `HTMLInputElement` because
they receive certain attributes that generic DOM nodes (such as
HTMLDivElement) don't

For the components where we use simple `div` elements (and where people
use `as={...}`) that renders a different element, it doesn't make sense
to use `HTMLDivElement`. Using a more generic `HTMLElement` is simpler
and more correct (we still had `HTMLUListElement` and `HTMLLIElement`
for "div" DOM nodes which is incorrect).

This shouldn't be a breaking change because an `HTMLDivElement` is still
a valid `HTMLElement`. The other way around wouldn't be the case.
  • Loading branch information
RobinMalfait committed May 3, 2024
1 parent f0e3e5b commit 0bd8c47
Show file tree
Hide file tree
Showing 9 changed files with 27 additions and 27 deletions.
10 changes: 5 additions & 5 deletions packages/@headlessui-react/src/components/combobox/combobox.tsx
Expand Up @@ -550,7 +550,7 @@ let ComboboxDataContext = createContext<

inputRef: MutableRefObject<HTMLInputElement | null>
buttonRef: MutableRefObject<HTMLButtonElement | null>
optionsRef: MutableRefObject<HTMLUListElement | null>
optionsRef: MutableRefObject<HTMLElement | null>
} & Omit<StateDefinition<unknown>, 'dataRef'>)
| null
>(null)
Expand Down Expand Up @@ -1425,7 +1425,7 @@ function ButtonFn<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG>(

let refocusInput = useRefocusableInput(data.inputRef)

let handleKeyDown = useEvent((event: ReactKeyboardEvent<HTMLUListElement>) => {
let handleKeyDown = useEvent((event: ReactKeyboardEvent<HTMLElement>) => {
switch (event.key) {
// Ref: https://www.w3.org/WAI/ARIA/apg/patterns/menu/#keyboard-interaction-12

Expand Down Expand Up @@ -1574,7 +1574,7 @@ export type ComboboxOptionsProps<TTag extends ElementType = typeof DEFAULT_OPTIO

function OptionsFn<TTag extends ElementType = typeof DEFAULT_OPTIONS_TAG>(
props: ComboboxOptionsProps<TTag>,
ref: Ref<HTMLUListElement>
ref: Ref<HTMLElement>
) {
let internalId = useId()
let {
Expand Down Expand Up @@ -1750,7 +1750,7 @@ function OptionFn<
// TODO: One day we will be able to infer this type from the generic in Combobox itself.
// But today is not that day..
TType = Parameters<typeof ComboboxRoot>[0]['value'],
>(props: ComboboxOptionProps<TTag, TType>, ref: Ref<HTMLLIElement>) {
>(props: ComboboxOptionProps<TTag, TType>, ref: Ref<HTMLElement>) {
let data = useData('Combobox.Option')
let actions = useActions('Combobox.Option')

Expand All @@ -1772,7 +1772,7 @@ function OptionFn<
: data.options[data.activeOptionIndex]?.id === id

let selected = data.isSelected(value)
let internalOptionRef = useRef<HTMLLIElement | null>(null)
let internalOptionRef = useRef<HTMLElement | null>(null)

let bag = useLatestValue<ComboboxOptionDataRef<TType>['current']>({
disabled,
Expand Down
Expand Up @@ -107,7 +107,7 @@ export type DescriptionProps<TTag extends ElementType = typeof DEFAULT_DESCRIPTI

function DescriptionFn<TTag extends ElementType = typeof DEFAULT_DESCRIPTION_TAG>(
props: DescriptionProps<TTag>,
ref: Ref<HTMLParagraphElement>
ref: Ref<HTMLElement>
) {
let internalId = useId()
let providedDisabled = useDisabled()
Expand Down
14 changes: 7 additions & 7 deletions packages/@headlessui-react/src/components/dialog/dialog.tsx
Expand Up @@ -61,7 +61,7 @@ enum DialogStates {

interface StateDefinition {
titleId: string | null
panelRef: MutableRefObject<HTMLDivElement | null>
panelRef: MutableRefObject<HTMLElement | null>
}

enum ActionTypes {
Expand Down Expand Up @@ -135,7 +135,7 @@ export type DialogProps<TTag extends ElementType = typeof DEFAULT_DIALOG_TAG> =

function DialogFn<TTag extends ElementType = typeof DEFAULT_DIALOG_TAG>(
props: DialogProps<TTag>,
ref: Ref<HTMLDivElement>
ref: Ref<HTMLElement>
) {
let internalId = useId()
let {
Expand Down Expand Up @@ -173,7 +173,7 @@ function DialogFn<TTag extends ElementType = typeof DEFAULT_DIALOG_TAG>(
open = (usesOpenClosedState & State.Open) === State.Open
}

let internalDialogRef = useRef<HTMLDivElement | null>(null)
let internalDialogRef = useRef<HTMLElement | null>(null)
let dialogRef = useSyncRefs(internalDialogRef, ref)

let ownerDocument = useOwnerDocument(internalDialogRef)
Expand Down Expand Up @@ -440,7 +440,7 @@ export type DialogOverlayProps<TTag extends ElementType = typeof DEFAULT_OVERLAY

function OverlayFn<TTag extends ElementType = typeof DEFAULT_OVERLAY_TAG>(
props: DialogOverlayProps<TTag>,
ref: Ref<HTMLDivElement>
ref: Ref<HTMLElement>
) {
let internalId = useId()
let { id = `headlessui-dialog-overlay-${internalId}`, ...theirProps } = props
Expand Down Expand Up @@ -492,7 +492,7 @@ export type DialogBackdropProps<TTag extends ElementType = typeof DEFAULT_BACKDR

function BackdropFn<TTag extends ElementType = typeof DEFAULT_BACKDROP_TAG>(
props: DialogBackdropProps<TTag>,
ref: Ref<HTMLDivElement>
ref: Ref<HTMLElement>
) {
let internalId = useId()
let { id = `headlessui-dialog-backdrop-${internalId}`, ...theirProps } = props
Expand Down Expand Up @@ -547,7 +547,7 @@ export type DialogPanelProps<TTag extends ElementType = typeof DEFAULT_PANEL_TAG

function PanelFn<TTag extends ElementType = typeof DEFAULT_PANEL_TAG>(
props: DialogPanelProps<TTag>,
ref: Ref<HTMLDivElement>
ref: Ref<HTMLElement>
) {
let internalId = useId()
let { id = `headlessui-dialog-panel-${internalId}`, ...theirProps } = props
Expand Down Expand Up @@ -594,7 +594,7 @@ export type DialogTitleProps<TTag extends ElementType = typeof DEFAULT_TITLE_TAG

function TitleFn<TTag extends ElementType = typeof DEFAULT_TITLE_TAG>(
props: DialogTitleProps<TTag>,
ref: Ref<HTMLHeadingElement>
ref: Ref<HTMLElement>
) {
let internalId = useId()
let { id = `headlessui-dialog-title-${internalId}`, ...theirProps } = props
Expand Down
Expand Up @@ -54,7 +54,7 @@ interface StateDefinition {
linkedPanel: boolean

buttonRef: MutableRefObject<HTMLButtonElement | null>
panelRef: MutableRefObject<HTMLDivElement | null>
panelRef: MutableRefObject<HTMLElement | null>

buttonId: string | null
panelId: string | null
Expand Down Expand Up @@ -433,7 +433,7 @@ export type DisclosurePanelProps<TTag extends ElementType = typeof DEFAULT_PANEL

function PanelFn<TTag extends ElementType = typeof DEFAULT_PANEL_TAG>(
props: DisclosurePanelProps<TTag>,
ref: Ref<HTMLDivElement>
ref: Ref<HTMLElement>
) {
let internalId = useId()
let { id = `headlessui-disclosure-panel-${internalId}`, ...theirProps } = props
Expand Down
Expand Up @@ -90,9 +90,9 @@ export type FocusTrapProps<TTag extends ElementType = typeof DEFAULT_FOCUS_TRAP_

function FocusTrapFn<TTag extends ElementType = typeof DEFAULT_FOCUS_TRAP_TAG>(
props: FocusTrapProps<TTag>,
ref: Ref<HTMLDivElement>
ref: Ref<HTMLElement>
) {
let container = useRef<HTMLDivElement | null>(null)
let container = useRef<HTMLElement | null>(null)
let focusTrapRef = useSyncRefs(container, ref)
let {
initialFocus,
Expand Down
6 changes: 3 additions & 3 deletions packages/@headlessui-react/src/components/listbox/listbox.tsx
Expand Up @@ -418,7 +418,7 @@ let ListboxDataContext = createContext<
listRef: MutableRefObject<Map<string, HTMLElement | null>>

buttonRef: MutableRefObject<HTMLButtonElement | null>
optionsRef: MutableRefObject<HTMLUListElement | null>
optionsRef: MutableRefObject<HTMLElement | null>
} & Omit<StateDefinition<unknown>, 'dataRef'>)
| null
>(null)
Expand Down Expand Up @@ -1003,7 +1003,7 @@ function OptionsFn<TTag extends ElementType = typeof DEFAULT_OPTIONS_TAG>(
container?.focus({ preventScroll: true })
}, [data.listboxState, data.optionsRef, data.optionsRef.current])

let handleKeyDown = useEvent((event: ReactKeyboardEvent<HTMLUListElement>) => {
let handleKeyDown = useEvent((event: ReactKeyboardEvent<HTMLElement>) => {
searchDisposables.dispose()

switch (event.key) {
Expand Down Expand Up @@ -1176,7 +1176,7 @@ function OptionFn<
data.activeOptionIndex !== null ? data.options[data.activeOptionIndex].id === id : false

let selected = data.isSelected(value)
let internalOptionRef = useRef<HTMLLIElement | null>(null)
let internalOptionRef = useRef<HTMLElement | null>(null)
let getTextValue = useTextValue(internalOptionRef)
let bag = useLatestValue<ListboxOptionDataRef<TType>['current']>({
disabled,
Expand Down
6 changes: 3 additions & 3 deletions packages/@headlessui-react/src/components/menu/menu.tsx
Expand Up @@ -93,7 +93,7 @@ interface StateDefinition {
__demoMode: boolean
menuState: MenuStates
buttonRef: MutableRefObject<HTMLButtonElement | null>
itemsRef: MutableRefObject<HTMLDivElement | null>
itemsRef: MutableRefObject<HTMLElement | null>
items: { id: string; dataRef: MenuItemDataRef }[]
searchQuery: string
activeItemIndex: number | null
Expand Down Expand Up @@ -590,7 +590,7 @@ export type MenuItemsProps<TTag extends ElementType = typeof DEFAULT_ITEMS_TAG>

function ItemsFn<TTag extends ElementType = typeof DEFAULT_ITEMS_TAG>(
props: MenuItemsProps<TTag>,
ref: Ref<HTMLDivElement>
ref: Ref<HTMLElement>
) {
let internalId = useId()
let {
Expand Down Expand Up @@ -675,7 +675,7 @@ function ItemsFn<TTag extends ElementType = typeof DEFAULT_ITEMS_TAG>(
},
})

let handleKeyDown = useEvent((event: ReactKeyboardEvent<HTMLDivElement>) => {
let handleKeyDown = useEvent((event: ReactKeyboardEvent<HTMLElement>) => {
searchDisposables.dispose()

switch (event.key) {
Expand Down
6 changes: 3 additions & 3 deletions packages/@headlessui-react/src/components/popover/popover.tsx
Expand Up @@ -730,7 +730,7 @@ export type PopoverOverlayProps<TTag extends ElementType = typeof DEFAULT_OVERLA

function OverlayFn<TTag extends ElementType = typeof DEFAULT_OVERLAY_TAG>(
props: PopoverOverlayProps<TTag>,
ref: Ref<HTMLDivElement>
ref: Ref<HTMLElement>
) {
let internalId = useId()
let { id = `headlessui-popover-overlay-${internalId}`, ...theirProps } = props
Expand Down Expand Up @@ -804,7 +804,7 @@ export type PopoverPanelProps<TTag extends ElementType = typeof DEFAULT_PANEL_TA

function PanelFn<TTag extends ElementType = typeof DEFAULT_PANEL_TAG>(
props: PopoverPanelProps<TTag>,
ref: Ref<HTMLDivElement>
ref: Ref<HTMLElement>
) {
let internalId = useId()
let {
Expand All @@ -822,7 +822,7 @@ function PanelFn<TTag extends ElementType = typeof DEFAULT_PANEL_TAG>(
let beforePanelSentinelId = `headlessui-focus-sentinel-before-${internalId}`
let afterPanelSentinelId = `headlessui-focus-sentinel-after-${internalId}`

let internalPanelRef = useRef<HTMLDivElement | null>(null)
let internalPanelRef = useRef<HTMLElement | null>(null)
let anchor = useResolvedAnchor(rawAnchor)
let [floatingRef, style] = useFloatingPanel(anchor)
let getFloatingPanelProps = useFloatingPanelProps()
Expand Down
Expand Up @@ -303,7 +303,7 @@ function useNesting(done?: () => void, parent?: NestingContextValues) {
// ---

let DEFAULT_TRANSITION_CHILD_TAG = Fragment
type TransitionChildRenderPropArg = MutableRefObject<HTMLDivElement>
type TransitionChildRenderPropArg = MutableRefObject<HTMLElement>
let TransitionChildRenderFeatures = RenderFeatures.RenderStrategy

function TransitionChildFn<TTag extends ElementType = typeof DEFAULT_TRANSITION_CHILD_TAG>(
Expand Down

0 comments on commit 0bd8c47

Please sign in to comment.