diff --git a/packages/studio-ui-codegen-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap b/packages/studio-ui-codegen-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap index 57c64037f..129e8fe0c 100644 --- a/packages/studio-ui-codegen-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap +++ b/packages/studio-ui-codegen-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap @@ -18,7 +18,7 @@ export default function Test(props: TestProps): JSX.Element { fontFamily=\\"Times New Roman\\" fontSize=\\"20px\\" {...props} - {...getOverrideProps(props.overrides, \\"View\\")} + {...getOverrideProps(props.overrides, \\"Box\\")} > ); } @@ -93,12 +93,11 @@ export type BoxWithButtonProps = {} & { }; export default function BoxWithButton(props: BoxWithButtonProps): JSX.Element { return ( - + ); @@ -124,7 +123,7 @@ export default function BoxWithCustomButton( props: BoxWithCustomButtonProps ): JSX.Element { return ( - + + ); @@ -175,16 +173,17 @@ import { } from \\"@aws-amplify/ui-react\\"; export type ComponentWithDataBindingProps = { - width: Number, - isDisabled: Boolean, + width?: Number, + isDisabled?: Boolean, buttonUser?: User, - buttonColor: String, + buttonColor?: String, } & { overrides?: EscapeHatchProps | undefined | null, }; export default function ComponentWithDataBinding( props: ComponentWithDataBindingProps ): JSX.Element { + const { width, isDisabled, buttonUser, buttonColor } = props; return ( ); @@ -265,14 +262,13 @@ function BoxWithButton(props) { Object.assign( {}, props, - ui_react_1.getOverrideProps(props.overrides, \\"View\\") + ui_react_1.getOverrideProps(props.overrides, \\"Box\\") ), react_1.default.createElement( ui_react_1.Button, Object.assign( { color: \\"#ff0000\\", width: \\"20px\\" }, - props, - ui_react_1.getOverrideProps(props.overrides, \\"Button\\") + ui_react_1.getOverrideProps(props.overrides, \\"Box.Button\\") ) ) ); @@ -297,11 +293,7 @@ export type BoxWithButtonProps = {} & { }; export default function BoxWithButton(props: BoxWithButtonProps): JSX.Element { return ( - + - children.map((child) => this.renderJsx(child)), + return new CollectionRenderer(component, this.importCollection, parent).renderElement((children) => + children.map((child) => this.renderJsx(child, node)), ); case 'Badge': - return new BadgeRenderer(component, this.importCollection).renderElement((children) => - children.map((child) => this.renderJsx(child)), + return new BadgeRenderer(component, this.importCollection, parent).renderElement((children) => + children.map((child) => this.renderJsx(child, node)), ); case 'Button': - return new ButtonRenderer(component, this.importCollection).renderElement((children) => - children.map((child) => this.renderJsx(child)), + return new ButtonRenderer(component, this.importCollection, parent).renderElement((children) => + children.map((child) => this.renderJsx(child, node)), ); case 'Box': - return new BoxRenderer(component, this.importCollection).renderElement((children) => - children.map((child) => this.renderJsx(child)), + return new BoxRenderer(component, this.importCollection, parent).renderElement((children) => + children.map((child) => this.renderJsx(child, node)), ); case 'Card': - return new CardRenderer(component, this.importCollection).renderElement((children) => - children.map((child) => this.renderJsx(child)), + return new CardRenderer(component, this.importCollection, parent).renderElement((children) => + children.map((child) => this.renderJsx(child, node)), ); case 'Divider': - return new DividerRenderer(component, this.importCollection).renderElement(); + return new DividerRenderer(component, this.importCollection, parent).renderElement(); case 'Flex': - return new FlexRenderer(component, this.importCollection).renderElement((children) => - children.map((child) => this.renderJsx(child)), + return new FlexRenderer(component, this.importCollection, parent).renderElement((children) => + children.map((child) => this.renderJsx(child, node)), ); case 'Image': - return new ImageRenderer(component, this.importCollection).renderElement(); + return new ImageRenderer(component, this.importCollection, parent).renderElement(); case 'String': return renderString(component); case 'Text': - return new TextRenderer(component, this.importCollection).renderElement(); + return new TextRenderer(component, this.importCollection, parent).renderElement(); } console.warn(`${component.componentType} is not one of the primitives - assuming CustomComponent`); return new CustomComponentRenderer(component, this.importCollection).renderElement((children) => - children.map((child) => this.renderJsx(child)), + children.map((child) => this.renderJsx(child, node)), ); } } diff --git a/packages/studio-ui-codegen-react/lib/react-component-renderer.ts b/packages/studio-ui-codegen-react/lib/react-component-renderer.ts index c48e09b3d..6295a63ba 100644 --- a/packages/studio-ui-codegen-react/lib/react-component-renderer.ts +++ b/packages/studio-ui-codegen-react/lib/react-component-renderer.ts @@ -1,13 +1,17 @@ import { StudioComponent, StudioComponentChild, StudioComponentProperties } from '@amzn/amplify-ui-codegen-schema'; -import { ComponentRendererBase } from '@amzn/studio-ui-codegen'; +import { ComponentRendererBase, StudioNode } from '@amzn/studio-ui-codegen'; import { JsxAttribute, JsxAttributeLike, JsxElement, JsxOpeningElement, NodeFactory } from 'typescript'; import { addBindingPropertiesImports, buildOpeningElementAttributes } from './react-component-render-helper'; import { ImportCollection } from './import-collection'; export abstract class ReactComponentRenderer extends ComponentRendererBase { - constructor(component: StudioComponent | StudioComponentChild, protected importCollection: ImportCollection) { - super(component); + constructor( + component: StudioComponent | StudioComponentChild, + protected importCollection: ImportCollection, + protected parent?: StudioNode, + ) { + super(component, parent); addBindingPropertiesImports(component, importCollection); } @@ -32,8 +36,10 @@ export abstract class ReactComponentRenderer extends ComponentRendererB } private addPropsSpreadAttributes(factory: NodeFactory, attributes: JsxAttributeLike[], tagName: string) { - const propsAttr = factory.createJsxSpreadAttribute(factory.createIdentifier('props')); - attributes.push(propsAttr); + if (this.node.isRoot()) { + const propsAttr = factory.createJsxSpreadAttribute(factory.createIdentifier('props')); + attributes.push(propsAttr); + } const overrideAttr = factory.createJsxSpreadAttribute( factory.createCallExpression(factory.createIdentifier('getOverrideProps'), undefined, [ @@ -41,7 +47,13 @@ export abstract class ReactComponentRenderer extends ComponentRendererB factory.createIdentifier('props'), factory.createIdentifier('overrides'), ), - factory.createStringLiteral(tagName), + factory.createStringLiteral( + this.node + .getComponentPathToRoot() + .reverse() + .map((component) => component.componentType) + .join('.'), + ), ]), ); this.importCollection.addImport('@aws-amplify/ui-react', 'getOverrideProps'); diff --git a/packages/studio-ui-codegen-react/lib/react-component-with-children-renderer.ts b/packages/studio-ui-codegen-react/lib/react-component-with-children-renderer.ts index d3d80e1cb..f9cc82f37 100644 --- a/packages/studio-ui-codegen-react/lib/react-component-with-children-renderer.ts +++ b/packages/studio-ui-codegen-react/lib/react-component-with-children-renderer.ts @@ -1,4 +1,4 @@ -import { ComponentWithChildrenRendererBase } from '@amzn/studio-ui-codegen'; +import { ComponentWithChildrenRendererBase, StudioNode } from '@amzn/studio-ui-codegen'; import { StudioComponent, StudioComponentChild, StudioComponentProperties } from '@amzn/amplify-ui-codegen-schema'; import { @@ -19,8 +19,12 @@ export abstract class ReactComponentWithChildrenRenderer extends Compon JsxElement, JsxChild > { - constructor(component: StudioComponent | StudioComponentChild, protected importCollection: ImportCollection) { - super(component); + constructor( + component: StudioComponent | StudioComponentChild, + protected importCollection: ImportCollection, + protected parent?: StudioNode, + ) { + super(component, parent); addBindingPropertiesImports(component, importCollection); } @@ -92,8 +96,10 @@ export abstract class ReactComponentWithChildrenRenderer extends Compon } private addPropsSpreadAttributes(factory: NodeFactory, attributes: JsxAttributeLike[], tagName: string) { - const propsAttr = factory.createJsxSpreadAttribute(factory.createIdentifier('props')); - attributes.push(propsAttr); + if (this.node.isRoot()) { + const propsAttr = factory.createJsxSpreadAttribute(factory.createIdentifier('props')); + attributes.push(propsAttr); + } const overrideAttr = factory.createJsxSpreadAttribute( factory.createCallExpression(factory.createIdentifier('getOverrideProps'), undefined, [ @@ -101,7 +107,13 @@ export abstract class ReactComponentWithChildrenRenderer extends Compon factory.createIdentifier('props'), factory.createIdentifier('overrides'), ), - factory.createStringLiteral(tagName), + factory.createStringLiteral( + this.node + .getComponentPathToRoot() + .reverse() + .map((component) => component.componentType) + .join('.'), + ), ]), ); this.importCollection.addImport('@aws-amplify/ui-react', 'getOverrideProps'); diff --git a/packages/studio-ui-codegen/index.ts b/packages/studio-ui-codegen/index.ts index 7d8ab21fe..8c92b3e14 100644 --- a/packages/studio-ui-codegen/index.ts +++ b/packages/studio-ui-codegen/index.ts @@ -11,3 +11,4 @@ export * from './lib/mapper/mapper-base'; export * from './lib/renderer-helper'; export * from './lib/framework-output-config'; export * from './lib/framework-render-config'; +export * from './lib/studio-node'; diff --git a/packages/studio-ui-codegen/lib/common-component-renderer.ts b/packages/studio-ui-codegen/lib/common-component-renderer.ts index 1c44f7ecf..1454172db 100644 --- a/packages/studio-ui-codegen/lib/common-component-renderer.ts +++ b/packages/studio-ui-codegen/lib/common-component-renderer.ts @@ -6,6 +6,8 @@ import { WrappedComponentProperties, } from '@amzn/amplify-ui-codegen-schema'; +import { StudioNode } from './studio-node'; + /** * Shared class for rendering components. * Mostly contains helper functions for mapping the Studio schema to actual props. @@ -13,10 +15,13 @@ import { export abstract class CommonComponentRenderer { protected inputProps: WrappedComponentProperties; - constructor(protected component: StudioComponent | StudioComponentChild) { + protected node: StudioNode; + + constructor(protected component: StudioComponent | StudioComponentChild, protected parent?: StudioNode) { const flattenedProps = Object.entries(component.properties).map((prop) => { return [prop[0], prop[1]]; }); this.inputProps = Object.fromEntries(flattenedProps); + this.node = new StudioNode(component, parent); } } diff --git a/packages/studio-ui-codegen/lib/studio-node.ts b/packages/studio-ui-codegen/lib/studio-node.ts new file mode 100644 index 000000000..fc6709f4b --- /dev/null +++ b/packages/studio-ui-codegen/lib/studio-node.ts @@ -0,0 +1,23 @@ +import { StudioComponent, StudioComponentChild } from '@amzn/amplify-ui-codegen-schema'; + +export class StudioNode { + component: StudioComponent | StudioComponentChild; + + parent?: StudioNode; + + constructor(component: StudioComponent | StudioComponentChild, parent?: StudioNode) { + this.component = component; + this.parent = parent; + } + + isRoot(): boolean { + return this.parent === undefined; + } + + getComponentPathToRoot(): (StudioComponent | StudioComponentChild)[] { + if (this.parent !== undefined) { + return [this.component].concat(this.parent.getComponentPathToRoot()); + } + return [this.component]; + } +}