Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .changeset/nasty-apricots-whisper.md

This file was deleted.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
157 changes: 157 additions & 0 deletions docs/content/drafts/MarkdownEditor.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
---
componentId: markdown_editor
title: MarkdownEditor
status: Deprecated
description: Full-featured Markdown input.
storybook: '/react/storybook?path=/story/components-forms-markdowneditor--default'
---

import data from '../../../packages/react/src/drafts/MarkdownEditor/MarkdownEditor.docs.json'

```js
import {MarkdownEditor} from '@primer/react/drafts'
```

`MarkdownEditor` is a full-featured editor for GitHub Flavored Markdown, with support for:

- Formatting (keyboard shortcuts & toolbar buttons)
- File uploads (drag & drop, paste, click to upload)
- Inline suggestions (emojis, `@` mentions, and `#` references)
- Saved replies
- Markdown pasting (ie, paste URL onto selected text to create a link)
- List editing (create a new list item on `Enter`)
- Indenting selected text

## Examples

### Minimal Example

A `Label` is always required for accessibility:

```javascript live noinline drafts
const renderMarkdown = async markdown => {
// In production code, this would make a query to some external API endpoint to render
return 'Rendered Markdown.'
}

const MinimalExample = () => {
const [value, setValue] = React.useState('')

return (
<MarkdownEditor value={value} onChange={setValue} onRenderPreview={renderMarkdown}>
<MarkdownEditor.Label>Minimal Example</MarkdownEditor.Label>
</MarkdownEditor>
)
}

render(MinimalExample)
```

### Suggestions, File Uploads, and Saved Replies

```javascript live noinline drafts
const renderMarkdown = async markdown => 'Rendered Markdown.'

const uploadFile = async file => ({
url: `https://example.com/${encodeURIComponent(file.name)}`,
file,
})

const emojis = [
{name: '+1', character: '👍'},
{name: '-1', character: '👎'},
{name: 'heart', character: '❤️'},
{name: 'wave', character: '👋'},
{name: 'raised_hands', character: '🙌'},
{name: 'pray', character: '🙏'},
{name: 'clap', character: '👏'},
{name: 'ok_hand', character: '👌'},
{name: 'point_up', character: '☝️'},
{name: 'point_down', character: '👇'},
{name: 'point_left', character: '👈'},
{name: 'point_right', character: '👉'},
{name: 'raised_hand', character: '✋'},
{name: 'thumbsup', character: '👍'},
{name: 'thumbsdown', character: '👎'},
]

const references = [
{id: '1', titleText: 'Add logging functionality', titleHtml: 'Add logging functionality'},
{
id: '2',
titleText: 'Error: `Failed to install` when installing',
titleHtml: 'Error: <code>Failed to install</code> when installing',
},
{id: '3', titleText: 'Add error-handling functionality', titleHtml: 'Add error-handling functionality'},
]

const mentionables = [
{identifier: 'monalisa', description: 'Monalisa Octocat'},
{identifier: 'github', description: 'GitHub'},
{identifier: 'primer', description: 'Primer'},
]

const savedReplies = [
{name: 'Duplicate', content: 'Duplicate of #'},
{name: 'Welcome', content: 'Welcome to the project!\n\nPlease be sure to read the contributor guidelines.'},
{name: 'Thanks', content: 'Thanks for your contribution!'},
]

const MinimalExample = () => {
const [value, setValue] = React.useState('')

return (
<MarkdownEditor
value={value}
onChange={setValue}
onRenderPreview={renderMarkdown}
onUploadFile={uploadFile}
emojiSuggestions={emojis}
referenceSuggestions={references}
mentionSuggestions={mentionables}
savedReplies={savedReplies}
>
<MarkdownEditor.Label>Suggestions, File Uploads, and Saved Replies Example</MarkdownEditor.Label>
</MarkdownEditor>
)
}

render(MinimalExample)
```

### Custom Buttons

```javascript live noinline drafts
const renderMarkdown = async markdown => 'Rendered Markdown.'

const MinimalExample = () => {
const [value, setValue] = React.useState('')

return (
<MarkdownEditor value={value} onChange={setValue} onRenderPreview={renderMarkdown}>
<MarkdownEditor.Label visuallyHidden>Custom Buttons</MarkdownEditor.Label>

<MarkdownEditor.Toolbar>
<MarkdownEditor.ToolbarButton icon={SquirrelIcon} aria-label="Custom button 1" />
<MarkdownEditor.DefaultToolbarButtons />
<MarkdownEditor.ToolbarButton icon={BugIcon} aria-label="Custom button 2" />
</MarkdownEditor.Toolbar>

<MarkdownEditor.Footer>
<MarkdownEditor.FooterButton variant="danger">Custom Button</MarkdownEditor.FooterButton>

<MarkdownEditor.Action>
<MarkdownEditor.ActionButton variant="danger">Cancel</MarkdownEditor.ActionButton>
<MarkdownEditor.ActionButton variant="primary">Submit</MarkdownEditor.ActionButton>
</MarkdownEditor.Action>
</MarkdownEditor.Footer>
</MarkdownEditor>
)
}

