Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ import { getWidgetErrorCount } from "layoutSystems/anvil/editor/AnvilWidgetName/
import {
getAnvilHighlightShown,
getAnvilSpaceDistributionStatus,
getWidgetsDistributingSpace,
} from "layoutSystems/anvil/integrations/selectors";
import { useSelector } from "react-redux";
import { combinedPreviewModeSelector } from "selectors/editorSelectors";
import { isWidgetFocused, isWidgetSelected } from "selectors/widgetSelectors";

export function useWidgetBorderStyles(widgetId: string, widgetType: string) {
export function useWidgetBorderStyles(
widgetId: string,
widgetType: string,
elevatedBackground?: boolean,
) {
/** Selectors */
const isFocused = useSelector(isWidgetFocused(widgetId));
const isSelected = useSelector(isWidgetSelected(widgetId));
Expand All @@ -28,7 +33,9 @@ export function useWidgetBorderStyles(widgetId: string, widgetType: string) {
const isDistributingSpace: boolean = useSelector(
getAnvilSpaceDistributionStatus,
);

const widgetsEffectedBySpaceDistribution = useSelector(
getWidgetsDistributingSpace,
);
const isPreviewMode = useSelector(combinedPreviewModeSelector);

/** EO selectors */
Expand All @@ -37,11 +44,14 @@ export function useWidgetBorderStyles(widgetId: string, widgetType: string) {
if (isPreviewMode) {
return {};
}

const isZoneDistributingSpace =
widgetsEffectedBySpaceDistribution.zones.includes(widgetId);
// If the widget is a zone and is distributing space and has no elevated background
const isZoneNotElevated = isZoneDistributingSpace && !elevatedBackground;
// Show the border if the widget has widgets being dragged or redistributed inside it
const showDraggedOnBorder =
(highlightShown && highlightShown.canvasId === widgetId) ||
(isDistributingSpace && isSelected);
isZoneNotElevated;

const onCanvasUI = WidgetFactory.getConfig(widgetType)?.onCanvasUI;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const AnvilEditorFlexComponent = (props: AnvilFlexComponentProps) => {
props.widgetName,
props.isVisible,
props.widgetType,
!!props.elevatedBackground,
ref,
);
useAnvilWidgetDrag(props.widgetId, props.widgetType, props.layoutId, ref);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const AnvilEditorWidgetOnion = (props: BaseWidgetProps) => {
}, [isPreviewMode, props.type]);
return (
<WidgetWrapper
elevatedBackground={!!props.elevatedBackground}
flexGrow={props.flexGrow}
isVisible={!!props.isVisible}
layoutId={props.layoutId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { EVAL_ERROR_PATH } from "utils/DynamicBindingUtils";
import get from "lodash/get";
import { createSelector } from "reselect";
import { getIsDragging } from "selectors/widgetDragSelectors";
import { getAnvilHighlightShown } from "layoutSystems/anvil/integrations/selectors";
import {
getAnvilHighlightShown,
getAnvilSpaceDistributionStatus,
} from "layoutSystems/anvil/integrations/selectors";
import { isWidgetFocused, isWidgetSelected } from "selectors/widgetSelectors";
import { isEditOnlyModeSelector } from "selectors/editorSelectors";

Expand Down Expand Up @@ -58,14 +61,16 @@ export function shouldSelectOrFocus(widgetId: string) {
getAnvilHighlightShown,
isWidgetSelected(widgetId),
isWidgetFocused(widgetId),
getAnvilSpaceDistributionStatus,
(
isEditorOpen,
isDragging,
highlightShown,
isWidgetSelected,
isWidgetFocused,
isDistributingSpace,
) => {
const baseCondition = isEditorOpen && !isDragging;
const baseCondition = isEditorOpen && !isDragging && !isDistributingSpace;
let onCanvasUIState: NameComponentStates = "none";
if (baseCondition) {
if (isWidgetSelected) onCanvasUIState = "select";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@ import { AnvilViewerCanvas } from "layoutSystems/anvil/viewer/canvas/AnvilViewer
import React, { useCallback, useEffect, useRef } from "react";
import { useSelectWidgetListener } from "./hooks/useSelectWidgetListener";
import { useClickToClearSelections } from "./hooks/useClickToClearSelections";
import {
useAnvilGlobalDnDStates,
type AnvilGlobalDnDStates,
} from "./hooks/useAnvilGlobalDnDStates";
import type { AnvilGlobalDnDStates } from "./hooks/useAnvilGlobalDnDStates";
import { useAnvilGlobalDnDStates } from "./hooks/useAnvilGlobalDnDStates";
import { AnvilDragPreview } from "../canvasArenas/AnvilDragPreview";
import { AnvilWidgetElevationProvider } from "./providers/AnvilWidgetElevationProvider";

export const AnvilDnDStatesContext = React.createContext<
AnvilGlobalDnDStates | undefined
>(undefined);

/**
* Anvil Main Canvas is just a wrapper around AnvilCanvas.
* Why do we need this?
Expand Down Expand Up @@ -58,14 +56,16 @@ export const AnvilEditorCanvas = (props: BaseWidgetProps) => {
// using AnvilDnDStatesContext to provide the states to the child AnvilDraggingArena
const anvilGlobalDnDStates = useAnvilGlobalDnDStates();
return (
<AnvilDnDStatesContext.Provider value={anvilGlobalDnDStates}>
<AnvilViewerCanvas {...props} ref={canvasRef} />
<AnvilDragPreview
dragDetails={anvilGlobalDnDStates.dragDetails}
draggedBlocks={anvilGlobalDnDStates.draggedBlocks}
isDragging={anvilGlobalDnDStates.isDragging}
isNewWidget={anvilGlobalDnDStates.isNewWidget}
/>
</AnvilDnDStatesContext.Provider>
<AnvilWidgetElevationProvider>
<AnvilDnDStatesContext.Provider value={anvilGlobalDnDStates}>
<AnvilViewerCanvas {...props} ref={canvasRef} />
<AnvilDragPreview
dragDetails={anvilGlobalDnDStates.dragDetails}
draggedBlocks={anvilGlobalDnDStates.draggedBlocks}
isDragging={anvilGlobalDnDStates.isDragging}
isNewWidget={anvilGlobalDnDStates.isNewWidget}
/>
</AnvilDnDStatesContext.Provider>
</AnvilWidgetElevationProvider>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useEffect } from "react";
import { useAnvilWidgetElevation } from "../providers/AnvilWidgetElevationProvider";

export const useAnvilWidgetElevationSetter = (
widgetId: string,
elevatedBackground: boolean,
) => {
const anvilWidgetElevation = useAnvilWidgetElevation();
const { setWidgetElevation } = anvilWidgetElevation || {};
useEffect(() => {
if (setWidgetElevation) {
setWidgetElevation(widgetId, elevatedBackground);
}
}, [elevatedBackground, setWidgetElevation]);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, {
type ReactNode,
createContext,
useState,
useCallback,
useContext,
} from "react";

interface WidgetElevation {
[key: string]: boolean;
}

interface AnvilWidgetElevationContextType {
elevatedWidgets: WidgetElevation;
setWidgetElevation: (widgetId: string, isElevated: boolean) => void;
}

const AnvilWidgetElevationContext = createContext<
AnvilWidgetElevationContextType | undefined
>(undefined);

export const useAnvilWidgetElevation = () =>
useContext(AnvilWidgetElevationContext);
/**
* AnvilWidgetElevationProvider indexes all sections and zones and records their evaluated value of elevation(Visual Separation).
*
* Why not just use the evaluated values directly?
* Because we need to keep track of the elevation of each widget in the editor to apply the correct elevation styles.
* elevation being a bindable property, we need to keep track of the evaluated value of elevation of each sections and zones in the editor.
*
* When adding compensators to the dragged widgets(useAnvilDnDCompensators), we need to know the elevation of the zone widget as well as its corresponding siblings
* to decide if the zone has to treated as a elevated zone or not.
*
* In-order to skip iterating the data tree every time we need to know the elevation of a widget, we are storing the elevation of each widget in this context.
* This way we do not have dependency on the data tree to know the elevation of a widget.
*/
export const AnvilWidgetElevationProvider = ({
children,
}: {
children: ReactNode;
}) => {
const [elevatedWidgets, setElevatedWidgets] = useState<WidgetElevation>({});

const setWidgetElevation = useCallback(
(widgetId: string, isElevated: boolean) => {
setElevatedWidgets((prev) => {
return {
...prev,
[widgetId]: isElevated,
};
});
},
[setElevatedWidgets],
);

return (
<AnvilWidgetElevationContext.Provider
value={{
elevatedWidgets,
setWidgetElevation,
}}
>
{children}
</AnvilWidgetElevationContext.Provider>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const AnvilModalDropArena = ({
return (
<StyledModalEditorDropArenaWrapper
isModalEmpty={isModalEmpty}
style={{ height: "100%" }}
style={{ height: isModalEmpty ? "100%" : "auto" }}
>
<StyledEmptyModalDropArena
isActive={isCurrentDraggedCanvas}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { AnvilGlobalDnDStates } from "../../canvas/hooks/useAnvilGlobalDnDS
import { getWidgets } from "sagas/selectors";
import { useMemo } from "react";
import { ZoneWidget } from "widgets/anvil/ZoneWidget";
import { useAnvilWidgetElevation } from "../../canvas/providers/AnvilWidgetElevationProvider";

interface AnvilDnDListenerStatesProps {
anvilGlobalDragStates: AnvilGlobalDnDStates;
Expand Down Expand Up @@ -97,6 +98,8 @@ export const useAnvilDnDListenerStates = ({
mainCanvasLayoutId,
} = anvilGlobalDragStates;
const allWidgets = useSelector(getWidgets);
const anvilWidgetElevation = useAnvilWidgetElevation();
const elevatedWidgets = anvilWidgetElevation?.elevatedWidgets || {};
const widgetProps = allWidgets[widgetId];
const selectedWidgets = useSelector(getSelectedWidgets);
/**
Expand Down Expand Up @@ -134,22 +137,21 @@ export const useAnvilDnDListenerStates = ({
(each) => !allWidgets[each].detachFromLayout,
).length === 0;

const allSiblingsWidgets = useMemo(() => {
const allSiblings =
(widgetProps.parentId && allWidgets[widgetProps.parentId]?.children) ||
[];
return allSiblings.map((each) => allWidgets[each]);
const allSiblingsWidgetIds = useMemo(() => {
return (
(widgetProps.parentId && allWidgets[widgetProps.parentId]?.children) || []
);
}, [widgetProps, allWidgets]);

const isElevatedWidget = useMemo(() => {
if (widgetProps.type === ZoneWidget.type) {
const isAnyZoneElevated = allSiblingsWidgets.some(
(each) => !!each.elevatedBackground,
const isAnyZoneElevated = allSiblingsWidgetIds.some(
(each) => !!elevatedWidgets[each],
);
return isAnyZoneElevated;
}
return !!widgetProps.elevatedBackground;
}, [widgetProps, allSiblingsWidgets]);
return !!elevatedWidgets[widgetId];
}, [widgetProps, elevatedWidgets, allSiblingsWidgetIds]);

const {
edgeCompensatorValues,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const useAnvilWidgetStyles = (
widgetName: string,
isVisible = true,
widgetType: string,
elevatedBackground: boolean,
ref: React.RefObject<HTMLDivElement>, // Ref object to reference the AnvilFlexComponent
) => {
// Selectors to determine whether the widget is selected or dragging
Expand All @@ -18,7 +19,11 @@ export const useAnvilWidgetStyles = (
(state: AppState) => state.ui.widgetDragResize.isDragging,
);
// Get widget border styles using useWidgetBorderStyles
const widgetBorderStyles = useWidgetBorderStyles(widgetId, widgetType);
const widgetBorderStyles = useWidgetBorderStyles(
widgetId,
widgetType,
elevatedBackground,
);

// Effect hook to apply widget border styles to the widget
useEffect(() => {
Expand Down
6 changes: 5 additions & 1 deletion app/client/src/layoutSystems/anvil/integrations/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ export function getDropTargetLayoutId(state: AppState, canvasId: string) {
* Returns a boolean indicating if space distribution is in progress
*/
export function getAnvilSpaceDistributionStatus(state: AppState) {
return state.ui.widgetDragResize.anvil.isDistributingSpace;
return state.ui.widgetDragResize.anvil.spaceDistribution.isDistributingSpace;
}

export function getWidgetsDistributingSpace(state: AppState) {
return state.ui.widgetDragResize.anvil.spaceDistribution.widgetsEffected;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { AnvilReduxActionTypes } from "../integrations/actions/actionTypes";

export const startAnvilSpaceDistributionAction = (payload: {
section: string;
zones: string[];
}) => {
return {
type: AnvilReduxActionTypes.ANVIL_SPACE_DISTRIBUTION_START,
payload,
};
};

export const stopAnvilSpaceDistributionAction = () => {
return {
type: AnvilReduxActionTypes.ANVIL_SPACE_DISTRIBUTION_STOP,
};
};

export const updateSpaceDistributionAction = (
sectionLayoutId: string,
zonesDistributed: {
[widgetId: string]: number;
},
) => {
return {
type: AnvilReduxActionTypes.ANVIL_SPACE_DISTRIBUTION_UPDATE,
payload: {
zonesDistributed,
sectionLayoutId,
},
};
};
Loading