yansern / vue-multipane

Resizable split panes for Vue.js.
https://yansern.github.io/vue-multipane/
Other
588 stars 125 forks source link

Cannot resize when adding custom resize handles. #32

Open skamansam opened 3 years ago

skamansam commented 3 years ago

I am trying to customize my resizer by adding icons as visual indicators. This works surprisingly well, but when the icons are clicked on, nothing happens - the resize doesn't work. I am using @mdi/font (for the icons) and Vuetify, all latest versions. My project is pretty much clean - I just started it today.

Here is my code:

<template>
  <v-app>
    <app-header />
    <v-main>
      <multipane class="custom-resizer" layout="vertical">
        <terms-panel class="pane" style="width: 40vh" />
        <multipane-resizer>
          <i class="mdi mdi-dots-vertical" />
          <i class="mdi mdi-dots-vertical" />
          <i class="mdi mdi-dots-vertical" />
        </multipane-resizer>
        <similar-terms-panel class="pane" style="width: 35vh" />
        <multipane-resizer>
          <i class="mdi mdi-dots-vertical" />
          <i class="mdi mdi-dots-vertical" />
          <i class="mdi mdi-dots-vertical" />
        </multipane-resizer>
        <tag-panel class="pane" style="flex: 1" />
      </multipane>
    </v-main>
  </v-app>
</template>

<script>
import { Multipane, MultipaneResizer } from 'vue-multipane';
import TermsPanel from '@/components/TermsPanel.vue';
import SimilarTermsPanel from '@/components/SimilarTermsPanel.vue';
import TagPanel from '@/components/TagPanel.vue';
import AppHeader from '@/components/AppHeader.vue';

export default {
  name: 'App',

  components: {
    AppHeader,
    Multipane,
    MultipaneResizer,
    SimilarTermsPanel,
    TagPanel,
    TermsPanel,
  },

  data: () => ({
    //
  }),
  mount() {
    // this is here because when I click on the handle images, it tries to drag the image. 
    this.$el.querySelector('.multipane-resizer i').forEach((el) => {
      el.draggable = false; // eslint-disable-line
    });
  },
};
</script>

<style lang="scss">
  .custom-resizer {
    width: 100%;
    height: 100%;
  }
  .custom-resizer > .pane {
    text-align: left;
    padding: 15px;
    overflow: hidden;
    background: #ffffff;
    border: 1px solid #ccc;
  }
  .custom-resizer > .pane ~ .pane {
  }
  .custom-resizer > .multipane-resizer {
    margin: 0;
    left: 0;
    position: relative;
    width: 10px;
    background-color: var(--v-background-base);
    i {
      width: 15px;
      position: relative;
      margin-top: 22vh;
      display: block;
      left: -25%;
      color: var(--v-background-darken3);
      &:before {
        width: 15px;
      }
    }
    &:hover {
      background-color: var(--v-background-lighten1);
    }
  }
</style>
juventus18 commented 3 years ago

Having the same issue. I don't have any events bound to the child element, so it seems something is stopping event propagation from the child elements (not sure). @skamansam Did you ever figure out a resolution?

juventus18 commented 3 years ago

I take it back, it looks like the event is bubbling properly, but there is this on line 40 of multipane.js: if (resizer.className && resizer.className.match('multipane-resizer')) since the child is now the target, it doesn't have the 'multipane-resizer' class, and so the code is never actually executed. I think this line needs to be modified to use .closest() (https://developer.mozilla.org/en-US/docs/Web/API/Element/closest) to check parent elements and target the actual resizer. Polyfills exist if needing to allow backward compatibility for older browsers.

juventus18 commented 3 years ago

I've got a workaround for anyone running into this issue in the meantime...

First, add a ref to the multipane-resizer component. Then, give the child elements a listener for the mousedown event so we can retarget:

<multipane-resizer ref="resizer" class="d-flex align-items-center">
    <div class="grabber" @mousedown="mousedownParent"></div>
</multipane-resizer>

Lastly, create the handler to send the event as the parent element instead of the child:

mousedownParent(e) {
    var new_e = new e.constructor(e.type, e);
    e.preventDefault();
    this.$refs.resizer.$el.dispatchEvent(new_e);
}