@databiosphere/findable-ui 38.1.0 → 38.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +19 -0
  3. package/lib/components/DataDictionary/components/Description/description.d.ts +2 -0
  4. package/lib/components/DataDictionary/components/Description/description.js +8 -0
  5. package/lib/components/DataDictionary/components/Description/description.styles.d.ts +10 -0
  6. package/lib/components/DataDictionary/components/Description/description.styles.js +51 -0
  7. package/lib/components/DataDictionary/components/Description/types.d.ts +3 -0
  8. package/lib/components/DataDictionary/components/Description/types.js +1 -0
  9. package/lib/components/DataDictionary/components/Layout/components/EntitiesLayout/entitiesLayout.styles.js +2 -0
  10. package/lib/components/DataDictionary/dataDictionary.js +3 -1
  11. package/lib/components/DataDictionary/hooks/UseDataDictionaryConfig/hook.js +1 -0
  12. package/lib/components/DataDictionary/hooks/UseDataDictionaryConfig/types.d.ts +1 -0
  13. package/lib/components/Filter/components/FilterRange/filterRange.styles.js +1 -0
  14. package/lib/components/Table/components/TableBody/tableBody.d.ts +3 -3
  15. package/lib/components/Table/components/TableBody/tableBody.js +2 -12
  16. package/lib/components/Table/hooks/UseVirtualization/hook.d.ts +7 -0
  17. package/lib/components/Table/hooks/UseVirtualization/hook.js +18 -0
  18. package/lib/components/Table/hooks/UseVirtualization/types.d.ts +8 -0
  19. package/lib/components/Table/hooks/UseVirtualization/types.js +1 -0
  20. package/lib/components/Table/{components/TableBody → hooks/UseVirtualization}/utils.d.ts +1 -3
  21. package/lib/components/Table/{components/TableBody → hooks/UseVirtualization}/utils.js +8 -4
  22. package/lib/components/Table/table.js +13 -14
  23. package/package.json +1 -1
  24. package/src/components/DataDictionary/components/Description/description.styles.ts +56 -0
  25. package/src/components/DataDictionary/components/Description/description.tsx +17 -0
  26. package/src/components/DataDictionary/components/Description/types.ts +3 -0
  27. package/src/components/DataDictionary/components/Layout/components/EntitiesLayout/entitiesLayout.styles.ts +2 -0
  28. package/src/components/DataDictionary/dataDictionary.tsx +3 -1
  29. package/src/components/DataDictionary/hooks/UseDataDictionaryConfig/hook.ts +1 -0
  30. package/src/components/DataDictionary/hooks/UseDataDictionaryConfig/types.ts +1 -0
  31. package/src/components/Filter/components/FilterRange/filterRange.styles.ts +1 -0
  32. package/src/components/Table/components/TableBody/tableBody.tsx +6 -19
  33. package/src/components/Table/hooks/UseVirtualization/hook.ts +31 -0
  34. package/src/components/Table/hooks/UseVirtualization/types.ts +9 -0
  35. package/src/components/Table/{components/TableBody → hooks/UseVirtualization}/utils.ts +11 -5
  36. package/src/components/Table/table.tsx +12 -14
  37. package/lib/hooks/useScroll.d.ts +0 -10
  38. package/lib/hooks/useScroll.js +0 -12
  39. package/src/hooks/useScroll.ts +0 -21
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "38.1.0"
2
+ ".": "38.2.0"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [38.2.0](https://github.com/DataBiosphere/findable-ui/compare/v38.1.1...v38.2.0) (2025-07-11)
4
+
5
+
6
+ ### Features
7
+
8
+ * add 'introduction' section to data dictionary ([#566](https://github.com/DataBiosphere/findable-ui/issues/566)) ([#567](https://github.com/DataBiosphere/findable-ui/issues/567)) ([5aeb758](https://github.com/DataBiosphere/findable-ui/commit/5aeb758792532a78fa4ec71dc0f7b3ad8c80c376))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * align range filter toggle button styles with design ([#563](https://github.com/DataBiosphere/findable-ui/issues/563)) ([#564](https://github.com/DataBiosphere/findable-ui/issues/564)) ([1cc1ffd](https://github.com/DataBiosphere/findable-ui/commit/1cc1ffd88ae3b2f436717b494e425614412cface))
14
+
15
+ ## [38.1.1](https://github.com/DataBiosphere/findable-ui/compare/v38.1.0...v38.1.1) (2025-07-09)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * table view fails to render after switching from graph view ([#560](https://github.com/DataBiosphere/findable-ui/issues/560)) ([#561](https://github.com/DataBiosphere/findable-ui/issues/561)) ([35a2f0c](https://github.com/DataBiosphere/findable-ui/commit/35a2f0c84119f66c372750442c8b29ca93af9057))
21
+
3
22
  ## [38.1.0](https://github.com/DataBiosphere/findable-ui/compare/v38.0.0...v38.1.0) (2025-07-09)
4
23
 
5
24
 
@@ -0,0 +1,2 @@
1
+ import { DescriptionProps } from "./types";
2
+ export declare const Description: ({ description, }: DescriptionProps) => JSX.Element | null;
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ import { StyledMarkdownRenderer, StyledRoundedPaper, } from "./description.styles";
3
+ export const Description = ({ description, }) => {
4
+ if (!description)
5
+ return null;
6
+ return (React.createElement(StyledRoundedPaper, { elevation: 0 },
7
+ React.createElement(StyledMarkdownRenderer, { value: description })));
8
+ };
@@ -0,0 +1,10 @@
1
+ export declare const StyledRoundedPaper: import("@emotion/styled").StyledComponent<import("../../../types").BaseComponentProps & import("@mui/material").PaperOwnProps & import("@mui/material/OverridableComponent").CommonProps & Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
2
+ ref?: ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLDivElement> | null | undefined;
3
+ }, "style" | "className" | "classes" | "children" | "sx" | "elevation" | "square" | "variant"> & {
4
+ component?: React.ElementType;
5
+ } & {
6
+ theme?: import("@emotion/react").Theme;
7
+ }, {}, {}>;
8
+ export declare const StyledMarkdownRenderer: import("@emotion/styled").StyledComponent<import("../../../MarkdownRenderer/types").MarkdownRendererProps & {
9
+ theme?: import("@emotion/react").Theme;
10
+ }, {}, {}>;
@@ -0,0 +1,51 @@
1
+ import styled from "@emotion/styled";
2
+ import { PALETTE } from "../../../../styles/common/constants/palette";
3
+ import { mediaTabletDown, mediaTabletUp, } from "../../../../styles/common/mixins/breakpoints";
4
+ import { textHeadingSmall } from "../../../../styles/common/mixins/fonts";
5
+ import { RoundedPaper } from "../../../common/Paper/components/RoundedPaper/roundedPaper";
6
+ import { MarkdownRenderer } from "../../../MarkdownRenderer/markdownRenderer";
7
+ export const StyledRoundedPaper = styled(RoundedPaper) `
8
+ padding: 20px;
9
+
10
+ ${mediaTabletDown} {
11
+ padding: 20px 16px;
12
+ }
13
+ `;
14
+ export const StyledMarkdownRenderer = styled(MarkdownRenderer) `
15
+ align-self: flex-start;
16
+
17
+ code {
18
+ all: unset;
19
+ font: inherit;
20
+ font-family: Roboto Mono, monospace;
21
+ }
22
+
23
+ h2,
24
+ h3,
25
+ h4,
26
+ h5,
27
+ h6 {
28
+ margin: 8px 0;
29
+ }
30
+
31
+ h2 {
32
+ ${textHeadingSmall};
33
+ font-size: 18px;
34
+ line-height: 26px;
35
+
36
+ ${mediaTabletUp} {
37
+ font-size: 18px;
38
+ line-height: 26px;
39
+ }
40
+ }
41
+
42
+ hr {
43
+ border: none;
44
+ border-bottom: 1px solid ${PALETTE.SMOKE_MAIN};
45
+ margin: 16px 0;
46
+ }
47
+
48
+ p {
49
+ font: inherit;
50
+ }
51
+ `;
@@ -0,0 +1,3 @@
1
+ export interface DescriptionProps {
2
+ description?: string;
3
+ }
@@ -4,6 +4,8 @@ import { LAYOUT_SPACING } from "../../constants";
4
4
  const PB = LAYOUT_SPACING.CONTENT_PADDING_BOTTOM; /* bottom padding */
5
5
  const PT = LAYOUT_SPACING.CONTENT_PADDING_TOP; /* top padding */
6
6
  export const Layout = styled("div") `
7
+ display: grid;
8
+ gap: 16px;
7
9
  grid-column: 2;
8
10
  grid-row: 1;
9
11
  padding-bottom: ${PB}px;
@@ -1,6 +1,7 @@
1
1
  import { Fade } from "@mui/material";
2
2
  import React from "react";
3
3
  import { useLayoutSpacing } from "../../hooks/UseLayoutSpacing/hook";
4
+ import { Description } from "./components/Description/description";
4
5
  import { Entities } from "./components/Entities/entities";
5
6
  import { ColumnFilterTags } from "./components/Filters/components/ColumnFilterTags/columnFilterTags";
6
7
  import { Filters } from "./components/Filters/filters";
@@ -17,7 +18,7 @@ import { useDataDictionaryConfig } from "./hooks/UseDataDictionaryConfig/hook";
17
18
  import { useMeasureFilters } from "./hooks/UseMeasureFilters/hook";
18
19
  export const DataDictionary = ({ className, dictionary, EntitiesLayout = DefaultEntitiesLayout, FiltersLayout = DefaultFiltersLayout, Outline = DefaultOutline, OutlineLayout = DefaultOutlineLayout, Title = DefaultTitle, TitleLayout = DefaultTitleLayout, }) => {
19
20
  // Get dictionary configuration.
20
- const { classes, tableOptions, title } = useDataDictionaryConfig(dictionary);
21
+ const { classes, description, tableOptions, title } = useDataDictionaryConfig(dictionary);
21
22
  // Layout measurements.
22
23
  // Get header and footer dimensions.
23
24
  const { spacing } = useLayoutSpacing();
@@ -40,5 +41,6 @@ export const DataDictionary = ({ className, dictionary, EntitiesLayout = Default
40
41
  React.createElement(ColumnFilterTags, { table: table })),
41
42
  React.createElement(Fade, { in: dimensions.height > 0 },
42
43
  React.createElement(EntitiesLayout, { spacing: entitiesSpacing },
44
+ React.createElement(Description, { description: description }),
43
45
  React.createElement(Entities, { spacing: entitiesSpacing, table: table }))))));
44
46
  };
@@ -20,6 +20,7 @@ export const useDataDictionaryConfig = (dictionary) => {
20
20
  // exists above and would have thrown an error if undefined.
21
21
  return {
22
22
  classes: dataDictionaryConfig.dataDictionary.classes,
23
+ description: dataDictionaryConfig.dataDictionary.description,
23
24
  tableOptions: dataDictionaryConfig.tableOptions,
24
25
  title: dataDictionaryConfig.dataDictionary.title,
25
26
  };
@@ -2,6 +2,7 @@ import { RowData, TableOptions } from "@tanstack/react-table";
2
2
  import { Attribute, Class } from "../../../../common/entities";
3
3
  export interface UseDataDictionaryConfig<T extends RowData = Attribute> {
4
4
  classes: Class<T>[];
5
+ description?: string;
5
6
  tableOptions: Omit<TableOptions<T>, "data" | "getCoreRowModel">;
6
7
  title: string;
7
8
  }
@@ -12,6 +12,7 @@ export const StyledForm = styled("form") `
12
12
 
13
13
  .MuiToggleButton-root {
14
14
  color: ${PALETTE.INK_LIGHT};
15
+ padding: 8px 12px;
15
16
  text-transform: capitalize;
16
17
 
17
18
  &.Mui-selected {
@@ -1,10 +1,10 @@
1
1
  import { Row, RowData, Table } from "@tanstack/react-table";
2
- import { RefObject } from "react";
2
+ import { Virtualizer } from "@tanstack/react-virtual";
3
3
  import { ROW_DIRECTION } from "../../common/entities";
4
4
  export interface TableBodyProps<T extends RowData> {
5
5
  rowDirection: ROW_DIRECTION;
6
6
  rows: Row<T>[];
7
- tableContainerRef: RefObject<HTMLDivElement>;
8
7
  tableInstance: Table<T>;
8
+ virtualizer: Virtualizer<HTMLDivElement, Element>;
9
9
  }
10
- export declare const TableBody: <T extends RowData>({ rowDirection, rows, tableContainerRef, tableInstance, }: TableBodyProps<T>) => JSX.Element;
10
+ export declare const TableBody: <T extends RowData>({ rowDirection, rows, tableInstance, virtualizer, }: TableBodyProps<T>) => JSX.Element;
@@ -1,22 +1,12 @@
1
1
  import { TableBody as MTableBody } from "@mui/material";
2
- import { useVirtualizer } from "@tanstack/react-virtual";
3
2
  import React from "react";
4
3
  import { ROW_DIRECTION } from "../../common/entities";
5
4
  import { CollapsableRows } from "../TableRows/components/CollapsableRows/collapsableRows";
6
5
  import { VirtualizedRow } from "../TableRows/components/VirtualizedRow/virtualizedRow";
7
6
  import { TableRows } from "../TableRows/tableRows";
8
- import { getAllVirtualizedRows } from "./utils";
9
- export const TableBody = ({ rowDirection, rows, tableContainerRef, tableInstance, }) => {
10
- const virtualizedRows = getAllVirtualizedRows(tableInstance, rows, rowDirection);
11
- const virtualizer = useVirtualizer({
12
- count: virtualizedRows.length,
13
- estimateSize: () => 56,
14
- gap: 1,
15
- getScrollElement: () => tableContainerRef.current,
16
- overscan: 20,
17
- });
7
+ export const TableBody = ({ rowDirection, rows, tableInstance, virtualizer, }) => {
18
8
  return (React.createElement(MTableBody, null,
19
9
  React.createElement(VirtualizedRow, { isUpperRow: true, virtualizer: virtualizer }),
20
- rowDirection === ROW_DIRECTION.DEFAULT ? (React.createElement(TableRows, { rows: virtualizedRows, virtualizer: virtualizer })) : (React.createElement(CollapsableRows, { rows: virtualizedRows, tableInstance: tableInstance, virtualizer: virtualizer })),
10
+ rowDirection === ROW_DIRECTION.DEFAULT ? (React.createElement(TableRows, { rows: rows, virtualizer: virtualizer })) : (React.createElement(CollapsableRows, { rows: rows, tableInstance: tableInstance, virtualizer: virtualizer })),
21
11
  React.createElement(VirtualizedRow, { isUpperRow: false, virtualizer: virtualizer })));
22
12
  };
@@ -0,0 +1,7 @@
1
+ import { RowData, Table } from "@tanstack/react-table";
2
+ import { ROW_DIRECTION } from "../../common/entities";
3
+ import { UseVirtualizationProps } from "./types";
4
+ export declare const useVirtualization: <T extends RowData>({ rowDirection, table, }: {
5
+ rowDirection: ROW_DIRECTION;
6
+ table: Table<T>;
7
+ }) => UseVirtualizationProps<T>;
@@ -0,0 +1,18 @@
1
+ import { useVirtualizer } from "@tanstack/react-virtual";
2
+ import { useRef } from "react";
3
+ import { getRowsForVirtualization } from "./utils";
4
+ export const useVirtualization = ({ rowDirection, table, }) => {
5
+ // Ref for the scrollable container.
6
+ const scrollElementRef = useRef(null);
7
+ // Derive the list of rows eligible for virtualization based on grouping and row direction.
8
+ const rows = getRowsForVirtualization(table, rowDirection);
9
+ // Build virtualizer instance.
10
+ const virtualizer = useVirtualizer({
11
+ count: rows.length,
12
+ estimateSize: () => 56,
13
+ gap: 1,
14
+ getScrollElement: () => scrollElementRef.current,
15
+ overscan: 20,
16
+ });
17
+ return { rows, scrollElementRef, virtualizer };
18
+ };
@@ -0,0 +1,8 @@
1
+ import { Row, RowData } from "@tanstack/react-table";
2
+ import { Virtualizer } from "@tanstack/react-virtual";
3
+ import { RefObject } from "react";
4
+ export interface UseVirtualizationProps<T extends RowData> {
5
+ rows: Row<T>[];
6
+ scrollElementRef: RefObject<HTMLDivElement>;
7
+ virtualizer: Virtualizer<HTMLDivElement, Element>;
8
+ }
@@ -3,10 +3,8 @@ import { ROW_DIRECTION } from "../../common/entities";
3
3
  /**
4
4
  * Filters and returns the appropriate rows for a virtualized table based on row direction
5
5
  * and grouping state.
6
- * Rows are filtered if `ROW_DIRECTION` is `VERTICAL` and the table is grouped.
7
6
  * @param table - Table.
8
- * @param rows - Rows.
9
7
  * @param rowDirection - Row direction.
10
8
  * @returns Rows based on the provided row direction and table grouping state.
11
9
  */
12
- export declare function getAllVirtualizedRows<T extends RowData>(table: Table<T>, rows: Row<T>[], rowDirection: ROW_DIRECTION): Row<T>[];
10
+ export declare function getRowsForVirtualization<T extends RowData>(table: Table<T>, rowDirection: ROW_DIRECTION): Row<T>[];
@@ -2,16 +2,20 @@ import { ROW_DIRECTION } from "../../common/entities";
2
2
  /**
3
3
  * Filters and returns the appropriate rows for a virtualized table based on row direction
4
4
  * and grouping state.
5
- * Rows are filtered if `ROW_DIRECTION` is `VERTICAL` and the table is grouped.
6
5
  * @param table - Table.
7
- * @param rows - Rows.
8
6
  * @param rowDirection - Row direction.
9
7
  * @returns Rows based on the provided row direction and table grouping state.
10
8
  */
11
- export function getAllVirtualizedRows(table, rows, rowDirection) {
9
+ export function getRowsForVirtualization(table, rowDirection) {
10
+ const { getRowModel, getState } = table;
11
+ const { rows } = getRowModel();
12
+ const { grouping } = getState();
13
+ // If the row direction is DEFAULT, return all rows.
12
14
  if (rowDirection === ROW_DIRECTION.DEFAULT)
13
15
  return rows;
14
- if (table.getState().grouping.length === 0)
16
+ // If the table is not grouped, return all rows.
17
+ if (grouping.length === 0)
15
18
  return rows;
19
+ // If the row direction is VERTICAL, return only grouped rows.
16
20
  return rows.filter(({ getIsGrouped }) => getIsGrouped());
17
21
  }
@@ -1,11 +1,10 @@
1
1
  import { TableContainer } from "@mui/material";
2
- import React, { Fragment, useRef } from "react";
2
+ import React, { Fragment, useCallback } from "react";
3
3
  import { track } from "../../common/analytics/analytics";
4
4
  import { EVENT_NAME, EVENT_PARAM, PAGINATION_DIRECTION, } from "../../common/analytics/entities";
5
5
  import { BREAKPOINT_FN_NAME, useBreakpointHelper, } from "../../hooks/useBreakpointHelper";
6
6
  import { useExploreMode } from "../../hooks/useExploreMode/useExploreMode";
7
7
  import { useExploreState } from "../../hooks/useExploreState";
8
- import { useScroll } from "../../hooks/useScroll";
9
8
  import { ExploreActionKind } from "../../providers/exploreState";
10
9
  import { TABLET } from "../../theme/common/breakpoints";
11
10
  import { Loading, LOADING_PANEL_STYLE } from "../Loading/loading";
@@ -17,9 +16,9 @@ import { TableBody } from "./components/TableBody/tableBody";
17
16
  import { TableHead } from "./components/TableHead/tableHead";
18
17
  import { TablePagination } from "./components/TablePagination/tablePagination";
19
18
  import { TableToolbar } from "./components/TableToolbar/tableToolbar";
19
+ import { useVirtualization } from "./hooks/UseVirtualization/hook";
20
20
  import { GridTable } from "./table.styles";
21
21
  export const Table = ({ listView, loading, table, }) => {
22
- const tableContainerRef = useRef(null);
23
22
  const tabletDown = useBreakpointHelper(BREAKPOINT_FN_NAME.DOWN, TABLET);
24
23
  const exploreMode = useExploreMode();
25
24
  const { exploreDispatch, exploreState } = useExploreState();
@@ -30,11 +29,13 @@ export const Table = ({ listView, loading, table, }) => {
30
29
  const rowDirection = tabletDown
31
30
  ? ROW_DIRECTION.VERTICAL
32
31
  : ROW_DIRECTION.DEFAULT;
33
- const { getRowModel, getVisibleFlatColumns, nextPage: tableNextPage, previousPage: tablePreviousPage, } = table;
34
- const { rows } = getRowModel();
32
+ const { rows, scrollElementRef, virtualizer } = useVirtualization({
33
+ rowDirection,
34
+ table,
35
+ });
36
+ const { getVisibleFlatColumns, nextPage: tableNextPage, previousPage: tablePreviousPage, } = table;
35
37
  const noResults = !loading && (!rows || rows.length === 0);
36
- const scrollTop = useScroll();
37
- const handleTableNextPage = () => {
38
+ const handleTableNextPage = useCallback(() => {
38
39
  let nextPage = tableNextPage;
39
40
  if (!clientFiltering) {
40
41
  nextPage = () => {
@@ -50,9 +51,8 @@ export const Table = ({ listView, loading, table, }) => {
50
51
  });
51
52
  }
52
53
  nextPage();
53
- scrollTop();
54
- };
55
- const handleTablePreviousPage = () => {
54
+ }, [clientFiltering, exploreDispatch, exploreState, tableNextPage]);
55
+ const handleTablePreviousPage = useCallback(() => {
56
56
  let previousPage = tablePreviousPage;
57
57
  if (!clientFiltering) {
58
58
  previousPage = () => {
@@ -67,8 +67,7 @@ export const Table = ({ listView, loading, table, }) => {
67
67
  });
68
68
  }
69
69
  previousPage();
70
- scrollTop();
71
- };
70
+ }, [clientFiltering, exploreDispatch, exploreState, tablePreviousPage]);
72
71
  function canNextPage() {
73
72
  return currentPage < pages;
74
73
  }
@@ -78,9 +77,9 @@ export const Table = ({ listView, loading, table, }) => {
78
77
  return noResults ? (React.createElement(NoResults, { Paper: null, title: "No Results found" })) : (React.createElement(Fragment, null,
79
78
  React.createElement(TableToolbar, { listView: listView, tableInstance: table }),
80
79
  React.createElement(Loading, { appear: false, autoPosition: false, loading: loading, panelStyle: LOADING_PANEL_STYLE.INHERIT }),
81
- React.createElement(TableContainer, { ref: tableContainerRef },
80
+ React.createElement(TableContainer, { ref: scrollElementRef },
82
81
  React.createElement(GridTable, { collapsable: true, gridTemplateColumns: getColumnTrackSizing(getVisibleFlatColumns()), stickyHeader: true },
83
82
  React.createElement(TableHead, { tableInstance: table }),
84
- React.createElement(TableBody, { rows: rows, rowDirection: rowDirection, tableContainerRef: tableContainerRef, tableInstance: table }))),
83
+ React.createElement(TableBody, { rows: rows, rowDirection: rowDirection, tableInstance: table, virtualizer: virtualizer }))),
85
84
  !disablePagination && (React.createElement(TablePagination, { canNextPage: canNextPage(), canPreviousPage: canPreviousPage(), currentPage: currentPage, onNextPage: handleTableNextPage, onPreviousPage: handleTablePreviousPage, totalPage: pages ?? 0 }))));
86
85
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@databiosphere/findable-ui",
3
- "version": "38.1.0",
3
+ "version": "38.2.0",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
@@ -0,0 +1,56 @@
1
+ import styled from "@emotion/styled";
2
+ import { PALETTE } from "../../../../styles/common/constants/palette";
3
+ import {
4
+ mediaTabletDown,
5
+ mediaTabletUp,
6
+ } from "../../../../styles/common/mixins/breakpoints";
7
+ import { textHeadingSmall } from "../../../../styles/common/mixins/fonts";
8
+ import { RoundedPaper } from "../../../common/Paper/components/RoundedPaper/roundedPaper";
9
+ import { MarkdownRenderer } from "../../../MarkdownRenderer/markdownRenderer";
10
+
11
+ export const StyledRoundedPaper = styled(RoundedPaper)`
12
+ padding: 20px;
13
+
14
+ ${mediaTabletDown} {
15
+ padding: 20px 16px;
16
+ }
17
+ `;
18
+
19
+ export const StyledMarkdownRenderer = styled(MarkdownRenderer)`
20
+ align-self: flex-start;
21
+
22
+ code {
23
+ all: unset;
24
+ font: inherit;
25
+ font-family: Roboto Mono, monospace;
26
+ }
27
+
28
+ h2,
29
+ h3,
30
+ h4,
31
+ h5,
32
+ h6 {
33
+ margin: 8px 0;
34
+ }
35
+
36
+ h2 {
37
+ ${textHeadingSmall};
38
+ font-size: 18px;
39
+ line-height: 26px;
40
+
41
+ ${mediaTabletUp} {
42
+ font-size: 18px;
43
+ line-height: 26px;
44
+ }
45
+ }
46
+
47
+ hr {
48
+ border: none;
49
+ border-bottom: 1px solid ${PALETTE.SMOKE_MAIN};
50
+ margin: 16px 0;
51
+ }
52
+
53
+ p {
54
+ font: inherit;
55
+ }
56
+ `;
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ import {
3
+ StyledMarkdownRenderer,
4
+ StyledRoundedPaper,
5
+ } from "./description.styles";
6
+ import { DescriptionProps } from "./types";
7
+
8
+ export const Description = ({
9
+ description,
10
+ }: DescriptionProps): JSX.Element | null => {
11
+ if (!description) return null;
12
+ return (
13
+ <StyledRoundedPaper elevation={0}>
14
+ <StyledMarkdownRenderer value={description} />
15
+ </StyledRoundedPaper>
16
+ );
17
+ };
@@ -0,0 +1,3 @@
1
+ export interface DescriptionProps {
2
+ description?: string;
3
+ }
@@ -7,6 +7,8 @@ const PB = LAYOUT_SPACING.CONTENT_PADDING_BOTTOM; /* bottom padding */
7
7
  const PT = LAYOUT_SPACING.CONTENT_PADDING_TOP; /* top padding */
8
8
 
9
9
  export const Layout = styled("div")<LayoutSpacing>`
10
+ display: grid;
11
+ gap: 16px;
10
12
  grid-column: 2;
11
13
  grid-row: 1;
12
14
  padding-bottom: ${PB}px;
@@ -3,6 +3,7 @@ import { RowData } from "@tanstack/react-table";
3
3
  import React from "react";
4
4
  import { Attribute } from "../../common/entities";
5
5
  import { useLayoutSpacing } from "../../hooks/UseLayoutSpacing/hook";
6
+ import { Description } from "./components/Description/description";
6
7
  import { Entities } from "./components/Entities/entities";
7
8
  import { ColumnFilterTags } from "./components/Filters/components/ColumnFilterTags/columnFilterTags";
8
9
  import { Filters } from "./components/Filters/filters";
@@ -30,7 +31,7 @@ export const DataDictionary = <T extends RowData = Attribute>({
30
31
  TitleLayout = DefaultTitleLayout,
31
32
  }: DataDictionaryProps): JSX.Element => {
32
33
  // Get dictionary configuration.
33
- const { classes, tableOptions, title } =
34
+ const { classes, description, tableOptions, title } =
34
35
  useDataDictionaryConfig<T>(dictionary);
35
36
 
36
37
  // Layout measurements.
@@ -64,6 +65,7 @@ export const DataDictionary = <T extends RowData = Attribute>({
64
65
  <Fade in={dimensions.height > 0}>
65
66
  {/* Fade in entities when filters are measured. */}
66
67
  <EntitiesLayout spacing={entitiesSpacing}>
68
+ <Description description={description} />
67
69
  <Entities spacing={entitiesSpacing} table={table} />
68
70
  </EntitiesLayout>
69
71
  </Fade>
@@ -31,6 +31,7 @@ export const useDataDictionaryConfig = <T extends RowData = Attribute>(
31
31
  // exists above and would have thrown an error if undefined.
32
32
  return {
33
33
  classes: dataDictionaryConfig!.dataDictionary.classes,
34
+ description: dataDictionaryConfig!.dataDictionary.description,
34
35
  tableOptions: dataDictionaryConfig!.tableOptions,
35
36
  title: dataDictionaryConfig!.dataDictionary.title,
36
37
  };
@@ -3,6 +3,7 @@ import { Attribute, Class } from "../../../../common/entities";
3
3
 
4
4
  export interface UseDataDictionaryConfig<T extends RowData = Attribute> {
5
5
  classes: Class<T>[];
6
+ description?: string;
6
7
  tableOptions: Omit<TableOptions<T>, "data" | "getCoreRowModel">;
7
8
  title: string;
8
9
  }
@@ -13,6 +13,7 @@ export const StyledForm = styled("form")`
13
13
 
14
14
  .MuiToggleButton-root {
15
15
  color: ${PALETTE.INK_LIGHT};
16
+ padding: 8px 12px;
16
17
  text-transform: capitalize;
17
18
 
18
19
  &.Mui-selected {
@@ -1,46 +1,33 @@
1
1
  import { TableBody as MTableBody } from "@mui/material";
2
2
  import { Row, RowData, Table } from "@tanstack/react-table";
3
- import { useVirtualizer } from "@tanstack/react-virtual";
4
- import React, { RefObject } from "react";
3
+ import { Virtualizer } from "@tanstack/react-virtual";
4
+ import React from "react";
5
5
  import { ROW_DIRECTION } from "../../common/entities";
6
6
  import { CollapsableRows } from "../TableRows/components/CollapsableRows/collapsableRows";
7
7
  import { VirtualizedRow } from "../TableRows/components/VirtualizedRow/virtualizedRow";
8
8
  import { TableRows } from "../TableRows/tableRows";
9
- import { getAllVirtualizedRows } from "./utils";
10
9
 
11
10
  export interface TableBodyProps<T extends RowData> {
12
11
  rowDirection: ROW_DIRECTION;
13
12
  rows: Row<T>[];
14
- tableContainerRef: RefObject<HTMLDivElement>;
15
13
  tableInstance: Table<T>;
14
+ virtualizer: Virtualizer<HTMLDivElement, Element>;
16
15
  }
17
16
 
18
17
  export const TableBody = <T extends RowData>({
19
18
  rowDirection,
20
19
  rows,
21
- tableContainerRef,
22
20
  tableInstance,
21
+ virtualizer,
23
22
  }: TableBodyProps<T>): JSX.Element => {
24
- const virtualizedRows = getAllVirtualizedRows(
25
- tableInstance,
26
- rows,
27
- rowDirection
28
- );
29
- const virtualizer = useVirtualizer({
30
- count: virtualizedRows.length,
31
- estimateSize: () => 56,
32
- gap: 1,
33
- getScrollElement: () => tableContainerRef.current,
34
- overscan: 20,
35
- });
36
23
  return (
37
24
  <MTableBody>
38
25
  <VirtualizedRow isUpperRow={true} virtualizer={virtualizer} />
39
26
  {rowDirection === ROW_DIRECTION.DEFAULT ? (
40
- <TableRows rows={virtualizedRows} virtualizer={virtualizer} />
27
+ <TableRows rows={rows} virtualizer={virtualizer} />
41
28
  ) : (
42
29
  <CollapsableRows
43
- rows={virtualizedRows}
30
+ rows={rows}
44
31
  tableInstance={tableInstance}
45
32
  virtualizer={virtualizer}
46
33
  />
@@ -0,0 +1,31 @@
1
+ import { RowData, Table } from "@tanstack/react-table";
2
+ import { useVirtualizer } from "@tanstack/react-virtual";
3
+ import { useRef } from "react";
4
+ import { ROW_DIRECTION } from "../../common/entities";
5
+ import { UseVirtualizationProps } from "./types";
6
+ import { getRowsForVirtualization } from "./utils";
7
+
8
+ export const useVirtualization = <T extends RowData>({
9
+ rowDirection,
10
+ table,
11
+ }: {
12
+ rowDirection: ROW_DIRECTION;
13
+ table: Table<T>;
14
+ }): UseVirtualizationProps<T> => {
15
+ // Ref for the scrollable container.
16
+ const scrollElementRef = useRef<HTMLDivElement>(null);
17
+
18
+ // Derive the list of rows eligible for virtualization based on grouping and row direction.
19
+ const rows = getRowsForVirtualization(table, rowDirection);
20
+
21
+ // Build virtualizer instance.
22
+ const virtualizer = useVirtualizer({
23
+ count: rows.length,
24
+ estimateSize: () => 56,
25
+ gap: 1,
26
+ getScrollElement: () => scrollElementRef.current,
27
+ overscan: 20,
28
+ });
29
+
30
+ return { rows, scrollElementRef, virtualizer };
31
+ };
@@ -0,0 +1,9 @@
1
+ import { Row, RowData } from "@tanstack/react-table";
2
+ import { Virtualizer } from "@tanstack/react-virtual";
3
+ import { RefObject } from "react";
4
+
5
+ export interface UseVirtualizationProps<T extends RowData> {
6
+ rows: Row<T>[];
7
+ scrollElementRef: RefObject<HTMLDivElement>;
8
+ virtualizer: Virtualizer<HTMLDivElement, Element>;
9
+ }
@@ -4,18 +4,24 @@ import { ROW_DIRECTION } from "../../common/entities";
4
4
  /**
5
5
  * Filters and returns the appropriate rows for a virtualized table based on row direction
6
6
  * and grouping state.
7
- * Rows are filtered if `ROW_DIRECTION` is `VERTICAL` and the table is grouped.
8
7
  * @param table - Table.
9
- * @param rows - Rows.
10
8
  * @param rowDirection - Row direction.
11
9
  * @returns Rows based on the provided row direction and table grouping state.
12
10
  */
13
- export function getAllVirtualizedRows<T extends RowData>(
11
+ export function getRowsForVirtualization<T extends RowData>(
14
12
  table: Table<T>,
15
- rows: Row<T>[],
16
13
  rowDirection: ROW_DIRECTION
17
14
  ): Row<T>[] {
15
+ const { getRowModel, getState } = table;
16
+ const { rows } = getRowModel();
17
+ const { grouping } = getState();
18
+
19
+ // If the row direction is DEFAULT, return all rows.
18
20
  if (rowDirection === ROW_DIRECTION.DEFAULT) return rows;
19
- if (table.getState().grouping.length === 0) return rows;
21
+
22
+ // If the table is not grouped, return all rows.
23
+ if (grouping.length === 0) return rows;
24
+
25
+ // If the row direction is VERTICAL, return only grouped rows.
20
26
  return rows.filter(({ getIsGrouped }) => getIsGrouped());
21
27
  }
@@ -1,6 +1,6 @@
1
1
  import { TableContainer } from "@mui/material";
2
2
  import { RowData, Table as TanStackTable } from "@tanstack/react-table";
3
- import React, { Fragment, useRef } from "react";
3
+ import React, { Fragment, useCallback } from "react";
4
4
  import { track } from "../../common/analytics/analytics";
5
5
  import {
6
6
  EVENT_NAME,
@@ -14,7 +14,6 @@ import {
14
14
  } from "../../hooks/useBreakpointHelper";
15
15
  import { useExploreMode } from "../../hooks/useExploreMode/useExploreMode";
16
16
  import { useExploreState } from "../../hooks/useExploreState";
17
- import { useScroll } from "../../hooks/useScroll";
18
17
  import { ExploreActionKind } from "../../providers/exploreState";
19
18
  import { TABLET } from "../../theme/common/breakpoints";
20
19
  import { Loading, LOADING_PANEL_STYLE } from "../Loading/loading";
@@ -26,6 +25,7 @@ import { TableBody } from "./components/TableBody/tableBody";
26
25
  import { TableHead } from "./components/TableHead/tableHead";
27
26
  import { TablePagination } from "./components/TablePagination/tablePagination";
28
27
  import { TableToolbar } from "./components/TableToolbar/tableToolbar";
28
+ import { useVirtualization } from "./hooks/UseVirtualization/hook";
29
29
  import { GridTable } from "./table.styles";
30
30
 
31
31
  export interface TableProps<T extends RowData> {
@@ -39,7 +39,6 @@ export const Table = <T extends RowData>({
39
39
  loading,
40
40
  table,
41
41
  }: TableProps<T>): JSX.Element => {
42
- const tableContainerRef = useRef<HTMLDivElement>(null);
43
42
  const tabletDown = useBreakpointHelper(BREAKPOINT_FN_NAME.DOWN, TABLET);
44
43
  const exploreMode = useExploreMode();
45
44
  const { exploreDispatch, exploreState } = useExploreState();
@@ -50,19 +49,20 @@ export const Table = <T extends RowData>({
50
49
  const rowDirection = tabletDown
51
50
  ? ROW_DIRECTION.VERTICAL
52
51
  : ROW_DIRECTION.DEFAULT;
52
+ const { rows, scrollElementRef, virtualizer } = useVirtualization({
53
+ rowDirection,
54
+ table,
55
+ });
53
56
 
54
57
  const {
55
- getRowModel,
56
58
  getVisibleFlatColumns,
57
59
  nextPage: tableNextPage,
58
60
  previousPage: tablePreviousPage,
59
61
  } = table;
60
62
 
61
- const { rows } = getRowModel();
62
63
  const noResults = !loading && (!rows || rows.length === 0);
63
- const scrollTop = useScroll();
64
64
 
65
- const handleTableNextPage = (): void => {
65
+ const handleTableNextPage = useCallback((): void => {
66
66
  let nextPage = tableNextPage;
67
67
  if (!clientFiltering) {
68
68
  nextPage = (): void => {
@@ -78,10 +78,9 @@ export const Table = <T extends RowData>({
78
78
  });
79
79
  }
80
80
  nextPage();
81
- scrollTop();
82
- };
81
+ }, [clientFiltering, exploreDispatch, exploreState, tableNextPage]);
83
82
 
84
- const handleTablePreviousPage = (): void => {
83
+ const handleTablePreviousPage = useCallback((): void => {
85
84
  let previousPage = tablePreviousPage;
86
85
  if (!clientFiltering) {
87
86
  previousPage = (): void => {
@@ -96,8 +95,7 @@ export const Table = <T extends RowData>({
96
95
  });
97
96
  }
98
97
  previousPage();
99
- scrollTop();
100
- };
98
+ }, [clientFiltering, exploreDispatch, exploreState, tablePreviousPage]);
101
99
 
102
100
  function canNextPage(): boolean {
103
101
  return currentPage < pages;
@@ -118,7 +116,7 @@ export const Table = <T extends RowData>({
118
116
  loading={loading}
119
117
  panelStyle={LOADING_PANEL_STYLE.INHERIT}
120
118
  />
121
- <TableContainer ref={tableContainerRef}>
119
+ <TableContainer ref={scrollElementRef}>
122
120
  <GridTable
123
121
  collapsable={true}
124
122
  gridTemplateColumns={getColumnTrackSizing(getVisibleFlatColumns())}
@@ -128,8 +126,8 @@ export const Table = <T extends RowData>({
128
126
  <TableBody
129
127
  rows={rows}
130
128
  rowDirection={rowDirection}
131
- tableContainerRef={tableContainerRef}
132
129
  tableInstance={table}
130
+ virtualizer={virtualizer}
133
131
  />
134
132
  </GridTable>
135
133
  </TableContainer>
@@ -1,10 +0,0 @@
1
- type ScrollType = "top" | "bottom";
2
- type UseScrollReturn = () => void;
3
- /**
4
- * Hook used to scroll the to top or bottom of the page.
5
- * This hook can only be used on the client-side.
6
- * @param scrollType - top or bottom of the page. Default = top
7
- * @returns scroll function
8
- */
9
- export declare const useScroll: (scrollType?: ScrollType) => UseScrollReturn;
10
- export {};
@@ -1,12 +0,0 @@
1
- import { useCallback } from "react";
2
- /**
3
- * Hook used to scroll the to top or bottom of the page.
4
- * This hook can only be used on the client-side.
5
- * @param scrollType - top or bottom of the page. Default = top
6
- * @returns scroll function
7
- */
8
- export const useScroll = (scrollType = "top") => {
9
- return useCallback(() => window.scrollTo({
10
- top: scrollType === "top" ? 0 : document.body.scrollHeight,
11
- }), [scrollType]);
12
- };
@@ -1,21 +0,0 @@
1
- import { useCallback } from "react";
2
-
3
- type ScrollType = "top" | "bottom";
4
-
5
- type UseScrollReturn = () => void;
6
-
7
- /**
8
- * Hook used to scroll the to top or bottom of the page.
9
- * This hook can only be used on the client-side.
10
- * @param scrollType - top or bottom of the page. Default = top
11
- * @returns scroll function
12
- */
13
- export const useScroll = (scrollType: ScrollType = "top"): UseScrollReturn => {
14
- return useCallback(
15
- () =>
16
- window.scrollTo({
17
- top: scrollType === "top" ? 0 : document.body.scrollHeight,
18
- }),
19
- [scrollType]
20
- );
21
- };