From bf632076b3edd78a1679e88917c295f0e86a9f07 Mon Sep 17 00:00:00 2001 From: Jane Chu <7559015+janechu@users.noreply.github.com> Date: Mon, 11 Feb 2019 18:20:07 -0800 Subject: [PATCH] feat: add root level component navigation and ability to have string children --- .../app/configs/example.data.ts | 1 + .../src/navigation/navigation.props.ts | 2 +- .../src/navigation/navigation.spec.tsx | 48 +++---- .../src/navigation/navigation.tsx | 122 ++++++++++-------- .../navigation/navigation.utilities.spec.ts | 43 ++++-- .../src/navigation/navigation.utilities.ts | 13 +- 6 files changed, 137 insertions(+), 92 deletions(-) diff --git a/packages/fast-navigation-generator-react/app/configs/example.data.ts b/packages/fast-navigation-generator-react/app/configs/example.data.ts index 255e7ee7e62..583c612fcdb 100644 --- a/packages/fast-navigation-generator-react/app/configs/example.data.ts +++ b/packages/fast-navigation-generator-react/app/configs/example.data.ts @@ -11,6 +11,7 @@ const noChildren: any = { const children: any = { children: [ + "Foo", { id: get(noChildrenSchema, "id"), props: noChildren, diff --git a/packages/fast-navigation-generator-react/src/navigation/navigation.props.ts b/packages/fast-navigation-generator-react/src/navigation/navigation.props.ts index 22fb8b7ff52..bb2e0e41682 100644 --- a/packages/fast-navigation-generator-react/src/navigation/navigation.props.ts +++ b/packages/fast-navigation-generator-react/src/navigation/navigation.props.ts @@ -6,7 +6,7 @@ export interface NavigationState { /** * The navigation data */ - navigation: TreeNavigation[]; + navigation: TreeNavigation; /** * The open items tracked by data location diff --git a/packages/fast-navigation-generator-react/src/navigation/navigation.spec.tsx b/packages/fast-navigation-generator-react/src/navigation/navigation.spec.tsx index 019946d742a..e56ea94bbbd 100644 --- a/packages/fast-navigation-generator-react/src/navigation/navigation.spec.tsx +++ b/packages/fast-navigation-generator-react/src/navigation/navigation.spec.tsx @@ -100,9 +100,9 @@ describe("Navigation", () => { const rendered: any = shallow(); const item: any = rendered.find(treeItemEndPointSelector); expect(item).toHaveLength(1); - expect(rendered.find(treeItemExpandListTriggerSelector)).toHaveLength(0); + expect(rendered.find(treeItemExpandListTriggerSelector)).toHaveLength(1); expect(item.props().className).toEqual(managedClasses.navigation_itemLink); - expect(item.props()["aria-level"]).toEqual(1); + expect(item.props()["aria-level"]).toEqual(2); expect(item.props()["aria-setsize"]).toEqual(1); expect(item.props()["aria-posinset"]).toEqual(1); }); @@ -127,13 +127,13 @@ describe("Navigation", () => { const rendered: any = shallow(); const item: any = rendered.find(treeItemEndPointSelector); expect(item).toHaveLength(2); - expect(rendered.find(treeItemExpandListTriggerSelector)).toHaveLength(0); + expect(rendered.find(treeItemExpandListTriggerSelector)).toHaveLength(1); expect(item.at(0).props().className).toEqual(managedClasses.navigation_itemLink); - expect(item.at(0).props()["aria-level"]).toEqual(1); + expect(item.at(0).props()["aria-level"]).toEqual(2); expect(item.at(0).props()["aria-setsize"]).toEqual(2); expect(item.at(0).props()["aria-posinset"]).toEqual(1); expect(item.at(1).props().className).toEqual(managedClasses.navigation_itemLink); - expect(item.at(1).props()["aria-level"]).toEqual(1); + expect(item.at(1).props()["aria-level"]).toEqual(2); expect(item.at(1).props()["aria-setsize"]).toEqual(2); expect(item.at(1).props()["aria-posinset"]).toEqual(2); }); @@ -156,18 +156,18 @@ describe("Navigation", () => { const rendered: any = shallow(); const linkItem: any = rendered.find(treeItemEndPointSelector); - const triggerItem: any = rendered.find(treeItemExpandListTriggerSelector); + const triggerItem: any = rendered.find(treeItemExpandListTriggerSelector).at(1); expect(triggerItem).toHaveLength(1); expect(triggerItem.props().className).toEqual( managedClasses.navigation_itemExpandListTrigger ); - expect(triggerItem.parent().props()["aria-level"]).toEqual(1); + expect(triggerItem.parent().props()["aria-level"]).toEqual(2); expect(triggerItem.parent().props()["aria-setsize"]).toEqual(1); expect(triggerItem.parent().props()["aria-posinset"]).toEqual(1); expect(linkItem).toHaveLength(1); expect(linkItem.props().className).toEqual(managedClasses.navigation_itemLink); - expect(linkItem.props()["aria-level"]).toEqual(2); + expect(linkItem.props()["aria-level"]).toEqual(3); expect(linkItem.props()["aria-setsize"]).toEqual(1); expect(linkItem.props()["aria-posinset"]).toEqual(1); }); @@ -196,26 +196,26 @@ describe("Navigation", () => { const rendered: any = shallow(); const linkItem: any = rendered.find(treeItemEndPointSelector); - const triggerItem: any = rendered.find(treeItemExpandListTriggerSelector); + const triggerItem: any = rendered.find(treeItemExpandListTriggerSelector).at(1); expect(triggerItem).toHaveLength(1); expect(triggerItem.props().className).toEqual( managedClasses.navigation_itemExpandListTrigger ); - expect(triggerItem.parent().props()["aria-level"]).toEqual(1); + expect(triggerItem.parent().props()["aria-level"]).toEqual(2); expect(triggerItem.parent().props()["aria-setsize"]).toEqual(1); expect(triggerItem.parent().props()["aria-posinset"]).toEqual(1); expect(linkItem).toHaveLength(2); expect(linkItem.at(0).props().className).toEqual( managedClasses.navigation_itemLink ); - expect(linkItem.at(0).props()["aria-level"]).toEqual(2); + expect(linkItem.at(0).props()["aria-level"]).toEqual(3); expect(linkItem.at(0).props()["aria-setsize"]).toEqual(2); expect(linkItem.at(0).props()["aria-posinset"]).toEqual(1); expect(linkItem.at(1).props().className).toEqual( managedClasses.navigation_itemLink ); - expect(linkItem.at(1).props()["aria-level"]).toEqual(2); + expect(linkItem.at(1).props()["aria-level"]).toEqual(3); expect(linkItem.at(1).props()["aria-setsize"]).toEqual(2); expect(linkItem.at(1).props()["aria-posinset"]).toEqual(2); }); @@ -257,51 +257,51 @@ describe("Navigation", () => { const linkItem: any = rendered.find(treeItemEndPointSelector); const triggerItem: any = rendered.find(treeItemExpandListTriggerSelector); - expect(triggerItem).toHaveLength(2); + expect(triggerItem).toHaveLength(3); expect( triggerItem - .at(0) + .at(1) .parent() .props()["aria-level"] - ).toEqual(1); + ).toEqual(2); expect( triggerItem - .at(0) + .at(1) .parent() .props()["aria-setsize"] ).toEqual(2); expect( triggerItem - .at(0) + .at(1) .parent() .props()["aria-posinset"] ).toEqual(1); expect( triggerItem - .at(1) + .at(2) .parent() .props()["aria-level"] - ).toEqual(1); + ).toEqual(2); expect( triggerItem - .at(1) + .at(2) .parent() .props()["aria-setsize"] ).toEqual(2); expect( triggerItem - .at(1) + .at(2) .parent() .props()["aria-posinset"] ).toEqual(2); expect(linkItem).toHaveLength(3); - expect(linkItem.at(0).props()["aria-level"]).toEqual(2); + expect(linkItem.at(0).props()["aria-level"]).toEqual(3); expect(linkItem.at(0).props()["aria-setsize"]).toEqual(2); expect(linkItem.at(0).props()["aria-posinset"]).toEqual(1); - expect(linkItem.at(1).props()["aria-level"]).toEqual(2); + expect(linkItem.at(1).props()["aria-level"]).toEqual(3); expect(linkItem.at(1).props()["aria-setsize"]).toEqual(2); expect(linkItem.at(1).props()["aria-posinset"]).toEqual(2); - expect(linkItem.at(2).props()["aria-level"]).toEqual(2); + expect(linkItem.at(2).props()["aria-level"]).toEqual(3); expect(linkItem.at(2).props()["aria-setsize"]).toEqual(1); expect(linkItem.at(2).props()["aria-posinset"]).toEqual(1); }); diff --git a/packages/fast-navigation-generator-react/src/navigation/navigation.tsx b/packages/fast-navigation-generator-react/src/navigation/navigation.tsx index 231c7bd0ecf..2e3ca8ad032 100644 --- a/packages/fast-navigation-generator-react/src/navigation/navigation.tsx +++ b/packages/fast-navigation-generator-react/src/navigation/navigation.tsx @@ -56,7 +56,7 @@ export default class Navigation extends Foundation< role={"tree"} className={this.props.managedClasses.navigation} > - {this.renderTreeItems(this.state.navigation, 1)} + {this.renderTreeItem(this.state.navigation, 1, 1, 1, 0)} ); } @@ -75,6 +75,64 @@ export default class Navigation extends Foundation< ); } + private renderTreeItem( + navigation: TreeNavigation, + level: number, + navigationLength: number, + positionInNavigation: number, + index: number + ): React.ReactNode { + if (Array.isArray(navigation.items)) { + return ( +
+ + {navigation.text} + + {this.renderTreeItemContainer(navigation.items, level)} +
+ ); + } + + return ( +
+ + {navigation.text} + +
+ ); + } + /** * Renders tree items */ @@ -86,60 +144,12 @@ export default class Navigation extends Foundation< const navigationLength: number = navigation.length; const positionInNavigation: number = index + 1; - if (Array.isArray(navigationItem.items)) { - return ( -
- - {navigationItem.text} - - {this.renderTreeItemContainer(navigationItem.items, level)} -
- ); - } - - return ( -
- - {navigationItem.text} - -
+ return this.renderTreeItem( + navigationItem, + level, + navigationLength, + positionInNavigation, + index ); }); } @@ -376,7 +386,7 @@ export default class Navigation extends Foundation< this.state.openItems.find( (openItem: string) => openItem.slice(0, dataLocation.length) === dataLocation - ) + ) !== undefined ) { return true; } diff --git a/packages/fast-navigation-generator-react/src/navigation/navigation.utilities.spec.ts b/packages/fast-navigation-generator-react/src/navigation/navigation.utilities.spec.ts index 3738354c24b..93f05c60bc9 100644 --- a/packages/fast-navigation-generator-react/src/navigation/navigation.utilities.spec.ts +++ b/packages/fast-navigation-generator-react/src/navigation/navigation.utilities.spec.ts @@ -21,8 +21,29 @@ const childOptions: ChildOptionItem[] = [ * Gets the navigation */ describe("getNavigationFromData", () => { - test("should return an empty array if no data is passed", () => { - expect(getNavigationFromData({}, {}, [])).toEqual([]); + test("should return a single item if no data is passed", () => { + expect(getNavigationFromData({}, {}, [])).toEqual({ + dataLocation: "", + items: [], + text: "Undefined", + type: "children", + }); + }); + test("should return a single item if a single string child has been passed", () => { + const childrenText: string = "Foo"; + const data: any = { + children: childrenText, + }; + const navigationFromData: TreeNavigation[] = getNavigationFromData( + data, + childrenSchema, + childOptions + ).items; + expect(navigationFromData).toHaveLength(1); + expect(navigationFromData[0].items).toEqual(undefined); + expect(navigationFromData[0].dataLocation).toEqual("children"); + expect(navigationFromData[0].text).toEqual(childrenText); + expect(navigationFromData[0].type).toEqual(ItemType.children); }); test("should return a single item if a single child has been passed", () => { const data: any = { @@ -36,7 +57,7 @@ describe("getNavigationFromData", () => { data, childrenSchema, childOptions - ); + ).items; expect(navigationFromData).toHaveLength(1); expect(navigationFromData[0].items).toEqual(undefined); expect(navigationFromData[0].dataLocation).toEqual("children"); @@ -44,6 +65,7 @@ describe("getNavigationFromData", () => { expect(navigationFromData[0].type).toEqual(ItemType.children); }); test("should return multiple items if multiple children have been passed", () => { + const childrenText: string = "Bar"; const data: any = { children: [ { @@ -54,6 +76,7 @@ describe("getNavigationFromData", () => { id: childOptions[0].schema.id, props: {}, }, + childrenText, ], }; @@ -61,9 +84,9 @@ describe("getNavigationFromData", () => { data, childrenSchema, childOptions - ); + ).items; - expect(navigationFromData).toHaveLength(2); + expect(navigationFromData).toHaveLength(3); expect(navigationFromData[0].items).toEqual(undefined); expect(navigationFromData[0].dataLocation).toEqual("children[0]"); expect(navigationFromData[0].text).toEqual(childOptions[0].schema.title); @@ -72,6 +95,10 @@ describe("getNavigationFromData", () => { expect(navigationFromData[1].dataLocation).toEqual("children[1]"); expect(navigationFromData[1].text).toEqual(childOptions[0].schema.title); expect(navigationFromData[1].type).toEqual(ItemType.children); + expect(navigationFromData[2].items).toEqual(undefined); + expect(navigationFromData[2].dataLocation).toEqual("children[2]"); + expect(navigationFromData[2].text).toEqual(childrenText); + expect(navigationFromData[2].type).toEqual(ItemType.children); }); test("should return a nested item if nested children have been passed", () => { const data: any = { @@ -90,7 +117,7 @@ describe("getNavigationFromData", () => { data, childrenSchema, childOptions - ); + ).items; expect(navigationFromData).toHaveLength(1); expect(navigationFromData[0].dataLocation).toEqual("children"); expect(navigationFromData[0].text).toEqual(childOptions[1].schema.title); @@ -127,7 +154,7 @@ describe("getNavigationFromData", () => { data, childrenSchema, childOptions - ); + ).items; expect(navigationFromData).toHaveLength(1); expect(navigationFromData[0].dataLocation).toEqual("children"); expect(navigationFromData[0].text).toEqual(childOptions[1].schema.title); @@ -181,7 +208,7 @@ describe("getNavigationFromData", () => { data, childrenSchema, childOptions - ); + ).items; expect(navigationFromData).toHaveLength(2); expect(navigationFromData[0].dataLocation).toEqual("children[0]"); expect(navigationFromData[0].text).toEqual(childOptions[1].schema.title); diff --git a/packages/fast-navigation-generator-react/src/navigation/navigation.utilities.ts b/packages/fast-navigation-generator-react/src/navigation/navigation.utilities.ts index 232ff075c22..c80dbcbbc75 100644 --- a/packages/fast-navigation-generator-react/src/navigation/navigation.utilities.ts +++ b/packages/fast-navigation-generator-react/src/navigation/navigation.utilities.ts @@ -88,7 +88,9 @@ function getNavigationFromChildLocations( updatedNavigation.push({ text: get(subSchema, "schema.title") ? subSchema.schema.title - : "Undefined", + : typeof get(data, childrenDataLocation) === "string" + ? get(data, childrenDataLocation) + : "Undefined", dataLocation: childrenDataLocation, type: ItemType.children, }); @@ -104,7 +106,7 @@ export function getNavigationFromData( data: any, schema: any, childOptions: ChildOptionItem[] -): TreeNavigation[] { +): TreeNavigation { const childrenDataLocations: string[] = getDataLocationsOfChildren( schema, data, @@ -118,5 +120,10 @@ export function getNavigationFromData( childOptions ); - return navigation; + return { + text: schema.title ? schema.title : "Undefined", + dataLocation: "", + items: navigation, + type: ItemType.children, + }; }