fix: Fix table picker overlay

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2022-11-08 22:21:57 +01:00
parent fc017e2d2e
commit 526c16e609
3 changed files with 72 additions and 86 deletions

View file

@ -15,6 +15,7 @@ import type { OverlayInjectedProps } from 'react-bootstrap/Overlay'
import { replaceSelection } from '../formatters/replace-selection' import { replaceSelection } from '../formatters/replace-selection'
import { useChangeEditorContentCallback } from '../../../change-content-context/use-change-editor-content-callback' import { useChangeEditorContentCallback } from '../../../change-content-context/use-change-editor-content-callback'
import { createMarkdownTable } from './create-markdown-table' import { createMarkdownTable } from './create-markdown-table'
import './table-picker.module.scss'
enum PickerMode { enum PickerMode {
INVISIBLE, INVISIBLE,
@ -58,11 +59,10 @@ export const TablePickerButton: React.FC = () => {
}, []) }, [])
const createPopoverElement = useCallback<(props: OverlayInjectedProps) => React.ReactElement>( const createPopoverElement = useCallback<(props: OverlayInjectedProps) => React.ReactElement>(
({ ref, ...popoverProps }) => ( (popoverProps) => (
<TableSizePickerPopover <TableSizePickerPopover
onTableSizeSelected={onSizeSelect} onTableSizeSelected={onSizeSelect}
onShowCustomSizeModal={onShowModal} onShowCustomSizeModal={onShowModal}
onRefUpdate={ref}
{...popoverProps} {...popoverProps}
/> />
), ),
@ -84,7 +84,9 @@ export const TablePickerButton: React.FC = () => {
target={button.current} target={button.current}
onHide={onOverlayHide} onHide={onOverlayHide}
show={pickerMode === PickerMode.GRID} show={pickerMode === PickerMode.GRID}
placement={'bottom'} placement={'auto'}
flip={true}
offset={[0, 0]}
rootClose={pickerMode === PickerMode.GRID}> rootClose={pickerMode === PickerMode.GRID}>
{createPopoverElement} {createPopoverElement}
</Overlay> </Overlay>

View file

@ -4,19 +4,14 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
.table-cell {
.table-picker-container { margin: 1px;
z-index: 1111; border-radius: 2px;
border: solid 1px var(--bs-dark);
.table-cell {
margin: 1px;
border-radius: 2px;
}
.table-container {
display: grid;
grid-template-columns: repeat(10, 15px [col-start]);
grid-template-rows: repeat(8, 15px [row-start]);
}
} }
.table-container {
display: grid;
grid-template-columns: repeat(10, 15px [col-start]);
grid-template-rows: repeat(8, 15px [row-start]);
}

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import React, { useCallback, useMemo, useRef, useState } from 'react' import React, { useCallback, useMemo, useState } from 'react'
import { createNumberRangeArray } from '../../../../common/number-range/number-range' import { createNumberRangeArray } from '../../../../common/number-range/number-range'
import { Button, Popover } from 'react-bootstrap' import { Button, Popover } from 'react-bootstrap'
import { TableSizeText } from './table-size-text' import { TableSizeText } from './table-size-text'
@ -12,13 +12,11 @@ import { Trans, useTranslation } from 'react-i18next'
import { cypressAttribute, cypressId } from '../../../../../utils/cypress-attribute' import { cypressAttribute, cypressId } from '../../../../../utils/cypress-attribute'
import { ForkAwesomeIcon } from '../../../../common/fork-awesome/fork-awesome-icon' import { ForkAwesomeIcon } from '../../../../common/fork-awesome/fork-awesome-icon'
import type { PopoverProps } from 'react-bootstrap/Popover' import type { PopoverProps } from 'react-bootstrap/Popover'
import { useOnRefChange } from '../../../../markdown-renderer/hooks/use-on-ref-change'
import styles from './table-picker.module.scss' import styles from './table-picker.module.scss'
export interface TableSizePickerPopoverProps extends Omit<PopoverProps, 'id'> { export interface TableSizePickerPopoverProps extends PopoverProps {
onShowCustomSizeModal: () => void onShowCustomSizeModal: () => void
onTableSizeSelected: (rows: number, cols: number) => void onTableSizeSelected: (rows: number, cols: number) => void
onRefUpdate: (newRef: HTMLDivElement | null) => void
} }
export interface TableSize { export interface TableSize {
@ -34,72 +32,63 @@ export interface TableSize {
* @param onRefUpdate The callback, that will be called if ref was updated. * @param onRefUpdate The callback, that will be called if ref was updated.
* @param props Additional props given directly to the modal * @param props Additional props given directly to the modal
*/ */
export const TableSizePickerPopover: React.FC<TableSizePickerPopoverProps> = ({ export const TableSizePickerPopover = React.forwardRef<HTMLDivElement, TableSizePickerPopoverProps>(
onShowCustomSizeModal, ({ onShowCustomSizeModal, onTableSizeSelected, ...props }, ref) => {
onTableSizeSelected, const { t } = useTranslation()
onRefUpdate, const [tableSize, setTableSize] = useState<TableSize>()
...props
}) => {
const { t } = useTranslation()
const [tableSize, setTableSize] = useState<TableSize>()
const onSizeHover = useCallback( const onSizeHover = useCallback(
(selectedRows: number, selectedCols: number) => () => { (selectedRows: number, selectedCols: number) => () => {
setTableSize({ setTableSize({
rows: selectedRows, rows: selectedRows,
columns: selectedCols columns: selectedCols
})
},
[]
)
const tableContainer = useMemo(
() =>
createNumberRangeArray(8).map((row: number) =>
createNumberRangeArray(10).map((col: number) => {
const selected = tableSize && row < tableSize.rows && col < tableSize.columns
return (
<div
key={`${row}_${col}`}
className={`${styles['table-cell']} ${selected ? 'bg-primary border-primary' : ''}`}
{...cypressAttribute('selected', selected ? 'true' : 'false')}
{...cypressAttribute('col', `${col + 1}`)}
{...cypressAttribute('row', `${row + 1}`)}
onMouseEnter={onSizeHover(row + 1, col + 1)}
title={t('editor.editorToolbar.table.titleWithSize', { cols: col + 1, rows: row + 1 })}
onClick={() => onTableSizeSelected(row + 1, col + 1)}
/>
)
}) })
), },
[onTableSizeSelected, onSizeHover, t, tableSize] []
) )
const popoverRef = useRef<HTMLDivElement | null>(null) const tableContainer = useMemo(
useOnRefChange(popoverRef, (newRef) => onRefUpdate(newRef)) () =>
createNumberRangeArray(8).map((row: number) =>
createNumberRangeArray(10).map((col: number) => {
const selected = tableSize && row < tableSize.rows && col < tableSize.columns
return (
<div
key={`${row}_${col}`}
className={`${styles['table-cell']} ${selected ? 'bg-primary border-primary' : ''}`}
{...cypressAttribute('selected', selected ? 'true' : 'false')}
{...cypressAttribute('col', `${col + 1}`)}
{...cypressAttribute('row', `${row + 1}`)}
onMouseEnter={onSizeHover(row + 1, col + 1)}
title={t('editor.editorToolbar.table.titleWithSize', { cols: col + 1, rows: row + 1 })}
onClick={() => onTableSizeSelected(row + 1, col + 1)}
/>
)
})
),
[onTableSizeSelected, onSizeHover, t, tableSize]
)
return ( return (
<Popover <Popover ref={ref} {...cypressId('table-size-picker-popover')} className={`bg-light`} {...props}>
{...props} <Popover.Header>
ref={popoverRef} <TableSizeText tableSize={tableSize} />
id={'table-picker'} </Popover.Header>
{...cypressId('table-size-picker-popover')} <Popover.Body>
className={`${styles['table-picker-container']} bg-light`}> <div className={styles['table-container']} role='grid'>
<Popover.Header> {tableContainer}
<TableSizeText tableSize={tableSize} /> </div>
</Popover.Header> <div className='d-flex justify-content-center mt-2'>
<Popover.Body> <Button {...cypressId('show-custom-table-modal')} className={'text-center'} onClick={onShowCustomSizeModal}>
<div className={styles['table-container']} role='grid'> <ForkAwesomeIcon icon='table' />
{tableContainer} &nbsp;
</div> <Trans i18nKey={'editor.editorToolbar.table.customSize'} />
<div className='d-flex justify-content-center mt-2'> </Button>
<Button {...cypressId('show-custom-table-modal')} className={'text-center'} onClick={onShowCustomSizeModal}> </div>
<ForkAwesomeIcon icon='table' /> </Popover.Body>
&nbsp; </Popover>
<Trans i18nKey={'editor.editorToolbar.table.customSize'} /> )
</Button> }
</div> )
</Popover.Body>
</Popover> TableSizePickerPopover.displayName = 'TableSizePickerPopover'
)
}