Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: repaint ui for setProperties in visual editor #2017

Merged
merged 26 commits into from
Mar 3, 2020
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e401f62
elements interface
alanlong9278 Feb 19, 2020
874417f
styled component
alanlong9278 Feb 21, 2020
85c04ce
Merge branch 'master' into julong/nodeDesign
alanlong9278 Feb 21, 2020
1de0d13
use styledComponent in visual editor
alanlong9278 Feb 21, 2020
8136288
refactor
alanlong9278 Feb 21, 2020
e662100
Merge branch 'master' into julong/nodeDesign
alanlong9278 Feb 22, 2020
e571084
add styled package
alanlong9278 Feb 22, 2020
cd45b6c
Merge branch 'julong/nodeDesign' of https://github.com/microsoft/BotF…
alanlong9278 Feb 22, 2020
cd3a822
module name
alanlong9278 Feb 22, 2020
0375ba5
revert uischema & refactor itemOverview component
alanlong9278 Feb 24, 2020
c06b9e6
ui adjust
alanlong9278 Feb 24, 2020
337e8f3
rename & delete needless code
alanlong9278 Feb 24, 2020
5221a3f
Merge branch 'master' into julong/nodeDesign
a-b-r-o-w-n Feb 25, 2020
1c4b956
Merge branch 'master' into julong/nodeDesign
alanlong9278 Feb 26, 2020
bbc3cc9
Merge branch 'julong/nodeDesign' of https://github.com/microsoft/BotF…
alanlong9278 Feb 26, 2020
291b44f
truncate text
alanlong9278 Feb 26, 2020
ea45495
Merge branch 'master' into julong/nodeDesign
alanlong9278 Feb 27, 2020
4c4cbf6
copy formcard to listoverviewcard for choiceinput and setProperties
alanlong9278 Feb 27, 2020
e907af9
refactor code
alanlong9278 Feb 27, 2020
2c96f84
Merge branch 'master' into julong/nodeDesign
alanlong9278 Feb 27, 2020
da2dbd3
Merge branch 'master' into julong/nodeDesign
alanlong9278 Feb 28, 2020
b744555
delete listOverviewWidget
alanlong9278 Feb 28, 2020
349cd6e
css
alanlong9278 Feb 28, 2020
b05c560
fix some bug
alanlong9278 Feb 29, 2020
582bb49
Merge branch 'master' into julong/nodeDesign
alanlong9278 Mar 2, 2020
0535f83
Merge branch 'master' into julong/nodeDesign
alanlong9278 Mar 3, 2020
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
3 changes: 2 additions & 1 deletion Composer/packages/extensions/visual-designer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
},
"dependencies": {
"@bfc/shared": "*",
"@emotion/core": "^10.0.7",
"@emotion/core": "^10.0.27",
"@emotion/styled": "^10.0.27",
"@types/react": "16.9.0",
"classnames": "^2.2.6",
"create-react-class": "^15.6.3",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import React from 'react';

import { MultiLineDiv, parseElementSchema } from '../elements/styledComponents';
import { UIElement } from '../elements/styledComponents.types';

export interface ListOverviewProps {
items: string[];
elementSchema: UIElement;
maxCount: number;
role: string;
styles?: Record<string, any>;
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
}
export const ListOverview: React.FC<ListOverviewProps> = ({ items, elementSchema, maxCount, role, styles }) => {
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
const { ElementComponent, props } = parseElementSchema(elementSchema);
return (
<>
{items.map((value, index) => {
if (index < 3) {
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
return (
<ElementComponent
key={index}
role={role}
title={typeof value === 'string' ? value : ''}
{...props}
style={styles}
>
{value}
</ElementComponent>
);
}
})}
{items.length > maxCount ? (
<MultiLineDiv
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
data-testid="hasMore"
style={{
...styles,
textAlign: 'center',
}}
>
{`${items.length - 3} more`}
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
</MultiLineDiv>
) : null}
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { css } from '@emotion/core';
import styled from '@emotion/styled';
import { Link } from 'office-ui-fabric-react/lib/Link';

import { ObiColors } from '../../constants/ElementColors';

import { UIElement, ElementProps, MultiLineDivProps, UI_ELEMENT_KEY } from './styledComponents.types';

const dynamicStyle = props =>
css`
color: ${props.color || ObiColors.Black};
`;

export const parseElementSchema = (element: UIElement) => {
const { [UI_ELEMENT_KEY]: ElementComponent, ...props } = element;
return {
ElementComponent,
props,
};
};

export const LinkBtn = styled(Link)`
${dynamicStyle}
`;

export const Span = styled.span`
${dynamicStyle}
`;

export const BorderedDiv = styled.div<ElementProps>(props => ({
color: props.color || ObiColors.Black,
padding: '2px 0 0 8px',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflow: 'hidden',
fontFamily: 'Segoe UI',
fontSize: '12px',
lineHeight: '14px',
border: '1px solid #C4C4C4',
boxSizing: 'border-box',
}));

export const MultiLineDiv = styled.div<MultiLineDivProps>(props => ({
color: props.color || ObiColors.Black,
fontSize: '12px',
lineHeight: '19px',
fontFamily: 'Segoe UI',
overflow: 'hidden',
textOverflow: 'ellipsis',
display: '-webkit-box',
'-webkit-line-clamp': props.lineNum || 1,
'-webkit-box-orient': 'vertical',
}));
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { DetailedHTMLProps, HTMLAttributes, ComponentClass, FC } from 'react';

export const UI_ELEMENT_KEY = 'ui:element';
export type ElementProps = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
export interface MultiLineDivProps extends ElementProps {
lineNum?: number;
}
export interface UIElement {
[UI_ELEMENT_KEY]: ElementComponent<ElementProps>;
propKey?: ElementProps;
}

export type ElementComponent<T extends ElementProps> = FC<T> | ComponentClass<T, any>;
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { FunctionComponent } from 'react';
import { InitNodeSize } from '../../../constants/ElementSizes';
import { ElementIcon } from '../../../utils/obiPropertyResolver';
import { Icon } from '../../decorations/icon';
import { MultiLineDiv } from '../../elements/styledComponents';

const boxWidth = InitNodeSize.width;
const boxHeight = InitNodeSize.height;
Expand All @@ -28,7 +29,7 @@ const containerStyle = {
interface NodeProps {
header: string;
corner?: any;
label: any;
label?: any;
icon?: string;
iconSize?: number;
styles?: object;
Expand Down Expand Up @@ -95,47 +96,35 @@ export const FormCard: FunctionComponent<NodeProps> = ({
height: contentHeight,
}}
>
<div
css={{
fontWeight: 400,
paddingLeft: '5px',
margin: '3px 5px',
fontSize: '14px',
lineHeight: '19px',
display: 'flex',
alignItems: 'center',
}}
>
{icon && icon !== ElementIcon.None && (
<div
css={{
width: 16,
height: 16,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginRight: '5px',
}}
>
<Icon icon={icon} color={iconColor} size={iconSize || 16} />
</div>
)}
{label && (
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
<div
css={{
height: '100%',
width: 'calc(100% - 20px)',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflow: 'hidden',
fontSize: '12px',
fontWeight: 400,
paddingLeft: '5px',
margin: '3px 5px',
fontSize: '14px',
lineHeight: '19px',
fontFamily: 'Segoe UI',
display: 'flex',
alignItems: 'center',
}}
title={typeof label === 'string' ? label : ''}
>
{label}
{icon && icon !== ElementIcon.None && (
<div
css={{
width: 16,
height: 16,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginRight: '5px',
}}
>
<Icon icon={icon} color={iconColor} size={iconSize || 16} />
</div>
)}
<MultiLineDiv title={typeof label === 'string' ? label : ''}>{label}</MultiLineDiv>
</div>
</div>
)}
{children}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ export const ChoiceInputSize = {
export const ChoiceInputMarginTop = 8;
export const ChoiceInputMarginBottom = 10;

export const PropertyAssignmentSize = {
width: 155,
height: 16,
};

export const AssignmentMarginTop = 6;
export const AssignmentMarginBottom = 8;

export const EventNodeSize = {
width: 240,
height: 125,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import {
ChoiceInputMarginTop,
ChoiceInputMarginBottom,
IconBrickSize,
AssignmentMarginTop,
PropertyAssignmentSize,
AssignmentMarginBottom,
} from '../constants/ElementSizes';
import { transformIfCondtion } from '../transformers/transformIfCondition';
import { transformSwitchCondition } from '../transformers/transformSwitchCondition';
Expand Down Expand Up @@ -72,6 +75,20 @@ export function measureChoiceInputDetailBoundary(data): Boundary {
return new Boundary(width, height);
}

export function measurePropertyAssignmentBoundary(data): Boundary {
const width = InitNodeSize.width;
const height = Math.max(
InitNodeSize.height / 2 +
(data.assignments && Array.isArray(data.assignments)
? (data.assignments.length < 4
? data.assignments.length * (PropertyAssignmentSize.height + AssignmentMarginTop)
: 4 * (PropertyAssignmentSize.height + AssignmentMarginTop)) + AssignmentMarginBottom
: 0),
InitNodeSize.height
);
return new Boundary(width, height);
}

function measureBaseInputBoundary(data): Boundary {
const { botAsks, userAnswers } = transformBaseInput(data, '');
return calculateBaseInputBoundary(measureJsonBoundary(botAsks.json), measureJsonBoundary(userAnswers.json));
Expand Down Expand Up @@ -118,6 +135,9 @@ export function measureJsonBoundary(json): Boundary {
case ObiTypes.InvalidPromptBrick:
boundary = new Boundary(IconBrickSize.width, IconBrickSize.height);
break;
case ObiTypes.SetProperties:
boundary = measurePropertyAssignmentBoundary(json);
break;
default:
boundary = new Boundary(InitNodeSize.width, InitNodeSize.height);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ import { IfConditionWidget } from '../widgets/IfConditionWidget';
import { SwitchConditionWidget } from '../widgets/SwitchConditionWidget';
import { ForeachWidget } from '../widgets/ForeachWidget';
import { ChoiceInputChoices } from '../widgets/ChoiceInput';
import { PropertiesWidget } from '../widgets/PropertiesWidget';
import { ElementIcon } from '../utils/obiPropertyResolver';
import { ObiColors } from '../constants/ElementColors';
import { measureChoiceInputDetailBoundary } from '../layouters/measureJsonBoundary';
import { measureChoiceInputDetailBoundary, measurePropertyAssignmentBoundary } from '../layouters/measureJsonBoundary';
import { UI_ELEMENT_KEY } from '../components/elements/styledComponents.types';
import { MultiLineDiv, BorderedDiv } from '../components/elements/styledComponents';

import { UISchema, UIWidget } from './uischema.types';

Expand All @@ -40,7 +43,10 @@ const BaseInputSchema: UIWidget = {
icon: ElementIcon.User,
menu: 'none',
content: data => data.property || '<property>',
children: data => (data.$type === SDKTypes.ChoiceInput ? <ChoiceInputChoices choices={data.choices} /> : null),
children: data =>
data.$type === SDKTypes.ChoiceInput ? (
<ChoiceInputChoices choices={data.choices} elementSchema={{ [UI_ELEMENT_KEY]: BorderedDiv }} />
) : null,
size: data => measureChoiceInputDetailBoundary(data),
colors: {
theme: ObiColors.LightBlue,
Expand Down Expand Up @@ -126,8 +132,9 @@ export const uiSchema: UISchema = {
content: data => `{${data.property || '?'}} = ${data.value || '?'}`,
},
[SDKTypes.SetProperties]: {
'ui:widget': ActionCard,
content: data => `Set ${Array.isArray(data.assignments) ? data.assignments.length : 0} property values`,
'ui:widget': PropertiesWidget,
content: data => ({ assignments: data.assignments, elementSchema: { [UI_ELEMENT_KEY]: MultiLineDiv } }),
size: data => measurePropertyAssignmentBoundary(data),
},
[SDKTypes.DeleteProperty]: {
'ui:widget': ActionCard,
Expand Down
Loading