diff --git a/packages/interactivity/src/constants.js b/packages/interactivity/src/constants.js index f462753c9f8179..669e94263fb9ca 100644 --- a/packages/interactivity/src/constants.js +++ b/packages/interactivity/src/constants.js @@ -1 +1 @@ -export const directivePrefix = 'data-wp-'; +export const directivePrefix = 'wp'; diff --git a/packages/interactivity/src/directives.js b/packages/interactivity/src/directives.js index 14151945674222..5ecdcf6c4d6b93 100644 --- a/packages/interactivity/src/directives.js +++ b/packages/interactivity/src/directives.js @@ -64,7 +64,7 @@ export default () => { ); } ); - // data-wp-effect.[name] + // data-wp-effect--[name] directive( 'effect', ( { directives: { effect }, context, evaluate } ) => { const contextValue = useContext( context ); Object.values( effect ).forEach( ( path ) => { @@ -74,7 +74,7 @@ export default () => { } ); } ); - // data-wp-init.[name] + // data-wp-init--[name] directive( 'init', ( { directives: { init }, context, evaluate } ) => { const contextValue = useContext( context ); Object.values( init ).forEach( ( path ) => { @@ -84,7 +84,7 @@ export default () => { } ); } ); - // data-wp-on.[event] + // data-wp-on--[event] directive( 'on', ( { directives: { on }, element, evaluate, context } ) => { const contextValue = useContext( context ); Object.entries( on ).forEach( ( [ name, path ] ) => { @@ -94,7 +94,7 @@ export default () => { } ); } ); - // data-wp-class.[classname] + // data-wp-class--[classname] directive( 'class', ( { @@ -139,7 +139,7 @@ export default () => { } ); - // data-wp-bind.[attribute] + // data-wp-bind--[attribute] directive( 'bind', ( { directives: { bind }, element, context, evaluate } ) => { @@ -175,6 +175,24 @@ export default () => { } ); + // data-wp-text + directive( + 'text', + ( { + directives: { + text: { default: text }, + }, + element, + evaluate, + context, + } ) => { + const contextValue = useContext( context ); + element.props.children = evaluate( text, { + context: contextValue, + } ); + } + ); + // data-wp-ignore directive( 'ignore', diff --git a/packages/interactivity/src/hydration.js b/packages/interactivity/src/hydration.js index 2fc34eeb64b9b5..e5a8e5128a1d14 100644 --- a/packages/interactivity/src/hydration.js +++ b/packages/interactivity/src/hydration.js @@ -11,7 +11,7 @@ import { directivePrefix } from './constants'; export const init = async () => { document - .querySelectorAll( `[${ directivePrefix }island]` ) + .querySelectorAll( `[data-${ directivePrefix }-interactive]` ) .forEach( ( node ) => { if ( ! hydratedIslands.has( node ) ) { const fragment = createRootFragment( node.parentNode, node ); diff --git a/packages/interactivity/src/vdom.js b/packages/interactivity/src/vdom.js index 07640319b88a8a..fe09f492dbd566 100644 --- a/packages/interactivity/src/vdom.js +++ b/packages/interactivity/src/vdom.js @@ -7,9 +7,23 @@ import { h } from 'preact'; */ import { directivePrefix as p } from './constants'; -const ignoreAttr = `${ p }ignore`; -const islandAttr = `${ p }island`; -const directiveParser = new RegExp( `${ p }([^.]+)\.?(.*)$` ); +const ignoreAttr = `data-${ p }-ignore`; +const islandAttr = `data-${ p }-interactive`; +const fullPrefix = `data-${ p }-`; + +// Regular expression for directive parsing. +const directiveParser = new RegExp( + `^data-${ p }-` + // ${p} must be a prefix string, like '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]+)*)' + + // (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][a-z0-9-]+))?$', + 'i' // Case insensitive. +); export const hydratedIslands = new WeakSet(); @@ -44,7 +58,10 @@ export function toVdom( root ) { for ( let i = 0; i < attributes.length; i++ ) { const n = attributes[ i ].name; - if ( n[ p.length ] && n.slice( 0, p.length ) === p ) { + if ( + n[ fullPrefix.length ] && + n.slice( 0, fullPrefix.length ) === fullPrefix + ) { if ( n === ignoreAttr ) { ignore = true; } else if ( n === islandAttr ) {