@scality/core-ui 0.184.0 → 0.186.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.
@@ -45,13 +45,7 @@ const withThemeProvider = (Story, context) => {
45
45
  <QueryClientProvider client={new QueryClient()}>
46
46
  <CoreUiThemeProvider theme={theme}>
47
47
  {/* Wrapper to make the stories take the full screen but not in docs */}
48
- <div
49
- style={
50
- viewMode === 'story'
51
- ? { height: 100 + 'vh', overflow: 'scroll' }
52
- : null
53
- }
54
- >
48
+ <div style={viewMode === 'story' ? { height: 100 + 'vh' } : null}>
55
49
  <ToastProvider>
56
50
  <Wrapper style={{ backgroundColor: background }}>
57
51
  <Story {...context} />
@@ -1 +1 @@
1
- {"version":3,"file":"Form.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/form/Form.component.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,kBAAkB,EAGlB,YAAY,EACZ,SAAS,EAKV,MAAM,OAAO,CAAC;AAKf,OAAO,EAAQ,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAKxD,QAAA,MAAM,kBAAkB,cAAc,CAAC;AACvC,QAAA,MAAM,YAAY,WAAW,CAAC;AAG9B,KAAK,SAAS,GAAG,IAAI,CACnB,kBAAkB,CAAC,eAAe,CAAC,EACnC,YAAY,GAAG,gBAAgB,CAChC,GAAG;IACF,QAAQ,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IAChC,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,QAAQ,CAAC;KACjB,CAAC;CACH,GAAG,SAAS,CAAC;AACd,KAAK,YAAY,GAAG;IAAE,MAAM,EAAE;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAA;CAAE,GAAG,SAAS,CAAC;AAyD5D,KAAK,YAAY,GAAG;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IACtC,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,QAAA,MAAM,SAAS,6GAWZ,cAAc,4CAqGhB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,QAAQ,EAAE,YAAY,CAAC,cAAc,CAAC,GAAG,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IACxE,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAChE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,SAAS,CAAC;CAC1B,CAAC;AAEF,QAAA,MAAM,WAAW,wDAKd,gBAAgB,4CAmClB,CAAC;AAgGF,QAAA,MAAM,IAAI,4HAYT,CAAC;AASF,QAAA,MAAM,eAAe;;YANX,MAAM;eACH,OAAO;eACP,OAAO;CAWnB,CAAC;AAEF,OAAO,EACL,IAAI,EACJ,WAAW,EACX,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,YAAY,GACb,CAAC"}
1
+ {"version":3,"file":"Form.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/form/Form.component.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,kBAAkB,EAGlB,YAAY,EACZ,SAAS,EAKV,MAAM,OAAO,CAAC;AAKf,OAAO,EAAQ,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAKxD,QAAA,MAAM,kBAAkB,cAAc,CAAC;AACvC,QAAA,MAAM,YAAY,WAAW,CAAC;AAG9B,KAAK,SAAS,GAAG,IAAI,CACnB,kBAAkB,CAAC,eAAe,CAAC,EACnC,YAAY,GAAG,gBAAgB,CAChC,GAAG;IACF,QAAQ,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IAChC,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,QAAQ,CAAC;KACjB,CAAC;CACH,GAAG,SAAS,CAAC;AACd,KAAK,YAAY,GAAG;IAAE,MAAM,EAAE;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAA;CAAE,GAAG,SAAS,CAAC;AAyD5D,KAAK,YAAY,GAAG;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IACtC,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,QAAA,MAAM,SAAS,6GAWZ,cAAc,4CAyGhB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,QAAQ,EAAE,YAAY,CAAC,cAAc,CAAC,GAAG,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IACxE,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAChE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,SAAS,CAAC;CAC1B,CAAC;AAEF,QAAA,MAAM,WAAW,wDAKd,gBAAgB,4CAmClB,CAAC;AAgGF,QAAA,MAAM,IAAI,4HAYT,CAAC;AASF,QAAA,MAAM,eAAe;;YANX,MAAM;eACH,OAAO;eACP,OAAO;CAWnB,CAAC;AAEF,OAAO,EACL,IAAI,EACJ,WAAW,EACX,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,YAAY,GACb,CAAC"}
@@ -80,7 +80,7 @@ const FormGroup = ({ direction = 'horizontal', label, id, labelHelpTooltip, cont
80
80
  return (_jsx(FieldContext.Provider, { value: value, children: _jsxs(Box, { display: "flex", flexDirection: direction === 'horizontal' ? 'row' : 'column', alignItems: "baseline", gap: direction === 'horizontal' ? spacing['r32'] : spacing['r4'], children: [_jsx("div", { style: {
81
81
  width: maxLabelWidth === 0 ? 'max-content' : `${maxLabelWidth}px`,
82
82
  flex: 'none',
83
- }, children: _jsxs(Stack, { children: [_jsx("label", { htmlFor: id, id: `${LABEL_PREFIX}${id}`, ref: labelRef, style: { opacity: disabled ? 0.5 : 1 }, children: _jsxs(Text, { children: [label, requireMode !== 'all' && required && ' *', requireMode === 'all' && !required && ' (optional)'] }) }), labelHelpTooltip && (_jsx(IconHelp, { tooltipMessage: labelHelpTooltip, overlayStyle: maxWidthTooltip }))] }) }), _jsxs(Stack, { direction: helpErrorPosition === 'right' ? 'horizontal' : 'vertical', gap: helpErrorPosition === 'right' ? 'r8' : 'r4', children: [content, error ? (_jsx(Text, { variant: "Smaller", color: "statusCritical", isEmphazed: true, id: `${DESCRIPTION_PREFIX}${id}`, children: error })) : help ? (_jsx("div", { style: {
83
+ }, children: _jsxs("label", { htmlFor: id, id: `${LABEL_PREFIX}${id}`, ref: labelRef, style: { opacity: disabled ? 0.5 : 1 }, children: [_jsxs(Text, { children: [label, requireMode !== 'all' && required && ' *', requireMode === 'all' && !required && ' (optional)'] }), labelHelpTooltip && (_jsx(Box, { display: "inline-block", marginLeft: spacing.r8, style: { whiteSpace: 'nowrap' }, children: _jsx(IconHelp, { tooltipMessage: labelHelpTooltip, overlayStyle: maxWidthTooltip }) }))] }) }), _jsxs(Stack, { direction: helpErrorPosition === 'right' ? 'horizontal' : 'vertical', gap: helpErrorPosition === 'right' ? 'r8' : 'r4', children: [content, error ? (_jsx(Text, { variant: "Smaller", color: "statusCritical", isEmphazed: true, id: `${DESCRIPTION_PREFIX}${id}`, children: error })) : help ? (_jsx("div", { style: {
84
84
  opacity: disabled ? 0.5 : 1,
85
85
  }, children: _jsx(Text, { variant: "Smaller", color: "textSecondary", isEmphazed: true, id: `${DESCRIPTION_PREFIX}${id}`, children: help }) })) : (_jsx(Text, { variant: "Smaller", isEmphazed: true, children: "\u00A0" }))] })] }) }));
86
86
  };
@@ -10,6 +10,7 @@ export type SingleSelectableContentProps<DATA_ROW extends Record<string, unknown
10
10
  hasScrollbar?: boolean;
11
11
  isLoadingMoreItems?: boolean;
12
12
  children?: (rows: JSX.Element) => JSX.Element;
13
+ autoScrollToSelected?: boolean;
13
14
  };
14
- export declare function SingleSelectableContent<DATA_ROW extends Record<string, unknown> = Record<string, unknown>>({ rowHeight, separationLineVariant, locale, selectedId, isLoadingMoreItems, onRowSelected, customItemKey, children, }: SingleSelectableContentProps<DATA_ROW>): import("react/jsx-runtime").JSX.Element;
15
+ export declare function SingleSelectableContent<DATA_ROW extends Record<string, unknown> = Record<string, unknown>>({ rowHeight, separationLineVariant, locale, selectedId, isLoadingMoreItems, onRowSelected, customItemKey, children, autoScrollToSelected, }: SingleSelectableContentProps<DATA_ROW>): import("react/jsx-runtime").JSX.Element;
15
16
  //# sourceMappingURL=SingleSelectableContent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SingleSelectableContent.d.ts","sourceRoot":"","sources":["../../../src/lib/components/tablev2/SingleSelectableContent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AASlC,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EACjB,MAAM,cAAc,CAAC;AAOtB,MAAM,MAAM,4BAA4B,CACtC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAChE;IACF,SAAS,EAAE,kBAAkB,CAAC;IAC9B,qBAAqB,EAAE,gBAAgB,CAAC;IAExC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,KAAK,MAAM,CAAC;IAC1D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,CAAC;CAC/C,CAAC;AAEF,wBAAgB,uBAAuB,CACrC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,EACA,SAAiB,EACjB,qBAA0C,EAE1C,MAAa,EACb,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,QAAQ,GACT,EAAE,4BAA4B,CAAC,QAAQ,CAAC,2CAmJxC"}
1
+ {"version":3,"file":"SingleSelectableContent.d.ts","sourceRoot":"","sources":["../../../src/lib/components/tablev2/SingleSelectableContent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AASlC,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EACjB,MAAM,cAAc,CAAC;AAOtB,MAAM,MAAM,4BAA4B,CACtC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAChE;IACF,SAAS,EAAE,kBAAkB,CAAC;IAC9B,qBAAqB,EAAE,gBAAgB,CAAC;IAExC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,KAAK,MAAM,CAAC;IAC1D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,CAAC;IAC9C,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,wBAAgB,uBAAuB,CACrC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,EACA,SAAiB,EACjB,qBAA0C,EAE1C,MAAa,EACb,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,QAAQ,EACR,oBAA4B,GAC7B,EAAE,4BAA4B,CAAC,QAAQ,CAAC,2CAmKxC"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { memo, useEffect } from 'react';
2
+ import { memo, useEffect, useRef } from 'react';
3
3
  import { areEqual } from 'react-window';
4
4
  import { useTableContext } from './Tablev2.component';
5
5
  import { HeadRow, TableRow, TableBody, TableHeader, SortCaret, } from './Tablestyle';
@@ -8,15 +8,29 @@ import useSyncedScroll from './useSyncedScroll';
8
8
  import { Loader } from '../loader/Loader.component';
9
9
  import { Box } from '../box/Box';
10
10
  import { spacing } from '../../spacing';
11
- export function SingleSelectableContent({ rowHeight = 'h40', separationLineVariant = 'backgroundLevel3', locale = 'en', selectedId, isLoadingMoreItems, onRowSelected, customItemKey, children, }) {
11
+ export function SingleSelectableContent({ rowHeight = 'h40', separationLineVariant = 'backgroundLevel3', locale = 'en', selectedId, isLoadingMoreItems, onRowSelected, customItemKey, children, autoScrollToSelected = false, }) {
12
12
  if (selectedId && !onRowSelected) {
13
13
  console.error('Please specify the onRowSelected function.');
14
14
  }
15
15
  const { headerRef } = useSyncedScroll();
16
+ const listRef = useRef(null);
16
17
  const { headerGroups, prepareRow, rows, setRowHeight } = useTableContext();
17
18
  useEffect(() => {
18
19
  setRowHeight(rowHeight);
19
20
  }, [rowHeight, setRowHeight]);
21
+ useEffect(() => {
22
+ if (!autoScrollToSelected || !selectedId || !listRef.current)
23
+ return;
24
+ const selectedIndex = rows.findIndex((row) => row.id === selectedId);
25
+ if (selectedIndex < 0)
26
+ return;
27
+ const timer = setTimeout(() => {
28
+ if (!listRef.current)
29
+ return;
30
+ listRef.current.scrollToItem(selectedIndex, 'center');
31
+ }, 100);
32
+ return () => clearTimeout(timer);
33
+ }, [autoScrollToSelected, selectedId, rows]);
20
34
  const RenderRow = memo(({ index, style }) => {
21
35
  const row = rows[index];
22
36
  prepareRow(row);
@@ -76,5 +90,5 @@ export function SingleSelectableContent({ rowHeight = 'h40', separationLineVaria
76
90
  headerStyleProps.onClick(event);
77
91
  }
78
92
  }, children: _jsxs("div", { children: [column.render('Header'), _jsx(SortCaret, { column: column })] }) }));
79
- }) }))) }), _jsx(TableBody, { role: "rowgroup", className: "tbody", ref: handleScrollbarWidth, children: _jsx(TableRows, { locale: locale, children: children, customItemKey: customItemKey, RenderRow: RenderRow }) }), isLoadingMoreItems && (_jsx(Box, { display: "flex", justifyContent: "center", marginTop: spacing.r16, marginBottom: spacing.r16, children: _jsx(Loader, { size: "large" }) }))] }));
93
+ }) }))) }), _jsx(TableBody, { role: "rowgroup", className: "tbody", ref: handleScrollbarWidth, children: _jsx(TableRows, { locale: locale, children: children, customItemKey: customItemKey, RenderRow: RenderRow, listRef: listRef }) }), isLoadingMoreItems && (_jsx(Box, { display: "flex", justifyContent: "center", marginTop: spacing.r16, marginBottom: spacing.r16, children: _jsx(Loader, { size: "large" }) }))] }));
80
94
  }
