-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TextHighlight: Convert component to TypeScript (#41698)
* TextHighlight: Convert component to TypeScript * Update CHANGELOG.md * Remove return type * Format files after wp-prettier upgrade * Apply suggestions from code review Co-authored-by: Lena Morita <lena@jaguchi.com> * Update CHANGELOG.md * Update comments * Add defaults * Move changelog entry to unreleased Co-authored-by: Lena Morita <lena@jaguchi.com>
- Loading branch information
Showing
10 changed files
with
202 additions
and
182 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
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 was deleted.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { escapeRegExp } from 'lodash'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { createInterpolateElement } from '@wordpress/element'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import type { TextHighlightProps } from './types'; | ||
|
||
/** | ||
* Highlights occurrences of a given string within another string of text. Wraps | ||
* each match with a `<mark>` tag which provides browser default styling. | ||
* | ||
* ```jsx | ||
* import { TextHighlight } from '@wordpress/components'; | ||
* | ||
* const MyTextHighlight = () => ( | ||
* <TextHighlight | ||
* text="Why do we like Gutenberg? Because Gutenberg is the best!" | ||
* highlight="Gutenberg" | ||
* /> | ||
* ); | ||
* ``` | ||
*/ | ||
export const TextHighlight = ( props: TextHighlightProps ) => { | ||
const { text = '', highlight = '' } = props; | ||
const trimmedHighlightText = highlight.trim(); | ||
|
||
if ( ! trimmedHighlightText ) { | ||
return <>{ text }</>; | ||
} | ||
|
||
const regex = new RegExp( | ||
`(${ escapeRegExp( trimmedHighlightText ) })`, | ||
'gi' | ||
); | ||
|
||
return createInterpolateElement( text.replace( regex, '<mark>$&</mark>' ), { | ||
mark: <mark />, | ||
} ); | ||
}; | ||
|
||
export default TextHighlight; |
This file was deleted.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import type { ComponentMeta, ComponentStory } from '@storybook/react'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import TextHighlight from '..'; | ||
|
||
const meta: ComponentMeta< typeof TextHighlight > = { | ||
component: TextHighlight, | ||
title: 'Components/TextHighlight', | ||
parameters: { | ||
controls: { | ||
expanded: true, | ||
}, | ||
docs: { source: { state: 'open' } }, | ||
}, | ||
}; | ||
export default meta; | ||
|
||
const Template: ComponentStory< typeof TextHighlight > = ( args ) => { | ||
return <TextHighlight { ...args } />; | ||
}; | ||
|
||
export const Default: ComponentStory< typeof TextHighlight > = Template.bind( | ||
{} | ||
); | ||
Default.args = { | ||
text: 'We call the new editor Gutenberg. The entire editing experience has been rebuilt for media rich pages and posts.', | ||
highlight: 'Gutenberg', | ||
}; |
This file was deleted.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { render } from '@testing-library/react'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import TextHighlight from '..'; | ||
|
||
const getMarks = ( container: Element ) => | ||
// Use querySelectorAll because the `mark` role is not officially supported | ||
// yet. This should be changed to `getByRole` when it is. | ||
Array.from( container.querySelectorAll( 'mark' ) ); | ||
|
||
const defaultText = | ||
'We call the new editor Gutenberg. The entire editing experience has been rebuilt for media rich pages and posts.'; | ||
|
||
describe( 'TextHighlight', () => { | ||
describe( 'Basic rendering', () => { | ||
it.each( [ [ 'Gutenberg' ], [ 'media' ] ] )( | ||
'should highlight the singular occurance of the text "%s" in the text if it exists', | ||
( highlight ) => { | ||
const { container } = render( | ||
<TextHighlight | ||
text={ defaultText } | ||
highlight={ highlight } | ||
/> | ||
); | ||
|
||
const highlightedEls = getMarks( container ); | ||
|
||
highlightedEls.forEach( ( el ) => { | ||
expect( el ).toHaveTextContent( | ||
new RegExp( `^${ highlight }$` ) | ||
); | ||
} ); | ||
} | ||
); | ||
|
||
it( 'should highlight multiple occurances of the string every time it exists in the text', () => { | ||
const highlight = 'edit'; | ||
|
||
const { container } = render( | ||
<TextHighlight text={ defaultText } highlight={ highlight } /> | ||
); | ||
|
||
const highlightedEls = getMarks( container ); | ||
|
||
expect( highlightedEls ).toHaveLength( 2 ); | ||
|
||
highlightedEls.forEach( ( el ) => { | ||
expect( el.textContent ).toEqual( | ||
expect.stringContaining( highlight ) | ||
); | ||
} ); | ||
} ); | ||
|
||
it( 'should highlight occurances of a string regardless of capitalisation', () => { | ||
// Note that `The` occurs twice in the default text, once in | ||
// lowercase and once capitalized. | ||
const highlight = 'The'; | ||
|
||
const { container } = render( | ||
<TextHighlight text={ defaultText } highlight={ highlight } /> | ||
); | ||
|
||
const highlightedEls = getMarks( container ); | ||
|
||
expect( highlightedEls ).toHaveLength( 2 ); | ||
|
||
// Make sure the matcher is case insensitive, since the test should | ||
// match regardless of the case of the string. | ||
const regex = new RegExp( highlight, 'i' ); | ||
|
||
highlightedEls.forEach( ( el ) => { | ||
expect( el.innerHTML ).toMatch( regex ); | ||
} ); | ||
} ); | ||
|
||
it( 'should not highlight a string that is not in the text', () => { | ||
const highlight = 'Antidisestablishmentarianism'; | ||
|
||
const { container } = render( | ||
<TextHighlight text={ defaultText } highlight={ highlight } /> | ||
); | ||
|
||
const highlightedEls = getMarks( container ); | ||
|
||
expect( highlightedEls ).toHaveLength( 0 ); | ||
} ); | ||
} ); | ||
} ); |
Oops, something went wrong.