[internal] add demo mode to Menu and Popover components (#2448)

* add demo mode to `Menu` and `Popover`

* update changelog
This commit is contained in:
Robin Malfait
2023-04-21 13:51:26 +02:00
committed by GitHub
parent b98e642a67
commit 08127dd2ad
3 changed files with 53 additions and 16 deletions
+3 -1
View File
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- Nothing yet!
### Added
- [internal] add demo mode to `Menu` and `Popover` components ([#2448](https://github.com/tailwindlabs/headlessui/pull/2448))
## [1.7.14] - 2023-04-12
@@ -69,6 +69,7 @@ type MenuItemDataRef = MutableRefObject<{
}>
interface StateDefinition {
__demoMode: boolean
menuState: MenuStates
buttonRef: MutableRefObject<HTMLButtonElement | null>
itemsRef: MutableRefObject<HTMLDivElement | null>
@@ -141,7 +142,12 @@ let reducers: {
},
[ActionTypes.OpenMenu](state) {
if (state.menuState === MenuStates.Open) return state
return { ...state, menuState: MenuStates.Open }
return {
...state,
/* We can turn off demo mode once we re-open the `Menu` */
__demoMode: false,
menuState: MenuStates.Open,
}
},
[ActionTypes.GoToItem]: (state, action) => {
let adjustedState = adjustOrderedState(state)
@@ -238,14 +244,23 @@ interface MenuRenderPropArg {
close: () => void
}
export type MenuProps<TTag extends ElementType> = Props<TTag, MenuRenderPropArg>
export type MenuProps<TTag extends ElementType> = Props<
TTag,
MenuRenderPropArg,
never,
{
__demoMode?: boolean
}
>
function MenuFn<TTag extends ElementType = typeof DEFAULT_MENU_TAG>(
props: MenuProps<TTag>,
ref: Ref<HTMLElement>
) {
let { __demoMode = false, ...theirProps } = props
let reducerBag = useReducer(stateReducer, {
menuState: MenuStates.Closed,
__demoMode,
menuState: __demoMode ? MenuStates.Open : MenuStates.Closed,
buttonRef: createRef(),
itemsRef: createRef(),
items: [],
@@ -279,7 +294,6 @@ function MenuFn<TTag extends ElementType = typeof DEFAULT_MENU_TAG>(
[menuState, close]
)
let theirProps = props
let ourProps = { ref: menuRef }
return (
@@ -604,6 +618,7 @@ function ItemFn<TTag extends ElementType = typeof DEFAULT_ITEM_TAG>(
let itemRef = useSyncRefs(ref, internalItemRef)
useIsoMorphicEffect(() => {
if (state.__demoMode) return
if (state.menuState !== MenuStates.Open) return
if (!active) return
if (state.activationTrigger === ActivationTrigger.Pointer) return
@@ -613,6 +628,7 @@ function ItemFn<TTag extends ElementType = typeof DEFAULT_ITEM_TAG>(
})
return d.dispose
}, [
state.__demoMode,
internalItemRef,
active,
state.menuState,
@@ -63,6 +63,7 @@ enum PopoverStates {
}
interface StateDefinition {
__demoMode: boolean
popoverState: PopoverStates
buttons: MutableRefObject<Symbol[]>
@@ -100,13 +101,22 @@ let reducers: {
action: Extract<Actions, { type: P }>
) => StateDefinition
} = {
[ActionTypes.TogglePopover]: (state) => ({
...state,
popoverState: match(state.popoverState, {
[PopoverStates.Open]: PopoverStates.Closed,
[PopoverStates.Closed]: PopoverStates.Open,
}),
}),
[ActionTypes.TogglePopover]: (state) => {
let nextState = {
...state,
popoverState: match(state.popoverState, {
[PopoverStates.Open]: PopoverStates.Closed,
[PopoverStates.Closed]: PopoverStates.Open,
}),
}
/* We can turn off demo mode once we re-open the `Popover` */
if (nextState.popoverState === PopoverStates.Open) {
nextState.__demoMode = false
}
return nextState
},
[ActionTypes.ClosePopover](state) {
if (state.popoverState === PopoverStates.Closed) return state
return { ...state, popoverState: PopoverStates.Closed }
@@ -198,12 +208,20 @@ interface PopoverRenderPropArg {
): void
}
export type PopoverProps<TTag extends ElementType> = Props<TTag, PopoverRenderPropArg>
export type PopoverProps<TTag extends ElementType> = Props<
TTag,
PopoverRenderPropArg,
never,
{
__demoMode?: boolean
}
>
function PopoverFn<TTag extends ElementType = typeof DEFAULT_POPOVER_TAG>(
props: PopoverProps<TTag>,
ref: Ref<HTMLElement>
) {
let { __demoMode = false, ...theirProps } = props
let internalPopoverRef = useRef<HTMLElement | null>(null)
let popoverRef = useSyncRefs(
ref,
@@ -214,7 +232,8 @@ function PopoverFn<TTag extends ElementType = typeof DEFAULT_POPOVER_TAG>(
let buttons = useRef([])
let reducerBag = useReducer(stateReducer, {
popoverState: PopoverStates.Closed,
__demoMode,
popoverState: __demoMode ? PopoverStates.Open : PopoverStates.Closed,
buttons,
button: null,
buttonId: null,
@@ -354,7 +373,6 @@ function PopoverFn<TTag extends ElementType = typeof DEFAULT_POPOVER_TAG>(
[popoverState, close]
)
let theirProps = props
let ourProps = { ref: popoverRef }
return (
@@ -771,6 +789,7 @@ function PanelFn<TTag extends ElementType = typeof DEFAULT_PANEL_TAG>(
// Move focus within panel
useEffect(() => {
if (state.__demoMode) return
if (!focus) return
if (state.popoverState !== PopoverStates.Open) return
if (!internalPanelRef.current) return
@@ -779,7 +798,7 @@ function PanelFn<TTag extends ElementType = typeof DEFAULT_PANEL_TAG>(
if (internalPanelRef.current.contains(activeElement)) return // Already focused within Dialog
focusIn(internalPanelRef.current, Focus.First)
}, [focus, internalPanelRef, state.popoverState])
}, [state.__demoMode, focus, internalPanelRef, state.popoverState])
let slot = useMemo<PanelRenderPropArg>(
() => ({ open: state.popoverState === PopoverStates.Open, close }),