Coder Social home page Coder Social logo

sketch-hq / sketchapi Goto Github PK

View Code? Open in Web Editor NEW
842.0 842.0 126.0 9.79 MB

The JavaScript plugin library embedded in Sketch

Home Page: https://developer.sketch.com/reference/api

License: MIT License

JavaScript 97.19% Shell 0.04% Python 2.61% Objective-C 0.03% Swift 0.13%
sketch sketch-plugin

sketchapi's Introduction

Sketch JavaScript API

JavaScript API for Sketch for writing scripts and creating plugins.

Sketch JavaScript API Architecture

Usage

For guides, concepts and regular updates on what's new in the latest version of Sketch, see the Plugin Developer Documentation.

Example

Try the following script within the PluginsRun Script… panel.

// The Sketch JavaScript API is bundled with the Sketch Mac app
// and must be imported before it can be used.
const sketch = require('sketch')
const { Group, Shape, Rectangle } = sketch

// Get the current Document and Page
const doc = sketch.getSelectedDocument()
const page = doc.selectedPage

// Create and select a new Group within the current Page
var group = new Group({
  parent: page,
  frame: new Rectangle(0, 0, 100, 100),
  name: 'Test',
  selected: true,
})

// Add a new Rectangle Shape Layer to newly created Group
var rect = new Shape({
  parent: group,
  frame: new Rectangle(10, 10, 80, 80),
})

// Get and log the current selection
var sel = doc.selectedLayers
console.log(sel.isEmpty)

sel.forEach(function (elem) {
  console.log(elem.name)
})

Development

Prerequisits

Overview

The Sketch API is written in JavaScript/CocoaScript and gets bundled as part of the build process using webpack.

In addition to the API, this project also defines core modules to be included in Sketch as part of the official release process. Both are written to the build output folder when the build script is run:

./build.sh

Scripts

The following npm scripts are available for development of the API.

Script Description
npm run build Build SketchAPI into the build folder
npm run test:build Build integration test plugin
npm run lint Lint the source code
npm run format-check Check the format with Prettier
npm run api-location:write Tell Sketch to use your local SketchAPI
npm run api-location:delete Undo npm run api-location:write

Build and run

Follow the steps below to use a local copy of the API with your installation of Sketch.

Note, any plugins you have installed or code you invoke in Sketch's PluginsRun Script… sheet will use your local copy of the API.

  1. Checkout this repository.
  2. Configure Sketch to use your local version of SketchAPI instead of the built-in.
    npm run api-location:write
  3. Ensure you've installed the dependencies with npm, and then build SketchAPI.
    npm install
    npm run build
  4. Start Sketch and your changes will be picked up.

⚠️ Sketch must be restarted for API changes to take effect after running npm run build.

⚠️ You must remove the custom location configuration to make your installation of Sketch use the version of the API included with the app.

npm run api-location:delete

Testing

The SketchAPI builds on top of macOS and internal Sketch APIs via CocoaScript. To ensure the API works for a specific Sketch version or build, this repository includes *.test.js files containing integration tests.

These integration tests are compiled into a single test plugin using Webpack and can run by the run_tests.py Python script, or from the Sketch application menu.

Build test plugin

To build the plugin separately, e.g. to install and run it manually, run the following command.

npm install # if you haven't installed dependencies already
npm run test:build --identifier=IDENTIFIER

To build the plugin including only one spec file, e.g. run tests from one spec only, run this command:

npm run test:build --identifier=IDENTIFIER

Use different IDENTIFIER values if you are testing different versions of Sketch or want to run integration tests concurrently on the same machine.

Note: The Sketch JavaScript API does not need to be rebuilt. The integration tests use the API bundled within Sketch or the custom API location specified in the user defaults.

Run test plugin

To run the integration test plugin from the command-line, you must provide the path to the plugin and a file path to be used by the plugin to write the test results and can be watched by the Python script for changes.

python run_tests.py -p /path/to/SketchIntegrationTests-$UUID.sketchplugin -o FILE_PATH [-s SKETCH_PATH] [-t TIMEOUT]

Optionally, specify the Sketch installation to be used for the tests. If none is provided the default installation path /Applications/Sketch.app is going to be used.

