diff --git a/CHANGELOG.md b/CHANGELOG.md
index c48ed22c61..9217cf3427 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
## [Unreleased]
+### Features
+- Add `Tree` Component @priyankar205 ([#479]
+(https://github.com/stardust-ui/react/pull/479))
+
## [v0.13.0](https://github.com/stardust-ui/react/tree/v0.13.0) (2018-11-27)
[Compare changes](https://github.com/stardust-ui/react/compare/v0.12.1...v0.13.0)
diff --git a/docs/src/examples/components/Tree/Types/TreeExample.shorthand.tsx b/docs/src/examples/components/Tree/Types/TreeExample.shorthand.tsx
new file mode 100644
index 0000000000..aef1cbc7f4
--- /dev/null
+++ b/docs/src/examples/components/Tree/Types/TreeExample.shorthand.tsx
@@ -0,0 +1,35 @@
+import * as React from 'react'
+import { Tree } from '@stardust-ui/react'
+
+const items = [
+ {
+ key: '1',
+ title: 'one',
+ items: [
+ {
+ key: '1',
+ title: 'one one',
+ items: [
+ {
+ key: '1',
+ title: 'one one one',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ key: '2',
+ title: ' two',
+ items: [
+ {
+ key: '1',
+ title: 'two one',
+ },
+ ],
+ },
+]
+
+const TreeExampleShorthand = () =>
extends React.Component
{ +class UIComponent
extends React.Component
{ private readonly childClass = this.constructor as typeof UIComponent static defaultProps: { [key: string]: any } static displayName: string diff --git a/src/lib/accessibility/Behaviors/Tree/treeTitleBehavior.ts b/src/lib/accessibility/Behaviors/Tree/treeTitleBehavior.ts new file mode 100644 index 0000000000..1358cc9c50 --- /dev/null +++ b/src/lib/accessibility/Behaviors/Tree/treeTitleBehavior.ts @@ -0,0 +1,15 @@ +import { Accessibility } from '../../types' + +/** + * @specification + * Adds attribute 'aria-expanded=true' based on the property 'open' if the component has 'hasSubtree' property. + */ +const treeTitleBehavior: Accessibility = (props: any) => ({ + attributes: { + root: { + ...(props.hasSubtree && { 'aria-expanded': props.open ? 'true' : 'false' }), + }, + }, +}) + +export default treeTitleBehavior diff --git a/src/lib/accessibility/index.ts b/src/lib/accessibility/index.ts index fc8c7f4904..0562467be6 100644 --- a/src/lib/accessibility/index.ts +++ b/src/lib/accessibility/index.ts @@ -24,4 +24,5 @@ export { default as popupFocusTrapBehavior } from './Behaviors/Popup/popupFocusT export { default as chatBehavior } from './Behaviors/Chat/chatBehavior' export { default as chatMessageBehavior } from './Behaviors/Chat/chatMessageBehavior' export { default as gridBehavior } from './Behaviors/Grid/gridBehavior' +export { default as treeTitleBehavior } from './Behaviors/Tree/treeTitleBehavior' export { default as dialogBehavior } from './Behaviors/Dialog/dialogBehavior' diff --git a/src/themes/teams-dark/componentVariables.ts b/src/themes/teams-dark/componentVariables.ts index a91c112954..8e3ec3ed40 100644 --- a/src/themes/teams-dark/componentVariables.ts +++ b/src/themes/teams-dark/componentVariables.ts @@ -3,3 +3,4 @@ export { default as Divider } from './components/Divider/dividerVariables' export { default as Header } from './components/Header/headerVariables' export { default as Input } from './components/Input/inputVariables' export { default as Text } from './components/Text/textVariables' +export { default as TreeTitle } from './components/Tree/treeTitleVariables' diff --git a/src/themes/teams-dark/components/Tree/treeTitleVariables.ts b/src/themes/teams-dark/components/Tree/treeTitleVariables.ts new file mode 100644 index 0000000000..e8cce3da52 --- /dev/null +++ b/src/themes/teams-dark/components/Tree/treeTitleVariables.ts @@ -0,0 +1,7 @@ +import { TreeTitleVariables } from '../../../teams/components/Tree/treeTitleVariables' + +export default (siteVars: any): TreeTitleVariables => { + return { + defaultColor: siteVars.white, + } +} diff --git a/src/themes/teams-high-contrast/componentVariables.ts b/src/themes/teams-high-contrast/componentVariables.ts index ccc007c5b0..38bb4040b9 100644 --- a/src/themes/teams-high-contrast/componentVariables.ts +++ b/src/themes/teams-high-contrast/componentVariables.ts @@ -6,3 +6,4 @@ export { default as Header } from './components/Header/headerVariables' export { default as Input } from './components/Input/inputVariables' export { default as Text } from './components/Text/textVariables' +export { default as TreeTitle } from './components/Tree/treeTitleVariables' diff --git a/src/themes/teams-high-contrast/components/Tree/treeTitleVariables.ts b/src/themes/teams-high-contrast/components/Tree/treeTitleVariables.ts new file mode 100644 index 0000000000..e8cce3da52 --- /dev/null +++ b/src/themes/teams-high-contrast/components/Tree/treeTitleVariables.ts @@ -0,0 +1,7 @@ +import { TreeTitleVariables } from '../../../teams/components/Tree/treeTitleVariables' + +export default (siteVars: any): TreeTitleVariables => { + return { + defaultColor: siteVars.white, + } +} diff --git a/src/themes/teams/componentStyles.ts b/src/themes/teams/componentStyles.ts index ff31420305..4490cc07e2 100644 --- a/src/themes/teams/componentStyles.ts +++ b/src/themes/teams/componentStyles.ts @@ -52,4 +52,8 @@ export { default as Status } from './components/Status/statusStyles' export { default as Text } from './components/Text/textStyles' +export { default as Tree } from './components/Tree/treeStyles' +export { default as TreeItem } from './components/Tree/treeItemStyles' +export { default as TreeTitle } from './components/Tree/treeTitleStyles' + export { default as Animation } from './components/Animation/animationStyles' diff --git a/src/themes/teams/componentVariables.ts b/src/themes/teams/componentVariables.ts index eeb611e45a..384724a913 100644 --- a/src/themes/teams/componentVariables.ts +++ b/src/themes/teams/componentVariables.ts @@ -47,4 +47,6 @@ export { default as Status } from './components/Status/statusVariables' export { default as Text } from './components/Text/textVariables' +export { default as TreeTitle } from './components/Tree/treeTitleVariables' + export { default as Animation } from './components/Animation/animationVariables' diff --git a/src/themes/teams/components/Tree/treeItemStyles.ts b/src/themes/teams/components/Tree/treeItemStyles.ts new file mode 100644 index 0000000000..7b981ed410 --- /dev/null +++ b/src/themes/teams/components/Tree/treeItemStyles.ts @@ -0,0 +1,11 @@ +import { ICSSInJSStyle } from '../../../types' +import { pxToRem } from '../../../../lib' + +const treeItemStyles = { + root: (): ICSSInJSStyle => ({ + listStyleType: 'none', + padding: `0 0 0 ${pxToRem(1)}`, + }), +} + +export default treeItemStyles diff --git a/src/themes/teams/components/Tree/treeStyles.ts b/src/themes/teams/components/Tree/treeStyles.ts new file mode 100644 index 0000000000..713956a787 --- /dev/null +++ b/src/themes/teams/components/Tree/treeStyles.ts @@ -0,0 +1,11 @@ +import { ICSSInJSStyle } from '../../../types' +import { pxToRem } from '../../../../lib' + +const treeStyles = { + root: (): ICSSInJSStyle => ({ + display: 'block', + paddingLeft: `${pxToRem(10)}`, + }), +} + +export default treeStyles diff --git a/src/themes/teams/components/Tree/treeTitleStyles.ts b/src/themes/teams/components/Tree/treeTitleStyles.ts new file mode 100644 index 0000000000..3efdfbd680 --- /dev/null +++ b/src/themes/teams/components/Tree/treeTitleStyles.ts @@ -0,0 +1,12 @@ +import { ICSSInJSStyle } from '../../../types' +import { pxToRem } from '../../../../lib' + +const treeTitleStyles = { + root: ({ variables }): ICSSInJSStyle => ({ + padding: `${pxToRem(1)} 0`, + cursor: 'pointer', + color: variables.defaultColor, + }), +} + +export default treeTitleStyles diff --git a/src/themes/teams/components/Tree/treeTitleVariables.ts b/src/themes/teams/components/Tree/treeTitleVariables.ts new file mode 100644 index 0000000000..cb80ee65ce --- /dev/null +++ b/src/themes/teams/components/Tree/treeTitleVariables.ts @@ -0,0 +1,9 @@ +export interface TreeTitleVariables { + defaultColor: string +} + +export default (siteVars: any): TreeTitleVariables => { + return { + defaultColor: siteVars.black, + } +} diff --git a/test/specs/behaviors/behavior-test.tsx b/test/specs/behaviors/behavior-test.tsx index bc38e2ddc5..a2951092cf 100644 --- a/test/specs/behaviors/behavior-test.tsx +++ b/test/specs/behaviors/behavior-test.tsx @@ -26,6 +26,7 @@ import { toggleButtonBehavior, toolbarBehavior, toolbarButtonBehavior, + treeTitleBehavior, gridBehavior, } from 'src/lib/accessibility' import { TestHelper } from './testHelper' @@ -55,6 +56,7 @@ testHelper.addBehavior('tabListBehavior', tabListBehavior) testHelper.addBehavior('toolbarBehavior', toolbarBehavior) testHelper.addBehavior('toggleButtonBehavior', toggleButtonBehavior) testHelper.addBehavior('toolbarButtonBehavior', toolbarButtonBehavior) +testHelper.addBehavior('treeTitleBehavior', treeTitleBehavior) testHelper.addBehavior('gridBehavior', gridBehavior) testHelper.addBehavior('dialogBehavior', dialogBehavior) diff --git a/test/specs/behaviors/testDefinitions.ts b/test/specs/behaviors/testDefinitions.ts index 8015733f50..4f73c31fdb 100644 --- a/test/specs/behaviors/testDefinitions.ts +++ b/test/specs/behaviors/testDefinitions.ts @@ -163,6 +163,48 @@ definitions.push({ }, }) +// Example: Adds attribute 'aria-expanded=true' based on the property 'open' if the component has 'hasSubtree' property. +definitions.push({ + regexp: /Adds attribute '([\w\-\w \s*]+)=([a-z]+)' based on the property '([a-z]+)' if the component has '([a-zA-Z]+)' property./g, + testMethod: (parameters: TestMethod) => { + const [ + attributeToBeAdded, + attributeExpectedValue, + propertyDependingOnFirst, + propertyDependingOnSecond, + ] = [...parameters.props] + + const property = {} + + property[propertyDependingOnFirst] = attributeExpectedValue + property[propertyDependingOnSecond] = true + const actualResult = parameters.behavior(property).attributes.root[attributeToBeAdded] + expect(testHelper.convertToBooleanIfApplicable(actualResult)).toEqual( + testHelper.convertToBooleanIfApplicable(attributeExpectedValue), + ) + + const propertyFirstPropNegate = {} + propertyFirstPropNegate[propertyDependingOnFirst] = !testHelper.convertToBooleanIfApplicable( + attributeExpectedValue, + ) + propertyFirstPropNegate[propertyDependingOnSecond] = true + const actualResultFirstPropertyNegate = parameters.behavior(propertyFirstPropNegate).attributes + .root[attributeToBeAdded] + expect(testHelper.convertToBooleanIfApplicable(actualResultFirstPropertyNegate)).toEqual( + !testHelper.convertToBooleanIfApplicable(attributeExpectedValue), + ) + + const propertyFirstPropUndefined = {} + propertyFirstPropUndefined[propertyDependingOnFirst] = true + propertyFirstPropUndefined[propertyDependingOnSecond] = undefined + const actualResultFirstPropertyNegateUndefined = parameters.behavior(propertyFirstPropUndefined) + .attributes.root[attributeToBeAdded] + expect( + testHelper.convertToBooleanIfApplicable(actualResultFirstPropertyNegateUndefined), + ).toEqual(undefined) + }, +}) + // Example: Adds role='button' if element type is other than 'button'. definitions.push({ regexp: /Adds role='([a-z]+)' if element type is other than '[a-z]+'\.+/g, diff --git a/test/specs/behaviors/testHelper.tsx b/test/specs/behaviors/testHelper.tsx index f79e51e7cb..8b9842f294 100644 --- a/test/specs/behaviors/testHelper.tsx +++ b/test/specs/behaviors/testHelper.tsx @@ -115,9 +115,12 @@ export class TestHelper { return importedBehavior } - public convertToBooleanIfApplicable(stringToConvert: string) { - if (stringToConvert === 'true' || stringToConvert === 'false') { - return Boolean(stringToConvert) + public convertToBooleanIfApplicable(stringToConvert: any) { + if (stringToConvert === 'true') { + return true + } + if (stringToConvert === 'false') { + return false } return stringToConvert } diff --git a/test/specs/components/Tree/Tree-test.tsx b/test/specs/components/Tree/Tree-test.tsx new file mode 100644 index 0000000000..0999e2b17f --- /dev/null +++ b/test/specs/components/Tree/Tree-test.tsx @@ -0,0 +1,7 @@ +import { isConformant } from 'test/specs/commonTests' + +import Tree from 'src/components/Tree/Tree' + +describe('Tree', () => { + isConformant(Tree) +})