-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1013 from tomrule007/feature/markdown-toolbar
WIP Feature/markdown toolbar
- Loading branch information
Showing
31 changed files
with
19,252 additions
and
84 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
export const mockUseBreakpoint = jest.fn(() => false) | ||
jest.mock('../helpers/useBreakpoint', () => mockUseBreakpoint) | ||
jest.mock('../helpers/useBreakpoint', () => ({ | ||
__esModule: true, | ||
default: mockUseBreakpoint | ||
})) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export const mockUseIsMac = jest.fn(() => false) | ||
jest.mock('../helpers/useIsMac', () => ({ | ||
__esModule: true, | ||
default: mockUseIsMac | ||
})) |
Large diffs are not rendered by default.
Oops, something went wrong.
3,984 changes: 3,984 additions & 0 deletions
3,984
__tests__/pages/admin/__snapshots__/lessons.test.js.snap
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
498 changes: 498 additions & 0 deletions
498
__tests__/pages/review/__snapshots__/[lesson].test.js.snap
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import React from 'react' | ||
import { render, screen } from '@testing-library/react' | ||
import userEvent from '@testing-library/user-event' | ||
import '@testing-library/jest-dom' | ||
import MarkdownToolbar from './MarkdownToolbar' | ||
import { markdown } from '../helpers/textStylers' | ||
jest.mock('../helpers/textStylers') | ||
describe('MarkdownToolbar Component', () => { | ||
const mockTextArea = {} | ||
const mockRef = { current: mockTextArea } | ||
|
||
test('Should match screenshot', () => { | ||
const { container } = render( | ||
<MarkdownToolbar isMac={false} inputRef={mockRef} onChange={() => {}} /> | ||
) | ||
expect(container).toMatchSnapshot() | ||
}) | ||
test('Should render "cmd" based hotkey tooltips for Mac users', () => { | ||
render( | ||
<MarkdownToolbar isMac={true} inputRef={mockRef} onChange={() => {}} /> | ||
) | ||
expect(screen.queryAllByLabelText(/ctrl/).length).toBe(0) | ||
expect(screen.queryAllByLabelText(/cmd/).length).toBeGreaterThan(0) | ||
}) | ||
test('Should render "ctrl" based hotkey tooltips for non Mac users', () => { | ||
render( | ||
<MarkdownToolbar isMac={false} inputRef={mockRef} onChange={() => {}} /> | ||
) | ||
expect(screen.queryAllByLabelText(/ctrl/).length).toBeGreaterThan(0) | ||
expect(screen.queryAllByLabelText(/cmd/).length).toBe(0) | ||
}) | ||
test('does not call onChange if inputRef.current is null', () => { | ||
const nullRef = { current: null } | ||
const mockOnChange = jest.fn() | ||
render( | ||
<MarkdownToolbar | ||
isMac={false} | ||
inputRef={nullRef} | ||
onChange={mockOnChange} | ||
/> | ||
) | ||
userEvent.click(screen.getByRole('button', { name: /header/ })) | ||
expect(mockOnChange).not.toBeCalled() | ||
}) | ||
|
||
describe('Buttons should call markdown stylers when clicked', () => { | ||
test('header calls -> markdown.header', () => { | ||
render( | ||
<MarkdownToolbar isMac={false} inputRef={mockRef} onChange={() => {}} /> | ||
) | ||
userEvent.click(screen.getByRole('button', { name: /header/ })) | ||
expect(markdown.header).toBeCalledWith(mockTextArea) | ||
}) | ||
|
||
test('bold calls -> markdown.bold', () => { | ||
render( | ||
<MarkdownToolbar isMac={false} inputRef={mockRef} onChange={() => {}} /> | ||
) | ||
userEvent.click(screen.getByRole('button', { name: /bold/ })) | ||
expect(markdown.bold).toBeCalledWith(mockTextArea) | ||
}) | ||
|
||
test('italic calls -> markdown.italic', () => { | ||
render( | ||
<MarkdownToolbar isMac={false} inputRef={mockRef} onChange={() => {}} /> | ||
) | ||
userEvent.click(screen.getByRole('button', { name: /italic/ })) | ||
expect(markdown.italic).toBeCalledWith(mockTextArea) | ||
}) | ||
|
||
test('quote calls -> markdown.quote', () => { | ||
render( | ||
<MarkdownToolbar isMac={false} inputRef={mockRef} onChange={() => {}} /> | ||
) | ||
userEvent.click(screen.getByRole('button', { name: /quote/ })) | ||
expect(markdown.quote).toBeCalledWith(mockTextArea) | ||
}) | ||
|
||
test('code calls -> markdown.code', () => { | ||
render( | ||
<MarkdownToolbar isMac={false} inputRef={mockRef} onChange={() => {}} /> | ||
) | ||
userEvent.click(screen.getByRole('button', { name: /code/ })) | ||
expect(markdown.code).toBeCalledWith(mockTextArea) | ||
}) | ||
|
||
test('link calls -> markdown.link', () => { | ||
render( | ||
<MarkdownToolbar isMac={false} inputRef={mockRef} onChange={() => {}} /> | ||
) | ||
userEvent.click(screen.getByRole('button', { name: /link/ })) | ||
expect(markdown.link).toBeCalledWith(mockTextArea) | ||
}) | ||
|
||
test('bulletList calls -> markdown.bulletList', () => { | ||
render( | ||
<MarkdownToolbar isMac={false} inputRef={mockRef} onChange={() => {}} /> | ||
) | ||
userEvent.click(screen.getByRole('button', { name: /bulleted list/ })) | ||
expect(markdown.bulletList).toBeCalledWith(mockTextArea) | ||
}) | ||
|
||
test('orderedList calls -> markdown.orderedList', () => { | ||
render( | ||
<MarkdownToolbar isMac={false} inputRef={mockRef} onChange={() => {}} /> | ||
) | ||
userEvent.click(screen.getByRole('button', { name: /numbered list/ })) | ||
expect(markdown.orderedList).toBeCalledWith(mockTextArea) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import React from 'react' | ||
import { | ||
HeadingIcon, | ||
BoldIcon, | ||
ItalicIcon, | ||
QuoteIcon, | ||
CodeIcon, | ||
LinkIcon, | ||
ListUnorderedIcon, | ||
ListOrderedIcon, | ||
Icon | ||
} from '@primer/octicons-react' | ||
import { ButtonToolbar, OverlayTrigger, Tooltip } from 'react-bootstrap' | ||
import { markdown, TextAreaState } from '../helpers/textStylers' | ||
|
||
type ButtonProps = { | ||
tooltipTitle: string | ||
hotkey?: string | ||
macHotkey?: string | ||
handleMarkdown: (i: HTMLTextAreaElement) => TextAreaState | ||
Icon: Icon | ||
} | ||
|
||
// The hotkeys are registered in the MdInput.tsx files hotkeyMap | ||
// Any changes to the hotkeys here will need to match those hotkeys | ||
const buttons: ButtonProps[] = [ | ||
{ | ||
tooltipTitle: 'Add header text', | ||
handleMarkdown: markdown.header, | ||
Icon: HeadingIcon | ||
}, | ||
{ | ||
tooltipTitle: 'Add bold text', | ||
hotkey: 'ctrl+b', | ||
macHotkey: 'cmd+b', | ||
handleMarkdown: markdown.bold, | ||
Icon: BoldIcon | ||
}, | ||
{ | ||
tooltipTitle: 'Add italic text', | ||
hotkey: 'ctrl+i', | ||
macHotkey: 'cmd+i', | ||
handleMarkdown: markdown.italic, | ||
Icon: ItalicIcon | ||
}, | ||
{ | ||
tooltipTitle: 'Insert a quote', | ||
hotkey: 'ctrl+shift+.', | ||
macHotkey: 'cmd+shift+.', | ||
handleMarkdown: markdown.quote, | ||
Icon: QuoteIcon | ||
}, | ||
{ | ||
tooltipTitle: 'Insert code', | ||
hotkey: 'ctrl+e', | ||
macHotkey: 'cmd+e', | ||
handleMarkdown: markdown.code, | ||
Icon: CodeIcon | ||
}, | ||
{ | ||
tooltipTitle: 'Add a link', | ||
hotkey: 'ctrl+k', | ||
macHotkey: 'cmd+k', | ||
handleMarkdown: markdown.link, | ||
Icon: LinkIcon | ||
}, | ||
{ | ||
tooltipTitle: 'Add a bulleted list', | ||
hotkey: 'ctrl+shift+8', | ||
macHotkey: 'cmd+shift+8', | ||
handleMarkdown: markdown.bulletList, | ||
Icon: ListUnorderedIcon | ||
}, | ||
{ | ||
tooltipTitle: 'Add a numbered list', | ||
hotkey: 'ctrl+shift+7', | ||
macHotkey: 'cmd+shift+7', | ||
handleMarkdown: markdown.orderedList, | ||
Icon: ListOrderedIcon | ||
} | ||
] | ||
|
||
type Props = { | ||
isMac: boolean | ||
className?: string | ||
inputRef: React.RefObject<HTMLTextAreaElement> | ||
onChange: (i: TextAreaState) => void | ||
} | ||
|
||
const MarkdownToolbar: React.FC<Props> = ({ | ||
isMac, | ||
inputRef, | ||
onChange, | ||
className = '' | ||
}) => { | ||
return ( | ||
<ButtonToolbar className={className}> | ||
{buttons.map( | ||
({ tooltipTitle, handleMarkdown, Icon, macHotkey, hotkey }, i) => { | ||
const hotkeyString = isMac ? macHotkey : hotkey | ||
const tooltipWithHotkey = | ||
tooltipTitle + (hotkeyString ? ` <${hotkeyString}>` : '') | ||
return ( | ||
<OverlayTrigger | ||
key={i} | ||
placement="bottom-end" | ||
delay={{ show: 200, hide: 100 }} | ||
overlay={<Tooltip id="btn-tooltip">{tooltipWithHotkey}</Tooltip>} | ||
> | ||
{({ ref, ...triggerHandler }) => { | ||
return ( | ||
<button | ||
className="btn" | ||
{...triggerHandler} | ||
ref={ref} | ||
aria-label={tooltipWithHotkey} | ||
onClick={() => { | ||
inputRef.current && | ||
onChange(handleMarkdown(inputRef.current)) | ||
}} | ||
> | ||
<Icon size={'small'} /> | ||
</button> | ||
) | ||
}} | ||
</OverlayTrigger> | ||
) | ||
} | ||
)} | ||
</ButtonToolbar> | ||
) | ||
} | ||
|
||
export default MarkdownToolbar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
f06753b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs: