-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(RichTextEditor): integrate Image plugin (#3723)
- Loading branch information
1 parent
0efcb95
commit 11d8463
Showing
37 changed files
with
961 additions
and
33 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 |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
'@toptal/picasso-rich-text-editor': major | ||
--- | ||
|
||
### RichText | ||
|
||
- add support for images ([example](https://picasso.toptal.net/?path=/story/forms-richtexteditor--richtexteditor#image-upload)) | ||
- update peer dependency of Picasso to `37.1.0` (BREAKING CHANGE) |
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
File renamed without changes.
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,159 @@ | ||
import React, { useState } from 'react' | ||
import type { | ||
RichTextEditorProps, | ||
UploadedImage, | ||
} from '@toptal/picasso-rich-text-editor' | ||
import { ImagePlugin, RichTextEditor } from '@toptal/picasso-rich-text-editor' | ||
import { Container } from '@toptal/picasso' | ||
|
||
const editorTestId = 'editor' | ||
const imageUploadButtonTestId = 'image-upload-button' | ||
const resultContainerTestId = 'result-container' | ||
|
||
const defaultProps = { | ||
id: 'foo', | ||
onChange: () => {}, | ||
placeholder: 'placeholder', | ||
testIds: { | ||
editor: editorTestId, | ||
imageUploadButton: imageUploadButtonTestId, | ||
}, | ||
} | ||
|
||
const editorSelector = `#${defaultProps.id}` | ||
|
||
const Editor = (props: RichTextEditorProps) => { | ||
const [value, setValue] = useState('') | ||
|
||
return ( | ||
<Container style={{ maxWidth: '600px' }} padded='small'> | ||
<RichTextEditor {...props} onChange={value => setValue(value)} /> | ||
<Container padded='small' data-testid={resultContainerTestId}> | ||
{value} | ||
</Container> | ||
</Container> | ||
) | ||
} | ||
|
||
const component = 'RichTextEditor' | ||
|
||
const setAliases = () => { | ||
cy.get(editorSelector).as('editor') | ||
cy.getByTestId(imageUploadButtonTestId).as('imageUploadButton') | ||
cy.getByTestId(resultContainerTestId).as('resultContainer') | ||
cy.contains('placeholder').as('placeholder') | ||
} | ||
|
||
const getSubmitButton = () => | ||
cy.get('button').contains('Confirm').closest('button') | ||
|
||
describe('ImagePlugin', () => { | ||
describe('when image upload is successful', () => { | ||
it('inserts image into rich text editor', () => { | ||
const uploadedFileName = 'uploaded-image.png' | ||
const uploadedFileContent = | ||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAANklEQVR42u3OMQ0AAAgDsM2/aFBBwtEqaJOZPFZBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQcEbC6LIT9nCVOrVAAAAAElFTkSuQmCC' | ||
const uploadedFileAltText = 'alt text' | ||
|
||
cy.mount( | ||
<Editor | ||
{...{ | ||
...defaultProps, | ||
plugins: [ | ||
<ImagePlugin | ||
data-testid={imageUploadButtonTestId} | ||
onUpload={(file: UploadedImage) => | ||
new Promise<UploadedImage>(resolve => { | ||
setTimeout( | ||
() => | ||
resolve({ | ||
...file, | ||
url: uploadedFileContent, | ||
}), | ||
200 | ||
) | ||
}) | ||
} | ||
/>, | ||
], | ||
}} | ||
/> | ||
) | ||
setAliases() | ||
|
||
cy.get('@editor').click() | ||
cy.get('@imageUploadButton').click() | ||
|
||
cy.getByRole('dialog').contains('No file chosen') | ||
|
||
getSubmitButton().should('be.disabled') | ||
|
||
cy.get('input[type=file]').selectFile( | ||
{ | ||
contents: Cypress.Buffer.from(''), | ||
fileName: uploadedFileName, | ||
}, | ||
{ force: true } | ||
) | ||
|
||
cy.getByRole('dialog').contains('Uploading ' + uploadedFileName) | ||
cy.getByRole('dialog').contains(uploadedFileName) | ||
cy.get('[placeholder="An Image Description"]').type(uploadedFileAltText) | ||
|
||
getSubmitButton().should('not.be.disabled') | ||
getSubmitButton().click() | ||
|
||
cy.get('@resultContainer').contains( | ||
`<p><img src="${uploadedFileContent}" alt="${uploadedFileAltText}"></p>` | ||
) | ||
|
||
cy.get('body').happoScreenshot({ | ||
component, | ||
variant: 'image-plugin/successful-upload', | ||
}) | ||
}) | ||
}) | ||
|
||
describe('when image upload fails', () => { | ||
it('shows error', () => { | ||
const fileUploadErrorMessage = 'Upload failed' | ||
|
||
cy.mount( | ||
<Editor | ||
{...{ | ||
...defaultProps, | ||
plugins: [ | ||
<ImagePlugin | ||
data-testid={imageUploadButtonTestId} | ||
onUpload={() => | ||
new Promise<UploadedImage>((resolve, reject) => { | ||
setTimeout(() => reject(fileUploadErrorMessage), 200) | ||
}) | ||
} | ||
/>, | ||
], | ||
}} | ||
/> | ||
) | ||
setAliases() | ||
|
||
cy.get('@editor').click() | ||
cy.get('@imageUploadButton').click() | ||
|
||
cy.get('input[type=file]').selectFile( | ||
{ | ||
contents: Cypress.Buffer.from('file contents'), | ||
fileName: 'test.png', | ||
}, | ||
{ force: true } | ||
) | ||
|
||
cy.get('p').contains(fileUploadErrorMessage).should('be.visible') | ||
|
||
cy.get('[role="presentation"]').happoScreenshot({ | ||
component, | ||
variant: 'image-plugin/failed-upload', | ||
}) | ||
}) | ||
}) | ||
}) |
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
19 changes: 19 additions & 0 deletions
19
packages/picasso-rich-text-editor/src/RichText/components/Emoji.tsx
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,19 @@ | ||
import React from 'react' | ||
import type { ReactNode } from 'react' | ||
import { makeStyles } from '@material-ui/core' | ||
|
||
const useStyles = makeStyles({ | ||
default: { | ||
maxWidth: 24, | ||
height: 24, | ||
verticalAlign: 'bottom', | ||
}, | ||
}) | ||
|
||
const Emoji = (props: { children?: ReactNode }) => { | ||
const classes = useStyles() | ||
|
||
return <img className={classes.default} {...props} /> | ||
} | ||
|
||
export default Emoji |
17 changes: 17 additions & 0 deletions
17
packages/picasso-rich-text-editor/src/RichText/components/Image.tsx
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,17 @@ | ||
import React from 'react' | ||
import type { ReactNode } from 'react' | ||
import { makeStyles } from '@material-ui/core' | ||
|
||
const useStyles = makeStyles({ | ||
default: { | ||
maxWidth: '100%', | ||
}, | ||
}) | ||
|
||
const Image = (props: { children?: ReactNode }) => { | ||
const classes = useStyles() | ||
|
||
return <img className={classes.default} {...props} /> | ||
} | ||
|
||
export default Image |
2 changes: 2 additions & 0 deletions
2
packages/picasso-rich-text-editor/src/RichText/components/index.ts
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,2 @@ | ||
export { default as Emoji } from './Emoji' | ||
export { default as Image } from './Image' |
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
Oops, something went wrong.