— Roadmap Card
Description
Right now it’s a bit complex the way people can test class names in a processor:
const test = node => node.props.className.split(" ").includes("my-class")
const test = node => /my-class/.test(node.props.className)
User Stories
As a package developer
I want to add processors based on class names
so that the processor tests are easy to use and understand
Possible solution
@orballo proposed these two solutions:
1. Add hasClass()
to node
const test = node => node.hasClass("my-class");
2. Switch className
to an array
const test = node => node.className.inclues("my-class");
I’m more in favor of the first one because it’s backward compatible.
I totally agree.
I think we could redefine this feature to something more general, like adding helpers for processors tests. Another case that I found in some occasions is when you need to get an array of nodes after searching through the tree, which usually requires to implement a recursive function. Maybe something like the following could be helpful:
node.find(node => node.component === "img")
Could you add an example of what you are doing right now?
Here is an example of a gallery from where I’d like to get an array of images to map them to an array of urls later:
const process = node => {
const images = (function searchImages(node: Node) {
let result: Node[] = [];
if (node.type !== "element") return result;
if (node.component === "img") {
result.push(node);
} else if (node.children && node.children.length) {
node.children.forEach(child => {
result = result.concat(searchImages(child));
});
}
return result;
})(node);
node.props.media = images.map(image => image.props.src);
node.component = Gallery;
return node;
}
This could be something like:
const process = node => {
const images = node.find(node => node.type === "element"
&& node.component === "image");
node.props.media = images.map(image => image.props.src);
node.component = Gallery;
return node;
}
Ok, I see. What about allowing you to apply the same processor pattern?
const images = [];
node.process({
test: node.component === "image",
process: node => { images.push(node); }
})
Ok, I think that would be easier. Anyway, we need a different feature for this. Would you mind opening it @orballo
As suggested by @orballo in Styling the HTML content with the `css` prop we can also do something like this instead of node.hasClass
:
{
test: node => node.is(".wp-block-button"),
test: node => node.is("a.wp-block-button"),
test: node => node.is("#accept"),
test: node => node.is('input[type="submit"]'),
}
I think it’s a great idea because people are already used to this syntax and it’s faster and cleaner.
I wonder if there is a JavaScript library that can extract that selector query to tag
, class
, id
and so on…
It wasn’t hard to find: https://github.com/fb55/css-what and it’s only 4Kbs
I think we can integrate this with our processors. It’d be really cool to do things like:
// Select anchor that links to a dailymotion video
test: ({ node }) => node.is("a[href^='https://dailymotion.com/video']")
// Select images that belong to a Gutenberg block
test: ({ node }) => node.is("img < .wp-block-image")
// Select images that don't belong to a Gutenberg block
test: ({ node }) => node.is("img < :not(.wp-block-image)")
// Select a figure that has an image children with left alignment
test: ({ node }) => node.is("figure > image.align-left")
// Select a button block with background
test: ({ node }) => node.is(".wp-block-button.has-background")
I have created a little sandbox to play with this: https://codesandbox.io/s/css-what-quop3
You can check it out to see the type of object it returns for each case.