miniArray/monorail

View on GitHub
src/components/MSplitView/MSplitView.vue

Summary

Maintainability
Test Coverage
<template>
  <div
    :style="splitViewStyles"
    class="split-view">
    <div
      :style="paneStyles"
      class="pane">
      <div
        :style="paneWrapperStyles"
        class="pane__wrapper">
        <!-- @slot Content for pane slot -->
        <slot name="pane" />
      </div>
    </div>
    <div class="content">
      <!-- @slot Content for content slot -->
      <slot name="content" />
    </div>
  </div>
</template>

<style scoped lang="postcss">
.split-view {
  display: grid;
  grid-template-rows: auto;
  grid-gap: 0px;
}

.pane,
.content {
  align-items: center;
  justify-items: center;
}

.content,
.pane,
.pane__wrapper,
.pane__wrapper > *,
.content > * {
  height: 100%;
}

.pane {
  overflow: hidden;
  grid-column-start: 1;
  z-index: 2;
}

.content {
  grid-column: 2;
  z-index: 1;
}

</style>

<script>
import always from 'ramda/es/always'
import ifElse from 'ramda/es/ifElse'
import equals from 'ramda/es/equals'
import pipe from 'ramda/es/pipe'
import cond from 'ramda/es/cond'
import tween from 'popmotion/animations/tween'

const px = num => `${num}px`
const splitViewOptions = [
  'compact-inline',
  'compact-overlay'
]

export default {
  name: 'MSplitView',

  props: {
    /**
     * Collapsed state of the pane
     */
    collapsed: {
      type: Boolean,
      default: false
    },

    /**
     * Width of pane when collapsed
     */
    collapsedWidth: {
      type: Number,
      default () {
        return this.$monorail.settings.listItemIcon
      }
    },

    /**
     * Mode of pane:
     * `compact-inline, compoact-overlay`
     */
    mode: {
      type: String,
      default: 'compact-inline',
      validate: val => splitViewOptions.includes(val)
    },

    /**
     * Width of the pane when expanded
     */
    expandedWidth: {
      type: Number,
      default () {
        return this.$monorail.settings.splitViewExpandedWidth
      }
    }
  },

  data () {
    return {
      width: 0
    }
  },

  computed: {
    paneStyles () {
      return {
        gridColumnEnd: this.mode === 'compact-inline' ? 1 : 2,
        width: px(this.width)
      }
    },

    paneWrapperStyles () {
      return {
        width: px(this.expandedWidth)
      }
    },

    splitViewStyles () {
      const width = pipe(this.getColumnWidthFromMode, px)(this.mode)

      return {
        gridTemplateColumns: `${width} 1fr`
      }
    }
  },

  watch: {
    collapsed () {
      this.animatePaneWidth()
    }
  },

  created () {

    this.width = ifElse(
      always(true),
      always(this.collapsedWidth),
      always(this.expandedWidth)
    )(this.collapsed)
  },

  methods: {
    getColumnWidthFromMode (mode) {
      return cond([
        [equals('compact-overlay'), always(this.collapsedWidth)],
        [equals('compact-inline'), always(this.width)]
      ])(mode)
    },

    animatePaneWidth () {
      tween({
        from: !this.collapsed ? this.collapsedWidth : this.expandedWidth,
        to: this.collapsed ? this.collapsedWidth : this.expandedWidth,
      }).start(v => this.width = v)
    }
  },
}
</script>

<docs>
### Compact Inline mode

Content area is always visible.

```vue
<template>
  <div>
    <div>
      <m-switch :checked="!collapsed" @change="collapsed = !collapsed" caption="Expanded" />
      <br/>
      <br/>
    </div>

    <m-split-view :collapsed="collapsed" mode="compact-inline" style="min-height: 100px">
      <div style='background: #ddd' slot="pane"/>
      <div style='background: #ccc' slot="content">
        Lorem ipsum dolor sit, amet consectetur adipisicing elit. Quos, aut eveniet tempora dolore modi officia distinctio rerum, deserunt aspernatur molestias possimus similique itaque ipsa ad, assumenda blanditiis labore hic maiores.
      </div>
    </m-split-view>
  </div>
</template>

<script>
export default {
  data () {
    return {
      collapsed: true,
    }
  }
}
</script>
```

### Compact Overlay mode

Content area is hidden when pane is not collapsed.

```vue
<template>
  <div>
    <div>
      <m-switch :checked="!collapsed" @change="collapsed = !collapsed" caption="Expanded" />
      <br/>
      <br/>
    </div>

    <m-split-view :collapsed="collapsed" mode="compact-overlay" style="min-height: 100px">
      <div style='background: #ddd' slot="pane"/>
      <div style='background: #ccc' slot="content">
        Lorem ipsum dolor sit, amet consectetur adipisicing elit. Quos, aut eveniet tempora dolore modi officia distinctio rerum, deserunt aspernatur molestias possimus similique itaque ipsa ad, assumenda blanditiis labore hic maiores.
      </div>
    </m-split-view>
  </div>
</template>

<script>
export default {
  data () {
    return {
      collapsed: true,
    }
  }
}
</script>
```
</docs>