Merge pull request #12178 from ToolJet/gutter-issue-container-padding

Fix gutter issue at the bottom of the container
This commit is contained in:
Johnson Cherian 2025-03-10 14:29:40 +05:30 committed by GitHub
commit dea079939b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 277 additions and 276 deletions

View file

@ -3,9 +3,13 @@ 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;
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 +31,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 +41,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 +51,12 @@ export const ConfigHandle = ({
className={`config-handle ${customClassName}`}
widget-id={id}
style={{
top: position === 'top' ? '-20px' : widgetTop + height - (widgetTop < 10 ? 15 : 10),
top:
componentType === 'Modal' && isModalOpen
? '0px'
: position === 'top'
? '-20px'
: `${height - (CONFIG_HANDLE_HEIGHT + BUFFER_HEIGHT)}px`,
visibility: _showHandle ? 'visible' : 'hidden',
left: '-1px',
}}
@ -63,7 +71,10 @@ export const ConfigHandle = ({
>
<span
style={{
background: isModal && isModalOpen ? '#c6cad0' : '#4D72FA',
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"
>
@ -77,17 +88,30 @@ export const ConfigHandle = ({
data-cy={`${componentName?.toLowerCase()}-config-handle`}
className="text-truncate"
>
<img
style={{ cursor: 'pointer', marginRight: '5px', verticalAlign: 'middle' }}
src="assets/images/icons/settings.svg"
width="12"
height="12"
draggable="false"
/>
{/* Settings Icon */}
<span style={{ cursor: 'pointer', marginRight: '5px' }}>
<SolidIcon
name="settings"
width="12"
height="12"
fill={visibility === false ? 'var(--text-placeholder)' : '#fff'}
/>
</span>
<span>{componentName}</span>
{/* Divider */}
<hr
style={{
marginLeft: '10px',
height: '12px',
width: '2px',
backgroundColor: visibility === false ? 'var(--text-placeholder)' : '#fff',
opacity: 0.5,
}}
/>
</div>
{/* Delete Button */}
{!isMultipleComponentsSelected && !shouldFreeze && (
<div className="delete-part">
<div>
<img
style={{ cursor: 'pointer', marginLeft: '5px' }}
src="assets/images/icons/inspect.svg"
@ -99,19 +123,20 @@ export const ConfigHandle = ({
data-cy={`${componentName.toLowerCase()}-inspect-button`}
className="config-handle-inspect"
/>
<img
<span
style={{ cursor: 'pointer', marginLeft: '5px' }}
src="assets/images/icons/trash-light.svg"
width="12"
role="button"
height="12"
draggable="false"
onClick={() => {
deleteComponents([id]);
}}
data-cy={`${componentName.toLowerCase()}-delete-button`}
className="delete-icon"
/>
>
<SolidIcon
name="trash"
width="12"
height="12"
fill={visibility === false ? 'var(--text-placeholder)' : '#fff'}
/>
</span>
</div>
)}
</span>

View file

@ -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
}
}

View file

@ -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_FORM_CANVAS_PADDING,
SUBCONTAINER_CANVAS_BORDER_WIDTH,
BOX_PADDING,
} from './appCanvasConstants';
import { useGridStore } from '@/_stores/gridStore';
import NoComponentCanvasContainer from './NoComponentCanvasContainer';
import { RIGHT_SIDE_BAR_TAB } from '../RightSideBar/rightSidebarConstants';
@ -35,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);
@ -95,12 +103,16 @@ 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' || 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
@ -143,7 +155,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)

View file

@ -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;
@ -830,7 +829,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;
@ -884,7 +883,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;
}

View file

@ -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 = ({
<div
style={{
height: '100%',
padding: resolvedStyles?.padding == 'none' ? '0px' : '2px', //chart and image has a padding property other than container padding
padding: resolvedStyles?.padding == 'none' ? '0px' : `${BOX_PADDING}px`, //chart and image has a padding property other than container padding
}}
role={'Box'}
className={inCanvas ? `_tooljet-${component?.component} _tooljet-${component?.name}` : ''} //required for custom CSS

View file

@ -27,7 +27,7 @@ const WidgetWrapper = memo(
);
const layoutData = useStore((state) => 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);
@ -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 (
<>
@ -68,7 +70,6 @@ const WidgetWrapper = memo(
id={id}
widgetid={id}
style={{
// transform: `translate(332px, -134px)`,
// zIndex: mode === 'view' && widget.component.component == 'Datepicker' ? 2 : null,
...styles,
}}
@ -84,7 +85,6 @@ const WidgetWrapper = memo(
{mode == 'edit' && (
<ConfigHandle
id={id}
position={layoutData.top < 15 ? 'bottom' : 'top'}
widgetTop={layoutData.top}
widgetHeight={layoutData.height}
showHandle={isWidgetActive}

View file

@ -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_FORM_CANVAS_PADDING = 7;
export const SUBCONTAINER_CANVAS_BORDER_WIDTH = 1;
export const BOX_PADDING = 2;

View file

@ -1,99 +0,0 @@
import React, { useMemo } from 'react';
import { Container as ContainerComponent } from '@/AppBuilder/AppCanvas/Container';
import Spinner from '@/_ui/Spinner';
import { useExposeState } from '@/AppBuilder/_hooks/useExposeVariables';
export const Container = ({
id,
properties,
styles,
darkMode,
height,
width,
setExposedVariables,
setExposedVariable,
}) => {
const { borderRadius, borderColor, boxShadow, headerHeight = 80 } = styles;
const { isDisabled, isVisible, isLoading } = useExposeState(
properties.loadingState,
properties.visibility,
properties.disabledState,
setExposedVariables,
setExposedVariable
);
const contentBgColor = useMemo(() => {
return {
backgroundColor:
['#fff', '#ffffffff'].includes(styles.backgroundColor) && darkMode ? '#232E3C' : styles.backgroundColor,
};
}, [styles.backgroundColor, darkMode]);
const headerBgColor = useMemo(() => {
return {
backgroundColor:
['#fff', '#ffffffff'].includes(styles.headerBackgroundColor) && darkMode
? '#232E3C'
: styles.headerBackgroundColor,
};
}, [styles.headerBackgroundColor, darkMode]);
const computedStyles = {
backgroundColor: contentBgColor.backgroundColor,
borderRadius: borderRadius ? parseFloat(borderRadius) : 0,
border: `1px solid ${borderColor}`,
height,
display: isVisible ? 'flex' : 'none',
flexDirection: 'column',
position: 'relative',
boxShadow,
};
const computedHeaderStyles = {
...headerBgColor,
height: `${headerHeight}px`,
flexShrink: 0,
flexGrow: 0,
borderBottom: `1px solid var(--border-weak)`,
};
const computedContentStyles = {
...contentBgColor,
flex: 1,
overflow: 'auto',
};
return (
<div
className={`jet-container widget-type-container ${properties.loadingState && 'jet-container-loading'}`}
id={id}
data-disabled={isDisabled}
style={computedStyles}
>
{properties.showHeader && (
<ContainerComponent
id={`${id}-header`}
styles={computedHeaderStyles}
canvasHeight={headerHeight / 10}
canvasWidth={width}
allowContainerSelect={true}
darkMode={darkMode}
/>
)}
{isLoading ? (
<div className="h-100 d-flex align-items-center">
<Spinner />
</div>
) : (
<ContainerComponent
id={id}
styles={computedContentStyles}
canvasHeight={height}
canvasWidth={width}
darkMode={darkMode}
/>
)}
</div>
);
};

View file

@ -0,0 +1,119 @@
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_FORM_CANVAS_PADDING,
SUBCONTAINER_CANVAS_BORDER_WIDTH,
} from '@/AppBuilder/AppCanvas/appCanvasConstants';
import useStore from '@/AppBuilder/_stores/store';
import './container.scss';
export const Container = ({
id,
properties,
styles,
darkMode,
height,
width,
setExposedVariables,
setExposedVariable,
}) => {
const { isDisabled, isVisible, isLoading } = useExposeState(
properties.loadingState,
properties.visibility,
properties.disabledState,
setExposedVariables,
setExposedVariable
);
const isWidgetInContainerDragging = useStore(
(state) => state.containerChildrenMapping?.[id]?.includes(state?.draggingComponentId),
shallow
);
const { borderRadius, borderColor, boxShadow, headerHeight = 80 } = styles;
const contentBgColor = useMemo(() => {
return {
backgroundColor:
['#fff', '#ffffffff'].includes(styles.backgroundColor) && darkMode ? '#232E3C' : styles.backgroundColor,
};
}, [styles.backgroundColor, darkMode]);
const headerBgColor = useMemo(() => {
return {
backgroundColor:
['#fff', '#ffffffff'].includes(styles.headerBackgroundColor) && darkMode
? '#232E3C'
: styles.headerBackgroundColor,
};
}, [styles.headerBackgroundColor, darkMode]);
const computedStyles = {
backgroundColor: contentBgColor.backgroundColor,
borderRadius: borderRadius ? parseFloat(borderRadius) : 0,
border: `${SUBCONTAINER_CANVAS_BORDER_WIDTH}px solid ${borderColor}`,
height,
display: isVisible ? 'flex' : 'none',
flexDirection: 'column',
position: 'relative',
boxShadow,
};
const containerHeaderStyles = {
flexShrink: 0,
padding: `${CONTAINER_FORM_CANVAS_PADDING}px ${CONTAINER_FORM_CANVAS_PADDING}px 3px ${CONTAINER_FORM_CANVAS_PADDING}px`,
...headerBgColor,
};
const containerContentStyles = {
overflow: 'hidden auto',
display: 'flex',
height: '100%',
padding: `${CONTAINER_FORM_CANVAS_PADDING}px`,
};
return (
<div
className={`jet-container ${isLoading ? 'jet-container-loading' : ''}`}
id={id}
data-disabled={isDisabled}
style={computedStyles}
>
{isLoading ? (
<Spinner />
) : (
<>
{properties.showHeader && (
<div style={containerHeaderStyles} className="wj-container-header">
<ContainerComponent
id={`${id}-header`}
styles={{ ...headerBgColor, height: `${headerHeight}px` }}
canvasHeight={headerHeight / 10}
canvasWidth={width}
allowContainerSelect={true}
darkMode={darkMode}
componentType="Container"
/>
</div>
)}
<div style={containerContentStyles}>
<ContainerComponent
id={id}
styles={{
...contentBgColor,
// Prevent the scroll when dragging a widget inside the container or moving out of the container
overflow: isWidgetInContainerDragging ? 'hidden' : 'hidden auto',
}}
canvasHeight={height}
canvasWidth={width}
darkMode={darkMode}
componentType="Container"
/>
</div>
</>
)}
</div>
);
};

View file

@ -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);
}
}

View file

@ -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 && (
<div style={formHeader}>
<div style={formHeader} className="wj-form-header">
<SubContainer
id={`${id}-header`}
canvasHeight={canvasHeaderHeight}
@ -298,6 +303,7 @@ export const Form = function Form(props) {
backgroundColor: 'transparent',
height: headerHeight,
}}
componentType="Form"
/>
</div>
)}
@ -320,29 +326,8 @@ export const Form = function Form(props) {
onOptionsChange={onOptionsChange}
styles={{ backgroundColor: computedStyles.backgroundColor }}
darkMode={darkMode}
componentType="Form"
/>
{/* <SubContainer
parentComponent={component}
containerCanvasWidth={width}
parent={id}
parentRef={parentRef}
removeComponent={removeComponent}
onOptionChange={function ({ component, optionName, value, componentId }) {
if (componentId) {
onOptionChange({ component, optionName, value, componentId });
}
}}
currentPageId={props.currentPageId}
{...props}
{...containerProps}
height={'100%'} // This height is required since Subcontainer has a issue if height is provided, it stores it in the ref and never updates that ref
/>
<SubCustomDragLayer
containerCanvasWidth={width}
parent={id}
parentRef={parentRef}
currentLayout={currentLayout}
/> */}
</div>
)}
{advanced &&
@ -375,28 +360,6 @@ export const Form = function Form(props) {
onOptionsChange={onComponentOptionsChangedForSubcontainer}
/>
</div>
{/* <Box
{...props}
component={item}
id={index}
width={width}
height={item.defaultSize.height}
mode={mode}
inCanvas={true}
paramUpdated={paramUpdated}
onEvent={onEvent}
onComponentClick={onComponentClick}
darkMode={darkMode}
removeComponent={removeComponent}
// canvasWidth={width}
// readOnly={readOnly}
// customResolvables={customResolvables}
parentId={id}
getContainerProps={getContainerProps}
onOptionChanged={onComponentOptionChangedForSubcontainer}
onOptionsChanged={onComponentOptionsChanged}
isFromSubContainer={true}
/> */}
</div>
);
})}
@ -404,7 +367,7 @@ export const Form = function Form(props) {
)}
</div>
{showFooter && (
<div className="jet-form-footer" style={formFooter}>
<div className="jet-form-footer wj-form-footer" style={formFooter}>
<SubContainer
id={`${id}-footer`}
canvasHeight={canvasFooterHeight}
@ -416,6 +379,7 @@ export const Form = function Form(props) {
backgroundColor: 'transparent',
height: footerHeight,
}}
componentType="Form"
/>
</div>
)}