Note: Tests can be run concurrently but only for different Sketch installations. Only one test run per Sketch installation location is supported because the Sketch process is terminated at the end of the test run based on its path on disk.

Tests can also be run manually from within Sketch:

  1. Doubleclick to install the SketchIntegrationTests-$UUID.sketchplugin.
  2. Open Sketch version to test.
  3. Select Test Sketch API from the application menu in PluginsSketch Integration Tests ($UUID)

The test results are written to the specified output file or, if no dedicated path is provided, to a temporary file. Use macOS' Console.app to view Sketch's logs containing information on the file location and test progress in general.

Acknowledgements

We would like to thank:

sketchapi's People

Contributors

acf avatar alexrepty avatar almeidarruben avatar bomberstudios avatar christianklotz avatar dependabot[bot] avatar elfenlaid avatar freddiewrites avatar invisiblepixels avatar jedrichards avatar kevingutowski avatar kgn avatar klaaspieter avatar lrossi avatar lucastobrazil avatar mathieudutour avatar mikeabdullah avatar mkeiser avatar opsgavin avatar pieteromvlee avatar randomsequence avatar robintindale avatar royalrex avatar samdeane avatar sheffieldkevin avatar sketch-joseluis avatar sreilly avatar thierryc avatar wcbyrne avatar whakkee avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sketchapi's Issues

Can't iterate over selected layers with selectedLayers

I follow the guide on this page, however the code below doesn't work

var sketch = context.api()
var document = sketch.selectedDocument
var selection = document.selectedLayers
selection.iterate( function (item) { log( item.name() ) } )

It would throw this error:

TypeError: undefined is not an object (evaluating 'this._object._application.wrapObject')
line: 1627
sourceURL: /Applications/Sketch.app/Contents/Resources/SketchAPI.js
column: 54

But this works as expected:

var selection = context.selection

for (var i = 0; i < selection.length; i++) {
  var _selection = selection[i]
  log(_selection.name())
}

And here is my env:

log(sketch.api_version) // 1.1
log(sketch.version) // 40.2
log(sketch.build) // 33826

lock the layer

Can you implement a method to lock the layer? It will be useful.

Group Class doesn't implement isGroup

@samdeane Guessing you may already have this well underway in a branch somewhere, but just hit this working with the JS API and wanted to documented it.

Issue:
Checking for object.isGroup on a known Group always returns false.

Expected:
Checking for object.isGroup on a known Group should return true.

Poked at the source and saw that in the Group class it's is_group and not isGroup https://github.com/BohemianCoding/SketchAPI/blob/master/Source/Group.js#L17

Wondering if that can be updated to isGroup to override the default https://github.com/BohemianCoding/SketchAPI/blob/master/Source/Layer.js#L43

alert() - wrong arguments order

In Application.js, line: 276 is:
app.displayDialog_withTitle(message, title)
but it should be:
app.displayDialog_withTitle(title, message)
Reference page is ok.

ReferenceError: Can't find variable: Rectangle

Rectangle is not exposed to the global space so parent.newGroup({"frame": new Rectangle(0, 44, 100, 44)}); fails.

Is it safe to add this to the top of Rectangle.js?

function _Rectangle(x, y, width, height) {
  return new Rectangle(x, y, width, height);
}

__globals.Rectangle = _Rectangle;

This fixes the issue, but I'm not sure if there should be a global object named Rectangle, what do you guys think?

Proposal: Move UI functions to a UserInterface class

In my opinion it's strange to have the UI input functions hang off the Application class. Do you guys think it makes more sense to have them be part of a UserInterface class?

Something like this instead?

var sketch = context.api()
sketch.ui.input("Test", "default");
sketch.ui.select("Test", ["One", "Two"], 1);
sketch.ui.message("Hello mum!");
sketch.ui.alert("Title", "message");

select is the one that really stands out to me, because "select" has a very understood meaning in Sketch, to select an object. In the develop branch this function is getSelectionFromUser which if you just read sketch. getSelectionFromUser is very confusing, my first thought is this is a function to get the user's current layer selection.

layerNamed(obj) resolves to only base layer type.

I'm not sure what the end plan here is but given that the "types" that inherit from Layer.js one would assume that when executing the layerNamed(string) resolves to the API centric type.

for example

context.api().selectedDocument.layerNamed("Page 1").isPage yields true.
context.api().selectedDocument.layerNamed("Artboard 1").isArtboard yields true.

