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

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

Merged
merged 2 commits into from
Apr 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/@headlessui-react/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
24 changes: 20 additions & 4 deletions packages/@headlessui-react/src/components/menu/menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ type MenuItemDataRef = MutableRefObject<{
}>

interface StateDefinition {
__demoMode: boolean
menuState: MenuStates
buttonRef: MutableRefObject<HTMLButtonElement | null>
itemsRef: MutableRefObject<HTMLDivElement | null>
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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: [],
Expand Down Expand Up @@ -279,7 +294,6 @@ function MenuFn<TTag extends ElementType = typeof DEFAULT_MENU_TAG>(
[menuState, close]
)

let theirProps = props
let ourProps = { ref: menuRef }

return (
Expand Down Expand Up @@ -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
Expand All @@ -613,6 +628,7 @@ function ItemFn<TTag extends ElementType = typeof DEFAULT_ITEM_TAG>(
})
return d.dispose
}, [
state.__demoMode,
internalItemRef,
active,
state.menuState,
Expand Down
41 changes: 30 additions & 11 deletions packages/@headlessui-react/src/components/popover/popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ enum PopoverStates {
}

interface StateDefinition {
__demoMode: boolean
popoverState: PopoverStates

buttons: MutableRefObject<Symbol[]>
Expand Down Expand Up @@ -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 }
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -354,7 +373,6 @@ function PopoverFn<TTag extends ElementType = typeof DEFAULT_POPOVER_TAG>(
[popoverState, close]
)

let theirProps = props
let ourProps = { ref: popoverRef }

return (
Expand Down Expand Up @@ -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
Expand All @@ -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 }),
Expand Down
Loading