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
- 閲覧モード x
- 上記は
AppContainer.updateDrawerMode()
で判定- unstated の state を正しく更新・参照するために await を乱発するとパフォーマンスが落ちるため、呼び出し側で新しい状態オブジェクトである
newState
を作成して引数に入れている - 更新のトリガーは以下
- 閲覧・編集モードタブ切り替え
- デバイスサイズ変更を検知する media query イベントハンドラ
- unstated の state を正しく更新・参照するために await を乱発するとパフォーマンスが落ちるため、呼び出し側で新しい状態オブジェクトである
モード変更時のトランジション抑制
- 状態に応じて以下を抑制しないと気持ち悪い動きになる
- Sidebar の実態である navigationUIController の開閉 transition
@mixin drawer()
で左右に動かしている部分の transition
- ロジック
- Dock Mode での navigationUIController の開閉状態を記憶、判定の材料に使う
- Dock -> Drawer
- 元々 collapse していた場合、1を抑制してはいけない
- 抑制してしまうと瞬時に open 状態になり、スムーズに画面外に掃けなくなる
- 元々 collapse していた場合、2を抑制する
- 抑制することで navigationUIController が open 状態に遷移するとしても、Sidebar 全体は画面外へ速やかに移動する
- 元々 collapse していた場合、1を抑制してはいけない
- Drawer -> Dock
- 元々 collapse していた場合、1を抑制する
- navigationUIController を瞬時に open -> collapse に戻すことができる
- 元々 collapse していた場合、1を抑制する
- 抑制手段
- 少し気持ち悪いが一旦クリアして setTimeout で元に戻す
clearNavigationTransitionTemporary(elem) { const transitionCache = elem.style.transition; // clear elem.style.transition = undefined; // restore after 300ms setTimeout(() => { elem.style.transition = transitionCache; }, 300); }
- 少し気持ち悪いが一旦クリアして setTimeout で元に戻す
ページロード時の初期状態
- sm 以下の場合は、CSS により
.grw-sidebar-drawer
クラスの有無に関わらず@mixin drawer()
が適用される- media query の判定はページロード完了後になるため、
AppContainer.state.isDeviceSmallerThanMd
を初期状態セットアップに利用することができない - Sidebar の実態である navigationUIController は、画面外で
AppContainer.state.isDrawerMode
の初期化を待って Drawer Mode へ遷移する
- media query の判定はページロード完了後になるため、
- md 以上の場合は、AppContainer の初期化完了時に既に localStorage から値を読み込んだ
AppContainer.state.preferDrawerMode*
が利用可能であるため、その値を利用して初期状態への遷移を行う- Sidebar の実態である navigationUIController は、
SidebarWithNavigation
でNavigationProvider
のinitialUIController
が設定される- preferDrawerModeByUser が true なら初期値をセット、false なら何もセットせず、キャッシュ(
localStorage.ATLASKIT_NAVIGATION_UI_STATE
)を利用する
- preferDrawerModeByUser が true なら初期値をセット、false なら何もセットせず、キャッシュ(
- Sidebar の実態である navigationUIController は、
growi-sidebar-drawer
クラスの有無で @mixin drawer()
が適用されるかどうかが決まる