DEPRECATED

master ブランチは Atlaskit を使わず自前実装に切り替え済み。

元の材料

  • @atlaskit/navigation-next external_link を Sidebar コンポーネントでラップしている
  • 開閉(collapse)できる
  • サイズの固定・解除ができる
    • サイズ固定状態では、collapse が解除される

Drawer Mode

  • navigationUIController.disableResize() を行い、サイズ固定、Sidebar としては常に collapse 解除(open 状態)にする
  • 上記をスタイル変更で画面外に隠す
    • @mixin drawer()
  • Drawer の開閉は、Sidebar コンポーネントごと css で左右に移動させる
    • AppContainer.state.isDrawerOpened
  • モーダルバックドロップは自作している
    • .grw-sidebar-backdrop.modal-backdrop

Dock Mode

  • navigationUIController.enableResize() を行い、サイズ可変にする

Hack

  • navigation-next は unstated container を利用しているが、一部のコードでバグがある
    • UIController.storeState で、更新完了していない state を参照してしまっている(await していない)
    • そのため、1世代前の state 情報を localStorege に保存してしまう
  • 上記を回避するため、以下のようなコードで storeState メソッドを上書きしている
Sidebar.jsx
/** * hack and override UIController.storeState * * Since UIController is an unstated container, setState() in storeState method should be awaited before writing to cache. */ hackUIController() { const { navigationUIController } = this.props; // see: @atlaskit/navigation-next/dist/esm/ui-controller/UIController.js const orgStoreState = navigationUIController.storeState; navigationUIController.storeState = async(state) => { await navigationUIController.setState(state); orgStoreState(state); }; }

モード変更条件

  • デバイスサイズ sm 以下では Drawer Mode
  • デバイスサイズ md 以上では、閲覧/編集 モード x ユーザーpreference のマトリックスにより、4種類の状態を遷移する
    • 閲覧モード x localStorage.preferDrawerModeByUser: true -> Drawer Mode
    • 閲覧モード x localStorage.preferDrawerModeByUser: false -> Dock Mode
    • 編集モード x localStorage.preferDrawerModeOnEditByUser: true -> Drawer Mode
    • 編集モード x localStorage.preferDrawerModeOnEditByUser: false -> Dock Mode
  • 上記は AppContainer.updateDrawerMode() で判定
    • unstated の state を正しく更新・参照するために await を乱発するとパフォーマンスが落ちるため、呼び出し側で新しい状態オブジェクトである newState を作成して引数に入れている
    • 更新のトリガーは以下
      • 閲覧・編集モードタブ切り替え
      • デバイスサイズ変更を検知する media query イベントハンドラ

モード変更時のトランジション抑制

  • 状態に応じて以下を抑制しないと気持ち悪い動きになる
    1. Sidebar の実態である navigationUIController の開閉 transition
    2. @mixin drawer() で左右に動かしている部分の transition
  • ロジック
    • Dock Mode での navigationUIController の開閉状態を記憶、判定の材料に使う
    • Dock -> Drawer
      • 元々 collapse していた場合、1を抑制してはいけない
        • 抑制してしまうと瞬時に open 状態になり、スムーズに画面外に掃けなくなる
      • 元々 collapse していた場合、2を抑制する
        • 抑制することで navigationUIController が open 状態に遷移するとしても、Sidebar 全体は画面外へ速やかに移動する
    • Drawer -> Dock
      • 元々 collapse していた場合、1を抑制する
        • navigationUIController を瞬時に open -> collapse に戻すことができる
  • 抑制手段
    • 少し気持ち悪いが一旦クリアして setTimeout で元に戻す
      clearNavigationTransitionTemporary(elem) { const transitionCache = elem.style.transition; // clear elem.style.transition = undefined; // restore after 300ms setTimeout(() => { elem.style.transition = transitionCache; }, 300); }

ページロード時の初期状態

  • sm 以下の場合は、CSS により .grw-sidebar-drawer クラスの有無に関わらず @mixin drawer() が適用される
    • media query の判定はページロード完了後になるため、 AppContainer.state.isDeviceSmallerThanMd を初期状態セットアップに利用することができない
    • Sidebar の実態である navigationUIController は、画面外で AppContainer.state.isDrawerMode の初期化を待って Drawer Mode へ遷移する
  • md 以上の場合は、AppContainer の初期化完了時に既に localStorage から値を読み込んだ AppContainer.state.preferDrawerMode* が利用可能であるため、その値を利用して初期状態への遷移を行う
    • Sidebar の実態である navigationUIController は、SidebarWithNavigationNavigationProviderinitialUIController が設定される
      • preferDrawerModeByUser が true なら初期値をセット、false なら何もセットせず、キャッシュ(localStorage.ATLASKIT_NAVIGATION_UI_STATE)を利用する

growi-sidebar-drawer クラスの有無で @mixin drawer() が適用されるかどうかが決まる