diff --git a/packages/canary-docs/docs.json b/packages/canary-docs/docs.json index e622244dfd..a97ab73423 100644 --- a/packages/canary-docs/docs.json +++ b/packages/canary-docs/docs.json @@ -705,10 +705,10 @@ }, { "name": "loadingOptions", - "type": "{ description?: string; label?: string; labelDuration?: number; max?: number; min?: number; progress?: number; showBackground?: boolean; monochrome?: boolean; }", + "type": "{ description?: string; label?: string; labelDuration?: number; max?: number; min?: number; progress?: number; showBackground?: boolean; monochrome?: boolean; overlay?: boolean; }", "complexType": { - "original": "{\n description?: string;\n label?: string;\n labelDuration?: number;\n max?: number;\n min?: number;\n progress?: number;\n showBackground?: boolean;\n monochrome?: boolean;\n }", - "resolved": "{ description?: string; label?: string; labelDuration?: number; max?: number; min?: number; progress?: number; showBackground?: boolean; monochrome?: boolean; }", + "original": "{\n description?: string;\n label?: string;\n labelDuration?: number;\n max?: number;\n min?: number;\n progress?: number;\n showBackground?: boolean;\n monochrome?: boolean;\n overlay?: boolean;\n }", + "resolved": "{ description?: string; label?: string; labelDuration?: number; max?: number; min?: number; progress?: number; showBackground?: boolean; monochrome?: boolean; overlay?: boolean; }", "references": {} }, "mutable": false, @@ -717,7 +717,7 @@ "docsTags": [], "values": [ { - "type": "{ description?: string; label?: string; labelDuration?: number; max?: number; min?: number; progress?: number; showBackground?: boolean; monochrome?: boolean; }" + "type": "{ description?: string; label?: string; labelDuration?: number; max?: number; min?: number; progress?: number; showBackground?: boolean; monochrome?: boolean; overlay?: boolean; }" } ], "optional": true, diff --git a/packages/canary-react/src/component-tests/IcDataTable/IcDataTable.cy.tsx b/packages/canary-react/src/component-tests/IcDataTable/IcDataTable.cy.tsx index ce235bdd1c..8b99c03042 100644 --- a/packages/canary-react/src/component-tests/IcDataTable/IcDataTable.cy.tsx +++ b/packages/canary-react/src/component-tests/IcDataTable/IcDataTable.cy.tsx @@ -1177,6 +1177,107 @@ describe("IcDataTables", () => { }, }); }); + + it("should render a backdrop with circular loading indicator when loadingOption.overlay is set to true", () => { + mount( + + ); + cy.checkHydrated(DATA_TABLE_SELECTOR); + + cy.get(DATA_TABLE_SELECTOR).invoke("prop", "loading", true); + + cy.findShadowEl(DATA_TABLE_SELECTOR, ".loading-overlay").should( + "be.visible" + ); + cy.findShadowEl(DATA_TABLE_SELECTOR, "tbody").should("be.visible"); + cy.findShadowEl(DATA_TABLE_SELECTOR, "ic-loading-indicator") + .shadow() + .find(".ic-loading-circular-outer") + .should("be.visible"); + + cy.get(DATA_TABLE_SELECTOR).invoke("prop", "data", LONG_DATA); + + cy.wait(1000); + + cy.findShadowEl(DATA_TABLE_SELECTOR, ".loading-overlay").should( + "be.not.exist" + ); + cy.findShadowEl(DATA_TABLE_SELECTOR, "tbody").should("be.visible"); + cy.findShadowEl(DATA_TABLE_SELECTOR, "ic-loading-indicator").should( + "not.exist" + ); + }); + + it("should not render an overlay with circular loading indicator when loadingOption.overlay is set to false", () => { + mount( + + ); + cy.checkHydrated(DATA_TABLE_SELECTOR); + + cy.get(DATA_TABLE_SELECTOR).invoke("prop", "loading", true); + + cy.findShadowEl(DATA_TABLE_SELECTOR, ".loading-overlay").should( + "not.exist" + ); + cy.findShadowEl(DATA_TABLE_SELECTOR, "tbody").should("not.exist"); + cy.findShadowEl(DATA_TABLE_SELECTOR, "ic-loading-indicator") + .shadow() + .find(".ic-loading-circular-outer") + .should("be.visible"); + }); + + it("should render an overlay with circular loading indicator when loadingOption.overlay is set to true and no data is set", () => { + mount( + + ); + cy.checkHydrated(DATA_TABLE_SELECTOR); + + cy.get(DATA_TABLE_SELECTOR).invoke("prop", "loading", true); + + cy.findShadowEl(DATA_TABLE_SELECTOR, ".loading-overlay").should( + "be.visible" + ); + cy.findShadowEl(DATA_TABLE_SELECTOR, "tbody").should("not.exist"); + cy.findShadowEl(DATA_TABLE_SELECTOR, "ic-empty-state").should("be.visible"); + cy.findShadowEl(DATA_TABLE_SELECTOR, "ic-loading-indicator") + .shadow() + .find(".ic-loading-circular-outer") + .should("be.visible"); + + cy.get(DATA_TABLE_SELECTOR).invoke("prop", "data", LONG_DATA); + + cy.wait(1000); + + cy.findShadowEl(DATA_TABLE_SELECTOR, ".loading-overlay").should( + "not.exist" + ); + cy.findShadowEl(DATA_TABLE_SELECTOR, "tbody").should("be.visible"); + cy.findShadowEl(DATA_TABLE_SELECTOR, "ic-empty-state").should("not.exist"); + cy.findShadowEl(DATA_TABLE_SELECTOR, "ic-loading-indicator").should( + "not.exist" + ); + }); }); describe("IcDataTables with IcPaginationBar", () => { diff --git a/packages/canary-react/src/stories/ic-data-table.stories.mdx b/packages/canary-react/src/stories/ic-data-table.stories.mdx index 40a0fa7999..79e1424678 100644 --- a/packages/canary-react/src/stories/ic-data-table.stories.mdx +++ b/packages/canary-react/src/stories/ic-data-table.stories.mdx @@ -975,6 +975,8 @@ The loading indicator can be customised using the `loadingOptions` prop: - `label` sets the visual message - `labelDuration` is the number of milliseconds before the label changes - `showBackground` allows for a white background and grey border to help the indicator stand out +- `overlay` renders a dark overlay over the previous data set while new data is loaded + - Setting `overlay` also sets `showBackground` to `true` so the loading indicator stands out against the dark overlay. If it needs to be determinate, use `max`, `min` and `progress`. @@ -2207,6 +2209,7 @@ export const defaultArgs = { loadingMax: 100, loadingMin: 0, loadingProgress: 50, + loadingOverlay: false, loadingShowBackground: false, minimumLoadingDisplayDuration: 1000, paginationItemsPerPageOptions: [ @@ -2318,7 +2321,8 @@ export const defaultArgs = { max: args.loadingMax, min: args.loadingMin, progress: args.loadingProgress, - showBackground: args.loadingShowBackground + showBackground: args.loadingShowBackground, + overlay: args.loadingOverlay }} minimumLoadingDisplayDuration={args.minimumLoadingDisplayDuration} paginationBarOptions={{ diff --git a/packages/canary-web-components/src/components.d.ts b/packages/canary-web-components/src/components.d.ts index 0068e5b590..e6544f95d8 100644 --- a/packages/canary-web-components/src/components.d.ts +++ b/packages/canary-web-components/src/components.d.ts @@ -119,6 +119,7 @@ export namespace Components { progress?: number; showBackground?: boolean; monochrome?: boolean; + overlay?: boolean; }; /** * Sets the maximum width of the data table. Can be set in `px`, `rem`, or `%`. @@ -838,6 +839,7 @@ declare namespace LocalJSX { progress?: number; showBackground?: boolean; monochrome?: boolean; + overlay?: boolean; }; /** * Sets the maximum width of the data table. Can be set in `px`, `rem`, or `%`. diff --git a/packages/canary-web-components/src/components/ic-data-table/ic-data-table.css b/packages/canary-web-components/src/components/ic-data-table/ic-data-table.css index 708181db12..599fb2f2e2 100644 --- a/packages/canary-web-components/src/components/ic-data-table/ic-data-table.css +++ b/packages/canary-web-components/src/components/ic-data-table/ic-data-table.css @@ -338,6 +338,7 @@ td.table-density-spacious { left: calc(50% - 5.9741rem); opacity: 0; transition: opacity var(--ic-transition-duration-slow); + z-index: calc(var(--ic-z-index-dialog) - 1); } .loading.show-background { @@ -424,6 +425,35 @@ td.table-density-spacious { grid-template-columns: auto auto; } +.loading-overlay { + visibility: hidden; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: var(--ic-data-table-loading-indicator-overlay-background); + z-index: calc(var(--ic-z-index-dialog) - 2); + opacity: 0; + transition: opacity var(--ic-transition-duration-slow); +} + +.loading-overlay.show { + visibility: visible; + opacity: 0.6; +} + +.sr-only { + position: absolute; + left: -9999px; +} + +@media (prefers-reduced-motion: reduce) { + .loading-overlay { + transition: none; + } +} + @media screen and (min-width: 577px) { .column-header-inner-container { display: flex; diff --git a/packages/canary-web-components/src/components/ic-data-table/ic-data-table.stories.mdx b/packages/canary-web-components/src/components/ic-data-table/ic-data-table.stories.mdx index dcc94509b8..8fad05897b 100644 --- a/packages/canary-web-components/src/components/ic-data-table/ic-data-table.stories.mdx +++ b/packages/canary-web-components/src/components/ic-data-table/ic-data-table.stories.mdx @@ -816,6 +816,8 @@ The loading indicator can be customised using the `loadingOptions` prop: - `label` sets the visual message - `labelDuration` is the number of milliseconds before the label changes - `showBackground` allows for a white background and grey border to help the indicator stand out +- `overlay` renders a dark overlay over the previous data set while new data is loaded + - Setting `overlay` also sets `showBackground` to `true` so the loading indicator stands out against the dark overlay. If it needs to be determinate, use `max`, `min` and `progress`. diff --git a/packages/canary-web-components/src/components/ic-data-table/ic-data-table.tsx b/packages/canary-web-components/src/components/ic-data-table/ic-data-table.tsx index 13b65df94b..4886e66399 100644 --- a/packages/canary-web-components/src/components/ic-data-table/ic-data-table.tsx +++ b/packages/canary-web-components/src/components/ic-data-table/ic-data-table.tsx @@ -27,6 +27,7 @@ import { IcDataTableTruncationTypes, IcDensityUpdateEventDetail, IcSortEventDetail, + IcLoadingOptions, } from "./ic-data-table.types"; import { IcPaginationBarOptions, IcThemeMode } from "../../utils/types"; // Unable to import helper functions via @ukic/web-components @@ -73,6 +74,7 @@ export class DataTable { private hasLoadedForOneSecond = true; private loadingIndicator: HTMLIcLoadingIndicatorElement; + private loadingOverlay: HTMLDivElement; private timerStarted: number; private resizeObserver: ResizeObserver = null; private SHOW_HIDE_STRING = "show-hide"; @@ -201,6 +203,7 @@ export class DataTable { progress?: number; showBackground?: boolean; monochrome?: boolean; + overlay?: boolean; }; /** @@ -340,7 +343,7 @@ export class DataTable { this.sortedColumnOrder = this.sortOptions.sortOrders[0]; this.loadingOptions = { ...this.loadingOptions, - showBackground: this.data?.length > 0, + showBackground: this.data?.length > 0 || !!this.loadingOptions?.overlay, }; this.initialLoad = true; this.previousItemsPerPage = this.rowsPerPage; @@ -978,7 +981,7 @@ export class DataTable { async dataHandler(newData: IcDataTableDataType[]): Promise { this.loadingOptions = { ...this.loadingOptions, - showBackground: newData?.length > 0, + showBackground: newData?.length > 0 || !!this.loadingOptions?.overlay, }; if (this.loading) { !this.hasLoadedForOneSecond @@ -1093,6 +1096,9 @@ export class DataTable { } private showLoadingIndicator() { + if (this.loadingOptions?.overlay) { + this.loadingOverlay?.classList.add("show"); + } this.loadingIndicator?.classList.add("show"); } @@ -1872,11 +1878,95 @@ export class DataTable { }); }; + private renderTableBody = ( + data: IcDataTableDataType[], + loading: boolean, + overlay: boolean + ) => { + if (!data?.length) return; + + if (overlay && loading) { + return {this.createRows()}; + } else if (loading && !overlay) { + return null; + } else { + return {this.createRows()}; + } + }; + + private renderLoadingIndicator = ( + isLoading: boolean, + loadingOptions: IcLoadingOptions + ) => { + if (!isLoading) return null; + + return ( + +
(this.loadingOverlay = el)} + >
+ + (this.loadingIndicator = el) + } + > +
+ ); + }; + + private renderAriaLiveLoading = () => { + if (this.loading) { + return this.loadingOptions?.label || "Loading..."; + } else if (this.updating) { + return this.updatingOptions?.description || "Updating table data"; + } else { + return ""; + } + }; + + private renderEmptyState = ( + data: IcDataTableDataType[], + loading: boolean, + overlay: boolean + ) => { + const emptyStateEl = isSlotUsed(this.el, "empty-state") ? ( + + ) : ( + + ); + + if (loading && !data?.length && overlay) { + return emptyStateEl; + } else if (!loading && !data?.length) { + return emptyStateEl; + } else { + return null; + } + }; + render() { const { caption, createColumnHeaders, - createRows, createUpdatingIndicator, data, hideColumnHeaders, @@ -1934,40 +2024,14 @@ export class DataTable { ) : ( createUpdatingIndicator() ))} - {data?.length > 0 && !loading && {createRows()}} + {this.renderTableBody(data, loading, loadingOptions.overlay)} - {!data?.length && - !loading && - (isSlotUsed(this.el, "empty-state") ? ( - - ) : ( - - ))} + {this.renderEmptyState(data, loading, loadingOptions.overlay)} - {loading && ( - - (this.loadingIndicator = el) - } - > - )} +
+ {this.renderAriaLiveLoading()} +
+ {this.renderLoadingIndicator(loading, loadingOptions)} {(showPagination || isSlotUsed(this.el, "pagination-bar")) && (
{isSlotUsed(this.el, "pagination-bar") ? ( diff --git a/packages/canary-web-components/src/components/ic-data-table/ic-data-table.types.tsx b/packages/canary-web-components/src/components/ic-data-table/ic-data-table.types.tsx index 8e59149d50..73289103c4 100644 --- a/packages/canary-web-components/src/components/ic-data-table/ic-data-table.types.tsx +++ b/packages/canary-web-components/src/components/ic-data-table/ic-data-table.types.tsx @@ -41,6 +41,18 @@ export type IcDataTableColumnObject = { }; }; +export type IcLoadingOptions = { + monochrome?: boolean; + description?: string; + label?: string; + labelDuration?: number; + max?: number; + min?: number; + progress?: number; + showBackground?: boolean; + overlay?: boolean; +}; + export type IcDataTableRowHeights = number | "auto"; export interface IcDensityUpdateEventDetail { diff --git a/packages/canary-web-components/src/components/ic-data-table/readme.md b/packages/canary-web-components/src/components/ic-data-table/readme.md index 2ee41f5e20..418b814d44 100644 --- a/packages/canary-web-components/src/components/ic-data-table/readme.md +++ b/packages/canary-web-components/src/components/ic-data-table/readme.md @@ -7,35 +7,35 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `caption` _(required)_ | `caption` | The title for the table only visible to screen readers. | `string` | `undefined` | -| `columnHeaderTruncation` | `column-header-truncation` | Determines whether the column header should be truncated and display a tooltip. Default is `false`. | `boolean` | `false` | -| `columns` _(required)_ | -- | The column headers for the table. | `IcDataTableColumnObject[]` | `undefined` | -| `data` | -- | The row content for the table. | `IcDataTableDataType[]` | `undefined` | -| `density` | `density` | Set the density of the table including font and padding. | `"default" \| "dense" \| "spacious"` | `"default"` | -| `embedded` | `embedded` | Applies a border to the table container. | `boolean` | `false` | -| `globalRowHeight` | `global-row-height` | Sets the row height on all rows in the table that aren't set using the `variableRowHeight` method. | `"auto" \| number` | `"auto"` | -| `height` | `height` | Sets the table height. Can be set to `auto` or a specific value in `px`, `rem`, or `%`. | `string` | `undefined` | -| `hideColumnHeaders` | `hide-column-headers` | If `true`, column headers will not be visible. | `boolean` | `false` | -| `loading` | `loading` | When set to `true`, the full table will show a loading state, featuring a radial indicator. | `boolean` | `false` | -| `loadingOptions` | -- | Sets the props for the circular loading indicator used in the loading state. | `{ description?: string; label?: string; labelDuration?: number; max?: number; min?: number; progress?: number; showBackground?: boolean; monochrome?: boolean; }` | `undefined` | -| `maxWidth` | `max-width` | Sets the maximum width of the data table. Can be set in `px`, `rem`, or `%`. | `string` | `undefined` | -| `minWidth` | `min-width` | Sets the minimum width of the data table. Can be set in `px`, `rem`, or `%`. | `string` | `undefined` | -| `minimumLoadingDisplayDuration` | `minimum-loading-display-duration` | The minimum amount of time the `loading` state displays for before showing the data. Used to prevent flashing in the component. | `number` | `1000` | -| `paginationBarOptions` | -- | Sets the props for the built-in pagination bar. If the `pagination-bar` slot is used then this prop is ignored. | `IcPaginationBarOptions` | `{ itemsPerPageOptions: [ { label: "10", value: "10" }, { label: "25", value: "25" }, { label: "50", value: "50" }, ], rangeLabelType: "page", type: "simple", showItemsPerPageControl: true, showGoToPageControl: true, alignment: "right", itemLabel: "Item", pageLabel: "Page", hideRangeLabel: false, hideAllFromItemsPerPage: false, monochrome: false, }` | -| `showPagination` | `show-pagination` | If `true`, adds a pagination bar to the bottom of the table. | `boolean` | `false` | -| `sortOptions` | -- | Sets the order columns will be sorted in and allows for 'default' sorts to be added. | `{ sortOrders: IcDataTableSortOrderOptions[]; defaultColumn?: string; }` | `{ sortOrders: ["unsorted", "ascending", "descending"], defaultColumn: "", }` | -| `sortable` | `sortable` | If `true`, allows table columns to be sorted using applied sort buttons. | `boolean` | `false` | -| `stickyColumnHeaders` | `sticky-column-headers` | If `true`, column headers will remain at the top of the table when scrolling vertically. | `boolean` | `false` | -| `stickyRowHeaders` | `sticky-row-headers` | If `true`, row headers will remain to the left when scrolling horizontally. | `boolean` | `false` | -| `tableLayout` | `table-layout` | Sets the layout of the table | `"auto" \| "fixed"` | `"fixed"` | -| `theme` | `theme` | Sets the theme color to the dark or light theme color. "inherit" will set the color based on the system settings or ic-theme component. | `"dark" \| "inherit" \| "light"` | `"inherit"` | -| `truncationPattern` | `truncation-pattern` | Sets the method used to truncate long text in cells where textWrap is `false`. The `tooltip` truncation pattern allows the overflowing text to be seen in a tooltip. The `show-hide` truncation pattern allows the overflowing text to be shown and hidden using the ic-typography "See more"/"See less" buttons. | `"show-hide" \| "tooltip"` | `undefined` | -| `updating` | `updating` | If `true`, the table displays a linear loading indicator below the header row to indicate an updating state. | `boolean` | `false` | -| `updatingOptions` | -- | Sets the props for the linear loading indicator used in the updating state. | `{ description?: string; max?: number; min?: number; progress?: number; monochrome?: boolean; }` | `undefined` | -| `variableRowHeight` | -- | Allows for custom setting of row heights on individual rows based on an individual value from the `data` prop and the row index. If the function returns `null`, that row's height will be set to the `globalRowHeight` property. | `(params: { [key: string]: any; index: number; }) => IcDataTableRowHeights` | `undefined` | -| `width` | `width` | Sets the table width. Can be set to `auto` or a specific value in `px`, `rem`, or `%`. | `string` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `caption` _(required)_ | `caption` | The title for the table only visible to screen readers. | `string` | `undefined` | +| `columnHeaderTruncation` | `column-header-truncation` | Determines whether the column header should be truncated and display a tooltip. Default is `false`. | `boolean` | `false` | +| `columns` _(required)_ | -- | The column headers for the table. | `IcDataTableColumnObject[]` | `undefined` | +| `data` | -- | The row content for the table. | `IcDataTableDataType[]` | `undefined` | +| `density` | `density` | Set the density of the table including font and padding. | `"default" \| "dense" \| "spacious"` | `"default"` | +| `embedded` | `embedded` | Applies a border to the table container. | `boolean` | `false` | +| `globalRowHeight` | `global-row-height` | Sets the row height on all rows in the table that aren't set using the `variableRowHeight` method. | `"auto" \| number` | `"auto"` | +| `height` | `height` | Sets the table height. Can be set to `auto` or a specific value in `px`, `rem`, or `%`. | `string` | `undefined` | +| `hideColumnHeaders` | `hide-column-headers` | If `true`, column headers will not be visible. | `boolean` | `false` | +| `loading` | `loading` | When set to `true`, the full table will show a loading state, featuring a radial indicator. | `boolean` | `false` | +| `loadingOptions` | -- | Sets the props for the circular loading indicator used in the loading state. | `{ description?: string; label?: string; labelDuration?: number; max?: number; min?: number; progress?: number; showBackground?: boolean; monochrome?: boolean; overlay?: boolean; }` | `undefined` | +| `maxWidth` | `max-width` | Sets the maximum width of the data table. Can be set in `px`, `rem`, or `%`. | `string` | `undefined` | +| `minWidth` | `min-width` | Sets the minimum width of the data table. Can be set in `px`, `rem`, or `%`. | `string` | `undefined` | +| `minimumLoadingDisplayDuration` | `minimum-loading-display-duration` | The minimum amount of time the `loading` state displays for before showing the data. Used to prevent flashing in the component. | `number` | `1000` | +| `paginationBarOptions` | -- | Sets the props for the built-in pagination bar. If the `pagination-bar` slot is used then this prop is ignored. | `IcPaginationBarOptions` | `{ itemsPerPageOptions: [ { label: "10", value: "10" }, { label: "25", value: "25" }, { label: "50", value: "50" }, ], rangeLabelType: "page", type: "simple", showItemsPerPageControl: true, showGoToPageControl: true, alignment: "right", itemLabel: "Item", pageLabel: "Page", hideRangeLabel: false, hideAllFromItemsPerPage: false, monochrome: false, }` | +| `showPagination` | `show-pagination` | If `true`, adds a pagination bar to the bottom of the table. | `boolean` | `false` | +| `sortOptions` | -- | Sets the order columns will be sorted in and allows for 'default' sorts to be added. | `{ sortOrders: IcDataTableSortOrderOptions[]; defaultColumn?: string; }` | `{ sortOrders: ["unsorted", "ascending", "descending"], defaultColumn: "", }` | +| `sortable` | `sortable` | If `true`, allows table columns to be sorted using applied sort buttons. | `boolean` | `false` | +| `stickyColumnHeaders` | `sticky-column-headers` | If `true`, column headers will remain at the top of the table when scrolling vertically. | `boolean` | `false` | +| `stickyRowHeaders` | `sticky-row-headers` | If `true`, row headers will remain to the left when scrolling horizontally. | `boolean` | `false` | +| `tableLayout` | `table-layout` | Sets the layout of the table | `"auto" \| "fixed"` | `"fixed"` | +| `theme` | `theme` | Sets the theme color to the dark or light theme color. "inherit" will set the color based on the system settings or ic-theme component. | `"dark" \| "inherit" \| "light"` | `"inherit"` | +| `truncationPattern` | `truncation-pattern` | Sets the method used to truncate long text in cells where textWrap is `false`. The `tooltip` truncation pattern allows the overflowing text to be seen in a tooltip. The `show-hide` truncation pattern allows the overflowing text to be shown and hidden using the ic-typography "See more"/"See less" buttons. | `"show-hide" \| "tooltip"` | `undefined` | +| `updating` | `updating` | If `true`, the table displays a linear loading indicator below the header row to indicate an updating state. | `boolean` | `false` | +| `updatingOptions` | -- | Sets the props for the linear loading indicator used in the updating state. | `{ description?: string; max?: number; min?: number; progress?: number; monochrome?: boolean; }` | `undefined` | +| `variableRowHeight` | -- | Allows for custom setting of row heights on individual rows based on an individual value from the `data` prop and the row index. If the function returns `null`, that row's height will be set to the `globalRowHeight` property. | `(params: { [key: string]: any; index: number; }) => IcDataTableRowHeights` | `undefined` | +| `width` | `width` | Sets the table width. Can be set to `auto` or a specific value in `px`, `rem`, or `%`. | `string` | `undefined` | ## Events diff --git a/packages/canary-web-components/src/components/ic-data-table/story-data.ts b/packages/canary-web-components/src/components/ic-data-table/story-data.ts index 9df6884f21..df5aad9d6f 100644 --- a/packages/canary-web-components/src/components/ic-data-table/story-data.ts +++ b/packages/canary-web-components/src/components/ic-data-table/story-data.ts @@ -1278,6 +1278,7 @@ export const Loading = (): HTMLIcDataTableElement => { dataTable.setAttribute("loading", "true"); return dataTable; }; + export const EmptyLoading = (): HTMLIcDataTableElement => { const dataTable = createDataTableElement( "Empty and Loading State", diff --git a/packages/canary-web-components/src/components/ic-data-table/test/basic/__snapshots__/ic-data-table.spec.tsx.snap b/packages/canary-web-components/src/components/ic-data-table/test/basic/__snapshots__/ic-data-table.spec.tsx.snap index 349853a83f..abc29d7f96 100644 --- a/packages/canary-web-components/src/components/ic-data-table/test/basic/__snapshots__/ic-data-table.spec.tsx.snap +++ b/packages/canary-web-components/src/components/ic-data-table/test/basic/__snapshots__/ic-data-table.spec.tsx.snap @@ -225,6 +225,7 @@ exports[`ic-data-table should apply a specified row height to all rows when glob
+
@@ -455,6 +456,7 @@ exports[`ic-data-table should apply a specified row height to specific rows when +
@@ -685,6 +687,7 @@ exports[`ic-data-table should apply the correct density scaler to rowHeights whe +
@@ -915,6 +918,7 @@ exports[`ic-data-table should apply the correct density scaler to rowHeights whe +
@@ -964,6 +968,7 @@ exports[`ic-data-table should be able to slot a custom empty state into the data +
@@ -1234,6 +1239,7 @@ exports[`ic-data-table should correctly render a custom icon in the header when +
@@ -1464,6 +1470,7 @@ exports[`ic-data-table should not override the height of certain rows if \`varia +
@@ -1694,6 +1701,7 @@ exports[`ic-data-table should not override the height of rows if \`globalRowHeig +
@@ -1924,6 +1932,7 @@ exports[`ic-data-table should not render custom icon in header when hideOnHeader +
@@ -2155,6 +2164,7 @@ exports[`ic-data-table should pass the caption down to any slotted ic-data-table +
@@ -2277,6 +2287,9 @@ exports[`ic-data-table should pass through the updatingOptions to the linear loa +
+ Updating +
@@ -2507,6 +2520,7 @@ exports[`ic-data-table should render 1`] = ` +
@@ -2738,6 +2752,7 @@ exports[`ic-data-table should render a slotted icon instead of an icon defined i +
@@ -3252,6 +3268,7 @@ exports[`ic-data-table should render column icon on all column cells if onAllCel +
@@ -3482,6 +3499,7 @@ exports[`ic-data-table should render embedded 1`] = ` +
@@ -3724,6 +3742,7 @@ exports[`ic-data-table should render sortable 1`] = ` +
table unsorted
@@ -3776,6 +3795,7 @@ exports[`ic-data-table should render the empty state when data is null 1`] = ` +
@@ -3825,6 +3845,92 @@ exports[`ic-data-table should render the empty state when no data is passed thro +
+ + + +`; + +exports[`ic-data-table should render the loading indicator with an overlay above the table 1`] = ` + + +
+
+ + + + + + + + + + + + + + + + + + +
+ test table +
+
+ + Name + +
+
+
+ + Age + +
+
+
+ + Department + +
+
+
+ + Employee number + +
+
+
+ + John Smith + +
+
+
+ + 36 + +
+
+
+ + Accounts + +
+
+
+ + 1 + +
+
+
+
+ Loading +
+
+
@@ -3926,6 +4032,95 @@ exports[`ic-data-table should render the updating state when the \`updating\` pr +
+ Updating +
+ + + +`; + +exports[`ic-data-table should render updating in assertive aria-live div 1`] = ` + + +
+
+ + + + + + + + + + + + + + + + + + + +
+ test table +
+
+ + Name + +
+
+
+ + Age + +
+
+
+ + Department + +
+
+
+ + Employee number + +
+
+ +
+
+ + John Smith + +
+
+
+ + 36 + +
+
+
+ + Accounts + +
+
+
+ + 1 + +
+
+
+
+ Updating +
@@ -4157,6 +4352,7 @@ exports[`ic-data-table should render with a slotted ic-data-table-title-bar 1`] +
@@ -4388,6 +4584,7 @@ exports[`ic-data-table should render with cell overrides 1`] = ` +
@@ -4641,6 +4838,7 @@ exports[`ic-data-table should render with column header truncation 1`] = ` +
@@ -4871,6 +5069,7 @@ exports[`ic-data-table should render with column header truncation 2`] = ` +
@@ -5069,6 +5268,7 @@ exports[`ic-data-table should render with column headers hidden 1`] = ` +
@@ -5299,6 +5499,7 @@ exports[`ic-data-table should render with column overrides 1`] = ` +
@@ -5652,6 +5853,7 @@ exports[`ic-data-table should render with pagination 1`] = ` +
@@ -5861,6 +6063,7 @@ exports[`ic-data-table should render with row headers 1`] = ` +
@@ -6067,6 +6270,7 @@ exports[`ic-data-table should render with row overrides 1`] = ` +
@@ -6300,6 +6504,7 @@ exports[`ic-data-table should reset all rows to the default height when resetRow +
@@ -6530,6 +6735,7 @@ exports[`ic-data-table should reset all rows to the default height when resetRow +
@@ -7085,6 +7291,7 @@ exports[`ic-data-table should sort data when the sort button is clicked 1`] = ` +
table unsorted
@@ -7358,6 +7565,7 @@ exports[`ic-data-table should sort data when the sort button is clicked 2`] = ` +
name sorted ascending
@@ -7631,6 +7839,7 @@ exports[`ic-data-table should sort data when the sort button is clicked 3`] = ` +
name sorted descending
@@ -7904,6 +8113,7 @@ exports[`ic-data-table should sort data when the sort button is clicked 4`] = ` +
age sorted ascending
@@ -8235,6 +8445,7 @@ exports[`ic-data-table when loading is \`true\`, if data is set before 1 second +
@@ -8514,6 +8725,7 @@ exports[`ic-data-table when loading is \`true\`, setting data should cancel the +
diff --git a/packages/canary-web-components/src/components/ic-data-table/test/basic/ic-data-table.spec.tsx b/packages/canary-web-components/src/components/ic-data-table/test/basic/ic-data-table.spec.tsx index 6ed51178cc..38ef262dc7 100644 --- a/packages/canary-web-components/src/components/ic-data-table/test/basic/ic-data-table.spec.tsx +++ b/packages/canary-web-components/src/components/ic-data-table/test/basic/ic-data-table.spec.tsx @@ -1370,4 +1370,39 @@ describe(icDataTable, () => { expect(page.root).toMatchSnapshot(); }); + + it("should render the loading indicator with an overlay above the table", async () => { + const page = await newSpecPage({ + components: [DataTable], + template: () => ( + + ), + }); + + expect(page.root).toMatchSnapshot(); + }); + + it("should render updating in assertive aria-live div", async () => { + const page = await newSpecPage({ + components: [DataTable], + template: () => ( + + ), + }); + + expect(page.root).toMatchSnapshot(); + }); }); diff --git a/packages/web-components/src/global/color-mode.css b/packages/web-components/src/global/color-mode.css index 9825090dce..ac3921f413 100644 --- a/packages/web-components/src/global/color-mode.css +++ b/packages/web-components/src/global/color-mode.css @@ -676,6 +676,9 @@ ic-theme, --ic-data-table-header-text: var(--ic-color-text-primary); --ic-data-table-overlay-background: var(--ic-color-background-primary); --ic-data-table-overlay-border: var(--ic-color-border-neutral-grey-dark); + --ic-data-table-loading-indicator-overlay-background: var( + --ic-architectural-black + ); /* Data table title bar */ --ic-data-table-title-bar-title: var(--ic-color-text-primary); @@ -2020,6 +2023,9 @@ ic-theme, --ic-data-table-header-text: var(--ic-color-text-primary); --ic-data-table-overlay-background: var(--ic-color-background-primary); --ic-data-table-overlay-border: var(--ic-color-border-neutral-grey-light); + --ic-data-table-loading-indicator-overlay-background: var( + --ic-architectural-black + ); /* Data table title bar */ --ic-data-table-title-bar-title: var(--ic-color-text-primary); @@ -3373,6 +3379,9 @@ ic-theme, --ic-data-table-header-text: var(--ic-color-text-primary); --ic-data-table-overlay-background: var(--ic-color-background-primary); --ic-data-table-overlay-border: var(--ic-color-border-neutral-grey-light); + --ic-data-table-loading-indicator-overlay-background: var( + --ic-architectural-black + ); /* Data table title bar */ --ic-data-table-title-bar-title: var(--ic-color-text-primary);