Giter Site home page Giter Site logo

dflex-js / dflex Goto Github PK

View Code? Open in Web Editor NEW
1.7K 12.0 26.0 6.92 MB

The sophisticated Drag and Drop library you've been waiting for πŸ₯³

Home Page: https://www.dflex.dev

License: MIT License

JavaScript 1.63% CSS 0.96% HTML 0.16% TypeScript 95.49% Vue 1.75%
drag-and-drop draggable dom-manipulation dom-api dom-store sortable droppable dnd

dflex's Introduction

Dflex build status number of opened pull requests DFlex last released version number of opened issues Dflex welcomes pull request Follow DFlex on twitter

DFlex

DFlex is a Javascript library for modern Drag and Drop apps. It's built with vanilla Javascript and implemented an enhanced transformation mechanism to manipulate DOM elements. It is by far the only Drag and Drop library on the internet that manipulates the DOM instead of reconstructing it and has its own scheduler and reconciler.

Features

  • Dynamic architecture.
  • Traverse DOM without calling browser API.
  • Infinite DOM transformation instead of reconstructing the DOM tree with every interaction.
  • Customized and enhanced reconciler targets only elements transformed from origin.
  • Isolated from data flow with a scheduler prevents any blocking event.
  • Prevent layout shift that happens with any Drag and Drop mechanism.
  • Animated transformation with each interaction.
  • Headless and compatible with any modern JS framework.
  • Targeting each DOM element individually based on registration.
  • Event driven and fully customized API.
  • Extensible using its own matching algorithm instead of flat recursion algorithm(s).
  • Support three different types of restrictions.
  • Support four types of custom events and custom layout state emitter.

Implemented Transformation πŸ’‘

  • The original input order which appears when inspecting elements stays the same. While the visual order happens after transformation and it's supported by the data-index attribute to know the order of elements in the visual list.

    original and visual order

  • To enable handling a large set of elements, the transformation is related to the viewport. No matter how many elements are affected, DFlex only transforms elements visible on the screen. Elements outside the viewport are triggered to a new position when they are visible.

    Trigger elements visible on the screen

  • Support strict transformation between containers.

    Handle orphaned container

Installation

npm install @dflex/dnd

API

DFlex DnD depends on three principles to achieve DOM interactivity:

  • Register element in the store.
  • Start dragging when mouse is down.
  • End dragging to release element when mouse is up.
import { store, DnD } from "@dflex/dnd";

Register element

Each element should be registered in DFlex DnD Store in order to be active for drag and drop later.

store.register(RegisterInputOpts): void;

Where RegisterInputOpts is an object with the following properties:

  • id: string Targeted element-id.
  • depth?: number The depth of targeted element starting from zero (The default value is zero).
  • readonly?: boolean True for elements that won't be transformed during DnD but belongs to the same interactive container.

Create Drag and Drop Session

The responsive drag and drop session should be created when onmousedown is fired. So it can initialize the element and its siblings before start dragging.

const dflexDnD = new DnD(id, coordinate, opts);
  • id: string registered element-id in the store.
  • coordinate: AxesPoint is an object with {x: number, y: number} contains the coordinates of the mouse/touch click.
  • opts?: DFlexDnDOpts is DnD options object. You can see DFlex DnD options full documentation by clicking here.

Start responsive dragging

dflexDnD.dragAt(x, y);
  • x: number is event.clientX, the horizontal click coordinate.
  • y: number is event.clientY, the vertical click coordinate.

End Drag and Drop Session

dflexDnD.endDragging();

Cleanup element

It's necessary to cleanup the element from store when the element won't be used or will be removed/unmounted from the DOM to prevent any potential memory leaks.

store.unregister(id: string): void

Options

You can pass options when creating a DnD instance that controls each element individually. So your options can be different from each other.

Dragging Threshold

The threshold object defines when the dragging event should be fired and triggers the response of other sibling elements.

Threshold Interface

interface ThresholdPercentages {
  /** vertical threshold in percentage from 0-100 */
  vertical: number;

  /** horizontal threshold in percentage from 0-100 */
  horizontal: number;
}

Threshold Definition

interface DFlexDnDOpts {
  // ... other options.
  threshold?: Partial<ThresholdPercentages>;
}

Threshold Default Value

{
  "threshold": {
    "vertical": 60,
    "horizontal": 60
  }
}

Commit changes to DOM

DFlex is built to manipulate DOM elements with transformation indefinitely. This means you can always drag and drop elements without reconstruction of the DOM. Still, it comes with a reconciler that tracks elements' changes and only reconciles the elements that have changed their position from their origin.

Commit Interface

interface CommitInterface {
  enableAfterEndingDrag: boolean;
  enableForScrollOnly: boolean;
}

Commit Definition

interface DFlexDnDOpts {
  // ... other options.
  commit?: Partial<CommitInterface>;
}

Commit Default Value

{
  "commit": {
    "enableAfterEndingDrag": true,
    "enableForScrollOnly": true
  }
}

Dragging Restrictions

You can define the dragging restrictions for each element relative:

  1. Element position.
  2. Element parent container.
  3. Screen viewport (automatically enabled).

Restrictions Interface

interface Restrictions {
  self: {
    allowLeavingFromTop: boolean;
    allowLeavingFromBottom: boolean;
    allowLeavingFromLeft: boolean;
    allowLeavingFromRight: boolean;
  };
  container: {
    allowLeavingFromTop: boolean;
    allowLeavingFromBottom: boolean;
    allowLeavingFromLeft: boolean;
    allowLeavingFromRight: boolean;
  };
}

Restrictions Definition

interface DFlexDnDOpts {
  // ... other options.
  restrictions?: {
    self?: Partial<Restrictions["self"]>;
    container?: Partial<Restrictions["container"]>;
  };
}

Restrictions Default Value

{
  "restrictions": {
    "self": {
      "allowLeavingFromTop": true,
      "allowLeavingFromBottom": true,
      "allowLeavingFromLeft": true,
      "allowLeavingFromRight": true
    },
    "container": {
      "allowLeavingFromTop": true,
      "allowLeavingFromBottom": true,
      "allowLeavingFromLeft": true,
      "allowLeavingFromRight": true
    }
  }
}

Auto-Scroll

Auto-Scroll Interface

interface ScrollOptions {
  enable?: boolean;
  initialSpeed?: number;
  threshold?: Partial<ThresholdPercentages>;
}

Auto-Scroll Definition

interface DFlexDnDOpts {
  // ... other options.
  scroll?: Partial<ScrollOptions>;
}

Auto-Scroll Default Value

{
  "scroll": {
    "enable": true,
    "initialSpeed": 10,
    "threshold": {
      "vertical": 15,
      "horizontal": 15
    }
  }
}

Events

DFlex has three (3) types of custom events.

  1. DFlex Dragged Event.
  2. DFlex Interactivity Event.
  3. DFlex Siblings Event.

Event Usage

// DFlex event handler.
const onDFlexEvent = (e: DFlexEvents) => {
  // Do something.
  console.log(`onDFlexEvent: ${e.type}`, e.detail);
};

// Dragged Events.
const ON_OUT_CONTAINER = "$onDragOutContainer";
const ON_OUT_THRESHOLD = "$onDragOutThreshold";

//  Interactivity Events.
const ON_DRAG_OVER = "$onDragOver";
const ON_DRAG_LEAVE = "$onDragLeave";

// Sibling Events.
const ON_LIFT_UP = "$onLiftUpSiblings";
const ON_MOVE_DOWN = "$onMoveDownSiblings";

// Capture DFlex event.
document.addEventListener(
  ON_OUT_CONTAINER /** or another event */,
  onDFlexEvent
);

// Remove it later when dragging is done.
document.removeEventListener(
  ON_OUT_CONTAINER /** or another event */,
  onDFlexEvent
);

Dragged Event

It's an event related to capturing dragged positions. This event is fired when the dragged is out of its threshold position $onDragOutContainer or out of its container $onDragOutThreshold.

DraggedEvent interface

