mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-28 16:40:58 -05:00
fix: Fix table picker overlay
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
fc017e2d2e
commit
526c16e609
3 changed files with 72 additions and 86 deletions
|
@ -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>
|
||||||
|
|
|
@ -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]);
|
||||||
|
}
|
||||||
|
|
|
@ -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}
|
|
||||||
</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>
|
||||||
|
</Popover>
|
||||||
<Trans i18nKey={'editor.editorToolbar.table.customSize'} />
|
)
|
||||||
</Button>
|
}
|
||||||
</div>
|
)
|
||||||
</Popover.Body>
|
|
||||||
</Popover>
|
TableSizePickerPopover.displayName = 'TableSizePickerPopover'
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue