Skip to content

Commit

Permalink
Apply suggestions from code review
Browse files Browse the repository at this point in the history
Co-authored-by: Kristin Bradley <kristin.bradley@hashicorp.com>
Co-authored-by: Melanie Sumner <melanie@hashicorp.com>
  • Loading branch information
3 people committed May 9, 2024
1 parent 77fb8c8 commit 1956a09
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
Controls if the popover should be rendered initially opened.
<br />
<br />
_Notice: in this case the popover can't be dismissed via `esc` or `click outside` until the end user has interacted with it (it's in a "manual" state)._
_Notice: in this case, the popover can't be dismissed via `esc` or `click outside` until the end user has interacted with it (it's in a "manual" state)._
</C.Property>
<C.Property @name="enableSoftEvents" @type="boolean" @default="false" @values={{array "true" "false"}}>
Assigns "soft" events listeners (`mouseEnter/Leave` + `focusIn/Out`) to the toggle, to control the visibility of the popover content.
Assigns "soft" event listeners (`mouseEnter/Leave` + `focusIn/Out`) to the toggle, to control the visibility of the popover content.
</C.Property>
<C.Property @name="enableClickEvents" @type="boolean" @default="false" @values={{array "true" "false"}}>
Assigns a "click" event listener (`onClick`) to the toggle, to control the visibility of the popover content.
Assigns a click event listener (`onClick`) to the toggle, to control the visibility of the popover content.
</C.Property>
<C.Property @name="onOpen" @type="function">
A callback function invoked when the popover is opened (if provided).
Expand All @@ -20,16 +20,16 @@
Provides a callback function invoked when the popover is closed (if provided).
</C.Property>
<C.Property @name="[PP].setupPrimitiveContainer" @type="modifier">
Provides a modifiers that needs to be applied to the container of the toggle and popover elements.
Provides a modifier that needs to be applied to the container of the toggle and popover elements.
</C.Property>
<C.Property @name="[PP].setupPrimitiveToggle" @type="modifier">
Provides a modifiers that needs to be applied to the toggle element.
Provides a modifier that needs to be applied to the toggle element.
<br />
<br />
_⚠️ Important: the HTML element must be a `<button>` for accessibility conformance. If not, the component will throw an errow._
_⚠️ Important: The HTML element must be a `<button>` for accessibility conformance. If not, the component will throw an error._
</C.Property>
<C.Property @name="[PP].setupPrimitivePopover" @type="modifier">
Provides a modifiers that needs to be applied to the popover element. It accepts an `anchoredPositionOptions` object as "named" argument, with different keys corresponding to different options (see below). These options are forwarded to underlying modifier `hds-anchored-position`, and in turn are passed down to the [Floating UI](https://floating-ui.com) library.
Provides a modifier that needs to be applied to the popover element. It accepts an `anchoredPositionOptions` object as "named" argument, with different keys corresponding to different options (see below). These options are forwarded to the underlying `hds-anchored-position` modifier, and in turn are passed down to the [Floating UI](https://floating-ui.com) library.
<Doc::ComponentApi as |C|>
<C.Property @name="anchoredPositionOptions.placement" @type="enum" @values={{array "top" "top-start" "top-end" "right" "right-start" "right-end" "bottom" "bottom-start" "bottom-end" "left" "left-start" "left-end"}} @default="bottom">
Placement for the preferred starting position of the popover relative to the toggle element.
Expand All @@ -38,22 +38,22 @@
_Notice: if `@enableCollision` is set, the popover will automatically shift position to remain visible when near the edges of the screen regardless of the starting placement._
</C.Property>
<C.Property @name="anchoredPositionOptions.strategy" @type="enum" @values={{array "absolute" "fixed"}} @default="absolute">
Controls how the layout of the popover is applied using the CSS `position` property. Since the component uses the [native web Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) which promotes the popover to the [top layer](https://developer.mozilla.org/en-US/docs/Glossary/Top_layer), there is no need to use the `fixed` position to avoid stacking context conflicts, but we leave the option open for edge cases in which this is needed anyway.
Controls how the layout of the popover is applied using the CSS `position` property. Since the component uses the [native web Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) which promotes the popover to the [top layer](https://developer.mozilla.org/en-US/docs/Glossary/Top_layer), there is no need to use the `fixed` position to avoid stacking context conflicts, but we leave the option open for edge cases in which this is needed.
<br />
<br />
_Notice: if the position/strategy is set to `fixed`, the rendering of the popover becomes jagged when the page is scrolled._
</C.Property>
<C.Property @name="anchoredPositionOptions.offsetOptions" @type="number|object" @default="0">
A number that represents the distance between the popover element and the toggle element. An object can also be passed, which enables to individually configure different axis.
A number that represents the distance between the popover element and the toggle element. An object can also be passed, which enables individually configuring different axes.
<br />
<br />
For details see: [Floating UI > Offset > Options](https://floating-ui.com/docs/offset#options).
<br />
<br />
_Notice: this options can be used to control the relative position of the arrow in relation to the toggle._
_Notice: These options can be used to control the relative position of the arrow in relation to the toggle._
</C.Property>
<C.Property @name="anchoredPositionOptions.enableCollisionDetection" @type="boolean|string" @values={{array "true" "false" "flip" "shift" "auto"}} @default="false">
This property controls if the popover should automatically adapt its position to remain visible when near the edges of the screen. It can be enabled for both axes setting it to `true`, or a single axes can be chosen passing the `flip` or `shift` value. If set to `auto` it will automatically place the popover in the position where there's more space available, but in this case it will ignore the `placement` value.
This property controls whether the popover should automatically adapt its position to remain visible when near the edges of the screen. It can be enabled for both axes by setting it to `true`, or a single axes can be chosen by passing either the `flip` or `shift` values. If set to `auto`, it will automatically place the popover in the position where there's more space available, but in this case, it will ignore the `placement` value.
<br />
<br />
For an overview of how collision detection works and is controlled see: [Floating UI > Tutorial](https://floating-ui.com/docs/tutorial), [Floating UI > Flip](https://floating-ui.com/docs/flip), [Floating UI > Shift](https://floating-ui.com/docs/shift), and [Floating UI > autoPlacement](https://floating-ui.com/docs/autoPlacement).
Expand All @@ -71,7 +71,7 @@
For details about how this middleware works (and its options) see: [Floating UI > Shift](https://floating-ui.com/docs/shift)
</C.Property>
<C.Property @name="anchoredPositionOptions.autoPlacementOptions" @type="object" @default="{ padding: 8 }">
The options for the `autoPlacement` middleware in Floating UI, that controls the automatic repositioning of the popover based on the most space available.
The options for the `autoPlacement` middleware in Floating UI that controls the automatic repositioning of the popover based on the most space available.
<br />
<br />
For details about how this middleware works (and its options) see: [Floating UI > Shift](https://floating-ui.com/docs/autoPlacement)
Expand All @@ -83,13 +83,13 @@
For details about how these functions work in the context of the library (and how to define custom ones) see: [Floating UI > Middleware](https://floating-ui.com/docs/middleware) and [Floating UI > Custom middleware](https://floating-ui.com/docs/computePosition#custom).
</C.Property>
<C.Property @name="anchoredPositionOptions.arrowElement" @type="DOM element">
A reference to the DOM element that represents the "arrow" decoration, if it exists, so it position can be updated accordingly to the popover position in relation to the toggle anchor.
A reference to the DOM element that represents the "arrow" decoration, if it exists, that allows its position to be updated according to the popover position in relation to the toggle anchor.
<br />
<br />
For details see: [Floating UI > Arrow](https://floating-ui.com/docs/arrow)
</C.Property>
<C.Property @name="anchoredPositionOptions.arrowElement" @type="string">
A DOM selector to the "arrow", if it's not possible to provide directly a reference to the DOM element (internally it's then converted to the `arrowElement` option).
A DOM selector for the "arrow", if it's not possible to provide a direct reference to the DOM element (internally it's then converted to the `arrowElement` option).
</C.Property>
<C.Property @name="anchoredPositionOptions.arrowPadding" @type="number">
The padding between the arrow and the edges of the popover element.
Expand All @@ -103,10 +103,10 @@
Provides a reference to the toggle DOM element element (container).
</C.Property>
<C.Property @name="[PP].arrowElement" @type="DOM element">
Provides a reference to the arrow DOM element element (if provided to the `setupPrimitivePopover` modifier through the `anchoredPositionOptions` object).
Provides a reference to the arrow DOM element (if provided to the `setupPrimitivePopover` modifier through the `anchoredPositionOptions` object).
</C.Property>
<C.Property @name="[PP].popoverElement" @type="DOM element">
A reference to the popover DOM element element (container).
A reference to the popover DOM element (container).
</C.Property>
<C.Property @name="[PP].showPopover" @type="function">
Hook into this function to programmatically show the popover.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,31 @@ This component is intended only for internal Helios use. If you need to use it,

## How to use this component

The `PopoverPrimitive` is a **headless component** that associates a "toggle" element with a "popover" element (both elements act as containers). "Soft" (hover/focus) or "click" event listeners can be assigned to the "toggle", and when triggered they toggle the visibility of the "popover".
The `PopoverPrimitive` is a **headless component** that associates a "toggle" element with a "popover" element (both elements act as containers). "Soft" (hover/focus) or click event listeners can be assigned to the toggle, and when triggered they toggle the visibility of the popover.

When the "popover" is visible, it can be closed in various ways: toggling via the "soft" or "click" events, clicking outside of the popover, or via the `esc` key.
When the popover is visible, it can be closed in various ways: toggling via the "soft" or click events, clicking outside of the popover, or via the `esc` key.

Under the hood the component uses the [native web Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) to promote the popover content to the [top layer](https://developer.mozilla.org/en-US/docs/Glossary/Top_layer). This solves the issues related to stacking contexts and provides the "light dismiss" (click outside / `esc` key) out of the box.
Under the hood, the component uses the [native web Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) to promote the popover content to the [top layer](https://developer.mozilla.org/en-US/docs/Glossary/Top_layer). This solves issues related to stacking contexts and provides "light dismiss" functionality (click outside / `esc` key) out of the box.

The primitive also uses the third-party library [Floating UI](https://floating-ui.com/) to provide the anchoring and automatic positioning/collision detection functionality.
The primitive also uses the [Floating UI](https://floating-ui.com/) third-party library to provide anchoring as well as automatic positioning and collision detection functionality.

For older browsers (in particular Firefox 124 and older) that don't support the Popover API, it uses a [Popover Polyfill](https://github.com/oddbird/popover-polyfill) library to emulate the native behaviour.

!!! Insight

**Learn more**

- For details about the native web Popover API see: [MDN / Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API)
- For details about the Floating UI third-party library see: [Floating UI](https://floating-ui.com/)
- For details about the native web Popover API, see: [MDN / Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API)
- For details about the Floating UI third-party library, see: [Floating UI](https://floating-ui.com/)

For details about the Floating UI third-party library see: [Floating UI](https://floating-ui.com/)

!!!

The internal logic and APIs of this component are quite complex, it's impossible to describe everything in detail. Below we provide a few basic examples, but if you need more in-depth knowledge of how the primitive can be configured and used we suggest looking at the source code of the component itself, as well as the `hds-anchored-position` modifier, which is a custom wrapper around the Floating UI library.
The internal logic and APIs of this component are quite complex; it's impossible to describe everything in detail. Below we provide a few basic examples, but if you need more in-depth knowledge of how the primitive can be configured and used, we suggest looking at the source code of the component itself as well as the `hds-anchored-position` modifier, which is a custom wrapper around the Floating UI library.

### Basic invocation

The basic invocation of this primitive sees three different modifiers (`setupPrimitiveContainer`, `setupPrimitiveToggle`, and `setupPrimitivePopover`) applied to three distinct elements (they can be HTML elements or Ember components):
The basic invocation of this primitive uses three different modifiers (`setupPrimitiveContainer`, `setupPrimitiveToggle`, and `setupPrimitivePopover`) applied to three distinct elements (which can be either HTML elements or Ember components):

```handlebars{data-execute=false}
<Hds::PopoverPrimitive as |PP|>
Expand All @@ -41,7 +40,7 @@ The basic invocation of this primitive sees three different modifiers (`setupPri
</Hds::PopoverPrimitive>
```

The primitive itself doesn't provide any styling to the container, toggle, popover (and arrow) elements, and doesn't generate any extra HTML beyond the one yielded to the component itself. It provides only the popover, anchoring, and collision detection functionalities to the elements that the "setup" modifiers are applied to.
The primitive itself doesn't provide any styling to the container, toggle, popover (and arrow) elements, and doesn't generate any extra HTML beyond that which is yielded to the component itself. It provides only the popover, anchoring, and collision detection functionalities to the elements that the "setup" modifiers are applied to.

### Event listeners

Expand All @@ -56,7 +55,7 @@ The visibility of the popover can be toggled via "soft" event listeners (hover/f
</Hds::PopoverPrimitive>
```

_Notice: from a purely technical standpoint, the events are `mouseEnter/Leave` and `focusIn/Out`._
_Notice: The actual technical events used are `mouseEnter/Leave` and `focusIn/Out`._

Alternatively, the toggle behaviour can be enabled via "click" events:

Expand Down Expand Up @@ -107,11 +106,11 @@ The collision detection logic can be controlled using the `enableCollisionDetect
</Hds::PopoverPrimitive>
```

For details about how the collision detection works refer to the [Floating UI > Tutorial](https://floating-ui.com/docs/tutorial).
For details about how the collision detection works, refer to the [Floating UI > Tutorial](https://floating-ui.com/docs/tutorial).

### With an arrow

It is possible to account for an arrow element in the positioning of the popover, if an `arrowSelector` (or directly an `arrowElement` reference) if provided to the `anchoredPositionOptions`:
It is possible to account for an arrow element in the positioning of the popover, if an `arrowSelector` (or directly an `arrowElement` reference) is provided to the `anchoredPositionOptions`:

```handlebars{data-execute=false}
<Hds::PopoverPrimitive as |PP|>
Expand All @@ -130,4 +129,4 @@ It is possible to account for an arrow element in the positioning of the popover

### Other `anchoredPositionOptions`

There are more possible options and configurations that can be provided to the popover via the `@anchoredPositionOptions` argument. Refer to the [Component API](#component-api) section below for more details, and to the code of the `hds-anchored-position` modifier for in depth understanding of how this modifier works under the hood.
Other options and configurations can be provided to the popover via the `@anchoredPositionOptions` argument. Refer to the [Component API](#component-api) section below for more details, and to the code of the `hds-anchored-position` modifier for an in-depth understanding of how this modifier works.
3 changes: 1 addition & 2 deletions website/tests/acceptance/utilities/popover-primitive-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { module, test } from 'qunit';
import { visit, currentURL } from '@ember/test-helpers';
import { setupApplicationTest } from 'website/tests/helpers';
import { a11yAudit } from 'ember-a11y-testing/test-support';
import { globalAxeOptions } from 'website/tests/a11y-helper';

module('Acceptance | utilities/popover-primitive', function (hooks) {
setupApplicationTest(hooks);
Expand All @@ -20,7 +19,7 @@ module('Acceptance | utilities/popover-primitive', function (hooks) {

test('utilities/popover-primitive passes a11y automated checks', async function (assert) {
await visit('/utilities/popover-primitive');
await a11yAudit(globalAxeOptions);
await a11yAudit();
assert.ok(true, 'a11y automation audit passed');
});
});

0 comments on commit 1956a09

Please sign in to comment.