Deprecated npm packages

npm WARN deprecated [email protected]: Babel's CLI commands have been moved from the babel package to the babel-cli package
npm WARN deprecated [email protected]: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated [email protected]: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated [email protected]: graceful-fs v3.0.0 and before will fail on node releases >= v7.0. Please update to graceful-fs@^4.0.0 as soon as possible. Use 'npm ls graceful-fs' to find it in the tree.

Feature Request: webview window

Any plans to add a method for creating webview modal, something like:
Application.openWebview(URL, size, callback)

If anyone has created something like that, would love to hear about it.

methods missed in Settings API

image
It looks like not every method imported from Settings API.

another question, how do I set SketchAPILocation back to default?
image

Thx!

example script didn't work?

var sketch = context.api()

log(sketch.api_version)
log(sketch.version)
log(sketch.build)
log(sketch.full_version)

var document = sketch.frontDocument;
var selection = document.selection;
var page = document.selectedPage;

var group = page.newGroup({frame:sketch.rectangle(0, 0, 100, 100), name:"Test"});
var rect = group.newShape({frame:sketch.rectangle(10, 10, 80, 80)});

log(selection.is_empty());
selection.iterate(function(item) { log(item.name); } );

selection.clear();
log(selection.is_empty());

group.select();
rect.add_to_selection();

sketch.input("Test", "default");
sketch.select("Test", ["One", "Two"], 1);
sketch.message("Hello mum!");
sketch.alert("Title", "message");

we got this error

1.1
40
33762
40 (33762)
TypeError: undefined is not an object (evaluating 'document.selection')
line: 15
sourceURL: /Users/tcmac/.atom/packages/sketchapp-scripter/scripting/run.sketchplugin
column: 25
stack: onRun@/Users/tcmac/.atom/packages/sketchapp-scripter/scripting/run.sketchplugin:15:25

and the page.addGroup seems didn't work too

color.hexValue() Function No longer works

The hexValue function throws an error when used in a plugin. "TypeError: hexValue is not a function."

This worked in previous versions of Sketch. Is there a new version of this function I can use? I searched through the documentation with no luck.

newPage and selectedArtboard missing.

At the time of writing I can't seem to locate any hints of the signature newPage() within the context of a Document.

I'm hopeful that selectedDocument.newPage() is a likely outcome here. Currently I've had to revert to older methods to achieve this (context.document.addBlankPage()) then either find it by name or set it to being selected. So far i've been able to route back into the API layer but its quite cumbersome to retain this parity.

Also in the same line of thinking, given there is selectedPage, selectedDocument why is selectedArtboard not appearing (is that in the backlog or something?).

Add the thinkness of border with new API

I'm modifing my plugin, flowmate, to fix errors and update new APIs. It's really hard to understand the new and old APIs because there is not useful example. Your example is just for few cases and most of plugin still use old API (Please add some example to API documents)

And I have one questions. Do you have a plan to change thinkness of shape using new API? I saw the "Style.js" source and the implement is not hard I guess. That's why I don't understand you don't implement thickness (and gradient)

P.S : Is this way to I modify the core script like Style.js and test directly on Sketch app?

Why isn't this more known?

What am I missing here. Just happened to drop in here and it looks awesome. Is it me or is this gem a little hidden currently?

No wrappers for MSSymbolInstance and MSSymbolMaster

I'm currently having to hack around the lack of wrappers for these two Sketch objects in my plugin (see nefaurk/select-parent-artboards#6), and I'd prefer not to have to.

Ideally, I could write code such as:

var artboardForItem = function(document, item) {
  if (item.isArtboard) {
    return item;
  } else if (item.container != null) {
    return artboardForItem(document, item.container);
  } else {
    return null;
  }
};

But instead, I'm having to write code such as:

var artboardForItem = function(document, item) {
  if (item.isArtboard) {
    return item;
  } else if (item.sketchObject != null && item.sketchObject.className() == "MSSymbolInstance") {
    var parent = item.sketchObject.parentGroup();
    var container = document.wrapObject(parent);
    return artboardForItem(document, container);
  } else if (item.container != null) {
    return artboardForItem(document, item.container);
  } else {
    return null;
  }
};

For more info, see: http://sketchplugins.com/d/209-no-mapped-wrapper-for-mssymbolinstance

context.document is `undefined` for some actions so it breaks the API

In the manifest commands:

 "script": "myscript.js",
"handlers": {
  "actions": {
    "SelectionChanged.finish": "onSelectionChanged"
  }
}

in myscript.js

var onSelectionChanged = function(context) {
  var sketch = context.api()

  log(sketch.api_version)
  log(sketch.version)
  log(sketch.build)
  log(sketch.full_version)

  var document = sketch.selectedDocument;
  log(document.selectedLayers);
}

When changing selection:

TypeError: null is not an object (evaluating 'this._object.currentPage')
line: 810
sourceURL: /Applications/Sketch.app/Contents/Resources/SketchAPI.js
column: 41

Looks like the code in question is:

{
  key: 'selectedPage',
  get: function get() {
    return new _Page.Page(this._object.currentPage(), this);
  }
}

Will we get events as well?

To be able to listen to in plugins. Stuff like "on new layer created", "on symbol renamed", etc. ? Or is that too much regarding performance (which is hanging by a thread as it is ;) ).

Should Selection inherit from WrapperObject?

I ask because Selection wraps a collection of objects, it's strange that it has a .sketchObject and that it returns a MSPage.

I wonder if there should be an Object that is the top level class that contains the tests. WrapperObject and Selection could both inherit from this class.

create Shape with style not work

wx20180303-142800 2x

I can log the style property from selected layer which works as intended according to the source code, but the color just not rendered on the layer

Uploading entire document

I am trying to upload the current sketch file to a URL.

I have looked through all the example code and don't see anything that would get me close to it.

Is there an API I'm not seeing to export the document to ZIP format?

Thanks,

-bash: gulp: command not found

After following the steps in the readme, npm install works fine, but then running gulp gulp is not installed. Does gulp need to be installed globally and should that be mentioned in the readme?

How to find a symbol master by name?

I'm trying to write a plugin that will set overrides in symbol instances in specific layer groups based on data from a JSON file.

The first problem is that overrides in a symbol instance don't have any name or label, it looks like I can only reference them by index in overrides array. I figured out that maybe I could get these names from the symbol master. However, I can't figure out how to get an existing symbol master. The API only mentions how to create one, not how to find one.

Is there a reason that the create functions are on Group instead of Layer?

I'm getting up to speed with scripting for Sketch at the same time as going through everything in this project so the way it's structured may make the most sense and I'm probably missing something :)

But I can't help but ask, should the newShape, newText, newGroup, and newImage functions be on the Layer class instead of the Group class? Maybe this is just me thinking about it as a Sketch user, but it seems strange to me to have these factory methods on a group, to me a layer makes more sense because they are all layers.

can Artboard create flow prototype?

I can create an artboard by new Artboard({ flow: { target: anothorArtboard } }) and there will be a link between two artboards, but when I click preview it does not work.
And I find that I can not create link in sketch(from an artboard).
Did I miss something or the flow property should be removed from document(in Artboard)?

Access to resizing information

I've been browsing the API docs and I can't find any properties that correlate to resizing masks on layers. Does this functionality exist? I'm hoping to developer a plugin that would export Sketch layers into a prototyping tool but would preserve the resizing behavior.

Export method not working on Page object ([__NSSingleObjectArrayI name]: unrecognized selector)

Summary

I'm trying to export a Page with the new API (Sketch 49). It works well when giving an artboard to the export method. But when giving a Page object it crash (the script, not the app).

http://developer.sketchapp.com/reference/api/#export

Steps to Reproduce:

Create a plugin to test with this script :

var sketch = require('sketch/dom');

export default function(context) {
    
    var document = sketch.Document.getSelectedDocument();

    //I know I have 2 Pages on my test document in Sketch
    log(document.pages);

    for (var i = 0; i < document.pages.length; i++) {
        var page = document.pages[i];
        
        log(page);
        log(page.name);

        sketch.export(page, {
            overwriting: true,
            output: "~/Desktop/test_output"
        });
    }
}

// Logs
// 
// // Pages
// (
//     "<null>",
//     "<null>"
// )

// // Page [0]
// (null) // page
// screen_1 // page.name

