We previously made a panel with a Web page inside. We’ll now work on adding logic to it by making this WebView communicate with Sketch and vice versa. To illustrate passing information from the WebView to Sketch, we’ll trigger Sketch tools when clicking on buttons in the Web page. To illustrate the other way around, we’ll show the selected layer’s CSS style in the Web page.
To trigger an action in Sketch (e.g. open the Rectangle tool) by clicking on a button in the Web page, we need to receive click events in the Web page and then send this information to the Sketch plugin. The only way to do that is quite confusing: we need to use the local Web page’s URL hash. Changing the hash won’t reload the page but we’ll still be able to receive an event for that change thanks to a delegate. Before starting, to make it easier for us to work with delegates, we’re going to use MochaJSDelegate.
But because we only listen to URL changes, doing the same action multiples times in a row won’t trigger the event. To fix that, we’ll use an object (JSON) that contains the action we want to pass to Sketch, and the current UNIX date to make it unique in every case. To make it easier to add multiple actions with the same event, we’ll store actions (MSRectangleShapeAction, MSOvalShapeAction, MSTriangleShapeAction…) in “data-action” HTML attributes on each button in the Web page.
After getting the hash in the delegate, we can just parse it to get back our object that we can work with. We can now use Sketch’s actionsController() to trigger the specific action asked by which button was clicked in the Web page.
Everything works as expected, but just to make it a bit prettier, we’ll use the Sketch tools icons instead of default buttons.
We’ll now show a CSS preview of the selected layer on a simple div. We’ll use the same delegate as before but with a new event this time: webView:didFinishLoadForFrame:. By listening to when the Web page is done loading, we can set the preview before the interface even shows up.
We’ll first create a very basic function in our Web page that accepts a string of CSS attributes and apply those to a specific div.
In the plugin, we’ll use the windowScriptObject property again to execute that function, passing either a string of CSS attributes from the selection or an empty string if we can’t get any CSS attributes (e.g. multiple layers, images…), making the div look like our selection or invisible if we can’t show anything.
The preview looks nice but it only updates when we start the plugin. To fix that, we can use Actions: a Sketch API that allows us to execute code based on events in Sketch. There’s a lot of events available but we only need one of them for what we want to achieve: SelectionChanged.finish.
We’ll modify our plugin’s manifest.json with a new entry to tell Sketch that we want to listen to that event.
In our plugin, we can now add an onSelectionChanged function below onRun that will be executed every time the selection changes in Sketch. Because it’s a different function from onRun, we need to find a way to get access to the panel and its content again. We’ll just check for the reference we stored earlier with the same identifier, and if it exists we can access the panel again with it. If it doesn’t exist, that means that there is no panel opened so we shouldn’t do anything.
After accessing the panel, we can also access the WebView by using the subviews property. We can then essentially use the same code that we created for the webView:didFinishLoadForFrame: event earlier to update the preview every time we change our selection in Sketch.
We now have a floating panel that interacts with Sketch and updates when we select new layers, yay!
If something went wrong for you, here’s the code for the final result. This was just the tip of the iceberg, but I hope that this basic example was a good start to inspire you to create better and more advanced Sketch plugins.