Git Product home page Git Product logo

vue-multipane's Introduction

vue-multipane npm tag

Resizable split panes for Vue.js.


Check out the live demo.

Features

  • Uses CSS3 Flexbox.
  • Supports vertical & horizontal layouts.
  • Supports fixed and fluid panes.
  • Configure everything using CSS!

Installation

$ npm install vue-multipane

Using vue-multipane

First, import vue-multipane into your Vue component.

import { Multipane, MultipaneResizer } from 'vue-multipane';

export default {
  // ...
  components: {
    MultiPane,
    MultiPaneResizer
  }
}

Then, construct your split pane layout using multipane component.

<multipane>
  <div>Pane 1</div>
  <multipane-resizer></multipane-resizer>
  <div>Pane 2</div>
  <multipane-resizer></multipane-resizer>
  <div>Pane 3</div>
</multipane>

Customizing pane layout

You can customize pane layouts using CSS.

  • Create vertical/horizontal layouts using layout="vertical|horizontal" attribute.
  • Set initial pane size using width|height CSS property.
  • Set pane size constraints using min-width|min-height|max-width|max-height CSS property.
  • Create fixed/fluid combination panes by using px|% units.
  • Use flex-grow: 1 for that one pane that should take all remaining space available on the multipane container.

This example below shows a combination of different styling properties you can apply to make the panes render the way you want it to:

<multipane class="foo" layout="vertical">
  <div :style="{ width: '100px', maxWidth: '200px' }">Pane 1</div>
  <multipane-resizer></multipane-resizer>
  <div :style="{ width: '25%', maxWidth: '50%' }">Pane 2</div>
  <multipane-resizer></multipane-resizer>
  <div :style="{ flexGrow: 1 }">Pane 3</div>
</multipane>

Customizing resize handle

By default, vue-multipane creates an invisible 10px resize handle that sits in between 2 panes. You can customize the appearance of the resize handle to fit your needs.

This example below creates a 15px blue resize handle:

.multipane.foo.layout-v .multipane-resizer {
  margin: 0; left: 0; /* reset default styling */
  width: 15px;
  background: blue;
}

.multipane.foo.layout-h .multipane-resizer {
  margin: 0; top: 0; /* reset default styling */
  height: 15px;
  background: blue;
}

Optional resize handle

You can also add resize handle only specific panes by just adding <multipane-resizer> next it.

<multipane>
  <div>Pane 1</div> <!-- No resizing on Pane 1. -->
  <div>Pane 2</div> <!-- Resizing is possible on Pane 2. -->
  <multipane-resizer></multipane-resizer>
  <div>Pane 3</div>
</multipane>

Options

** Multipane **

Property Description Type Default
layout Determine layout of panes. String [vertical, horizontal] vertical

Events

** Multipane **

Event Description Returns
paneresizestart When user clicks on the resize handle to start resizing a pane. pane, container, size
paneresize When user is resizing a pane. pane, container, size
paneresizestop When user release the resize handle to stop resizing a pane. pane, container, size

License

vue-multipane by Yan Sern licensed under MIT.

PS: I would love to know if you're using vue-multipane. Tweet to me at @yansernio.

vue-multipane's People

Contributors

yansern avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue-multipane's Issues

Panes overlap when window smaller than min-width

Hi,
The panes overlap when the window is resized smaller than the min-width.
Imgur

Any way you can update the code to prevent this?

UPDATE:
It turns out it's to do with the rightmost panel having content that is larger than the one to the left.
Imgur
Sorry about the quality. I still have no fix.

Thank you,
Jamie

Cannot combine vertical and horizontal panes

For example, the following code does not work.

<template>
    <multipane layout="vertical" class="container">
        <div class="left">
            <h6 class="title is-6">Pane 1</h6>
        </div>
        <multipane-resizer></multipane-resizer>
        <multipane layout="horizontal" class="right">
            <div class="top">
              <h6 class="title is-6">Pane 2</h6>
            </div>
            <multipane-resizer></multipane-resizer>
            <div class="bottom">
              <h6 class="title is-6">Pane 3</h6>
            </div>
        </multipane>
    </multipane>
</template>

<script>
import { Multipane, MultipaneResizer } from '@/src';

export default {
  components: {
    Multipane,
    MultipaneResizer,
  },
};
</script>

<style>
.container {
  height: 600px;
  width: 100%;
}

.left {
  width: 50%;
  min-width: 20%;
  max-width: 80%;
  height: 600px;
  border: 1px solid #ccc;
  background: #eee;
}