@@ -1,4 +1,4 @@
1
- import { ComponentType, LegacyRef } from 'react';
1
+ import { ComponentType, Ref } from 'react';
2
2
  import { Row } from 'react-table';
3
3
  import { FixedSizeList, ListChildComponentProps, ListItemKeySelector } from 'react-window';
4
4
  import { TableHeightKeyType, TableLocalType } from './TableUtils';
@@ -12,7 +12,7 @@ type VirtualizedRowsType<DATA_ROW extends Record<string, unknown> = Record<strin
12
12
  itemKey?: ListItemKeySelector<Row<DATA_ROW>[]>;
13
13
  onBottom?: (rowLength: number) => void;
14
14
  onBottomOffset?: number;
15
- listRef?: LegacyRef<FixedSizeList<Row<DATA_ROW>[]>>;
15
+ listRef?: Ref<FixedSizeList<Row<DATA_ROW>[]>>;
16
16
  };
17
17
  export declare const VirtualizedRows: <DATA_ROW extends Record<string, unknown> = Record<string, unknown>>({ rows, rowHeight, setHasScrollbar, onBottom, onBottomOffset, RenderRow, listRef, itemKey, }: VirtualizedRowsType<DATA_ROW>) => import("react/jsx-runtime").JSX.Element;
18
18
  export declare const useTableScrollbar: () => {
@@ -30,7 +30,8 @@ type TableRowsProps<DATA_ROW extends Record<string, unknown> = Record<string, un
30
30
  children?: (children: JSX.Element) => JSX.Element;
31
31
  customItemKey?: (index: number, data: DATA_ROW) => string;
32
32
  RenderRow: React.MemoExoticComponent<({ index, style }: RenderRowType) => JSX.Element>;
33
+ listRef?: Ref<FixedSizeList<Row<DATA_ROW>[]>>;
33
34
  };
34
- export declare function TableRows<DATA_ROW extends Record<string, unknown> = Record<string, unknown>>({ locale, children, customItemKey, RenderRow }: TableRowsProps<DATA_ROW>): import("react/jsx-runtime").JSX.Element | null;
35
+ export declare function TableRows<DATA_ROW extends Record<string, unknown> = Record<string, unknown>>({ locale, children, customItemKey, RenderRow, listRef: externalListRef, }: TableRowsProps<DATA_ROW>): import("react/jsx-runtime").JSX.Element | null;
35
36
  export {};
36
37
  //# sourceMappingURL=TableCommon.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TableCommon.d.ts","sourceRoot":"","sources":["../../../src/lib/components/tablev2/TableCommon.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAyB,MAAM,OAAO,CAAC;AACxE,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,OAAO,EACL,aAAa,EAEb,uBAAuB,EACvB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAEL,kBAAkB,EAClB,cAAc,EAEf,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlD,KAAK,mBAAmB,CACtB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAChE;IACF,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;IACtB,SAAS,EAAE,aAAa,CACtB,KAAK,CAAC,iBAAiB,CAAC,uBAAuB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAClE,CAAC;IACF,SAAS,EAAE,kBAAkB,CAAC;IAC9B,eAAe,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC/C,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,SAAS,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;CACrD,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,0HAUvC,mBAAmB,CAAC,QAAQ,CAAC,4CAmC/B,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;;;CAwB7B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,aAAa,CAAC;CACtB,CAAC;AAEF,KAAK,cAAc,CACjB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAChE;IACF,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,CAAC;IAClD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,KAAK,MAAM,CAAC;IAC1D,SAAS,EAAE,KAAK,CAAC,mBAAmB,CAClC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,aAAa,KAAK,GAAG,CAAC,OAAO,CACjD,CAAC;CACH,CAAC;AACF,wBAAgB,SAAS,CACvB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,EAAE,cAAc,CAAC,QAAQ,CAAC,kDAyEzE"}
