Skip to content
This repository has been archived by the owner on Oct 16, 2024. It is now read-only.

Validate new categories on input #198

Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import { PluginDocumentSettingPanel } from '@wordpress/edit-post';
import { Spinner } from '@wordpress/components';

Expand All @@ -7,6 +8,10 @@ import Creatable from 'react-select/creatable';
import toKebabCase from '../../utils/toKebabCase';
import getSelectedOptions from '../../utils/getSelectedOptions';
import getCustomCategories from '../../utils/getCustomCategories';
import {
checkIllegalChars,
stripIllegalChars,
} from '../../utils/validateInput';
import type { BaseSidebarProps, AdditionalSidebarProps } from './types';

/**
Expand All @@ -20,6 +25,9 @@ export default function CategoriesPanel( {
handleChange,
}: BaseSidebarProps< 'categories' | 'customCategories' > &
AdditionalSidebarProps< 'categoryOptions' > ) {
const [ categoryTitleIsInvalid, setCategoryTitleIsInvalid ] =
useState( false );
Comment on lines +25 to +26
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't think of a simple way to show the modified style (the styles prop in Creatable below) without using state.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine, it's simple


return (
<PluginDocumentSettingPanel
name="patternmanager-pattern-editor-pattern-categories"
Expand Down Expand Up @@ -55,7 +63,10 @@ export default function CategoriesPanel( {
onCreateOption={ ( newCategoryTitle ) => {
handleChange(
'customCategories',
[ ...customCategories, newCategoryTitle ],
[
...customCategories,
stripIllegalChars( newCategoryTitle ),
kienstra marked this conversation as resolved.
Show resolved Hide resolved
],
{
categories: [
...categories,
Expand All @@ -64,12 +75,29 @@ export default function CategoriesPanel( {
}
);
} }
onInputChange={ ( event ) => {
setCategoryTitleIsInvalid(
!! checkIllegalChars( event )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe checkIllegalChars() could return a boolean, so it doesn't need !! in front of it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good suggestion! Updated with 0e133b2.

Copy link
Contributor Author

@mike-day mike-day Jun 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the name to hasIllegalChars for that function as well. It is a much more descriptive name for this usage.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0e133b2 looks good! Good idea for hasIllegalChars().

);
} }
formatCreateLabel={ ( userInput ) =>
`Create "${ stripIllegalChars( userInput ) }"`
}
menuPlacement="auto"
styles={ {
menu: ( base ) => ( {
...base,
zIndex: 100,
} ),
control: ( baseStyles ) => ( {
...baseStyles,
borderColor: categoryTitleIsInvalid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice handling.

You can still create a category with the valid characters, but you know something's invalid:

Screenshot 2023-06-15 at 3 19 24 PM

? 'red !important'
: baseStyles.borderColor,
boxShadow: categoryTitleIsInvalid
? '0 0 0 1px red'
: baseStyles.boxShadow,
} ),
} }
/>
) : (
Expand Down
37 changes: 37 additions & 0 deletions wp-modules/editor/js/src/utils/test/validateInput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { checkIllegalChars, stripIllegalChars } from '../validateInput';

const regexPattern = new RegExp( /([^a-z0-9 -]+)/gi );

describe( 'validateInput', () => {
describe( 'checkIllegalChars', () => {
it.each( [
[ '', null ],
[ 'Nothing to strip', null ],
[ 'String with !#@$%^&*() illegal chars', [ '!#@$%^&*()' ] ],
[
'String !#@$% with ^&*() separated \'"? illegal []{}|/ chars',
[ '!#@$%', '^&*()', '\'"?', '[]{}|/' ],
],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good test cases

] )( 'matches the illegal characters', ( input, expected ) => {
expect( checkIllegalChars( input, regexPattern ) ).toEqual(
expected
);
} );
} );
describe( 'stripIllegalChars', () => {
it.each( [
[ '', '' ],
[ 'Nothing to strip', 'Nothing to strip' ],
[
'String with !#@$%^&*() illegal chars',
'String with illegal chars',
],
[
"This might've caused a whitescreen previously!",
'This mightve caused a whitescreen previously',
],
] )( 'strips the illegal characters', ( input, expected ) => {
expect( stripIllegalChars( input, regexPattern ) ).toBe( expected );
} );
} );
} );
15 changes: 15 additions & 0 deletions wp-modules/editor/js/src/utils/validateInput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const defaultPattern = new RegExp( /([^a-z0-9 -]+)/gi );
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defaultPattern (and its usage as a default param) might be unneeded, but I like how simple it is to test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, you knew I'd comment on that! 🤣

Good enough reason to keep defaultPattern


export function checkIllegalChars(
input: string,
regexPattern = defaultPattern
) {
return input.match( regexPattern );
}

export function stripIllegalChars(
input: string,
regexPattern = defaultPattern
) {
return input.replace( regexPattern, '' );
}