From 433eee9c22e40e0e7b6955589de348af9992fff4 Mon Sep 17 00:00:00 2001 From: Kevin Chappell <kevin.b.chappell@gmail.com> Date: Sat, 28 Mar 2020 15:15:11 -0700 Subject: [PATCH] feat: response panel ui --- src/js/components/panels.js | 108 ++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 35 deletions(-) diff --git a/src/js/components/panels.js b/src/js/components/panels.js index 2e4997a3..3a5d97f0 100644 --- a/src/js/components/panels.js +++ b/src/js/components/panels.js @@ -2,6 +2,7 @@ import i18n from 'mi18n' import Sortable from 'sortablejs' import h, { indexOfNode } from '../common/helpers' import dom from '../common/dom' +import { ANIMATION_SPEED_SLOW, ANIMATION_SPEED_FAST } from '../constants' const defaults = { type: 'field', @@ -19,32 +20,52 @@ export default class Panels { * @return {Object} Panels */ constructor(options) { - const _this = this this.opts = Object.assign({}, defaults, options) - this.labels = _this.panelNav() - const panels = _this.panelsWrap() + this.labels = this.panelNav() + const panelsWrap = this.createPanelsWrap() - this.panels = panels.childNodes - this.currentPanel = _this.panels[0] - this.nav = _this.navActions() + this.panels = panelsWrap.childNodes + this.activePanelIndex = 0 + this.currentPanel = this.panels[this.activePanelIndex] + this.nav = this.navActions() this.panelDisplay = this.opts.displayType || 'slider' + const resizeObserver = new window.ResizeObserver(([{ contentRect: { width } }]) => { + if (this.activePanelIndex && this.currentWidth !== width) { + this.currentWidth = width + this.nav.setTranslateX(this.activePanelIndex, false) + this.toggleTabbedLayout() + } + }) + + const observeTimeout = window.setTimeout(() => { + resizeObserver.observe(this.panelsWrap) + window.clearTimeout(observeTimeout) + }, ANIMATION_SPEED_SLOW) + return { - children: [_this.labels, panels], - nav: _this.nav, + children: [this.labels, panelsWrap], + nav: this.nav, action: { - resize: _this.resizePanels, + resize: this.resizePanels, }, } } - /** - * Resize the panel after its contents change in height - * @return {String} panel's height in pixels - */ - resizePanels = () => { + get isTabbed() { + const panelsWrap = this.panelsWrap + const column = panelsWrap.parentElement.parentElement + const width = parseInt(dom.getStyle(column, 'width')) + const autoDisplayType = width > 390 ? 'tabbed' : 'slider' + this.panelDisplay = this.opts.displayType || autoDisplayType + const isTabbed = this.panelDisplay === 'tabbed' + panelsWrap.parentElement.classList.toggle('tabbed-panels', isTabbed) + return isTabbed + } + + toggleTabbedLayout = () => { const panelsWrap = this.panelsWrap const column = panelsWrap.parentElement.parentElement const width = parseInt(dom.getStyle(column, 'width')) @@ -52,11 +73,20 @@ export default class Panels { this.panelDisplay = this.opts.displayType || autoDisplayType const isTabbed = this.panelDisplay === 'tabbed' panelsWrap.parentElement.classList.toggle('tabbed-panels', isTabbed) - const panelStyle = panelsWrap.style - const activePanelHeight = dom.getStyle(this.currentPanel, 'height') if (isTabbed) { column.querySelector('.panel-labels div').removeAttribute('style') } + return isTabbed + } + + /** + * Resize the panel after its contents change in height + * @return {String} panel's height in pixels + */ + resizePanels = () => { + this.toggleTabbedLayout() + const panelStyle = this.panelsWrap.style + const activePanelHeight = dom.getStyle(this.currentPanel, 'height') panelStyle.height = activePanelHeight return activePanelHeight } @@ -66,7 +96,7 @@ export default class Panels { * if the panel belongs to a field * @return {Object} DOM element */ - panelsWrap() { + createPanelsWrap() { this.panelsWrap = dom.create({ className: 'panels', content: this.opts.panels, @@ -202,7 +232,7 @@ export default class Panels { const groupParent = this.currentPanel.parentElement const firstControlNav = this.labels.querySelector('.panel-labels').firstChild const siblingGroups = this.currentPanel.parentElement.childNodes - let index = indexOfNode(this.currentPanel, groupParent) + this.activePanelIndex = indexOfNode(this.currentPanel, groupParent) let offset = { nav: 0, panel: 0 } let lastOffset = { ...offset } @@ -217,7 +247,14 @@ export default class Panels { return this.currentPanel } - const translateX = (offset, reset) => { + const getOffset = index => { + return { + nav: -firstControlNav.offsetWidth * index, + panel: -groupParent.offsetWidth * index, + } + } + + const translateX = ({ offset, reset, duration = ANIMATION_SPEED_FAST, animate = true }) => { if (_this.panelDisplay === 'tabbed') { firstControlNav.removeAttribute('style') const { transform } = getTransition(offset.panel) @@ -237,7 +274,7 @@ export default class Panels { const animationOptions = { easing: 'ease-in-out', - duration: 150, + duration: animate ? duration : 0, fill: 'forwards', } @@ -253,17 +290,18 @@ export default class Panels { panelTransition.addEventListener('finish', handleFinish) } + action.setTranslateX = (panelIndex, animate = true) => { + offset = getOffset(panelIndex || this.activePanelIndex) + translateX({ offset, animate }) + } + action.refresh = newIndex => { if (newIndex !== undefined) { - index = newIndex + this.activePanelIndex = newIndex groupChange(newIndex) } _this.resizePanels() - offset = { - nav: -firstControlNav.offsetWidth * index, - panel: -groupParent.offsetWidth * index, - } - translateX(offset) + action.setTranslateX(this.activePanelIndex) } /** @@ -271,42 +309,42 @@ export default class Panels { * @return {Object} current group after navigation */ action.nextGroup = () => { - const newIndex = index + 1 + const newIndex = this.activePanelIndex + 1 if (newIndex !== siblingGroups.length) { const curPanel = groupChange(newIndex) offset = { nav: -firstControlNav.offsetWidth * newIndex, panel: -curPanel.offsetLeft, } - translateX(offset) - index++ + translateX({ offset }) + this.activePanelIndex++ } else { offset = { nav: lastOffset.nav - 8, panel: lastOffset.panel - 8, } - translateX(offset, true) + translateX({ offset, reset: true }) } return this.currentPanel } action.prevGroup = () => { - if (index !== 0) { - const newIndex = index - 1 + if (this.activePanelIndex !== 0) { + const newIndex = this.activePanelIndex - 1 const curPanel = groupChange(newIndex) offset = { nav: -firstControlNav.offsetWidth * newIndex, panel: -curPanel.offsetLeft, } - translateX(offset) - index-- + translateX({ offset }) + this.activePanelIndex-- } else { offset = { nav: 8, panel: 8, } - translateX(offset, true) + translateX({ offset, reset: true }) } }