diff --git a/frontend/src/AppBuilder/AppCanvas/Container.jsx b/frontend/src/AppBuilder/AppCanvas/Container.jsx
index e622e1a2cd..fcc0a95d4e 100644
--- a/frontend/src/AppBuilder/AppCanvas/Container.jsx
+++ b/frontend/src/AppBuilder/AppCanvas/Container.jsx
@@ -20,6 +20,7 @@ import NoComponentCanvasContainer from './NoComponentCanvasContainer';
import { RIGHT_SIDE_BAR_TAB } from '../RightSideBar/rightSidebarConstants';
import { isPDFSupported } from '@/_helpers/appUtils';
import toast from 'react-hot-toast';
+import useSortedComponents from '../_hooks/useSortedComponents';
//TODO: Revisit the logic of height (dropRef)
@@ -146,6 +147,8 @@ export const Container = React.memo(
[setLastCanvasClickPosition]
);
+ const sortedComponents = useSortedComponents(components, currentLayout, id);
+
return (
- {components.map((id) => (
+ {sortedComponents.map((id) => (
state.setReorderContainerChildren, shallow);
useEffect(() => {
const selectedSet = new Set(selectedComponents);
@@ -536,6 +537,7 @@ export default function Grid({ gridWidth, currentLayout }) {
})
);
}
+ setReorderContainerChildren(draggedOverElemId ?? 'canvas');
} catch (error) {
console.error('Error dragging group', error);
}
@@ -696,6 +698,7 @@ export default function Grid({ gridWidth, currentLayout }) {
resizeData.gw = _gridWidth;
}
handleResizeStop([resizeData]);
+ setReorderContainerChildren(currentWidget?.parent ?? 'canvas');
} catch (error) {
console.error('ResizeEnd error ->', error);
}
@@ -775,6 +778,11 @@ export default function Grid({ gridWidth, currentLayout }) {
ev.target.style.transform = `translate(${posX}px, ${posY}px)`;
});
}
+
+ const groupParentId =
+ boxList.find(({ id }) => id === groupResizeDataRef.current[0].target.id)?.parent ?? 'canvas';
+ setReorderContainerChildren(groupParentId);
+
groupResizeDataRef.current = [];
reloadGrid();
} catch (error) {
@@ -841,6 +849,8 @@ export default function Grid({ gridWidth, currentLayout }) {
useStore.getState().setDraggingComponentId(null);
isDraggingRef.current = false;
}
+
+ const oldParentId = boxList.find((b) => b.id === e.target.id)?.parent ?? 'canvas';
prevDragParentId.current = null;
newDragParentId.current = null;
setDragParentId(null);
@@ -880,6 +890,12 @@ export default function Grid({ gridWidth, currentLayout }) {
// Apply transform for smooth transition
e.target.style.transform = `translate(${left}px, ${top}px)`;
+ // Force reordering of conatiner if the parent has not changed
+ const newParentId = target.slotId === 'real-canvas' ? 'canvas' : target.slotId;
+ if (oldParentId === newParentId) {
+ setReorderContainerChildren(newParentId);
+ }
+
// Select the dragged component after drop
setTimeout(() => setSelectedComponents([dragged.id]));
} catch (error) {
diff --git a/frontend/src/AppBuilder/_hooks/useSortedComponents.js b/frontend/src/AppBuilder/_hooks/useSortedComponents.js
new file mode 100644
index 0000000000..9877206444
--- /dev/null
+++ b/frontend/src/AppBuilder/_hooks/useSortedComponents.js
@@ -0,0 +1,49 @@
+import { useMemo, useRef } from 'react';
+import useStore from '@/AppBuilder/_stores/store';
+import { shallow } from 'zustand/shallow';
+
+const useSortedComponents = (components, currentLayout, id) => {
+ const getCurrentPageComponents = useStore((state) => state.getCurrentPageComponents, shallow);
+ const reorderContainerChildren = useStore((state) => state.reorderContainerChildren, shallow);
+ const prevForceUpdateRef = useRef(0);
+ const prevComponentsOrder = useRef(components);
+
+ // Function to sort the components based on position in container for tab navigation
+ const sortedComponents = useMemo(() => {
+ const { triggerUpdate, containerId } = reorderContainerChildren;
+
+ // If a forced update occurred for a different container, return the previous order
+ const isForcedUpdate = prevForceUpdateRef.current !== triggerUpdate;
+ if (isForcedUpdate) {
+ prevForceUpdateRef.current = triggerUpdate;
+ if (containerId !== id) {
+ return prevComponentsOrder.current;
+ }
+ }
+
+ const currentPageComponents = getCurrentPageComponents();
+
+ const newComponentsOrder = [...components].sort((a, b) => {
+ const aTop = currentPageComponents?.[a]?.layouts?.[currentLayout]?.top;
+ const bTop = currentPageComponents?.[b]?.layouts?.[currentLayout]?.top;
+ if (aTop !== bTop) {
+ return aTop - bTop;
+ } else {
+ const aLeft = currentPageComponents?.[a]?.layouts?.[currentLayout]?.left;
+ const bLeft = currentPageComponents?.[b]?.layouts?.[currentLayout]?.left;
+ if (aLeft !== bLeft) {
+ return aLeft - bLeft;
+ }
+ return 0;
+ }
+ });
+
+ prevComponentsOrder.current = newComponentsOrder;
+ return newComponentsOrder;
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [components, currentLayout, reorderContainerChildren.triggerUpdate, id]);
+
+ return sortedComponents;
+};
+
+export default useSortedComponents;
diff --git a/frontend/src/AppBuilder/_stores/slices/gridSlice.js b/frontend/src/AppBuilder/_stores/slices/gridSlice.js
index 642266a32b..37de5cf81a 100644
--- a/frontend/src/AppBuilder/_stores/slices/gridSlice.js
+++ b/frontend/src/AppBuilder/_stores/slices/gridSlice.js
@@ -8,6 +8,10 @@ const initialState = {
lastCanvasIdClick: '',
lastCanvasClickPosition: null,
draggingComponentId: null,
+ reorderContainerChildren: {
+ containerId: null,
+ triggerUpdate: 0,
+ },
};
export const createGridSlice = (set, get) => ({
@@ -73,4 +77,10 @@ export const createGridSlice = (set, get) => ({
setLastCanvasClickPosition: (position) => {
set({ lastCanvasClickPosition: position });
},
+ setReorderContainerChildren: (containerId) => {
+ // Function to trigger reordering of specific container for tab navigation
+ set((state) => ({
+ reorderContainerChildren: { containerId, triggerUpdate: state.reorderContainerChildren.triggerUpdate + 1 },
+ }));
+ },
});