Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/core-instance/src/CoreInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class CoreInstance extends AbstractInstance implements CoreInstanceInterface {

isVisible: boolean;

isInjected?: true;

hasToTransform!: boolean;

animatedFrame: number | null;
Expand All @@ -50,6 +52,7 @@ class CoreInstance extends AbstractInstance implements CoreInstanceInterface {

super(element, opts);

this.isInjected = opts.isInjected;
this.order = order;
this.keys = keys;
this.depth = depth;
Expand Down
10 changes: 10 additions & 0 deletions packages/core-instance/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
export interface AbstractOpts {
isInitialized: boolean;
isPaused: boolean;
isInjected?: true;
}

export type AbstractInput = {
Expand Down Expand Up @@ -102,6 +103,15 @@ export interface CoreInstanceInterface extends AbstractInterface {
/** Element visibility in the scroll container. */
isVisible: boolean;

/**
* True when element is injected in the registry.
* Represents the higher node element in the registered tree and prevents
* recursive fetching child/parent.
* So when the store reads `isInjected: true` it knows this is it and whe have
* to stop fetching higher nodes.
*/
isInjected?: true;

/** Animated frame if the element is transforming */
readonly animatedFrame: number | null;

Expand Down
6 changes: 4 additions & 2 deletions packages/dnd/src/DnD.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ class DnD extends Droppable {

const options = extractOpts(opts);

const { SK } = store.registry[id].keys;
const {
keys: { SK },
} = store.registry[id];

if (!SK) {
throw new Error(`DFlex: unable to find element list key in the Store.`);
Expand All @@ -48,7 +50,7 @@ class DnD extends Droppable {
* In case it is not already initiated in the store. We do it here guarantee
* all the branch is updated.
*/
store.initSiblingsScrollAndVisibilityIfNecessary(SK);
store.onLoadListeners();

const draggable = new DraggableInteractive(
id,
Expand Down
78 changes: 61 additions & 17 deletions packages/dnd/src/DnDStore/DnDStoreImp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class DnDStoreImp extends Store implements DnDStoreInterface {

layoutState: DnDStoreInterface["layoutState"];

/** has list of child-id that needs parent container. */
#nodesNeedParents: string[];

private events: Events;

private isDOM: boolean;
Expand Down Expand Up @@ -73,6 +76,8 @@ class DnDStoreImp extends Store implements DnDStoreInterface {
this.siblingsGrid = {};
this.siblingsGridContainer = {};

this.#nodesNeedParents = [];

this.layoutState = "pending";

// @ts-expect-error Should be initialized when calling DnD instance.
Expand Down Expand Up @@ -155,7 +160,7 @@ class DnDStoreImp extends Store implements DnDStoreInterface {

updateElementVisibility(
elmID: string,
parenID: string,
parentID: string | null,
scroll: ScrollInterface,
allowDynamicVisibility: boolean,
permitExceptionToOverride: boolean
Expand All @@ -174,6 +179,12 @@ class DnDStoreImp extends Store implements DnDStoreInterface {
this.registry[elmID].keys.SK,
this.registry[elmID].offset!
);

if (parentID) {
this.registry[parentID].assignBoundaries(
this.registry[elmID].offset!
);
}
}
}

Expand Down Expand Up @@ -244,25 +255,23 @@ class DnDStoreImp extends Store implements DnDStoreInterface {
const firstElemID = branch[0];

// Check the parent of first element.
const { parent } = this.getElmTreeById(firstElemID);
const { parent, element } = this.getElmTreeById(firstElemID);

let parentID: string;
let parentID: string | null = null;

/**
* If parent is not registered, but children are then extract it and use it.
* If parent is not registered, and element not injected in the registry.
*/
if (!parent) {
const childInstance = this.registry[firstElemID];
this.register({
ref: childInstance.getELmParentRef()!,
depth: childInstance.depth + 1,
});

({ id: parentID } = this.getElmTreeById(firstElemID).parent!);
} else {
parentID = parent.id;
if (!parent && !element.isInjected) {
this.#nodesNeedParents.push(firstElemID);

// No need to continue, because the parent is not registered and we cant
// detect the boundaries rect.
return;
}

parentID = parent?.id || null;

branch.forEach((elmID, i) => {
if (elmID.length > 0) {
const permitExceptionToOverride = i > prevIndex;
Expand Down Expand Up @@ -400,6 +409,7 @@ class DnDStoreImp extends Store implements DnDStoreInterface {

if (scroll.allowDynamicVisibility) {
this.updateBranchVisibility(key, true);

scroll.scrollEventCallback = this.updateBranchVisibility;
} else {
this.updateBranchVisibility(key, false);
Expand All @@ -410,6 +420,37 @@ class DnDStoreImp extends Store implements DnDStoreInterface {
Object.keys(this.DOMGen.branches).forEach((branchKey) => {
this.initSiblingsScrollAndVisibilityIfNecessary(branchKey);
});

this.#nodesNeedParents.forEach((id) => {
const childInstance = this.registry[id];

const ref = childInstance.getELmParentRef();

if (ref) {
this.register(
{
ref,
depth: childInstance.depth + 1,
},
true
);
}
});

this.#nodesNeedParents.forEach((id) => {
const {
keys: { SK },
} = this.registry[id];

this.updateBranchVisibility(
SK,
this.siblingsScrollElement[SK].allowDynamicVisibility
);
});

if (this.#nodesNeedParents.length > 0) {
this.#nodesNeedParents = [];
}
}

#assignSiblingsGrid(id: string, SK: string, rect: RectDimensions) {
Expand Down Expand Up @@ -548,7 +589,7 @@ class DnDStoreImp extends Store implements DnDStoreInterface {
*
* @param element -
*/
register(element: RegisterInput) {
register(element: RegisterInput, isInjected?: true) {
const hasRef = !!element.ref;

if (!hasRef && !element.id) {
Expand Down Expand Up @@ -599,6 +640,7 @@ class DnDStoreImp extends Store implements DnDStoreInterface {
depth: element.depth || 0,
ref: element.ref,
isInitialized: hasRef,
isInjected,
isPaused: true,
scrollX: 0,
scrollY: 0,
Expand Down Expand Up @@ -647,7 +689,7 @@ class DnDStoreImp extends Store implements DnDStoreInterface {

const {
keys: { SK, PK },
order: { parent: pi },
order,
} = element;

/**
Expand All @@ -661,7 +703,9 @@ class DnDStoreImp extends Store implements DnDStoreInterface {
*/
let parent = null;
if (parents !== undefined) {
const parentsID = Array.isArray(parents) ? parents[pi] : parents;
const parentsID = Array.isArray(parents)
? parents[order.parent]
: parents;
parent = this.registry[parentsID as string];
}

Expand Down
56 changes: 50 additions & 6 deletions packages/dnd/src/Draggable/DraggableAxes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,46 @@ class DraggableAxes
siblings !== null &&
(opts.restrictionsStatus.isContainerRestricted ||
opts.restrictionsStatus.isSelfRestricted);

this.#iniLayoutsThreshold();
}

#iniLayoutsThreshold() {
const {
offset: { width, height },
currentPosition,
id,
} = this.draggedElm;

this.threshold.setMainThreshold(id, {
width,
height,
left: currentPosition.x,
top: currentPosition.y,
});

const {
branches: { parents },
} = store.getElmTreeById(id);

(Array.isArray(parents) ? parents : [parents]).forEach((parentID) => {
if (!parentID) return;

const { boundaries } = store.registry[parentID];

if (!boundaries) {
if (process.env.NODE_ENV !== "production") {
// eslint-disable-next-line no-console
throw new Error(
`Unable to find boundaries Rect for parent ${parentID}`
);
}

return;
}

this.threshold.setContainerThreshold(parentID, boundaries);
});
}

private axesYFilter(
Expand Down Expand Up @@ -180,15 +220,19 @@ class DraggableAxes
let filteredY = y;
let filteredX = x;

const { SK } = store.registry[this.draggedElm.id].keys;
const { id } = this.draggedElm;

const {
keys: { SK },
} = store.registry[id];

if (this.axesFilterNeeded) {
const {
top,
bottom,
left: maxLeft,
right: minRight,
} = store.siblingsBoundaries[SK];
} = store.getElmTreeById(id).parent!.boundaries!;

if (this.restrictionsStatus.isContainerRestricted) {
filteredX = this.axesXFilter(
Expand Down Expand Up @@ -256,15 +300,15 @@ class DraggableAxes
);
}

isOutThreshold(SK?: string) {
isOutThreshold(parentID?: string) {
const {
id,
offset: { height, width },
} = this.draggedElm;

const { x, y } = this.positionPlaceholder;

const key = SK || id;
const key = parentID || id;

return (
this.threshold.isOutThresholdV(key, y, y + height) ||
Expand All @@ -283,11 +327,11 @@ class DraggableAxes
}

isNotSettled() {
const { SK } = store.registry[this.draggedElm.id].keys;
const { id } = store.getElmTreeById(this.draggedElm.id).parent!;

return (
!this.#isLeavingFromTail() &&
(this.isOutThreshold() || this.isOutThreshold(SK))
(this.isOutThreshold() || this.isOutThreshold(id))
);
}
}
Expand Down
5 changes: 5 additions & 0 deletions packages/dnd/test/Store/__snapshots__/dndStore.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Object {
"depth": 0,
"id": "id-1",
"isInitialized": true,
"isInjected": undefined,
"isPaused": true,
"isVisible": false,
"keys": Object {
Expand All @@ -27,6 +28,7 @@ Object {
"depth": 0,
"id": "id-2",
"isInitialized": true,
"isInjected": undefined,
"isPaused": true,
"isVisible": false,
"keys": Object {
Expand All @@ -47,6 +49,7 @@ Object {
"depth": 0,
"id": "id-3",
"isInitialized": true,
"isInjected": undefined,
"isPaused": true,
"isVisible": false,
"keys": Object {
Expand All @@ -67,6 +70,7 @@ Object {
"depth": 0,
"id": "id-4",
"isInitialized": true,
"isInjected": undefined,
"isPaused": true,
"isVisible": false,
"keys": Object {
Expand Down Expand Up @@ -101,6 +105,7 @@ Object {
"depth": 0,
"id": "id-1",
"isInitialized": true,
"isInjected": undefined,
"isPaused": true,
"isVisible": false,
"keys": Object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Object {
"hasToTransform": false,
"id": "id-0",
"isInitialized": true,
"isInjected": undefined,
"isPaused": false,
"isVisible": true,
"keys": Object {
Expand Down
3 changes: 2 additions & 1 deletion packages/store/src/Store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Store {
}

private submitElementToRegistry(element: RegisterInput) {
const { id, depth, isPaused, isInitialized, ...rest } = element;
const { id, depth, isPaused, isInitialized, isInjected, ...rest } = element;

const { order, keys } = this.DOMGen.getElmPointer(id, depth);

Expand All @@ -38,6 +38,7 @@ class Store {
this.registry[id] = new CoreInstance(coreElement, {
isInitialized,
isPaused,
isInjected,
});
}

Expand Down
1 change: 1 addition & 0 deletions packages/store/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export type RegisterInput = {
depth: number;
isInitialized: boolean;
isPaused: boolean;
isInjected?: true;
scrollX: number;
scrollY: number;
};
Expand Down
Loading