diff --git a/packages/main/src/components/AnalyticalTable/AnalyticalTable.cy.tsx b/packages/main/src/components/AnalyticalTable/AnalyticalTable.cy.tsx
index 761987a8c25..99e167dbc4f 100644
--- a/packages/main/src/components/AnalyticalTable/AnalyticalTable.cy.tsx
+++ b/packages/main/src/components/AnalyticalTable/AnalyticalTable.cy.tsx
@@ -256,6 +256,16 @@ describe('AnalyticalTable', () => {
});
it('autoResize', () => {
+ function doubleClickResizer(selector: string, columnName: string, outerWidth: number) {
+ cy.get(selector)
+ .realHover()
+ .should('have.css', 'background-color', cssVarToRgb('--sapContent_DragAndDropActiveColor'))
+ .dblclick()
+ // fallback
+ .realClick({ clickCount: 2 });
+ cy.get(`[data-column-id="${columnName}"]`).invoke('outerWidth').should('equal', outerWidth);
+ }
+
let resizeColumns = columns.map((el) => {
return { ...el, autoResizable: true };
});
@@ -277,26 +287,19 @@ describe('AnalyticalTable', () => {
}}
/>,
);
- cy.wait(100);
cy.get('[data-component-name="AnalyticalTableResizer"]').eq(0).as('resizer1');
cy.get('[data-component-name="AnalyticalTableResizer"]').eq(1).as('resizer2');
- cy.get('@resizer2').should('be.visible').dblclick();
- cy.get('[data-column-id="age"]').invoke('outerWidth').should('equal', 476);
- cy.get('@resizer1').should('be.visible').dblclick();
- cy.get('[data-column-id="name"]').invoke('outerWidth').should('equal', 476);
-
- cy.get('@resize').should('have.callCount', 2);
+ doubleClickResizer('@resizer2', 'age', 476);
+ doubleClickResizer('@resizer1', 'name', 476);
+ // doubled call count because of fallback
+ cy.get('@resize').should('have.callCount', 4);
cy.mount();
- cy.wait(100);
- cy.get('@resizer2').should('be.visible').dblclick();
- cy.get('[data-column-id="age"]').invoke('outerWidth').should('equal', 60);
- cy.get('@resizer1').should('be.visible').dblclick();
- cy.get('[data-column-id="name"]').invoke('outerWidth').should('equal', 129);
-
- cy.get('@resize').should('have.callCount', 4);
+ doubleClickResizer('@resizer2', 'age', 60);
+ doubleClickResizer('@resizer1', 'name', 129);
+ cy.get('@resize').should('have.callCount', 8);
dataFixed = generateMoreData(200);
@@ -319,10 +322,8 @@ describe('AnalyticalTable', () => {
);
cy.get('[data-component-name="AnalyticalTableBody"]').scrollTo('bottom');
- cy.get('@resizer1').should('be.visible').dblclick();
- cy.get('[data-column-id="name"]').invoke('outerWidth').should('equal', 93);
-
- cy.get('@resize').should('have.callCount', 5);
+ doubleClickResizer('@resizer1', 'name', 93);
+ cy.get('@resize').should('have.callCount', 10);
resizeColumns = columns.map((el) => {
return { ...el, autoResizable: false };
@@ -330,12 +331,10 @@ describe('AnalyticalTable', () => {
cy.mount();
cy.wait(100);
- cy.get('@resizer2').should('be.visible').dblclick();
- cy.get('[data-column-id="age"]').invoke('outerWidth').should('equal', 472.75);
- cy.get('@resizer1').should('be.visible').dblclick();
- cy.get('[data-column-id="name"]').invoke('outerWidth').should('equal', 472.75);
+ doubleClickResizer('@resizer2', 'age', 472.75);
+ doubleClickResizer('@resizer1', 'name', 472.75);
- cy.get('@resize').should('have.callCount', 5);
+ cy.get('@resize').should('have.callCount', 10);
const dataSub = data.map((el, i) => {
if (i === 2) return { ...el, name: 'Longer Name Too' };
@@ -358,25 +357,17 @@ describe('AnalyticalTable', () => {
onAutoResize={resizeSpy}
/>,
);
- cy.wait(100);
- cy.get('@resizer2').should('be.visible').dblclick();
- cy.get('[data-column-id="age"]').invoke('outerWidth').should('equal', 60);
- cy.get('@resizer1').should('be.visible').dblclick();
- cy.get('[data-column-id="name"]').invoke('outerWidth').should('equal', 165);
-
- cy.get('@resize').should('have.callCount', 7);
+ doubleClickResizer('@resizer2', 'age', 60);
+ doubleClickResizer('@resizer1', 'name', 165);
+ cy.get('@resize').should('have.callCount', 14);
const dataResizeTree = [...dataTree];
dataResizeTree[0].subRows[0].name = 'Longer Name To Resize Here';
cy.mount();
- cy.wait(100);
- cy.get('@resizer1').should('be.visible').dblclick();
- cy.get('[data-column-id="name"]').invoke('outerWidth').should('equal', 169);
+ doubleClickResizer('@resizer1', 'name', 169);
cy.get('[aria-rowindex="1"] > [aria-colindex="1"] > [title="Expand Node"] > [ui5-button]').click();
- cy.get('@resizer1').should('be.visible').dblclick();
- cy.get('[data-column-id="name"]').invoke('outerWidth').should('equal', 251);
-
- cy.get('@resize').should('have.callCount', 9);
+ doubleClickResizer('@resizer1', 'name', 251);
+ cy.get('@resize').should('have.callCount', 18);
});
it('scrollTo', () => {
diff --git a/packages/main/src/components/AnalyticalTable/TableBody/VirtualTableBody.tsx b/packages/main/src/components/AnalyticalTable/TableBody/VirtualTableBody.tsx
index ccedb4ae084..ec29d314b7c 100644
--- a/packages/main/src/components/AnalyticalTable/TableBody/VirtualTableBody.tsx
+++ b/packages/main/src/components/AnalyticalTable/TableBody/VirtualTableBody.tsx
@@ -1,12 +1,12 @@
import type { Virtualizer } from '@tanstack/react-virtual';
import { clsx } from 'clsx';
-import type { MutableRefObject } from 'react';
+import type { MutableRefObject, RefObject } from 'react';
import { useEffect, useMemo, useRef } from 'react';
import type {
AnalyticalTablePropTypes,
ClassNames,
DivWithCustomScrollProp,
- ScrollToRefType,
+ ReactVirtualScrollToMethods,
TableInstance,
TriggerScrollState,
} from '../types/index.js';
@@ -35,7 +35,7 @@ interface VirtualTableBodyProps {
subRowsKey: string;
scrollContainerRef?: MutableRefObject;
triggerScroll?: TriggerScrollState;
- scrollToRef: MutableRefObject;
+ scrollToRef: RefObject;
rowVirtualizer: Virtualizer;
}
diff --git a/packages/main/src/components/AnalyticalTable/hooks/useScrollToRef.ts b/packages/main/src/components/AnalyticalTable/hooks/useScrollToRef.ts
new file mode 100644
index 00000000000..8b45f488f0b
--- /dev/null
+++ b/packages/main/src/components/AnalyticalTable/hooks/useScrollToRef.ts
@@ -0,0 +1,71 @@
+import type { RefCallback, RefObject } from 'react';
+import { useCallback, useRef } from 'react';
+import type { AnalyticalTableScrollMode } from '../../../enums/index.js';
+import type { AnalyticalTableDomRef, ScrollToRefType, TableInstance } from '../types/index.js';
+
+export function useScrollToRef(
+ componentRef: (node: AnalyticalTableDomRef) => void,
+ dispatch: TableInstance['dispatch'],
+): [RefCallback, RefObject] {
+ const scrollToRef = useRef(null);
+
+ const cbRef: RefCallback = useCallback(
+ (node) => {
+ if (!node) return;
+
+ const extendedNode = Object.assign(node, {
+ scrollTo: (offset: number, align?: AnalyticalTableScrollMode | keyof typeof AnalyticalTableScrollMode) => {
+ if (typeof scrollToRef.current?.scrollToOffset === 'function') {
+ scrollToRef.current.scrollToOffset(offset, { align });
+ } else {
+ dispatch({
+ type: 'TRIGGER_PROG_SCROLL',
+ payload: { direction: 'vertical', type: 'offset', args: [offset, { align }] },
+ });
+ }
+ },
+ scrollToItem: (index: number, align?: AnalyticalTableScrollMode | keyof typeof AnalyticalTableScrollMode) => {
+ if (typeof scrollToRef.current?.scrollToIndex === 'function') {
+ scrollToRef.current.scrollToIndex(index, { align });
+ } else {
+ dispatch({
+ type: 'TRIGGER_PROG_SCROLL',
+ payload: { direction: 'vertical', type: 'item', args: [index, { align }] },
+ });
+ }
+ },
+ horizontalScrollTo: (
+ offset: number,
+ align?: AnalyticalTableScrollMode | keyof typeof AnalyticalTableScrollMode,
+ ) => {
+ if (typeof scrollToRef.current?.horizontalScrollToOffset === 'function') {
+ scrollToRef.current.horizontalScrollToOffset(offset, { align });
+ } else {
+ dispatch({
+ type: 'TRIGGER_PROG_SCROLL',
+ payload: { direction: 'horizontal', type: 'offset', args: [offset, { align }] },
+ });
+ }
+ },
+ horizontalScrollToItem: (
+ index: number,
+ align?: AnalyticalTableScrollMode | keyof typeof AnalyticalTableScrollMode,
+ ) => {
+ if (typeof scrollToRef.current?.horizontalScrollToIndex === 'function') {
+ scrollToRef.current.horizontalScrollToIndex(index, { align });
+ } else {
+ dispatch({
+ type: 'TRIGGER_PROG_SCROLL',
+ payload: { direction: 'horizontal', type: 'item', args: [index, { align }] },
+ });
+ }
+ },
+ });
+
+ componentRef(extendedNode);
+ },
+ [componentRef, dispatch],
+ );
+
+ return [cbRef, scrollToRef];
+}
diff --git a/packages/main/src/components/AnalyticalTable/hooks/useTableScrollHandles.ts b/packages/main/src/components/AnalyticalTable/hooks/useTableScrollHandles.ts
deleted file mode 100644
index de87b3b9561..00000000000
--- a/packages/main/src/components/AnalyticalTable/hooks/useTableScrollHandles.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-import type { ScrollToOptions } from '@tanstack/react-virtual';
-import type { MutableRefObject } from 'react';
-import { useEffect, useRef } from 'react';
-import type { AnalyticalTableScrollMode } from '../../../enums/index.js';
-import type { AnalyticalTableDomRef } from '../types/index.js';
-
-interface ScrollToMethods {
- scrollTo: (offset: number, align?: AnalyticalTableScrollMode | keyof typeof AnalyticalTableScrollMode) => void;
- scrollToItem: (index: number, align?: AnalyticalTableScrollMode | keyof typeof AnalyticalTableScrollMode) => void;
- horizontalScrollTo: (
- offset: number,
- align?: AnalyticalTableScrollMode | keyof typeof AnalyticalTableScrollMode,
- ) => void;
- horizontalScrollToItem: (
- index: number,
- align?: AnalyticalTableScrollMode | keyof typeof AnalyticalTableScrollMode,
- ) => void;
-}
-
-interface ReactVirtualScrollToMethods {
- scrollToOffset?: (offset: number, options?: ScrollToOptions) => void;
- scrollToIndex?: (index: number, options?: ScrollToOptions) => void;
- horizontalScrollToOffset?: (offset: number, options?: ScrollToOptions) => void;
- horizontalScrollToIndex?: (index: number, options?: ScrollToOptions) => void;
-}
-
-export const useTableScrollHandles = (ref, dispatch) => {
- let analyticalTableRef = useRef(null);
- if (ref) {
- analyticalTableRef = ref;
- }
- const scrollToRef = useRef({});
-
- useEffect(() => {
- if (analyticalTableRef.current) {
- Object.assign, ScrollToMethods>(analyticalTableRef.current, {
- scrollTo: (offset, align) => {
- if (typeof scrollToRef.current?.scrollToOffset === 'function') {
- scrollToRef.current.scrollToOffset(offset, { align });
- } else {
- dispatch({
- type: 'TRIGGER_PROG_SCROLL',
- payload: { direction: 'vertical', type: 'offset', args: [offset, { align }] },
- });
- }
- },
- scrollToItem: (index, align) => {
- if (typeof scrollToRef.current?.scrollToIndex === 'function') {
- scrollToRef.current.scrollToIndex(index, { align });
- } else {
- dispatch({
- type: 'TRIGGER_PROG_SCROLL',
- payload: { direction: 'vertical', type: 'item', args: [index, { align }] },
- });
- }
- },
- horizontalScrollTo: (offset, align) => {
- if (typeof scrollToRef.current?.horizontalScrollToOffset === 'function') {
- scrollToRef.current.horizontalScrollToOffset(offset, { align });
- } else {
- dispatch({
- type: 'TRIGGER_PROG_SCROLL',
- payload: { direction: 'horizontal', type: 'offset', args: [offset, { align }] },
- });
- }
- },
- horizontalScrollToItem: (index, align) => {
- if (typeof scrollToRef.current?.horizontalScrollToIndex === 'function') {
- scrollToRef.current.horizontalScrollToIndex(index, { align });
- } else {
- dispatch({
- type: 'TRIGGER_PROG_SCROLL',
- payload: { direction: 'horizontal', type: 'item', args: [index, { align }] },
- });
- }
- },
- });
- }
- }, []);
-
- return [analyticalTableRef, scrollToRef];
-};
diff --git a/packages/main/src/components/AnalyticalTable/index.tsx b/packages/main/src/components/AnalyticalTable/index.tsx
index 158a5d6b24e..40639619fa3 100644
--- a/packages/main/src/components/AnalyticalTable/index.tsx
+++ b/packages/main/src/components/AnalyticalTable/index.tsx
@@ -70,10 +70,10 @@ import { useResizeColumnsConfig } from './hooks/useResizeColumnsConfig.js';
import { useRowHighlight } from './hooks/useRowHighlight.js';
import { useRowNavigationIndicators } from './hooks/useRowNavigationIndicator.js';
import { useRowSelectionColumn } from './hooks/useRowSelectionColumn.js';
+import { useScrollToRef } from './hooks/useScrollToRef.js';
import { useSelectionChangeCallback } from './hooks/useSelectionChangeCallback.js';
import { useSingleRowStateSelection } from './hooks/useSingleRowStateSelection.js';
import { useStyling } from './hooks/useStyling.js';
-import { useTableScrollHandles } from './hooks/useTableScrollHandles.js';
import { useToggleRowExpand } from './hooks/useToggleRowExpand.js';
import { useVisibleColumnsWidth } from './hooks/useVisibleColumnsWidth.js';
import { VerticalScrollbar } from './scrollbars/VerticalScrollbar.js';
@@ -307,9 +307,10 @@ const AnalyticalTable = forwardRef 0 || tableState.globalFilter ? noDataTextFiltered : noDataTextI18n);
- const [componentRef, updatedRef] = useSyncRef(ref);
- //@ts-expect-error: types are compatible
- const isRtl = useIsRTL(updatedRef);
+ const [componentRef, analyticalTableRef] = useSyncRef(ref);
+ const [cbRef, scrollToRef] = useScrollToRef(componentRef, dispatch);
+ // @ts-expect-error: is HTMLElement
+ const isRtl = useIsRTL(analyticalTableRef);
const columnVirtualizer = useVirtualizer({
count: visibleColumnsWidth.length,
@@ -340,8 +341,6 @@ const AnalyticalTable = forwardRef {
if (
@@ -737,7 +736,7 @@ const AnalyticalTable = forwardRef
{header && (
diff --git a/packages/main/src/components/AnalyticalTable/types/index.ts b/packages/main/src/components/AnalyticalTable/types/index.ts
index 317097b9996..f6b7c59617b 100644
--- a/packages/main/src/components/AnalyticalTable/types/index.ts
+++ b/packages/main/src/components/AnalyticalTable/types/index.ts
@@ -101,7 +101,11 @@ export interface TableInstance {
disableGlobalFilter?: boolean;
disableGroupBy?: boolean;
disableSortBy?: boolean;
- dispatch?: (action: any) => void;
+ dispatch?: (action: {
+ type: string;
+ payload?: Record | AnalyticalTableState['popInColumns'] | boolean | string;
+ clientX?: number;
+ }) => void;
expandedDepth?: number;
expandedRows?: RowType[];
filteredFlatRows?: RowType[];
@@ -280,6 +284,13 @@ export interface TriggerScrollState {
args: [number, Omit?];
}
+export interface ReactVirtualScrollToMethods {
+ scrollToOffset?: (offset: number, options?: ScrollToOptions) => void;
+ scrollToIndex?: (index: number, options?: ScrollToOptions) => void;
+ horizontalScrollToOffset?: (offset: number, options?: ScrollToOptions) => void;
+ horizontalScrollToIndex?: (index: number, options?: ScrollToOptions) => void;
+}
+
interface PopInColumnsState {
id: string;
column: ColumnType;