OpenCloseMixin

Tracks the open/close state of a component

Overview

Purpose: tracks the opened/closed state of an element with open/close semantics, such as a Dialog, Drawer, Popup, or Toast. It allows for the possibility that the open/close operations are asynchronous.

This mixin works in the middle of the Elix render pipeline:

events → methodssetState → updates → render DOM → post-render

Expects the component to provide:

Provides the component with:

  • state.opened member that is true if the element is open, false if closed.
  • opened property that reflects the internal state of state.opened.
  • closed property that is the inverse of opened.
  • toggle method that toggles the opened/closed state.
  • open method that opens the element.
  • close method that closes the element.
  • state.openCloseEffects member that defaults to true if this mixin is used in combination with TransitionEffectMixin.
  • closeFinished property. By default, this is the same value as the close property. If state.openCloseEffects (see above) is true, then closeFinished is true only after the close effect has finished (reached the after phase). See asynchronous effects, below.

Usage

import OpenCloseMixin from 'elix/src/OpenCloseMixin.js';
class MyElement extends OpenCloseMixin(HTMLElement) {}

You can use OpenCloseMixin to provide any component that conceptually opens and closes with a consistent open/close API. This can make things easier for developers to use your component.

Using OpenCloseMixin allows makes it easy to take advantage of related Elix mixins, including DialogModalityMixin, OverlayMixin, PopupModalityMixin, and TransitionEffectMixin. However, OpenCloseMixin can be used for components which aren't overlays, such as components that expand or open in place.

Example

An overlay is one type of component that can be opened and closed. When open, they appear on top of other elements:

Here's a dialog.

This paragraph has a z-index, but should appear behind the dialog. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse sed lorem scelerisque, blandit libero vitae, dapibus nisl. Sed turpis diam, placerat a feugiat sed, maximus at velit. Ut sit amet semper sapien. Donec vitae leo ex. Duis eget quam sed metus tempor lobortis eget feugiat elit. Cras varius, arcu ac commodo tincidunt, lectus dui convallis nunc, quis maximus nisl erat ac mi. Phasellus et velit diam.

Demo: A Dialog opens on top of other elements

A component might also choose to interpret the semantics of opening and closing as expanding or collapsing in place, as in ExpandablePanel:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Demo: An ExpandablePanel opens in place

Use of OpenCloseMixin in these situations allows for a consistent open/close API.

Asynchronous open/close effects

Many components that open and close do so with asynchronous transitional effects: fading in, sliding in, etc., when opened, then fading out or sliding out when closed. Such effects can add considerable complexity to an element's state, making it hard to define exactly when a component has "opened" or "closed".

Drawer elements go here...
Demo: A Drawer has asynchronous open/close transition effects

To support such effects, OpenCloseMixin interoperates with TransitionEffectMixin. When used in combination, OpenCloseMixin will:

  • Assume an element is completely closed by default. The default state.effect is "close", and the default state.effectPhase is "after".
  • Define state.openCloseEffects to be true by default — i.e., that the element wants to use transition effects for open/close operations.
  • Trigger the "open" effect when the element is opened by any means (the open or toggle methods, or setting opened to true). This sets state.effect to "open" and the phase to "before". TransitionEffectMixin will then manage the remaining phases of the effect.
  • Conversely, trigger the "close" effect when the element is closed by any means.

API

Used by classes AlertDialog, ComboBox, Dialog, Drawer, DropdownList, ExpandablePanel, ExpandableSection, HamburgerMenuButton, ListComboBox, MenuButton, Overlay, Popup, PopupButton, PopupSource, and Toast.

close(closeResult) method

Close the component (if not already closed).

Some components like AlertDialog want to indicate why or how they were closed. To support such scenarios, you can supply a value to the optional closeResult parameter. This closeResult will be made available in the whenClosed promise and the state.closeResult member.

Parameters:

  • closeResult: objectan indication of how or why the element closed

closed property

True if the element is currently closed.

Type: boolean

closed event

Raised when the component closes.

closeFinished property

True if the element has completely closed.

For components not using asynchronous open/close effects, this property returns the same value as the closed property. For elements that have a true value of state.openCloseEffects (e.g., elements using TransitionEffectMixin), this property returns true only if state.effect is "close" and state.effectPhase is "after".

Type: boolean

open() method

Open the element (if not already opened).

opened property

True if the element is currently opened.

Type: boolean

opened event

Raised when the component opens.

opened-changed event

Raised when the opened/closed state of the component changes.

toggle(opened) method

Toggle the open/close state of the element.

Parameters:

  • opened: booleantrue if the element should be opened, false if closed.

whenClosed() method

This method can be used as an alternative to listening to the "opened-changed" event, particularly in situations where you want to only handle the next time the component is closed.

Returns: Promise A promise that resolves when the element has completely closed, including the completion of any asynchronous opening effect.