interface PayloadDraggedEvent {
  /** Returns element id in the registry  */
  id: string;

  /** Returns dragged temp index */
  index: number;
}

/** For dragged out of threshold or container event. */
type DFlexDraggedEvent = CustomEvent<PayloadDraggedEvent>;

Interactivity Event

It's an event related to capturing dragged interactions with other elements. This event is fired when the dragged is over another element $onDragOver or when the dragged is leaving the occupied position $onDragLeave.

InteractivityEvent interface
interface PayloadInteractivityEvent {
  /** Returns element id in the registry  */
  id: string;

  /** Returns element current index */
  index: number;

  /** Returns the element that triggered the event  */
  target: HTMLElement;
}

/** For dragged over an element or leaving an element. */
type DFlexInteractivityEvent = CustomEvent<PayloadInteractivityEvent>;

Siblings Event

It's an event related to capturing siblings' positions. This event is fired when the siblings are lifting up $onLiftUpSiblings or moving down $onMoveDownSiblings

SiblingsEvent interface
interface PayloadSiblingsEvent {
  /** Returns the index where the dragged left  */
  from: number;

  /** Returns the last index effected of the dragged leaving/entering  */
  to: number;

  /** Returns an array of sibling ids in order  */
  siblings: string[];
}

/** When dragged movement triggers the siblings up/down. */
type DFlexSiblingsEvent = CustomEvent<PayloadSiblingsEvent>;

Listeners

DFlex listeners are more generic than the custom events and responsible for monitoring the entire layout and reporting back to you.

DFlex has two (2) types of listeners:

  1. Layout state listener.
  2. Mutation listener.

Listener Usage

// app/index.js

const unsubscribeLayout = store.listeners.subscribe((e) => {
  console.info("new layout state", e);
}, "layoutState");

// call it later for clear listeners from memory.
unsubscribeLayout();

const unsubscribeMutation = store.listeners.subscribe((e) => {
  console.info("new mutation state", e);
}, "mutation");

// call it later for clear listeners from memory.
unsubscribeMutation();

Layout state listener

Responsible for monitoring any change that happens to layout interactivity.

Layout state listener interface

type LayoutState =
  | "pending" // when DnD is initiated but not activated yet.
  | "ready" // When clicking over the registered element. The element is ready but not being dragged.
  | "dragging" // as expected.
  | "dragEnd" // as expected.
  | "dragCancel"; // When releasing the drag without settling in the new position.

interface DFlexLayoutStateEvent {
  type: "layoutState";
  status: LayoutState;
}

Mutation listener

Responsible for monitoring DOM mutation that happens during reconciliation.

Mutation listener interface

type ElmMutationType = "committed";

interface DFlexElmMutationEvent {
  type: "mutation";
  status: ElmMutationType;
  payload: {
    target: HTMLElement; // HTML element container.
    ids: string[]; // Committed Elements' id in order.
  };
}

Advanced

getSerializedElm

DFlex elements are serialized and exported accordingly.

store.getSerializedElm(elmID: string): DFlexSerializedElement | null

type DFlexSerializedElement = {
  type: string;
  version: number;
  id: string;
  translate: PointNum | null;
  grid: PointNum;
  order: DFlexDOMGenOrder;
  initialPosition: AxesPoint;
  rect: BoxRectAbstract;
  hasTransformedFromOrigin: boolean;
  hasPendingTransformation: boolean;
  isVisible: boolean;
};

getSerializedScrollContainer

DFlex scroll containers are serialized and exported accordingly. You can get any scroll container for any registered element id.

store.getSerializedScrollContainer(elmID: string): DFlexSerializedScroll | null

type DFlexSerializedScroll = {
  type: string;
  version: number;
  key: string;
  hasOverFlow: AxesPoint<boolean>;
  hasDocumentAsContainer: boolean;
  scrollRect: AbstractBox;
  scrollContainerRect: AbstractBox;
  invisibleDistance: AbstractBox;
  visibleScreen: Dimensions;
};

commit

Commit changes to the DOM. commit will always do surgical reconciliation. and it's the same function that's used in the options

store.commit(): void

isLayoutAvailable

True when DFlex is not transforming any elements and not executing any task.

isLayoutAvailable(): boolean

unregister

safely removing element from store.

store.unregister(id: string): void

destroy

To destroy all DFlex instances. This is what you should do when you are done with DnD completely and your app is about to be closed.

store.destroy(): void;

Project Content πŸš€

DFlex DOM relations generator algorithm. It Generates relations between DOM elements based on element depth so all the registered DOM can be called inside registry without the need to call browser API. Read once, implement everywhere.

Core instance is the mirror of interactive element that includes all the properties and methods to manipulate the node.

A collection of shared functions. Mostly classes, and types that are used across the project.

DFex Store has main registry for all DOM elements that will be manipulated. It is a singleton object that is accessible from anywhere in the application. The initial release was generic but it only has the Core of the library since ^V3.

Light weight draggable element without extra functionalities that is responsible for interacting with the DOM and moving the affected element(s).

The main package that depends on the other packages. It is responsible for the magical logic of the library to introduce the drag and drop interactive functionality.

Documentation πŸ“–

For documentation, more information about DFlex and a live demo, be sure to visit the DFlex website https://www.dflex.dev/

Contribution 🌎

PRs are welcome, If you wish to help, you can learn more about how you can contribute to this project in the Contributing guide.

Work in progress πŸ”¨

DFlex is a work-in-progress project and currently in development.

License 🀝

DFlex is MIT License.

Author

Jalal Maskoun (@jalal246)

dflex's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar dwlooney avatar jalal246 avatar jerehut avatar pranay0302 avatar renovate[bot] avatar robertseidler avatar tepexic 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

dflex's Issues

Bug: not properly committing when migrating between scrollable containers

Video of the behavour:

05.10.2023_08.53.34_REC.mp4

When dragging an element from one scrollable container to another scrollable container, the dragged element is covered by the elements in the receiving container on release. The reason seems to be that the dropped element somehow persists the position: absolute CSS property in the receiving container.

If I make the containers shorter, i.e. non-scrollable, then the dragged element is properly placed in the container.

playground issues

Hello,

I tried running the playground locally and noticed all sorts of weird issues. Are some of these not expected to work? The /grid example was worse, I couldn't get it to sort at all, and often ended up in states like this:
2

The root example

<ContainerBasedEvent
  isHorizontal={false}
  isIncludeOneContainer={false}
/>

only works if the vertical space is enough to fit the whole list. Otherwise it throws Uncaught TypeError: this._innerThresholdInViewport is null. I saw similar error in my own application, where if I didn't have more than 10 items in the list, I'd get an error that this._outerThresholdInViewport was null (but it was called this.V but tracing the code looked like this method. Then I noticed a variable private static _MAX_NUM_OF_SIBLINGS_BEFORE_DYNAMIC_VISIBILITY = 10; so if you have fewer elements than that, then _outerThresholdInViewport will always stay null.

For more context, I'm attempting to implement sorting without React. My project is a Rails app using Stimulus JS. I've probably wired up some things wrong, but since many of the demos in the playground seemed off too, I wondered if maybe some things are still in flight. Is this project in a production ready state? Thanks!

npm install fails

I have cloned the repo and run npm install to setup the project but got this error:

D:\Projects\External\dflex>npm install
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: dflex-monorepo@undefined
npm ERR! Found: [email protected]
npm ERR! node_modules/vite
npm ERR!   dev vite@"^4.4.9" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer vite@"^2" from [email protected]
npm ERR! node_modules/vite-plugin-replace
npm ERR!   dev vite-plugin-replace@"^0.1.1" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR!
npm ERR! For a full report see:
npm ERR! C:\Users\......\AppData\Local\npm-cache\_logs\2023-10-03T13_05_02_947Z-eresolve-report.txt

npm ERR! A complete log of this run can be found in: C:\Users\......\AppData\Local\npm-cache\_logs\2023-10-03T13_05_02_947Z-debug-0.log

What am I doing wrong? I want to run the playgrounds - how can I do that?

After dragging is done, translate3d property still exists in dragged element's style attribute

After a dragged element is let go by mouseup event, the z-index: 99 and position: relative are removed from the style attribute, but the transform property is still there.

Yes, it's set to translate3d(0px, 0px, 0px), but it still messes up stacking context in cases where you have e.g. a dropdown inside those draggable elements. I fixed it temporarily with this code after dflexDnD.endDragging():

  setTimeout(()=>{
    dndCompRef.current.style.transform="";
  }, 50);

Which is of course just a hack. Instantly removing the attribute synchronously is somehow not working, probably overwritten later.

Maybe this is something that's intended for some reason I don't see yet. If it's not intended, I'd appreciate a quick "yes, this is a bug" from @jalal246 (or someone else more familiar with this codebase), maybe this is suited for my first OSS contribution :)

Feature: drag item and scroll

I would like to be able to drag item number 1 to below item number 1000 by dragging down. I would like to drag item number 1000 to above item number 1 by dragging the item up. Right now It does not have the option to scroll.

Bonus, make the speed variable based on distance of the drag from bottom of screen. The further the faster.

Add Vue template for DnD

This issue is dedicated to creating a template for the Vue framework.

I used create-react-app to create react playgrounds which I usually use to develop DFlex. But looking to publish a template for Vue, something like this repo: https://github.com/dflex-js/react-draggable-starter.

For the sake of productivity, creating a starter form scratch can be simpler than open PR directly to this rep. Both, of course, are welcomed πŸŽ‰πŸŽ‰πŸŽ‰

Animation demo

The homepage says that "animated transformation with each interaction" can be done with dflex; however, the demo doesn't have any animation. Can animations be added to the demo or to a separate demo?

Error when trying to add new DnDComponent while running: Uncaught TypeError: h2 is undefined

Everything works as long as all the elements are initialized from the beginning.

As soon as I add an element on runtime via javascript (and then also successfully register in the store), the next mousedown event logs this obsfuscated error and doesn't allow any drag and drop operations (not the old elements and also not the new ones).

The logged, obfuscated error:

Uncaught TypeError: h2 is undefined
    st dflex-dnd.mjs:1
    it dflex-dnd.mjs:1
    et dflex-dnd.mjs:1
    gt dflex-dnd.mjs:1
    onMouseDown DnDComponent.tsx:83
    React 23
    hydrate entry.client.tsx:7
    startTransition React
    hydrate entry.client.tsx:6
    requestIdleCallback handler* entry.client.tsx:17
2 dflex-dnd.mjs:1:27428

I used the example code that has this nice DnDComponent for React. I also found out the line in the component that's triggering the error:

        dflexDnD = new DnD(id, { x: clientX, y: clientY }, opts); //<-- this is line 83

I also noticed that the JavaScript-added element doesn't follow the data-index count of the other elements, but starts from 0 again (each additional javascript-added element then counts up 1, 2, 3 from there on again).

If I do

        console.log(store.getContainerByID(id));
        dflexDnD = new DnD(id, { x: clientX, y: clientY }, opts);

The logged container looks normal, same as before I dynamically add an element at runtime (where everything still worked). So the store does indeed contain this newly added element. Also when I add an element via javascript and then save and reload the page, everything works again, until I add another element.

What may I have forgotten to do? Unfortunately, my whole code is way too long, but the core part is mapping a list with each element mapping to a DnDComponent. As soon as I add one item to that list via JavaScript, it seems to mess up something.

I tried to read as much as possible in the codebase about how the new DnD constructor is, but nothing jumped my eye.

Drag and scrolling doesn't work

In the large list demo, drag the item 2 and move to the bottom of the list.
Then, while still dragging, scroll the container. The dragged item is not following the scroll, and it's becoming crazy.

Restricted element cause other elements to jump beneath

In the restricted demo, when dragging a restricted element (for example the "restricted bottom" element), to the left, the next element will jump up to take its place, even if the dragged element is still visible, causing the next element to become hidden/invisible to the user.

It's not very convenient to use.

v3.6.0 Draggable throws Error `can't access property "x", translate is undefined`

Some basic vue example:

<template>
  <div
    :id="id"
    ref="elRoot"
    class="DragAndDrop"
    @mousedown.stop.prevent="onMouseDown"
  ></div>
</template>

<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue'
import { Draggable, store } from '@dflex/draggable'
import cuid from 'cuid'

export default defineComponent({
  name: 'DragAndDrop',
  components: {},

  setup() {
    const id = `draggable-button.${cuid.slug()}`
    let draggedEvent: Draggable
    const elRoot = ref()

    const onMouseDown = (event: MouseEvent) => {
      draggedEvent = new Draggable(id, { x: event.clientX, y: event.clientY })

      document.addEventListener('mouseup', onMouseUp)
      document.addEventListener('mousemove', onMouseMove)
    }

    const onMouseMove = (event: MouseEvent) => {
      if (!draggedEvent) return

      draggedEvent.dragAt(event.clientX, event.clientY)
    }

    const onMouseUp = () => {
      if (draggedEvent) {
        draggedEvent.endDragging()

        document.removeEventListener('mouseup', onMouseUp)
        document.removeEventListener('mousemove', onMouseMove)
      }
    }

    onMounted(() => {
      store.register(id)
    })

    return {
      id,
      elRoot,
      onMouseDown,
      onMouseMove,
    }
  },
})
</script>

<style lang="scss">
.DragAndDrop {
  $block: &;

  width: 200px;
  height: 100px;
  border: 2px solid fuchsia;
  border-radius: 10px;
  background-color: rgba(fuchsia, 0.1);
}
</style>

As soon as the onMouseDown is fired, there is an error:

can't access property "x", translate is undefined

It happens with 3.6.0 but works fine with 3.5.4. I was trying to create a reproduction on Codesandbox but for some reason I can't add @dflex/draggable as a dependency there…

Please update the documentation and release notes

Dear @jalal246 ,

Could you please update the documentation and the release note pages with the new features you added lately?

I was away for some time and lost grip of the functionality of DFlex, so now it would be more difficult for me to gather all the new things you added. I would rather prefer to refer to the docs.

Thank you!

Bug in example demo

I encountered a bug while testing the live demo of this library. The bug occurs when a list item is dragged and dropped exactly at the top of other list item in a specific manner. It seems like the dflex is creating additional unknown nodes to the list. Screenshots:
Screenshot 2023-08-21 at 8 56 32 PM
Screenshot 2023-08-21 at 8 57 15 PM
Screenshot 2023-08-21 at 9 29 58 PM

Cannot destructure property 'translate' of 'this.draggedElm' as it is undefined

I have the following Vue component:

<template>
  <component :is="tag" style="touch-action: none" @pointerdown="onPointerDown">
    <template v-for="slot of Object.keys($slots)" #[slot]="scope">
      <slot :name="slot" v-bind="scope || {}" />
    </template>
  </component>
</template>

<script setup>
import { onUnmounted } from 'vue'
import { store, DnD } from '@dflex/dnd'

const props = defineProps({
  tag: { type: [String, Object], required: true },
  id: { type: String, required: true }
})

store.register({ id: props.id })
onUnmounted(() => {
  store.unregister(props.id)
})
let dndSession = null

function onPointerDown (event) {
  event.currentTarget.setPointerCapture(event.pointerId)
  event.currentTarget.addEventListener('pointermove', onPointerMove)
  event.currentTarget.addEventListener('pointerup', onPointerUp)
  dndSession = new DnD(props.id, { x: event.clientX, y: event.clientY })
}
function onPointerMove (event) {
  // dndSession.dragAt(event.clientX, event.clientY)
}
function onPointerUp (event) {
  event.currentTarget.removeEventListener('pointermove', onPointerMove)
  event.currentTarget.removeEventListener('pointerup', onPointerUp)
  dndSession.endDragging()
  dndSession = null
}
</script>

When I click on the element (pointerdown) I get the following error:
image

Am I doing something wrong?

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.