fix: remove unsupported block colors menu
This commit is contained in:
@@ -436,9 +436,10 @@ Defined in `src/components/editorSchema.tsx` and styled in `src/components/Edito
|
||||
|
||||
Defined in `src/components/tolariaEditorFormatting.tsx` and `src/components/tolariaEditorFormattingConfig.ts`:
|
||||
|
||||
- `SingleEditorView` disables BlockNote's default formatting toolbar and `/` menu, then mounts Tolaria-owned controllers so the visible formatting surface matches Tolaria's markdown round-trip guarantees.
|
||||
- `SingleEditorView` disables BlockNote's default formatting toolbar, `/` menu, and side menu, then mounts Tolaria-owned controllers so the visible formatting surface matches Tolaria's markdown round-trip guarantees.
|
||||
- The formatting toolbar only exposes inline controls that persist through `blocksToMarkdownLossy()` in Tolaria's save pipeline: bold, italic, strike, nesting, and link creation. Controls that BlockNote can render temporarily but Tolaria cannot faithfully persist, such as underline, color, alignment, and the block-type dropdown, are hidden instead of appearing to work and later disappearing.
|
||||
- The `/` slash menu remains the supported path for markdown-safe block transformations such as headings, quotes, and list blocks. Tolaria filters out BlockNote's toggle-heading and toggle-list variants because those do not map cleanly to the markdown note model.
|
||||
- The block-handle side menu keeps only actions that survive Tolaria's markdown round-trip. Delete and table-header toggles remain available; BlockNote's `Colors` submenu is removed because block colors are not part of Tolaria's supported markdown surface.
|
||||
|
||||
### Markdown-to-BlockNote Pipeline
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
||||
import type { ReactNode } from 'react'
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
// Provide a localStorage mock that supports all methods (jsdom's may be incomplete)
|
||||
@@ -125,6 +126,12 @@ vi.mock('@blocknote/core/extensions', () => ({
|
||||
|
||||
vi.mock('@blocknote/react', () => ({
|
||||
createReactInlineContentSpec: () => ({ render: () => null }),
|
||||
BlockNoteViewRaw: ({ children }: { children?: ReactNode }) => (
|
||||
<div data-testid="blocknote-view">{children}</div>
|
||||
),
|
||||
ComponentsContext: {
|
||||
Provider: ({ children }: { children?: ReactNode }) => <>{children}</>,
|
||||
},
|
||||
useCreateBlockNote: () => ({
|
||||
tryParseMarkdownToBlocks: async () => [],
|
||||
replaceBlocks: () => {},
|
||||
@@ -132,6 +139,7 @@ vi.mock('@blocknote/react', () => ({
|
||||
insertInlineContent: () => {},
|
||||
onMount: (cb: () => void) => { cb(); return () => {} },
|
||||
}),
|
||||
SideMenuController: () => null,
|
||||
SuggestionMenuController: () => null,
|
||||
}))
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ vi.mock('@blocknote/react', () => ({
|
||||
</div>
|
||||
),
|
||||
FormattingToolbarController: () => null,
|
||||
SideMenuController: () => null,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- mock
|
||||
SuggestionMenuController: (props: any) => {
|
||||
capturedGetItemsByTrigger[props.triggerCharacter] = props.getItems
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
SuggestionMenuController,
|
||||
BlockNoteViewRaw,
|
||||
ComponentsContext,
|
||||
SideMenuController,
|
||||
} from '@blocknote/react'
|
||||
import { components } from '@blocknote/mantine'
|
||||
import { MantineContext, MantineProvider } from '@mantine/core'
|
||||
@@ -23,6 +24,7 @@ import {
|
||||
TolariaFormattingToolbar,
|
||||
TolariaFormattingToolbarController,
|
||||
} from './tolariaEditorFormatting'
|
||||
import { TolariaSideMenu } from './tolariaBlockNoteSideMenu'
|
||||
import { useEditorLinkActivation } from './useEditorLinkActivation'
|
||||
|
||||
const TEST_TABLE_MARKDOWN = `| Head 1 | Head 2 | Head 3 |
|
||||
@@ -223,7 +225,9 @@ export function SingleEditorView({ editor, entries, onNavigateWikilink, onChange
|
||||
editable={editable}
|
||||
formattingToolbar={false}
|
||||
slashMenu={false}
|
||||
sideMenu={false}
|
||||
>
|
||||
<SideMenuController sideMenu={TolariaSideMenu} />
|
||||
<TolariaFormattingToolbarController
|
||||
formattingToolbar={TolariaFormattingToolbar}
|
||||
floatingUIOptions={{
|
||||
|
||||
44
src/components/tolariaBlockNoteSideMenu.test.tsx
Normal file
44
src/components/tolariaBlockNoteSideMenu.test.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import type { ComponentType, PropsWithChildren } from 'react'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { TolariaSideMenu } from './tolariaBlockNoteSideMenu'
|
||||
|
||||
let capturedDragHandleMenu: ComponentType | null = null
|
||||
|
||||
vi.mock('@blocknote/react', () => ({
|
||||
DragHandleMenu: ({ children }: PropsWithChildren) => (
|
||||
<div data-testid="drag-handle-menu">{children}</div>
|
||||
),
|
||||
RemoveBlockItem: ({ children }: PropsWithChildren) => <div>{children}</div>,
|
||||
SideMenu: ({ dragHandleMenu }: { dragHandleMenu?: ComponentType }) => {
|
||||
capturedDragHandleMenu = dragHandleMenu ?? null
|
||||
return <div data-testid="side-menu" />
|
||||
},
|
||||
TableColumnHeaderItem: ({ children }: PropsWithChildren) => <div>{children}</div>,
|
||||
TableRowHeaderItem: ({ children }: PropsWithChildren) => <div>{children}</div>,
|
||||
useDictionary: () => ({
|
||||
drag_handle: {
|
||||
delete_menuitem: 'Delete',
|
||||
header_row_menuitem: 'Header row',
|
||||
header_column_menuitem: 'Header column',
|
||||
colors_menuitem: 'Colors',
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
describe('TolariaSideMenu', () => {
|
||||
it('replaces BlockNote block colors with markdown-safe drag-handle items', () => {
|
||||
render(<TolariaSideMenu />)
|
||||
|
||||
expect(screen.getByTestId('side-menu')).toBeInTheDocument()
|
||||
expect(capturedDragHandleMenu).not.toBeNull()
|
||||
|
||||
const DragHandleMenuComponent = capturedDragHandleMenu!
|
||||
render(<DragHandleMenuComponent />)
|
||||
|
||||
expect(screen.getByText('Delete')).toBeInTheDocument()
|
||||
expect(screen.getByText('Header row')).toBeInTheDocument()
|
||||
expect(screen.getByText('Header column')).toBeInTheDocument()
|
||||
expect(screen.queryByText('Colors')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
25
src/components/tolariaBlockNoteSideMenu.tsx
Normal file
25
src/components/tolariaBlockNoteSideMenu.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import {
|
||||
DragHandleMenu,
|
||||
RemoveBlockItem,
|
||||
SideMenu,
|
||||
TableColumnHeaderItem,
|
||||
TableRowHeaderItem,
|
||||
type SideMenuProps,
|
||||
useDictionary,
|
||||
} from '@blocknote/react'
|
||||
|
||||
function TolariaDragHandleMenu() {
|
||||
const dict = useDictionary()
|
||||
|
||||
return (
|
||||
<DragHandleMenu>
|
||||
<RemoveBlockItem>{dict.drag_handle.delete_menuitem}</RemoveBlockItem>
|
||||
<TableRowHeaderItem>{dict.drag_handle.header_row_menuitem}</TableRowHeaderItem>
|
||||
<TableColumnHeaderItem>{dict.drag_handle.header_column_menuitem}</TableColumnHeaderItem>
|
||||
</DragHandleMenu>
|
||||
)
|
||||
}
|
||||
|
||||
export function TolariaSideMenu(props: SideMenuProps) {
|
||||
return <SideMenu {...props} dragHandleMenu={TolariaDragHandleMenu} />
|
||||
}
|
||||
@@ -66,6 +66,8 @@ async function expectZoomedHandleClickToWork(
|
||||
|
||||
const menu = page.locator('.mantine-Menu-dropdown').filter({ has: page.locator('.mantine-Menu-item') }).first()
|
||||
await expect(menu).toBeVisible({ timeout: 5_000 })
|
||||
await expect(menu.getByRole('menuitem', { name: 'Delete' })).toBeVisible()
|
||||
await expect(menu.getByRole('menuitem', { name: 'Colors' })).toHaveCount(0)
|
||||
await page.keyboard.press('Escape')
|
||||
await expect(menu).toBeHidden({ timeout: 5_000 })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user