Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interactivity API: Allow more directives suffixes #65803

Open
wants to merge 12 commits into
base: trunk
Choose a base branch
from
29 changes: 17 additions & 12 deletions packages/interactivity/src/directives.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -354,19 +354,24 @@ export default () => {
.forEach( ( entry ) => {
const className = entry.suffix;
const result = evaluate( entry );
const currentClass = element.props.class || '';
const classFinder = new RegExp(
`(^|\\s)${ className }(\\s|$)`,
'g'
);
Comment on lines -365 to -368
Copy link
Member Author

Choose a reason for hiding this comment

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

Independent of the other changes, this is likely a good change. Building a regex effectively from an input string like was done here is risky.

Copy link
Member Author

Choose a reason for hiding this comment

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

This change is necessary here because there are number of special characters that would need special processing in the Regexp like [].


const classProxyElement = document.createElement( 'div' );
if ( 'string' === typeof element.props.class ) {
classProxyElement.className = element.props.class;
}

if ( ! result ) {
element.props.class = currentClass
.replace( classFinder, ' ' )
.trim();
} else if ( ! classFinder.test( currentClass ) ) {
element.props.class = currentClass
? `${ currentClass } ${ className }`
: className;
if (
classProxyElement.classList.contains( className )
) {
classProxyElement.classList.remove( className );
element.props.class = classProxyElement.className;
}
} else if (
! classProxyElement.classList.contains( className )
) {
classProxyElement.classList.add( className );
element.props.class = classProxyElement.className;
}
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved

useInit( () => {
Expand Down
16 changes: 8 additions & 8 deletions packages/interactivity/src/vdom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,15 @@ const isObject = ( item: unknown ): item is Record< string, unknown > =>

// Regular expression for directive parsing.
const directiveParser = new RegExp(
`^data-${ p }-` + // ${p} must be a prefix string, like 'wp'.
`^${ fullPrefix }` + // ${fullPrefix} is the expected prefix string: "data-wp-".
// Match alphanumeric characters including hyphen-separated
// segments. It excludes underscore intentionally to prevent confusion.
// E.g., "custom-directive".
'([a-z0-9]+(?:-[a-z0-9]+)*)' +
'(?:[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)' +
// (Optional) Match '--' followed by any alphanumeric charachters. It
// excludes underscore intentionally to prevent confusion, but it can
// contain multiple hyphens. E.g., "--custom-prefix--with-more-info".
'(?:--([a-z0-9_-]+))?$',
'i' // Case insensitive.
'(?:--)?'
);

// Regular expression for reference parsing. It can contain a namespace before
Expand Down Expand Up @@ -141,13 +140,14 @@ export function toVdom( root: Node ): Array< ComponentChild > {
if ( directives.length ) {
props.__directives = directives.reduce(
( obj, [ name, ns, value ] ) => {
const directiveMatch = directiveParser.exec( name );
if ( directiveMatch === null ) {
if ( ! directiveParser.test( name ) ) {
warn( `Found malformed directive name: ${ name }.` );
return obj;
}
const prefix = directiveMatch[ 1 ] || '';
const suffix = directiveMatch[ 2 ] || 'default';

const [ prefix, suffix = 'default' ] = name
.slice( fullPrefix.length )
.split( '--', 2 );

obj[ prefix ] = obj[ prefix ] || [];
obj[ prefix ].push( {
Expand Down
Loading