NullVoxPopuli/ember-popperjs

feature request: provide an optional {{reference}} modifier

Closed this issue · 8 comments

Currently, the this._referenceElement always refers to the trigger element, but in practice, some cases do not fit in this assumption.

For example, consider this UI pattern:

example pattern

  1. The Trigger is the little downward triangle (with a light gray hovering background)
  2. The entire button surrounded with dark gray border is the Reference
  3. The Popover is the menu

Users can only show the popover menu by clicking the downward triangle precisely, but not the entire button because the whole button has a different interactive meaning here (that is, clicking to select/unselect)

However, we still need the entire button to be the reference element because we need to align the popover menu with the left side of the button as the whole, not the downward angle.

If developers can specify the reference element optionally, they can archive this pattern easily and quickly.

In our application, we use ember-ref-bucket to hold a reference element and pass it to the popperjs modifier (we made our popperjs modifier before, but we would like to use this addon instead).

Maybe a better way is to provide an optional {{reference}} modifier, so developers can use it to assign a custom element instead of always as the same as the trigger element.

can you provide the markup for that popover menu? it should be possible to place {{reference}} on that outer gray border. {{reference}} does not need to be the same as the trigger

and maybe I need better examples in the README 🙃

can you provide the markup for that popover menu? it should be possible to place {{reference}} on that outer gray border.

and maybe I need better examples in the README 🙃

Sure, this is our implementation (a simplified version):

{{! this div is the reference element }}
<div role="button" {{create-ref "reference"}}>
  <span>Some Text</span>

  <Menu @reference={{ref-to "reference"}} @placement="bottom-start">
    <:trigger>
      {{! this button is the trigger element }}
      <Button />
    </:trigger>

    <:content as |state|>
      <List>
        {{! here is the menu popover }}
      </List>
    </:content>
  </Menu>
</div>

<Menu /> is our version of popper.js wrapper component, since we passing the reference element individually, so we don't have to use the <Menu /> to wrap it inside.

I think if use this addon, this example could be like this:

<PopperJS as |reference trigger popover|>
  <div {{reference}}>
    <span>Some Text</span>

    <button {{trigger}}>
      ▼
    </button>
  </div>

  {{#if this.yourVisibilityIndicator}}
    <div {{popover}}>
      This is a popover!
    </div>
  {{/if}}
</PopperJS>

ah I see. I mean, so.. this is exactly what's happening today.

I'll take the first example from the README, and only change the name of the variable in the yield.

<PopperJS as |reference popover|>
  <button {{reference}} {{on "click" this.yourClickHandler}}>
    {{yield to="trigger"}}
  </button>

  {{#if this.yourVisibilityIndicator}}
    <div {{popover}}>
      This is a popover!
      {{yield to="default"}}
    </div>
  {{/if}}
</PopperJS>

and with the wrapper div, it'd look like:

<PopperJS as |reference popover|>
  <div {{reference}}>
    <button {{on "click" this.yourClickHandler}}>
      {{yield to="trigger"}}
    </button>
  </div>

  {{#if this.yourVisibilityIndicator}}
    <div {{popover}}>
      This is a popover!
      {{yield to="default"}}
    </div>
  {{/if}}
</PopperJS>

Does that make sense?

I'd gladly accept a PR clarifying this in the README.
The arguments yielded by the <PopperJS> component are modifiers that have nothing to do with actually showing or hiding the popover (as trigger kind of implies)

for your example, I think that would look like this with ember-popperjs:

<PopperJS @placement="bottom-start" as |reference popover|>
  <div role="button" {{reference}}>
    <span>Some Text</span>

    <Menu >
      <:trigger>
        {{! this button is the trigger element }}
        <Button />
      </:trigger>

      <:content as |state|>
        <List {{popover}}>
          {{! here is the menu popover }}
        </List>
      </:content>
    </Menu>
  </div>
</PopperJS>

for your example, I think that would look like this with ember-popperjs:

<PopperJS @placement="bottom-start" as |reference popover|>
  <div role="button" {{reference}}>
    <span>Some Text</span>

    <Menu >
      <:trigger>
        {{! this button is the trigger element }}
        <Button />
      </:trigger>

      <:content as |state|>
        <List {{popover}}>
          {{! here is the menu popover }}
        </List>
      </:content>
    </Menu>
  </div>
</PopperJS>

Sort of, only if ember-popperjs provides the {{reference}} modifier, we don't need the <Menu /> component anymore, since it also wraps the popper.js.

but that first yielded arg is the reference modifier

but that first yielded arg is the reference modifier

Yes, this is what I mean: if ember-popperjs provides the {{reference}} modifier (as your example shows above), then we could get rid of our <Menu /> component, I like that idea, hope it becomes real soon, thanks.

that's what's already provided. The thing that this addon won't do though is providing a way to manage hide/show of the popover -- too many ways to do that (or animate it! <3)

thanks for the discussion! let me know if anything is still unclear.