render(MinimalExample)
```

## Props

<ComponentProps data={data} />
103 changes: 103 additions & 0 deletions docs/content/drafts/MarkdownViewer.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
componentId: markdown_viewer
title: MarkdownViewer
status: Deprecated
description: Displays rendered Markdown and facilitates interaction.
---

import data from '../../../packages/react/src/drafts/MarkdownViewer/MarkdownViewer.docs.json'

```js
import {MarkdownViewer} from '@primer/react/drafts'
```

The `MarkdownViewer` displays rendered Markdown and handles interaction (link clicking and checkbox checking/unchecking) with that content.

## Examples

### Simple Example

```javascript live noinline drafts
const MarkdownViewerExample = () => {
return (
// eslint-disable-next-line github/unescaped-html-literal
<MarkdownViewer dangerousRenderedHTML={{__html: '<strong>Lorem ipsum</strong> dolor sit amet.'}} />
)
}

render(MarkdownViewerExample)
```

### Link-Handling Example

```javascript live noinline drafts
const MarkdownViewerExample = () => {
return (
<MarkdownViewer
// eslint-disable-next-line github/unescaped-html-literal
dangerousRenderedHTML={{__html: "<a href='https://example.com'>Example link</a>"}}
onLinkClick={ev => console.log(ev)}
/>
)
}

render(MarkdownViewerExample)
```

### Checkbox Interaction Example

```javascript live noinline drafts
const markdownSource = `
text before list

- [ ] item 1
- [ ] item 2

text after list`

const renderedHtml = `
<p>text before list</p>
<ul class='contains-task-list'>
<li class='task-list-item'><input type='checkbox' class='task-list-item-checkbox' disabled/> item 1</li>
<li class='task-list-item'><input type='checkbox' class='task-list-item-checkbox' disabled/> item 2</li>
</ul>
<p>text after list</p>`

const MarkdownViewerExample = () => {
return (
<MarkdownViewer
dangerousRenderedHTML={{__html: renderedHtml}}
markdownValue={markdownSource}
onChange={value => console.log(value) /* save the value to the server */}
disabled={false}
/>
)
}

render(MarkdownViewerExample)
```

## Props

<ComponentProps data={data} />

## Status

<ComponentChecklist
items={{
propsDocumented: false,
noUnnecessaryDeps: true,
adaptsToThemes: true,
adaptsToScreenSizes: true,
fullTestCoverage: true,
usedInProduction: true,
usageExamplesDocumented: false,
hasStorybookStories: false,
designReviewed: false,
a11yReviewed: false,
stableApi: false,
addressedApiFeedback: false,
hasDesignGuidelines: false,
hasFigmaComponent: false,
}}
/>
44 changes: 22 additions & 22 deletions e2e/components/drafts/ActionBar.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ import {themes} from '../../test-helpers/themes'
import {viewports} from '../../test-helpers/viewports'

test.describe('ActionBar', () => {
test.describe('Default', () => {
test.describe('Default state', () => {
for (const theme of themes) {
test.describe(theme, () => {
test('default @vrt', async ({page}) => {
await visit(page, {
id: 'drafts-components-actionbar--default',
id: 'drafts-components-actionbar--comment-box',
globals: {
colorScheme: theme,
},
})
expect(await page.screenshot()).toMatchSnapshot(`drafts.ActionBar.${theme}.png`)
expect(await page.screenshot()).toMatchSnapshot(`drafts.ActionBar.CommentBox.${theme}.png`)
})

test('axe @aat', async ({page}) => {
await visit(page, {
id: 'drafts-components-actionbar--default',
id: 'drafts-components-actionbar--comment-box',
globals: {
colorScheme: theme,
},
Expand All @@ -31,24 +31,24 @@ test.describe('ActionBar', () => {
})

test.describe('ActionBar Interactions', () => {
test('Overflow interaction @vrt', async ({page}) => {
await visit(page, {
id: 'drafts-components-actionbar--default',
for (const theme of themes) {
test.describe(theme, () => {
test('Overflow interaction @vrt', async ({page}) => {
await visit(page, {
id: 'drafts-components-actionbar--comment-box',
globals: {
colorScheme: theme,
},
})
const toolbarButtonSelector = `button[data-component="IconButton"]`
await expect(page.locator(toolbarButtonSelector)).toHaveCount(10)
await page.setViewportSize({width: viewports['primer.breakpoint.xs'], height: 768})
await expect(page.locator(toolbarButtonSelector)).toHaveCount(6)
const moreButtonSelector = page.getByLabel('More Comment box toolbar items')
await moreButtonSelector.click()
await expect(page.locator('ul[role="menu"]>li')).toHaveCount(5)
})
})

await page.setViewportSize({width: viewports['primer.breakpoint.lg'], height: 768})

const toolbarButtonSelector = `button[data-component="IconButton"]`
await expect(page.locator(toolbarButtonSelector)).toHaveCount(10)

await page.setViewportSize({width: 320, height: 768})
await page.getByLabel('More Toolbar items').waitFor()

await expect(page.locator(toolbarButtonSelector)).toHaveCount(6)

const moreButtonSelector = page.getByLabel('More Toolbar items')
await moreButtonSelector.click()
await expect(page.locator('ul[role="menu"] > li')).toHaveCount(5)
})
}
})
})
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,4 @@
"lint-staged": {
"**/*.{js,ts,tsx,md,mdx}": "npm run lint"
}
}
}
Loading