javascripthtmlcsssveltedrag

Resizable Sidebar in Svelte. Mouse and sidebar width don't stay in sync


Having a minimal Resizable Sidebar example.

While it works, I would like that the mouse location and the drag handle stay visually in sync, which is not the case. See attached gif, the mouse moves faster then the sidebar is scaled: enter image description here

The code in question (see Svelte Repl - might be a improved/fixed version):

<script>
    import { onDrag } from './dragMe';
    let width = 58;
    let resizeWidth = width;
    let debugDelta;
</script>

    <div style="display: flex;">
        <div style="background-color:red;
                                width:{resizeWidth}px;" >1</div>
                
        <div 
            role="separator"
          aria-orientation="vertical"
            style="background-color:gray; 
                         width:4px;
                         cursor: col-resize;" 
            use:onDrag={{orientation:'vertical'}}
            on:drag={({ detail: delta }) => {resizeWidth = width + delta; debugDelta=delta;}}
            on:dragEnd={() => (width = resizeWidth)}
            > </div>
        
        <div style="background-color:blue;">2</div>
    </div>
/** @type {import('svelte/action').Action}  */
export const onDrag = (node, params) => {
  let dragStart = null;

  const attr = params.orientation === 'vertical' ? 'screenX' : 'screenY';

  const mouseDownAction = (e) => {
    e.preventDefault();
    node.dispatchEvent(new CustomEvent('dragStart', { detail: 'hello' }));
    dragStart = e[attr];
  };
  const mouseMoveAction = (e) => {
    if (dragStart != null) {
      const delta = e[attr] - dragStart;
      node.dispatchEvent(new CustomEvent('drag', { detail: delta }));
    }
  };
  const mouseUpAction = () => {
    dragStart = null;
    node.dispatchEvent(new CustomEvent('dragEnd', { detail: 'hello' }));
  };

  node.addEventListener('mousedown', mouseDownAction);
  document.addEventListener('mousemove', mouseMoveAction);
  document.addEventListener('mouseup', mouseUpAction);

  return {
    destroy() {
      node.removeEventListener('mousedown', mouseDownAction);
      document.removeEventListener('mousemove', mouseMoveAction);
      document.removeEventListener('mouseup', mouseUpAction);
    }
  };
};

Anyone know what am I missing ?


Solution

  • The problem is present probably because of how flex containers work. Instead of assigning a 100% width to the second DIV, use flex: 1. It will work appropriately.

    I don't have an explanation for this. If any smarter person would like to volunteer one, I am all ears.