.right {
  flex-grow: 1;
  height: 600px;
  border: 1px solid #ccc;
  background: #eee;
}

.top {
  height: 300px;
  min-height: 20%;
  max-height: 80%;
  width: 100%;
  border: 1px solid #ccc;
  background: #eee;
}
.bottom {
  flex-grow: 1;
  width: 100%;
  border: 1px solid #ccc;
  background: #eee;
}
</style>

When resizing the horizontal resizer both the height and the width of the pane 2 will be change.

This is because the multipane component catch the mouse up and mouse down event on the whole component instead of the resizer.

I think this could be fixed by catching the event of the resizer instead of the whole component.

event handler case warnings on paneresize

Hello and thank you for this cool component.

I saw in doc that the resize event is "paneresize".

But when I use it like this :
<multipane id="general-panel" layout="vertical" @paneresize="resized">
the callback method is not fired and I get this warning in browser's console :
vue.esm.js?efeb:580 [Vue tip]: Event "paneresize" is emitted in component <Multipane> but the handler is registered for "paneResize". Note that HTML attributes are case-insensitive and you cannot use v-on to listen to camelCase events when using in-DOM templates. You should probably use "pane-resize" instead of "paneResize".

If I change to @paneResize="resized", the callback is now fired and works but the warning still appears.

If I change to @pane-resize="resized", the callback is not fired and the warning still appears.

So only the second solution works, (with paneResize) but I don't like to use camelCase with HTML attributes, and the warning remains.

Am I wrong with the way I catch the event ? Is there any solution ?

Thank you for your time, best regards.

错误提交,待删除!

阻止冒泡虽然能解决问题,但不太优雅;
所以希望能从根儿上解决,如:if (typeof t.className === 'string' && t.className.match('multipane-resizer'))

Cannot resize when adding custom resize handles.

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>

Incorrect import example

`import { Multipane, MultipaneResizer } from 'vue-multipane';

export default {
// ...
components: {
MultiPane,
MultiPaneResizer
}
}`

should be:

`import { Multipane, MultipaneResizer } from 'vue-multipane';

export default {
// ...
components: {
Multipane,
MultipaneResizer
}
}`

Error occur when clicking svg tags

The error output is:

TypeError: resizer.className.match is not a function
   at VueComponent.onMouseDown (multipane.js?77e5:41)

The error happens in this line:

