Skip to content

Commit

Permalink
fix: updating override paths to support child indices
Browse files Browse the repository at this point in the history
  • Loading branch information
alharris-at committed Nov 3, 2021
1 parent 7510dc8 commit 278b6f8
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 93 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,7 @@ export class ReactComponentRenderer<TPropIn> extends ComponentRendererBase<TProp
const overrideAttr = factory.createJsxSpreadAttribute(
factory.createCallExpression(factory.createIdentifier('getOverrideProps'), undefined, [
factory.createIdentifier('overrides'),
factory.createStringLiteral(
this.node
.getComponentPathToRoot()
.reverse()
.map((component) => component.componentType)
.join('.'),
),
factory.createStringLiteral(this.node.getOverrideKey()),
]),
);
this.importCollection.addImport('@aws-amplify/ui-react', 'getOverrideProps');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,7 @@ export class ReactComponentWithChildrenRenderer<TPropIn> extends ComponentWithCh
const overrideAttr = factory.createJsxSpreadAttribute(
factory.createCallExpression(factory.createIdentifier('getOverrideProps'), undefined, [
factory.createIdentifier('overrides'),
factory.createStringLiteral(
this.node
.getComponentPathToRoot()
.reverse()
.map((component) => component.componentType)
.join('.'),
),
factory.createStringLiteral(this.node.getOverrideKey()),
]),
);
this.importCollection.addImport('@aws-amplify/ui-react', 'getOverrideProps');
Expand Down
2 changes: 1 addition & 1 deletion packages/studio-ui-codegen-react/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ MockComponentRenderer {
},
},
"node": StudioNode {
"children": Array [],
"component": Object {
"componentType": "Button",
"name": "MyButton",
Expand All @@ -26,7 +27,11 @@ MockComponentRenderer {
},
},
},
"elementIndex": 0,
"parent": StudioNode {
"children": Array [
[Circular],
],
"component": Object {
"componentType": "View",
"name": "MyView",
Expand All @@ -36,6 +41,22 @@ MockComponentRenderer {
},
},
"parent": StudioNode {
"children": Array [
StudioNode {
"children": Array [],
"component": Object {
"componentType": "Button",
"name": "MyButton",
"properties": Object {
"value": Object {
"value": "Confirm",
},
},
},
"elementIndex": 0,
"parent": [Circular],
},
],
"component": Object {
"componentType": "View",
"name": "MyView",
Expand Down
87 changes: 85 additions & 2 deletions packages/studio-ui-codegen/lib/__tests__/studio-node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
/* eslint-disable no-new */
import { StudioNode } from '../studio-node';
import { StudioComponentChild } from '../types';

describe('StudioNone', () => {
describe('StudioNode', () => {
describe('isRoot', () => {
test('true when parent is undefined', () => {
const component = {
Expand Down Expand Up @@ -56,7 +58,88 @@ describe('StudioNone', () => {
};
const componentPathToRoot = new StudioNode(component, parent).getComponentPathToRoot();

expect(componentPathToRoot.map(({ name }) => name)).toEqual([componentName, parentComponentName]);
expect(componentPathToRoot.map(({ component: { name } }) => name)).toEqual([componentName, parentComponentName]);
});
});

describe('getOverrideKey', () => {
test('returns for parent', () => {
const rootComponent = new StudioNode(createSimpleComponentForType('Flex'));
new StudioNode(createSimpleComponentForType('Button'), rootComponent);

expect(rootComponent.getOverrideKey()).toEqual('Flex');
});

test('returns only one child', () => {
const rootComponent = new StudioNode(createSimpleComponentForType('Flex'));
const childComponent = new StudioNode(createSimpleComponentForType('Button'), rootComponent);

expect(childComponent.getOverrideKey()).toEqual('Flex.Button[0]');
});

test('returns index 0 for first of multiple elements', () => {
const rootComponent = new StudioNode(createSimpleComponentForType('Flex'));
const firstChildComponent = new StudioNode(createSimpleComponentForType('Button'), rootComponent);
new StudioNode(createSimpleComponentForType('Button'), rootComponent);
new StudioNode(createSimpleComponentForType('Tooltip'), rootComponent);

expect(firstChildComponent.getOverrideKey()).toEqual('Flex.Button[0]');
});

test('returns index 0 for first of element of type', () => {
const rootComponent = new StudioNode(createSimpleComponentForType('Flex'));
new StudioNode(createSimpleComponentForType('Button'), rootComponent);
new StudioNode(createSimpleComponentForType('Button'), rootComponent);
const firstTooltipChildComponent = new StudioNode(createSimpleComponentForType('Tooltip'), rootComponent);

expect(firstTooltipChildComponent.getOverrideKey()).toEqual('Flex.Tooltip[0]');
});

test('returns index 1 for second of element of type', () => {
const rootComponent = new StudioNode(createSimpleComponentForType('Flex'));
new StudioNode(createSimpleComponentForType('Button'), rootComponent);
const secondChildComponent = new StudioNode(createSimpleComponentForType('Button'), rootComponent);
new StudioNode(createSimpleComponentForType('Tooltip'), rootComponent);

expect(secondChildComponent.getOverrideKey()).toEqual('Flex.Button[1]');
});

/**
* <Flex> <-- rootComponent: 'Flex'
* <Flex />
* <Flex />
* <Flex> <-- thirdComponentOfType: 'Flex.Flex[2]'
* <Button />
* <Button> <-- secondSubChildOfType: 'Flex.Flex[2].Button[1]'
* <Tooltip /> <-- firstSubSubChild: 'Flex.Flex[2].Button[1].Tooltip[0]'
* </Button>
* </Flex>
* <Tooltip />
* <Button />
* </Flex>
*/
test('returns for deeply nested elements', () => {
const rootComponent = new StudioNode(createSimpleComponentForType('Flex'));
new StudioNode(createSimpleComponentForType('Flex'), rootComponent);
new StudioNode(createSimpleComponentForType('Flex'), rootComponent);
const thirdChildComponentOfType = new StudioNode(createSimpleComponentForType('Flex'), rootComponent);
new StudioNode(createSimpleComponentForType('Tooltip'), rootComponent);
new StudioNode(createSimpleComponentForType('Button'), rootComponent);
new StudioNode(createSimpleComponentForType('Button'), thirdChildComponentOfType);
const secondSubChildOfType = new StudioNode(createSimpleComponentForType('Button'), thirdChildComponentOfType);
const firstSubSubChild = new StudioNode(createSimpleComponentForType('Tooltip'), secondSubChildOfType);

expect(thirdChildComponentOfType.getOverrideKey()).toEqual('Flex.Flex[2]');
expect(secondSubChildOfType.getOverrideKey()).toEqual('Flex.Flex[2].Button[1]');
expect(firstSubSubChild.getOverrideKey()).toEqual('Flex.Flex[2].Button[1].Tooltip[0]');
});
});
});

const createSimpleComponentForType = (type: string): StudioComponentChild => {
return {
componentType: type,
name: type,
properties: {},
};
};
35 changes: 32 additions & 3 deletions packages/studio-ui-codegen/lib/studio-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,48 @@ export class StudioNode {

parent?: StudioNode;

children: StudioNode[];

elementIndex?: number;

constructor(component: StudioComponent | StudioComponentChild, parent?: StudioNode) {
this.component = component;
this.parent = parent;
this.children = [];
if (this.parent) {
this.elementIndex = this.parent.children.filter(
(childNode) => this.component.componentType === childNode.component.componentType,
).length;
this.parent.children.push(this);
}
}

isRoot(): boolean {
return this.parent === undefined;
}

getComponentPathToRoot(): (StudioComponent | StudioComponentChild)[] {
getComponentPathToRoot(): StudioNode[] {
if (this.parent !== undefined) {
return [this.component].concat(this.parent.getComponentPathToRoot());
return [this as StudioNode].concat(this.parent.getComponentPathToRoot());
}
return [this.component];
return [this];
}

/**
* Build the override path for a given element walking from the node to tree root, providing an index
* for all but the top-level components.
* Example:
* <Flex> <-- returns 'Flex'
* <Button> <-- returns 'Flex.Button[0]'
* <Button> <-- returns 'Flex.Button[1]'
* <Flex> <-- returns 'Flex.Flex[0]'
* </Button> <-- returns 'Flex.Flex[0].Button[0]'
* </Flex>
* </Flex>
*/
getOverrideKey(): string {
const [parentElement, ...childElements] = this.getComponentPathToRoot().reverse();
const childPath = childElements.map((node) => `${node.component.componentType}[${node.elementIndex}]`);
return [parentElement.component.componentType, ...childPath].join('.');
}
}
2 changes: 1 addition & 1 deletion packages/studio-ui-codegen/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/test-generator/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 278b6f8

Please sign in to comment.