diff --git a/redisinsight/ui/src/components/cli/components/cli-body/CliBody/CliBody.tsx b/redisinsight/ui/src/components/cli/components/cli-body/CliBody/CliBody.tsx index 92ea09205b..d7392503dd 100644 --- a/redisinsight/ui/src/components/cli/components/cli-body/CliBody/CliBody.tsx +++ b/redisinsight/ui/src/components/cli/components/cli-body/CliBody/CliBody.tsx @@ -2,7 +2,7 @@ import React, { Ref, useEffect, useRef, useState } from 'react' import { EuiFlexGroup, EuiFlexItem, keys } from '@elastic/eui' import { useDispatch, useSelector } from 'react-redux' -import { Nullable } from 'uiSrc/utils' +import { Nullable, scrollIntoView } from 'uiSrc/utils' import { isModifiedEvent } from 'uiSrc/services' import { ClearCommand } from 'uiSrc/constants/cliOutput' import { outputSelector } from 'uiSrc/slices/cli/cli-output' @@ -41,7 +41,7 @@ const CliBody = (props: Props) => { useEffect(() => { inputEl?.focus() - scrollDivRef?.current?.scrollIntoView({ + scrollIntoView(scrollDivRef?.current, { behavior: 'smooth', block: 'nearest', inline: 'end', diff --git a/redisinsight/ui/src/components/field-message/FieldMessage.tsx b/redisinsight/ui/src/components/field-message/FieldMessage.tsx index caa8ac2810..6222c6c8c7 100644 --- a/redisinsight/ui/src/components/field-message/FieldMessage.tsx +++ b/redisinsight/ui/src/components/field-message/FieldMessage.tsx @@ -2,6 +2,7 @@ import React, { Ref, useEffect, useRef } from 'react' import cx from 'classnames' import { EuiIcon, EuiTextColor } from '@elastic/eui' +import { scrollIntoView } from 'uiSrc/utils' import styles from './styles.module.scss' type Colors = 'default' | 'secondary' | 'accent' | 'warning' | 'danger' | 'subdued' | 'ghost' @@ -19,7 +20,7 @@ const FieldMessage = ({ children, color, testID, icon, scrollViewOnAppear }: Pro useEffect(() => { // componentDidMount if (scrollViewOnAppear) { - divRef?.current?.scrollIntoView({ + scrollIntoView(divRef?.current, { behavior: 'smooth', block: 'nearest', inline: 'end', diff --git a/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx b/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx index ba7a21e2a0..79cbfef1c8 100644 --- a/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx +++ b/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx @@ -9,6 +9,7 @@ import { removeMonacoComments, splitMonacoValuePerLines, getMultiCommands, + scrollIntoView, } from 'uiSrc/utils' import { sendWBCommandAction, @@ -165,7 +166,7 @@ const WBViewWrapper = () => { } const scrollResults = (inline: ScrollLogicalPosition = 'start') => { - scrollDivRef?.current?.scrollIntoView({ + scrollIntoView(scrollDivRef?.current, { behavior: 'smooth', block: 'nearest', inline, diff --git a/redisinsight/ui/src/utils/index.ts b/redisinsight/ui/src/utils/index.ts index 73854a4e21..9e361713f6 100644 --- a/redisinsight/ui/src/utils/index.ts +++ b/redisinsight/ui/src/utils/index.ts @@ -36,6 +36,7 @@ export * from './monitorUtils' export * from './handlePlatforms' export * from './plugins' export * from './redistack' +export * from './polyfills' export { Maybe, diff --git a/redisinsight/ui/src/utils/polyfills.ts b/redisinsight/ui/src/utils/polyfills.ts new file mode 100644 index 0000000000..7a417793d8 --- /dev/null +++ b/redisinsight/ui/src/utils/polyfills.ts @@ -0,0 +1,12 @@ +import { Nullable } from './types' + +const isScrollBehaviorSupported = (): boolean => + 'scrollBehavior' in globalThis.document.documentElement.style + +export const scrollIntoView = (el: Nullable, opts?: ScrollIntoViewOptions) => { + if (el && isScrollBehaviorSupported()) { + el?.scrollIntoView(opts) + } else { + el?.scrollIntoView(true) + } +} diff --git a/redisinsight/ui/src/utils/tests/polyfills.spec.ts b/redisinsight/ui/src/utils/tests/polyfills.spec.ts new file mode 100644 index 0000000000..7738785e75 --- /dev/null +++ b/redisinsight/ui/src/utils/tests/polyfills.spec.ts @@ -0,0 +1,31 @@ +import { scrollIntoView } from 'uiSrc/utils' + +describe('scrollIntoView', () => { + it('should called with options for all browser except Safari', () => { + const mockScrollIntoView = jest.fn() + const opts: ScrollIntoViewOptions = { + behavior: 'smooth', + inline: 'end', + block: 'nearest', + } + const newDiv = document.createElement('div') + newDiv.scrollIntoView = mockScrollIntoView + scrollIntoView(newDiv, opts) + expect(mockScrollIntoView).toBeCalledWith(opts) + }) + + it('should called with "true" instead of options for Safari', () => { + const mockScrollIntoView = jest.fn() + const opts: ScrollIntoViewOptions = { + behavior: 'smooth', + inline: 'end', + block: 'nearest', + } + + Object.defineProperty(global.document.documentElement, 'style', { value: {} }) + const newDiv = document.createElement('div') + newDiv.scrollIntoView = mockScrollIntoView + scrollIntoView(newDiv, opts) + expect(mockScrollIntoView).toBeCalledWith(true) + }) +})