mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 06:03:45 +01:00
Merge pull request #33600 from overleaf/worktree-mg-bullet-list-compact
Combine toolbar list controls and render indentation controls conditionally GitOrigin-RevId: 48d7c52983449566bfa21b5572915d79e595c704
This commit is contained in:
@@ -2126,6 +2126,7 @@
|
||||
"toolbar_insert_figure": "",
|
||||
"toolbar_insert_inline_math": "",
|
||||
"toolbar_insert_link": "",
|
||||
"toolbar_insert_list": "",
|
||||
"toolbar_insert_math": "",
|
||||
"toolbar_insert_math_and_symbols": "",
|
||||
"toolbar_insert_math_lowercase": "",
|
||||
|
||||
@@ -7,12 +7,14 @@ import OLPopover from '@/shared/components/ol/ol-popover'
|
||||
import { EditorView } from '@codemirror/view'
|
||||
import { emitToolbarEvent } from '../../extensions/toolbar/utils/analytics'
|
||||
import { useCodeMirrorViewContext } from '../codemirror-context'
|
||||
import classNames from 'classnames'
|
||||
|
||||
export const ToolbarButtonMenu: FC<
|
||||
React.PropsWithChildren<{
|
||||
id: string
|
||||
label: string
|
||||
icon: React.ReactNode
|
||||
orientation?: 'vertical' | 'horizontal'
|
||||
disabled?: boolean
|
||||
disablePopover?: boolean
|
||||
altCommand?: (view: EditorView) => void
|
||||
@@ -22,6 +24,7 @@ export const ToolbarButtonMenu: FC<
|
||||
icon,
|
||||
id,
|
||||
label,
|
||||
orientation = 'vertical',
|
||||
altCommand,
|
||||
onToggle,
|
||||
disabled,
|
||||
@@ -86,7 +89,10 @@ export const ToolbarButtonMenu: FC<
|
||||
<OLPopover
|
||||
id={`${id}-menu`}
|
||||
ref={ref}
|
||||
className="ol-cm-toolbar-button-menu-popover"
|
||||
className={classNames('ol-cm-toolbar-button-menu-popover', {
|
||||
'ol-cm-toolbar-button-menu-popover-horizontal':
|
||||
orientation === 'horizontal',
|
||||
})}
|
||||
>
|
||||
<OLListGroup
|
||||
role="menu"
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
import { ToolbarButtonMenu } from './button-menu'
|
||||
import { emitToolbarEvent } from '../../extensions/toolbar/utils/analytics'
|
||||
import MaterialIcon from '../../../../shared/components/material-icon'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useCodeMirrorViewContext } from '../codemirror-context'
|
||||
import {
|
||||
toggleBulletList,
|
||||
toggleNumberedList,
|
||||
} from '../../extensions/toolbar/commands'
|
||||
import { memo } from 'react'
|
||||
import OLListGroupItem from '@/shared/components/ol/ol-list-group-item'
|
||||
import OLTooltip from '@/shared/components/ol/ol-tooltip'
|
||||
|
||||
export const InsertListDropdown = memo(function InsertListDropdown() {
|
||||
const { t } = useTranslation()
|
||||
const view = useCodeMirrorViewContext()
|
||||
|
||||
return (
|
||||
<ToolbarButtonMenu
|
||||
id="toolbar-insert-list"
|
||||
label={t('toolbar_insert_list')}
|
||||
icon={<MaterialIcon type="format_list_bulleted" />}
|
||||
orientation="horizontal"
|
||||
>
|
||||
<OLTooltip
|
||||
id="toolbar-bullet-list"
|
||||
description={t('toolbar_bulleted_list')}
|
||||
overlayProps={{ placement: 'bottom' }}
|
||||
>
|
||||
<OLListGroupItem
|
||||
aria-label={t('toolbar_bulleted_list')}
|
||||
onClick={event => {
|
||||
emitToolbarEvent(view, 'toolbar-bullet-list')
|
||||
event.preventDefault()
|
||||
toggleBulletList(view)
|
||||
view.focus()
|
||||
}}
|
||||
>
|
||||
<MaterialIcon type="format_list_bulleted" />
|
||||
</OLListGroupItem>
|
||||
</OLTooltip>
|
||||
<OLTooltip
|
||||
id="toolbar-numbered-list"
|
||||
description={t('toolbar_numbered_list')}
|
||||
overlayProps={{ placement: 'bottom' }}
|
||||
>
|
||||
<OLListGroupItem
|
||||
aria-label={t('toolbar_numbered_list')}
|
||||
onClick={event => {
|
||||
emitToolbarEvent(view, 'toolbar-numbered-list')
|
||||
event.preventDefault()
|
||||
toggleNumberedList(view)
|
||||
view.focus()
|
||||
}}
|
||||
>
|
||||
<MaterialIcon type="format_list_numbered" />
|
||||
</OLListGroupItem>
|
||||
</OLTooltip>
|
||||
</ToolbarButtonMenu>
|
||||
)
|
||||
})
|
||||
+21
-28
@@ -9,6 +9,7 @@ import getMeta from '../../../../utils/meta'
|
||||
import { InsertFigureDropdown } from './insert-figure-dropdown'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { MathDropdown } from './math-dropdown'
|
||||
import { InsertListDropdown } from './insert-list-dropdown'
|
||||
import { TableDropdown } from './table-dropdown'
|
||||
import { LegacyTableDropdown } from './table-inserter-dropdown-legacy'
|
||||
import { withinFormattingCommand } from '@/features/source-editor/utils/tree-operations/formatting'
|
||||
@@ -164,34 +165,26 @@ export const ToolbarItems: FC<{
|
||||
data-overflow="group-list"
|
||||
aria-label={t('toolbar_list_indentation')}
|
||||
>
|
||||
<ToolbarButton
|
||||
id="toolbar-bullet-list"
|
||||
label={t('toolbar_bulleted_list')}
|
||||
command={commands.toggleBulletList}
|
||||
icon="format_list_bulleted"
|
||||
/>
|
||||
<ToolbarButton
|
||||
id="toolbar-numbered-list"
|
||||
label={t('toolbar_numbered_list')}
|
||||
command={commands.toggleNumberedList}
|
||||
icon="format_list_numbered"
|
||||
/>
|
||||
<ToolbarButton
|
||||
id="toolbar-format-indent-decrease"
|
||||
label={t('toolbar_decrease_indent')}
|
||||
command={commands.indentDecrease}
|
||||
icon="format_indent_decrease"
|
||||
shortcut={visual ? (isMac ? '⌘[' : 'Ctrl+[') : undefined}
|
||||
disabled={listDepth < 2}
|
||||
/>
|
||||
<ToolbarButton
|
||||
id="toolbar-format-indent-increase"
|
||||
label={t('toolbar_increase_indent')}
|
||||
command={commands.indentIncrease}
|
||||
icon="format_indent_increase"
|
||||
shortcut={visual ? (isMac ? '⌘]' : 'Ctrl+]') : undefined}
|
||||
disabled={listDepth < 1}
|
||||
/>
|
||||
<InsertListDropdown />
|
||||
{listDepth >= 1 && (
|
||||
<>
|
||||
<ToolbarButton
|
||||
id="toolbar-format-indent-decrease"
|
||||
label={t('toolbar_decrease_indent')}
|
||||
command={commands.indentDecrease}
|
||||
icon="format_indent_decrease"
|
||||
shortcut={visual ? (isMac ? '⌘[' : 'Ctrl+[') : undefined}
|
||||
disabled={listDepth < 2}
|
||||
/>
|
||||
<ToolbarButton
|
||||
id="toolbar-format-indent-increase"
|
||||
label={t('toolbar_increase_indent')}
|
||||
command={commands.indentIncrease}
|
||||
icon="format_indent_increase"
|
||||
shortcut={visual ? (isMac ? '⌘]' : 'Ctrl+]') : undefined}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -107,6 +107,11 @@ const toolbarTheme = EditorView.theme({
|
||||
},
|
||||
},
|
||||
},
|
||||
'.ol-cm-toolbar-button-menu-popover-horizontal': {
|
||||
'& .list-group': {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
},
|
||||
'.ol-cm-toolbar-button-group': {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
import { forwardRef } from 'react'
|
||||
import { ListGroupItem, ListGroupItemProps } from 'react-bootstrap'
|
||||
|
||||
function OLListGroupItem(props: ListGroupItemProps) {
|
||||
const as = props.as ?? 'button'
|
||||
const OLListGroupItem = forwardRef<HTMLElement, ListGroupItemProps>(
|
||||
function OLListGroupItem(props, ref) {
|
||||
const as = props.as ?? 'button'
|
||||
|
||||
return (
|
||||
<ListGroupItem
|
||||
{...props}
|
||||
as={as}
|
||||
type={as === 'button' ? 'button' : undefined}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<ListGroupItem
|
||||
{...props}
|
||||
ref={ref}
|
||||
as={as}
|
||||
type={as === 'button' ? 'button' : undefined}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
OLListGroupItem.displayName = 'OLListGroupItem'
|
||||
|
||||
export default OLListGroupItem
|
||||
|
||||
@@ -2740,6 +2740,7 @@
|
||||
"toolbar_insert_figure": "Insert figure",
|
||||
"toolbar_insert_inline_math": "Insert inline math",
|
||||
"toolbar_insert_link": "Insert link",
|
||||
"toolbar_insert_list": "Insert list",
|
||||
"toolbar_insert_math": "Insert math",
|
||||
"toolbar_insert_math_and_symbols": "Insert math and symbols",
|
||||
"toolbar_insert_math_lowercase": "Insert math",
|
||||
|
||||
+61
-18
@@ -19,6 +19,11 @@ const clickToolbarButton = (name: string) => {
|
||||
cy.findByRole('button', { name }).trigger('mouseout')
|
||||
}
|
||||
|
||||
const clickListType = (type: string) => {
|
||||
cy.findByRole('button', { name: 'Insert list' }).click()
|
||||
cy.findByRole('button', { name: type }).click()
|
||||
}
|
||||
|
||||
const mountEditor = (content: string) => {
|
||||
const scope = mockScope(content)
|
||||
|
||||
@@ -131,8 +136,7 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
||||
mountEditor('test')
|
||||
selectAll()
|
||||
|
||||
clickToolbarButton('More editor toolbar items')
|
||||
clickToolbarButton('Bulleted list')
|
||||
clickListType('Bulleted list')
|
||||
|
||||
cy.get('.cm-content').should('have.text', ' test')
|
||||
|
||||
@@ -144,8 +148,7 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
||||
mountEditor('test')
|
||||
selectAll()
|
||||
|
||||
clickToolbarButton('More editor toolbar items')
|
||||
clickToolbarButton('Numbered list')
|
||||
clickListType('Numbered list')
|
||||
|
||||
cy.get('.cm-content').should('have.text', ' test')
|
||||
|
||||
@@ -157,8 +160,7 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
||||
mountEditor('test')
|
||||
selectAll()
|
||||
|
||||
clickToolbarButton('More editor toolbar items')
|
||||
clickToolbarButton('Numbered list')
|
||||
clickListType('Numbered list')
|
||||
|
||||
// expose the markup
|
||||
cy.get('.cm-line').eq(0).type('{rightArrow}')
|
||||
@@ -173,7 +175,7 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
||||
].join('')
|
||||
)
|
||||
|
||||
clickToolbarButton('Bulleted list')
|
||||
clickListType('Bulleted list')
|
||||
|
||||
cy.get('.cm-content').should(
|
||||
'have.text',
|
||||
@@ -190,8 +192,7 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
||||
mountEditor('test')
|
||||
selectAll()
|
||||
|
||||
clickToolbarButton('More editor toolbar items')
|
||||
clickToolbarButton('Numbered list')
|
||||
clickListType('Numbered list')
|
||||
|
||||
// expose the markup
|
||||
cy.get('.cm-line').eq(0).type('{rightArrow}')
|
||||
@@ -206,7 +207,7 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
||||
].join('')
|
||||
)
|
||||
|
||||
clickToolbarButton('Numbered list')
|
||||
clickListType('Numbered list')
|
||||
|
||||
cy.get('.cm-content').should('have.text', 'test')
|
||||
})
|
||||
@@ -215,8 +216,7 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
||||
mountEditor('test\ntest')
|
||||
selectAll()
|
||||
|
||||
clickToolbarButton('More editor toolbar items')
|
||||
clickToolbarButton('Numbered list')
|
||||
clickListType('Numbered list')
|
||||
|
||||
// expose the markup
|
||||
cy.get('.cm-line').eq(1).type('{rightArrow}')
|
||||
@@ -252,8 +252,7 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
||||
|
||||
cy.get('.cm-line').eq(1).click()
|
||||
|
||||
clickToolbarButton('More editor toolbar items')
|
||||
clickToolbarButton('Numbered list')
|
||||
clickListType('Numbered list')
|
||||
|
||||
cy.get('.cm-line').eq(0).type('{upArrow}')
|
||||
|
||||
@@ -273,8 +272,7 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
||||
mountEditor('test\ntest')
|
||||
selectAll()
|
||||
|
||||
clickToolbarButton('More editor toolbar items')
|
||||
clickToolbarButton('Numbered list')
|
||||
clickListType('Numbered list')
|
||||
|
||||
// expose the markup
|
||||
cy.get('.cm-line').eq(1).type('{rightArrow}')
|
||||
@@ -310,8 +308,7 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
||||
|
||||
cy.get('.cm-line').eq(0).click()
|
||||
|
||||
clickToolbarButton('More editor toolbar items')
|
||||
clickToolbarButton('Numbered list')
|
||||
clickListType('Numbered list')
|
||||
|
||||
// expose the markup
|
||||
cy.get('.cm-line').eq(1).type('{rightArrow}')
|
||||
@@ -339,4 +336,50 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
||||
mountEditor('')
|
||||
cy.findByLabelText('Insert symbol').should('not.exist')
|
||||
})
|
||||
|
||||
it('should show both list type options in the list type dropdown', function () {
|
||||
mountEditor('test')
|
||||
|
||||
cy.findByRole('button', { name: 'Insert list' }).click()
|
||||
cy.findByRole('button', { name: 'Bulleted list' }).should('exist')
|
||||
cy.findByRole('button', { name: 'Numbered list' }).should('exist')
|
||||
})
|
||||
|
||||
it('should hide indent buttons when cursor is not in a list', function () {
|
||||
mountEditor('test')
|
||||
|
||||
cy.findByRole('button', { name: 'Increase indent' }).should('not.exist')
|
||||
cy.findByRole('button', { name: 'Decrease indent' }).should('not.exist')
|
||||
})
|
||||
|
||||
it('should show indent buttons when cursor is inside a list', function () {
|
||||
mountEditor('test')
|
||||
selectAll()
|
||||
|
||||
clickListType('Bulleted list')
|
||||
|
||||
cy.get('.cm-line').eq(0).click()
|
||||
|
||||
cy.findByRole('button', { name: 'Increase indent' }).should('exist')
|
||||
cy.findByRole('button', { name: 'Decrease indent' }).should('exist')
|
||||
})
|
||||
|
||||
it('should disable decrease indent when at the top level of a list', function () {
|
||||
mountEditor('test')
|
||||
selectAll()
|
||||
|
||||
clickListType('Bulleted list')
|
||||
|
||||
cy.get('.cm-line').eq(0).click()
|
||||
|
||||
cy.findByRole('button', { name: 'Decrease indent' }).should(
|
||||
'have.attr',
|
||||
'aria-disabled',
|
||||
'true'
|
||||
)
|
||||
cy.findByRole('button', { name: 'Increase indent' }).should(
|
||||
'not.have.attr',
|
||||
'aria-disabled'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user