Skip to content

Commit 95bd4c4

Browse files
authored
Merge pull request #3766 from czwe-01/thulasizwe/en/canvas
Thulasizwe/en/canvas
2 parents 96c404d + 6782b93 commit 95bd4c4

File tree

23 files changed

+526
-194
lines changed

23 files changed

+526
-194
lines changed

shesha-reactjs/src/components/formDesigner/designerMainArea/index.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ConfigurableFormRenderer, SidebarContainer } from '@/components';
22
import ConditionalWrap from '@/components/conditionalWrapper';
3-
import { DataContextProvider, MetadataProvider, useCanvas, useShaFormInstance } from '@/providers';
3+
import { DataContextProvider, MetadataProvider, useShaFormInstance } from '@/providers';
44
import { useFormDesignerStateSelector } from '@/providers/formDesigner';
55
import ParentProvider from '@/providers/parentProvider';
66
import React, { FC, useMemo, useEffect } from 'react';
@@ -26,9 +26,8 @@ export const DesignerMainArea: FC<IDesignerMainAreaProps> = () => {
2626
const readOnly = useFormDesignerStateSelector((state) => state.readOnly);
2727
const formSettings = useFormDesignerStateSelector((state) => state.formSettings);
2828
const formMode = useFormDesignerStateSelector((state) => state.formMode);
29-
const { antdForm: form } = useShaFormInstance();
30-
const { designerWidth, zoom } = useCanvas();
3129
const shaForm = useShaFormInstance();
30+
const { antdForm: form } = shaForm;
3231
const { styles } = useStyles();
3332

3433
useEffect(() => {
@@ -45,36 +44,36 @@ export const DesignerMainArea: FC<IDesignerMainAreaProps> = () => {
4544
[readOnly]);
4645

4746
return (
48-
<div
49-
className={styles.mainArea}
47+
<div
48+
className={styles.mainArea}
5049
style={{
5150
borderTop: '1px solid #d3d3d3',
5251
...(formMode !== 'designer' && {
5352
maxHeight: '85vh',
5453
overflow: 'auto',
5554
}),
56-
}}
55+
}}
5756
>
5857
<ConditionalWrap
5958
condition={formMode === 'designer'}
6059
wrap={(children) => (
6160
<SidebarContainer
6261
leftSidebarProps={leftSidebarProps}
6362
rightSidebarProps={rightSidebarProps}
63+
canZoom={true}
6464
>
6565
{children}
6666
</SidebarContainer>
6767
)}
6868
>
69-
<div style={{ width: designerWidth, zoom: `${zoom}%`, overflow: 'auto', margin: '0 auto' }}>
7069
<ConditionalWrap
7170
condition={Boolean(formSettings?.modelType)}
7271
wrap={(children) => (<MetadataProvider modelType={formSettings?.modelType}>{children}</MetadataProvider>)}
7372
>
7473
<ParentProvider model={null} formMode="designer">
75-
<DataContextProvider
76-
id={SheshaCommonContexts.FormContext}
77-
name={SheshaCommonContexts.FormContext}
74+
<DataContextProvider
75+
id={SheshaCommonContexts.FormContext}
76+
name={SheshaCommonContexts.FormContext}
7877
type="form"
7978
description="Form designer"
8079
>
@@ -83,11 +82,11 @@ export const DesignerMainArea: FC<IDesignerMainAreaProps> = () => {
8382
<DebugPanel />
8483
)}
8584
</ConfigurableFormRenderer>
85+
8686
</DataContextProvider>
8787
</ParentProvider>
8888
</ConditionalWrap>
8989

90-
</div>
9190
</ConditionalWrap>
9291
</div>
9392
);

shesha-reactjs/src/components/formDesigner/styles/styles.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getFormDesignerBackgroundSvg } from '@/components/sidebarContainer/styles/svg/dropHint';
12
import { createStyles, sheshaStyles } from '@/styles';
23

