consul/ui/packages/consul-ui/app/components/disclosure
Michael Klein 03a1a86dfe
ui: chore - upgrade ember and friends (#14518)
* v3.20.2...v3.24.0

* Fix handle undefined outlet in route component

* Don't use template helper for optional modal.open

Using the optional-helper here will trigger a computation
in the same runloop error. This is because we are setting
the `modal`-property when the `<Ref>` component gets
rendered which will update the `this.modal`-property which
will then recompute the `optional`-helper leading to this
error.

Instead we will create an action that will call the `open`-method
on the modal when it is defined. This gets rid of the double
computation error as we will not access the modal property
twice in the same runloop when `modal` is getting set.

* Fix - fn needs to be passed function tab-nav

We create functions in the component file instead
so that fn-helper stops complaining about the
need to pass a function.

* Update ember-exam to 6.1 version

"Makes it compatible" with ember-qunit v5

* scheduleOnce setMaxHeight paged-collection

We need to schedule to get around double-computation error.

* Fix - model.data is removed from ember-data

This has been private API all along - we need to
work around the removal.

Reference: https://github.com/emberjs/data/pull/7338/files#diff-9a8746fc5c86fd57e6122f00fef3155f76f0f3003a24b53fb7c4621d95dcd9bfL1310

* Fix `propContains` instead of `deepEqual` policy

Recent model.data works differently than iterating attributes.
We use `propContains` instead of `deepEqual`. We are only
interested in the properties we assert against and match
the previous behavior with this change.

* Fix `propContains` instead of `deepEqual` token

* Better handling single-records repo test-helper

`model.data` has been removed we need to handle proxies and
model instances differently.

* Fix remaining repository tests with propContains

We don't want to match entire objects - we don't care
about properties we haven't defined in the assertion.

* Don't use template helper for optional modal.open

Using a template helper will give us a recomputation error -
we work around it by creating an explicit action on
the component instead.

* Await `I $verb the $pageObject object` step

* Fix no more customization ember-can

No need to customize, the helper handles destruction
fine on its own.

* Fix - don't pass `optional` functions to fn

We will declare the functions on the component instead.
This gives us the same behavior but no error from
`fn`, which expects a function to be passed.

* Fix - handle `undefined` state on validate modifier

StateChart can yield out an undefined `state` we need
to handle that in the validate modifier

* Fix linting errors tests directory

* Warn / turn off new ember linting issues

We will tackle them one by one and don't want to
autofix issues that could be dangerous to auto-fix.

* Auto-fix linting issues

* More linting configuration

* Fix remaining linting issues

* Fix linting issues new files after rebase

* ui: Remove ember-cli-uglify config now we are using terser (#14574)

Co-authored-by: John Cowen <johncowen@users.noreply.github.com>
2022-09-15 09:43:17 +01:00
..
action ui: Disclosure Component amends plus DisclosureMenu Component (#12304) 2022-02-11 14:11:16 +00:00
details ui: Disclosure Component amends plus DisclosureMenu Component (#12304) 2022-02-11 14:11:16 +00:00
README.mdx ui: Start using mermaid state diagrams in our docs (#12350) 2022-02-17 14:57:14 +00:00
index.hbs ui: Disclosure Component amends plus DisclosureMenu Component (#12304) 2022-02-11 14:11:16 +00:00
index.js ui: chore - upgrade ember and friends (#14518) 2022-09-15 09:43:17 +01:00

README.mdx

# Disclosure

A renderless component which can be used to implement an aria Disclosure pattern.

The disclosure exports an Action component already configured for use as a
clickable action. But if you want to contruct your own trigger, disclosure has
all the properties to enable you to do so.

You should make use of the `disclosure.Details` property in order control the
disclosure of the disclosure's content. By default it will automatically do
this for you. But if you need to control this yourself you can make use of the
`@auto` argument (see below for details).

You can use multiple `Details` components which lets you control multiple
areas with a single trigger/button.

Clicking outside will not close the disclosure by default, if you require this
functionality please combine with our `{{on-outside 'click'}}` modifier (see example).

By default, there are no aria attributes that you need to add or think about
as a consumer of the component, but you **should** make use of the
`details.id` property to set the `id=""` on the DOM element you are
disclosing. Every `Details` component has its `id` added to the `Action`
`aria-controls` attribute by default so you don't need to do this yourself if
using the `Details` component.

```hbs preview-template
<Disclosure as |disclosure|>
  <disclosure.Action
    {{on-outside 'click' disclosure.close}}
    {{on 'click' disclosure.toggle}}
  >
    {{if disclosure.expanded "Close" "Open"}}
  </disclosure.Action>
  <disclosure.Details as |details|>
    <p
      id={{details.id}}
    >
      Disclose Me!
    </p>
  </disclosure.Details>
</Disclosure>
```

You can also use multiple Details components for a single Discloure Action component to control multiple areas.

```hbs preview-template
<Disclosure as |disclosure|>
  <disclosure.Action
    {{on-outside 'click' disclosure.close}}
    {{on 'click' disclosure.toggle}}
  >
    {{if disclosure.expanded "Close" "Open"}}
  </disclosure.Action>
  <disclosure.Details as |details|>
    <p
      id={{details.id}}
    >
      Disclose Me!
    </p>
  </disclosure.Details>
  <disclosure.Details as |details|>
    <p
      id={{details.id}}
    >
      Disclose Me also!
    </p>
  </disclosure.Details>
</Disclosure>
```

Or use two buttons/Actions to control one Detail (or multiple Details).

```hbs preview-template
<Disclosure as |disclosure|>
  <div
    {{on-outside 'click' disclosure.close}}
  >
    <disclosure.Action
      {{on 'click' disclosure.toggle}}
    >
      {{if disclosure.expanded "1 Close" "1 Open"}}
    </disclosure.Action>
    <disclosure.Action
      {{on 'click' disclosure.toggle}}
    >
      {{if disclosure.expanded "2 Close" "2 Open"}}
    </disclosure.Action>
    <disclosure.Details as |details|>
      <p
        id={{details.id}}
      >
        Disclose Me!
      </p>
    </disclosure.Details>
  </div>
</Disclosure>
```

If you don't want to use the automatic hiding/showing (and therefore removal from the DOM) of the Details component, you can pass a `@auto={{false}}` argument to the Details component, which allows you to either specify a Handlebars conditional yourself or use CSS to hide/show the content to be disclosed.

**Please note:** We use a `style` attribute here just for illustrative purposes, you should consider using a `class` attribute instead if you want to use CSS for disclosure.

```hbs preview-template
<Disclosure as |disclosure|>
  <disclosure.Action
    {{on-outside 'click' disclosure.close}}
    {{on 'click' disclosure.toggle}}
  >
    {{if disclosure.expanded "Close" "Open"}}
  </disclosure.Action>
  <disclosure.Details
    @auto={{false}}
  as |details|>
    {{#if details.expanded}}
      <p
        id={{details.id}}
      >
        Disclose Me with a hbs conditional!
      </p>
    {{/if}}
  </disclosure.Details>
  <disclosure.Details
    @auto={{false}}
  as |details|>
      <p
        id={{details.id}}
        aria-hidden={{if (not details.expanded) 'false'}}
        style={{style-map
          (array 'display' (if (not details.expanded) 'none'))
        }}
      >
        Disclose Me via CSS!
      </p>
  </disclosure.Details>
</Disclosure>
```

By making use of `@auto={{false}}` and hand-rolling your show/hide logic you
can use disclosure to implement slightly more complex UI.

```hbs preview-template
<Disclosure as |disclosure|>
  <disclosure.Action
    {{on-outside 'click' disclosure.close}}
    {{on 'click' disclosure.toggle}}
  >
    {{if disclosure.expanded "Close" "Open"}}
  </disclosure.Action>
  <disclosure.Details
  as |details|>
      <p
        id={{details.id}}
      >
        Disclose Me!
      </p>
  </disclosure.Details>
  <disclosure.Details
    @auto={{false}}
  as |details|>
    {{#if (not details.expanded)}}
      <p
        id={{details.id}}
      >
        Disclose Me by default but hide when the other details is disclosed!
      </p>
    {{/if}}
  </disclosure.Details>
</Disclosure>
```

## Arguments

| Argument | Type | Default | Description |
| --- | --- | --- | --- |
| `expanded` | `Boolean` | false | The _initial_ state of the disclosure. Please note: this is the _initial_ state only, please use the `disclosure.open` and `disclosure.close` for controling the state. |

## Exported API

| Name | Type | Description |
| --- | --- | --- |
| `Action` | `GlimmerComponent` | A contextual '<Action />' component with aria attributes correctly applied, please note you still need to add an 'on' modifier here so you can control whether it opens on click/hover etc |
| `Details` | `GlimmerComponent` | A contextual '<Action />' component with aria attributes correctly applied, please note you still need to add an 'on' modifier here so you can control whether it opens on click/hover etc |
| `open` | `Function` | Open the disclosure if its not already open |
| `close` | `Function` | Close the disclosure if its not already closed |
| `toggle` | `Function` | Toggle the open/close state of the disclosure |
| `expanded` | `Boolean` | Whether the disclosure is 'expanded' or not |
| `event` | `Boolean` | The event used to change the state of the disclosure |
| `button` | `string` | A unique id reference to reference the an Action with if required for a11y reasons |
| `controls` | `string` | An id to use on the panel for the disclosure |


### disclosure.Action

An `<Action />` component with the correct aria attributes added.

### disclosure.Details

#### Arguments

| Argument | Type | Default | Description |
| --- | --- | --- | --- |
| `auto` | `Boolean` | true | Whether to automatically control the disclosure of the details component. Set to false to control this yourself. Please be aware of using `aria-hidden` if using CSS to control the visibility of disclosure (see examples above). |

#### Exported API

| Name | Type | Description |
| --- | --- | --- |
| `id` | `String` | A unique id which you **should** (for aria reasons) use for the root DOM element you are controlling with the disclosure |
| `expanded` | `Boolean` | An alias of `disclosure.expanded`. Whether the disclosure is 'expanded' or not. If disclosure of the `Details` is controlled via CSS you **should** use this to set/unset `aria-hidden` |

## Internal States

Opened and closed states of the Disclosure are managed internally by a simple boolean state machine:

```mermaid
stateDiagram-v2
    [*] --> false
    true --> false: TOGGLE
    true --> false: FALSE
    false --> true: TOGGLE
    false --> true: TRUE
```

which in the context of the Disclosure component is better represented via:

```mermaid
stateDiagram-v2
    [*] --> closed
    opened --> closed: TOGGLE
    opened --> closed: CLOSE
    closed --> opened: TOGGLE
    closed --> opened: OPEN
```

## See

- [Component Source Code](./index.js)
- [Template Source Code](./index.hbs)

---