diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/BaseInput.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/BaseInput.tsx index d10d209cfb..f824bea719 100644 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/BaseInput.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/BaseInput.tsx @@ -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); @@ -33,31 +36,19 @@ export const BaseInput: FC = ({ id, data, onEvent, onResize }): JSX.E return (
- + + + - + + + - + + + {edges ? edges.map(x => ) : null}
diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/Foreach.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/Foreach.tsx index c45ecf053e..cc31e9c421 100644 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/Foreach.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/Foreach.tsx @@ -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'; @@ -68,16 +71,19 @@ export const Foreach: FunctionComponent = ({ id, data, onEvent, onRes } const { foreachNode, stepsNode, loopBeginNode, loopEndNode } = nodeMap; + const ForeachHeader = data.$type === ObiTypes.Foreach ? ForeachDetail : ForeachPageDetail; return (
- + + + = ({ id, data, onEvent, o return (
- + + + { const result = transformSwitchCondition(data, path); @@ -65,13 +66,15 @@ export const SwitchCondition: FunctionComponent = ({ id, data, onEven return (
- + + + | ComponentClass { - const renderer = rendererByObiType[$type] || DEFAULT_RENDERER; - return renderer; -} const nodeBorderHoveredStyle = css` box-shadow: 0px 0px 0px 1px #323130; @@ -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 = ({ id, data, onEvent, onResize, tab }): JSX.Element => { - const ChosenRenderer = chooseRendererByType(data.$type); +export const ElementWrapper: FC = ({ id, tab, children }): JSX.Element => { const selectableId = tab ? `${id}${tab}` : id; const { focusedId, focusedEvent, focusedTab } = useContext(NodeRendererContext); const { selectedIds, getNodeIndex } = useContext(SelectionContext); @@ -86,16 +63,7 @@ export const ElementRenderer: FC = ({ id, data, onEvent, onResize, ta `} {...declareElementAttributes(selectableId, id)} > - { - onResize(size, 'element'); - }} - /> + {children}
); }; - -ElementRenderer.defaultProps = defaultNodeProps; diff --git a/Composer/packages/extensions/visual-designer/src/components/renderers/StepRenderer.tsx b/Composer/packages/extensions/visual-designer/src/components/renderers/StepRenderer.tsx index ecda4751fb..6dfe14d70c 100644 --- a/Composer/packages/extensions/visual-designer/src/components/renderers/StepRenderer.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/renderers/StepRenderer.tsx @@ -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, @@ -23,17 +26,31 @@ const rendererByObiType = { [ObiTypes.TextInput]: BaseInput, [ObiTypes.ChoiceInput]: BaseInput, }; -const DEFAULT_RENDERER = ElementRenderer; +const DEFAULT_RENDERER = UISchemaRenderer; function chooseRendererByType($type): FC | ComponentClass { 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 = ({ id, data, onEvent, onResize }): JSX.Element => { - const ChosenRenderer = chooseRendererByType(data.$type); + const $type = get(data, '$type', ''); - return ( + const ChosenRenderer = chooseRendererByType($type); + const content = ( = ({ id, data, onEvent, onResize }): JS }} /> ); + + if (TypesWithoutWrapper.some(x => $type === x)) { + return content; + } + + return {content}; }; StepRenderer.defaultProps = defaultNodeProps; diff --git a/Composer/packages/extensions/visual-designer/src/schema/uischema.types.ts b/Composer/packages/extensions/visual-designer/src/schema/uischema.types.ts index 546980b1ab..6fb2a37d7e 100644 --- a/Composer/packages/extensions/visual-designer/src/schema/uischema.types.ts +++ b/Composer/packages/extensions/visual-designer/src/schema/uischema.types.ts @@ -34,6 +34,6 @@ export interface WidgetContainerProps { [propKey: string]: any; } -export type UIWidgetProp = Value | PropGenerator; +export type UIWidgetProp = Value | PropGenerator | UIWidget; type Value = string | number | { [key: string]: any }; type PropGenerator = (data: any) => string | number | object | JSX.Element; diff --git a/Composer/packages/extensions/visual-designer/src/schema/uischemaRenderer.tsx b/Composer/packages/extensions/visual-designer/src/schema/uischemaRenderer.tsx index a088031c80..0b27608df9 100644 --- a/Composer/packages/extensions/visual-designer/src/schema/uischemaRenderer.tsx +++ b/Composer/packages/extensions/visual-designer/src/schema/uischemaRenderer.tsx @@ -8,34 +8,41 @@ import get from 'lodash/get'; import { uiSchema } from './uischema'; import { UIWidget, UI_WIDGET_KEY, UIWidgetProp, WidgetEventHandler } from './uischema.types'; -const buildWidgetProp = (data: BaseSchema, rawPropValue: UIWidgetProp) => { +const parseWidgetSchema = (widgetSchema: UIWidget) => { + const { [UI_WIDGET_KEY]: Widget, ...props } = widgetSchema; + return { + Widget, + props, + }; +}; + +const buildWidgetProp = (rawPropValue: UIWidgetProp, context: UISchemaContext) => { if (typeof rawPropValue === 'function') { const dataTransformer = rawPropValue; - const element = dataTransformer(data); + const element = dataTransformer(context.data); return element; } + if (typeof rawPropValue === 'object' && rawPropValue[UI_WIDGET_KEY]) { + const widgetSchema = rawPropValue as UIWidget; + return renderUISchema(widgetSchema, context); + } + return rawPropValue; }; -const buildWidgetProps = (data: BaseSchema, rawProps) => { - return Object.keys(rawProps).reduce((props, propName) => { +const renderUISchema = (schema: UIWidget, context: UISchemaContext): JSX.Element => { + const { Widget, props: rawProps } = parseWidgetSchema(schema); + const widgetProps = Object.keys(rawProps).reduce((props, propName) => { const propValue = rawProps[propName]; - props[propName] = buildWidgetProp(data, propValue); + props[propName] = buildWidgetProp(propValue, context); return props; }, {}); -}; -const parseWidgetSchema = (data: BaseSchema, widgetSchema: UIWidget) => { - const { [UI_WIDGET_KEY]: Widget, ...rawProps } = widgetSchema; - const props = buildWidgetProps(data, rawProps); - return { - Widget, - props, - }; + return ; }; -export interface UISchemaRendererProps { +export interface UISchemaContext { /** The uniq id of current schema data. Usually a json path. */ id: string; @@ -46,9 +53,8 @@ export interface UISchemaRendererProps { onEvent: WidgetEventHandler; } -export const UISchemaRenderer: FC = ({ id, data, onEvent, ...contextProps }): JSX.Element => { - const $type = get(data, '$type'); +export const UISchemaRenderer: FC = (props): JSX.Element => { + const $type = get(props.data, '$type'); const schema = get(uiSchema, $type, uiSchema.default); - const { Widget, props } = parseWidgetSchema(data, schema); - return ; + return renderUISchema(schema, props); };