├── .appcast.xml
├── .gitignore
├── Copy-Paste-Position-Size
├── .gitignore
├── README.md
├── assets
│ └── icon.png
├── package-lock.json
├── package.json
├── sketch-assets
│ └── icons.sketch
└── src
│ ├── manifest.json
│ └── my-command.js
├── README.md
├── assets
└── icon.png
├── demo-copy-paste-position-size.gif
├── package-lock.json
├── package.json
├── sketch-assets
└── icons.sketch
└── src
├── copy-paste-position-size.js
└── manifest.json
/.appcast.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 | -
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # build artifacts
2 | sketch-copy-paste-position-size.sketchplugin
3 |
4 | # npm
5 | node_modules
6 | .npm
7 | npm-debug.log
8 |
9 | # mac
10 | .DS_Store
11 |
12 | # WebStorm
13 | .idea
14 |
15 | # sketch
16 | # sketch-assets
17 |
--------------------------------------------------------------------------------
/Copy-Paste-Position-Size/.gitignore:
--------------------------------------------------------------------------------
1 | # build artifacts
2 | copy-paste-position-size.sketchplugin
3 |
4 | # npm
5 | node_modules
6 | .npm
7 | npm-debug.log
8 |
9 | # mac
10 | .DS_Store
11 |
12 | # WebStorm
13 | .idea
14 |
15 | # sketch
16 | # sketch-assets
17 |
--------------------------------------------------------------------------------
/Copy-Paste-Position-Size/README.md:
--------------------------------------------------------------------------------
1 | # Copy-Paste-Position-Size
2 |
3 | ## Installation
4 |
5 | - [Download](../../releases/latest/download/copy-paste-position-size.sketchplugin.zip) the latest release of the plugin
6 | - Un-zip
7 | - Double-click on copy-paste-position-size.sketchplugin
8 |
9 | ## Development Guide
10 |
11 | _This plugin was created using `skpm`. For a detailed explanation on how things work, checkout the [skpm Readme](https://github.com/skpm/skpm/blob/master/README.md)._
12 |
13 | ### Usage
14 |
15 | Install the dependencies
16 |
17 | ```bash
18 | npm install
19 | ```
20 |
21 | Once the installation is done, you can run some commands inside the project folder:
22 |
23 | ```bash
24 | npm run build
25 | ```
26 |
27 | To watch for changes:
28 |
29 | ```bash
30 | npm run watch
31 | ```
32 |
33 | Additionally, if you wish to run the plugin every time it is built:
34 |
35 | ```bash
36 | npm run start
37 | ```
38 |
39 | ### Custom Configuration
40 |
41 | #### Babel
42 |
43 | To customize Babel, you have two options:
44 |
45 | - You may create a [`.babelrc`](https://babeljs.io/docs/usage/babelrc) file in your project's root directory. Any settings you define here will overwrite matching config-keys within skpm preset. For example, if you pass a "presets" object, it will replace & reset all Babel presets that skpm defaults to.
46 |
47 | - If you'd like to modify or add to the existing Babel config, you must use a `webpack.skpm.config.js` file. Visit the [Webpack](#webpack) section for more info.
48 |
49 | #### Webpack
50 |
51 | To customize webpack create `webpack.skpm.config.js` file which exports function that will change webpack's config.
52 |
53 | ```js
54 | /**
55 | * Function that mutates original webpack config.
56 | * Supports asynchronous changes when promise is returned.
57 | *
58 | * @param {object} config - original webpack config.
59 | * @param {boolean} isPluginCommand - whether the config is for a plugin command or a resource
60 | **/
61 | module.exports = function(config, isPluginCommand) {
62 | /** you can change config here **/
63 | }
64 | ```
65 |
66 | ### Debugging
67 |
68 | To view the output of your `console.log`, you have a few different options:
69 |
70 | - Use the [`sketch-dev-tools`](https://github.com/skpm/sketch-dev-tools)
71 | - Run `skpm log` in your Terminal, with the optional `-f` argument (`skpm log -f`) which causes `skpm log` to not stop when the end of logs is reached, but rather to wait for additional data to be appended to the input
72 |
73 | ### Publishing your plugin
74 |
75 | ```bash
76 | skpm publish
77 | ```
78 |
79 | (where `bump` can be `patch`, `minor` or `major`)
80 |
81 | `skpm publish` will create a new release on your GitHub repository and create an appcast file in order for Sketch users to be notified of the update.
82 |
83 | You will need to specify a `repository` in the `package.json`:
84 |
85 | ```diff
86 | ...
87 | + "repository" : {
88 | + "type": "git",
89 | + "url": "git+https://github.com/ORG/NAME.git"
90 | + }
91 | ...
92 | ```
93 |
--------------------------------------------------------------------------------
/Copy-Paste-Position-Size/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrejilderda/Sketch-Copy-Paste-Position-Size/47162efa13fe7fbccc81f5197f465fcac380833e/Copy-Paste-Position-Size/assets/icon.png
--------------------------------------------------------------------------------
/Copy-Paste-Position-Size/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "copy-paste-position-size",
3 | "description": "",
4 | "version": "0.1.0",
5 | "engines": {
6 | "sketch": ">=49.0"
7 | },
8 | "skpm": {
9 | "name": "Copy-Paste-Position-Size",
10 | "manifest": "src/manifest.json",
11 | "main": "copy-paste-position-size.sketchplugin",
12 | "assets": [
13 | "assets/**/*"
14 | ],
15 | "sketch-assets-file": "sketch-assets/icons.sketch"
16 | },
17 | "scripts": {
18 | "build": "skpm-build",
19 | "watch": "skpm-build --watch",
20 | "start": "skpm-build --watch --run",
21 | "postinstall": "npm run build && skpm-link"
22 | },
23 | "devDependencies": {
24 | "@skpm/builder": "^0.7.0"
25 | },
26 | "author": "Andre Jilderda "
27 | }
28 |
--------------------------------------------------------------------------------
/Copy-Paste-Position-Size/sketch-assets/icons.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrejilderda/Sketch-Copy-Paste-Position-Size/47162efa13fe7fbccc81f5197f465fcac380833e/Copy-Paste-Position-Size/sketch-assets/icons.sketch
--------------------------------------------------------------------------------
/Copy-Paste-Position-Size/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/sketch-hq/SketchAPI/develop/docs/sketch-plugin-manifest-schema.json",
3 | "icon": "icon.png",
4 | "commands": [
5 | {
6 | "name": "my-command",
7 | "identifier": "copy-paste-position-size.my-command-identifier",
8 | "script": "./my-command.js"
9 | }
10 | ],
11 | "menu": {
12 | "title": "Copy-Paste-Position-Size",
13 | "items": [
14 | "copy-paste-position-size.my-command-identifier"
15 | ]
16 | }
17 | }
--------------------------------------------------------------------------------
/Copy-Paste-Position-Size/src/my-command.js:
--------------------------------------------------------------------------------
1 | import sketch from 'sketch'
2 | // documentation: https://developer.sketchapp.com/reference/api/
3 |
4 | export default function() {
5 | sketch.UI.message("It's alive 🙌")
6 | }
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Sketch Copy Paste Position & Size
2 | A Sketch plugin that lets you easily copy & paste width, height, x & y values from and to objects!
3 |
4 | ## Demo
5 | 
6 |
7 | ## How to use
8 | Just run 'Copy' ctrl + shift + c to store an object's width, height, x & y axis for reuse. Select another layer and use one of the 'Paste' plugins. For example ctrl + shift + v) will paste the size to the selected object(s).
9 |
10 | Multiple layer support for copying (will store the selection bounds) as well as pasting. The following actions are available:
11 |
12 | ## Shortcuts
13 | | Action | Shortcut |
14 | | :------- | :---- |
15 | | Copy* | ctrl + shift + c |
16 | | Paste Size | ctrl + shift + v |
17 | | Paste Width | ctrl + shift + w |
18 | | Paste Height | ctrl + shift + h |
19 | | Paste X | ctrl + shift + x |
20 | | Paste Y | ctrl + shift + y |
21 | | Paste Position *(X & Y)* | ctrl + shift + p |
22 | | Paste Width Porportionally** | ctrl + shift + alt + w |
23 | | Paste Height Porportionally** | ctrl + shift + alt + h |
24 |
25 | \*The values are copied within Sketch and won't interfere with your OS' clipboard.
26 | \**Paste proportionally will respect the selected layer's aspect ratio.
27 |
28 | ## Installation
29 | 1. [Download](https://github.com/ajilderda/Sketch-Copy-Paste-Position-Size/releases/latest/download/sketch-copy-paste-position-size.sketchplugin.zip) the latest release.
30 | 2. Run ‘Copy Paste Position Size.sketchplugin’ to install
31 |
32 | ## Thanks to
33 | This plugin is inspired by John Dunning's [Copy Paste WHXY](http://johndunning.com/fireworks/about/CopyPasteWHXY), a Fireworks plugin I've used for a long time!
34 |
35 | ## Feedback
36 | If you find any issues or have any suggestions, please create an issue. Pull requests are welcome also!
37 |
38 | ## Created by
39 | [Andre Jilderda](https://github.com/ajilderda)
40 |
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrejilderda/Sketch-Copy-Paste-Position-Size/47162efa13fe7fbccc81f5197f465fcac380833e/assets/icon.png
--------------------------------------------------------------------------------
/demo-copy-paste-position-size.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrejilderda/Sketch-Copy-Paste-Position-Size/47162efa13fe7fbccc81f5197f465fcac380833e/demo-copy-paste-position-size.gif
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sketch-copy-paste-position-size",
3 | "description": "Easily copy and paste width, height, x & y values from and to objects",
4 | "version": "1.6.1",
5 | "engines": {
6 | "sketch": ">=49.0"
7 | },
8 | "skpm": {
9 | "name": "Sketch-Copy-Paste-Position-Size",
10 | "manifest": "src/manifest.json",
11 | "main": "sketch-copy-paste-position-size.sketchplugin",
12 | "assets": [
13 | "assets/**/*"
14 | ],
15 | "sketch-assets-file": "sketch-assets/icons.sketch"
16 | },
17 | "scripts": {
18 | "build": "skpm-build",
19 | "watch": "skpm-build --watch",
20 | "start": "skpm-build --watch --run",
21 | "postinstall": "npm run build && skpm-link"
22 | },
23 | "devDependencies": {
24 | "@skpm/builder": "^0.7.0"
25 | },
26 | "author": "Andre Jilderda ",
27 | "repository": {
28 | "type": "git",
29 | "url": "git+https://github.com/ajilderda/Sketch-Copy-Paste-Position-Size.git"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/sketch-assets/icons.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrejilderda/Sketch-Copy-Paste-Position-Size/47162efa13fe7fbccc81f5197f465fcac380833e/sketch-assets/icons.sketch
--------------------------------------------------------------------------------
/src/copy-paste-position-size.js:
--------------------------------------------------------------------------------
1 | const Group = require('sketch/dom').Group;
2 | const Text = require('sketch/dom').Text;
3 | const document = require('sketch/dom').getSelectedDocument();
4 | const Settings = require('sketch/settings');
5 | const UI = require('sketch/ui');
6 |
7 | const pixelFit = (input) => {
8 | return Settings.globalSettingForKey("tryToFitToPixelBounds") ? Math.round(input) : input;
9 | }
10 |
11 | const getRelativeCoordinates = layer => layer.frame.changeBasis({
12 | from: layer.parent,
13 | to: layer.getParentArtboard()
14 | });
15 |
16 | export function onCopy() {
17 | const selection = document.selectedLayers;
18 | if (!selection.length) return UI.message('Please select at least one layer to copy from.');
19 |
20 | if (selection.length === 1) {
21 | const layer = selection.layers[0];
22 | const frame = getRelativeCoordinates(layer);
23 |
24 | const copiedWidth = pixelFit(frame.width);
25 | const copiedHeight = pixelFit(frame.height);
26 | const copiedX = pixelFit(frame.x);
27 | const copiedY = pixelFit(frame.y);
28 |
29 | Settings.setSettingForKey("copiedWidth", copiedWidth);
30 | Settings.setSettingForKey("copiedHeight", copiedHeight);
31 | Settings.setSettingForKey("copiedX", copiedX);
32 | Settings.setSettingForKey("copiedY", copiedY);
33 |
34 | UI.message(`📋 Width: ${pixelFit(copiedWidth)} Height: ${pixelFit(copiedHeight)} X: ${pixelFit(copiedX)} Y: ${pixelFit(copiedY)}`);
35 | } else {
36 | const { layers } = selection;
37 |
38 | const selectionBounds = layers.reduce((acc, layer) => {
39 | const coordinates = getRelativeCoordinates(layer);
40 | const selectionBoundR = coordinates.x + coordinates.width;
41 | const selectionBoundB = coordinates.y + coordinates.height;
42 |
43 | return {
44 | l: [...acc.l, coordinates.x],
45 | t: [...acc.t, coordinates.y],
46 | r: [...acc.r, selectionBoundR],
47 | b: [...acc.b, selectionBoundB],
48 | }
49 | }, { l: [], t: [], r: [], b: [] });
50 |
51 | const selectionBoundL = Math.min(...selectionBounds.l);
52 | const selectionBoundT = Math.min(...selectionBounds.t);
53 | const selectionBoundR = Math.max(...selectionBounds.r);
54 | const selectionBoundB = Math.max(...selectionBounds.b);
55 | const selectionWidth = pixelFit(selectionBoundR - selectionBoundL);
56 | const selectionHeight = pixelFit(selectionBoundB - selectionBoundT);
57 |
58 | Settings.setSettingForKey("copiedWidth", selectionWidth);
59 | Settings.setSettingForKey("copiedHeight", selectionHeight);
60 | Settings.setSettingForKey("copiedX", pixelFit(selectionBoundL));
61 | Settings.setSettingForKey("copiedY", pixelFit(selectionBoundT));
62 |
63 | UI.message(`📋 Width: ${pixelFit(selectionWidth)} Height: ${pixelFit(selectionHeight)} X: ${pixelFit(selectionBoundL)} Y: ${pixelFit(selectionBoundT)}`);
64 | }
65 | }
66 |
67 | export function pasteWHXY(w,h,x,y,proportional) {
68 | const { selectedLayers } = document;
69 |
70 | selectedLayers.forEach( layer => {
71 | const { frame } = layer;
72 |
73 | const newWidth = pixelFit(Settings.settingForKey('copiedWidth'));
74 | const newHeight = pixelFit(Settings.settingForKey('copiedHeight'));
75 | const newX = pixelFit(Settings.settingForKey('copiedX'));
76 | const newY = pixelFit(Settings.settingForKey('copiedY'));
77 |
78 | // we must run this function twice to get the layer frame updated properly.
79 | // once before and once after the layer was resized.
80 | if ( proportional || w || h ) fitTextFrame( layer );
81 |
82 | // Set width / height
83 | if( proportional ) {
84 | const oldWidth = frame.width;
85 | const oldHeight = frame.height;
86 |
87 | if (w) {
88 | const proportion = newWidth / oldWidth;
89 | frame.width = newWidth;
90 | frame.height = oldHeight * proportion;
91 | }
92 | if (h) {
93 | const proportion = newHeight / oldHeight;
94 | frame.height = newHeight;
95 | frame.width = oldWidth * proportion;
96 | }
97 | }
98 | else {
99 | if (w) frame.width = newWidth;
100 | if (h) frame.height = newHeight;
101 | }
102 |
103 | // run the fitTextFrame function again
104 | if ( proportional || w || h ) fitTextFrame( layer );
105 |
106 | // Set position
107 | if (x) frame.x = newX;
108 | if (y) frame.y = newY;
109 | })
110 | }
111 |
112 | // below 2 functions were partly borrowed from https://github.com/juliussohn/sketch-textbox-fit-content
113 | // attempt to fix the textbox height after resizing. There are however issues with (text)layers with the
114 | // 'Fix height' property set and there doesn't seem to be a way to set this value programmatically
115 | function fitTextFrame( layer ) {
116 | if ( layer instanceof MSTextLayer ) {
117 | // convert to wrapped API object, since some methods are only available in the Sketch API
118 | layer = Text.fromNative( layer );
119 | layer.fixedWidth = true;
120 |
121 | // adjust the layer frame height based on the text lines
122 | const lineCount = layer.fragments.length;
123 | const baseHeight = layer.fragments[lineCount - 1].rect.y + layer.fragments[lineCount - 1].rect.height;
124 | layer.frame.height = baseHeight;
125 | }
126 | else if ( layer instanceof MSLayerGroup ) {
127 | // adjust group frame to fit children
128 | layer.resizeToFitChildrenWithOption(0)
129 |
130 | const group = Group.fromNative(layer);
131 | const groupLayers = group.layers;
132 | for (let layer of groupLayers) {
133 | fitTextFrame( layer.sketchObject );
134 | };
135 | group.adjustToFit();
136 | }
137 | }
138 |
139 | export function onPasteSize() {
140 | pasteWHXY(true, true, false, false, false); //WHXY & proportional
141 | }
142 |
143 | export function onPasteWidth() {
144 | pasteWHXY(true, false, false, false, false);
145 | }
146 |
147 | export function onPasteHeight() {
148 | pasteWHXY(false, true, false, false, false);
149 | }
150 |
151 | export function onPasteSizePorportionally() {
152 | pasteWHXY(true, true, false, false, true);
153 | }
154 |
155 | export function onPasteWidthPorportionally() {
156 | pasteWHXY(true, false, false, false, true);
157 | }
158 |
159 | export function onPasteHeightPorportionally() {
160 | pasteWHXY(false, true, false, false, true);
161 | }
162 |
163 | export function onPastePosition() {
164 | pasteWHXY(false, false, true, true, false);
165 | }
166 |
167 | export function onPasteX() {
168 | pasteWHXY(false, false, true, false, false);
169 | }
170 |
171 | export function onPasteY() {
172 | pasteWHXY(false, false, false, true, false);
173 | }
174 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/sketch-hq/SketchAPI/develop/docs/sketch-plugin-manifest-schema.json",
3 | "icon": "icon.png",
4 | "name" : "Copy Paste Position Size",
5 | "identifier" : "com.sketchapp.copypastepositionsize",
6 | "description" : "Easily copy and paste width, height, x & y values from and to objects",
7 | "authorEmail" : "mail@andrejilderda.nl",
8 | "author" : "Andre Jilderda",
9 | "commands": [
10 | {
11 | "name" : "Copy",
12 | "script" : "copy-paste-position-size.js",
13 | "handler" : "onCopy",
14 | "shortcut" : "ctrl shift c",
15 | "identifier" : "onCopy"
16 | },
17 | {
18 | "name" : "Paste Size",
19 | "script" : "copy-paste-position-size.js",
20 | "handler" : "onPasteSize",
21 | "shortcut" : "ctrl shift v",
22 | "identifier" : "onPasteSize"
23 | },
24 | {
25 | "name" : "Paste Width",
26 | "script" : "copy-paste-position-size.js",
27 | "handler" : "onPasteWidth",
28 | "shortcut" : "ctrl shift w",
29 | "identifier" : "onPasteWidth"
30 | },
31 | {
32 | "name" : "Paste Height",
33 | "script" : "copy-paste-position-size.js",
34 | "handler" : "onPasteHeight",
35 | "shortcut" : "ctrl shift h",
36 | "identifier" : "onPasteHeight"
37 | },
38 | {
39 | "name" : "Paste Width Porportionally",
40 | "script" : "copy-paste-position-size.js",
41 | "handler" : "onPasteWidthPorportionally",
42 | "shortcut" : "ctrl shift alt w",
43 | "identifier" : "onPasteWidthPorportionally"
44 | },
45 | {
46 | "name" : "Paste Height Porportionally",
47 | "script" : "copy-paste-position-size.js",
48 | "handler" : "onPasteHeightPorportionally",
49 | "shortcut" : "ctrl shift alt h",
50 | "identifier" : "onPasteHeightPorportionally"
51 | },
52 | {
53 | "name" : "Paste Position",
54 | "script" : "copy-paste-position-size.js",
55 | "handler" : "onPastePosition",
56 | "shortcut" : "ctrl shift p",
57 | "identifier" : "onPastePosition"
58 | },
59 | {
60 | "name" : "Paste X",
61 | "script" : "copy-paste-position-size.js",
62 | "handler" : "onPasteX",
63 | "shortcut" : "ctrl shift x",
64 | "identifier" : "onPasteX"
65 | },
66 | {
67 | "name" : "Paste Y",
68 | "script" : "copy-paste-position-size.js",
69 | "handler" : "onPasteY",
70 | "shortcut" : "ctrl shift y",
71 | "identifier" : "onPasteY"
72 | }
73 | ],
74 | "menu": {
75 | "title": "Copy Paste Position Size",
76 | "items": [
77 | "onCopy",
78 | "onPasteSize",
79 | "onPasteWidth",
80 | "onPasteHeight",
81 | "onPasteSizePorportionally",
82 | "onPasteWidthPorportionally",
83 | "onPasteHeightPorportionally",
84 | "onPastePosition",
85 | "onPasteX",
86 | "onPasteY"
87 | ]
88 | }
89 | }
--------------------------------------------------------------------------------