PromucFlow_constructor/app/client/src/pages/Editor/MainContainerLayoutControl.tsx
Ashok Kumar M 0149085bf8
feat: Reflow and Resize while Dragging and Resizing widgets. (#9054)
* resize n reflow rough cut

* removing warnings

* relatively stable changes

* minor bug fix

* reflow relative collision

* working dp cut

* fix for reflow of widgets closer next to each other

* disabling scroll

* Drag with reflow

* reflow fix

* overlap and retracing fix

* On Drop updates.

* bug when no displacement but resize update.

* temp fix for new widget addition.

* reflow bug fixes

* new widget addition bug.

* stop reflow on leave.

* fix corner case overlap

* update bottom row when reflowed widgets go beyond bottom boundary.

* capture mouse positions on enter

* enable container jumps with faster mouse movements.

* reflow only for snap changes.

* restructured reflow Algorithm

* collision check and bug fixes

* undo redo fix for new widget drop

* resizable fix snapRows fix

* directional stability

* self collision fix

* first round of perf fixes

* update bottom row while resizing and resize-reflowing

* performance fix and overlapping fix

* Remove eslint warning

* remove eslint warning

* eslint warning

* can reflowed Drop Indication Stability

* container jumps and force direction on entering canvas

* fixing scroll on resize jitters.

* reflow when jumping into container.

* reflow ux fixes while leaving container

* resizing fixes.

* fixes for edge move.

* restrict container jumps into reflowed containers.

* container jump direction reflow

* checkbox dimensions fix.

* Excess bottom rows not lost post dragging or resizing widgets.

* fixing the after drop css glitch.

* double first move trigger bug fix.

* stop reflow only if reflowing

* stabilize container exit directions

* using acceleration and speed instead of movement covered to restrict reflow.

* fixing modal drops.

* remove warnings.

* reflow resize styles

* moving acceleration and movement logic to a monitoring effect.

* adding beta flag for reflow.

* fixing jest tests

* Adding analytics to beta flag toggle.

* Adding placeholder for reflow beta screens.

* fixing initial load's screen

* few more crashes.

* force close onboarding for the session.

* fixing bugs in reset canvas.

* Beta flag bug fixes.

* fixing bugs.

* restrict reflow screens during onboarding.

* disabling reflow screens in tests.

* code review comments.

* fixing store based specs.

* fixing cypress failures.

* fixing specs.

* code cleanup

* reverting yarn lock changes

* removing onboarding screens.

* more cleanup and function descriptors

* keeping reflow under the hood.

Co-authored-by: rahulramesha <rahul@appsmith.com>
Co-authored-by: Arpit Mohan <arpit@appsmith.com>
2022-01-13 18:51:57 +05:30

175 lines
4.8 KiB
TypeScript

import classNames from "classnames";
import { useDispatch } from "react-redux";
import React, { useMemo, useCallback } from "react";
import {
getCurrentApplicationId,
getCurrentApplicationLayout,
} from "selectors/editorSelectors";
import { useSelector } from "store";
import { Colors } from "constants/Colors";
import {
AppLayoutConfig,
SupportedLayouts,
} from "reducers/entityReducers/pageListReducer";
import TooltipComponent from "components/ads/Tooltip";
import Icon, { IconName, IconSize } from "components/ads/Icon";
import { updateApplicationLayout } from "actions/applicationActions";
import { setEnableReflowAction } from "actions/reflowActions";
import Checkbox from "components/ads/Checkbox";
import { ReactComponent as BetaIcon } from "assets/icons/menu/beta.svg";
import styled from "styled-components";
import { isReflowEnabled } from "selectors/widgetReflowSelectors";
import { setReflowBetaFlag } from "utils/storage";
import AnalyticsUtil from "utils/AnalyticsUtil";
import { getCurrentUser } from "selectors/usersSelectors";
import { User } from "constants/userConstants";
interface AppsmithLayoutConfigOption {
name: string;
type: SupportedLayouts;
icon?: IconName;
}
export const AppsmithDefaultLayout: AppLayoutConfig = {
type: "FLUID",
};
const AppsmithLayouts: AppsmithLayoutConfigOption[] = [
{
name: "Fluid Width",
type: "FLUID",
icon: "fluid",
},
{
name: "Desktop",
type: "DESKTOP",
icon: "desktop",
},
{
name: "Tablet(Large)",
type: "TABLET_LARGE",
icon: "tablet",
},
{
name: "Tablet",
type: "TABLET",
icon: "tablet",
},
{
name: "Mobile Device",
type: "MOBILE",
icon: "mobile",
},
];
const ReflowBetaWrapper = styled.div`
display: inline-flex;
flex-direction: row;
.beta-icon {
fill: #feb811;
rect {
stroke: #feb811;
}
path {
fill: #fff;
}
}
`;
export function MainContainerLayoutControl() {
const dispatch = useDispatch();
const appId = useSelector(getCurrentApplicationId);
const appLayout = useSelector(getCurrentApplicationLayout);
const shouldResize = useSelector(isReflowEnabled);
const user: User | undefined = useSelector(getCurrentUser);
/**
* return selected layout. if there is no app
* layout, use the default one ( fluid )
*/
const selectedLayout = useMemo(() => {
return AppsmithLayouts.find(
(each) => each.type === (appLayout?.type || AppsmithDefaultLayout.type),
);
}, [appLayout]);
/**
* updates the app layout
*
* @param layoutConfig
*/
const updateAppLayout = useCallback(
(layoutConfig: AppLayoutConfig) => {
const { type } = layoutConfig;
dispatch(
updateApplicationLayout(appId || "", {
appLayout: {
type,
},
}),
);
},
[dispatch, appLayout],
);
const reflowBetaToggle = (isChecked: boolean) => {
if (user?.email) {
setReflowBetaFlag(user.email, isChecked);
}
dispatch(setEnableReflowAction(isChecked));
AnalyticsUtil.logEvent("REFLOW_BETA_FLAG", {
enabled: isChecked,
});
};
const appsmithEmailRegex = /@appsmith.com/g;
const canReflow = user && user.email && appsmithEmailRegex.test(user.email);
return (
<div className="px-3 space-y-2 t--layout-control-wrapper">
<p className="text-sm text-gray-700">Canvas Size</p>
<div className="flex justify-around">
{AppsmithLayouts.map((layoutOption: any, index: number) => {
return (
<TooltipComponent
className="flex-grow"
content={layoutOption.name}
key={layoutOption.name}
position={
index === AppsmithLayouts.length - 1 ? "bottom-right" : "bottom"
}
>
<button
className={classNames({
"border-transparent border flex items-center justify-center p-2 flex-grow": true,
"bg-white border-gray-300":
selectedLayout?.name === layoutOption.name,
"bg-gray-100 hover:bg-gray-200":
selectedLayout?.name !== layoutOption.name,
})}
onClick={() => updateAppLayout(layoutOption)}
>
<Icon
fillColor={Colors.BLACK}
name={layoutOption.icon}
size={layoutOption.iconSize || IconSize.MEDIUM}
/>
</button>
</TooltipComponent>
);
})}
</div>
{canReflow && (
<ReflowBetaWrapper>
<Checkbox
isDefaultChecked={shouldResize}
label="New Reflow & Resize"
onCheckChange={reflowBetaToggle}
/>
<BetaIcon className="beta-icon" />
</ReflowBetaWrapper>
)}
</div>
);
}