if (resizer.className && resizer.className.match('multipane-resizer')) {

The resizer.className here is expected to be a string, however, when click a svg tag, the classname returned is a SVGAnimatedString object. SVGAnimatedString objects don't implement the match method, so a error is thrown.

To fix this bug, a simple way is changing resizer.className into (resizer.className + ""), this will turn the SVGAnimatedString objects into null, and no error occurs in my environment.

iframe support

Maybe masker should be considered to cover the whole panel after mousedown is triggered, becourse mousemove over an iframe can not be detected.

horizontal/vertical are backwards

Maybe I'm crazy, but layout=vertical to me implies that the panels will stack from top to bottom. The opposite seems to be the case.

height: 100% not working

Thanks for a great component!

I ran into the following issue: I'd like the panes to take up 100% of the available space.

In the demo code (1st example), I tried setting height to 100% instead of 400px.
This seems to disable the slider control and fixes the window height to the content size, rather than available space.

How can I size the panes to occupy the entire available space vertically?

Text creates scaling issues (vertical)

It seems that text causes scaling issues. When there is a fair amount of text the resizer jumps back to where it likes to be, instead of where I want it.

This issue can be seen with the vertical panes demo, when you (in the inspector) duplicate the text "Takes remaining available space." lets say 6 times, you can see the problem.

Is there any fix for this?

resizer does not work properly if its left or upper pane has flex-grow of 1

The resizer does not work properly if its left or upper pane has flex-grow of 1.

The following is a test case

<template>
    <multipane layout="vertical" class="container">
        <div class="left">
            <h6 class="title is-6">Pane 1</h6>
            <p class="subtitle is-6">Takes remaining available space.</p>
            <p>
              <small>
                <strong>Configured with:</strong><br/>
                flex-grow: 1<br/>
              </small>
            </p>
        </div>
        <multipane-resizer></multipane-resizer>
        <div class="right">
            <h6 class="title is-6">Pane 2</h6>
            <p class="subtitle is-6">Fluid width.</p>
            <p>
              <small>
                <strong>Configured with:</strong><br/>
                width: 50%<br/>
                min-width: 20%;<br/>
                max-width: 80%;<br/>
              </small>
            </p>
        </div>
    </multipane>
</template>

<script>
import { Multipane, MultipaneResizer } from '@/src';

export default {
  components: {
    Multipane,
    MultipaneResizer,
  },
};
</script>

<style>
.container {
  height: 600px;
  width: 100%;
}

.left {
  flex-grow: 1;
  height: 600px;
  border: 1px solid #ccc;
  background: #eee;
}

.right {
  width: 50%;
  min-width: 20%;
  max-width: 80%;
  height: 600px;
  border: 1px solid #ccc;
  background: #eee;
}
</style>

Need guide on paneresizestart use !

I want to trigger paneresizestart but its not working

`


<multipane @pane-resize="onResizeStart" layout="vertical">

<iframe
class="opacity-100 h-[550px]"
width="100%"
srcdoc="

                <head>
                    <meta charset='UTF-8'>
                    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
                    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
                    <link href='https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css' rel='stylesheet'>
                </head>

                <body class='pointer'>
                    <div class='xl:relative mx-auto xl:px-0 sm:px-4 grid md:grid-cols-2 items-center bg-white'>
                        <div class='h-full'>
                            <img src='https://source.unsplash.com/random/800x600' alt='img' class='w-full h-full object-cover object-left'>
                        </div>
                        <div class='max-w-lg container mx-auto px-4 lg:py-6 py-3'>

                            <h2 class='lg:text-4xl text-2xl font-medium'>Login</h2>
                            <p class='border-b border-gray-300 lg:text-lg text-sm py-4 text-gray-500'>We Connect and Keep your
                                Social
                                data.</p>
                            <div class='flex flex-col my-4 lg:my-6'>
                                <div
                                    class='flex justify-center items-center bg-blue-400 hover:bg-blue-500 rounded-sm px-8 lg:py-3 py-2'>
                                    <input type='button' value='Login with Github'
                                        class='bg-transparent text-white lg:text-xl text-base ml-1'>
                                </div>
                                <div class='text-center lg:my-3 my-1'>
                                    <samp class='text-xl'>OR</samp>
                                </div>
                                <div class='rounded-md px-4 lg:py-3 py-2 border border-gray-300 mb-5'>
                                    <input type='email' placeholder='E-mail' class='outline-none lg:text-xl text-base w-full'>
                                </div>
                                <div class='rounded-md px-4 lg:py-3 py-2 border border-gray-300 mb-5'>
                                    <input type='password' placeholder='Password' class='outline-none lg:text-xl text-base'>
                                </div>
                                <div
                                    class='text-center bg-blue-400 hover:bg-blue-500 rounded-sm px-8 py-2 my-2'>
                                    <input type='button' value='Sign in' class='bg-transparent text-white lg:text-xl text-base'>
                                </div>
                            </div>
                            <div class='text-center'>
                                <div class='text-center lg:text-md text-xs font-medium text-blue-500'>
                                    <a href='!#' class='block lg:mb-2 mb-1'>Forgot your Password ?</a>
                                    <a href='!#'>I Want to Sign up</a>
                                </div>
                            </div>
                        </div>
                    </div>

                </body>

                </html>"
				frameborder="2"
			></iframe>
			<div :class="{ 'pointer-events-none': !resizing }" class="hidden absolute opacity-0 inset-0 mr-4 sm:block pointer-events-none"></div>
		</div>
		<multipane-resizer></multipane-resizer>
	</multipane>
</div>
<script> import Vue from 'vue'; import iframeResize from 'iframe-resizer/js/iframeResizer'; import { Multipane, MultipaneResizer } from 'vue-multipane'; // import DetailsCode from './detailsCode.vue' Vue.directive('resize', { bind: function (el, { value = {} }) { el.addEventListener('load', () => iframeResize(value, el)); }, unbind: function (el) { el.iFrameResizer.removeListeners(); }, }); export default { components: { Multipane, MultipaneResizer, }, data() { return { resizing: false, }; }, methods: { onResizeStart() { console.log('jojo'); }, }, }; </script> <style> iframe::-webkit-scrollbar { display: none; } .layout-v > .multipane-resizer { width: 20px; height: auto; margin-left: -20px; left: 0; cursor: ew-resize; } </style>

`

Bug when pane contains svg

I have highchart inside of pane, and when click on it, there error raised with text:
TypeError: t.className.match is not a function

because t is path element and it's className is array, and really array has no function match.

VueComponent.onMouseDown
vue-multipane/dist/vue-multipane.esm.js:3:560

Touch support ??

Hi, Thanks for this great library , can we have touch support to drag and resize?

Thanks,
Abhi

vue3/nuxt3

Are there any plans to update this for vue3/nuxt3 🙏?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.