From 41d5d884e252f531cf5a2309b97f3edef2380e36 Mon Sep 17 00:00:00 2001 From: Peter Makowski Date: Wed, 24 Apr 2024 15:53:10 +0200 Subject: [PATCH] feat: allow multiple DynamicTable per page MAASENG-3091 --- .../components/DynamicTable/DynamicTable.scss | 4 ++ .../DynamicTable/DynamicTable.stories.tsx | 69 +++++++++++++++++++ .../DynamicTable/DynamicTable.test.tsx | 24 ++++++- .../components/DynamicTable/DynamicTable.tsx | 63 ++++++++++++----- .../TableCaption/TableCaption.stories.tsx | 2 +- 5 files changed, 140 insertions(+), 22 deletions(-) diff --git a/src/lib/components/DynamicTable/DynamicTable.scss b/src/lib/components/DynamicTable/DynamicTable.scss index 26977a68..18247afe 100644 --- a/src/lib/components/DynamicTable/DynamicTable.scss +++ b/src/lib/components/DynamicTable/DynamicTable.scss @@ -21,6 +21,10 @@ thead { scrollbar-gutter: stable; + position: sticky; + top: 0; + z-index: 1; + background-color: white; } thead tr, diff --git a/src/lib/components/DynamicTable/DynamicTable.stories.tsx b/src/lib/components/DynamicTable/DynamicTable.stories.tsx index cc05e0e7..e190cff8 100644 --- a/src/lib/components/DynamicTable/DynamicTable.stories.tsx +++ b/src/lib/components/DynamicTable/DynamicTable.stories.tsx @@ -21,6 +21,7 @@ export default meta; export const Example: StoryObj = { args: { className: "machines-table", + variant: "full-height", children: ( <> @@ -54,3 +55,71 @@ export const Example: StoryObj = { ), }, }; + +export const TwoTablesExample: StoryObj = { + render: (args) =>
{args.children}
, + args: { + children: ( + <> + + + + FQDN + IP address + Zone + Owner + Actions + + + + {data.slice(0, 10).map((item) => ( + + {item.fqdn} + {item.ipAddress} + {item.zone} + {item.owner} + + + + + ))} + + + + + + FQDN + IP address + Zone + Owner + Actions + + + + {data.slice(10, 20).map((item) => ( + + {item.fqdn} + {item.ipAddress} + {item.zone} + {item.owner} + + + + + ))} + + + + ), + }, +}; diff --git a/src/lib/components/DynamicTable/DynamicTable.test.tsx b/src/lib/components/DynamicTable/DynamicTable.test.tsx index 26f86cba..5da7feba 100644 --- a/src/lib/components/DynamicTable/DynamicTable.test.tsx +++ b/src/lib/components/DynamicTable/DynamicTable.test.tsx @@ -23,7 +23,7 @@ beforeAll(() => { } as DOMRect); }); -it("sets a fixed table body height based on top offset on large screens", async () => { +it("sets a fixed table body height based on top offset on large screens in full-height variant", async () => { vi.spyOn(window, "innerWidth", "get").mockReturnValue(BREAKPOINTS.xSmall); await act(async () => { @@ -31,7 +31,7 @@ it("sets a fixed table body height based on top offset on large screens", async }); const { container } = render( - + Test content @@ -60,9 +60,27 @@ it("sets a fixed table body height based on top offset on large screens", async ); }); +it("does not apply dynamic height in regular variant", async () => { + vi.spyOn(window, "innerWidth", "get").mockReturnValue(BREAKPOINTS.large); + const { container } = render( + + + + Test content + + + , + ); + await act(async () => { + fireEvent(window, new Event("resize")); + }); + const tbody = container.querySelector("tbody"); + await vi.waitFor(() => expect(tbody).toHaveStyle("height: undefined")); +}); + it("displays loading state", () => { const { container } = render( - + , ); diff --git a/src/lib/components/DynamicTable/DynamicTable.tsx b/src/lib/components/DynamicTable/DynamicTable.tsx index 0754b595..c7f683d9 100644 --- a/src/lib/components/DynamicTable/DynamicTable.tsx +++ b/src/lib/components/DynamicTable/DynamicTable.tsx @@ -5,6 +5,9 @@ import { useLayoutEffect, useRef, useCallback, + createContext, + useContext, + useMemo, } from "react"; import type { RowData, Table } from "@tanstack/react-table"; @@ -14,24 +17,37 @@ import { BREAKPOINTS } from "@/constants"; import { Placeholder } from "@/lib/elements"; import "./DynamicTable.scss"; -export type DynamicTableProps = PropsWithChildren<{ className?: string }>; +const DynamicTableContext = createContext<{ + variant: "full-height" | "regular"; +}>({ variant: "regular" }); + +export type DynamicTableProps = PropsWithChildren<{ + className?: string; + variant: "full-height" | "regular"; +}>; /** - * A table based on tanstack/react-table with a fixed header, where the table body can be scrolled vertically independent of the page itself. + * A table based on tanstack/react-table. + * In a full-height variant has a fixed header and the table body can be scrolled vertically independent of the page itself. The table body will take up the remaining height of the viewport. + * In a regular variant, the table body will scroll with the page and the header is sticky. * * @param className A class name to apply to the element + * @param variant The variant of the table ("full-height" or "regular"). * @param children The markup of the table itself, composed of and DynamicTable.Body * @returns */ export const DynamicTable = ({ className, children, + variant, ...props }: DynamicTableProps) => { return ( -
- {children} -
+ + + {children} +
+
); }; @@ -77,15 +93,21 @@ const DynamicTableLoading = ({ ); }; -/** - * sets a fixed height for the table body - * allowing it to be scrolled independently of the page - */ + +interface DynamicTableBodyProps extends AriaAttributes { + className?: string; + children: React.ReactNode; + height?: string; + style?: React.CSSProperties; +} + const DynamicTableBody = ({ className, children, + style, ...props -}: PropsWithChildren<{ className?: string } & AriaAttributes>) => { +}: DynamicTableBodyProps) => { + const { variant } = useContext(DynamicTableContext); const tableBodyRef: RefObject = useRef(null); const [offset, setOffset] = useState(null); @@ -107,23 +129,28 @@ const DynamicTableBody = ({ return () => window.removeEventListener("resize", handleResize); }, [handleResize]); + const dynamicStyle = useMemo(() => { + if (variant === "full-height" && offset) { + return { + height: `calc(100vh - ${offset}px)`, + minHeight: `calc(100vh - ${offset}px)`, + ...style, + }; + } + return style; + }, [variant, offset, style]); + return ( {children} ); }; + DynamicTable.Body = DynamicTableBody; DynamicTable.Loading = DynamicTableLoading; diff --git a/src/lib/components/TableCaption/TableCaption.stories.tsx b/src/lib/components/TableCaption/TableCaption.stories.tsx index 9646f4b0..97a88838 100644 --- a/src/lib/components/TableCaption/TableCaption.stories.tsx +++ b/src/lib/components/TableCaption/TableCaption.stories.tsx @@ -24,7 +24,7 @@ export const Example: StoryObj = { ), }, render: (args) => ( - + FQDN