メニューが横幅に収まらない時に右上に収納されるやつ

あまりサンプルが見つからなかったのでやってみた。
こういう動きを何て言うのか分からないので、自分が見つけられなかっただけの可能性は否めないです・・・。

## デモ
<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="negibouze" data-slug-hash="pozgYYJ" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="navbar with menu storage">
  <span>See the Pen <a href="https://codepen.io/negibouze/pen/pozgYYJ/">
  navbar with menu storage</a> by Yoshiaki Itakura (<a href="https://codepen.io/negibouze">@negibouze</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## ちょっと解説
せっかくなので、[Intersection Observer](https://developer.mozilla.org/ja/docs/Web/API/Intersection_Observer_API)を使ってみました。
ポイントは`root`を`#menu`にするところくらいです。

```javascript
const setIntersectionObserver = () => {
  const observerOptions = {
    root: document.querySelector("#menu"), // menuをroot要素にする
    rootMargin: "0px",
    threshold: [0.8]
  };

  const items = document.querySelectorAll(".menu-item");
  observer = new IntersectionObserver(
      intersectionCallback,
      observerOptions
    );
  // menu-itemを監視対象にする
  for (const item of items) {
    observer.observe(item);
  }
}
```

`entry.isIntersecting `で処理を分岐します。
`true`: 見えるようになった
`false`: 見えなくなった

```javascript
const intersectionCallback = (entries) => {
  entries.forEach(entry => {
    const target = entry.target;
    const storage = document.querySelector(".storage");
    if (entry.isIntersecting) {
      // navbarのメニューを表示する
      target.classList.remove("invisible");
      const len = overflowMenuItems.length;
      if (1 <= len) {
        if (len === 1) {
          // 最後の要素が表示された時は、more(縦の「・・・」)を非表示にする
          storage.classList.add("hide");      
        }
        // 収納していたメニューの先頭を削除する
        overflowMenuItems.shift();
      }
    } else {
      // あふれメニューの末尾に要素のクローンを追加する
      overflowMenuItems.unshift(target.cloneNode(true));
      // navbarのメニューを非表示にする
      target.classList.add("invisible");
      // more(縦の「・・・」)を表示する
      storage.classList.remove("hide");
    }
  });
  sortOverflowItems();
  createOverflowMenu();
}
```

並び順を保証するために、data属性のorderでsortします。
※これをやらないと、初回表示時に横幅が足りない時に並び順が保証されない

```javascript
const sortOverflowItems = () => {
  overflowMenuItems.sort((a, b) => {
    return a.dataset.order < b.dataset.order ? -1 : 1;
  })
}
```

`#overflowMenu`の子要素にあふれた分のメニューを追加します。
差分更新にした方が良いと思いますが、ひとまず毎回、既存の子要素を全削除してから、再度追加しています。

```javascript
const createOverflowMenu = () => {
  const menu = document.querySelector("#overflowMenu");
  // 一回全部消す
  while (menu.firstChild) {
    menu.removeChild(menu.firstChild);
  }
  for (const item of overflowMenuItems) {
    menu.appendChild(item);
  }
}
```

おまけ: ドラッグで横幅を変えるやつ（動作確認用）

```javascript
/* 動作確認用 */
const wrapper = document.querySelector(".wrapper");

const addResizeEvent = () => {
  const rightEdge = document.querySelector(".right-edge");

  rightEdge.addEventListener("mousedown", initResize, false);
}

const initResize = (e) => {
  window.addEventListener("mousemove", Resize, false);
  window.addEventListener("mouseup", stopResize, false);
}

const Resize = (e) => {
  wrapper.style.width = `${e.clientX - wrapper.offsetLeft}px`;
}

const stopResize = (e) => {
  window.removeEventListener("mousemove", Resize, false);
  window.removeEventListener("mouseup", stopResize, false);
}
```