diff --git a/packages/@headlessui-react/src/components/menu/menu.tsx b/packages/@headlessui-react/src/components/menu/menu.tsx index dd733657d7..2bea2c8568 100644 --- a/packages/@headlessui-react/src/components/menu/menu.tsx +++ b/packages/@headlessui-react/src/components/menu/menu.tsx @@ -12,6 +12,7 @@ import { useId } from '../../hooks/use-id' import { Keys } from '../keyboard' import { Focus, calculateActiveIndex } from '../../utils/calculate-active-index' import { resolvePropValue } from '../../utils/resolve-prop-value' +import { isDisabledReactIssue7711 } from '../../utils/bugs' enum MenuStates { Open, @@ -413,7 +414,8 @@ function Item( }, [bag, id]) const handleClick = React.useCallback( - (event: { preventDefault: Function }) => { + (event: React.MouseEvent) => { + if (isDisabledReactIssue7711(event.currentTarget)) return event.preventDefault() if (disabled) return event.preventDefault() dispatch({ type: ActionTypes.CloseMenu }) disposables().nextFrame(() => state.buttonRef.current?.focus({ preventScroll: true })) diff --git a/packages/@headlessui-react/src/components/switch/switch.tsx b/packages/@headlessui-react/src/components/switch/switch.tsx index b389b80c7d..7fd2024b7a 100644 --- a/packages/@headlessui-react/src/components/switch/switch.tsx +++ b/packages/@headlessui-react/src/components/switch/switch.tsx @@ -5,6 +5,7 @@ import { render } from '../../utils/render' import { useId } from '../../hooks/use-id' import { Keys } from '../keyboard' import { resolvePropValue } from '../../utils/resolve-prop-value' +import { isDisabledReactIssue7711 } from '../../utils/bugs' type StateDefinition = { switch: HTMLButtonElement | null @@ -84,6 +85,7 @@ export function Switch onChange(!checked), [onChange, checked]) const handleClick = React.useCallback( (event: React.MouseEvent) => { + if (isDisabledReactIssue7711(event.currentTarget)) return event.preventDefault() event.preventDefault() toggle() }, diff --git a/packages/@headlessui-react/src/utils/bugs.ts b/packages/@headlessui-react/src/utils/bugs.ts new file mode 100644 index 0000000000..712047796e --- /dev/null +++ b/packages/@headlessui-react/src/utils/bugs.ts @@ -0,0 +1,30 @@ +// See: https://github.com/facebook/react/issues/7711 +// See: https://github.com/facebook/react/pull/20612 +// See: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-disabled (2.) +export function isDisabledReactIssue7711(element: Element): boolean { + let parent = element.parentElement + let legend = null + + while (parent && !(parent instanceof HTMLFieldSetElement)) { + if (parent instanceof HTMLLegendElement) legend = parent + parent = parent.parentElement + } + + let isParentDisabled = parent?.getAttribute('disabled') === '' ?? false + if (isParentDisabled && isFirstLegend(legend)) return false + + return isParentDisabled +} + +function isFirstLegend(element: HTMLLegendElement | null): boolean { + if (!element) return false + + let previous = element.previousElementSibling + + while (previous !== null) { + if (previous instanceof HTMLLegendElement) return false + previous = previous.previousElementSibling + } + + return true +}