// // sketch.export error
// -[__NSSingleObjectArrayI name]: unrecognized selector sent to instance 0x60800001a150

Expected Results

An image should be created representing the full page

Actual Results:

An error :

-[__NSSingleObjectArrayI name]: unrecognized selector sent to instance 0x60800001a150

Notes

It's weird, because when logging a page, null is printed, but page.name, print the name.

Installation Issue

Hi, I don't know where else to turn. I did exactly as the Sketch page instructed, to start working on a tutorial for a plugin, but I all end up with in the terminal is this:

iMac:~ xxx$ sudo skpm create my-plugin
module.js:540
    throw err;
    ^

Error: Cannot find module '../build/Release/keytar.node'
    at Function.Module._resolveFilename (module.js:538:15)
    at Function.Module._load (module.js:468:25)
    at Module.require (module.js:587:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/usr/local/lib/node_modules/skpm/node_modules/keytar/lib/keytar.js:1:76)
    at Module._compile (module.js:643:30)
    at Object.Module._extensions..js (module.js:654:10)
    at Module.load (module.js:556:32)
    at tryModuleLoad (module.js:499:12)
    at Function.Module._load (module.js:491:3)

The skpm package says it is version 1.0.13; the Node installation and npm installation were all fine. It turned out that despite my command line tools being installed, the keytar node had never been built and compiled into the right place. (And got it to work by sheer accident, by finding a keytar version that actually compiled through a homebrew node install, which I copied over).
Can you verify that the current tutorial actually works on High Sierra Vanilla installations? It could still be that things were wrong with my installation somehow and it got fixed by fiddling, but it took me three hours to get this going, and I would not be surprised if many potential developers jump ship without telling you there is an issue if this is the case.

How to build and run?

Hey Guys, wondering about documentation about how to build and run this so that when we work on changes and want to submit pull requests we can test the changes in the Sketch app?

Changing text spacing properties

I'm trying to change the line spacing on some API generated text. There doesn't seem to be a way to do it with current JS API, but is there a way to add it using the old API?

var text = group.newText({alignment: NSTextAlignmentCenter, text:copy, fixedWidth: true, font: NSFont.fontWithName_size_("Gotham HTF Book", 68.5)})

After looking at the code for the Sketch Set Line Height plugin, I tried using text.lineHeight() and text.setLineHeight() to no success. They come back saying those functions do not exist.

Any ideas? If there's a way to do it we can see about adding it to the JS API

Artboard object has no export method

Hello! So on, I have been working on my plugin for a while, and I have experienced the issue with exporting artboards.

I have an array of duplicated artboards:

var tmpArtboards = [];
rootLayers.forEach(function(rootLayer) {
    var tmp = rootLayer.duplicate();
    // ...
    tmpArtboards.push(tmp);
});

I try to set the export options for the artboards:

var options = {'scales': '1', 'formats': 'png'};
tmpArtboards.forEach(function(artboard) {
    artboard.export(options);
});

I get this:

TypeError: artboard.export is not a function. (In 'artboard.export(options)', 'artboard.export' is undefined)

As I know, Artboard inherits Layer and I should be able to use export method, but it seems that these objects are not belong to Layer.

Create a Font object, like how there is a Rectangle object

Like Rectangle I think it might make sense to have a javascript object for Font. Right now text.font has to be set to a NSFont object, exposing the underlying obj-c objects. Also the systemFontSize defined as set is a bit strange because then it's usage is text.systemFontSize = 40, but this will do more than just set the font size, it will override the font family to the system font, which kinda makes sense from the property name, but I think is still strange ;)

adjustToFit method not work for Artboard

It looks like the methods inherits from Group, but it just not works.
I find it works by following script

document.sketchObject.actionsController().actionForID("MSResizeArtboardToFitAction").resizeArtboardToFit(nil)

but should ensure the artboard layer is selected..

Did I miss something or is this a bug? Thanks!

Shared layer/text styles support

Is there any way to access/manipulate layer and text styles? Is it just missing in the documentation, or it's something that'll be provided in the future?

Can I use the new API in old sketch version?

It seems that the new API is absolutely different from the old one, can I just get the new API in old sketch version like release 48.2?
If not, does it mean that we have to rewrite our plugin and keep both two versions of plugin to adapt new release 49 and the older ones?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.