Custom Selections in Sketch App
A brief introduction on scripting commands that computers love to do over and over again.
This post is an answer to a Sketch feature request by Information Architects that I’ve stumbled upon Twitter:
@sketchapp Hey, we all use your program here. We would love to have a “Select all below feature” similar to the one in Axure. Cheers! — via @iA
I want to explain how this is possible by writing a simple plugin, that you can also download on Github.
About writing Sketch plugins
It’s been almost a year since I’ve started using Sketch in my design process. In the meantime, I’ve developed dozens of plugins that help me and my colleagues in our daily work at Ginetta.
Fortunately, most plugins only require a few lines of JavaScript to select and manipulate layers.
Every time I find myself repeating something over and over again, it’s time to use the computer for what it’s good for: automating tedious tasks.
In this article, I briefly want show you how to select layers based on properties. Selections are the core of most plugins and they are actually quite simple to perform.
If you’ve never developed a Sketch plugin, but also feel the urge to improve the way you work with Sketch, I recommend that you read the Sketch Developer Documentation.
Selecting layers with NSPredicate
The most efficient way to make selections is by using NSPredicate. It allows you to write simple queries that can select layers by style, text value, position, size and every other possible property of a layer, artboard, or page.
For example, the following line of code could be used to select all layers with a y-position greater than the mouse position:
var predicate = NSPredicate.predicateWithFormat(“frame.y > %@”, mouseY);
You could also select all text layers that have specific text value. Imagine you found a typo in a headline that appears on multiple artboards. If only you could select all those layers at once…
var predicate = NSPredicate.predicateWithFormat(“stringValue == %@”, referenceString);
To turn those selections into working plugins, you need to define a scope that you want to search on. This can be the whole document, a page, an artboard, a layer group or multiples of them.
The following command would set the scope to all children of the current page (including artboards, layers, shapes, …):
var scope = doc.currentPage().children();
Often, I find it more useful to only select layers that are on the same hierarchical level as the selected layer:
var scope = selection[0].parentGroup().layers().array();
Example plugin
For demonstration purposes, here is a bare bone example that selects all layers below a selected layer. I also wrote a plugin that uses the mouse position as a reference.
Imagine that you just removed a section in the middle of your design and now you want to move all layers below the section up to fill the gap.
We need to define the scope of our selection. In this case, we limit the selection to layers on the same layer level as the group that our selection is in.
var scope = selection[0].parentGroup().layers().array();
Because we want to get all layers below the current layer, we need to calculate the y-position of the bottom edge of the selected layer. The frame of a layer holds all the relevant position and size properties.
var frame = selection[0].frame();
var bottom = frame.y() + frame.height();
Now we can set up our NSPredicate filter, that checks each layers’frame.y property and compares it to the previously calculatedbottom value.
var predicate = NSPredicate.predicateWithFormat(“frame.y > %@”, bottom);
Now we need to get an array of matched layers
var queryResult = scope.filteredArrayUsingPredicate(predicate);
Finally, we can tell our document to select all those layers
doc.currentPage().selectLayers(queryResult);
That’s it. Less than 10 lines of code that are only a shortcut away to make your life easier.