View file

@ -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);
}
}

View file

@ -410,6 +410,7 @@ export function KanbanBoard({ widgetHeight, kanbanProps, parentRef, id }) {
width: `${(Number(cardWidth) || 300) + 48}px`,
}}
kanbanProps={kanbanProps}
componentType="Kanban"
>
{items[columnId] && (
<SortableContext items={items[columnId]} strategy={verticalListSortingStrategy}>

View file

@ -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"
/>
{/* <SubContainer
columns={positiveColumns}
listmode={mode}
parentComponent={component}
containerCanvasWidth={width}
parent={`${id}`}
parentName={component.name}
{...containerProps}
readOnly={index !== 0}
customResolvables={{ listItem }}
parentRef={parentRef}
removeComponent={removeComponent}
listViewItemOptions={{ index }}
exposedVariables={childrenData[index]}
onOptionChange={function ({ component, optionName, value, componentId }) {
setChildrenData((prevData) => {
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 };
});
}}
/> */}
</div>
))}
</div>

View file

@ -126,6 +126,7 @@ export const Tabs = function Tabs({
allowContainerSelect={true}
styles={{ backgroundColor: bgColor }}
darkMode={darkMode}
componentType="Tabs"
/>
</div>
);

View file

@ -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';

View file

@ -7,6 +7,7 @@ const initialState = {
triggerCanvasUpdater: false,
lastCanvasIdClick: '',
lastCanvasClickPosition: null,
draggingComponentId: null,
};
export const createGridSlice = (set, get) => ({
@ -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 = {};

View file

@ -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,

View file

@ -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);

View file

@ -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);