34
const designerClassNames = {
@@ -41,6 +42,7 @@ const designerClassNames = {
4142
formName: "form-name",
4243
formTitle: "form-title",
4344
formNameParent: "form-name-parent",
45+
toolbarWrapper: "form-toolbar-wrapper",
4446
};
4547
const useStylesResponse = {
4648
styles: designerClassNames,
@@ -174,6 +176,7 @@ export const useMainStyles = createStyles(({ css, cx, token, prefixCls, iconPref
174176
background: white;
175177
padding: 8px 12px 0px 12px;
176178
display: flex;
179+
align-items: center;
177180
justify-content: space-between;
178181
179182
.${formName} {
@@ -234,6 +237,7 @@ export const useMainStyles = createStyles(({ css, cx, token, prefixCls, iconPref
234237
.radio-group {
235238
display: flex;
236239
flex-direction: row;
240+
justify-content: center;
237241
.radio-button {
238242
display: flex;
239243
justify-content: center;
@@ -368,6 +372,7 @@ export const useMainStyles = createStyles(({ css, cx, token, prefixCls, iconPref
368372
369373
.${designerWorkArea}{
370374
background-color: white;
375+
height: 100%;
371376
.${shaComponentsContainer} {
372377
border-radius: 2px;
373378
@@ -376,12 +381,31 @@ export const useMainStyles = createStyles(({ css, cx, token, prefixCls, iconPref
376381
text-align: center;
377382
color: darkgray;
378383
padding: 10px;
384+
height: 55px;
379385
}
380386
381387
.${shaComponent} {
382388
min-height: 30px;
383389
}
384390
}
391+
392+
> div {
393+
height: 100%;
394+
.sha-drop-hint {
395+
display: none;
396+
}
397+
> div:not(.sha-drop-hint) {
398+
min-height: 100vh;
399+
height: 100%;
400+
}
401+
402+
> .sha-components-container-inner:not(:has(.sha-component)) {
403+
background: url("${getFormDesignerBackgroundSvg()}");
404+
background-size: 25vw;
405+
background-repeat: no-repeat;
406+
background-position: 50% 50%;
407+
}
408+
}
385409
}
386410
387411
.${shaComponentGhost} {
@@ -394,8 +418,6 @@ export const useMainStyles = createStyles(({ css, cx, token, prefixCls, iconPref
394418
}
395419
.${shaComponent} {
396420
position: relative;
397-
margin: 4px;
398-
//margin-left: 10px;
399421
400422
.${prefixCls}-alert.${shaDesignerWarning} {
401423
margin-bottom: 0;

shesha-reactjs/src/components/formDesigner/toolbar/canvasConfig.tsx

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,37 @@
1-
import React, { FC } from 'react';
2-
import { useStyles } from '../styles/styles';
3-
import { Radio } from 'antd';
4-
import { DesktopOutlined, MobileOutlined, TabletOutlined } from '@ant-design/icons';
5-
import { useCanvas } from '@/providers';
1+
import React, { FC } from "react";
2+
import { useStyles } from "../styles/styles";
3+
import { Button, Space, Tooltip } from "antd";
4+
import { ExpandOutlined, MinusOutlined, PlusOutlined } from "@ant-design/icons";
5+
import { useCanvas } from "@/providers";
6+
import { DeviceOptions } from "./mobileDropdown";
7+
import { DEFAULT_OPTIONS } from "@/providers/canvas/utils";
68

79
export interface ICanvasConfigProps {
810

911
}
1012

1113
export const CanvasConfig: FC<ICanvasConfigProps> = () => {
1214
const { styles } = useStyles();
13-
const { setDesignerDevice, designerDevice } = useCanvas();
15+
const { setCanvasZoom, setCanvasAutoZoom, autoZoom, zoom } = useCanvas();
1416

1517
return (
1618
<div className={styles.shaDesignerCanvasConfig}>
17-
<Radio.Group className="radio-group" value={designerDevice} buttonStyle="solid" size="middle">
18-
<Radio.Button className="radio-button" value="desktop" onClick={() => setDesignerDevice("desktop")} title="Desktop">
19-
<DesktopOutlined />
20-
</Radio.Button>
21-
22-
<Radio.Button className="radio-button" value="tablet" onClick={() => setDesignerDevice("tablet")} title="Tablet">
23-
<TabletOutlined />
24-
</Radio.Button>
25-
26-
<Radio.Button className="radio-button" value="mobile" onClick={() => setDesignerDevice("mobile")} title="Mobile">
27-
<MobileOutlined />
28-
</Radio.Button>
29-
</Radio.Group>
19+
<DeviceOptions />
20+
<Space direction="horizontal" size={0} style={{ flexWrap: "nowrap" }}>
21+
<Tooltip title={`${zoom}%`}>
22+
<Button
23+
size="small"
24+
type={autoZoom ? "link" : "text"}
25+
icon={<ExpandOutlined size={14} />}
26+
title="Auto"
27+
onClick={() => {
28+
setCanvasAutoZoom();
29+
}}
30+
/>
31+
</Tooltip>
32+
<Tooltip title={`${zoom}%`}><Button size="small" disabled={autoZoom} type="text" icon={<MinusOutlined />} title="Zoom out" onClick={() => setCanvasZoom(zoom - (zoom > DEFAULT_OPTIONS.minZoom ? 2 : 0))} /></Tooltip>
33+
<Tooltip title={`${zoom}%`}><Button size="small" disabled={autoZoom} type="text" icon={<PlusOutlined />} title="Zoom in" onClick={() => setCanvasZoom(zoom + (zoom < DEFAULT_OPTIONS.maxZoom ? 2 : 0))} /></Tooltip>
34+
</Space>
3035
</div>
3136
);
3237
};

shesha-reactjs/src/components/formDesigner/toolbar/formSettingsButton.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import { Button } from 'antd';
33
import { FormSettingsEditor } from '../formSettingsEditor';
44
import { SettingOutlined } from '@ant-design/icons';
55
import { useFormDesignerStateSelector } from '@/providers/formDesigner';
6+
import { SizeType } from 'antd/es/config-provider/SizeContext';
67

78
export interface IFormSettingsButtonProps {
89
buttonText?: string;
10+
size?: SizeType;
911
}
1012

11-
export const FormSettingsButton: FC<IFormSettingsButtonProps> = ({ buttonText }) => {
13+
export const FormSettingsButton: FC<IFormSettingsButtonProps> = ({ buttonText, size }) => {
1214
const [settingsVisible, setSettingsVisible] = useState(false);
1315
const readOnly = useFormDesignerStateSelector((x) => x.readOnly);
1416

@@ -18,7 +20,7 @@ export const FormSettingsButton: FC<IFormSettingsButtonProps> = ({ buttonText })
1820

1921
return (
2022
<>
21-
<Button icon={<SettingOutlined />} type="link" onClick={onSettingsClick} title="Form Settings">
23+
<Button icon={<SettingOutlined />} size={size} type="link" onClick={onSettingsClick} title="Form Settings">
2224
{ buttonText !== undefined ? buttonText : "Settings" }
2325
</Button>
2426
<FormSettingsEditor
@@ -30,4 +32,4 @@ export const FormSettingsButton: FC<IFormSettingsButtonProps> = ({ buttonText })
3032
/>
3133
</>
3234
);
33-
};
35+
};
Lines changed: 30 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,38 @@
11
import React, { FC } from 'react';
2-
import { Dropdown, MenuProps, Select } from 'antd';
2+
import { Tooltip } from 'antd';
33
import { useCanvas } from '@/providers';
4-
import { TabletOutlined } from '@ant-design/icons';
4+
import CustomDropdown from '@/designer-components/_settings/utils/CustomDropdown';
5+
import { getDeviceTypeByWidth, screenSizeOptions } from '@/providers/canvas/utils';
56

6-
export interface IPreviewButtonProps {
7-
refLink: React.LegacyRef<HTMLSpanElement>;
8-
customEditRef?: React.LegacyRef<HTMLSpanElement> | any;
9-
}
7+
export interface IPreviewButtonProps { }
108

11-
export const MobileOptions: FC<IPreviewButtonProps> = ({ refLink, customEditRef }) => {
12-
const { setCanvasWidth, designerWidth: width, designerDevice: activeDevice } = useCanvas();
13-
14-
const items: MenuProps['items'] = [
15-
{
16-
label: (
17-
<div style={{ width: '11rem' }}>
18-
<h5 style={{ marginTop: '-5px', textDecorationLine: 'underline' }}> Dimensions: Responsive</h5>
19-
<Select
20-
showSearch
21-
placeholder="Select a device"
22-
optionFilterProp="label"
23-
defaultValue="428"
24-
value={activeDevice === 'mobile' ? width.toString() : '428'}
25-
style={{ width: '100%' }}
26-
onChange={(val) => {
27-
if (val === '545') {
28-
customEditRef.current.click();
29-
} else {
30-
setCanvasWidth(parseInt(val, 10), 'mobile');
31-
}
32-
}}
33-
options={[
34-
{
35-
value: '375px',
36-
label: 'iPhone SE',
37-
},
38-
{
39-
value: '414px',
40-
label: 'iPhone XR',
41-
},
42-
{
43-
value: '390px',
44-
label: 'iPhone 12 Pro',
45-
},
46-
{
47-
value: '430px',
48-
label: 'iPhone 14 Pro Max',
49-
},
50-
{
51-
value: '360px',
52-
label: 'Samsung Galaxy S8+',
53-
},
54-
{
55-
value: '412px',
56-
label: 'Samsung Galaxy S20 Ultra',
57-
},
58-
{
59-
value: '768px',
60-
label: 'iPad Mini',
61-
},
62-
{
63-
value: '820px',
64-
label: 'iPad Air',
65-
},
66-
{
67-
value: '1024px',
68-
label: 'iPad Pro',
69-
},
70-
{
71-
value: '912px',
72-
label: 'Surface Pro 7',
73-
},
74-
{
75-
value: '540px',
76-
label: 'Surface Duo',
77-
},
78-
{
79-
value: '344px',
80-
label: 'Galaxy Z Fold 5',
81-
},
82-
{
83-
value: '853px',
84-
label: 'Asus Zenbook Fold',
85-
},
86-
{
87-
value: '1280px',
88-
label: 'Nest Hub Max',
89-
},
90-
{
91-
value: '322px',
92-
label: 'iPhone 4',
93-
},
94-
{
95-
value: '545px',
96-
label: 'Edit...',
97-
},
98-
]}
99-
/>
100-
</div>
101-
),
102-
key: '1',
103-
disabled: true,
104-
},
105-
];
106-
107-
const menuProps = {
108-
items,
109-
title: 'Responsive',
110-
};
9+
export const DeviceOptions: FC<IPreviewButtonProps> = () => {
10+
const { setCanvasWidth, designerWidth } = useCanvas();
11111

11212
return (
113-
<Dropdown menu={menuProps} placement="bottom" trigger={['click']} overlayStyle={{ border: '1px dashed gray' }}>
114-
<TabletOutlined ref={refLink} onClick={(e) => e.preventDefault()} />
115-
</Dropdown>
13+
<CustomDropdown
14+
placeholder="Select a device"
15+
optionFilterProp="label"
16+
defaultValue="1024px"
17+
style={{ width: '120px' }}
18+
size="small"
19+
customTooltip='Add a custom screen size e.g "1440px".'
20+
popupMatchSelectWidth={false}
21+
onChange={(val) => {
22+
const value = parseInt(val, 10);
23+
setCanvasWidth(value, getDeviceTypeByWidth(value));
24+
}}
25+
value={typeof designerWidth === 'number' ? `${designerWidth}px` : designerWidth}
26+
labelRender={({ label, value }) => {
27+
const option = screenSizeOptions.find((opt) => opt.value === value);
28+
const Icon = option?.icon;
29+
return (
30+
<Tooltip title={value}>
31+
{Icon ? <Icon /> : null} {label ?? value}
32+
</Tooltip>
33+
);
34+
}}
35+
options={screenSizeOptions.map((opt) => ({ ...opt, title: opt.value }))}
36+
/>
11637
);
11738
};

shesha-reactjs/src/components/formDesigner/toolbar/previewButton.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ export const PreviewButton: FC<IPreviewButtonProps> = (props) => {
2323
type={formMode === 'designer' ? 'default' : 'primary'}
2424
title="Preview"
2525
size={props.size}
26-
shape="circle"
2726
/>
2827
);
2928
};

0 commit comments

Comments
 (0)