@scality/core-ui 0.183.0 → 0.185.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.
- package/dist/components/form/Form.component.d.ts.map +1 -1
- package/dist/components/form/Form.component.js +1 -1
- package/dist/components/infomessage/InfoMessage.component.d.ts +2 -1
- package/dist/components/infomessage/InfoMessage.component.d.ts.map +1 -1
- package/dist/components/infomessage/InfoMessage.component.js +2 -2
- package/dist/components/tablev2/SingleSelectableContent.d.ts +2 -1
- package/dist/components/tablev2/SingleSelectableContent.d.ts.map +1 -1
- package/dist/components/tablev2/SingleSelectableContent.js +17 -3
- package/dist/components/tablev2/TableCommon.d.ts +4 -3
- package/dist/components/tablev2/TableCommon.d.ts.map +1 -1
- package/dist/components/tablev2/TableCommon.js +7 -5
- package/dist/components/textarea/TextArea.component.d.ts.map +1 -1
- package/dist/components/textarea/TextArea.component.js +4 -3
- package/package.json +1 -1
- package/src/lib/components/form/Form.component.tsx +22 -18
- package/src/lib/components/infomessage/InfoMessage.component.tsx +3 -2
- package/src/lib/components/infomessage/InfoMessageUtils.test.tsx +59 -1
- package/src/lib/components/tablev2/SingleSelectableContent.tsx +20 -2
- package/src/lib/components/tablev2/TableCommon.tsx +27 -9
- package/src/lib/components/textarea/TextArea.component.tsx +4 -3
- package/stories/tablev2.stories.tsx +56 -0
- package/stories/textarea.stories.tsx +8 -0
|
@@ -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,
|
|
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(
|
|
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
|
};
|
|
@@ -2,7 +2,8 @@ type Props = {
|
|
|
2
2
|
title: string | React.ReactNode;
|
|
3
3
|
content: React.ReactNode;
|
|
4
4
|
link?: string;
|
|
5
|
+
linkText?: string;
|
|
5
6
|
};
|
|
6
|
-
export declare const InfoMessage: ({ title, content, link }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare const InfoMessage: ({ title, content, link, linkText }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
7
8
|
export {};
|
|
8
9
|
//# sourceMappingURL=InfoMessage.component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfoMessage.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/infomessage/InfoMessage.component.tsx"],"names":[],"mappings":"AAMA,KAAK,KAAK,GAAG;IACX,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IAChC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"InfoMessage.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/infomessage/InfoMessage.component.tsx"],"names":[],"mappings":"AAMA,KAAK,KAAK,GAAG;IACX,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IAChC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAYF,eAAO,MAAM,WAAW,uCAAwC,KAAK,4CAuBpE,CAAC"}
|
|
@@ -13,8 +13,8 @@ const InfoMessageContainer = styled.div `
|
|
|
13
13
|
gap: 0.5rem;
|
|
14
14
|
color: white;
|
|
15
15
|
`;
|
|
16
|
-
export const InfoMessage = ({ title, content, link }) => {
|
|
16
|
+
export const InfoMessage = ({ title, content, link, linkText }) => {
|
|
17
17
|
const { containerRef, backgroundColor } = useComputeBackgroundColor();
|
|
18
18
|
const theme = useTheme();
|
|
19
|
-
return (_jsxs(InfoMessageContainer, { ref: containerRef, style: { backgroundColor: backgroundColor }, children: [_jsxs(Stack, { children: [_jsx(Icon, { name: "Info-circle", color: theme.infoPrimary, size: "lg" }), typeof title === 'string' ? _jsx(Text, { isEmphazed: true, children: title }) : title] }), _jsx(Text, { color: "textSecondary", isGentleEmphazed: true, children: content }), link && (_jsxs(Link, { href: link, target: "_blank", style: { alignSelf: 'flex-end' }, children: [
|
|
19
|
+
return (_jsxs(InfoMessageContainer, { ref: containerRef, style: { backgroundColor: backgroundColor }, children: [_jsxs(Stack, { children: [_jsx(Icon, { name: "Info-circle", color: theme.infoPrimary, size: "lg" }), typeof title === 'string' ? _jsx(Text, { isEmphazed: true, children: title }) : title] }), _jsx(Text, { color: "textSecondary", isGentleEmphazed: true, children: content }), link && (_jsxs(Link, { href: link, target: "_blank", style: { alignSelf: 'flex-end' }, children: [linkText || 'More info', " ", _jsx(Icon, { name: "External-link" })] }))] }));
|
|
20
20
|
};
|
|
@@ -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;
|
|
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,
|
|
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?:
|
|
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,
|
|
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:
|
|
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:
|
|
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":"TextArea.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/textarea/TextArea.component.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAEb,sBAAsB,EAMvB,MAAM,OAAO,CAAC;AAIf,KAAK,eAAe,GAAG,MAAM,GAAG,MAAM,CAAC;AAWvC,KAAK,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"TextArea.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/textarea/TextArea.component.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAEb,sBAAsB,EAMvB,MAAM,OAAO,CAAC;AAIf,KAAK,eAAe,GAAG,MAAM,GAAG,MAAM,CAAC;AAWvC,KAAK,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAAC;AA0J1C,eAAO,MAAM,QAAQ;cAnKT,eAAe;YACjB,aAAa,CAAC,OAAO,CAAC;aACrB,aAAa,CAAC,QAAQ,CAAC;IAChC;;;OAGG;eACQ,OAAO;2CA4J+C,CAAC"}
|
|
@@ -5,7 +5,7 @@ import { spacing } from '../../spacing';
|
|
|
5
5
|
const TextAreaContainer = styled.textarea `
|
|
6
6
|
padding: ${spacing.r12} ${spacing.r8};
|
|
7
7
|
border-radius: 4px;
|
|
8
|
-
resize: vertical;
|
|
8
|
+
resize: ${(props) => (props.autoGrow ? 'none' : 'vertical')};
|
|
9
9
|
font-family: ${(props) => props.variant === 'code' ? 'Courier New' : 'Lato'};
|
|
10
10
|
font-size: ${spacing.f14};
|
|
11
11
|
|
|
@@ -19,7 +19,7 @@ const TextAreaContainer = styled.textarea `
|
|
|
19
19
|
css `
|
|
20
20
|
width: ${props.width};
|
|
21
21
|
`}
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
${(props) => props.height &&
|
|
24
24
|
css `
|
|
25
25
|
height: ${props.height};
|
|
@@ -28,6 +28,7 @@ const TextAreaContainer = styled.textarea `
|
|
|
28
28
|
${(props) => props.autoGrow &&
|
|
29
29
|
css `
|
|
30
30
|
overflow: hidden;
|
|
31
|
+
box-sizing: border-box;
|
|
31
32
|
`}
|
|
32
33
|
|
|
33
34
|
&:placeholder-shown {
|
|
@@ -67,7 +68,7 @@ function TextAreaElement({ rows = 3, cols = 20, width, height, variant = 'code',
|
|
|
67
68
|
if (!textarea || !autoGrow)
|
|
68
69
|
return;
|
|
69
70
|
// Reset height to auto to get the correct scrollHeight
|
|
70
|
-
textarea.style.height = '
|
|
71
|
+
textarea.style.height = '0px';
|
|
71
72
|
// Set the height to match the content
|
|
72
73
|
const newHeight = textarea.scrollHeight;
|
|
73
74
|
textarea.style.height = `${newHeight}px`;
|
package/package.json
CHANGED
|
@@ -171,26 +171,30 @@ const FormGroup = ({
|
|
|
171
171
|
flex: 'none',
|
|
172
172
|
}}
|
|
173
173
|
>
|
|
174
|
-
<
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
>
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
<
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
</
|
|
197
|
+
</label>
|
|
194
198
|
</div>
|
|
195
199
|
<Stack
|
|
196
200
|
direction={helpErrorPosition === 'right' ? 'horizontal' : 'vertical'}
|
|
@@ -8,6 +8,7 @@ type Props = {
|
|
|
8
8
|
title: string | React.ReactNode;
|
|
9
9
|
content: React.ReactNode;
|
|
10
10
|
link?: string;
|
|
11
|
+
linkText?: string;
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
const InfoMessageContainer = styled.div`
|
|
@@ -20,7 +21,7 @@ const InfoMessageContainer = styled.div`
|
|
|
20
21
|
color: white;
|
|
21
22
|
`;
|
|
22
23
|
|
|
23
|
-
export const InfoMessage = ({ title, content, link }: Props) => {
|
|
24
|
+
export const InfoMessage = ({ title, content, link, linkText }: Props) => {
|
|
24
25
|
const { containerRef, backgroundColor } = useComputeBackgroundColor();
|
|
25
26
|
const theme = useTheme();
|
|
26
27
|
|
|
@@ -38,7 +39,7 @@ export const InfoMessage = ({ title, content, link }: Props) => {
|
|
|
38
39
|
</Text>
|
|
39
40
|
{link && (
|
|
40
41
|
<Link href={link} target="_blank" style={{ alignSelf: 'flex-end' }}>
|
|
41
|
-
More info <Icon name="External-link"></Icon>
|
|
42
|
+
{linkText || 'More info'} <Icon name="External-link"></Icon>
|
|
42
43
|
</Link>
|
|
43
44
|
)}
|
|
44
45
|
</InfoMessageContainer>
|
|
@@ -1,8 +1,66 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
import '@testing-library/jest-dom';
|
|
2
|
-
import { render } from '@testing-library/react';
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
3
4
|
import { coreUIAvailableThemes } from '../../style/theme';
|
|
4
5
|
import { CoreUiThemeProvider } from '../coreuithemeprovider/CoreUiThemeProvider';
|
|
5
6
|
import { useComputeBackgroundColor } from './InfoMessageUtils';
|
|
7
|
+
import { InfoMessage } from './InfoMessage.component';
|
|
8
|
+
import { getWrapper } from '../../testUtils';
|
|
9
|
+
|
|
10
|
+
describe('InfoMessage', () => {
|
|
11
|
+
const selectors = {
|
|
12
|
+
title: () => screen.getByText('Title'),
|
|
13
|
+
content: () => screen.getByText('Content'),
|
|
14
|
+
defaultLinkText: () => screen.getByText('More info'),
|
|
15
|
+
link: () => screen.getByRole('link'),
|
|
16
|
+
linkText: () => screen.getByText('Link text'),
|
|
17
|
+
};
|
|
18
|
+
it('should render', () => {
|
|
19
|
+
const { Wrapper } = getWrapper();
|
|
20
|
+
render(<InfoMessage title="Title" content="Content" />, {
|
|
21
|
+
wrapper: Wrapper,
|
|
22
|
+
});
|
|
23
|
+
expect(selectors.title()).toBeInTheDocument();
|
|
24
|
+
expect(selectors.content()).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
it('should render with link and default link text', () => {
|
|
27
|
+
const { Wrapper } = getWrapper();
|
|
28
|
+
render(
|
|
29
|
+
<InfoMessage
|
|
30
|
+
title="Title"
|
|
31
|
+
content="Content"
|
|
32
|
+
link="https://www.google.com"
|
|
33
|
+
/>,
|
|
34
|
+
{
|
|
35
|
+
wrapper: Wrapper,
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
expect(selectors.title()).toBeInTheDocument();
|
|
39
|
+
expect(selectors.content()).toBeInTheDocument();
|
|
40
|
+
expect(selectors.link()).toBeInTheDocument();
|
|
41
|
+
expect(selectors.defaultLinkText()).toBeInTheDocument();
|
|
42
|
+
expect(selectors.link()).toHaveAttribute('href', 'https://www.google.com');
|
|
43
|
+
});
|
|
44
|
+
it('should render with correct link text', () => {
|
|
45
|
+
const { Wrapper } = getWrapper();
|
|
46
|
+
render(
|
|
47
|
+
<InfoMessage
|
|
48
|
+
title="Title"
|
|
49
|
+
content="Content"
|
|
50
|
+
link="https://www.google.com"
|
|
51
|
+
linkText="Link text"
|
|
52
|
+
/>,
|
|
53
|
+
{
|
|
54
|
+
wrapper: Wrapper,
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
expect(selectors.title()).toBeInTheDocument();
|
|
58
|
+
expect(selectors.content()).toBeInTheDocument();
|
|
59
|
+
expect(selectors.link()).toBeInTheDocument();
|
|
60
|
+
expect(selectors.linkText()).toBeInTheDocument();
|
|
61
|
+
expect(selectors.link()).toHaveAttribute('href', 'https://www.google.com');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
6
64
|
|
|
7
65
|
describe('useComputeBackgroundColor', () => {
|
|
8
66
|
const SUT = jest.fn();
|
|
@@ -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,
|
|
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?:
|
|
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
|
-
>({
|
|
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={
|
|
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={
|
|
198
|
+
listRef={listRef}
|
|
181
199
|
setHasScrollbar={setHasScrollbar}
|
|
182
200
|
onBottom={onBottom}
|
|
183
201
|
onBottomOffset={onBottomOffset}
|
|
@@ -32,7 +32,7 @@ const TextAreaContainer = styled.textarea<{
|
|
|
32
32
|
}>`
|
|
33
33
|
padding: ${spacing.r12} ${spacing.r8};
|
|
34
34
|
border-radius: 4px;
|
|
35
|
-
resize: vertical;
|
|
35
|
+
resize: ${(props) => (props.autoGrow ? 'none' : 'vertical')};
|
|
36
36
|
font-family: ${(props) =>
|
|
37
37
|
props.variant === 'code' ? 'Courier New' : 'Lato'};
|
|
38
38
|
font-size: ${spacing.f14};
|
|
@@ -49,7 +49,7 @@ const TextAreaContainer = styled.textarea<{
|
|
|
49
49
|
css`
|
|
50
50
|
width: ${props.width};
|
|
51
51
|
`}
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
${(props) =>
|
|
54
54
|
props.height &&
|
|
55
55
|
css`
|
|
@@ -60,6 +60,7 @@ const TextAreaContainer = styled.textarea<{
|
|
|
60
60
|
props.autoGrow &&
|
|
61
61
|
css`
|
|
62
62
|
overflow: hidden;
|
|
63
|
+
box-sizing: border-box;
|
|
63
64
|
`}
|
|
64
65
|
|
|
65
66
|
&:placeholder-shown {
|
|
@@ -118,7 +119,7 @@ function TextAreaElement(
|
|
|
118
119
|
if (!textarea || !autoGrow) return;
|
|
119
120
|
|
|
120
121
|
// Reset height to auto to get the correct scrollHeight
|
|
121
|
-
textarea.style.height = '
|
|
122
|
+
textarea.style.height = '0px';
|
|
122
123
|
|
|
123
124
|
// Set the height to match the content
|
|
124
125
|
const newHeight = textarea.scrollHeight;
|
|
@@ -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
|
+
};
|
|
@@ -68,6 +68,14 @@ export const RowsAndColsSet = {
|
|
|
68
68
|
},
|
|
69
69
|
};
|
|
70
70
|
|
|
71
|
+
export const AutoGrowShortText = {
|
|
72
|
+
args: {
|
|
73
|
+
autoGrow: true,
|
|
74
|
+
defaultValue: 'Hello World!',
|
|
75
|
+
width: '400px',
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
|
|
71
79
|
/**
|
|
72
80
|
* Auto-growing textarea adjusts its height based on content
|
|
73
81
|
* Perfect for displaying commands or long text where you want the entire content visible
|