From cc84324c40628c9c337d7a3a2ec866400c5327d6 Mon Sep 17 00:00:00 2001 From: Nakul Nagargade Date: Thu, 13 Feb 2025 17:02:06 +0530 Subject: [PATCH 1/9] Fix gutter issue at the bottom of the container --- .../src/AppBuilder/AppCanvas/Container.jsx | 17 ++++++++++++--- .../src/AppBuilder/AppCanvas/Grid/Grid.jsx | 2 +- .../src/AppBuilder/AppCanvas/RenderWidget.jsx | 4 ++-- .../AppBuilder/AppCanvas/WidgetWrapper.jsx | 2 +- .../AppCanvas/appCanvasConstants.js | 8 +++++++ frontend/src/AppBuilder/Widgets/Container.jsx | 15 ++++++++++--- .../AppBuilder/_stores/slices/gridSlice.js | 2 ++ frontend/src/Editor/DraggableBox.jsx | 4 ++-- frontend/src/Editor/SubContainer.jsx | 4 ++-- frontend/src/_stores/gridStore.js | 21 ------------------- 10 files changed, 44 insertions(+), 35 deletions(-) diff --git a/frontend/src/AppBuilder/AppCanvas/Container.jsx b/frontend/src/AppBuilder/AppCanvas/Container.jsx index fc163939f6..c9466dc1dd 100644 --- a/frontend/src/AppBuilder/AppCanvas/Container.jsx +++ b/frontend/src/AppBuilder/AppCanvas/Container.jsx @@ -6,7 +6,15 @@ import useStore from '@/AppBuilder/_stores/store'; import { shallow } from 'zustand/shallow'; import { useDrop } from 'react-dnd'; import { addChildrenWidgetsToParent, addNewWidgetToTheEditor, computeViewerBackgroundColor } from './appCanvasUtils'; -import { CANVAS_WIDTHS, NO_OF_GRIDS, WIDGETS_WITH_DEFAULT_CHILDREN } from './appCanvasConstants'; +import { + CANVAS_WIDTHS, + NO_OF_GRIDS, + WIDGETS_WITH_DEFAULT_CHILDREN, + GRID_HEIGHT, + CONTAINER_CANVAS_PADDING, + CONTAINER_CANVAS_BORDER_WIDTH, + BOX_PADDING, +} from './appCanvasConstants'; import { useGridStore } from '@/_stores/gridStore'; import NoComponentCanvasContainer from './NoComponentCanvasContainer'; import { RIGHT_SIDE_BAR_TAB } from '../RightSideBar/rightSidebarConstants'; @@ -95,7 +103,10 @@ export const Container = React.memo( if (canvasWidth !== undefined) { if (componentType === 'Listview' && listViewMode == 'grid') return canvasWidth / columns - 2; if (id === 'canvas') return canvasWidth; - return canvasWidth - 2; + if (componentType === 'Container') { + return canvasWidth - (2 * CONTAINER_CANVAS_PADDING + 2 * CONTAINER_CANVAS_BORDER_WIDTH + 2 * BOX_PADDING); + } + return canvasWidth - 2; // Need to update this 2 to correct value for other subcontainers } return realCanvasRef?.current?.offsetWidth; } @@ -143,7 +154,7 @@ export const Container = React.memo( }} style={{ height: id === 'canvas' ? `${canvasHeight}` : '100%', - backgroundSize: `${gridWidth}px ${10}px`, + backgroundSize: `${gridWidth}px ${GRID_HEIGHT}px`, backgroundColor: currentMode === 'view' ? computeViewerBackgroundColor(darkMode, canvasBgColor) diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx index 6821f43ce2..6403d63201 100644 --- a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx +++ b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx @@ -830,7 +830,7 @@ export default function Grid({ gridWidth, currentLayout }) { onDragEnd={(e) => { try { if (isDraggingRef.current) { - useGridStore.getState().actions.setDraggingComponentId(null); + useStore.getState().setDraggingComponentId(null); isDraggingRef.current = false; } prevDragParentId.current = null; diff --git a/frontend/src/AppBuilder/AppCanvas/RenderWidget.jsx b/frontend/src/AppBuilder/AppCanvas/RenderWidget.jsx index 427cced97b..b26586dc08 100644 --- a/frontend/src/AppBuilder/AppCanvas/RenderWidget.jsx +++ b/frontend/src/AppBuilder/AppCanvas/RenderWidget.jsx @@ -6,7 +6,7 @@ import { OverlayTrigger } from 'react-bootstrap'; import { renderTooltip } from '@/_helpers/appUtils'; import { useTranslation } from 'react-i18next'; import ErrorBoundary from '@/_ui/ErrorBoundary'; - +import { BOX_PADDING } from './appCanvasConstants'; const shouldAddBoxShadowAndVisibility = [ 'Table', 'TextInput', @@ -164,7 +164,7 @@ const RenderWidget = ({
state.getComponentDefinition(id)?.layouts?.[currentLayout], shallow); const isWidgetActive = useStore((state) => state.selectedComponents.find((sc) => sc === id) && !readOnly, shallow); - const isDragging = useGridStore((state) => state.draggingComponentId === id); + const isDragging = useStore((state) => state.draggingComponentId === id); const isResizing = useGridStore((state) => state.resizingComponentId === id); const componentType = useStore((state) => state.getComponentDefinition(id)?.component?.component, shallow); const setHoveredComponentForGrid = useStore((state) => state.setHoveredComponentForGrid, shallow); diff --git a/frontend/src/AppBuilder/AppCanvas/appCanvasConstants.js b/frontend/src/AppBuilder/AppCanvas/appCanvasConstants.js index 75b3402331..1c598f8475 100644 --- a/frontend/src/AppBuilder/AppCanvas/appCanvasConstants.js +++ b/frontend/src/AppBuilder/AppCanvas/appCanvasConstants.js @@ -1,5 +1,7 @@ export const NO_OF_GRIDS = 43; +export const GRID_HEIGHT = 10; + export const CANVAS_WIDTHS = Object.freeze({ deviceWindowWidth: 450, leftSideBarWidth: 48, @@ -15,3 +17,9 @@ export const APP_HEADER_HEIGHT = 47; export const LEFT_SIDEBAR_WIDTH = 348; // exclusive of border export const SUBCONTAINER_WIDGETS = ['Container', 'Tabs', 'Listview', 'Kanban', 'Form']; + +export const CONTAINER_CANVAS_PADDING = 2; + +export const CONTAINER_CANVAS_BORDER_WIDTH = 1; + +export const BOX_PADDING = 2; diff --git a/frontend/src/AppBuilder/Widgets/Container.jsx b/frontend/src/AppBuilder/Widgets/Container.jsx index 1334098423..bcdb423561 100644 --- a/frontend/src/AppBuilder/Widgets/Container.jsx +++ b/frontend/src/AppBuilder/Widgets/Container.jsx @@ -2,6 +2,9 @@ import React, { useMemo } from 'react'; import { Container as ContainerComponent } from '@/AppBuilder/AppCanvas/Container'; import Spinner from '@/_ui/Spinner'; import { useExposeState } from '@/AppBuilder/_hooks/useExposeVariables'; +import { shallow } from 'zustand/shallow'; +import { CONTAINER_CANVAS_PADDING, CONTAINER_CANVAS_BORDER_WIDTH } from '@/AppBuilder/AppCanvas/appCanvasConstants'; +import useStore from '@/AppBuilder/_stores/store'; export const Container = ({ id, @@ -23,6 +26,11 @@ export const Container = ({ setExposedVariable ); + const isWidgetInContainerDragging = useStore( + (state) => state.containerChildrenMapping[id].includes(state.draggingComponentId), + shallow + ); + const contentBgColor = useMemo(() => { return { backgroundColor: @@ -42,8 +50,9 @@ export const Container = ({ const computedStyles = { backgroundColor: contentBgColor.backgroundColor, borderRadius: borderRadius ? parseFloat(borderRadius) : 0, - border: `1px solid ${borderColor}`, + border: `${CONTAINER_CANVAS_BORDER_WIDTH}px solid ${borderColor}`, height, + padding: `${CONTAINER_CANVAS_PADDING}px`, display: isVisible ? 'flex' : 'none', flexDirection: 'column', position: 'relative', @@ -61,9 +70,9 @@ export const Container = ({ const computedContentStyles = { ...contentBgColor, flex: 1, - overflow: 'auto', + // Prevent the scroll when dragging a widget inside the container or moving out of the container + overflow: isWidgetInContainerDragging ? 'hidden' : 'hidden auto', }; - return (
({ @@ -21,6 +22,7 @@ export const createGridSlice = (set, get) => ({ debouncedToggleCanvasUpdater: debounce(() => { get().toggleCanvasUpdater(); }, 200), + setDraggingComponentId: (id) => set(() => ({ draggingComponentId: id })), moveComponentPosition: (direction) => { const { setComponentLayout, currentLayout, getSelectedComponentsDefinition, debouncedToggleCanvasUpdater } = get(); let layouts = {}; diff --git a/frontend/src/Editor/DraggableBox.jsx b/frontend/src/Editor/DraggableBox.jsx index ae2740bc84..3cdad272b7 100644 --- a/frontend/src/Editor/DraggableBox.jsx +++ b/frontend/src/Editor/DraggableBox.jsx @@ -10,7 +10,7 @@ import { resolveWidgetFieldValue } from '@/_helpers/utils'; import ErrorBoundary from './ErrorBoundary'; import { useEditorStore } from '@/_stores/editorStore'; import { shallow } from 'zustand/shallow'; -import { useNoOfGrid, useGridStore } from '@/_stores/gridStore'; +import { useGridStore } from '@/_stores/gridStore'; import WidgetBox from './WidgetBox'; import * as Sentry from '@sentry/react'; import { findHighestLevelofSelection } from './DragContainer'; @@ -61,7 +61,7 @@ const DraggableBox = React.memo( }) => { const isResizing = useGridStore((state) => state.resizingComponentId === id); const [canDrag, setCanDrag] = useState(true); - const noOfGrid = useNoOfGrid(); + const noOfGrid = 43; const { currentLayout, setHoveredComponent, diff --git a/frontend/src/Editor/SubContainer.jsx b/frontend/src/Editor/SubContainer.jsx index 01335af55a..fc78875819 100644 --- a/frontend/src/Editor/SubContainer.jsx +++ b/frontend/src/Editor/SubContainer.jsx @@ -23,7 +23,7 @@ import { useEditorStore } from '@/_stores/editorStore'; // eslint-disable-next-line import/no-unresolved import { diff } from 'deep-object-diff'; -import { useGridStore, useResizingComponentId } from '@/_stores/gridStore'; +import { useGridStore } from '@/_stores/gridStore'; import GhostWidget from './GhostWidget'; import { deepClone } from '@/_helpers/utilities/utils.helpers'; @@ -68,7 +68,7 @@ export const SubContainer = ({ shallow ); - const resizingComponentId = useResizingComponentId(); + const resizingComponentId = useGridStore((state) => state.resizingComponentId, shallow); const noOfGrids = 43; const { isGridActive } = useGridStore((state) => ({ isGridActive: state.activeGrid === parent }), shallow); diff --git a/frontend/src/_stores/gridStore.js b/frontend/src/_stores/gridStore.js index aa070e4a89..213f07ac16 100644 --- a/frontend/src/_stores/gridStore.js +++ b/frontend/src/_stores/gridStore.js @@ -7,7 +7,6 @@ const initialState = { noOfGrid: 43, draggedSubContainer: false, resizingComponentId: null, - draggingComponentId: null, dragTarget: null, isGroupHandleHoverd: false, idGroupDragged: false, @@ -20,11 +19,7 @@ export const useGridStore = create( (set) => ({ ...initialState, actions: { - setActiveGrid: (gridId) => set({ activeGrid: gridId }), - setNoOfGrid: (noOfGrid) => set({ noOfGrid }), - setDraggedSubContainer: (draggedSubContainer) => set({ draggedSubContainer }), setResizingComponentId: (id) => set({ resizingComponentId: id }), - setDraggingComponentId: (id) => set({ draggingComponentId: id }), setDragTarget: (dragTarget) => set({ dragTarget }), setIsGroupHandleHoverd: (isGroupHandleHoverd) => set({ isGroupHandleHoverd }), setIdGroupDragged: (idGroupDragged) => set({ idGroupDragged }), @@ -46,21 +41,5 @@ useGridStore.subscribe(({ draggingComponentId }) => { } }); -// useEditorStore.subscribe(({ hoveredComponent }) => { -// console.log('hoveredComponent--', hoveredComponent); -// if (hoveredComponent) { -// document.querySelector(`[data-hovered-control]`)?.removeAttribute('data-hovered-control'); -// document.querySelector(`[target-id='${hoveredComponent}']`)?.setAttribute('data-hovered-control', true); -// } else if (document.querySelector(`[data-hovered-control]`)) { -// document.querySelector(`[data-hovered-control]`)?.removeAttribute('data-hovered-control'); -// } -// }); - -export const useActiveGrid = () => useGridStore((state) => state.activeGrid, shallow); -export const useNoOfGrid = () => useGridStore((state) => state.noOfGrid, shallow); -export const useDraggedSubContainer = () => useGridStore((state) => state.draggedSubContainer, shallow); -export const useGridStoreActions = () => useGridStore((state) => state.actions, shallow); -export const useDragTarget = () => useGridStore((state) => state.dragTarget, shallow); -export const useResizingComponentId = () => useGridStore((state) => state.resizingComponentId, shallow); export const useIsGroupHandleHoverd = () => useGridStore((state) => state.isGroupHandleHoverd, shallow); export const useOpenModalWidgetId = () => useGridStore((state) => state.openModalWidgetId, shallow); From 36cb2b04c8a692b7862a06bcb4a8427dfa368263 Mon Sep 17 00:00:00 2001 From: Nakul Nagargade Date: Fri, 14 Feb 2025 12:02:59 +0530 Subject: [PATCH 2/9] fix --- frontend/src/AppBuilder/Widgets/Container.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/AppBuilder/Widgets/Container.jsx b/frontend/src/AppBuilder/Widgets/Container.jsx index bcdb423561..23bfbb0eee 100644 --- a/frontend/src/AppBuilder/Widgets/Container.jsx +++ b/frontend/src/AppBuilder/Widgets/Container.jsx @@ -27,7 +27,7 @@ export const Container = ({ ); const isWidgetInContainerDragging = useStore( - (state) => state.containerChildrenMapping[id].includes(state.draggingComponentId), + (state) => state.containerChildrenMapping?.[id]?.includes(state?.draggingComponentId), shallow ); From 05637ef28123018ce6a445f8782d51bef3948b3a Mon Sep 17 00:00:00 2001 From: Nakul Nagargade Date: Mon, 17 Feb 2025 12:02:39 +0530 Subject: [PATCH 3/9] Prevent component handle adding scroll to the container --- .../AppCanvas/ConfigHandle/ConfigHandle.jsx | 15 +++++++++------ .../src/AppBuilder/AppCanvas/WidgetWrapper.jsx | 1 - 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx index bb4d4fc69b..f0dd4266e4 100644 --- a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx +++ b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx @@ -3,9 +3,12 @@ import { shallow } from 'zustand/shallow'; import './configHandle.scss'; import useStore from '@/AppBuilder/_stores/store'; import { findHighestLevelofSelection } from '../Grid/gridUtils'; + +const CONFIG_HANDLE_HEIGHT = 20; +const BUFFER_HEIGHT = 1; + export const ConfigHandle = ({ id, - position, widgetTop, widgetHeight, setSelectedComponentAsModal = () => null, //! Only Modal widget passes this uses props down. All other widgets use selecto lib @@ -27,6 +30,7 @@ export const ConfigHandle = ({ (state) => componentType === 'Tabs' && state.getExposedValueOfComponent(id)?.currentTab, shallow ); + const position = widgetTop < 15 ? 'bottom' : 'top'; const setComponentToInspect = useStore((state) => state.setComponentToInspect); const isModal = componentType === 'Modal' || componentType === 'ModalV2'; @@ -36,9 +40,7 @@ export const ConfigHandle = ({ // If one component is hovered and one is selected, show the handle for the hovered component return ( isWidgetHovered || - (showHandle && - (!isMultipleComponentsSelected || (isModal && isModalOpen)) && - !anyComponentHovered) + (showHandle && (!isMultipleComponentsSelected || (isModal && isModalOpen)) && !anyComponentHovered) ); }, shallow); let height = visibility === false ? 10 : widgetHeight; @@ -48,7 +50,7 @@ export const ConfigHandle = ({ className={`config-handle ${customClassName}`} widget-id={id} style={{ - top: position === 'top' ? '-20px' : widgetTop + height - (widgetTop < 10 ? 15 : 10), + top: position === 'top' ? '-20px' : `${height - (CONFIG_HANDLE_HEIGHT + BUFFER_HEIGHT)}px`, visibility: _showHandle ? 'visible' : 'hidden', left: '-1px', }} @@ -63,7 +65,8 @@ export const ConfigHandle = ({ > diff --git a/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx b/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx index e4bbef6802..9d9cade876 100644 --- a/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx +++ b/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx @@ -84,7 +84,6 @@ const WidgetWrapper = memo( {mode == 'edit' && ( Date: Tue, 18 Feb 2025 10:40:24 +0530 Subject: [PATCH 4/9] Add support for handle should still be displayed for hidden components in editor mode --- .../AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx | 10 ++++++++-- frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx | 1 - 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx index f0dd4266e4..e3e38999f3 100644 --- a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx +++ b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx @@ -50,7 +50,12 @@ export const ConfigHandle = ({ className={`config-handle ${customClassName}`} widget-id={id} style={{ - top: position === 'top' ? '-20px' : `${height - (CONFIG_HANDLE_HEIGHT + BUFFER_HEIGHT)}px`, + top: + componentType === 'Modal' && isModalOpen + ? '0px' + : position === 'top' + ? '-20px' + : `${height - (CONFIG_HANDLE_HEIGHT + BUFFER_HEIGHT)}px`, visibility: _showHandle ? 'visible' : 'hidden', left: '-1px', }} @@ -65,7 +70,8 @@ export const ConfigHandle = ({ > Date: Wed, 19 Feb 2025 19:17:31 +0530 Subject: [PATCH 5/9] add padding for Container and form --- .../src/AppBuilder/AppCanvas/Container.jsx | 13 +-- .../AppCanvas/appCanvasConstants.js | 4 +- .../Widgets/{ => Container}/Container.jsx | 83 +++++++++-------- .../Widgets/Container/container.scss | 13 +++ frontend/src/AppBuilder/Widgets/Form/Form.jsx | 92 ++++++------------- .../src/AppBuilder/Widgets/Form/form.scss | 25 +++++ .../AppBuilder/Widgets/Kanban/KanbanBoard.jsx | 1 + frontend/src/AppBuilder/Widgets/Listview.jsx | 35 +------ frontend/src/AppBuilder/Widgets/Tabs.jsx | 1 + .../src/AppBuilder/_helpers/editorHelpers.js | 2 +- 10 files changed, 126 insertions(+), 143 deletions(-) rename frontend/src/AppBuilder/Widgets/{ => Container}/Container.jsx (52%) create mode 100644 frontend/src/AppBuilder/Widgets/Container/container.scss create mode 100644 frontend/src/AppBuilder/Widgets/Form/form.scss diff --git a/frontend/src/AppBuilder/AppCanvas/Container.jsx b/frontend/src/AppBuilder/AppCanvas/Container.jsx index c9466dc1dd..e622e1a2cd 100644 --- a/frontend/src/AppBuilder/AppCanvas/Container.jsx +++ b/frontend/src/AppBuilder/AppCanvas/Container.jsx @@ -11,8 +11,8 @@ import { NO_OF_GRIDS, WIDGETS_WITH_DEFAULT_CHILDREN, GRID_HEIGHT, - CONTAINER_CANVAS_PADDING, - CONTAINER_CANVAS_BORDER_WIDTH, + CONTAINER_FORM_CANVAS_PADDING, + SUBCONTAINER_CANVAS_BORDER_WIDTH, BOX_PADDING, } from './appCanvasConstants'; import { useGridStore } from '@/_stores/gridStore'; @@ -43,10 +43,10 @@ export const Container = React.memo( canvasMaxWidth, isViewerSidebarPinned, pageSidebarStyle, + componentType, }) => { const realCanvasRef = useRef(null); const components = useStore((state) => state.getContainerChildrenMapping(id), shallow); - const componentType = useStore((state) => state.getComponentTypeFromId(id), shallow); const addComponentToCurrentPage = useStore((state) => state.addComponentToCurrentPage, shallow); const setActiveRightSideBarTab = useStore((state) => state.setActiveRightSideBarTab, shallow); const setLastCanvasClickPosition = useStore((state) => state.setLastCanvasClickPosition, shallow); @@ -103,15 +103,16 @@ export const Container = React.memo( if (canvasWidth !== undefined) { if (componentType === 'Listview' && listViewMode == 'grid') return canvasWidth / columns - 2; if (id === 'canvas') return canvasWidth; - if (componentType === 'Container') { - return canvasWidth - (2 * CONTAINER_CANVAS_PADDING + 2 * CONTAINER_CANVAS_BORDER_WIDTH + 2 * BOX_PADDING); + if (componentType === 'Container' || componentType === 'Form') { + return ( + canvasWidth - (2 * CONTAINER_FORM_CANVAS_PADDING + 2 * SUBCONTAINER_CANVAS_BORDER_WIDTH + 2 * BOX_PADDING) + ); } return canvasWidth - 2; // Need to update this 2 to correct value for other subcontainers } return realCanvasRef?.current?.offsetWidth; } const gridWidth = getContainerCanvasWidth() / NO_OF_GRIDS; - useEffect(() => { useGridStore.getState().actions.setSubContainerWidths(id, getContainerCanvasWidth() / NO_OF_GRIDS); // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/frontend/src/AppBuilder/AppCanvas/appCanvasConstants.js b/frontend/src/AppBuilder/AppCanvas/appCanvasConstants.js index 1c598f8475..e6a789fba0 100644 --- a/frontend/src/AppBuilder/AppCanvas/appCanvasConstants.js +++ b/frontend/src/AppBuilder/AppCanvas/appCanvasConstants.js @@ -18,8 +18,8 @@ export const LEFT_SIDEBAR_WIDTH = 348; // exclusive of border export const SUBCONTAINER_WIDGETS = ['Container', 'Tabs', 'Listview', 'Kanban', 'Form']; -export const CONTAINER_CANVAS_PADDING = 2; +export const CONTAINER_FORM_CANVAS_PADDING = 7; -export const CONTAINER_CANVAS_BORDER_WIDTH = 1; +export const SUBCONTAINER_CANVAS_BORDER_WIDTH = 1; export const BOX_PADDING = 2; diff --git a/frontend/src/AppBuilder/Widgets/Container.jsx b/frontend/src/AppBuilder/Widgets/Container/Container.jsx similarity index 52% rename from frontend/src/AppBuilder/Widgets/Container.jsx rename to frontend/src/AppBuilder/Widgets/Container/Container.jsx index 23bfbb0eee..4978427370 100644 --- a/frontend/src/AppBuilder/Widgets/Container.jsx +++ b/frontend/src/AppBuilder/Widgets/Container/Container.jsx @@ -3,8 +3,12 @@ import { Container as ContainerComponent } from '@/AppBuilder/AppCanvas/Containe import Spinner from '@/_ui/Spinner'; import { useExposeState } from '@/AppBuilder/_hooks/useExposeVariables'; import { shallow } from 'zustand/shallow'; -import { CONTAINER_CANVAS_PADDING, CONTAINER_CANVAS_BORDER_WIDTH } from '@/AppBuilder/AppCanvas/appCanvasConstants'; +import { + CONTAINER_FORM_CANVAS_PADDING, + SUBCONTAINER_CANVAS_BORDER_WIDTH, +} from '@/AppBuilder/AppCanvas/appCanvasConstants'; import useStore from '@/AppBuilder/_stores/store'; +import './container.scss'; export const Container = ({ id, @@ -16,8 +20,6 @@ export const Container = ({ setExposedVariables, setExposedVariable, }) => { - const { borderRadius, borderColor, boxShadow, headerHeight = 80 } = styles; - const { isDisabled, isVisible, isLoading } = useExposeState( properties.loadingState, properties.visibility, @@ -31,6 +33,7 @@ export const Container = ({ shallow ); + const { borderRadius, borderColor, boxShadow, headerHeight = 80 } = styles; const contentBgColor = useMemo(() => { return { backgroundColor: @@ -50,58 +53,66 @@ export const Container = ({ const computedStyles = { backgroundColor: contentBgColor.backgroundColor, borderRadius: borderRadius ? parseFloat(borderRadius) : 0, - border: `${CONTAINER_CANVAS_BORDER_WIDTH}px solid ${borderColor}`, + border: `${SUBCONTAINER_CANVAS_BORDER_WIDTH}px solid ${borderColor}`, height, - padding: `${CONTAINER_CANVAS_PADDING}px`, display: isVisible ? 'flex' : 'none', flexDirection: 'column', position: 'relative', boxShadow, }; - const computedHeaderStyles = { - ...headerBgColor, - height: `${headerHeight}px`, + const containerHeaderStyles = { flexShrink: 0, - flexGrow: 0, - borderBottom: `1px solid var(--border-weak)`, + padding: `${CONTAINER_FORM_CANVAS_PADDING}px ${CONTAINER_FORM_CANVAS_PADDING}px 3px ${CONTAINER_FORM_CANVAS_PADDING}px`, + ...headerBgColor, }; - const computedContentStyles = { - ...contentBgColor, - flex: 1, - // Prevent the scroll when dragging a widget inside the container or moving out of the container - overflow: isWidgetInContainerDragging ? 'hidden' : 'hidden auto', + const containerContentStyles = { + overflow: 'hidden auto', + display: 'flex', + height: '100%', + padding: `${CONTAINER_FORM_CANVAS_PADDING}px`, }; + return (
- {properties.showHeader && ( - - )} {isLoading ? ( -
- -
+ ) : ( - + <> + {properties.showHeader && ( +
+ +
+ )} +
+ +
+ )}
); diff --git a/frontend/src/AppBuilder/Widgets/Container/container.scss b/frontend/src/AppBuilder/Widgets/Container/container.scss new file mode 100644 index 0000000000..323f5e8c9a --- /dev/null +++ b/frontend/src/AppBuilder/Widgets/Container/container.scss @@ -0,0 +1,13 @@ +.wj-container-header { + position: relative; + &::after { + content: ''; + position: absolute; + bottom: 0; + left: -7px; + right: -7px; + height: 1px; + background-color: var(--border-weak); + } + } + \ No newline at end of file diff --git a/frontend/src/AppBuilder/Widgets/Form/Form.jsx b/frontend/src/AppBuilder/Widgets/Form/Form.jsx index c9ea9b7601..b61d40c194 100644 --- a/frontend/src/AppBuilder/Widgets/Form/Form.jsx +++ b/frontend/src/AppBuilder/Widgets/Form/Form.jsx @@ -1,21 +1,22 @@ -import React, { useRef, useState, useEffect, useMemo } from 'react'; +import React, { useRef, useState, useEffect } from 'react'; import { Container as SubContainer } from '@/AppBuilder/AppCanvas/Container'; // eslint-disable-next-line import/no-unresolved -import { diff } from 'deep-object-diff'; import _, { debounce, omit } from 'lodash'; -import { Box } from '@/Editor/Box'; import { generateUIComponents } from './FormUtils'; import { useMounted } from '@/_hooks/use-mount'; import { onComponentClick, removeFunctionObjects } from '@/_helpers/appUtils'; -import { useAppInfo } from '@/_stores/appDataStore'; import { deepClone } from '@/_helpers/utilities/utils.helpers'; import RenderSchema from './RenderSchema'; import useStore from '@/AppBuilder/_stores/store'; import { shallow } from 'zustand/shallow'; +import { + CONTAINER_FORM_CANVAS_PADDING, + SUBCONTAINER_CANVAS_BORDER_WIDTH, +} from '@/AppBuilder/AppCanvas/appCanvasConstants'; +import './form.scss'; const getCanvasHeight = (height) => { const parsedHeight = height.includes('px') ? parseInt(height, 10) : height; - return Math.ceil(parsedHeight); }; @@ -59,7 +60,7 @@ export const Form = function Form(props) { const computedStyles = { backgroundColor, borderRadius: borderRadius ? parseFloat(borderRadius) : 0, - border: `1px solid ${borderColor}`, + border: `${SUBCONTAINER_CANVAS_BORDER_WIDTH}px solid ${borderColor}`, height, display: visibility ? 'flex' : 'none', position: 'relative', @@ -69,25 +70,29 @@ export const Form = function Form(props) { const formHeader = { flexShrink: 0, - // height: headerHeight, - padding: '10px 6px', - borderBottom: '1px solid var(--border-weak)', + paddingBottom: '3px', + paddingTop: '7px', + paddingLeft: `${CONTAINER_FORM_CANVAS_PADDING}px`, + paddingRight: `${CONTAINER_FORM_CANVAS_PADDING}px`, backgroundColor: ['#fff', '#ffffffff'].includes(headerBackgroundColor) && darkMode ? '#1F2837' : headerBackgroundColor, }; - const formFooter = { - flexShrink: 0, - // height: footerHeight, - padding: '10px 6px', - borderTop: '1px solid var(--border-weak)', - backgroundColor: - ['#fff', '#ffffffff'].includes(footerBackgroundColor) && darkMode ? '#1F2837' : footerBackgroundColor, - }; + const formContent = { overflow: 'hidden auto', display: 'flex', height: '100%', - padding: '10px 6px', + paddingTop: `${CONTAINER_FORM_CANVAS_PADDING}px`, + paddingBottom: showFooter ? '3px' : '7px', + paddingLeft: `${CONTAINER_FORM_CANVAS_PADDING}px`, + paddingRight: `${CONTAINER_FORM_CANVAS_PADDING}px`, + }; + + const formFooter = { + flexShrink: 0, + padding: `${CONTAINER_FORM_CANVAS_PADDING}px`, + backgroundColor: + ['#fff', '#ffffffff'].includes(footerBackgroundColor) && darkMode ? '#1F2837' : footerBackgroundColor, }; const parentRef = useRef(null); @@ -287,7 +292,7 @@ export const Form = function Form(props) { }} //Hack, should find a better solution - to prevent losing z index+1 when container element is clicked > {showHeader && ( -
+
)} @@ -320,29 +326,8 @@ export const Form = function Form(props) { onOptionsChange={onOptionsChange} styles={{ backgroundColor: computedStyles.backgroundColor }} darkMode={darkMode} + componentType="Form" /> - {/* - */}
)} {advanced && @@ -375,28 +360,6 @@ export const Form = function Form(props) { onOptionsChange={onComponentOptionsChangedForSubcontainer} />
- {/* */}
); })} @@ -404,7 +367,7 @@ export const Form = function Form(props) { )} {showFooter && ( -
+
)} diff --git a/frontend/src/AppBuilder/Widgets/Form/form.scss b/frontend/src/AppBuilder/Widgets/Form/form.scss new file mode 100644 index 0000000000..88a5ad055e --- /dev/null +++ b/frontend/src/AppBuilder/Widgets/Form/form.scss @@ -0,0 +1,25 @@ +.wj-form-header { + position: relative; + &::after { + content: ''; + position: absolute; + bottom: 0; + left: -7px; + right: -7px; + height: 1px; + background-color: var(--border-weak); + } +} + +.wj-form-footer { + position: relative; + &::after { + content: ''; + position: absolute; + top: 0; + left: -7px; + right: -7px; + height: 1px; + background-color: var(--border-weak); + } +} diff --git a/frontend/src/AppBuilder/Widgets/Kanban/KanbanBoard.jsx b/frontend/src/AppBuilder/Widgets/Kanban/KanbanBoard.jsx index 34efc57221..649e79f451 100644 --- a/frontend/src/AppBuilder/Widgets/Kanban/KanbanBoard.jsx +++ b/frontend/src/AppBuilder/Widgets/Kanban/KanbanBoard.jsx @@ -410,6 +410,7 @@ export function KanbanBoard({ widgetHeight, kanbanProps, parentRef, id }) { width: `${(Number(cardWidth) || 300) + 48}px`, }} kanbanProps={kanbanProps} + componentType="Kanban" > {items[columnId] && ( diff --git a/frontend/src/AppBuilder/Widgets/Listview.jsx b/frontend/src/AppBuilder/Widgets/Listview.jsx index 5ec5abbb17..285f9e5bf9 100644 --- a/frontend/src/AppBuilder/Widgets/Listview.jsx +++ b/frontend/src/AppBuilder/Widgets/Listview.jsx @@ -12,11 +12,8 @@ import { shallow } from 'zustand/shallow'; export const Listview = function Listview({ id, - component, width, height, - containerProps, - removeComponent, properties, styles, fireEvent, @@ -270,38 +267,8 @@ export const Listview = function Listview({ columns={positiveColumns} listViewMode={mode} darkMode={darkMode} + componentType="Listview" /> - {/* { - const changedData = { [component.name]: { [optionName]: value } }; - const existingDataAtIndex = prevData[index] ?? {}; - const newDataAtIndex = { - ...prevData[index], - [component.name]: { - ...existingDataAtIndex[component.name], - ...changedData[component.name], - id: componentId, - }, - }; - const newChildrenData = { ...prevData, [index]: newDataAtIndex }; - return { ...prevData, ...newChildrenData }; - }); - }} - /> */}
))} diff --git a/frontend/src/AppBuilder/Widgets/Tabs.jsx b/frontend/src/AppBuilder/Widgets/Tabs.jsx index 3a93fa698b..7f4fb527e4 100644 --- a/frontend/src/AppBuilder/Widgets/Tabs.jsx +++ b/frontend/src/AppBuilder/Widgets/Tabs.jsx @@ -126,6 +126,7 @@ export const Tabs = function Tabs({ allowContainerSelect={true} styles={{ backgroundColor: bgColor }} darkMode={darkMode} + componentType="Tabs" /> ); diff --git a/frontend/src/AppBuilder/_helpers/editorHelpers.js b/frontend/src/AppBuilder/_helpers/editorHelpers.js index 38e9abd955..5e817c7f7e 100644 --- a/frontend/src/AppBuilder/_helpers/editorHelpers.js +++ b/frontend/src/AppBuilder/_helpers/editorHelpers.js @@ -59,7 +59,7 @@ import { BoundedBox } from '@/Editor/Components/BoundedBox/BoundedBox'; import { isPDFSupported } from '@/_helpers/appUtils'; import { resolveWidgetFieldValue } from '@/_helpers/utils'; import { useEditorStore } from '@/_stores/editorStore'; -import { Container } from '@/AppBuilder/Widgets/Container'; +import { Container } from '@/AppBuilder/Widgets/Container/Container'; import { Listview } from '@/AppBuilder/Widgets/Listview'; import { Tabs } from '@/AppBuilder/Widgets/Tabs'; import { Kanban } from '@/AppBuilder/Widgets/Kanban/Kanban'; From c031d5971865c25e03919037fcaecdc763cf66b4 Mon Sep 17 00:00:00 2001 From: Nakul Nagargade Date: Wed, 19 Feb 2025 21:00:12 +0530 Subject: [PATCH 6/9] replace settings icon with ne solid icon --- .../AppCanvas/ConfigHandle/ConfigHandle.jsx | 62 ++++++++++--------- .../AppBuilder/AppCanvas/WidgetWrapper.jsx | 2 + 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx index e3e38999f3..4deb50ea2e 100644 --- a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx +++ b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx @@ -3,6 +3,7 @@ import { shallow } from 'zustand/shallow'; import './configHandle.scss'; import useStore from '@/AppBuilder/_stores/store'; import { findHighestLevelofSelection } from '../Grid/gridUtils'; +import SolidIcon from '@/_ui/Icon/solidIcons/index'; const CONFIG_HANDLE_HEIGHT = 20; const BUFFER_HEIGHT = 1; @@ -73,6 +74,7 @@ export const ConfigHandle = ({ background: visibility === false ? '#c6cad0' : componentType === 'Modal' && isModalOpen ? '#c6cad0' : '#4D72FA', border: position === 'bottom' ? '1px solid white' : 'none', + color: visibility === false && 'var(--text-placeholder)', }} className="badge handle-content" > @@ -86,42 +88,42 @@ export const ConfigHandle = ({ data-cy={`${componentName?.toLowerCase()}-config-handle`} className="text-truncate" > - + {/* Settings Icon */} + + + {componentName} + {/* Divider */} +
+ {/* Delete Button */} {!isMultipleComponentsSelected && !shouldFreeze && ( -
- { + deleteComponents([id]); + }} + > + setComponentToInspect(componentName)} - data-cy={`${componentName.toLowerCase()}-inspect-button`} - className="config-handle-inspect" + fill={visibility === false ? 'var(--text-placeholder)' : '#fff'} /> - { - deleteComponents([id]); - }} - data-cy={`${componentName.toLowerCase()}-delete-button`} - className="delete-icon" - /> -
+ )} diff --git a/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx b/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx index ff22963444..895697091f 100644 --- a/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx +++ b/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx @@ -52,7 +52,9 @@ const WidgetWrapper = memo( height: visibility === false ? '10px' : `${height}px`, transform: `translate(${layoutData.left * gridWidth}px, ${layoutData.top}px)`, WebkitFontSmoothing: 'antialiased', + border: visibility === false ? `1px solid var(--border-default)` : 'none', }; + if (!componentType) return null; return ( <> From 53e7de02477c756b48de24f141dc55aec915ba75 Mon Sep 17 00:00:00 2001 From: Nakul Nagargade Date: Mon, 10 Mar 2025 13:25:20 +0530 Subject: [PATCH 7/9] Fix config handle --- .../AppCanvas/ConfigHandle/ConfigHandle.jsx | 34 +++++++++++++------ .../AppCanvas/ConfigHandle/configHandle.scss | 17 +--------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx index 4deb50ea2e..4c558f3cc2 100644 --- a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx +++ b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx @@ -111,19 +111,33 @@ export const ConfigHandle = ({ {/* Delete Button */} {!isMultipleComponentsSelected && !shouldFreeze && ( - { - deleteComponents([id]); - }} - > - + setComponentToInspect(componentName)} + data-cy={`${componentName.toLowerCase()}-inspect-button`} + className="config-handle-inspect" /> - + { + deleteComponents([id]); + }} + data-cy={`${componentName.toLowerCase()}-delete-button`} + > + + + )} diff --git a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/configHandle.scss b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/configHandle.scss index e7322959e5..5cb1b94268 100644 --- a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/configHandle.scss +++ b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/configHandle.scss @@ -31,22 +31,7 @@ .badge { font-size: 9px; border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - - .delete-part { - margin-left: 10px; - float: right; - } - - .delete-part::before { - height: 12px; - display: inline-block; - width: 2px; - background-color: rgba(255, 255, 255, 0.8); - opacity: 0.5; - content: ""; - vertical-align: middle; - } + border-bottom-right-radius: 0 } } From 753f3384e9623a9d73bcef10f1b2d405b86c5eb5 Mon Sep 17 00:00:00 2001 From: Nakul Nagargade Date: Mon, 10 Mar 2025 13:27:19 +0530 Subject: [PATCH 8/9] fix conflict --- frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx index 6403d63201..559c70fe86 100644 --- a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx +++ b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx @@ -884,7 +884,7 @@ export default function Grid({ gridWidth, currentLayout }) { onDrag={(e) => { // Since onDrag is called multiple times when dragging, hence we are using isDraggingRef to prevent setting state again and again if (!isDraggingRef.current) { - useGridStore.getState().actions.setDraggingComponentId(e.target.id); + useStore.getState().setDraggingComponentId(e.target.id); showGridLines(); isDraggingRef.current = true; } From 3af5166422e53be73839c7ce70f7bb3733e7ef4b Mon Sep 17 00:00:00 2001 From: Nakul Nagargade Date: Mon, 10 Mar 2025 13:42:21 +0530 Subject: [PATCH 9/9] Resolve conflict issues --- frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx index 559c70fe86..9964b06542 100644 --- a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx +++ b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx @@ -56,7 +56,7 @@ export default function Grid({ gridWidth, currentLayout }) { const getHoveredComponentForGrid = useStore((state) => state.getHoveredComponentForGrid, shallow); const getResolvedComponent = useStore((state) => state.getResolvedComponent, shallow); const [canvasBounds, setCanvasBounds] = useState(CANVAS_BOUNDS); - const draggingComponentId = useGridStore((state) => state.draggingComponentId, shallow); + const draggingComponentId = useStore((state) => state.draggingComponentId, shallow); const resizingComponentId = useGridStore((state) => state.resizingComponentId, shallow); const [dragParentId, setDragParentId] = useState(null); const [elementGuidelines, setElementGuidelines] = useState([]); @@ -641,8 +641,7 @@ export default function Grid({ gridWidth, currentLayout }) { const currentWidget = boxList.find(({ id }) => { return id === e.target.id; }); - document.getElementById('real-canvas')?.classList.remove('show-grid'); - document.getElementById('canvas-' + currentWidget.component?.parent)?.classList.remove('show-grid'); + hideGridLines(); let _gridWidth = useGridStore.getState().subContainerWidths[currentWidget.component?.parent] || gridWidth; let width = Math.round(e?.lastEvent?.width / _gridWidth) * _gridWidth; const height = Math.round(e?.lastEvent?.height / GRID_HEIGHT) * GRID_HEIGHT;