From 8ae5d5c049dc59af40694c218d5055de01a25f63 Mon Sep 17 00:00:00 2001 From: silviuavram Date: Thu, 24 Oct 2019 15:21:43 +0200 Subject: [PATCH 01/14] add expanded ids in activeItemIds --- packages/react/src/components/Tree/Tree.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/react/src/components/Tree/Tree.tsx b/packages/react/src/components/Tree/Tree.tsx index 334e4d5b44..0d2ee5ab67 100644 --- a/packages/react/src/components/Tree/Tree.tsx +++ b/packages/react/src/components/Tree/Tree.tsx @@ -146,9 +146,21 @@ class Tree extends AutoControlledComponent, TreeState> { } static getAutoControlledStateFromProps(nextProps: TreeProps, prevState: TreeState) { - const itemsForRender = Tree.getItemsForRender(nextProps.items) + const { items } = nextProps + const itemsForRender = Tree.getItemsForRender(items) + let { activeItemIds } = nextProps + + if (!activeItemIds && items) { + activeItemIds = [] + items.forEach(item => { + if (item['expanded'] && activeItemIds.indexOf(item['id']) === -1) { + activeItemIds.push(item['id']) + } + }) + } return { + activeItemIds, itemsForRender, } } From 90e08e096f18c939c7594f578a980ef11cc9d7fb Mon Sep 17 00:00:00 2001 From: silviuavram Date: Thu, 24 Oct 2019 16:04:38 +0200 Subject: [PATCH 02/14] replace open with expanded --- .../src/behaviors/Tree/treeItemBehavior.ts | 20 +++++++++---------- .../test/behaviors/treeItemBehavior-test.tsx | 4 ++-- packages/react/src/components/Tree/Tree.tsx | 12 +++++------ .../react/src/components/Tree/TreeItem.tsx | 10 +++++----- .../react/src/components/Tree/TreeTitle.tsx | 4 ++-- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts b/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts index e96eb93f60..c5055763b2 100644 --- a/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts +++ b/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts @@ -7,7 +7,7 @@ import treeTitleBehavior from './treeTitleBehavior' /** * @description * Adds role 'treeitem' to a non-leaf item and 'none' to a leaf item. - * Adds 'aria-expanded' with a value based on the 'open' prop if item is not a leaf. + * Adds 'aria-expanded' with a value based on the 'expanded' prop if item is not a leaf. * Adds 'tabIndex' as '-1' if the item is not a leaf. * * @specification @@ -22,7 +22,7 @@ const treeItemBehavior: Accessibility = props => ({ root: { role: 'none', ...(props.hasSubtree && { - 'aria-expanded': props.open, + 'aria-expanded': props.expanded, tabIndex: -1, [IS_FOCUSABLE_ATTRIBUTE]: true, role: 'treeitem', @@ -37,7 +37,7 @@ const treeItemBehavior: Accessibility = props => ({ performClick: { keyCombinations: [{ keyCode: keyboardKey.Enter }, { keyCode: keyboardKey.Spacebar }], }, - ...(isSubtreeOpen(props) && { + ...(isSubtreeExpanded(props) && { collapse: { keyCombinations: [{ keyCode: keyboardKey.ArrowLeft }], }, @@ -45,7 +45,7 @@ const treeItemBehavior: Accessibility = props => ({ keyCombinations: [{ keyCode: keyboardKey.ArrowRight }], }, }), - ...(!isSubtreeOpen(props) && { + ...(!isSubtreeExpanded(props) && { expand: { keyCombinations: [{ keyCode: keyboardKey.ArrowRight }], }, @@ -64,18 +64,18 @@ const treeItemBehavior: Accessibility = props => ({ }) export type TreeItemBehaviorProps = { - /** If item is a subtree, it indicates if it's open. */ - open?: boolean + /** If item is a subtree, it indicates if it's expanded. */ + expanded?: boolean level?: number index?: number hasSubtree?: boolean treeSize?: number } -/** Checks if current tree item has a subtree and it is opened */ -const isSubtreeOpen = (props: TreeItemBehaviorProps): boolean => { - const { hasSubtree, open } = props - return !!(hasSubtree && open) +/** Checks if current tree item has a subtree and it is expanded */ +const isSubtreeExpanded = (props: TreeItemBehaviorProps): boolean => { + const { hasSubtree, expanded } = props + return !!(hasSubtree && expanded) } export default treeItemBehavior diff --git a/packages/accessibility/test/behaviors/treeItemBehavior-test.tsx b/packages/accessibility/test/behaviors/treeItemBehavior-test.tsx index de7a9a42d8..c95e6a5fcd 100644 --- a/packages/accessibility/test/behaviors/treeItemBehavior-test.tsx +++ b/packages/accessibility/test/behaviors/treeItemBehavior-test.tsx @@ -20,12 +20,12 @@ describe('TreeItemBehavior', () => { }) test(`is added with 'false' value to an item that is expandable but not open`, () => { - const expectedResult = treeItemBehavior({ hasSubtree: true, open: false }) + const expectedResult = treeItemBehavior({ hasSubtree: true, expanded: false }) expect(expectedResult.attributes.root['aria-expanded']).toEqual(false) }) test(`is added with 'false' value to an item that is expandable and open`, () => { - const expectedResult = treeItemBehavior({ hasSubtree: true, open: true }) + const expectedResult = treeItemBehavior({ hasSubtree: true, expanded: true }) expect(expectedResult.attributes.root['aria-expanded']).toEqual(true) }) }) diff --git a/packages/react/src/components/Tree/Tree.tsx b/packages/react/src/components/Tree/Tree.tsx index 0d2ee5ab67..a7afc6e01f 100644 --- a/packages/react/src/components/Tree/Tree.tsx +++ b/packages/react/src/components/Tree/Tree.tsx @@ -37,13 +37,13 @@ export interface TreeProps extends UIComponentProps, ChildrenComponentProps { /** Accessibility behavior if overridden by the user. */ accessibility?: Accessibility - /** Ids of opened items. */ + /** Ids of expanded items. */ activeItemIds?: string[] /** Initial activeItemIds value. */ defaultActiveItemIds?: string[] - /** Only allow one subtree to be open at a time. */ + /** Only allow one subtree to be expanded at a time. */ exclusive?: boolean /** Shorthand array of props for Tree. */ @@ -151,7 +151,7 @@ class Tree extends AutoControlledComponent, TreeState> { let { activeItemIds } = nextProps if (!activeItemIds && items) { - activeItemIds = [] + activeItemIds = prevState.activeItemIds items.forEach(item => { if (item['expanded'] && activeItemIds.indexOf(item['id']) === -1) { activeItemIds.push(item['id']) @@ -285,14 +285,14 @@ class Tree extends AutoControlledComponent, TreeState> { const itemForRender = itemsForRender[item['id']] const { elementRef, ...restItemForRender } = itemForRender const isSubtree = hasSubtree(item) - const isSubtreeOpen = isSubtree && this.isActiveItem(item['id']) + const isSubtreeExpanded = isSubtree && this.isActiveItem(item['id']) const renderedItem = TreeItem.create(item, { defaultProps: { accessibility: accessibility.childBehaviors ? accessibility.childBehaviors.item : undefined, className: Tree.slotClassNames.item, - open: isSubtreeOpen, + expanded: isSubtreeExpanded, renderItemTitle, key: item['id'], contentRef: elementRef, @@ -304,7 +304,7 @@ class Tree extends AutoControlledComponent, TreeState> { return [ ...renderedItems, renderedItem, - ...(isSubtreeOpen ? renderItems(item['items']) : ([] as any)), + ...(isSubtreeExpanded ? renderItems(item['items']) : ([] as any)), ] }, [], diff --git a/packages/react/src/components/Tree/TreeItem.tsx b/packages/react/src/components/Tree/TreeItem.tsx index 8f0d34348d..42ecb26c97 100644 --- a/packages/react/src/components/Tree/TreeItem.tsx +++ b/packages/react/src/components/Tree/TreeItem.tsx @@ -64,8 +64,8 @@ export interface TreeItemProps extends UIComponentProps, ChildrenComponentProps /** Called when the item's parent is about to be focused. */ onFocusParent?: ComponentEventHandler - /** Whether or not the item is in the open state. Only makes sense if item has children items. */ - open?: boolean + /** Whether or not the item is in the expanded state. Only makes sense if item has children items. */ + expanded?: boolean /** The id of the parent tree item, if any. */ parent?: ShorthandValue @@ -117,7 +117,7 @@ class TreeItem extends UIComponent, TreeItemState> { onFocusFirstChild: PropTypes.func, onFocusParent: PropTypes.func, onSiblingsExpand: PropTypes.func, - open: PropTypes.bool, + expanded: PropTypes.bool, parent: customPropTypes.itemShorthand, renderItemTitle: PropTypes.func, siblings: customPropTypes.collectionShorthand, @@ -192,13 +192,13 @@ class TreeItem extends UIComponent, TreeItemState> { }) renderContent(accessibility: ReactAccessibilityBehavior) { - const { title, renderItemTitle, open, level, index } = this.props + const { title, renderItemTitle, expanded, level, index } = this.props const { hasSubtree, treeSize } = this.state return TreeTitle.create(title, { defaultProps: { className: TreeItem.slotClassNames.title, - open, + expanded, hasSubtree, as: hasSubtree ? 'span' : 'a', level, diff --git a/packages/react/src/components/Tree/TreeTitle.tsx b/packages/react/src/components/Tree/TreeTitle.tsx index a914d615b2..005ac67697 100644 --- a/packages/react/src/components/Tree/TreeTitle.tsx +++ b/packages/react/src/components/Tree/TreeTitle.tsx @@ -42,7 +42,7 @@ export interface TreeTitleProps onClick?: ComponentEventHandler /** Whether or not the subtree of the title is in the open state. */ - open?: boolean + expanded?: boolean /** Size of the tree containing this title without any children. */ treeSize?: number @@ -61,7 +61,7 @@ class TreeTitle extends UIComponent> { index: PropTypes.number, level: PropTypes.number, onClick: PropTypes.func, - open: PropTypes.bool, + expanded: PropTypes.bool, treeSize: PropTypes.number, } From 369a18a4340ed892b0a848a3d95a44436119f4be Mon Sep 17 00:00:00 2001 From: silviuavram Date: Thu, 24 Oct 2019 16:52:54 +0200 Subject: [PATCH 03/14] made test to work for expanded --- .../accessibility/test/behaviors/testDefinitions.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/accessibility/test/behaviors/testDefinitions.ts b/packages/accessibility/test/behaviors/testDefinitions.ts index d70f9cca96..47ae6edd7b 100644 --- a/packages/accessibility/test/behaviors/testDefinitions.ts +++ b/packages/accessibility/test/behaviors/testDefinitions.ts @@ -597,7 +597,13 @@ definitions.push({ regexp: /Triggers '(\w+)' action with '(\w+)' on '([\w-]+)', when has an opened subtree\./g, testMethod: (parameters: TestMethod) => { const [action, key, elementToPerformAction] = [...parameters.props] - const propertyOpenedSubtree = { open: true, items: [{ a: 1 }], siblings: [], hasSubtree: true } + const propertyOpenedSubtree = { + open: true, + expanded: true, + items: [{ a: 1 }], + siblings: [], + hasSubtree: true, + } const expectedKeyNumberVertical = parameters.behavior(propertyOpenedSubtree).keyActions[ elementToPerformAction ][action].keyCombinations[0].keyCode @@ -610,7 +616,7 @@ definitions.push({ regexp: /Triggers '(\w+)' action with '(\w+)' on '([\w-]+)', when has a closed subtree\./g, testMethod: (parameters: TestMethod) => { const [action, key, elementToPerformAction] = [...parameters.props] - const propertyClosedSubtree = { open: false, hasSubtree: false } + const propertyClosedSubtree = { open: false, expanded: false, hasSubtree: false } const expectedKeyNumberVertical = parameters.behavior(propertyClosedSubtree).keyActions[ elementToPerformAction ][action].keyCombinations[0].keyCode From 27d6bef6c31ae46f49978a4379f222c8ee839af4 Mon Sep 17 00:00:00 2001 From: silviuavram Date: Fri, 25 Oct 2019 12:54:27 +0200 Subject: [PATCH 04/14] fixed issue and added tests --- packages/react/src/components/Tree/Tree.tsx | 24 +++++++++++++++---- .../test/specs/components/Tree/Tree-test.tsx | 18 ++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/packages/react/src/components/Tree/Tree.tsx b/packages/react/src/components/Tree/Tree.tsx index a7afc6e01f..8332dab054 100644 --- a/packages/react/src/components/Tree/Tree.tsx +++ b/packages/react/src/components/Tree/Tree.tsx @@ -152,11 +152,25 @@ class Tree extends AutoControlledComponent, TreeState> { if (!activeItemIds && items) { activeItemIds = prevState.activeItemIds - items.forEach(item => { - if (item['expanded'] && activeItemIds.indexOf(item['id']) === -1) { - activeItemIds.push(item['id']) - } - }) + + const expandedItemsGenerator = items => + _.reduce( + items, + (acc, item) => { + if (item['expanded'] && acc.indexOf(item['id']) === -1) { + acc.push(item['id']) + } + + if (item['items']) { + return [...acc, expandedItemsGenerator(item['items'])] + } + + return acc + }, + activeItemIds, + ) + + expandedItemsGenerator(items) } return { diff --git a/packages/react/test/specs/components/Tree/Tree-test.tsx b/packages/react/test/specs/components/Tree/Tree-test.tsx index 7818b7d5d3..696f4bb86b 100644 --- a/packages/react/test/specs/components/Tree/Tree-test.tsx +++ b/packages/react/test/specs/components/Tree/Tree-test.tsx @@ -156,5 +156,23 @@ describe('Tree', () => { .simulate('keydown', { keyCode: keyboardKey['*'] }) checkOpenTitles(wrapper, ['1', '11', '12', '2', '21', '22', '3']) }) + + it('should have items expanded based on their expanded prop', () => { + const itemsClone = JSON.parse(JSON.stringify(items)) + itemsClone[0]['expanded'] = true + itemsClone[0]['items'][1]['expanded'] = true + const wrapper = mountWithProvider() + + checkOpenTitles(wrapper, ['1', '11', '12', '121', '2', '3']) + }) + + it('should have expanded prop from items overriden by controlling activeItemIds', () => { + const itemsClone = JSON.parse(JSON.stringify(items)) + itemsClone[0]['expanded'] = true + itemsClone[0]['items'][1]['expanded'] = true + const wrapper = mountWithProvider() + + checkOpenTitles(wrapper, ['1', '2', '21', '211', '22', '3']) + }) }) }) From f0b7d8ceb17b417d9bb9fa615847641ad52d36f1 Mon Sep 17 00:00:00 2001 From: silviuavram Date: Fri, 25 Oct 2019 14:10:37 +0200 Subject: [PATCH 05/14] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba5a7996d1..bdb29f2be7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Features - Add `menu` prop on `ToolbarMenuItem` component @mnajdova ([#1984](https://github.com/stardust-ui/react/pull/1984)) +- Control Tree `activeItemIds` through `expanded` TreeItem prop @silviuavram ([#2061]https://github.com/microsoft/fluent-ui-react/pull/2061) ### Documentation - Editor Toolbar prototype: Fix overflow menu overflowing in Portal window @miroslavstastny ([#2053](https://github.com/stardust-ui/react/pull/2053)) From 78f1087021d2508c5267bde9a0753020b09a39ff Mon Sep 17 00:00:00 2001 From: silviuavram Date: Fri, 25 Oct 2019 15:44:18 +0200 Subject: [PATCH 06/14] fix changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4a9dcc3ce..2b25fd847b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Features - Add `menu` prop on `ToolbarMenuItem` component @mnajdova ([#1984](https://github.com/stardust-ui/react/pull/1984)) -- Control Tree `activeItemIds` through `expanded` TreeItem prop @silviuavram ([#2061]https://github.com/microsoft/fluent-ui-react/pull/2061) +- Control Tree `activeItemIds` through `expanded` TreeItem prop @silviuavram ([#2061](https://github.com/stardust-ui/react/pull/2061) ### Documentation - Editor Toolbar prototype: Fix overflow menu overflowing in Portal window @miroslavstastny ([#2053](https://github.com/stardust-ui/react/pull/2053)) From 1cf0ba8f17c89d8b9369dada528fa692428d4691 Mon Sep 17 00:00:00 2001 From: silviuavram Date: Fri, 25 Oct 2019 16:14:02 +0200 Subject: [PATCH 07/14] fix changelog again --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b25fd847b..09ea04cd8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Features - Add `menu` prop on `ToolbarMenuItem` component @mnajdova ([#1984](https://github.com/stardust-ui/react/pull/1984)) -- Control Tree `activeItemIds` through `expanded` TreeItem prop @silviuavram ([#2061](https://github.com/stardust-ui/react/pull/2061) +- Control Tree `activeItemIds` through `expanded` TreeItem prop @silviuavram ([#2061](https://github.com/stardust-ui/react/pull/2061)) ### Documentation - Editor Toolbar prototype: Fix overflow menu overflowing in Portal window @miroslavstastny ([#2053](https://github.com/stardust-ui/react/pull/2053)) From 4d8a16c199a02bed69b2c92a9fe33d410ea75278 Mon Sep 17 00:00:00 2001 From: Silviu Avram Date: Mon, 11 Nov 2019 14:45:17 +0100 Subject: [PATCH 08/14] add test to behavior --- packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts b/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts index c5055763b2..43d1943f80 100644 --- a/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts +++ b/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts @@ -12,6 +12,7 @@ import treeTitleBehavior from './treeTitleBehavior' * * @specification * Triggers 'performClick' action with 'Enter' or 'Spacebar' on 'root'. + * Triggers 'expandSiblings' action with '*' on 'root'. * Triggers 'focusParent' action with 'ArrowLeft' on 'root', when has a closed subtree. * Triggers 'collapse' action with 'ArrowLeft' on 'root', when has an opened subtree. * Triggers 'expand' action with 'ArrowRight' on 'root', when has a closed subtree. From c2aa1e145cd0ad956d18261e8734394d784b0a7d Mon Sep 17 00:00:00 2001 From: Silviu Avram Date: Mon, 11 Nov 2019 15:30:46 +0100 Subject: [PATCH 09/14] fix expanded issue --- packages/react/src/components/Tree/Tree.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react/src/components/Tree/Tree.tsx b/packages/react/src/components/Tree/Tree.tsx index aa6f591101..bcb4a7cb42 100644 --- a/packages/react/src/components/Tree/Tree.tsx +++ b/packages/react/src/components/Tree/Tree.tsx @@ -153,7 +153,7 @@ class Tree extends AutoControlledComponent, TreeState> { if (!activeItemIds && items) { activeItemIds = prevState.activeItemIds - const expandedItemsGenerator = items => + const expandedItemsGenerator = (items, acc = activeItemIds) => _.reduce( items, (acc, item) => { @@ -162,12 +162,12 @@ class Tree extends AutoControlledComponent, TreeState> { } if (item['items']) { - return [...acc, expandedItemsGenerator(item['items'])] + return expandedItemsGenerator(item['items'], acc) } return acc }, - activeItemIds, + acc, ) expandedItemsGenerator(items) From 13608d590205e0d33cd38bef3fa7aef3d914714f Mon Sep 17 00:00:00 2001 From: Silviu Avram Date: Mon, 11 Nov 2019 15:39:52 +0100 Subject: [PATCH 10/14] add test to tree --- .../react/test/specs/components/Tree/Tree-test.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/react/test/specs/components/Tree/Tree-test.tsx b/packages/react/test/specs/components/Tree/Tree-test.tsx index 696f4bb86b..0d4f66bd4b 100644 --- a/packages/react/test/specs/components/Tree/Tree-test.tsx +++ b/packages/react/test/specs/components/Tree/Tree-test.tsx @@ -166,6 +166,16 @@ describe('Tree', () => { checkOpenTitles(wrapper, ['1', '11', '12', '121', '2', '3']) }) + it('should have multiple items on the same level expanded based on their expanded prop', () => { + const itemsClone = JSON.parse(JSON.stringify(items)) + itemsClone[0]['expanded'] = true + itemsClone[0]['items'][1]['expanded'] = true + itemsClone[1]['expanded'] = true + const wrapper = mountWithProvider() + + checkOpenTitles(wrapper, ['1', '11', '12', '121', '2', '21', '22', '3']) + }) + it('should have expanded prop from items overriden by controlling activeItemIds', () => { const itemsClone = JSON.parse(JSON.stringify(items)) itemsClone[0]['expanded'] = true From 6c3cf66b362750751f2a6b94b5d4d5c1da9e7d80 Mon Sep 17 00:00:00 2001 From: Silviu Avram Date: Mon, 11 Nov 2019 16:43:26 +0100 Subject: [PATCH 11/14] add more tests to TreeItem --- .../accessibility/src/behaviors/Tree/treeItemBehavior.ts | 5 +++++ packages/accessibility/test/behaviors/testDefinitions.ts | 2 +- packages/react/src/components/Tree/Tree.tsx | 2 ++ packages/react/src/components/Tree/TreeItem.tsx | 2 +- packages/react/test/specs/components/Tree/TreeItem-test.tsx | 6 ++++++ 5 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 packages/react/test/specs/components/Tree/TreeItem-test.tsx diff --git a/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts b/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts index 43d1943f80..af23767653 100644 --- a/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts +++ b/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts @@ -11,6 +11,11 @@ import treeTitleBehavior from './treeTitleBehavior' * Adds 'tabIndex' as '-1' if the item is not a leaf. * * @specification + * Adds attribute 'aria-expanded=true' based on the property 'expanded' if the component has 'hasSubtree' property. + * Adds attribute 'tabIndex=-1' to 'root' slot if 'hasSubtree' property is true. Does not set the attribute otherwise. + * Adds attribute 'aria-setsize=3' based on the property 'treeSize' if the component has 'hasSubtree' property. + * Adds attribute 'aria-posinset=2' based on the property 'index' if the component has 'hasSubtree' property. + * Adds attribute 'aria-level=1' based on the property 'level' if the component has 'hasSubtree' property. * Triggers 'performClick' action with 'Enter' or 'Spacebar' on 'root'. * Triggers 'expandSiblings' action with '*' on 'root'. * Triggers 'focusParent' action with 'ArrowLeft' on 'root', when has a closed subtree. diff --git a/packages/accessibility/test/behaviors/testDefinitions.ts b/packages/accessibility/test/behaviors/testDefinitions.ts index 47ae6edd7b..97ea62d617 100644 --- a/packages/accessibility/test/behaviors/testDefinitions.ts +++ b/packages/accessibility/test/behaviors/testDefinitions.ts @@ -189,7 +189,7 @@ function testMethodConditionallyAddAttribute( // Example: Adds attribute 'aria-disabled=true' to 'trigger' slot if 'disabled' property is true. Does not set the attribute otherwise. definitions.push({ - regexp: /Adds attribute '([\w-]+)=([\w\d]+)' to '([\w-]+)' slot if '([\w-]+)' property is true\. Does not set the attribute otherwise\./g, + regexp: /Adds attribute '([\w-]+)=([\w\d-]+)' to '([\w-]+)' slot if '([\w-]+)' property is true\. Does not set the attribute otherwise\./g, testMethod: (parameters: TestMethod) => { const [ attributeToBeAdded, diff --git a/packages/react/src/components/Tree/Tree.tsx b/packages/react/src/components/Tree/Tree.tsx index 5f41866815..63afacfaef 100644 --- a/packages/react/src/components/Tree/Tree.tsx +++ b/packages/react/src/components/Tree/Tree.tsx @@ -112,6 +112,8 @@ class Tree extends AutoControlledComponent, TreeState> { static autoControlledProps = ['activeItemIds'] + static Item = TreeItem + // memoize this function if performance issue occurs. static getItemsForRender = (itemsFromProps: ShorthandCollection) => { const itemsForRenderGenerator = ( diff --git a/packages/react/src/components/Tree/TreeItem.tsx b/packages/react/src/components/Tree/TreeItem.tsx index fabab6049c..a7f48e3b4b 100644 --- a/packages/react/src/components/Tree/TreeItem.tsx +++ b/packages/react/src/components/Tree/TreeItem.tsx @@ -137,7 +137,7 @@ class TreeItem extends UIComponent, TreeItemState> { static getDerivedStateFromProps(props: TreeItemProps) { return { hasSubtree: hasSubtree(props), - treeSize: props.siblings.length + 1, + treeSize: props.siblings ? props.siblings.length + 1 : 0, } } diff --git a/packages/react/test/specs/components/Tree/TreeItem-test.tsx b/packages/react/test/specs/components/Tree/TreeItem-test.tsx new file mode 100644 index 0000000000..50198c24d2 --- /dev/null +++ b/packages/react/test/specs/components/Tree/TreeItem-test.tsx @@ -0,0 +1,6 @@ +import { isConformant } from 'test/specs/commonTests' +import TreeItem from 'src/components/Tree/TreeItem' + +describe('TreeItem', () => { + isConformant(TreeItem, { requiredProps: { id: 'my-id' } }) +}) From f28dbce72b0c1443b5d8809dfb7bb573924c3ef2 Mon Sep 17 00:00:00 2001 From: Silviu Avram Date: Tue, 12 Nov 2019 10:45:41 +0100 Subject: [PATCH 12/14] more tests to behavior --- .../src/behaviors/Tree/treeItemBehavior.ts | 6 +- .../src/behaviors/Tree/treeTitleBehavior.ts | 9 +- .../test/behaviors/testDefinitions.ts | 91 ++++++++++++++++--- 3 files changed, 86 insertions(+), 20 deletions(-) diff --git a/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts b/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts index af23767653..a1c80d586b 100644 --- a/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts +++ b/packages/accessibility/src/behaviors/Tree/treeItemBehavior.ts @@ -5,17 +5,13 @@ import { IS_FOCUSABLE_ATTRIBUTE } from '../../attributes' import treeTitleBehavior from './treeTitleBehavior' /** - * @description - * Adds role 'treeitem' to a non-leaf item and 'none' to a leaf item. - * Adds 'aria-expanded' with a value based on the 'expanded' prop if item is not a leaf. - * Adds 'tabIndex' as '-1' if the item is not a leaf. - * * @specification * Adds attribute 'aria-expanded=true' based on the property 'expanded' if the component has 'hasSubtree' property. * Adds attribute 'tabIndex=-1' to 'root' slot if 'hasSubtree' property is true. Does not set the attribute otherwise. * Adds attribute 'aria-setsize=3' based on the property 'treeSize' if the component has 'hasSubtree' property. * Adds attribute 'aria-posinset=2' based on the property 'index' if the component has 'hasSubtree' property. * Adds attribute 'aria-level=1' based on the property 'level' if the component has 'hasSubtree' property. + * Adds attribute 'role=treeitem' to 'root' slot if 'hasSubtree' property is true. Sets the attribute to 'none' otherwise. * Triggers 'performClick' action with 'Enter' or 'Spacebar' on 'root'. * Triggers 'expandSiblings' action with '*' on 'root'. * Triggers 'focusParent' action with 'ArrowLeft' on 'root', when has a closed subtree. diff --git a/packages/accessibility/src/behaviors/Tree/treeTitleBehavior.ts b/packages/accessibility/src/behaviors/Tree/treeTitleBehavior.ts index 5abeb90e3f..cab37a9f24 100644 --- a/packages/accessibility/src/behaviors/Tree/treeTitleBehavior.ts +++ b/packages/accessibility/src/behaviors/Tree/treeTitleBehavior.ts @@ -4,11 +4,12 @@ import { IS_FOCUSABLE_ATTRIBUTE } from '../../attributes' import { Accessibility } from '../../types' /** - * @description - * Adds role 'treeitem' if the title is a leaf node inside the tree. - * Adds 'tabIndex' as '-1' if the title is a leaf node inside the tree. - * * @specification + * Adds attribute 'tabIndex=-1' to 'root' slot if 'hasSubtree' property is false or undefined. Does not set the attribute if true. + * Adds attribute 'role=treeitem' to 'root' slot if 'hasSubtree' property is false or undefined. Does not set the attribute if true. + * Adds attribute 'aria-setsize=3' based on the property 'treeSize' if the component has 'hasSubtree' property false or undefined. Does not set anything if true.. + * Adds attribute 'aria-posinset=2' based on the property 'index' if the component has 'hasSubtree' property false or undefined. Does not set anything if true.. + * Adds attribute 'aria-level=1' based on the property 'level' if the component has 'hasSubtree' property false or undefined. Does not set anything if true.. * Triggers 'performClick' action with 'Enter' or 'Spacebar' on 'root'. */ const treeTitleBehavior: Accessibility = props => ({ diff --git a/packages/accessibility/test/behaviors/testDefinitions.ts b/packages/accessibility/test/behaviors/testDefinitions.ts index 97ea62d617..9d6c427d91 100644 --- a/packages/accessibility/test/behaviors/testDefinitions.ts +++ b/packages/accessibility/test/behaviors/testDefinitions.ts @@ -167,11 +167,13 @@ function testMethodConditionallyAddAttribute( component, propertyDependsOn, valueOfProperty, + valueOfPropertyOtherwise, attributeToBeAdded, valueOfAttributeToBeAddedIfTrue, valueOfAttributeToBeAddedOtherwise, ) { const propertyWithAriaSelected = {} + propertyWithAriaSelected[propertyDependsOn] = valueOfPropertyOtherwise const expectedResultAttributeNotDefined = parameters.behavior(propertyWithAriaSelected) .attributes[component][attributeToBeAdded] expect(testHelper.convertToMatchingTypeIfApplicable(expectedResultAttributeNotDefined)).toEqual( @@ -203,6 +205,31 @@ definitions.push({ component, propertyDependsOn, true, + undefined, + attributeToBeAdded, + valueOfAttributeToBeAdded, + undefined, + ) + }, +}) + +// Example: Adds attribute 'aria-disabled=true' to 'trigger' slot if 'disabled' property is false or undefined. Does not set the attribute if true. +definitions.push({ + regexp: /Adds attribute '([\w-]+)=([\w\d-]+)' to '([\w-]+)' slot if '([\w-]+)' property is false or undefined\. Does not set the attribute if true\./g, + testMethod: (parameters: TestMethod) => { + const [ + attributeToBeAdded, + valueOfAttributeToBeAdded, + component, + propertyDependsOn, + ] = parameters.props + + testMethodConditionallyAddAttribute( + parameters, + component, + propertyDependsOn, + undefined, + true, attributeToBeAdded, valueOfAttributeToBeAdded, undefined, @@ -227,6 +254,7 @@ definitions.push({ component, propertyDependsOn, true, + undefined, attributeToBeAdded, valueOfAttributeToBeAddedIfTrue, valueOfAttributeToBeAddedOtherwise, @@ -234,7 +262,7 @@ definitions.push({ }, }) -// Adds attribute 'aria-haspopup=true' to 'root' slot if 'menu' menu property is set. +// Adds attribute 'aria-haspopup=true' to 'root' slot if 'menu' property is set. definitions.push({ regexp: /Adds attribute '([\w-]+)=([\w\d]+)' to '([\w-]+)' slot if '([\w-]+)' property is set\./g, testMethod: (parameters: TestMethod) => { @@ -251,6 +279,7 @@ definitions.push({ component, propertyDependsOn, 'custom-value', + undefined, attributeToBeAdded, valueOfAttributeToBeAddedIfTrue, valueOfAttributeToBeAddedOtherwise, @@ -317,6 +346,44 @@ definitions.push({ }, }) +// Example: Adds attribute 'aria-expanded=true' based on the property 'open' if the component has 'hasSubtree' property false or undefined. Does not set anything if true. +definitions.push({ + regexp: /Adds attribute '([\w-]+)=(\w+)' based on the property '(\w+)' if the component has '(\w+)' property false or undefined. Does not set anything if true\./g, + testMethod: (parameters: TestMethod) => { + const [ + attributeToBeAdded, + attributeExpectedValue, + propertyDependingOnFirst, + propertyDependingOnSecond, + ] = parameters.props + + const property = {} + + property[propertyDependingOnFirst] = attributeExpectedValue + property[propertyDependingOnSecond] = false + const actualResultIfFalse = parameters.behavior(property).attributes.root[attributeToBeAdded] + expect(testHelper.convertToMatchingTypeIfApplicable(actualResultIfFalse)).toEqual( + testHelper.convertToMatchingTypeIfApplicable(attributeExpectedValue), + ) + + property[propertyDependingOnSecond] = undefined + const actualResultIfUndefined = parameters.behavior(property).attributes.root[ + attributeToBeAdded + ] + expect(testHelper.convertToMatchingTypeIfApplicable(actualResultIfUndefined)).toEqual( + testHelper.convertToMatchingTypeIfApplicable(attributeExpectedValue), + ) + + const propertyFirstPropUndefined = {} + propertyFirstPropUndefined[propertyDependingOnSecond] = true + const actualResultFirstPropertyNegateUndefined = parameters.behavior(propertyFirstPropUndefined) + .attributes.root[attributeToBeAdded] + expect( + testHelper.convertToMatchingTypeIfApplicable(actualResultFirstPropertyNegateUndefined), + ).toEqual(undefined) + }, +}) + // Example: Adds attribute 'aria-expanded=true' based on the property 'open' if the component has 'hasSubtree' property. definitions.push({ regexp: /Adds attribute '([\w-]+)=(\w+)' based on the property '(\w+)' if the component has '(\w+)' property\./g, @@ -337,16 +404,18 @@ definitions.push({ testHelper.convertToMatchingTypeIfApplicable(attributeExpectedValue), ) - const propertyFirstPropNegate = {} - propertyFirstPropNegate[ - propertyDependingOnFirst - ] = !testHelper.convertToMatchingTypeIfApplicable(attributeExpectedValue) - propertyFirstPropNegate[propertyDependingOnSecond] = true - const actualResultFirstPropertyNegate = parameters.behavior(propertyFirstPropNegate).attributes - .root[attributeToBeAdded] - expect(testHelper.convertToMatchingTypeIfApplicable(actualResultFirstPropertyNegate)).toEqual( - !testHelper.convertToMatchingTypeIfApplicable(attributeExpectedValue), - ) + if (typeof testHelper.convertToMatchingTypeIfApplicable(attributeExpectedValue) === 'boolean') { + const propertyFirstPropNegate = {} + propertyFirstPropNegate[ + propertyDependingOnFirst + ] = !testHelper.convertToMatchingTypeIfApplicable(attributeExpectedValue) + propertyFirstPropNegate[propertyDependingOnSecond] = true + const actualResultFirstPropertyNegate = parameters.behavior(propertyFirstPropNegate) + .attributes.root[attributeToBeAdded] + expect(testHelper.convertToMatchingTypeIfApplicable(actualResultFirstPropertyNegate)).toEqual( + !testHelper.convertToMatchingTypeIfApplicable(attributeExpectedValue), + ) + } const propertyFirstPropUndefined = {} propertyFirstPropUndefined[propertyDependingOnFirst] = true From c978b34be39567e89da91be386b3a0f7d57645a0 Mon Sep 17 00:00:00 2001 From: Silviu Avram Date: Tue, 12 Nov 2019 12:29:49 +0100 Subject: [PATCH 13/14] TreeTitle conformant --- packages/react/src/components/Tree/Tree.tsx | 3 ++- .../react/test/specs/components/Tree/TreeTitle-test.tsx | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 packages/react/test/specs/components/Tree/TreeTitle-test.tsx diff --git a/packages/react/src/components/Tree/Tree.tsx b/packages/react/src/components/Tree/Tree.tsx index 63afacfaef..53b28b0b95 100644 --- a/packages/react/src/components/Tree/Tree.tsx +++ b/packages/react/src/components/Tree/Tree.tsx @@ -26,7 +26,7 @@ import { ShorthandValue, } from '../../types' import { hasSubtree, removeItemAtIndex } from './lib' -import { TreeTitleProps } from './TreeTitle' +import TreeTitle, { TreeTitleProps } from './TreeTitle' import { ReactAccessibilityBehavior } from '../../lib/accessibility/reactTypes' export interface TreeSlotClassNames { @@ -113,6 +113,7 @@ class Tree extends AutoControlledComponent, TreeState> { static autoControlledProps = ['activeItemIds'] static Item = TreeItem + static Title = TreeTitle // memoize this function if performance issue occurs. static getItemsForRender = (itemsFromProps: ShorthandCollection) => { diff --git a/packages/react/test/specs/components/Tree/TreeTitle-test.tsx b/packages/react/test/specs/components/Tree/TreeTitle-test.tsx new file mode 100644 index 0000000000..529d494e4b --- /dev/null +++ b/packages/react/test/specs/components/Tree/TreeTitle-test.tsx @@ -0,0 +1,6 @@ +import { isConformant } from 'test/specs/commonTests' +import TreeTitle from 'src/components/Tree/TreeTitle' + +describe('TreeTitle', () => { + isConformant(TreeTitle) +}) From b7a822f15e9cef48d551f642d9f9c149a70a64e3 Mon Sep 17 00:00:00 2001 From: Silviu Avram Date: Tue, 12 Nov 2019 13:44:39 +0100 Subject: [PATCH 14/14] default size is actually 1 --- packages/react/src/components/Tree/TreeItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/components/Tree/TreeItem.tsx b/packages/react/src/components/Tree/TreeItem.tsx index a7f48e3b4b..76c6b11bd0 100644 --- a/packages/react/src/components/Tree/TreeItem.tsx +++ b/packages/react/src/components/Tree/TreeItem.tsx @@ -137,7 +137,7 @@ class TreeItem extends UIComponent, TreeItemState> { static getDerivedStateFromProps(props: TreeItemProps) { return { hasSubtree: hasSubtree(props), - treeSize: props.siblings ? props.siblings.length + 1 : 0, + treeSize: props.siblings ? props.siblings.length + 1 : 1, } }