Skip to content

Commit

Permalink
Add EllipsisTooltip component to admin
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesricky committed Jan 9, 2024
1 parent 4f8ad32 commit c71d745
Show file tree
Hide file tree
Showing 9 changed files with 484 additions and 0 deletions.
14 changes: 14 additions & 0 deletions .changeset/lazy-items-impress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@comet/admin": minor
---

Add `EllipsisTooltip` component

Used to automatically add a tooltip to text that is too long to fit in its container.
This is useful for displaying text in a table or data grid when the text might be too long to fit in the column.

```tsx
<ElementThatIsNotVeryBig>
<EllipsisTooltip>{textThatMightBeVeryLong}</EllipsisTooltip>
</ElementThatIsNotVeryBig>
```
166 changes: 166 additions & 0 deletions packages/admin/admin-stories/src/admin/helpers/EllipsisTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import { EllipsisTooltip } from "@comet/admin/src";
import { Minus, Plus } from "@comet/admin-icons";
import { Button, Stack, Table, TableBody, TableCell, TableHead, TableRow, Typography } from "@mui/material";
import { Box } from "@mui/system";
import { DataGrid, GridColDef } from "@mui/x-data-grid";
import { storiesOf } from "@storybook/react";
import * as React from "react";

import { storyRouterDecorator } from "../../story-router.decorator";

const words = ["Cursus", "Ridiculus", "Pharetra", "Ligula", "Sem", "Nullam", "Viverra", "Vestibulum", "Vestibulum", "Vestibulum"];

const getRandomWord = () => {
return words[Math.floor(Math.random() * words.length)];
};

const getSomeWords = (numberOfWords: number) => {
return words.slice(0, numberOfWords).join(" ");
};

const DEBUG_SHOW_SINGLE_ROW_TABLE = true;
const DEBUG_SHOW_TABLE = true;
const DEBUG_SHOW_DATA_GRID = true;

