Skip to content

Commit

Permalink
render Elements with composition strategy (ElementRenderer -> Element…
Browse files Browse the repository at this point in the history
…Wrapper) (#1873)

Co-authored-by: Chris Whitten <[email protected]>
  • Loading branch information
yeze322 and cwhitten committed Jan 20, 2020
1 parent 0514596 commit 261cfb8
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import { OffsetContainer } from '../../lib/OffsetContainer';
import { Edge } from '../../lib/EdgeComponents';
import { GraphNode } from '../../../models/GraphNode';
import { transformBaseInput } from '../../../transformers/transformBaseInput';
import { ElementRenderer } from '../../renderers/ElementRenderer';
import { ElementWrapper } from '../../renderers/ElementWrapper';
import { BotAsks } from '../steps/BotAsks';
import { UserInput } from '../steps/UserInput';
import { InvalidPromptBrick } from '../steps/InvalidPromptBrick';

const calculateNodes = (data, jsonpath: string) => {
const { botAsks, userAnswers, invalidPrompt } = transformBaseInput(data, jsonpath);
Expand All @@ -33,31 +36,19 @@ export const BaseInput: FC<NodeProps> = ({ id, data, onEvent, onResize }): JSX.E
return (
<div className="Action-BaseInput" css={{ width: boundary.width, height: boundary.height }}>
<OffsetContainer offset={botAsksNode.offset}>
<ElementRenderer
id={botAsksNode.id}
tab={PromptTab.BOT_ASKS}
data={botAsksNode.data}
onEvent={onEvent}
onResize={onResize}
/>
<ElementWrapper id={botAsksNode.id} tab={PromptTab.BOT_ASKS}>
<BotAsks id={botAsksNode.id} data={botAsksNode.data} onEvent={onEvent} onResize={onResize} />
</ElementWrapper>
</OffsetContainer>
<OffsetContainer offset={userAnswersNode.offset}>
<ElementRenderer
id={userAnswersNode.id}
tab={PromptTab.USER_INPUT}
data={userAnswersNode.data}
onEvent={onEvent}
onResize={onResize}
/>
<ElementWrapper id={userAnswersNode.id} tab={PromptTab.USER_INPUT}>
<UserInput id={userAnswersNode.id} data={userAnswersNode.data} onEvent={onEvent} onResize={onResize} />
</ElementWrapper>
</OffsetContainer>
<OffsetContainer offset={brickNode.offset}>
<ElementRenderer
id={brickNode.id}
tab={PromptTab.OTHER}
data={brickNode.data}
onEvent={onEvent}
onResize={onResize}
/>
<ElementWrapper id={brickNode.id} tab={PromptTab.OTHER}>
<InvalidPromptBrick id={brickNode.id} data={brickNode.data} onEvent={onEvent} onResize={onResize} />
</ElementWrapper>
</OffsetContainer>
{edges ? edges.map(x => <Edge key={x.id} {...x} />) : null}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ import { NodeEventTypes } from '../../../constants/NodeEventTypes';
import { OffsetContainer } from '../../lib/OffsetContainer';
import { Edge } from '../../lib/EdgeComponents';
import { LoopIndicator } from '../../decorations/LoopIndicator';
import { ElementRenderer } from '../../renderers/ElementRenderer';
import { StepGroup } from '../../groups';
import { NodeProps, defaultNodeProps } from '../nodeProps';
import { ForeachDetail } from '../steps/ForeachDetail';
import { ElementWrapper } from '../../renderers/ElementWrapper';
import { ObiTypes } from '../../../constants/ObiTypes';
import { ForeachPageDetail } from '../steps/ForeachPageDetail';

import { NodeMap, BoundaryMap } from './types';

Expand Down Expand Up @@ -68,16 +71,19 @@ export const Foreach: FunctionComponent<NodeProps> = ({ id, data, onEvent, onRes
}

const { foreachNode, stepsNode, loopBeginNode, loopEndNode } = nodeMap;
const ForeachHeader = data.$type === ObiTypes.Foreach ? ForeachDetail : ForeachPageDetail;
return (
<div css={{ width: boundary.width, height: boundary.height, position: 'relative' }}>
<OffsetContainer offset={foreachNode.offset}>
<ElementRenderer
key={foreachNode.id}
id={foreachNode.id}
data={foreachNode.data}
onEvent={onEvent}
onResize={onResize}
/>
<ElementWrapper id={id}>
<ForeachHeader
key={foreachNode.id}
id={foreachNode.id}
data={foreachNode.data}
onEvent={onEvent}
onResize={onResize}
/>
</ElementWrapper>
</OffsetContainer>
<OffsetContainer offset={stepsNode.offset}>
<StepGroup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import { OffsetContainer } from '../../lib/OffsetContainer';
import { Edge } from '../../lib/EdgeComponents';
import { StepGroup } from '../../groups';
import { Diamond } from '../templates/Diamond';
import { ElementRenderer } from '../../renderers/ElementRenderer';
import { ElementWrapper } from '../../renderers/ElementWrapper';
import { NodeProps, defaultNodeProps } from '../nodeProps';
import { ConditionNode } from '../steps/ConditionNode';

import { NodeMap, BoundaryMap } from './types';

Expand Down Expand Up @@ -67,13 +68,15 @@ export const IfCondition: FunctionComponent<NodeProps> = ({ id, data, onEvent, o
return (
<div css={{ width: boundary.width, height: boundary.height, position: 'relative' }}>
<OffsetContainer offset={condition.offset}>
<ElementRenderer
key={condition.id}
id={condition.id}
data={condition.data}
onEvent={onEvent}
onResize={onResize}
/>
<ElementWrapper id={condition.id}>
<ConditionNode
key={condition.id}
id={condition.id}
data={condition.data}
onEvent={onEvent}
onResize={onResize}
/>
</ElementWrapper>
</OffsetContainer>
<OffsetContainer offset={choice.offset}>
<Diamond
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import { OffsetContainer } from '../../lib/OffsetContainer';
import { Edge } from '../../lib/EdgeComponents';
import { StepGroup } from '../../groups';
import { Diamond } from '../templates/Diamond';
import { ElementRenderer } from '../../renderers/ElementRenderer';
import { NodeProps, defaultNodeProps } from '../nodeProps';
import { ElementWrapper } from '../../renderers/ElementWrapper';
import { ConditionNode } from '../steps/ConditionNode';

const calculateNodeMap = (path, data) => {
const result = transformSwitchCondition(data, path);
Expand Down Expand Up @@ -65,13 +66,15 @@ export const SwitchCondition: FunctionComponent<NodeProps> = ({ id, data, onEven
return (
<div css={{ width: boundary.width, height: boundary.height, position: 'relative' }}>
<OffsetContainer offset={nodeMap && nodeMap.conditionNode.offset}>
<ElementRenderer
key={conditionNode.id}
id={conditionNode.id}
data={conditionNode.data}
onEvent={onEvent}
onResize={onResize}
/>
<ElementWrapper id={conditionNode.id}>
<ConditionNode
key={conditionNode.id}
id={conditionNode.id}
data={conditionNode.data}
onEvent={onEvent}
onResize={onResize}
/>
</ElementWrapper>
</OffsetContainer>
<OffsetContainer offset={choiceNode.offset} css={{ zIndex: 100 }}>
<Diamond
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,12 @@

/** @jsx jsx */
import { jsx, css } from '@emotion/core';
import { FC, ComponentClass, useContext } from 'react';
import { FC, useContext } from 'react';
import classnames from 'classnames';

import { ObiTypes } from '../../constants/ObiTypes';
import { AttrNames } from '../../constants/ElementAttributes';
import { NodeRendererContext } from '../../store/NodeRendererContext';
import { SelectionContext } from '../../store/SelectionContext';
import { ChoiceInput, BotAsks, UserInput, InvalidPromptBrick } from '../nodes/index';
import { ConditionNode } from '../nodes/steps/ConditionNode';
import { ForeachDetail } from '../nodes/steps/ForeachDetail';
import { ForeachPageDetail } from '../nodes/steps/ForeachPageDetail';
import { NodeProps, defaultNodeProps } from '../nodes/nodeProps';
import { UISchemaRenderer } from '../../schema/uischemaRenderer';

const rendererByObiType = {
[ObiTypes.ConditionNode]: ConditionNode,
[ObiTypes.ForeachDetail]: ForeachDetail,
[ObiTypes.ForeachPageDetail]: ForeachPageDetail,
[ObiTypes.BeginDialog]: UISchemaRenderer,
[ObiTypes.ReplaceDialog]: UISchemaRenderer,
[ObiTypes.SendActivity]: UISchemaRenderer,
[ObiTypes.ChoiceInputDetail]: ChoiceInput,
[ObiTypes.BotAsks]: BotAsks,
[ObiTypes.UserAnswers]: UserInput,
[ObiTypes.InvalidPromptBrick]: InvalidPromptBrick,
};
const DEFAULT_RENDERER = UISchemaRenderer;

function chooseRendererByType($type): FC<NodeProps> | ComponentClass<NodeProps> {
const renderer = rendererByObiType[$type] || DEFAULT_RENDERER;
return renderer;
}

const nodeBorderHoveredStyle = css`
box-shadow: 0px 0px 0px 1px #323130;
Expand All @@ -49,9 +23,12 @@ const nodeBorderDoubleSelectedStyle = css`
outline: 2px solid #0078d4;
box-shadow: 0px 0px 0px 6px rgba(0, 120, 212, 0.3);
`;
export interface ElementWrapperProps {
id: string;
tab?: string;
}

export const ElementRenderer: FC<NodeProps> = ({ id, data, onEvent, onResize, tab }): JSX.Element => {
const ChosenRenderer = chooseRendererByType(data.$type);
export const ElementWrapper: FC<ElementWrapperProps> = ({ id, tab, children }): JSX.Element => {
const selectableId = tab ? `${id}${tab}` : id;
const { focusedId, focusedEvent, focusedTab } = useContext(NodeRendererContext);
const { selectedIds, getNodeIndex } = useContext(SelectionContext);
Expand Down Expand Up @@ -86,16 +63,7 @@ export const ElementRenderer: FC<NodeProps> = ({ id, data, onEvent, onResize, ta
`}
{...declareElementAttributes(selectableId, id)}
>
<ChosenRenderer
id={id}
data={data}
onEvent={onEvent}
onResize={size => {
onResize(size, 'element');
}}
/>
{children}
</div>
);
};

ElementRenderer.defaultProps = defaultNodeProps;
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
/** @jsx jsx */
import { jsx } from '@emotion/core';
import { FC, ComponentClass } from 'react';
import { SDKTypes } from '@bfc/shared';
import get from 'lodash/get';

import { ObiTypes } from '../../constants/ObiTypes';
import { IfCondition, SwitchCondition, Foreach, BaseInput } from '../nodes/index';
import { NodeProps, defaultNodeProps } from '../nodes/nodeProps';
import { UISchemaRenderer } from '../../schema/uischemaRenderer';

import { ElementRenderer } from './ElementRenderer';
import { ElementWrapper } from './ElementWrapper';

const rendererByObiType = {
[ObiTypes.IfCondition]: IfCondition,
Expand All @@ -23,17 +26,31 @@ const rendererByObiType = {
[ObiTypes.TextInput]: BaseInput,
[ObiTypes.ChoiceInput]: BaseInput,
};
const DEFAULT_RENDERER = ElementRenderer;
const DEFAULT_RENDERER = UISchemaRenderer;

function chooseRendererByType($type): FC<NodeProps> | ComponentClass<NodeProps> {
const renderer = rendererByObiType[$type] || DEFAULT_RENDERER;
return renderer;
}

/** TODO: (zeye) integrate this array into UISchema */
const TypesWithoutWrapper = [
SDKTypes.IfCondition,
SDKTypes.SwitchCondition,
SDKTypes.Foreach,
SDKTypes.ForeachPage,
SDKTypes.AttachmentInput,
SDKTypes.ConfirmInput,
SDKTypes.DateTimeInput,
SDKTypes.NumberInput,
SDKTypes.TextInput,
SDKTypes.ChoiceInput,
];
export const StepRenderer: FC<NodeProps> = ({ id, data, onEvent, onResize }): JSX.Element => {
const ChosenRenderer = chooseRendererByType(data.$type);
const $type = get(data, '$type', '');

return (
const ChosenRenderer = chooseRendererByType($type);
const content = (
<ChosenRenderer
id={id}
data={data}
Expand All @@ -43,6 +60,12 @@ export const StepRenderer: FC<NodeProps> = ({ id, data, onEvent, onResize }): JS
}}
/>
);

if (TypesWithoutWrapper.some(x => $type === x)) {
return content;
}

return <ElementWrapper id={id}>{content}</ElementWrapper>;
};

StepRenderer.defaultProps = defaultNodeProps;

0 comments on commit 261cfb8

Please sign in to comment.