Repository: wagtail/wagtail
File: client/src/controllers/RevealController.ts (TypeScript)

Code before:
    }

    if (isInitial) return;
    // If we have known toggles, dispatch on those buttons
    toggles.forEach((target) => {
      this.dispatch('toggled', {
        cancelable: false,
        detail: {
          closed: shouldClose,
        },
        target,
      });
    });
  }

  close() {
    this.closedValue = true;
    this.stored = false;
  }

  open() {
    this.closedValue = false;
    this.stored = true;
  }

  peek() {
    if (this.closedValue) {
      this.peekingValue = true;
      this.open();
    }
  }

  toggle() {
    if (this.peekingValue) {
      this.peekingValue = false;
      // if peeking and toggle clicked, is already open
      // visually set the icon to the opened variant so it can be closed.
      this.updateToggleIcon(false);
      return;
    }
    this.closedValue = !this.closedValue;
  }

  /**
   * Collects all toggles, those controlled by this controller and any external
   * that have an aria-controls references to any content target elements.
   */
  get toggles() {
    const toggles = this.contentTargets
      .map((content) => content.id)
      .flatMap((id) =>

Review comment (bug):
This can cause issues as we have a 'peek' mode and a 'fixed' mode, open/close gets called in both.

This means we will be saving the storage state when the user is just 'peeking', and potentially thrashing the local storage in the meantime + causing an edge case if the user refreshes while peeking it will save their state unexpectedly.

```suggestion
```

Code after:
   */
  closedValueChanged(shouldClose: boolean, previouslyClosed?: boolean) {
    if (previouslyClosed === shouldClose) return;

    const closedClasses = this.closedClasses;
    const openedClasses = this.openedClasses;
    const contentTargets = this.contentTargets;
    const isInitial = previouslyClosed === undefined;
    const isPeeking = this.peekingValue;
    const openedContentClasses = this.openedContentClasses;
    const toggles = this.toggles;

    if (!isPeeking) this.updateToggleIcon(shouldClose);

    if (shouldClose) {
      const event = this.dispatch('closing', { cancelable: true });
      if (event.defaultPrevented) return;
      toggles.forEach((toggle) => {
        toggle.setAttribute('aria-expanded', 'false');
      });
      contentTargets.forEach((content) => {
        content.classList.remove(...openedContentClasses);
        content.hidden = true;
      });
      this.element.classList.add(...closedClasses);
      this.element.classList.remove(...openedClasses);
      this.dispatch('closed', { cancelable: false });
    } else {
      const event = this.dispatch('opening', { cancelable: true });
      if (event.defaultPrevented) return;
      toggles.forEach((toggle) => {
        toggle.setAttribute('aria-expanded', 'true');
      });
      contentTargets.forEach((content) => {
        content.classList.add(...openedContentClasses);
        content.hidden = false;
      });
      this.element.classList.remove(...closedClasses);
      this.element.classList.add(...openedClasses);
      this.dispatch('opened', { cancelable: false });
    }

    if (isInitial) return;
    // If we have known toggles, dispatch on those buttons
    toggles.forEach((target) => {
      this.dispatch('toggled', {
        cancelable: false,
        detail: {
          closed: shouldClose,
        },
        target,