export function Story() {
const [singleRowWords, setSingleRowWords] = React.useState(["Lorem", "Ipsum"]);
const [dataGridRowWords, setDataGridRowWords] = React.useState(["Lorem", "Ipsum"]);

const gridRows = Array.from({ length: 5 }).map((_, index) => ({
id: index,
firstName: getSomeWords(1 * (index + 1)),
lastName: index === 0 ? dataGridRowWords.join(" ") : getSomeWords(3 * (index + 1)),
}));

return (
<Stack spacing={8} pb={8}>
{DEBUG_SHOW_SINGLE_ROW_TABLE && (
<div>
<Typography variant="h3" pb={2}>
Table (Single Row)
</Typography>
<Table sx={{ tableLayout: "fixed" }}>
<TableBody>
<TableRow>
<TableCell sx={{ width: 120 }}>
<EllipsisTooltip>{getSomeWords(3)}</EllipsisTooltip>
</TableCell>
<TableCell>
<EllipsisTooltip>{singleRowWords.join(" ")}</EllipsisTooltip>
</TableCell>
<TableCell>
<EllipsisTooltip>{getSomeWords(10)}.</EllipsisTooltip>
</TableCell>
</TableRow>
</TableBody>
</Table>
<Stack direction="row" alignItems="center" spacing={2} pt={2}>
<Typography>Update number of words in second column:</Typography>
<Button
size="small"
variant="contained"
color="primary"
startIcon={<Minus />}
onClick={() => setSingleRowWords((words) => words.slice(0, -1))}
>
Remove Word
</Button>
<Button
size="small"
variant="contained"
color="primary"
startIcon={<Plus />}
onClick={() => setSingleRowWords((words) => [...words, getRandomWord()])}
>
Add Word
</Button>
</Stack>
</div>
)}
{DEBUG_SHOW_TABLE && (
<div>
<Typography variant="h3" pb={2}>
Table
</Typography>
<Table sx={{ tableLayout: "fixed" }}>
<TableHead>
<TableRow>
<TableCell>Col 1</TableCell>
<TableCell>Col 2</TableCell>
<TableCell>Col 3</TableCell>
</TableRow>
</TableHead>
<TableBody>
{Array.from({ length: 5 }).map((_, index) => (
<TableRow key={index}>
<TableCell>
<EllipsisTooltip>{getSomeWords(1 * (index + 1))}</EllipsisTooltip>
</TableCell>
<TableCell>
<EllipsisTooltip>{getSomeWords(2 * (index + 1))}</EllipsisTooltip>
</TableCell>
<TableCell>
<EllipsisTooltip>{getSomeWords(3 * (index + 1))}</EllipsisTooltip>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)}
{DEBUG_SHOW_DATA_GRID && (
<Box height={300}>
<Typography variant="h3" pb={2}>
Data-Grid
</Typography>
<DataGrid rows={gridRows} columns={gridColumns} disableSelectionOnClick />
<Stack direction="row" alignItems="center" spacing={2} pt={2}>
<Typography>Update number of words in second column of first row:</Typography>
<Button
size="small"
variant="contained"
color="primary"
startIcon={<Minus />}
onClick={() => setDataGridRowWords((words) => words.slice(0, -1))}
>
Remove Word
</Button>
<Button
size="small"
variant="contained"
color="primary"
startIcon={<Plus />}
onClick={() => setDataGridRowWords((words) => [...words, getRandomWord()])}
>
Add Word
</Button>
</Stack>
</Box>
)}
</Stack>
);
}

const gridColumns: GridColDef[] = [
{
field: "firstName",
headerName: "First name",
resizable: true,
width: 250,
renderCell: ({ row }) => {
return <EllipsisTooltip>{row.firstName}</EllipsisTooltip>;
},
},
{
field: "lastName",
headerName: "Last name",
flex: 1,
renderCell: ({ row }) => {
return <EllipsisTooltip>{row.lastName}</EllipsisTooltip>;
},
},
];

storiesOf("@comet/admin/helpers", module)
.addDecorator(storyRouterDecorator())
.add("Ellipsis Tooltip", () => <Story />);
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { EllipsisTooltip } from "@comet/admin";
import { DataGrid, GridColDef } from "@mui/x-data-grid";
import { storiesOf } from "@storybook/react";
import * as React from "react";

storiesOf("stories/components/EllipsisTooltip", module).add("DataGrid", () => {
const words = ["Cursus", "Ridiculus", "Pharetra", "Ligula", "Sem", "Nullam", "Viverra", "Vestibulum", "Vestibulum", "Vestibulum"];

const getSomeWords = (numberOfWords: number) => {
return [...words, ...words, ...words].slice(0, numberOfWords).join(" ");
};

const gridRows = Array.from({ length: 5 }).map((_, index) => ({
id: index,
firstName: getSomeWords(1 * (index + 2)),
lastName: getSomeWords(3 * (index + 2)),
}));

const gridColumns: GridColDef[] = [
{
field: "firstName",
headerName: "First name",
resizable: true,
width: 250,
renderCell: ({ row }) => {
return <EllipsisTooltip>{row.firstName}</EllipsisTooltip>;
},
},
{
field: "lastName",
headerName: "Last name",
flex: 1,
renderCell: ({ row }) => {
return <EllipsisTooltip>{row.lastName}</EllipsisTooltip>;
},
},
];

return <DataGrid autoHeight rows={gridRows} columns={gridColumns} disableSelectionOnClick />;
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Meta, Story, Canvas } from "@storybook/addon-docs";

<Meta title="Docs/Components/EllipsisTooltip" />

# EllipsisTooltip

`EllipsisTooltip` is used to automatically add a tooltip to text that is too long to fit in its container.<br />
This is useful for displaying text in a table or data grid when the text might be too long to fit in the column.

## Simple Example

<Canvas>
<Story id="stories-components-ellipsistooltip--simple" />
</Canvas>

## Noteworthy

Some noteworthy things to keep in mind when using `EllipsisTooltip`.

### Usage inside a table

When used inside a table (standard HTML table or MuiTable), the width of the individual cells must be limited.<br />
This can be done by setting a fixed width on the cell or setting `table-layout: fixed` on the table.

### Usage with text styling

When used in combination with text styling, e.g., `MuiTypography` the `EllipsisTooltip` must be contained by the element that styles the text.<br/>
This will make sure only the normal text is styled, and the text inside the tooltip looks the same as in any other tooltip.

<Canvas>
<Story id="stories-components-ellipsistooltip--textstyling" />
</Canvas>

## Example with `MuiTable`

<Canvas>
<Story id="stories-components-ellipsistooltip--table" />
</Canvas>

## Example with `MuiDataGrid`

<Canvas>
<Story id="stories-components-ellipsistooltip--datagrid" />
</Canvas>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { EllipsisTooltip } from "@comet/admin";
import { Paper, Stack, Typography } from "@mui/material";
import { storiesOf } from "@storybook/react";
import * as React from "react";

storiesOf("stories/components/EllipsisTooltip", module).add("Simple", () => {
return (
<Stack direction="row" justifyContent="center" spacing={4}>
<Paper elevation={1} sx={{ width: 200, p: 2 }}>
<Typography textAlign="center">
<EllipsisTooltip>Short Text</EllipsisTooltip>
</Typography>
</Paper>
<Paper elevation={1} sx={{ width: 200, p: 2 }}>
<Typography textAlign="center">
<EllipsisTooltip>
Really long text that requires the tooltip to show the entire text that should be shown in this element.
</EllipsisTooltip>
</Typography>
</Paper>
</Stack>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { EllipsisTooltip } from "@comet/admin";
import { Table, TableBody, TableCell, TableHead, TableRow } from "@mui/material";
import { storiesOf } from "@storybook/react";
import * as React from "react";

storiesOf("stories/components/EllipsisTooltip", module).add("Table", () => {
const words = ["Cursus", "Ridiculus", "Pharetra", "Ligula", "Sem", "Nullam", "Viverra", "Vestibulum", "Vestibulum", "Vestibulum"];

const getWordsForCell = (cellNumber: number, rowIndex: number) => {
return words.slice(0, cellNumber * (rowIndex + 1)).join(" ");
};

return (
<Table sx={{ tableLayout: "fixed" }}>
<TableHead>
<TableRow>
<TableCell>Column 1</TableCell>
<TableCell>Column 2</TableCell>
<TableCell>Column 3</TableCell>
</TableRow>
</TableHead>
<TableBody>
{Array.from({ length: 5 }).map((_, rowIndex) => (
<TableRow key={rowIndex}>
<TableCell>
<EllipsisTooltip>{getWordsForCell(1, rowIndex)}</EllipsisTooltip>
</TableCell>
<TableCell>
<EllipsisTooltip>{getWordsForCell(2, rowIndex)}</EllipsisTooltip>
</TableCell>
<TableCell>
<EllipsisTooltip>{getWordsForCell(3, rowIndex)}.</EllipsisTooltip>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { EllipsisTooltip } from "@comet/admin";
import { CheckmarkCircle, CrossCircle } from "@comet/admin-icons";
import { Paper, Stack, Typography } from "@mui/material";
import { storiesOf } from "@storybook/react";
import * as React from "react";

storiesOf("stories/components/EllipsisTooltip", module).add("TextStyling", () => {
return (
<Stack direction="row" justifyContent="center" spacing={4}>
<Stack spacing={2} width={300}>
<Stack direction="row" alignItems="center" spacing={1}>
<CheckmarkCircle color="success" />
<Typography variant="h5">Correct usage</Typography>
</Stack>
<Paper elevation={1} sx={{ p: 2 }}>
<Typography sx={{ fontSize: 18, lineHeight: 1.4, fontWeigh: 300, color: "#333" }}>
<EllipsisTooltip>Lorem ipsum integer posuere erat a ante venenatis dapibus posuere velit aliquet.</EllipsisTooltip>
</Typography>
</Paper>
</Stack>
<Stack spacing={2} width={300}>
<Stack direction="row" alignItems="center" spacing={1}>
<CrossCircle color="error" />
<Typography variant="h5">Breaks tooltip styling</Typography>
</Stack>
<Paper elevation={1} sx={{ p: 2 }}>
<EllipsisTooltip>
<Typography sx={{ display: "inline", fontSize: 18, lineHeight: 1.4, fontWeigh: 300, color: "#333" }}>
Lorem ipsum integer posuere erat a ante venenatis dapibus posuere velit aliquet.
</Typography>
</EllipsisTooltip>
</Paper>
</Stack>
<Stack spacing={2} width={300}>
<Stack direction="row" alignItems="center" spacing={1}>
<CrossCircle color="error" />
<Typography variant="h5">Prevents tooltip from rendering</Typography>
</Stack>
<Paper elevation={1} sx={{ p: 2 }}>
<EllipsisTooltip>
<Typography sx={{ fontSize: 18, lineHeight: 1.4, fontWeigh: 300, color: "#333" }}>
Lorem ipsum integer posuere erat a ante venenatis dapibus posuere velit aliquet.
</Typography>
</EllipsisTooltip>
</Paper>
</Stack>
</Stack>
);
});
Loading

0 comments on commit c71d745

Please sign in to comment.