Skip to content
This repository has been archived by the owner on May 24, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into menuWidthAuto
Browse files Browse the repository at this point in the history
  • Loading branch information
ashishkumbhare116 authored Dec 6, 2023
2 parents bbde0b1 + c3efad6 commit bb602e2
Show file tree
Hide file tree
Showing 35 changed files with 299 additions and 58 deletions.
3 changes: 3 additions & 0 deletions packages/terra-folder-tree/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Added
* Added the ability to expand and collapse folders.

## 1.0.0-alpha.1 - (November 22, 2023)

* Added
Expand Down
2 changes: 1 addition & 1 deletion packages/terra-folder-tree/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "terra-folder-tree",
"main": "lib/FolderTree.js",
"main": "lib/index.js",
"version": "1.0.0-alpha.1",
"description": "Terra Folder Tree is a vertical menu that displays files and folders in a hierarchical tree structure.",
"repository": {
Expand Down
5 changes: 2 additions & 3 deletions packages/terra-folder-tree/src/FolderTree.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import classNames from 'classnames/bind';

import ActionHeader from 'terra-action-header';

import FolderTreeItem from './subcomponents/FolderTreeItem';
import styles from './FolderTree.module.scss';

const cx = classNames.bind(styles);
Expand All @@ -13,7 +12,7 @@ const propTypes = {
/**
* List of FolderTree.Items to be displayed as content within the FolderTree.
*/
children: PropTypes.node.isRequired,
children: PropTypes.node,
/**
* The title of the folder tree.
*/
Expand All @@ -37,6 +36,7 @@ const FolderTree = ({ children, title, headerLevel }) => (
<ul
className={cx('folder-tree')}
role="tree"
aria-label={title}
>
{children}
</ul>
Expand All @@ -46,5 +46,4 @@ const FolderTree = ({ children, title, headerLevel }) => (
FolderTree.propTypes = propTypes;
FolderTree.defaultProps = defaultProps;

FolderTree.Item = FolderTreeItem;
export default FolderTree;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
:local {
.clinical-lowlight-theme {
--terra-folder-tree-item-border-bottom: #181b1d;
--terra-folder-tree-item-background-color: #1e3a49;
--terra-folder-tree-item-background: #1e3a49;
--terra-folder-tree-item-hover-background-color: #232a2d;
--terra-folder-tree-item-selected-background-color: #232a2d;
}
Expand Down
5 changes: 5 additions & 0 deletions packages/terra-folder-tree/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import FolderTree from './FolderTree';
import FolderTreeItem from './subcomponents/FolderTreeItem';

FolderTree.Item = FolderTreeItem;
export default FolderTree;
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
:local {
.orion-fusion-theme {
--terra-folder-tree-item-background-color-hover: #f4fafe;
// --terra-folder-tree-item-background-color-selected: ;
}
}
43 changes: 36 additions & 7 deletions packages/terra-folder-tree/src/subcomponents/FolderTreeItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { injectIntl } from 'react-intl';

import Spacer from 'terra-spacer';
import Arrange from 'terra-arrange';
import { IconFolder } from 'terra-icon';
import { IconFolder, IconCaretRight, IconCaretDown } from 'terra-icon';
import ThemeContext from 'terra-theme-context';

import styles from './FolderTreeItem.module.scss';
Expand All @@ -25,6 +25,10 @@ const propTypes = {
* List of FolderTree.Items to display in a subfolder when this FolderTreeItem is clicked. This makes the item expandable and collapsible. It also makes the item's icon a Folder, overriding anything given as the icon prop.
*/
subfolderItems: PropTypes.arrayOf(PropTypes.element),
/**
* Whether or not the item is expanded. Only items with subfolderItems can be expanded.
*/
isExpanded: PropTypes.bool,
/**
* Whether or not the item is selected. Since this component has the appearance of a radio button group, only one item should be selected at a time.
*/
Expand All @@ -33,6 +37,10 @@ const propTypes = {
* Callback function for click event.
*/
onClick: PropTypes.func,
/**
* Callback function for expand/collapse toggle event.
*/
onToggle: PropTypes.func,
/**
* @private
* Level of nesting for this item.
Expand All @@ -46,25 +54,30 @@ const propTypes = {
};

const defaultProps = {
isExpanded: false,
isSelected: false,
level: 0,
};

const FolderTreeItem = ({
icon,
label,
subfolderItems,
isExpanded,
isSelected,
onClick,
label,
level,
onClick,
onToggle,
subfolderItems,
intl,
}) => {
const theme = useContext(ThemeContext);
const isFolder = subfolderItems?.length > 0;

const subfolder = subfolderItems?.length > 0 ? (
const subfolder = isFolder ? (
<ul
className={cx('subfolder')}
role="group"
hidden={!isExpanded}
>
{subfolderItems.map((item) => (
<FolderTreeItem
Expand All @@ -77,11 +90,15 @@ const FolderTreeItem = ({
) : null;

const itemIcon = subfolder ? <IconFolder a11yLabel={intl.formatMessage({ id: 'Terra.folder-tree.folder-icon' })} /> : icon;
const expandCollapseIcon = isExpanded
? <IconCaretDown height="8px" width="8px" style={{ verticalAlign: 'baseline' }} /> // eslint-disable-line react/forbid-component-props
: <IconCaretRight height="8px" width="8px" style={{ verticalAlign: 'baseline' }} />; // eslint-disable-line react/forbid-component-props

const itemClassNames = classNames(
cx(
'folder-tree-item',
{ selected: isSelected },
{ folder: isFolder },
theme.className,
),
);
Expand All @@ -91,22 +108,34 @@ const FolderTreeItem = ({
<li
className={itemClassNames}
role="treeitem"
aria-expanded={isFolder ? isExpanded : null}
aria-selected={isSelected}
onClick={onToggle}
onKeyDown={onToggle}
>
<input
type="radio"
checked={isSelected}
onClick={onClick}
onChange={onClick}
aria-hidden // Hiding the radio button from assistive technology since they cannot be grouped correctly
tabIndex={-1} // Prevent tabbing to the button since it should not be read or acknowledged by assistive technology
/>
{/* eslint-disable-next-line react/forbid-dom-props */}
<span style={{ paddingLeft: `${level}rem` }}>
<Arrange
fitStart={(
<Spacer paddingLeft="medium" paddingRight="medium" isInlineBlock>
{
isFolder ? (
<Spacer paddingRight="small" isInlineBlock>
{expandCollapseIcon}
</Spacer>
) : null
}
{itemIcon}
</Spacer>
)}
fill={label}
fill={<span>{label}</span>}
alignFitStart="center"
/>
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
:local {
.folder-tree-item {
align-items: center;
background-color: var(--terra-folder-tree-item-background-color, #fff);
background: var(--terra-folder-tree-item-background, #fff);
border-bottom: var(--terra-folder-tree-item-border-bottom, 1px solid #dedfe0);
display: flex;
margin: 0;
Expand All @@ -18,6 +18,10 @@
}
}

.folder:hover {
cursor: pointer;
}

.selected {
background-color: var(--terra-folder-tree-item-selected-background-color, darken(#ebf6fd, 2%));
}
Expand Down
93 changes: 56 additions & 37 deletions packages/terra-folder-tree/tests/jest/FolderTree.test.jsx
Original file line number Diff line number Diff line change
@@ -1,66 +1,85 @@
import React from 'react';
import ActionHeader from 'terra-action-header';
/* eslint-disable-next-line import/no-extraneous-dependencies */
import { shallowWithIntl } from 'terra-enzyme-intl';
import { mountWithIntl, shallowWithIntl } from 'terra-enzyme-intl';
import FolderTree from '../../src/FolderTree';
import FolderTreeItem from '../../src/subcomponents/FolderTreeItem';

describe('basic folder tree', () => {
it('renders a folder tree with one level of children and no subfolders', () => {
const wrapper = shallowWithIntl(
<FolderTree title="Documents">
<FolderTree.Item label="Cat" />
<FolderTree.Item label="Dog" />
<FolderTree.Item label="Rabbit" />
<FolderTreeItem label="Cat" />
<FolderTreeItem label="Dog" />
<FolderTreeItem label="Rabbit" />
</FolderTree>,
);

expect(wrapper.find(ActionHeader).length).toBe(1);
expect(wrapper.find(ActionHeader).prop('text')).toBe('Documents');

expect(wrapper.find(FolderTree.Item).length).toBe(3);
expect(wrapper.find(FolderTree.Item).at(0).prop('label')).toBe('Cat');
// TODO: Fix these tests
// expect(wrapper.find(FolderTree.Item).at(0).prop('level')).toBe(0);
expect(wrapper.find(FolderTree.Item).at(1).prop('label')).toBe('Dog');
// expect(wrapper.find(FolderTree.Item).at(1).prop('level')).toBe(0);
expect(wrapper.find(FolderTree.Item).at(2).prop('label')).toBe('Rabbit');
// expect(wrapper.find(FolderTree.Item).at(2).prop('level')).toBe(0);
expect(wrapper.find(FolderTreeItem).length).toBe(3);
expect(wrapper.find(FolderTreeItem).at(0).prop('label')).toBe('Cat');
expect(wrapper.find(FolderTreeItem).at(0).dive().prop('level')).toBe(0);
expect(wrapper.find(FolderTreeItem).at(1).prop('label')).toBe('Dog');
expect(wrapper.find(FolderTreeItem).at(1).dive().prop('level')).toBe(0);
expect(wrapper.find(FolderTreeItem).at(2).prop('label')).toBe('Rabbit');
expect(wrapper.find(FolderTreeItem).at(2).dive().prop('level')).toBe(0);
});

it('renders a folder tree with subfolders', () => {
it('renders a folder tree item with subitems', () => {
const wrapper = mountWithIntl(
<FolderTreeItem
subfolderItems={[
(<FolderTreeItem label="item 1" />),
(<FolderTreeItem label="item 2" />),
(<FolderTreeItem label="item 3" />),
]}
/>,
);

const subfolder = wrapper.find('.subfolder');

expect(subfolder.find('span.fill.fill-block').length).toBe(3);
expect(subfolder.find('span.fill.fill-block').at(0).text()).toBe('item 1');
expect(subfolder.find('span.fill.fill-block').at(1).text()).toBe('item 2');
expect(subfolder.find('span.fill.fill-block').at(2).text()).toBe('item 3');
});

it('hides folder items when enclosing folder is collapsed', () => {
const wrapper = shallowWithIntl(
<FolderTree title="Documents">
<FolderTree.Item
<FolderTreeItem
label="Animals"
subfolderItems={[
(<FolderTree.Item label="Dog" />),
(<FolderTreeItem label="Dog" />),
]}
/>
</FolderTree>,
);

const firstSubfolder = wrapper.find(FolderTree.Item);
expect(firstSubfolder.prop('label')).toBe('Animals');
// TODO: Fix these tests
// expect(firstSubfolder.prop('level')).toBe(0);
// const secondSubfolder = wrapper.find(FolderTree.Item).dive();
// expect(secondSubfolder.find(FolderTree.Item).length).toBe(1);
// expect(secondSubfolder.find(FolderTree.Item).prop('label')).toBe('Dog');
// expect(secondSubfolder.find(FolderTree.Item).prop('level')).toBe(1);
const collapsedFolder = wrapper.find(FolderTreeItem).dive().dive();

expect(collapsedFolder.find('.folder-tree-item').prop('aria-expanded')).toBe(false);
expect(collapsedFolder.find('.subfolder').prop('hidden')).toBe(true);
});

// TODO: Fix these tests
// it('renders a folder tree item with subitems', () => {
// const wrapper = shallowWithIntl(
// <FolderTree.Item
// label="Animals"
// subfolderItems={[
// (<FolderTree.Item label="Dog"/>),
// (<FolderTree.Item label="Cat"/>),
// (<FolderTree.Item label="Rabbit"/>),
// ]}
// />,
// );
// expect(wrapper.find(FolderTree.Item).length).toBe(3);
// });
it('shows folder items when enclosing folder is expanded', () => {
const wrapper = shallowWithIntl(
<FolderTree title="Documents">
<FolderTreeItem
label="Animals"
isExpanded
subfolderItems={[
(<FolderTreeItem label="Dog" />),
]}
/>
</FolderTree>,
);

const expandedFolder = wrapper.find(FolderTreeItem).dive().dive();

expect(expandedFolder.find('.folder-tree-item').prop('aria-expanded')).toBe(true);
expect(expandedFolder.find('.subfolder').prop('hidden')).toBe(false);
});
});
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 22 additions & 7 deletions packages/terra-folder-tree/tests/wdio/folder-tree-spec.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
Terra.describeViewports('FolderTree', ['medium', 'large'], () => {
Terra.describeViewports('FolderTree', ['medium'], () => {
describe('Basic Folder Tree', () => {
beforeEach(() => {
it('displays a basic folder tree', () => {
browser.url('/raw/tests/cerner-terra-framework-docs/folder-tree/basic-folder-tree');
});

it('displays a basic folder tree', () => {
Terra.validates.screenshot('basic folder tree', { selector: '#basic-folder-tree' });
});

it('selects a folder tree item', () => {
browser.keys('Tab');
browser.keys('Space');
it('selects a folder tree item via mouse click', () => {
browser.url('/raw/tests/cerner-terra-framework-docs/folder-tree/basic-folder-tree');

$('input[type="radio"]').click();
$('h3').moveTo({ xOffset: 0, yOffset: 0 });
Terra.validates.screenshot('basic folder tree selected', { selector: '#basic-folder-tree' });
});

it('expands a collapsed folder via mouse click', () => {
browser.url('/raw/tests/cerner-terra-framework-docs/folder-tree/expand-collapse-folder-tree');

$('span=Projects - Level 1').click();
Terra.validates.screenshot('expanded folder', { selector: '#expand-collapse-folder-tree' });
});

it('collapses an expanded folder via mouse click', () => {
browser.url('/raw/tests/cerner-terra-framework-docs/folder-tree/expand-collapse-folder-tree');

$('span=Projects - Level 1').click();
$('span=Projects - Level 1').click();
Terra.validates.screenshot('collapsed folder', { selector: '#expand-collapse-folder-tree' });
});

it('wraps items with long labels', () => {
browser.url('/raw/tests/cerner-terra-framework-docs/folder-tree/wrapped-label-folder-tree');

Expand Down
1 change: 1 addition & 0 deletions packages/terra-framework-docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

* Added
* Added the example with `contentWidth` as auto value.
* Added examples and tests for `terra-folder-tree`.
* Added documentation for exported constants of `terra-table` in the About page.

* Changed
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ExpandCollapseFolderTree from './ExpandCollapseFolderTree?dev-site-example';

<ExpandCollapseFolderTree />
Loading

0 comments on commit bb602e2

Please sign in to comment.