1
+ {"version":3,"file":"TableCommon.d.ts","sourceRoot":"","sources":["../../../src/lib/components/tablev2/TableCommon.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,GAAG,EAAqC,MAAM,OAAO,CAAC;AAC9E,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,OAAO,EACL,aAAa,EAEb,uBAAuB,EACvB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAEL,kBAAkB,EAClB,cAAc,EAEf,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAWlD,KAAK,mBAAmB,CACtB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAChE;IACF,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;IACtB,SAAS,EAAE,aAAa,CACtB,KAAK,CAAC,iBAAiB,CAAC,uBAAuB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAClE,CAAC;IACF,SAAS,EAAE,kBAAkB,CAAC;IAC9B,eAAe,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC/C,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;CAC/C,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,0HAUvC,mBAAmB,CAAC,QAAQ,CAAC,4CAoC/B,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;;;CAwB7B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,aAAa,CAAC;CACtB,CAAC;AAEF,KAAK,cAAc,CACjB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAChE;IACF,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,CAAC;IAClD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,KAAK,MAAM,CAAC;IAC1D,SAAS,EAAE,KAAK,CAAC,mBAAmB,CAClC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,aAAa,KAAK,GAAG,CAAC,OAAO,CACjD,CAAC;IACF,OAAO,CAAC,EAAE,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;CAC/C,CAAC;AACF,wBAAgB,SAAS,CACvB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,EACA,MAAM,EACN,QAAQ,EACR,aAAa,EACb,SAAS,EACT,OAAO,EAAE,eAAe,GACzB,EAAE,cAAc,CAAC,QAAQ,CAAC,kDA2E1B"}
@@ -1,13 +1,14 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useCallback, useState } from 'react';
2
+ import { useCallback, useState, forwardRef } from 'react';
3
3
  import AutoSizer from 'react-virtualized-auto-sizer';
4
4
  import { FixedSizeList as List, } from 'react-window';
5
5
  import { convertRemToPixels, tableRowHeight, } from './TableUtils';
6
6
  import { useTableContext } from './Tablev2.component';
7
7
  import useSyncedScroll from './useSyncedScroll';
8
8
  import { UnsuccessfulResult } from '../UnsuccessfulResult.component';
