Fix Splitter issues (#1343)

Fix Splitter issues

* Replace code with hook useAdjustedRelativeSplitValue
* Add e2e tests for splitter

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2021-06-21 23:13:39 +02:00 committed by GitHub
parent 015a5cf496
commit 6cfcc37b1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 94 additions and 6 deletions

View file

@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Split view', () => {
beforeEach(() => {
cy.visitTestEditor()
})
it('can show both panes', () => {
cy.get('[data-cy="view-mode-both"]').click()
cy.get('.splitter.left').should('be.visible')
cy.get('.splitter.right').should('be.visible')
})
it('can show only preview pane', () => {
cy.get('[data-cy="view-mode-preview"]').click()
cy.get('.splitter.left').should('be.not.visible')
cy.get('.splitter.right').should('be.visible')
})
it('can show only editor pane', () => {
cy.get('[data-cy="view-mode-editor"]').click()
cy.get('.splitter.left').should('be.visible')
cy.get('.splitter.right').should('be.not.visible')
})
it('can change the split by dragging', () => {
cy.get('.splitter.left').then((leftPanebefore) => {
const widthBefore = leftPanebefore.outerWidth()
cy.get('[data-cy="view-mode-both"]').click()
cy.get('.split-divider').should('be.visible').trigger('mousedown', { buttons: 1 })
cy.document().trigger('mousemove', { buttons: 1, pageX: 0, pageY: 0 })
cy.get('.split-divider').trigger('mouseup')
cy.get('.splitter.left').should('not.eq', widthBefore)
})
})
})

View file

@ -29,13 +29,25 @@ export const EditorViewMode: React.FC = () => {
onChange={(value: EditorMode) => { onChange={(value: EditorMode) => {
setEditorMode(value) setEditorMode(value)
}}> }}>
<ToggleButton value={EditorMode.PREVIEW} variant='outline-secondary' title={t('editor.viewMode.view')}> <ToggleButton
data-cy={'view-mode-preview'}
value={EditorMode.PREVIEW}
variant='outline-secondary'
title={t('editor.viewMode.view')}>
<ForkAwesomeIcon icon='eye' /> <ForkAwesomeIcon icon='eye' />
</ToggleButton> </ToggleButton>
<ToggleButton value={EditorMode.BOTH} variant='outline-secondary' title={t('editor.viewMode.both')}> <ToggleButton
data-cy={'view-mode-both'}
value={EditorMode.BOTH}
variant='outline-secondary'
title={t('editor.viewMode.both')}>
<ForkAwesomeIcon icon='columns' /> <ForkAwesomeIcon icon='columns' />
</ToggleButton> </ToggleButton>
<ToggleButton value={EditorMode.EDITOR} variant='outline-secondary' title={t('editor.viewMode.edit')}> <ToggleButton
data-cy={'view-mode-editor'}
value={EditorMode.EDITOR}
variant='outline-secondary'
title={t('editor.viewMode.edit')}>
<ForkAwesomeIcon icon='pencil' /> <ForkAwesomeIcon icon='pencil' />
</ToggleButton> </ToggleButton>
</ToggleButtonGroup> </ToggleButtonGroup>

View file

@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { useMemo } from 'react'
/**
* Calculates the adjusted relative split value.
*
* @param showLeft Defines if the left split pane should be shown
* @param showRight Defines if the right split pane should be shown
* @param relativeSplitValue The relative size ratio of the split
* @return the limited (0% to 100%) relative split value. If only the left or right pane should be shown then the return value will be always 100 or 0
*/
export const useAdjustedRelativeSplitValue = (
showLeft: boolean,
showRight: boolean,
relativeSplitValue: number
): number =>
useMemo(() => {
let splitValue: number
if (!showLeft && showRight) {
splitValue = 0
} else if (showLeft && !showRight) {
splitValue = 100
} else {
splitValue = relativeSplitValue
}
return Math.min(100, Math.max(0, splitValue))
}, [relativeSplitValue, showLeft, showRight])

View file

@ -8,6 +8,7 @@ import React, { ReactElement, useCallback, useEffect, useRef, useState } from 'r
import { ShowIf } from '../../common/show-if/show-if' import { ShowIf } from '../../common/show-if/show-if'
import { SplitDivider } from './split-divider/split-divider' import { SplitDivider } from './split-divider/split-divider'
import './splitter.scss' import './splitter.scss'
import { useAdjustedRelativeSplitValue } from './hooks/use-adjusted-relative-split-value'
export interface SplitterProps { export interface SplitterProps {
left: ReactElement left: ReactElement
@ -62,7 +63,7 @@ export const Splitter: React.FC<SplitterProps> = ({
showRight showRight
}) => { }) => {
const [relativeSplitValue, setRelativeSplitValue] = useState(50) const [relativeSplitValue, setRelativeSplitValue] = useState(50)
const cappedRelativeSplitValue = Math.max(0, Math.min(100, showRight ? relativeSplitValue : 100)) const adjustedRelativeSplitValue = useAdjustedRelativeSplitValue(showLeft, showRight, relativeSplitValue)
const resizingInProgress = useRef(false) const resizingInProgress = useRef(false)
const splitContainer = useRef<HTMLDivElement>(null) const splitContainer = useRef<HTMLDivElement>(null)
@ -129,7 +130,7 @@ export const Splitter: React.FC<SplitterProps> = ({
<div ref={splitContainer} className={`flex-fill flex-row d-flex ${additionalContainerClassName || ''}`}> <div ref={splitContainer} className={`flex-fill flex-row d-flex ${additionalContainerClassName || ''}`}>
<div <div
className={`splitter left ${!showLeft ? 'd-none' : ''}`} className={`splitter left ${!showLeft ? 'd-none' : ''}`}
style={{ width: `calc(${cappedRelativeSplitValue}% - 5px)` }}> style={{ width: `calc(${adjustedRelativeSplitValue}% - 5px)` }}>
{left} {left}
</div> </div>
<ShowIf condition={showLeft && showRight}> <ShowIf condition={showLeft && showRight}>
@ -139,7 +140,7 @@ export const Splitter: React.FC<SplitterProps> = ({
</ShowIf> </ShowIf>
<div <div
className={`splitter right ${!showRight ? 'd-none' : ''}`} className={`splitter right ${!showRight ? 'd-none' : ''}`}
style={{ width: `calc(100% - ${cappedRelativeSplitValue}%)` }}> style={{ width: `calc(100% - ${adjustedRelativeSplitValue}%)` }}>
{right} {right}
</div> </div>
</div> </div>