Skip to content

Commit

Permalink
LG-3439, 3689, 3785: Nested Row animations (#2130)
Browse files Browse the repository at this point in the history
* change to super high value

* change height value

* changeset

* docs

* apply disableAnimations prop down to subcomponents

* tests

* tests

* fix animation jumpiness

* remove transition function

* rename spec describe

* measure content height with ref

* apply ref height calculation to cell transition

* Update Tooltip.spec.tsx

* Table cell overflow [LG-3952] (#2175)

* Update makeData.testutils.tsx

* Adds `overflow` prop. Styles truncated text

* Update InternalCell.tsx

* import correct styles

* Create wicked-impalas-battle.md

* contentClassName prop

* fix max-height default

---------

Co-authored-by: Adam Thompson <[email protected]>
Co-authored-by: Adam Thompson <[email protected]>
Co-authored-by: Brooke Scarlett Yalof <[email protected]>
  • Loading branch information
4 people authored Jan 25, 2024
1 parent e0b4080 commit bb8987d
Show file tree
Hide file tree
Showing 28 changed files with 281 additions and 129 deletions.
5 changes: 5 additions & 0 deletions .changeset/old-singers-kneel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@leafygreen-ui/table': minor
---

Adds `contentClassName` prop, applied to the inner `div` of the Cell
5 changes: 5 additions & 0 deletions .changeset/wicked-impalas-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@leafygreen-ui/table': minor
---

Adds `overflow` prop to `Cell` component. By default there is no change. When `overflow === 'truncate'`, the styling of the cell is updated (if necessary) to be aligned to the top, with an ellipsis after 2 lines of text.
5 changes: 5 additions & 0 deletions .changeset/wild-ads-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@leafygreen-ui/table': minor
---

Nested rows now support animations for content taller than 40px
13 changes: 7 additions & 6 deletions packages/table/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,12 @@ This option determines the alignment of the column. Refer to [Storybook deployme
#### Props
| Name | Description | Type | Default |
| ------------------------- | -------------------------------------------------------------- | -------- | ------- |
| `shouldAlternateRowColor` | Determines whether alternating rows will have dark backgrounds | boolean | false |
| `baseFontSize` | The base font size of the title and text rendered in children | 13 \| 16 | 13 |
| `darkMode` | Render the component in dark mode. | boolean | false |
| Name | Description | Type | Default |
| ------------------------- | ------------------------------------------------------------------------------------------- | -------- | ------- |
| `shouldAlternateRowColor` | Determines whether alternating rows will have dark backgrounds | boolean | false |
| `disableAnimations` | Disables all transition animations for smoother rendering of tall content where appropriate | boolean | false |
| `baseFontSize` | The base font size of the title and text rendered in children | 13 \| 16 | 13 |
| `darkMode` | Render the component in dark mode. | boolean | false |
\+ other HTML `table` element props
Expand Down Expand Up @@ -285,7 +286,7 @@ All HTML `tr` element props
`Cell` accepts HTML `td` element props.
> The `Cell` component does not automatically handle overflowing text content, as `text-overflow` depends on the element having `overflow: hidden` and an explicit pixel width value. Refer to the LeafyGreen [Storybook deployment](https://mongodb.github.io/leafygreen-ui/) for an example.
> All nested row animations are set at the Cell level, with a `max-height` set to 40vh, which should cover most cases with a relatively smooth animation. For taller content, set `disableAnimation={true}` or override the max-height with a `& > div { max-height: ... }` CSS selector on the `Cell` component.
## Feature Examples
Expand Down
57 changes: 37 additions & 20 deletions packages/table/src/Cell/Cell.styles.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TransitionStatus } from 'react-transition-group';

import { css } from '@leafygreen-ui/emotion';
import { spacing, transitionDuration } from '@leafygreen-ui/tokens';
import { spacing, transitionDuration, typeScales } from '@leafygreen-ui/tokens';

import { Align } from './Cell.types';

Expand All @@ -17,7 +17,6 @@ export const standardCellHeight = spacing[5] + spacing[2];
export const baseCellStyles = css`
padding: 0 8px;
overflow: hidden;
text-overflow: ellipsis;
&:focus-visible {
box-shadow: inset;
Expand Down Expand Up @@ -75,29 +74,47 @@ export const basicCellStyles = css`
}
`;

export const cellContentContainerStyles = css`
export const cellTransitionContainerStyles = css`
display: flex;
align-items: center;
text-overflow: ellipsis;
transition: ${transitionDuration.default}ms ease-in-out;
transition-property: min-height, max-height, opacity, transform;
min-height: ${standardCellHeight}px;
transition-property: min-height, max-height, opacity, padding, transform;
transition-duration: ${transitionDuration.default}ms;
transition-timing-function: ease;
`;

const _hiddenStyles = css`
opacity: 0;
min-height: 0;
max-height: 0;
export const truncatedContentStyles = css`
/* See https://css-tricks.com/line-clampin/#aa-the-standardized-way */
display: -webkit-box;
-webkit-line-clamp: ${standardCellHeight / typeScales.body1.lineHeight};
-webkit-box-orient: vertical;
-webkit-box-align: start;
`;

export const cellContentTransitionStyles: Record<TransitionStatus, string> = {
entered: css`
opacity: 1;
min-height: ${standardCellHeight}px;
max-height: ${standardCellHeight}px;
`,
entering: _hiddenStyles,
exiting: _hiddenStyles,
exited: _hiddenStyles,
unmounted: _hiddenStyles,
export const disableAnimationStyles = css`
transition-duration: 0;
transition: none;
`;

export const cellContentTransitionStateStyles = (
height?: number,
): Record<TransitionStatus, string> => {
const _hiddenStyles = css`
opacity: 0;
min-height: 0;
max-height: 0;
overflow: hidden;
`;

return {
entered: css`
opacity: 1;
min-height: ${standardCellHeight}px;
max-height: ${height ? height + 'px' : 'unset'};
`,
entering: _hiddenStyles,
exiting: _hiddenStyles,
exited: _hiddenStyles,
unmounted: _hiddenStyles,
};
};
35 changes: 27 additions & 8 deletions packages/table/src/Cell/Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,40 @@ import React from 'react';

import { cx } from '@leafygreen-ui/emotion';

import { useTableContext } from '../TableContext';

import {
alignmentStyles,
baseCellStyles,
basicCellStyles,
cellContentContainerStyles,
cellTransitionContainerStyles,
disableAnimationStyles,
} from './Cell.styles';
import { CellProps } from '.';

const Cell = ({ className, align, children, ...rest }: CellProps) => (
<td className={cx(baseCellStyles, basicCellStyles, className)} {...rest}>
<div className={cx(cellContentContainerStyles, alignmentStyles(align))}>
{children}
</div>
</td>
);
const Cell = ({
className,
contentClassName,
align,
children,
...rest
}: CellProps) => {
const { disableAnimations } = useTableContext();
return (
<td className={cx(baseCellStyles, basicCellStyles, className)} {...rest}>
<div
className={cx(
cellTransitionContainerStyles,
alignmentStyles(align),
{ [disableAnimationStyles]: disableAnimations },
contentClassName,
)}
>
{children}
</div>
</td>
);
};

Cell.displayName = 'Cell';

Expand Down
84 changes: 55 additions & 29 deletions packages/table/src/Cell/Cell.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,66 @@ export type Align = Extract<
'left' | 'right' | 'center'
>;

interface AlignProp {
export const CellOverflowBehavior = {
Default: 'default',
Truncate: 'truncate',
// TODO: `Expand`: The cell will expand to the height of its content
// Expand: 'expand',
} as const;
export type CellOverflowBehavior =
(typeof CellOverflowBehavior)[keyof typeof CellOverflowBehavior];

interface BaseCellProps extends HTMLElementProps<'td'> {
/**
* Alignment of the cell's contents
*
* Overrides `<td>`'s deprecated `align` prop
*/
align?: Align;

/** A `className` applied to the inner `div` of the Cell */
contentClassName?: string;

/**
* Defines how a cell should behave when its content is larger than the standard cell height.
*
* `Default`: The cell height will be fixed to the standard cell height (40px by default).
* Any overflowing content will be clipped.
*
* `Truncate`: The cell height will be fixed to the standard cell height (40px by default),
* and include an ellipsis before the content is clipped.
*
* Note: It's recommended to provide the same value for all cells in a given row.
*
* @default CellOverflowBehavior.Default
*/
overflow?: CellOverflowBehavior;
}

export type CellProps = HTMLElementProps<'td'> & AlignProp;

export type InternalCellProps = CellProps &
AlignProp & {
/**
* Index of the cell in its parent row.
*/
cellIndex: number;

/**
* Depth of nesting its parent row has.
*/
depth: number;

/**
* Defines whether the cell's row is visible (i.e. expanded)
*
* @default true
*/
isVisible?: boolean;

/**
* Defines whether the cell's row is expandable
*
* @default false
*/
isExpandable?: boolean;
};
export type CellProps = BaseCellProps;

export interface InternalCellProps extends BaseCellProps {
/**
* Index of the cell in its parent row.
*/
cellIndex: number;

/**
* Depth of nesting its parent row has.
*/
depth: number;

/**
* Defines whether the cell's row is visible (i.e. expanded)
*
* @default true
*/
isVisible?: boolean;

/**
* Defines whether the cell's row is expandable
*
* @default false
*/
isExpandable?: boolean;
}
6 changes: 3 additions & 3 deletions packages/table/src/Cell/HeaderCell/HeaderCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import React, { PropsWithChildren } from 'react';

import { cx } from '@leafygreen-ui/emotion';

import { useTableContext } from '../../TableContext/TableContext';
import { useTableContext } from '../../TableContext';
import { LGRowData } from '../../useLeafyGreenTable';
import {
alignmentStyles,
baseCellStyles,
cellContentContainerStyles,
cellTransitionContainerStyles,
getCellPadding,
} from '../Cell.styles';

Expand Down Expand Up @@ -65,7 +65,7 @@ const HeaderCell = <T extends LGRowData>({
>
<div
className={cx(
cellContentContainerStyles,
cellTransitionContainerStyles,
headerCellContentStyles,
// TS error is ignored (and not expected) as it doesn't show up locally but interrupts build
// @ts-ignore Header types need to be extended or declared in the react-table namespace
Expand Down
37 changes: 29 additions & 8 deletions packages/table/src/Cell/InternalCell.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
import React, { useRef } from 'react';
import React, { useMemo, useRef } from 'react';
import { Transition } from 'react-transition-group';
import PropTypes from 'prop-types';

import { cx } from '@leafygreen-ui/emotion';

import { useTableContext } from '../TableContext/TableContext';
import { useTableContext } from '../TableContext';

import {
alignmentStyles,
baseCellStyles,
cellContentContainerStyles,
cellContentTransitionStyles,
cellContentTransitionStateStyles,
cellTransitionContainerStyles,
disableAnimationStyles,
getCellPadding,
standardCellHeight,
truncatedContentStyles,
} from './Cell.styles';
import { InternalCellProps } from './Cell.types';
import { CellOverflowBehavior, InternalCellProps } from './Cell.types';

const InternalCell = ({
children,
className,
contentClassName,
cellIndex,
depth,
isVisible = true,
isExpandable = false,
overflow,
align,
...rest
}: InternalCellProps) => {
const isFirstCell = cellIndex === 0;
const { table } = useTableContext();
const { table, disableAnimations } = useTableContext();
const isSelectable = !!table && !!table.hasSelectableRows;
const transitionRef = useRef<HTMLElement | null>(null);
const contentRef = useRef<HTMLDivElement>(null);

const contentHeight = standardCellHeight;
const scrollHeight = contentRef.current
? contentRef.current?.scrollHeight
: 0;
const shouldTruncate = useMemo(() => {
return (
overflow === CellOverflowBehavior.Truncate && scrollHeight > contentHeight
);
}, [contentHeight, overflow, scrollHeight]);
return (
<td
className={cx(
Expand All @@ -45,10 +60,16 @@ const InternalCell = ({
{state => (
<div
data-state={state}
ref={contentRef}
className={cx(
cellContentContainerStyles,
cellContentTransitionStyles[state],
cellTransitionContainerStyles,
cellContentTransitionStateStyles(contentHeight)[state],
alignmentStyles(align),
{
[disableAnimationStyles]: disableAnimations,
[truncatedContentStyles]: shouldTruncate,
},
contentClassName,
)}
>
{children}
Expand Down
Loading

0 comments on commit bb8987d

Please sign in to comment.