9
+ const SmoothScrollDiv = forwardRef((props, ref) => (_jsx("div", { ref: ref, ...props, style: { ...props.style, scrollBehavior: 'smooth' } })));
9
10
  export const VirtualizedRows = ({ rows, rowHeight, setHasScrollbar, onBottom, onBottomOffset, RenderRow, listRef, itemKey, }) => (_jsx(AutoSizer, { disableWidth: true, children: ({ height }) => {
10
- return (_jsx(List, { height: height - 1, itemCount: rows.length, itemSize: convertRemToPixels(tableRowHeight[rowHeight]), width: '100%', itemKey: itemKey, itemData: rows, ref: listRef, onItemsRendered: ({ visibleStartIndex, visibleStopIndex, overscanStopIndex, }) => {
11
+ return (_jsx(List, { height: height - 1, itemCount: rows.length, itemSize: convertRemToPixels(tableRowHeight[rowHeight]), width: '100%', itemKey: itemKey, itemData: rows, ref: listRef, outerElementType: SmoothScrollDiv, onItemsRendered: ({ visibleStartIndex, visibleStopIndex, overscanStopIndex, }) => {
11
12
  setHasScrollbar(visibleStopIndex - visibleStartIndex < overscanStopIndex);
12
13
  if (onBottom &&
13
14
  onBottomOffset != null &&
@@ -36,10 +37,11 @@ export const useTableScrollbar = () => {
36
37
  handleScrollbarWidth,
37
38
  };
38
39
  };
39
- export function TableRows({ locale, children, customItemKey, RenderRow }) {
40
+ export function TableRows({ locale, children, customItemKey, RenderRow, listRef: externalListRef, }) {
40
41
  const { setHasScrollbar } = useTableScrollbar();
41
42
  const { rows, status, entityName, rowHeight, onBottom, onBottomOffset } = useTableContext();
42
43
  const { bodyRef } = useSyncedScroll();
44
+ const listRef = externalListRef || bodyRef;
43
45
  function itemKey(index, data) {
44
46
  if (typeof customItemKey === 'function') {
45
47
  return customItemKey(index, data);
@@ -52,14 +54,14 @@ export function TableRows({ locale, children, customItemKey, RenderRow }) {
52
54
  if (status === 'success' || status === undefined) {
53
55
  if (typeof children === 'function') {
54
56
  if (rows.length) {
55
- return children(_jsx(VirtualizedRows, { rows: rows, listRef: bodyRef, itemKey: itemKey, rowHeight: rowHeight, setHasScrollbar: setHasScrollbar, onBottom: onBottom, onBottomOffset: onBottomOffset, RenderRow: RenderRow }));
57
+ return children(_jsx(VirtualizedRows, { rows: rows, listRef: listRef, itemKey: itemKey, rowHeight: rowHeight, setHasScrollbar: setHasScrollbar, onBottom: onBottom, onBottomOffset: onBottomOffset, RenderRow: RenderRow }));
56
58
  }
57
59
  else {
58
60
  return children(_jsx(UnsuccessfulResult, { rowHeight: rowHeight, name: entityName, status: "noResult" }));
59
61
  }
60
62
  }
61
63
  else if (rows.length) {
62
- return (_jsx(VirtualizedRows, { rows: rows, listRef: bodyRef, setHasScrollbar: setHasScrollbar, onBottom: onBottom, onBottomOffset: onBottomOffset, itemKey: itemKey, rowHeight: rowHeight, RenderRow: RenderRow }));
64
+ return (_jsx(VirtualizedRows, { rows: rows, listRef: listRef, setHasScrollbar: setHasScrollbar, onBottom: onBottom, onBottomOffset: onBottomOffset, itemKey: itemKey, rowHeight: rowHeight, RenderRow: RenderRow }));
63
65
  }
64
66
  else {
65
67
  return (_jsx(UnsuccessfulResult, { rowHeight: rowHeight, name: entityName, status: "noResult" }));
@@ -1 +1 @@
1
- {"version":3,"file":"Tooltip.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/tooltip/Tooltip.component.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAA+B,MAAM,OAAO,CAAC;AAKnE,eAAO,MAAM,GAAG,QAAQ,CAAC;AACzB,eAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,eAAO,MAAM,IAAI,SAAS,CAAC;AAC3B,eAAO,MAAM,QAAQ,cAAc,CAAC;AACpC,eAAO,MAAM,MAAM,YAAY,CAAC;AAChC,eAAO,MAAM,KAAK,UAAU,CAAC;AAC7B,eAAO,MAAM,UAAU,gBAAgB,CAAC;AACxC,eAAO,MAAM,QAAQ,cAAc,CAAC;AACpC,eAAO,MAAM,SAAS,eAAe,CAAC;AACtC,eAAO,MAAM,WAAW,iBAAiB,CAAC;AAC1C,eAAO,MAAM,SAAS,eAAe,CAAC;AACtC,eAAO,MAAM,OAAO,aAAa,CAAC;AAClC,MAAM,MAAM,QAAQ,GAChB,OAAO,GAAG,GACV,OAAO,MAAM,GACb,OAAO,IAAI,GACX,OAAO,KAAK,GACZ,OAAO,QAAQ,GACf,OAAO,MAAM,GACb,OAAO,UAAU,GACjB,OAAO,QAAQ,GACf,OAAO,SAAS,GAChB,OAAO,WAAW,GAClB,OAAO,OAAO,GACd,OAAO,SAAS,CAAC;AACrB,MAAM,MAAM,KAAK,GAAG;IAClB,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AA4CF,iBAAS,OAAO,CAAC,EACf,SAAe,EACf,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,GAAG,IAAI,EACR,EAAE,KAAK,2CA+CP;AAED,OAAO,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"Tooltip.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/tooltip/Tooltip.component.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAY,MAAM,OAAO,CAAC;AAMhD,eAAO,MAAM,GAAG,QAAQ,CAAC;AACzB,eAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,eAAO,MAAM,IAAI,SAAS,CAAC;AAC3B,eAAO,MAAM,QAAQ,cAAc,CAAC;AACpC,eAAO,MAAM,MAAM,YAAY,CAAC;AAChC,eAAO,MAAM,KAAK,UAAU,CAAC;AAC7B,eAAO,MAAM,UAAU,gBAAgB,CAAC;AACxC,eAAO,MAAM,QAAQ,cAAc,CAAC;AACpC,eAAO,MAAM,SAAS,eAAe,CAAC;AACtC,eAAO,MAAM,WAAW,iBAAiB,CAAC;AAC1C,eAAO,MAAM,SAAS,eAAe,CAAC;AACtC,eAAO,MAAM,OAAO,aAAa,CAAC;AAClC,MAAM,MAAM,QAAQ,GAChB,OAAO,GAAG,GACV,OAAO,MAAM,GACb,OAAO,IAAI,GACX,OAAO,KAAK,GACZ,OAAO,QAAQ,GACf,OAAO,MAAM,GACb,OAAO,UAAU,GACjB,OAAO,QAAQ,GACf,OAAO,SAAS,GAChB,OAAO,WAAW,GAClB,OAAO,OAAO,GACd,OAAO,SAAS,CAAC;AACrB,MAAM,MAAM,KAAK,GAAG;IAClB,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AA0CF,iBAAS,OAAO,CAAC,EACf,SAAe,EACf,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,GAAG,IAAI,EACR,EAAE,KAAK,2CAsCP;AAED,OAAO,EAAE,OAAO,EAAE,CAAC"}
@@ -1,6 +1,7 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { computePosition, flip, offset, shift } from '@floating-ui/dom';
3
- import { useEffect, useRef, useState } from 'react';
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { flip, offset, shift, useFloating } from '@floating-ui/react';
3
+ import { useState } from 'react';
4
+ import { createPortal } from 'react-dom';
4
5
  import styled from 'styled-components';
5
6
  import { spacing } from '../../spacing';
6
7
  import { fontSize, zIndex } from '../../style/theme';
@@ -23,8 +24,6 @@ const TooltipContainer = styled.div `
23
24
  `;
24
25
  const TooltipOverLayContainer = styled.div `
25
26
  display: inline-block;
26
- opacity: 0;
27
- position: fixed;
28
27
  width: max-content;
29
28
  border: 1px solid ${getThemePropSelector('border')};
30
29
  background-color: ${(props) => (props && props.style && props.style.backgroundColor) ||
@@ -53,30 +52,18 @@ const TooltipText = styled.div `
53
52
  }
54
53
  `;
55
54
  function Tooltip({ placement = TOP, overlayStyle, children, overlay, ...rest }) {
56
- const childrenRef = useRef(null);
57
- const tooltipRef = useRef(null);
58
55
  const [isTooltipVisible, setIsTooltipVisible] = useState(false);
59
- useEffect(() => {
60
- if (childrenRef.current && tooltipRef.current) {
61
- computePosition(childrenRef.current, tooltipRef.current, {
62
- placement,
63
- middleware: [offset(5), shift(), flip()],
64
- }).then(({ x, y }) => {
65
- if (tooltipRef.current) {
66
- Object.assign(tooltipRef.current.style, {
67
- opacity: '1',
68
- // we set opacity to 1 to make sure the tooltip is not displayed before the position is computed
69
- left: `${x}px`,
70
- top: `${y}px`,
71
- });
72
- }
73
- });
74
- }
75
- }, [tooltipRef.current, childrenRef.current, isTooltipVisible]);
76
- return (_jsxs(TooltipContainer, { className: "sc-tooltip", onPointerEnter: () => {
77
- setIsTooltipVisible(true);
78
- }, onPointerLeave: () => {
79
- setIsTooltipVisible(false);
80
- }, children: [isTooltipVisible && overlay ? (_jsx(TooltipOverLayContainer, { ref: tooltipRef, className: "sc-tooltip-overlay", placement: placement, style: overlayStyle, children: _jsx(TooltipText, { className: "sc-tooltip-overlay-text", children: overlay }) })) : null, _jsx("div", { ref: childrenRef, children: children })] }));
56
+ const { refs, floatingStyles } = useFloating({
57
+ placement,
58
+ open: isTooltipVisible,
59
+ middleware: [offset(5), shift(), flip()],
60
+ });
61
+ return (_jsxs(_Fragment, { children: [_jsx(TooltipContainer, { className: "sc-tooltip", onPointerEnter: () => {
62
+ setIsTooltipVisible(true);
63
+ }, onPointerLeave: () => {
64
+ setIsTooltipVisible(false);
65
+ }, children: _jsx("div", { ref: refs.setReference, children: children }) }), isTooltipVisible &&
66
+ overlay &&
67
+ createPortal(_jsx(TooltipOverLayContainer, { ref: refs.setFloating, className: "sc-tooltip-overlay", placement: placement, style: { ...floatingStyles, ...overlayStyle }, children: _jsx(TooltipText, { className: "sc-tooltip-overlay-text", children: overlay }) }), document.body)] }));
81
68
  }
82
69
  export { Tooltip };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scality/core-ui",
3
- "version": "0.184.0",
3
+ "version": "0.186.0",
4
4
  "description": "Scality common React component library",
5
5
  "author": "Scality Engineering",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -171,26 +171,30 @@ const FormGroup = ({
171
171
  flex: 'none',
172
172
  }}
173
173
  >
174
- <Stack>
175
- <label
176
- htmlFor={id}
177
- id={`${LABEL_PREFIX}${id}`}
178
- ref={labelRef}
179
- style={{ opacity: disabled ? 0.5 : 1 }}
180
- >
181
- <Text>
182
- {label}
183
- {requireMode !== 'all' && required && ' *'}
184
- {requireMode === 'all' && !required && ' (optional)'}
185
- </Text>
186
- </label>
174
+ <label
175
+ htmlFor={id}
176
+ id={`${LABEL_PREFIX}${id}`}
177
+ ref={labelRef}
178
+ style={{ opacity: disabled ? 0.5 : 1 }}
179
+ >
180
+ <Text>
181
+ {label}
182
+ {requireMode !== 'all' && required && ' *'}
183
+ {requireMode === 'all' && !required && ' (optional)'}
184
+ </Text>
187
185
  {labelHelpTooltip && (
188
- <IconHelp
189
- tooltipMessage={labelHelpTooltip}
190
- overlayStyle={maxWidthTooltip}
191
- />
186
+ <Box
187
+ display="inline-block"
188
+ marginLeft={spacing.r8}
189
+ style={{ whiteSpace: 'nowrap' }}
190
+ >
191
+ <IconHelp
192
+ tooltipMessage={labelHelpTooltip}
193
+ overlayStyle={maxWidthTooltip}
194
+ />
195
+ </Box>
192
196
  )}
193
- </Stack>
197
+ </label>
194
198
  </div>
195
199
  <Stack
196
200
  direction={helpErrorPosition === 'right' ? 'horizontal' : 'vertical'}
@@ -1,5 +1,5 @@
1
- import { memo, useEffect } from 'react';
2
- import { areEqual } from 'react-window';
1
+ import { memo, useEffect, useRef } from 'react';
2
+ import { areEqual, FixedSizeList } from 'react-window';
3
3
  import { Row } from 'react-table';
4
4
  import { useTableContext } from './Tablev2.component';
5
5
  import {
@@ -33,6 +33,7 @@ export type SingleSelectableContentProps<
33
33
  hasScrollbar?: boolean;
34
34
  isLoadingMoreItems?: boolean;
35
35
  children?: (rows: JSX.Element) => JSX.Element;
36
+ autoScrollToSelected?: boolean;
36
37
  };
37
38
 
38
39
  export function SingleSelectableContent<
@@ -47,12 +48,14 @@ export function SingleSelectableContent<
47
48
  onRowSelected,
48
49
  customItemKey,
49
50
  children,
51
+ autoScrollToSelected = false,
50
52
  }: SingleSelectableContentProps<DATA_ROW>) {
51
53
  if (selectedId && !onRowSelected) {
52
54
  console.error('Please specify the onRowSelected function.');
53
55
  }
54
56
 
55
57
  const { headerRef } = useSyncedScroll<DATA_ROW>();
58
+ const listRef = useRef<FixedSizeList<Row<DATA_ROW>[]>>(null);
56
59
  const { headerGroups, prepareRow, rows, setRowHeight } =
57
60
  useTableContext<DATA_ROW>();
58
61
 
@@ -60,6 +63,20 @@ export function SingleSelectableContent<
60
63
  setRowHeight(rowHeight);
61
64
  }, [rowHeight, setRowHeight]);
62
65
 
66
+ useEffect(() => {
67
+ if (!autoScrollToSelected || !selectedId || !listRef.current) return;
68
+
69
+ const selectedIndex = rows.findIndex((row) => row.id === selectedId);
70
+ if (selectedIndex < 0) return;
71
+
72
+ const timer = setTimeout(() => {
73
+ if (!listRef.current) return;
74
+ listRef.current.scrollToItem(selectedIndex, 'center');
75
+ }, 100);
76
+
77
+ return () => clearTimeout(timer);
78
+ }, [autoScrollToSelected, selectedId, rows]);
79
+
63
80
  const RenderRow = memo(({ index, style }: RenderRowType) => {
64
81
  const row = rows[index];
65
82
  prepareRow(row);
@@ -180,6 +197,7 @@ export function SingleSelectableContent<
180
197
  children={children}
181
198
  customItemKey={customItemKey}
182
199
  RenderRow={RenderRow}
200
+ listRef={listRef}
183
201
  />
184
202
  </TableBody>
185
203
  {isLoadingMoreItems && (
@@ -1,4 +1,4 @@
1
- import { ComponentType, LegacyRef, useCallback, useState } from 'react';
1
+ import { ComponentType, Ref, useCallback, useState, forwardRef } from 'react';
2
2
  import { Row } from 'react-table';
3
3
  import AutoSizer from 'react-virtualized-auto-sizer';
4
4
  import {
@@ -18,6 +18,14 @@ import useSyncedScroll from './useSyncedScroll';
18
18
  import { CSSProperties } from 'styled-components';
19
19
  import { UnsuccessfulResult } from '../UnsuccessfulResult.component';
20
20
 
21
+ const SmoothScrollDiv = forwardRef<HTMLDivElement, any>((props, ref) => (
22
+ <div
23
+ ref={ref}
24
+ {...props}
25
+ style={{ ...props.style, scrollBehavior: 'smooth' }}
26
+ />
27
+ ));
28
+
21
29
  type VirtualizedRowsType<
22
30
  DATA_ROW extends Record<string, unknown> = Record<string, unknown>,
23
31
  > = {
@@ -31,7 +39,7 @@ type VirtualizedRowsType<
31
39
  itemKey?: ListItemKeySelector<Row<DATA_ROW>[]>;
32
40
  onBottom?: (rowLength: number) => void;
33
41
  onBottomOffset?: number;
34
- listRef?: LegacyRef<FixedSizeList<Row<DATA_ROW>[]>>;
42
+ listRef?: Ref<FixedSizeList<Row<DATA_ROW>[]>>;
35
43
  };
36
44
 
37
45
  export const VirtualizedRows = <
@@ -57,6 +65,7 @@ export const VirtualizedRows = <
57
65
  itemKey={itemKey}
58
66
  itemData={rows}
59
67
  ref={listRef}
68
+ outerElementType={SmoothScrollDiv}
60
69
  onItemsRendered={({
61
70
  visibleStartIndex,
62
71
  visibleStopIndex,
@@ -122,14 +131,23 @@ type TableRowsProps<
122
131
  RenderRow: React.MemoExoticComponent<
123
132
  ({ index, style }: RenderRowType) => JSX.Element
124
133
  >;
134
+ listRef?: Ref<FixedSizeList<Row<DATA_ROW>[]>>;
125
135
  };
126
136
  export function TableRows<
127
137
  DATA_ROW extends Record<string, unknown> = Record<string, unknown>,
128
- >({ locale, children, customItemKey, RenderRow }: TableRowsProps<DATA_ROW>) {
138
+ >({
139
+ locale,
140
+ children,
141
+ customItemKey,
142
+ RenderRow,
143
+ listRef: externalListRef,
144
+ }: TableRowsProps<DATA_ROW>) {
129
145
  const { setHasScrollbar } = useTableScrollbar();
130
146
  const { rows, status, entityName, rowHeight, onBottom, onBottomOffset } =
131
- useTableContext();
132
- const { bodyRef } = useSyncedScroll();
147
+ useTableContext<DATA_ROW>();
148
+ const { bodyRef } = useSyncedScroll<DATA_ROW>();
149
+ const listRef: Ref<FixedSizeList<Row<DATA_ROW>[]>> =
150
+ externalListRef || bodyRef;
133
151
 
134
152
  function itemKey(index, data) {
135
153
  if (typeof customItemKey === 'function') {
@@ -153,9 +171,9 @@ export function TableRows<
153
171
  if (typeof children === 'function') {
154
172
  if (rows.length) {
155
173
  return children(
156
- <VirtualizedRows
174
+ <VirtualizedRows<DATA_ROW>
157
175
  rows={rows}
158
- listRef={bodyRef}
176
+ listRef={listRef}
159
177
  itemKey={itemKey}
160
178
  rowHeight={rowHeight}
161
179
  setHasScrollbar={setHasScrollbar}
@@ -175,9 +193,9 @@ export function TableRows<
175
193
  }
176
194
  } else if (rows.length) {
177
195
  return (
178
- <VirtualizedRows
196
+ <VirtualizedRows<DATA_ROW>
179
197
  rows={rows}
180
- listRef={bodyRef}
198
+ listRef={listRef}
181
199
  setHasScrollbar={setHasScrollbar}
182
200
  onBottom={onBottom}
183
201
  onBottomOffset={onBottomOffset}
@@ -1,5 +1,6 @@
1
- import { computePosition, flip, offset, shift } from '@floating-ui/dom';
2
- import { CSSProperties, useEffect, useRef, useState } from 'react';
1
+ import { flip, offset, shift, useFloating } from '@floating-ui/react';
2
+ import { CSSProperties, useState } from 'react';
3
+ import { createPortal } from 'react-dom';
3
4
  import styled from 'styled-components';
4
5
  import { spacing } from '../../spacing';
5
6
  import { fontSize, zIndex } from '../../style/theme';
@@ -44,8 +45,6 @@ const TooltipOverLayContainer = styled.div<{
44
45
  style?: CSSProperties;
45
46
  }>`
46
47
  display: inline-block;
47
- opacity: 0;
48
- position: fixed;
49
48
  width: max-content;
50
49
  border: 1px solid ${getThemePropSelector('border')};
51
50
  background-color: ${(props) =>
@@ -85,51 +84,42 @@ function Tooltip({
85
84
  overlay,
86
85
  ...rest
87
86
  }: Props) {
88
- const childrenRef = useRef<HTMLDivElement | null>(null);
89
- const tooltipRef = useRef<HTMLDivElement | null>(null);
90
-
91
87
  const [isTooltipVisible, setIsTooltipVisible] = useState(false);
92
- useEffect(() => {
93
- if (childrenRef.current && tooltipRef.current) {
94
- computePosition(childrenRef.current, tooltipRef.current, {
95
- placement,
96
- middleware: [offset(5), shift(), flip()],
97
- }).then(({ x, y }) => {
98
- if (tooltipRef.current) {
99
- Object.assign(tooltipRef.current.style, {
100
- opacity: '1',
101
- // we set opacity to 1 to make sure the tooltip is not displayed before the position is computed
102
- left: `${x}px`,
103
- top: `${y}px`,
104
- });
105
- }
106
- });
107
- }
108
- }, [tooltipRef.current, childrenRef.current, isTooltipVisible]);
88
+
89
+ const { refs, floatingStyles } = useFloating({
90
+ placement,
91
+ open: isTooltipVisible,
92
+ middleware: [offset(5), shift(), flip()],
93
+ });
109
94
  return (
110
- <TooltipContainer
111
- className="sc-tooltip"
112
- onPointerEnter={() => {
113
- setIsTooltipVisible(true);
114
- }}
115
- onPointerLeave={() => {
116
- setIsTooltipVisible(false);
117
- }}
118
- >
119
- {isTooltipVisible && overlay ? (
120
- <TooltipOverLayContainer
121
- ref={tooltipRef}
122
- className="sc-tooltip-overlay"
123
- placement={placement}
124
- style={overlayStyle}
125
- >
126
- <TooltipText className="sc-tooltip-overlay-text">
127
- {overlay}
128
- </TooltipText>
129
- </TooltipOverLayContainer>
130
- ) : null}
131
- <div ref={childrenRef}>{children}</div>
132
- </TooltipContainer>
95
+ <>
96
+ <TooltipContainer
97
+ className="sc-tooltip"
98
+ onPointerEnter={() => {
99
+ setIsTooltipVisible(true);
100
+ }}
101
+ onPointerLeave={() => {
102
+ setIsTooltipVisible(false);
103
+ }}
104
+ >
105
+ <div ref={refs.setReference}>{children}</div>
106
+ </TooltipContainer>
107
+ {isTooltipVisible &&
108
+ overlay &&
109
+ createPortal(
110
+ <TooltipOverLayContainer
111
+ ref={refs.setFloating}
112
+ className="sc-tooltip-overlay"
113
+ placement={placement}
114
+ style={{ ...floatingStyles, ...overlayStyle }}
115
+ >
116
+ <TooltipText className="sc-tooltip-overlay-text">
117
+ {overlay}
118
+ </TooltipText>
119
+ </TooltipOverLayContainer>,
120
+ document.body,
121
+ )}
122
+ </>
133
123
  );
134
124
  }
135
125
 
@@ -10,7 +10,7 @@ const StyledWrapper = styled.div`
10
10
  background-color: ${theme[style?.backgroundColor || 'backgroundLevel3']};
11
11
  color: ${theme.textPrimary};
12
12
  box-sizing: border-box;
13
- overflow: scroll;
13
+ overflow: auto;
14
14
  `;
15
15
  }}
16
16
  `;
@@ -651,7 +651,7 @@ export const TableWithSyncButton = {
651
651
  };
652
652
 
653
653
  return (
654
- <Box>
654
+ <Box width="500px" height="250px">
655
655
  <Title>Table with Sync Button</Title>
656
656
  <Box
657
657
  display="flex"
@@ -676,3 +676,59 @@ export const TableWithSyncButton = {
676
676
  );
677
677
  },
678
678
  };
679
+
680
+ export const AutoScrollToSelected = {
681
+ render: () => {
682
+ const largeData: Entry[] = Array.from({ length: 100 }, (_, index) => ({
683
+ id: index + 1,
684
+ firstName: `FirstName${index + 1}`,
685
+ lastName: `LastName${index + 1}`,
686
+ health: ['healthy', 'warning', 'critical'][index % 3],
687
+ }));
688
+
689
+ const [selectedId, setSelectedId] = useState<string>(
690
+ 'LastName80 FirstName80',
691
+ );
692
+
693
+ const handleRowSelected = (row: Row<Entry>) => {
694
+ const rowId = `${row.original.lastName} ${row.original.firstName}`;
695
+ setSelectedId(rowId);
696
+ };
697
+
698
+ const handleSelectRandom = () => {
699
+ const randomIndex = Math.floor(Math.random() * largeData.length);
700
+ const randomRow = largeData[randomIndex];
701
+ setSelectedId(`${randomRow.lastName} ${randomRow.firstName}`);
702
+ };
703
+
704
+ return (
705
+ <>
706
+ <Title>Auto Scroll to Selected Row</Title>
707
+ <Box mb={2}>
708
+ <Button
709
+ variant="secondary"
710
+ label="Select Random Row"
711
+ onClick={handleSelectRandom}
712
+ />
713
+ <Box mt={1}>Currently selected: {selectedId || 'None'}</Box>
714
+ </Box>
715
+ <div style={{ height: '400px' }}>
716
+ <Table
717
+ columns={columns}
718
+ data={largeData}
719
+ defaultSortingKey="firstName"
720
+ getRowId={getRowId}
721
+ >
722
+ <Table.SingleSelectableContent
723
+ rowHeight="h40"
724
+ separationLineVariant="backgroundLevel3"
725
+ selectedId={selectedId}
726
+ onRowSelected={handleRowSelected}
727
+ autoScrollToSelected
728
+ />
729
+ </Table>
730
+ </div>
731
+ </>
732
+ );
733
+ },
734
+ };