Skip to content

Commit

Permalink
TextHighlight: Convert component to TypeScript (#41698)
Browse files Browse the repository at this point in the history
* 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
Petter Walbø Johnsgård and mirka authored Jun 30, 2022
1 parent 0ab1138 commit e25b2ce
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 182 deletions.
4 changes: 4 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Internal

- `TextHighlight`: Convert to TypeScript ([#41698](https://github.com/WordPress/gutenberg/pull/41698)).

## 19.14.0 (2022-06-29)

### Bug Fix
Expand Down
12 changes: 6 additions & 6 deletions packages/components/src/text-highlight/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ const MyTextHighlight = () => (

The component accepts the following props.

### text
### `highlight`: `string`

The string of text to be tested for occurrences of then given `highlight`.
The string to search for and highlight within the `text`. Case insensitive. Multiple matches.

- Type: `String`
- Required: Yes
- Default: `''`

### highlight
### `text`: `string`

The string to search for and highlight within the `text`. Case insensitive. Multiple matches.
The string of text to be tested for occurrences of then given `highlight`.

- Type: `String`
- Required: Yes
- Default: `''`
28 changes: 0 additions & 28 deletions packages/components/src/text-highlight/index.js

This file was deleted.

49 changes: 49 additions & 0 deletions packages/components/src/text-highlight/index.tsx
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;
28 changes: 0 additions & 28 deletions packages/components/src/text-highlight/stories/index.js

This file was deleted.

33 changes: 33 additions & 0 deletions packages/components/src/text-highlight/stories/index.tsx
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',
};
120 changes: 0 additions & 120 deletions packages/components/src/text-highlight/test/index.js

This file was deleted.

93 changes: 93 additions & 0 deletions packages/components/src/text-highlight/test/index.tsx
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 );
} );
} );
} );
Loading

0 comments on commit e25b2ce

Please sign in to comment.