MCPcopy Index your code
hub / github.com/dflex-js/dflex

github.com/dflex-js/dflex @v3.9.5

Chat with this repo
repository ↗ · DeepWiki ↗ · release v3.9.5 ↗ · + Follow
610 symbols 1,650 edges 243 files 96 documented · 16%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

DFlex is a Javascript library for modern Drag and Drop apps

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.

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

type DFlexSerializedScroll = { type: string; version: number; key: string; hasOverFlow: AxesPoint; hasDocumentAsContainer: boolean; scrollRect: AbstractBox; scrol

Extension points exported contracts — how you extend this code

Props (Interface)
(no doc)
packages/dflex-dnd-playground/src/components/DFlexDnDComponent.tsx
Keys (Interface)
(no doc)
packages/dflex-dom-gen/src/Generator.ts
Keys (Interface)
(no doc)
packages/dflex-core-instance/src/Element/DFlexCoreElement.ts
Dimensions (Interface)
(no doc)
packages/dflex-utils/src/types.ts
Props (Interface)
(no doc)
packages/dflex-next-playground/src/components/TodoItem.tsx
Document (Interface)
(no doc)
packages/dflex-dnd/src/types.ts
Props (Interface)
(no doc)
packages/dflex-dnd-playground/src/components/essential/ListMigration.tsx
Order (Interface)
(no doc)
packages/dflex-dom-gen/src/Generator.ts

Core symbols most depended-on inside this repo

moveDragged
called by 83
packages/dflex-dnd-playground/tests/utils/index.ts
assertDefaultChildrenIndex
called by 50
packages/dflex-dnd-playground/tests/utils/index.ts
getDraggedRect
called by 48
packages/dflex-dnd-playground/tests/utils/index.ts
has
called by 35
packages/dflex-dnd/src/LayoutManager/DFlexDnDExportedStore.ts
assertChildrenOrderIDs
called by 29
packages/dflex-dnd-playground/tests/utils/index.ts
getElmSiblingsByKey
called by 25
packages/dflex-dnd/src/LayoutManager/DFlexDnDExportedStore.ts
initialize
called by 24
packages/dflex-dnd-playground/tests/utils/index.ts
setStyleProperty
called by 23
packages/dflex-utils/src/computedStyleUtils/computedStyleUtils.ts

Shape

Method 298
Function 205
Class 70
Interface 37

Languages

TypeScript100%

Modules by API surface

packages/dflex-core-instance/src/Element/DFlexCoreElement.ts40 symbols
packages/dflex-dnd/src/LayoutManager/DFlexDnDStore.ts30 symbols
packages/dflex-core-instance/src/Container/DFlexScrollContainer.ts26 symbols
packages/dflex-dom-gen/src/Generator.ts25 symbols
packages/dflex-utils/src/DFlexCycle/DFlexCycle.ts22 symbols
packages/dflex-utils/src/Box/BoxNum.ts20 symbols
packages/dflex-store/src/DFlexBaseStore.ts19 symbols
packages/dflex-utils/src/computedStyleUtils/computedStyleUtils.ts18 symbols
packages/dflex-dnd/src/Draggable/DraggableAxes.ts18 symbols
packages/dflex-dnd/src/Mechanism/DFlexPositionUpdater.ts17 symbols
packages/dflex-dnd/src/Mechanism/DFlexMechanismController.ts16 symbols
packages/dflex-utils/src/TaskQueue/TaskQueue.ts15 symbols

For agents

$ claude mcp add dflex \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact