Skip to content
This repository has been archived by the owner on Aug 6, 2024. It is now read-only.

feat: added item freeze functionality to draggable list #279

Merged
merged 18 commits into from
Feb 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
946fd82
feat: added item freeze functionality to draggable list
keyurparalkar Dec 13, 2022
a4eac7e
fix: item dragging issue in draggable list
keyurparalkar Dec 14, 2022
f775824
chore: revert draggablelist.stories.tsx
keyurparalkar Dec 14, 2022
723e4b7
Merge branch 'release' of github.com:appsmithorg/design-system into f…
albinAppsmith Dec 14, 2022
eafebbd
Merge branch 'main' of github.com:appsmithorg/design-system into feat…
albinAppsmith Dec 14, 2022
cee9d38
Create olive-impalas-compare.md
albinAppsmith Dec 15, 2022
ff1c1d5
fix: addressed QA callouts
keyurparalkar Dec 16, 2022
c82b85c
fix: updated condition for unfrozenItems
keyurparalkar Dec 26, 2022
4ac1b3b
Merge branch 'release' of github.com:appsmithorg/design-system into f…
albinAppsmith Dec 26, 2022
9fb1903
Merge branch 'main' of github.com:appsmithorg/design-system into feat…
albinAppsmith Dec 26, 2022
6fdd488
fix: added new logic to disable drag for sticky items
keyurparalkar Jan 5, 2023
344c517
chore: added comments
keyurparalkar Jan 5, 2023
e3b22c5
Merge branch 'release' of github.com:appsmithorg/design-system into f…
albinAppsmith Jan 5, 2023
cfebac9
Merge branch 'main' of github.com:appsmithorg/design-system into feat…
albinAppsmith Jan 5, 2023
c1ca435
fix: renamed variable
keyurparalkar Jan 9, 2023
e0221b9
feat: added substract icon
keyurparalkar Jan 24, 2023
ce15b97
Merge branch 'release' of github.com:appsmithorg/design-system into f…
albinAppsmith Jan 24, 2023
c97264d
Merge branch 'release' into feat/feat-sticky-draggable-list
keyurparalkar Feb 10, 2023
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
5 changes: 5 additions & 0 deletions .changeset/olive-impalas-compare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@appsmithorg/design-system": patch
---

feat: added item freeze functionality to draggable list
6 changes: 6 additions & 0 deletions packages/design-system-old/src/ControlIcons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import SettingsIcon from "remixicon-react/Settings5LineIcon";
import EyeIcon from "remixicon-react/EyeLineIcon";
import EyeOffIcon from "remixicon-react/EyeOffLineIcon";
import CloseIcon from "remixicon-react/CloseLineIcon";
import SubtractIcon from "remixicon-react/SubtractFillIcon";

/* eslint-disable react/display-name */

Expand Down Expand Up @@ -400,6 +401,11 @@ export const ControlIcons: {
<QuestionIcon />
</IconWrapper>
),
COLUMN_UNFREEZE: (props: IconProps) => (
<IconWrapper {...props}>
<SubtractIcon />
</IconWrapper>
),
};

export type ControlIconName = keyof typeof ControlIcons;
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,16 @@ DraggableList.args = {
{
id: 1,
name: "Item 1",
isDragDisabled: true,
},
{
id: 2,
name: "Item 2",
},
{
id: 3,
name: "Item 3",
},
],
keyAccessor: "id",
onUpdate: (items) => {
Expand Down
186 changes: 113 additions & 73 deletions packages/design-system-old/src/DraggableList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,85 +131,118 @@ export function DraggableList(props: any) {

const bind: any = useDrag<any>((props: any) => {
const originalIndex = props.args[0];
const isDragDisabled = props.args[1];
const curIndex = order.current.indexOf(originalIndex);
const pointerFromTop = props.xy[1];
/**
* Checking for props.distance > 0 because:
* this container is the first recipient of all mouse events
* for self and children. Consequently, it treats a click as a drag request
* and updates the position of the list item.
* Checking for drag distance prevents this behavior.
*/
if (listRef && listRef.current && props?.distance > 0) {
const containerCoordinates = listRef?.current.getBoundingClientRect();
const container = listRef.current;
if (containerCoordinates) {
const containerDistanceFromTop = containerCoordinates.top;
if (props.dragging) {
if (pointerFromTop < containerDistanceFromTop + itemHeight / 2) {
// Scroll inside container till first element in list is completely visible
if (container.scrollTop > 0) {
container.scrollTop -= itemHeight / 10;
}
} else if (
pointerFromTop >=
containerDistanceFromTop + container.clientHeight - itemHeight / 2
) {
// Scroll inside container till container cannnot be scrolled more towards bottom
if (
container.scrollTop <=
springs.length * itemHeight -
container.clientHeight -
itemHeight / 2

if (isDragDisabled) {
props.cancel();
} else {
/**
* Checking for props.distance > 0 because:
* this container is the first recipient of all mouse events
* for self and children. Consequently, it treats a click as a drag request
* and updates the position of the list item.
* Checking for drag distance prevents this behavior.
*/
if (listRef && listRef.current && props?.distance > 0) {
const containerCoordinates = listRef?.current.getBoundingClientRect();
const container = listRef.current;
if (containerCoordinates) {
const containerDistanceFromTop = containerCoordinates.top;
if (props.dragging) {
if (pointerFromTop < containerDistanceFromTop + itemHeight / 2) {
// Scroll inside container till first element in list is completely visible
if (container.scrollTop > 0) {
container.scrollTop -= itemHeight / 10;
}
} else if (
pointerFromTop >=
containerDistanceFromTop + container.clientHeight - itemHeight / 2
) {
container.scrollTop += itemHeight / 10;
// Scroll inside container till container cannnot be scrolled more towards bottom
if (
container.scrollTop <=
springs.length * itemHeight -
container.clientHeight -
itemHeight / 2
) {
container.scrollTop += itemHeight / 10;
}
}
}
// finding distance of current pointer from the top of the container to find the final position
// currIndex * itemHeight for the initial position
// subtraction formar with latter for displacement
displacement.current =
pointerFromTop -
containerDistanceFromTop +
container.scrollTop -
curIndex * itemHeight -
itemHeight / 2;
// finding distance of current pointer from the top of the container to find the final position
// currIndex * itemHeight for the initial position
// subtraction formar with latter for displacement
displacement.current =
pointerFromTop -
containerDistanceFromTop +
container.scrollTop -
curIndex * itemHeight -
itemHeight / 2;

if (!dragging.current && Math.abs(displacement.current) > 10) {
dragging.current = props.dragging;
updateDragging && updateDragging(dragging.current);
}
} else {
if (dragging.current) {
dragging.current = props.dragging;
updateDragging && updateDragging(dragging.current);
if (!dragging.current && Math.abs(displacement.current) > 10) {
dragging.current = props.dragging;
updateDragging && updateDragging(dragging.current);
}
} else {
if (dragging.current) {
dragging.current = props.dragging;
updateDragging && updateDragging(dragging.current);
}
}
}

const curRow = clamp(
Math.round(
(curIndex * itemHeight + displacement.current) / itemHeight,
),
0,
items.length - 1,
);
const newOrder = [...order.current];
newOrder.splice(curRow, 0, newOrder.splice(curIndex, 1)[0]);
setSprings(
dragIdleSpringStyles(newOrder, {
down: props.down,
originalIndex,
curIndex,
y: Math.abs(displacement.current) > 10 ? displacement.current : 0,
itemHeight,
}),
);
if (curRow !== curIndex) {
// Feed springs new style data, they'll animate the view without causing a single render
if (!props.down) {
order.current = newOrder;
setSprings(updateSpringStyles(order.current, itemHeight));
debounce(onDrop, 400)(curIndex, curRow);
const curRow = clamp(
Math.round(
(curIndex * itemHeight + displacement.current) / itemHeight,
),
0,
items.length - 1,
);

/**
* We check if the final position's item's dragging is enabled.
*/
if (
!items[curRow].hasOwnProperty("isDragDisabled") ||
(items[curRow].hasOwnProperty("isDragDisabled") &&
!items[curRow].isDragDisabled)
) {
const newOrder = [...order.current];
newOrder.splice(curRow, 0, newOrder.splice(curIndex, 1)[0]);
setSprings(
dragIdleSpringStyles(newOrder, {
down: props.down,
originalIndex,
curIndex,
y:
Math.abs(displacement.current) > 10
? displacement.current
: 0,
itemHeight,
}),
);
if (curRow !== curIndex) {
// Feed springs new style data, they'll animate the view without causing a single render
if (!props.down) {
order.current = newOrder;
setSprings(updateSpringStyles(order.current, itemHeight));
debounce(onDrop, 400)(curIndex, curRow);
}
}
} else {
// retain the order if an item's drag is disabled.
setSprings(
dragIdleSpringStyles(order.current, {
down: props.down,
originalIndex,
curIndex,
y:
Math.abs(displacement.current) > 10
? displacement.current
: 0,
itemHeight,
}),
);
}
}
}
Expand Down Expand Up @@ -237,8 +270,15 @@ export function DraggableList(props: any) {
}}
>
{springs.map(({ scale, y, zIndex }, i) => (
/**
* Passing 2nd arg to bind is a boolean value that represents if the item's drag is disabled or not.
*/
<animated.div
{...bind(i)}
{...bind(
i,
items[i].hasOwnProperty("isDragDisabled") &&
items[i].isDragDisabled,
)}
data-rbd-draggable-id={items[i].id}
//having a key of items[i].id will break in few places,
//eg, primary columns in propertyPane of Table widget
Expand Down