Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 47 additions & 12 deletions packages/@react-spectrum/s2/src/TreeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,36 @@ import {
TreeItem,
TreeItemContent,
TreeItemContentProps,
TreeLoadMoreItem,
TreeLoadMoreItemProps,
useContextProps,
Virtualizer
} from 'react-aria-components';
import {centerBaseline} from './CenterBaseline';
import {Checkbox} from './Checkbox';
import Chevron from '../ui-icons/Chevron';
import {colorMix, focusRing, fontRelative, lightDark, style} from '../style' with {type: 'macro'};
import {DOMRef, DOMRefValue, forwardRefType, GlobalDOMAttributes, Key} from '@react-types/shared';
import {DOMRef, forwardRefType, GlobalDOMAttributes, Key, LoadingState} from '@react-types/shared';
import {getAllowedOverrides, StylesPropWithHeight, UnsafeStyles} from './style-utils' with {type: 'macro'};
import {IconContext} from './Icon';
// @ts-ignore
import intlMessages from '../intl/*.json';
import {ProgressCircle} from './ProgressCircle';
import {raw} from '../style/style-macro' with {type: 'macro'};
import React, {createContext, forwardRef, JSXElementConstructor, ReactElement, ReactNode, useContext, useRef} from 'react';
import {TextContext} from './Content';
import {useDOMRef} from '@react-spectrum/utils';
import {useLocale} from 'react-aria';
import {useLocale, useLocalizedStringFormatter} from 'react-aria';
import {useScale} from './utils';

interface S2TreeProps {
// Only detatched is supported right now with the current styles from Spectrum
// See https://github.com/adobe/react-spectrum/pull/7343 for what remaining combinations are left
/** Whether the tree should be displayed with a [detached style](https://spectrum.adobe.com/page/tree-view/#Detached). */
isDetached?: boolean,
/** Handler that is called when a user performs an action on a row. */
onAction?: (key: Key) => void,
// not fully supported yet
/** Whether the tree should be displayed with a [emphasized style](https://spectrum.adobe.com/page/tree-view/#Emphasis). */
isEmphasized?: boolean
}

Expand All @@ -58,6 +66,11 @@ export interface TreeViewItemProps extends Omit<RACTreeItemProps, 'className' |
hasChildItems?: boolean
}

export interface TreeViewLoadMoreItemProps extends Pick<TreeLoadMoreItemProps, 'onLoadMore'> {
/** The current loading state of the TreeView or TreeView row. */
loadingState?: LoadingState
}

interface TreeRendererContextValue {
renderer?: (item) => ReactElement<any, string | JSXElementConstructor<any>>
}
Expand Down Expand Up @@ -91,7 +104,10 @@ const tree = style({
}
}, getAllowedOverrides({height: true}));

const TreeView = /*#__PURE__*/ (forwardRef as forwardRefType)(function TreeView<T extends object>(props: TreeViewProps<T>, ref: DOMRef<HTMLDivElement>) {
/**
* A tree view provides users with a way to navigate nested hierarchical information.
*/
export const TreeView = /*#__PURE__*/ (forwardRef as forwardRefType)(function TreeView<T extends object>(props: TreeViewProps<T>, ref: DOMRef<HTMLDivElement>) {
let {children, isDetached, isEmphasized, UNSAFE_className, UNSAFE_style} = props;
let scale = useScale();

Expand Down Expand Up @@ -180,7 +196,6 @@ const treeRow = style({
}
});


const treeCellGrid = style({
display: 'grid',
width: 'full',
Expand Down Expand Up @@ -346,7 +361,6 @@ export const TreeViewItemContent = (props: TreeViewItemContentProps): ReactNode
gridArea: 'level-padding',
width: 'calc(calc(var(--tree-item-level, 0) - 1) * var(--indent))'
})} />
{/* TODO: revisit when we do async loading, at the moment hasChildItems will only cause the chevron to be rendered, no aria/data attributes indicating the row's expandability are added */}
<ExpandableRowChevron isDisabled={isDisabled} isExpanded={isExpanded} scale={scale} isHidden={!(hasChildItems)} />
<Provider
values={[
Expand All @@ -368,6 +382,33 @@ export const TreeViewItemContent = (props: TreeViewItemContentProps): ReactNode
);
};

const centeredWrapper = style({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: 'full',
height: 'full'
});

export const TreeViewLoadMoreItem = (props: TreeViewLoadMoreItemProps): ReactNode => {
let {loadingState, onLoadMore} = props;
let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/s2');
let isLoading = loadingState === 'loading' || loadingState === 'loadingMore';
return (
<TreeLoadMoreItem isLoading={isLoading} onLoadMore={onLoadMore} className={style({width: 'full', marginY: 4})}>
{() => {
return (
<div className={centeredWrapper}>
<ProgressCircle
isIndeterminate
aria-label={stringFormatter.format('table.loadingMore')} />
</div>
);
}}
</TreeLoadMoreItem>
);
};

interface ExpandableRowChevronProps {
isExpanded?: boolean,
isDisabled?: boolean,
Expand Down Expand Up @@ -437,9 +478,3 @@ function ExpandableRowChevron(props: ExpandableRowChevronProps) {
</Button>
);
}

/**
* A tree view provides users with a way to navigate nested hierarchical information.
*/
const _TreeView: <T extends object>(props: TreeViewProps<T> & React.RefAttributes<DOMRefValue<HTMLDivElement>>) => ReactElement | null = TreeView;
export {_TreeView as TreeView};
4 changes: 2 additions & 2 deletions packages/@react-spectrum/s2/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export {ToastContainer as UNSTABLE_ToastContainer, ToastQueue as UNSTABLE_ToastQ
export {ToggleButton, ToggleButtonContext} from './ToggleButton';
export {ToggleButtonGroup, ToggleButtonGroupContext} from './ToggleButtonGroup';
export {Tooltip, TooltipTrigger} from './Tooltip';
export {TreeView, TreeViewItem, TreeViewItemContent} from './TreeView';
export {TreeView, TreeViewItem, TreeViewItemContent, TreeViewLoadMoreItem} from './TreeView';

export {pressScale} from './pressScale';

Expand Down Expand Up @@ -152,5 +152,5 @@ export type {ToastOptions, ToastContainerProps} from './Toast';
export type {ToggleButtonProps} from './ToggleButton';
export type {ToggleButtonGroupProps} from './ToggleButtonGroup';
export type {TooltipProps} from './Tooltip';
export type {TreeViewProps, TreeViewItemProps, TreeViewItemContentProps} from './TreeView';
export type {TreeViewProps, TreeViewItemProps, TreeViewItemContentProps, TreeViewLoadMoreItemProps} from './TreeView';
export type {AutocompleteProps, FileTriggerProps, TooltipTriggerComponentProps as TooltipTriggerProps, SortDescriptor} from 'react-aria-components';
Loading