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

Composite: two-dimensional arrow navigation with MenuButtons #3768

Open
oandregal opened this issue May 6, 2024 · 9 comments · May be fixed by #3799
Open

Composite: two-dimensional arrow navigation with MenuButtons #3768

oandregal opened this issue May 6, 2024 · 9 comments · May be fixed by #3799
Assignees
Labels

Comments

@oandregal
Copy link

oandregal commented May 6, 2024

Updated Stackblitz repro: https://stackblitz.com/edit/vitejs-vite-p27qhy?file=src%2FApp.tsx&terminal=dev

Motivation

I'm trying to use Composite in WordPress/Gutenberg to create a two-dimensional arrow navigation experience. This is the PR where I'm working on it.

I'm having trouble making it work when it contains MenuButtons. This is a Stackblitz (outdated) demonstrating how the interaction doesn't work as expected:

Usage example

      <Ariakit.CompositeProvider>
        <Ariakit.Composite>
          <Ariakit.CompositeRow>
            <Ariakit.CompositeItem render={<button>Button</button>} />

            <Ariakit.CompositeItem
              render={
                <Ariakit.MenuProvider>
                  <Ariakit.MenuButton>Menu</Ariakit.MenuButton>{' '}
                  <Ariakit.Menu>
                    <Ariakit.MenuItem>Hello</Ariakit.MenuItem>
                  </Ariakit.Menu>
                </Ariakit.MenuProvider>
              }
            />

            <Ariakit.CompositeItem render={<button>Button</button>} />
          </Ariakit.CompositeRow>

          <Ariakit.CompositeRow>
            <Ariakit.CompositeItem render={<button>Button</button>} />

            <Ariakit.CompositeItem
              render={
                <Ariakit.MenuProvider>
                  <Ariakit.MenuButton>Menu</Ariakit.MenuButton>{' '}
                  <Ariakit.Menu>
                    <Ariakit.MenuItem>Hello</Ariakit.MenuItem>
                  </Ariakit.Menu>
                </Ariakit.MenuProvider>
              }
            />

            <Ariakit.CompositeItem render={<button>Button</button>} />
          </Ariakit.CompositeRow>
        </Ariakit.Composite>
      </Ariakit.CompositeProvider>

I'm not sure if I'm missing something or it just doesn't work with MenuButtons.

@DaniGuardiola
Copy link
Contributor

DaniGuardiola commented May 6, 2024

@diegohaz I want to contribute a fix to this, if that's what makes sense to do. One observation here:

There are some tricky interaction conflicts. For example, pressing arrow down opens a menu, but in a 2d composite it moves focus to the item below. I'm not sure how this should be handled.

@oandregal
Copy link
Author

oandregal commented May 6, 2024

In the example I shared, the menus are not reachable via arrow keys:

Gravacao.do.ecra.2024-05-06.as.13.34.49.mov

@DaniGuardiola
Copy link
Contributor

@oandregal I have added an updated repro to the description, as yours wasn't entirely correct (the element that the composite item needs to be "merged" with is MenuButton, not MenuProvider). Still doesn't work though!

I added two examples: CompositeItem rendered as MenuButton and the reverse case.

@DaniGuardiola
Copy link
Contributor

Digging deeper into this, it seems like this is a symptom of the composite item that's merged with the menu button not being registered in the composite collection store. Still trying to find the reason for this though.

@diegohaz
Copy link
Member

diegohaz commented May 7, 2024

Try to pass the store directly to CompositeItem instead of relying on CompositeProvider.

@DaniGuardiola
Copy link
Contributor

Isn't this somewhat similar to what @jjenzz has discussed multiple times in the context of Radix UI primitives regarding context scoping? @diegohaz

@diegohaz
Copy link
Member

diegohaz commented May 7, 2024

We have scoping on most components. We just don't check it on CompositeItem because it's too low level and most of the time people use it with the composite store directly rather than CompositeProvider.

@DaniGuardiola
Copy link
Contributor

The workaround of passing the store explicitly does indeed work: https://stackblitz.com/edit/vitejs-vite-kw6x9j?file=src%2FApp.tsx

One important detail is that the "topmost" component should be the CompositeItem (e.g. <CompositeItem render={<MenuButton />}), so that the CompositeItem has precedence in interactions like arrow down. See this demo (same sandbox I just linked) where only the middle row one is like this and properly works.

Kapture.2024-05-07.at.12.35.29.mp4

@diegohaz I feel like scoping should work here too, this is a valid use case and this behavior was unexpected. Do you agree, and if so, can you point me to an example of how it is implemented so I can contribute it for CompositeItem?

@diegohaz
Copy link
Member

diegohaz commented May 8, 2024

@DaniGuardiola Sure, I think this should be fixed in CompositeItem. Usually, using useCompositeProviderContext instead of just useCompositeContext is enough. I don't have my computer right now, but I believe MenuButton implements this.

@DaniGuardiola DaniGuardiola linked a pull request May 17, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants