├── .gitignore ├── distro ├── coolHue.sketch ├── ps_coolHue.grd └── CoolHue.sketchplugin │ └── Contents │ ├── Resources │ ├── icon.png │ ├── core │ │ ├── images │ │ │ └── sprite.png │ │ └── assets │ │ │ ├── script.min.js │ │ │ ├── style.css │ │ │ └── script.js │ └── _webpack_resources │ │ ├── aa5bcfacdda6e5b5e7a75cf12bfe0448.html │ │ └── 3ff137287832113452bf2ab1649999f2.html │ └── Sketch │ ├── manifest.json │ ├── coolhue.js.map │ └── coolhue.js ├── images ├── coolhue-logo.png ├── coolhue-logo.svg └── coolhue-sprite.svg ├── package.json ├── bower.json ├── LICENSE ├── appcast.xml ├── scripts ├── coolhue.json └── script.js ├── index.html ├── README.md └── css └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/* 3 | *.zip 4 | -------------------------------------------------------------------------------- /distro/coolHue.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webkul/coolhue/HEAD/distro/coolHue.sketch -------------------------------------------------------------------------------- /distro/ps_coolHue.grd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webkul/coolhue/HEAD/distro/ps_coolHue.grd -------------------------------------------------------------------------------- /images/coolhue-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webkul/coolhue/HEAD/images/coolhue-logo.png -------------------------------------------------------------------------------- /distro/CoolHue.sketchplugin/Contents/Resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webkul/coolhue/HEAD/distro/CoolHue.sketchplugin/Contents/Resources/icon.png -------------------------------------------------------------------------------- /distro/CoolHue.sketchplugin/Contents/Resources/core/images/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webkul/coolhue/HEAD/distro/CoolHue.sketchplugin/Contents/Resources/core/images/sprite.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coolhue", 3 | "version": "2.0.0", 4 | "description": "Coolest handpicked Gradient Hues and Swatches", 5 | "scripts": { 6 | "coolhue": "browser-sync start --server --files \"*.html, css/*.css\"" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/webkul/coolhue.git" 11 | }, 12 | "author": "", 13 | "license": "ISC", 14 | "bugs": { 15 | "url": "https://github.com/webkul/coolhue/issues" 16 | }, 17 | "homepage": "https://github.com/webkul/coolhue#readme", 18 | "devDependencies": { 19 | "browser-sync": "^2.24.5" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coolhue", 3 | "version": "2.0.0", 4 | "homepage": "https://webkul.github.io/coolhue/", 5 | "authors": [ 6 | "Nitish Kumar " 7 | ], 8 | "description": "Coolest handpicked Gradient Hues for your next super ��� amazing stuff", 9 | "main": "scripts/script.js", 10 | "keywords": [ 11 | "coolhue", 12 | "swatch", 13 | "palette", 14 | "color swatch", 15 | "color palette", 16 | "gradient swatch", 17 | "gradient palette" 18 | ], 19 | "license": "MIT", 20 | "ignore": [ 21 | "**/.*", 22 | "node_modules", 23 | "bower_components", 24 | "test", 25 | "tests" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /distro/CoolHue.sketchplugin/Contents/Sketch/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "compatibleVersion": 3, 3 | "bundleVersion": 1, 4 | "icon": "icon.png", 5 | "commands": [ 6 | { 7 | "name": "Gradient Palette", 8 | "identifier": "coolhue-palette-trigger", 9 | "script": "coolhue.js", 10 | "description": "Show CoolHue Bar", 11 | "icon": "icon-transparent.png" 12 | } 13 | ], 14 | "menu": { 15 | "title": "CoolHue", 16 | "items": [ 17 | "coolhue-palette-trigger" 18 | ] 19 | }, 20 | "appcast": "https://raw.githubusercontent.com/webkul/coolhue/master/appcast.xml", 21 | "version": "2.0.7", 22 | "description": "Coolest handpicked Gradient Hues and Swatches", 23 | "name": "CoolHue", 24 | "identifier": "CoolHue", 25 | "disableCocoaScriptPreprocessor": true, 26 | "author": "Webkul, Nitish Khagwal", 27 | "authorEmail": "support@webkul.com" 28 | } -------------------------------------------------------------------------------- /distro/CoolHue.sketchplugin/Contents/Resources/_webpack_resources/aa5bcfacdda6e5b5e7a75cf12bfe0448.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | View 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 |
20 |
21 |
22 |

CoolHue v2.0.7

23 |
24 |
25 | 26 | 27 |
28 |
29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /distro/CoolHue.sketchplugin/Contents/Resources/_webpack_resources/3ff137287832113452bf2ab1649999f2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | View 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 |
20 |
21 |
22 |

CoolHue v2.0.7

23 |
24 |
25 | 26 | 27 |
28 |
29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Webkul 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /appcast.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CoolHue - Sketch Plugin 5 | https://raw.githubusercontent.com/webkul/coolhue/master/appcast.xml 6 | Coolest Gradient Hues and Swatches 7 | en 8 | 9 | Version 2.0.3 10 | 11 | 12 | 13 | Version 2.0.4 14 | 15 | 16 | 17 | Version 2.0.5 18 | 19 | 20 | 21 | Version 2.0.6 22 | 23 | 24 | 25 | Version 2.0.7 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /scripts/coolhue.json: -------------------------------------------------------------------------------- 1 | [ 2 | ["#FDEB71", "#F8D800"], 3 | ["#ABDCFF", "#0396FF"], 4 | ["#FEB692", "#EA5455"], 5 | ["#CE9FFC", "#7367F0"], 6 | ["#90F7EC", "#32CCBC"], 7 | ["#FFF6B7", "#F6416C"], 8 | ["#81FBB8", "#28C76F"], 9 | ["#E2B0FF", "#9F44D3"], 10 | ["#F97794", "#623AA2"], 11 | ["#FCCF31", "#F55555"], 12 | ["#F761A1", "#8C1BAB"], 13 | ["#43CBFF", "#9708CC"], 14 | ["#5EFCE8", "#736EFE"], 15 | ["#FAD7A1", "#E96D71"], 16 | ["#FFD26F", "#3677FF"], 17 | ["#A0FE65", "#FA016D"], 18 | ["#FFDB01", "#0E197D"], 19 | ["#FEC163", "#DE4313"], 20 | ["#92FFC0", "#002661"], 21 | ["#EEAD92", "#6018DC"], 22 | ["#F6CEEC", "#D939CD"], 23 | ["#52E5E7", "#130CB7"], 24 | ["#F1CA74", "#A64DB6"], 25 | ["#E8D07A", "#5312D6"], 26 | ["#EECE13", "#B210FF"], 27 | ["#79F1A4", "#0E5CAD"], 28 | ["#FDD819", "#E80505"], 29 | ["#FFF3B0", "#CA26FF"], 30 | ["#FFF5C3", "#9452A5"], 31 | ["#F05F57", "#360940"], 32 | ["#2AFADF", "#4C83FF"], 33 | ["#FFF886", "#F072B6"], 34 | ["#97ABFF", "#123597"], 35 | ["#F5CBFF", "#C346C2"], 36 | ["#FFF720", "#3CD500"], 37 | ["#FF6FD8", "#3813C2"], 38 | ["#EE9AE5", "#5961F9"], 39 | ["#FFD3A5", "#FD6585"], 40 | ["#C2FFD8", "#465EFB"], 41 | ["#FD6585", "#0D25B9"], 42 | ["#FD6E6A", "#FFC600"], 43 | ["#65FDF0", "#1D6FA3"], 44 | ["#6B73FF", "#000DFF"], 45 | ["#FF7AF5", "#513162"], 46 | ["#F0FF00", "#58CFFB"], 47 | ["#FFE985", "#FA742B"], 48 | ["#FFA6B7", "#1E2AD2"], 49 | ["#FFAA85", "#B3315F"], 50 | ["#72EDF2", "#5151E5"], 51 | ["#FF9D6C", "#BB4E75"], 52 | ["#F6D242", "#FF52E5"], 53 | ["#69FF97", "#00E4FF"], 54 | ["#3B2667", "#BC78EC"], 55 | ["#70F570", "#49C628"], 56 | ["#3C8CE7", "#00EAFF"], 57 | ["#FAB2FF", "#1904E5"], 58 | ["#81FFEF", "#F067B4"], 59 | ["#FFA8A8", "#FCFF00"], 60 | ["#FFCF71", "#2376DD"], 61 | ["#FF96F9", "#C32BAC"] 62 | ] -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CoolHue 2.0 - Coolest Gradient Hues and Swatches 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 | CoolHue 19 |
20 |
21 | Dev Mode 22 |
23 |
24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 | 32 | 33 |
34 | 36 |
37 | 38 | 39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 | 51 |
52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![coolHue](https://webkul.github.io/coolhue/images/coolhue-cover.png?1.0.1)](https://webkul.github.io/coolhue/) 2 | # coolHue 3 | Coolest handpicked Gradient Hues and Swatches for your next super ⚡ amazing stuff. coolHue has 60 coolest Gradients. You can also personalize the coolHue Palette as per as your taste. 4 | 5 | CoolHue gradients palette is **rendered by JSON** which makes it very easy to make a subtle update anytime. 6 | 7 | # Installation 8 | You can create your very own personalized collection of Gradient Palette with CoolHue - 9 | You should have [`bower`](https://bower.io/#install-bower) package manager installed on your machine to proceed further. 10 | 1. Open terminal and install CoolHue with `bower install coolhue`. 11 | 2. Go to `coolhue` directory with `cd bower_components/coolhue` command and run `npm install`. 12 | 3. Once, all the node modules are installed successfully, run `npm run coolhue`. 13 | 4. All the gradients which appears in the browser are rendered from `scripts/coolhue.json` file. 14 | 5. You just need to update the `coolhue.json` Object (array) to create your very own gradient palette. Open `scripts/coolhue.json` in the text editor and add or update the hex codes to generate the gradient palettes. 15 | 16 | [![coolHue JS Object](https://webkul.github.io/coolhue/images/coolhue-json.png)](https://github.com/webkul/coolhue/blob/master/scripts/coolhue.json) 17 | 18 | ## Including CoolHue in `npm` Workflow 19 | CoolHue is also available as a node module. You can read [How it works](https://www.npmjs.com/package/coolhue) with `npm` to get started. If you are already familiar; Installation command is mentioned just below - 20 | 21 | `npm install --save-dev coolhue` 22 | 23 | ## Sketch App Plugin 24 | 1. Download [`Coolhue.sketchplugin.zip`](https://github.com/webkul/coolhue/releases/download/v2.0.7/CoolHue.sketchplugin.zip) 25 | 2. Extract the archive 26 | 3. Install `Coolhue.sketchplugin` for Sketch App 27 | 4. Access it from Sketch's Menu Bar. Go to `Plugins` ➡️ `Coolhue` ➡️ `Palette` 28 | 29 | [![coolHue Sketch Plugin](https://webkul.com/blog/wp-content/uploads/2018/12/coolhue-sketch-plugin.png)](https://webkul.github.io/coolhue/sketch-plugin) 30 | 31 | ## Sketch App Gradient Palette 32 | You can download the [coolHue Gradient Palette for Sketch App](http://bit.ly/coolhue-sketch). 33 | 34 | ## Photoshop Gradient Palette 35 | You can download the [coolHue Gradient Palette for Photoshop](http://bit.ly/coolhue-ps). 36 | 37 | # Credits 38 | © Copyright [Webkul Software](https://webkul.com/), All rights reserved. 39 | -------------------------------------------------------------------------------- /distro/CoolHue.sketchplugin/Contents/Resources/core/assets/script.min.js: -------------------------------------------------------------------------------- 1 | let initHandler=()=>{window.document.addEventListener('contextmenu',event=>event.preventDefault());var getPaint=document.getElementById("paint");var clTheme=document.querySelector(".cl-theme");var clShuffle=document.querySelector(".cl-shuffle");var getBody=document.body;var gradientRand=()=>{return"#"+Math.random().toString(16).substr(2,6)} 2 | var data=[["#FDEB71","#F8D800"],["#ABDCFF","#0396FF"],["#FEB692","#EA5455"],["#CE9FFC","#7367F0"],["#90F7EC","#32CCBC"],["#FFF6B7","#F6416C"],["#81FBB8","#28C76F"],["#E2B0FF","#9F44D3"],["#F97794","#623AA2"],["#FCCF31","#F55555"],["#F761A1","#8C1BAB"],["#43CBFF","#9708CC"],["#5EFCE8","#736EFE"],["#FAD7A1","#E96D71"],["#FFD26F","#3677FF"],["#A0FE65","#FA016D"],["#FFDB01","#0E197D"],["#FEC163","#DE4313"],["#92FFC0","#002661"],["#EEAD92","#6018DC"],["#F6CEEC","#D939CD"],["#52E5E7","#130CB7"],["#F1CA74","#A64DB6"],["#E8D07A","#5312D6"],["#EECE13","#B210FF"],["#79F1A4","#0E5CAD"],["#FDD819","#E80505"],["#FFF3B0","#CA26FF"],["#FFF5C3","#9452A5"],["#F05F57","#360940"],["#2AFADF","#4C83FF"],["#FFF886","#F072B6"],["#97ABFF","#123597"],["#F5CBFF","#C346C2"],["#FFF720","#3CD500"],["#FF6FD8","#3813C2"],["#EE9AE5","#5961F9"],["#FFD3A5","#FD6585"],["#C2FFD8","#465EFB"],["#FD6585","#0D25B9"],["#FD6E6A","#FFC600"],["#65FDF0","#1D6FA3"],["#6B73FF","#000DFF"],["#FF7AF5","#513162"],["#F0FF00","#58CFFB"],["#FFE985","#FA742B"],["#FFA6B7","#1E2AD2"],["#FFAA85","#B3315F"],["#72EDF2","#5151E5"],["#FF9D6C","#BB4E75"],["#F6D242","#FF52E5"],["#69FF97","#00E4FF"],["#3B2667","#BC78EC"],["#70F570","#49C628"],["#3C8CE7","#00EAFF"],["#FAB2FF","#1904E5"],["#81FFEF","#F067B4"],["#FFA8A8","#FCFF00"],["#FFCF71","#2376DD"],["#FF96F9","#C32BAC"]];for(var i=0;i{if(getBody.classList.contains("dark")){getBody.classList.remove("dark");localStorage.setItem("theme","bright")}else{getBody.classList.add("dark");localStorage.setItem("theme","dark")}})} 5 | window.addEventListener("click",(ev)=>{if(ev.target.matches(".brick")){var tempObj=new Object();tempObj.firstColor=ev.target.dataset.firstColor;tempObj.secondColor=ev.target.dataset.secondColor;window.postMessage('nativeGradientApplier',tempObj)}});clShuffle.addEventListener("click",()=>{var tempObj=new Object();tempObj.firstColor=gradientRand();tempObj.secondColor=gradientRand();window.postMessage('nativeGradientApplier',tempObj)})} 6 | window.addEventListener("load",initHandler) -------------------------------------------------------------------------------- /distro/CoolHue.sketchplugin/Contents/Resources/core/assets/style.css: -------------------------------------------------------------------------------- 1 | ::-webkit-scrollbar { 2 | width: 4px; 3 | } 4 | 5 | body .wrapper::-webkit-scrollbar-track { 6 | background: #F2F2F2; 7 | } 8 | 9 | body .wrapper::-webkit-scrollbar-thumb { 10 | background: #D7DDE4; 11 | } 12 | 13 | body.dark .wrapper::-webkit-scrollbar-track { 14 | background: #2c293a; 15 | } 16 | 17 | body.dark .wrapper::-webkit-scrollbar-thumb { 18 | background: #444059; 19 | } 20 | 21 | * { 22 | box-sizing: border-box; 23 | -webkit-user-select: none; 24 | } 25 | 26 | html { 27 | height: 100%; 28 | } 29 | 30 | body { 31 | background: #FFFFFF; 32 | color: #282828; 33 | font-family: -apple-system, system-ui, sans-serif; 34 | margin: 0; 35 | height: 100%; 36 | } 37 | 38 | .wrapper { 39 | position: fixed; 40 | left: 0; 41 | right: 0; 42 | top: 0; 43 | bottom: 40px; 44 | padding: 4px; 45 | text-align: center; 46 | overflow: auto; 47 | } 48 | 49 | .controller { 50 | z-index: 5; 51 | border-top: solid 1px #D7DDE4; 52 | position: fixed; 53 | height: 40px; 54 | left: 0; 55 | right: 0; 56 | bottom: 0; 57 | } 58 | 59 | .brick { 60 | width: 32px; 61 | height: 32px; 62 | display: inline-block; 63 | margin: 4px; 64 | border-radius: 3px; 65 | box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.1), 0px 1px 5px 0px rgba(0, 0, 0, 0.05); 66 | } 67 | .brick:active{ 68 | opacity: .85; 69 | } 70 | 71 | .grd { 72 | display: block; 73 | padding: 10px; 74 | font-size: 0; 75 | } 76 | 77 | .grd-lt, 78 | .grd-rt { 79 | display: inline-block; 80 | vertical-align: middle; 81 | } 82 | 83 | .grd-lt { 84 | text-align: left; 85 | width: 70%; 86 | } 87 | 88 | .grd-rt { 89 | text-align: right; 90 | width: 30%; 91 | } 92 | 93 | .grd-lt h2.cl-title { 94 | margin: 0; 95 | padding: 0; 96 | font-size: 14px; 97 | color: #8e92a1; 98 | font-weight: normal; 99 | cursor: default; 100 | } 101 | 102 | .grd-rt .cl-theme { 103 | width: 18px; 104 | height: 18px; 105 | display: inline-block; 106 | vertical-align: middle; 107 | background-image: url("../images/sprite.png"); 108 | background-position: 0px 0px; 109 | } 110 | 111 | .grd-rt .cl-shuffle { 112 | width: 18px; 113 | height: 18px; 114 | display: inline-block; 115 | vertical-align: middle; 116 | background-image: url("../images/sprite.png"); 117 | background-position: -36px 0px; 118 | margin-right: 7px; 119 | } 120 | 121 | body.dark { 122 | background: #343141; 123 | } 124 | 125 | body.dark .controller { 126 | border-top-color: #444059; 127 | } 128 | 129 | body.dark .grd-lt h2.cl-title { 130 | color: #84818e; 131 | } 132 | 133 | body.dark .grd-rt .cl-theme { 134 | background-position: -18px 0px; 135 | } 136 | 137 | body.dark .grd-rt .cl-shuffle { 138 | background-position: -54px 0px; 139 | } -------------------------------------------------------------------------------- /distro/CoolHue.sketchplugin/Contents/Resources/core/assets/script.js: -------------------------------------------------------------------------------- 1 | //Initialization 2 | let initHandler = () => { 3 | window.document.addEventListener('contextmenu', event => event.preventDefault()); 4 | var getPaint = document.getElementById("paint"); 5 | var clTheme = document.querySelector(".cl-theme"); 6 | var clShuffle = document.querySelector(".cl-shuffle"); 7 | var getBody = document.body; 8 | 9 | var gradientRand = () => { 10 | return "#" + Math.random().toString(16).substr(2,6); 11 | } 12 | var data = [ 13 | ["#FDEB71", "#F8D800"], 14 | ["#ABDCFF", "#0396FF"], 15 | ["#FEB692", "#EA5455"], 16 | ["#CE9FFC", "#7367F0"], 17 | ["#90F7EC", "#32CCBC"], 18 | ["#FFF6B7", "#F6416C"], 19 | ["#81FBB8", "#28C76F"], 20 | ["#E2B0FF", "#9F44D3"], 21 | ["#F97794", "#623AA2"], 22 | ["#FCCF31", "#F55555"], 23 | ["#F761A1", "#8C1BAB"], 24 | ["#43CBFF", "#9708CC"], 25 | ["#5EFCE8", "#736EFE"], 26 | ["#FAD7A1", "#E96D71"], 27 | ["#FFD26F", "#3677FF"], 28 | ["#A0FE65", "#FA016D"], 29 | ["#FFDB01", "#0E197D"], 30 | ["#FEC163", "#DE4313"], 31 | ["#92FFC0", "#002661"], 32 | ["#EEAD92", "#6018DC"], 33 | ["#F6CEEC", "#D939CD"], 34 | ["#52E5E7", "#130CB7"], 35 | ["#F1CA74", "#A64DB6"], 36 | ["#E8D07A", "#5312D6"], 37 | ["#EECE13", "#B210FF"], 38 | ["#79F1A4", "#0E5CAD"], 39 | ["#FDD819", "#E80505"], 40 | ["#FFF3B0", "#CA26FF"], 41 | ["#FFF5C3", "#9452A5"], 42 | ["#F05F57", "#360940"], 43 | ["#2AFADF", "#4C83FF"], 44 | ["#FFF886", "#F072B6"], 45 | ["#97ABFF", "#123597"], 46 | ["#F5CBFF", "#C346C2"], 47 | ["#FFF720", "#3CD500"], 48 | ["#FF6FD8", "#3813C2"], 49 | ["#EE9AE5", "#5961F9"], 50 | ["#FFD3A5", "#FD6585"], 51 | ["#C2FFD8", "#465EFB"], 52 | ["#FD6585", "#0D25B9"], 53 | ["#FD6E6A", "#FFC600"], 54 | ["#65FDF0", "#1D6FA3"], 55 | ["#6B73FF", "#000DFF"], 56 | ["#FF7AF5", "#513162"], 57 | ["#F0FF00", "#58CFFB"], 58 | ["#FFE985", "#FA742B"], 59 | ["#FFA6B7", "#1E2AD2"], 60 | ["#FFAA85", "#B3315F"], 61 | ["#72EDF2", "#5151E5"], 62 | ["#FF9D6C", "#BB4E75"], 63 | ["#F6D242", "#FF52E5"], 64 | ["#69FF97", "#00E4FF"], 65 | ["#3B2667", "#BC78EC"], 66 | ["#70F570", "#49C628"], 67 | ["#3C8CE7", "#00EAFF"], 68 | ["#FAB2FF", "#1904E5"], 69 | ["#81FFEF", "#F067B4"], 70 | ["#FFA8A8", "#FCFF00"], 71 | ["#FFCF71", "#2376DD"], 72 | ["#FF96F9", "#C32BAC"] 73 | ]; 74 | for (var i = 0; i < data.length; i++) { 75 | var createBrick = document.createElement("div"); 76 | let firstColor = data[i][0]; 77 | let secondColor = data[i][1]; 78 | createBrick.dataset.firstColor = firstColor; 79 | createBrick.dataset.secondColor = secondColor; 80 | createBrick.classList.add("brick"); 81 | createBrick.style.backgroundImage = "linear-gradient(135deg, " + firstColor + " 10%, " + secondColor + " 100%)"; 82 | getPaint.appendChild(createBrick); 83 | } 84 | 85 | 86 | 87 | if (typeof (Storage) != undefined) { 88 | var getTheme = localStorage.getItem("theme"); 89 | if (getTheme != undefined && getTheme === "dark") { 90 | getBody.classList.add("dark"); 91 | } 92 | clTheme.addEventListener("click", () => { 93 | if (getBody.classList.contains("dark")) { 94 | getBody.classList.remove("dark"); 95 | localStorage.setItem("theme", "bright"); 96 | } else { 97 | getBody.classList.add("dark"); 98 | localStorage.setItem("theme", "dark"); 99 | } 100 | }) 101 | } 102 | 103 | window.addEventListener("click", (ev) => { 104 | if (ev.target.matches(".brick")) { 105 | var tempObj = new Object(); 106 | tempObj["firstColor"] = ev.target.dataset.firstColor; 107 | tempObj["secondColor"] = ev.target.dataset.secondColor; 108 | window.postMessage('nativeGradientApplier', tempObj); 109 | } 110 | }); 111 | 112 | clShuffle.addEventListener("click", () => { 113 | var tempObj = new Object(); 114 | tempObj["firstColor"] = gradientRand(); 115 | tempObj["secondColor"] = gradientRand(); 116 | window.postMessage('nativeGradientApplier', tempObj); 117 | }); 118 | //Handler 119 | } 120 | 121 | //Trigger Intialization 122 | window.addEventListener("load", initHandler); -------------------------------------------------------------------------------- /images/coolhue-logo.svg: -------------------------------------------------------------------------------- 1 | 65 | -------------------------------------------------------------------------------- /scripts/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function () { 2 | //Globals 3 | var chPaper = document.querySelector(".ch-paper"); 4 | var chColorFrom = document.querySelectorAll(".ch-color-from"); 5 | var chColorTo = document.querySelectorAll(".ch-color-to"); 6 | var chGradient = document.querySelectorAll(".ch-gradient"); 7 | var chCode = document.querySelectorAll(".ch-code"); 8 | var chGrab = document.querySelectorAll(".ch-grab"); 9 | var notifyPlank = document.querySelector(".ch-notify-plank"); 10 | var backgroundImage = "background-image: "; 11 | var gradientType = "linear-gradient( 135deg, "; 12 | var gradientStart = " 10%, "; 13 | var gradientEnd = " 100%)"; 14 | var colorData; 15 | var chStarCount = document.querySelector(".ch-starcount"); 16 | 17 | var xhr = new XMLHttpRequest(); 18 | xhr.open("GET", "scripts/coolhue.json", true); 19 | xhr.send(); 20 | 21 | var coolHueThread = new Promise(function (resolve, reject) { 22 | xhr.onreadystatechange = function () { 23 | if (this.readyState == 4 && this.status == 200) { 24 | resolve(this.responseText); 25 | } 26 | } 27 | }); 28 | 29 | coolHueThread.then(function (data) { 30 | colorData = JSON.parse(data); 31 | renderPaper(); 32 | }); 33 | 34 | var renderPaper = function () { 35 | for (var i = 0; i < colorData.length; i++) { 36 | tempColorFrom = colorData[i][0]; 37 | tempColorTo = colorData[i][1]; 38 | var tempImage = gradientType + tempColorFrom + gradientStart + tempColorTo + gradientEnd; 39 | 40 | var nodeGradientBrick = document.createElement("div"); 41 | nodeGradientBrick.classList.add("ch-gradient-brick"); 42 | var nodeGradient = document.createElement("div"); 43 | nodeGradient.classList.add("ch-gradient"); 44 | nodeGradient.style.backgroundImage = tempImage; 45 | var nodeActions = document.createElement("div"); 46 | nodeActions.classList.add("ch-actions"); 47 | var nodeCode = document.createElement("a"); 48 | nodeCode.classList.add("ch-code"); 49 | nodeCode.dataset.colorFrom = tempColorFrom; 50 | nodeCode.dataset.colorTo = tempColorTo; 51 | 52 | var nodeGrab = document.createElement("a"); 53 | nodeGrab.classList.add("ch-grab"); 54 | nodeGrab.dataset.colorFrom = tempColorFrom; 55 | nodeGrab.dataset.colorTo = tempColorTo; 56 | 57 | var nodeColors = document.createElement("div"); 58 | nodeColors.classList.add("ch-colors"); 59 | 60 | var nodeColorFrom = document.createElement("span"); 61 | nodeColorFrom.classList.add("ch-color-from"); 62 | var nodeColorFromText = document.createTextNode(tempColorFrom); 63 | 64 | var nodeColorTo = document.createElement("span"); 65 | nodeColorTo.classList.add("ch-color-to"); 66 | nodeColorTo.style.color = tempColorTo; 67 | 68 | var nodeColorToText = document.createTextNode(tempColorTo); 69 | 70 | //Append to Paper 71 | nodeGradientBrick.appendChild(nodeGradient); 72 | nodeActions.appendChild(nodeCode); 73 | nodeActions.appendChild(nodeGrab); 74 | nodeGradient.appendChild(nodeActions); 75 | nodeColors.appendChild(nodeColorFrom); 76 | nodeColorFrom.appendChild(nodeColorFromText); 77 | nodeColors.appendChild(nodeColorTo); 78 | nodeColorTo.appendChild(nodeColorToText); 79 | nodeGradientBrick.appendChild(nodeColors); 80 | chPaper.appendChild(nodeGradientBrick); 81 | } 82 | } 83 | 84 | var coolHueAction = function (event) { 85 | //Copy Code 86 | if (event.target.matches(".ch-code")) { 87 | var eventColorFrom = event.target.dataset.colorFrom; 88 | var eventColorTo = event.target.dataset.colorTo; 89 | var eventResult = backgroundImage + gradientType + eventColorFrom + gradientStart + eventColorTo + gradientEnd + ";"; 90 | 91 | function dynamicNode() { 92 | var node = document.createElement("pre"); 93 | node.style.position = "fixed"; 94 | node.style.fontSize = "0px"; 95 | node.textContent = eventResult; 96 | return node; 97 | }; 98 | 99 | var node = dynamicNode(); 100 | document.body.appendChild(node); 101 | 102 | var selection = getSelection(); 103 | selection.removeAllRanges(); 104 | var range = document.createRange(); 105 | range.selectNodeContents(node); 106 | selection.addRange(range); 107 | 108 | document.execCommand('copy'); 109 | selection.removeAllRanges(); 110 | document.body.removeChild(node); 111 | 112 | function notifyClient() { 113 | 114 | notifyPlank.classList.add("ch-notify-plank"); 115 | var notify = document.createElement("span"); 116 | notify.classList.add("ch-notify", "ch-notify-animate"); 117 | var notifyText = document.createTextNode("CSS3 Code Copied! 👍"); 118 | notify.appendChild(notifyText); 119 | notifyPlank.appendChild(notify); 120 | } 121 | notifyClient(); 122 | var removeNotify = function () { 123 | var notify = document.querySelectorAll(".ch-notify")[0]; 124 | notifyPlank.removeChild(notify); 125 | }; 126 | setTimeout(removeNotify, 2000); 127 | } 128 | 129 | //Grab Palette 130 | if (event.target.matches(".ch-grab")) { 131 | var eventColorFrom = event.target.dataset.colorFrom; 132 | var eventColorTo = event.target.dataset.colorTo; 133 | var canvas = document.createElement("canvas"); 134 | canvas.width = "1000"; 135 | canvas.height = "1000"; 136 | var ctx = canvas.getContext("2d"); 137 | var tempGradient = ctx.createLinearGradient(0, 0, 1000, 1000); 138 | tempGradient.addColorStop(0, eventColorFrom); 139 | tempGradient.addColorStop(1, eventColorTo); 140 | ctx.fillStyle = tempGradient; 141 | ctx.fillRect(0, 0, 1000, 1000); 142 | var dataURL = canvas.toDataURL(); 143 | event.target.href = dataURL; 144 | var fileName = "coolHue-" + eventColorFrom.slice(1, 7) + "-" + eventColorTo.slice(1, 7); 145 | event.target.setAttribute("download", fileName); 146 | } 147 | } 148 | window.onclick = function (event) { 149 | coolHueAction(event); 150 | } 151 | window.ontouchstart = function (event) { 152 | coolHueAction(event); 153 | } 154 | 155 | //Distro 156 | var chDistroWrapper = document.querySelector(".ch-distro-wrapper"); 157 | var chDistroIcon = document.querySelector(".ch-distro-icon"); 158 | chDistroIcon.addEventListener("click", function () { 159 | if (this.classList.contains("ch-distro-icon-active")) { 160 | chDistroWrapper.classList.remove("ch-distro-wrapper-flap-up"); 161 | chDistroWrapper.classList.add("ch-distro-wrapper-flap-down"); 162 | setTimeout(function () { 163 | chDistroIcon.classList.remove("ch-distro-icon-active"); 164 | chDistroWrapper.classList.remove("ch-distro-wrapper-visible"); 165 | }, 400); 166 | } else { 167 | if (chDistroWrapper.classList.contains("ch-distro-wrapper-flap-down")) { 168 | chDistroWrapper.classList.remove("ch-distro-wrapper-flap-down"); 169 | } 170 | chDistroWrapper.classList.add("ch-distro-wrapper-visible"); 171 | chDistroWrapper.classList.add("ch-distro-wrapper-flap-up"); 172 | this.classList.add("ch-distro-icon-active"); 173 | } 174 | }); 175 | }); -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | /*coolHue Stylesheet */ 2 | 3 | * { 4 | box-sizing: border-box; 5 | } 6 | 7 | ::selection { 8 | background: #6833DF; 9 | color: #FFFFFF; 10 | } 11 | 12 | body { 13 | -webkit-font-smoothing: subpixel-antialiased; 14 | -moz-osx-font-smoothing: grayscale; 15 | font-family: 'Source Sans Pro', sans-serif; 16 | margin: 0; 17 | } 18 | 19 | a { 20 | color: #2750C4; 21 | text-decoration: none; 22 | } 23 | 24 | .ch-topbar { 25 | width: 100%; 26 | border-bottom: solid 1px #E5E5E5; 27 | background: #FFFFFF; 28 | box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.08); 29 | font-size: 0; 30 | } 31 | 32 | .ch-topbar .grid-lt { 33 | width: 25%; 34 | display: inline-block; 35 | vertical-align: middle; 36 | padding: 10px; 37 | } 38 | 39 | .ch-topbar .grid-rt { 40 | width: 75%; 41 | display: inline-block; 42 | text-align: right; 43 | vertical-align: middle; 44 | padding: 0 10px; 45 | } 46 | 47 | .ch-devmode { 48 | display: inline-block; 49 | vertical-align: middle; 50 | color: #534e5c; 51 | font-size: 15px; 52 | margin-left: 3px; 53 | background: #f2f2f2; 54 | border-radius: 15px; 55 | padding: 2px 10px 4px 10px; 56 | } 57 | 58 | p { 59 | font-size: 18px; 60 | color: #929197; 61 | padding: 15px 25px; 62 | } 63 | 64 | .ch-paper { 65 | width: 100%; 66 | max-width: 1600px; 67 | text-align: center; 68 | margin: 20px auto; 69 | } 70 | 71 | .ch-footer { 72 | text-align: center; 73 | padding: 0 0 25px 0; 74 | } 75 | 76 | .ch-gradient-brick { 77 | width: 180px; 78 | display: inline-block; 79 | border-radius: 12px; 80 | margin: 25px; 81 | box-shadow: 0px 0px 51px 0px rgba(0, 0, 0, 0.08), 0px 6px 18px 0px rgba(0, 0, 0, 0.05); 82 | transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.35s cubic-bezier(0.4, 0, 0.2, 1); 83 | transform: translateY(0px); 84 | } 85 | 86 | .ch-gradient-brick:hover { 87 | box-shadow: 0px 0px 114px 0px rgba(0, 0, 0, 0.08), 0px 30px 25px 0px rgba(0, 0, 0, 0.05); 88 | transform: translateY(-5px); 89 | } 90 | 91 | .ch-gradient { 92 | border-radius: 12px 12px 0px 0px; 93 | width: 100%; 94 | height: 180px; 95 | position: relative; 96 | background-color: #CFD8DC; 97 | } 98 | 99 | .ch-actions { 100 | display: none; 101 | position: absolute; 102 | right: 5px; 103 | bottom: 5px; 104 | } 105 | 106 | .ch-gradient-brick:hover .ch-actions { 107 | display: block; 108 | animation: micro-move .3s cubic-bezier(0.4, 0, 0.2, 1); 109 | } 110 | 111 | .ch-code, 112 | .ch-grab { 113 | width: 26px; 114 | height: 26px; 115 | display: inline-block; 116 | background-image: url("../images/coolhue-sprite.svg"); 117 | background-repeat: no-repeat; 118 | cursor: pointer; 119 | vertical-align: middle; 120 | margin: 3px; 121 | transform: translateY(0px); 122 | transition: 0.2s cubic-bezier(0.4, 0, 0.2, 1); 123 | opacity: .7; 124 | } 125 | 126 | @keyframes micro-move { 127 | from { 128 | transform: translateY(5px); 129 | } 130 | to { 131 | transform: translateY(0px); 132 | } 133 | } 134 | 135 | .ch-code:hover, 136 | .ch-grab:hover { 137 | opacity: 1; 138 | transform: translateY(-4px); 139 | } 140 | 141 | .ch-code:active, 142 | .ch-grab:active { 143 | opacity: 1; 144 | transform: translateY(-2px); 145 | } 146 | 147 | .ch-code { 148 | background-position: -26px 0px; 149 | } 150 | 151 | .ch-grab { 152 | background-position: 0px 0px; 153 | } 154 | 155 | .ch-colors { 156 | border-radius: 0px 0px 12px 12px; 157 | padding: 12px; 158 | text-align: left; 159 | text-transform: uppercase; 160 | font-size: 18px; 161 | } 162 | 163 | .ch-color-from { 164 | margin-bottom: 3px; 165 | } 166 | 167 | .ch-color-from, 168 | .ch-color-to { 169 | color: #929197; 170 | display: block; 171 | padding: 0px; 172 | } 173 | 174 | .ch-notify-plank { 175 | position: fixed; 176 | width: 260px; 177 | max-width: 80%; 178 | top: 30px; 179 | right: 0; 180 | z-index: 500; 181 | text-align: right; 182 | } 183 | 184 | .ch-notify { 185 | margin: 0px 35px 10px 0px; 186 | background-color: #FFFFFF; 187 | box-shadow: 0px 4px 15.36px 0.64px rgba(0, 0, 0, 0.1), 0px 2px 6px 0px rgba(0, 0, 0, 0.12); 188 | padding: 10px 20px; 189 | color: #534E5C; 190 | display: inline-block; 191 | border-radius: 500px; 192 | font-size: 18px; 193 | transition: .35s ease-in-out; 194 | } 195 | 196 | .ch-notify-animate { 197 | animation: notify-up 2s cubic-bezier(0.4, 0, 0.2, 1) forwards; 198 | } 199 | 200 | .ch-distro { 201 | position: fixed; 202 | z-index: 50; 203 | right: 15px; 204 | bottom: 15px; 205 | min-width: 200px; 206 | max-width: 100%; 207 | } 208 | 209 | .ch-distro-icon { 210 | width: 50px; 211 | height: 50px; 212 | border-radius: 50%; 213 | position: absolute; 214 | right: 0px; 215 | bottom: 0px; 216 | background-color: #FFFFFF; 217 | background-image: url("../images/coolhue-sprite.svg"); 218 | background-repeat: no-repeat; 219 | background-position: 0px -25px; 220 | box-shadow: 0px 12px 27px 3px rgba(0, 0, 0, 0.15), 0px 6px 4px 0px rgba(0, 0, 0, 0.05); 221 | transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.35s cubic-bezier(0.4, 0, 0.2, 1); 222 | transform: translateY(0px); 223 | cursor: pointer; 224 | } 225 | 226 | .ch-distro-icon-active, 227 | .ch-distro-icon:hover { 228 | box-shadow: 0px 25px 30px 5px rgba(0, 0, 0, 0.1), 0px 5px 20px 5px rgba(0, 0, 0, 0.03); 229 | transform: translateY(-6px); 230 | } 231 | 232 | .ch-distro-icon-active { 233 | background-position: -50px -25px; 234 | } 235 | 236 | .ch-distro-wrapper { 237 | left: 0px; 238 | right: 0px; 239 | bottom: 70px; 240 | position: absolute; 241 | background-color: #FFFFFF; 242 | box-shadow: 0px 0px 51px 0px rgba(0, 0, 0, 0.08), 0px 6px 18px 0px rgba(0, 0, 0, 0.05); 243 | border-radius: 8px; 244 | padding: 15px; 245 | display: none; 246 | } 247 | 248 | .ch-distro-type { 249 | color: #2750C4; 250 | display: block; 251 | padding: 7px 0 7px 0; 252 | text-decoration: none; 253 | font-size: 17px; 254 | background-position: left center; 255 | background-repeat: no-repeat; 256 | } 257 | 258 | .ch-distro-type:hover { 259 | text-decoration: underline; 260 | } 261 | 262 | .ch-distro-type:before { 263 | content: ""; 264 | width: 26px; 265 | height: 26px; 266 | display: inline-block; 267 | vertical-align: middle; 268 | margin-top: -3px; 269 | margin-right: 7px; 270 | } 271 | 272 | .ch-distro-type:nth-child(1):before { 273 | background-image: url("../images/coolhue-sprite.svg"); 274 | background-position: 0px -77px; 275 | } 276 | 277 | .ch-distro-type:nth-child(2):before { 278 | background-image: url("../images/coolhue-sprite.svg"); 279 | background-position: -26px -77px; 280 | } 281 | 282 | .ch-distro-type:nth-child(3):before { 283 | background-image: url("../images/coolhue-sprite.svg"); 284 | background-position: -52px -77px; 285 | } 286 | 287 | .ch-distro-wrapper-flap-up { 288 | animation: flap-up 0.5s cubic-bezier(0.4, 0, 0.2, 1); 289 | } 290 | 291 | .ch-distro-wrapper-flap-down { 292 | animation: flap-down 0.5s cubic-bezier(0.4, 0, 0.2, 1); 293 | } 294 | 295 | .ch-distro-wrapper-visible { 296 | display: block; 297 | } 298 | 299 | @keyframes flap-up { 300 | 0% { 301 | opacity: 0; 302 | transform: translateY(25px); 303 | } 304 | 100% { 305 | opacity: 1; 306 | transform: translateY(0px); 307 | } 308 | } 309 | 310 | @keyframes flap-down { 311 | 0% { 312 | opacity: 1; 313 | transform: translateY(0px); 314 | } 315 | 100% { 316 | opacity: 0; 317 | transform: translateY(25px); 318 | } 319 | } 320 | 321 | @keyframes notify-up { 322 | 0% { 323 | opacity: 0; 324 | transform: translateY(25px); 325 | } 326 | 10%, 327 | 90% { 328 | opacity: 1; 329 | transform: translateY(0px); 330 | } 331 | 100% { 332 | opacity: 0; 333 | transform: translateY(-25px); 334 | } 335 | } 336 | 337 | .ch-notify span { 338 | display: block; 339 | text-align: center; 340 | } 341 | 342 | noscript { 343 | font-size: 20px; 344 | color: #757575; 345 | } 346 | 347 | @media screen and (min-width:320px) and (max-width:1024px) { 348 | .ch-gradient-brick .ch-actions { 349 | display: block; 350 | animation: micro-move .3s cubic-bezier(0.4, 0, 0.2, 1); 351 | } 352 | .ch-gradient-brick:hover { 353 | transform: translateY(0px); 354 | box-shadow: 0px 0px 51px 0px rgba(0, 0, 0, 0.08), 0px 6px 18px 0px rgba(0, 0, 0, 0.05); 355 | } 356 | .ch-code:hover, 357 | .ch-grab:hover { 358 | transform: translateY(0px); 359 | } 360 | } 361 | 362 | @media screen and (max-width:480px) { 363 | .ch-share-brick { 364 | margin: 0; 365 | } 366 | .ch-share-brick:hover { 367 | box-shadow: none; 368 | } 369 | .ch-share-text, 370 | .ch-starcount { 371 | display: none; 372 | } 373 | } -------------------------------------------------------------------------------- /images/coolhue-sprite.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | coolhue-sprite 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /distro/CoolHue.sketchplugin/Contents/Sketch/coolhue.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap","webpack://exports/./node_modules/@skpm/timers/immediate.js","webpack://exports/./node_modules/@skpm/timers/test-if-fiber.js","webpack://exports/./node_modules/@skpm/timers/timeout.js","webpack://exports/./node_modules/cocoascript-class/lib/index.js","webpack://exports/./node_modules/cocoascript-class/lib/runtime.js","webpack://exports/./node_modules/promise-polyfill/lib/index.js","webpack://exports/./node_modules/sketch-module-web-view/lib/browser-api.js","webpack://exports/./node_modules/sketch-module-web-view/lib/constants.js","webpack://exports/./node_modules/sketch-module-web-view/lib/dispatch-first-click.js","webpack://exports/./node_modules/sketch-module-web-view/lib/fitSubview.js","webpack://exports/./node_modules/sketch-module-web-view/lib/index.js","webpack://exports/./node_modules/sketch-module-web-view/lib/inject-client-messaging.js","webpack://exports/./node_modules/sketch-module-web-view/lib/parseWebArguments.js","webpack://exports/./node_modules/sketch-module-web-view/lib/set-delegates.js","webpack://exports/./node_modules/sketch-module-web-view/lib/webview-api.js","webpack://exports/./src/coolhue.js","webpack://exports/./src/gradient.js","webpack://exports/./src/view.html","webpack://exports/external \"events\"","webpack://exports/external \"sketch\"","webpack://exports/external \"sketch/dom\"","webpack://exports/external \"sketch/ui\""],"names":["options","backgroundColor","identifier","width","height","resizable","movable","alwaysOnTop","minimizable","maximizable","title","vibrancy","browserWindow","BrowserWindow","isAlwaysOnTop","loadURL","require","webContents","on","fetchedData","GradientMaker","firstColor","secondColor","Style","firstStop","secondStop","doc","sketch","getSelectedDocument","selectedLayers","length","forEach","layer","type","style","fills","fillType","FillType","Gradient","fill","gradient","gradientType","GradientType","Linear","from","x","y","to","stops","position","color","UI","message"],"mappings":";;;;;;AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,kDAA0C,gCAAgC;AAC1E;AACA;;AAEA;AACA;AACA;AACA,gEAAwD,kBAAkB;AAC1E;AACA,yDAAiD,cAAc;AAC/D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAyC,iCAAiC;AAC1E,wHAAgH,mBAAmB,EAAE;AACrI;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;;AAGA;AACA;;;;;;;;;;;;AClFA;AACA,cAAc,mBAAO,CAAC,yDAAW;;AAEjC;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;;;;;;;;;;;ACdA;AACA;AACA;;;;;;;;;;;;ACFA;AACA,qBAAqB,mBAAO,CAAC,qEAAiB;;AAE9C;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA,yCAAyC,cAAc,IAAI;AAC3D;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;AC1Da;;AAEb;AACA;AACA,CAAC;AACD;AACA;;AAEA,eAAe,mBAAO,CAAC,qEAAc;;AAErC;;AAEA;AACA;;AAEA,6EAA6E,YAAY;;AAEzF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,OAAO;AACP;AACA,KAAK;AACL;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA,C;;;;;;;;;;;;AC7Da;;AAEb;AACA;AACA,CAAC;AACD;AACA;AACA,kCAAkC,qCAAqC;;AAEvE;AACA;AACA,4CAA4C,sCAAsC,GAAG,YAAY;AACjG;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA,iEAAiE;AACjE;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,oBAAoB,QAAQ,YAAY,WAAW;AACnD;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA,8GAA8G,YAAY,GAAG,YAAY,GAAG,aAAa,IAAI,UAAU,WAAW,GAAG;AACrL;AACA,8GAA8G,YAAY,GAAG,YAAY,GAAG,YAAY,IAAI,UAAU,WAAW,GAAG;;AAEpL;AACA,wCAAwC,gCAAgC,E;;;;;;;;;;;;ACvGxE,gEAAa;;AAEb;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,SAAS;AACpB;AACA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA,aAAa,SAAS;AACtB;AACA,aAAa,kBAAkB;AAC/B;AACA,aAAa,kBAAkB;AAC/B;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA,+CAA+C,SAAS;AACxD;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA,mBAAmB,iBAAiB;AACpC;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA,wCAAwC,SAAS;AACjD;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA,+DAA+D;AAC/D;AACA;;AAEA;;;;;;;;;;;;;AClQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,mBAAmB,OAAO;AAC1B;AACA;AACA;AACA,GAAG;AACH;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,SAAS;AACT,OAAO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,qBAAqB;AACrB;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,qBAAqB;AACrB;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;AACA,OAAO;AACP;AACA,OAAO;AACP;AACA,OAAO;AACP;AACA,OAAO;AACP;AACA,OAAO;AACP;AACA,OAAO;AACP;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;AChmBA;AACA;AACA;;;;;;;;;;;;ACFA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA,QAAQ;AACR,gBAAgB;AAChB,MAAM,eAAe;AACrB,0CAA0C,cAAc;AACxD,MAAM;AACN;AACA;;;;;;;;;;;;ACvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACrBA;AACA;AACA,mBAAmB,mBAAO,CAAC,sBAAQ;AACnC,sBAAsB,mBAAO,CAAC,+EAAe;AAC7C,kBAAkB,mBAAO,CAAC,+EAAe;AACzC,uBAAuB,mBAAO,CAAC,6EAAc;AAC7C,yBAAyB,mBAAO,CAAC,iGAAwB;AACzD,4BAA4B,mBAAO,CAAC,uGAA2B;AAC/D,mBAAmB,mBAAO,CAAC,mFAAiB;;AAE5C;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;;;;;;;;;;;ACnUA,gBAAgB,mBAAO,CAAC,2EAAa;;AAErC;AACA;AACA,qDAAqD;AACrD,gDAAgD;AAChD,uBAAuB;AACvB;AACA,MAAM;AACN;AACA;AACA;AACA;AACA,OAAO;AACP,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACxBA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;;;;;;;;;;AClBA,gBAAgB,mBAAO,CAAC,wEAAmB;AAC3C,wBAAwB,mBAAO,CAAC,2FAAqB;AACrD,gBAAgB,mBAAO,CAAC,2EAAa;;AAErC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,OAAO;;AAEP;AACA;AACA,OAAO;;AAEP;AACA;AACA,OAAO;;AAEP;AACA;AACA,OAAO;;AAEP;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA,WAAW;AACX,SAAS;AACT;AACA,OAAO;;AAEP;AACA;AACA,OAAO;;AAEP;AACA;AACA,OAAO;;AAEP;AACA;AACA,OAAO;AACP,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA,2CAA2C;AAC3C,OAAO;;AAEP;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA;AACA;AACA,aAAa;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA,OAAO;;AAEP;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,OAAO;AACP,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;;AAEH;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;;;;;;;;;;;ACtQA,kEAAmB,mBAAO,CAAC,sBAAQ;;AAEnC;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD;AACnD;AACA,QAAQ,kCAAkC;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA,WAAW;AACX;AACA,WAAW;AACX;AACA;AACA;AACA,SAAS;AACT;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,2BAA2B;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;;;;;;;;;;;;;ACtQA;AAAA;AAAA;AAAA;AAAA;AACA;AAEe,2EAAY;AAEzB;AACA,MAAMA,OAAO,GAAG;AACdC,mBAAe,EAAE,SADH;AAEdC,cAAU,EAAE,YAFE;AAGdC,SAAK,EAAE,GAHO;AAIdC,UAAM,EAAE,GAJM;AAKdC,aAAS,EAAE,KALG;AAMdC,WAAO,EAAE,IANK;AAOdC,eAAW,EAAE,IAPC;AAQdC,eAAW,EAAE,IARC;AASdC,eAAW,EAAE,KATC;AAUdC,SAAK,EAAE,aAVO;AAWdC,YAAQ,EAAE;AAXI,GAAhB;AAaA,MAAMC,aAAa,GAAG,IAAIC,6DAAJ,CAAkBb,OAAlB,CAAtB;AACAY,eAAa,CAACE,aAAd;AACAF,eAAa,CAACG,OAAd,CAAsBC,mBAAO,CAAC,oCAAD,CAA7B;AACAJ,eAAa,CAACK,WAAd,CAA0BC,EAA1B,CAA6B,uBAA7B,EAAsD,UAAUC,WAAV,EAAuB;AAC3EC,mEAAa,CAACD,WAAW,CAACE,UAAb,EAAwBF,WAAW,CAACG,WAApC,CAAb;AACD,GAFD;AAGD,C;;;;;;;;;;;;ACzBD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;AACA,IAAIC,KAAK,GAAGP,mBAAO,CAAC,8BAAD,CAAP,CAAsBO,KAAlC;;AAEO,SAASH,aAAT,CAAuBI,SAAvB,EAAkCC,UAAlC,EAA8C;AACjD,MAAIC,GAAG,GAAGC,6CAAM,CAACC,mBAAP,EAAV;AACA,MAAIC,cAAc,GAAGH,GAAG,CAACG,cAAzB;;AACA,MAAIA,cAAc,CAACC,MAAf,IAAyB,IAAzB,IAAiCD,cAAc,CAACC,MAAf,IAAyB,CAA9D,EAAiE;AAE7DD,kBAAc,CAACE,OAAf,CAAuB,UAAAC,KAAK,EAAI;AAC5B,UAAIA,KAAK,CAACC,IAAN,KAAe,OAAf,IAA0BD,KAAK,CAACC,IAAN,KAAe,WAA7C,EAA0D;AACtDD,aAAK,CAACE,KAAN,CAAYC,KAAZ,GAAoB,CAAC;AACjBC,kBAAQ,EAAEb,KAAK,CAACc,QAAN,CAAeC,QADR;AAEjBC,cAAI,EAAE,UAFW;AAGjBC,kBAAQ,EAAE;AACNC,wBAAY,EAAElB,KAAK,CAACmB,YAAN,CAAmBC,MAD3B;AAENC,gBAAI,EAAE;AACFC,eAAC,EAAE,CADD;AAEFC,eAAC,EAAE;AAFD,aAFA;AAMNC,cAAE,EAAE;AACAF,eAAC,EAAE,CADH;AAEAC,eAAC,EAAE;AAFH,aANE;AAUNE,iBAAK,EAAE,CAAC;AACAC,sBAAQ,EAAE,CADV;AAEAC,mBAAK,EAAE1B;AAFP,aAAD,EAIH;AACIyB,sBAAQ,EAAE,CADd;AAEIC,mBAAK,EAAEzB;AAFX,aAJG;AAVD;AAHO,SAAD,CAApB;AAwBH,OAzBD,MAyBO;AACH0B,wDAAE,CAACC,OAAH;AACH;AACJ,KA7BD;AA8BH,GAhCD,MAgCO;AACHD,oDAAE,CAACC,OAAH;AACH;AACJ,C;;;;;;;;;;;AC1CD,mI;;;;;;;;;;;ACAA,mC;;;;;;;;;;;ACAA,mC;;;;;;;;;;;ACAA,uC;;;;;;;;;;;ACAA,sC","file":"coolhue.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/coolhue.js\");\n","/* globals coscript, sketch */\nvar timeout = require('./timeout')\n\nfunction setImmediate(func, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) {\n return timeout.setTimeout(func, 0, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10)\n}\n\nfunction clearImmediate(id) {\n return timeout.clearTimeout(id)\n}\n\nmodule.exports = {\n setImmediate: setImmediate,\n clearImmediate: clearImmediate\n}\n","module.exports = function () {\n return typeof coscript !== 'undefined' && coscript.createFiber\n}\n","/* globals coscript, sketch */\nvar fiberAvailable = require('./test-if-fiber')\n\nvar setTimeout\nvar clearTimeout\n\nvar fibers = []\n\nif (fiberAvailable()) {\n var fibers = []\n\n setTimeout = function (func, delay, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) {\n // fibers takes care of keeping coscript around\n var id = fibers.length\n fibers.push(coscript.scheduleWithInterval_jsFunction(\n (delay || 0) / 1000,\n function () {\n func(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10)\n }\n ))\n return id\n }\n\n clearTimeout = function (id) {\n var timeout = fibers[id]\n if (timeout) {\n timeout.cancel() // fibers takes care of keeping coscript around\n fibers[id] = undefined // garbage collect the fiber\n }\n }\n} else {\n setTimeout = function (func, delay, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) {\n coscript.shouldKeepAround = true\n var id = fibers.length\n fibers.push(true)\n coscript.scheduleWithInterval_jsFunction(\n (delay || 0) / 1000,\n function () {\n if (fibers[id]) { // if not cleared\n func(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10)\n }\n clearTimeout(id)\n if (fibers.every(function (_id) { return !_id })) { // if everything is cleared\n coscript.shouldKeepAround = false\n }\n }\n )\n return id\n }\n\n clearTimeout = function (id) {\n fibers[id] = false\n }\n}\n\nmodule.exports = {\n setTimeout: setTimeout,\n clearTimeout: clearTimeout\n}\n","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.SuperCall = undefined;\nexports.default = ObjCClass;\n\nvar _runtime = require(\"./runtime.js\");\n\nexports.SuperCall = _runtime.SuperCall;\n\n// super when returnType is id and args are void\n// id objc_msgSendSuper(struct objc_super *super, SEL op, void)\n\nconst SuperInit = (0, _runtime.SuperCall)(NSStringFromSelector(\"init\"), [], { type: \"@\" });\n\n// Returns a real ObjC class. No need to use new.\nfunction ObjCClass(defn) {\n const superclass = defn.superclass || NSObject;\n const className = (defn.className || defn.classname || \"ObjCClass\") + NSUUID.UUID().UUIDString();\n const reserved = new Set(['className', 'classname', 'superclass']);\n var cls = MOClassDescription.allocateDescriptionForClassWithName_superclass_(className, superclass);\n // Add each handler to the class description\n const ivars = [];\n for (var key in defn) {\n const v = defn[key];\n if (typeof v == 'function' && key !== 'init') {\n var selector = NSSelectorFromString(key);\n cls.addInstanceMethodWithSelector_function_(selector, v);\n } else if (!reserved.has(key)) {\n ivars.push(key);\n cls.addInstanceVariableWithName_typeEncoding(key, \"@\");\n }\n }\n\n cls.addInstanceMethodWithSelector_function_(NSSelectorFromString('init'), function () {\n const self = SuperInit.call(this);\n ivars.map(name => {\n Object.defineProperty(self, name, {\n get() {\n return getIvar(self, name);\n },\n set(v) {\n (0, _runtime.object_setInstanceVariable)(self, name, v);\n }\n });\n self[name] = defn[name];\n });\n // If there is a passsed-in init funciton, call it now.\n if (typeof defn.init == 'function') defn.init.call(this);\n return self;\n });\n\n return cls.registerClass();\n};\n\nfunction getIvar(obj, name) {\n const retPtr = MOPointer.new();\n (0, _runtime.object_getInstanceVariable)(obj, name, retPtr);\n return retPtr.value().retain().autorelease();\n}","'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.SuperCall = SuperCall;\nexports.CFunc = CFunc;\nconst objc_super_typeEncoding = '{objc_super=\"receiver\"@\"super_class\"#}';\n\n// You can store this to call your function. this must be bound to the current instance.\nfunction SuperCall(selector, argTypes, returnType) {\n const func = CFunc(\"objc_msgSendSuper\", [{ type: '^' + objc_super_typeEncoding }, { type: \":\" }, ...argTypes], returnType);\n return function (...args) {\n const struct = make_objc_super(this, this.superclass());\n const structPtr = MOPointer.alloc().initWithValue_(struct);\n return func(structPtr, selector, ...args);\n };\n}\n\n// Recursively create a MOStruct\nfunction makeStruct(def) {\n if (typeof def !== 'object' || Object.keys(def).length == 0) {\n return def;\n }\n const name = Object.keys(def)[0];\n const values = def[name];\n\n const structure = MOStruct.structureWithName_memberNames_runtime(name, Object.keys(values), Mocha.sharedRuntime());\n\n Object.keys(values).map(member => {\n structure[member] = makeStruct(values[member]);\n });\n\n return structure;\n}\n\nfunction make_objc_super(self, cls) {\n return makeStruct({\n objc_super: {\n receiver: self,\n super_class: cls\n }\n });\n}\n\n// Due to particularities of the JS bridge, we can't call into MOBridgeSupport objects directly\n// But, we can ask key value coding to do the dirty work for us ;)\nfunction setKeys(o, d) {\n const funcDict = NSMutableDictionary.dictionary();\n funcDict.o = o;\n Object.keys(d).map(k => funcDict.setValue_forKeyPath(d[k], \"o.\" + k));\n}\n\n// Use any C function, not just ones with BridgeSupport\nfunction CFunc(name, args, retVal) {\n function makeArgument(a) {\n if (!a) return null;\n const arg = MOBridgeSupportArgument.alloc().init();\n setKeys(arg, {\n type64: a.type\n });\n return arg;\n }\n const func = MOBridgeSupportFunction.alloc().init();\n setKeys(func, {\n name: name,\n arguments: args.map(makeArgument),\n returnValue: makeArgument(retVal)\n });\n return func;\n}\n\n/*\n@encode(char*) = \"*\"\n@encode(id) = \"@\"\n@encode(Class) = \"#\"\n@encode(void*) = \"^v\"\n@encode(CGRect) = \"{CGRect={CGPoint=dd}{CGSize=dd}}\"\n@encode(SEL) = \":\"\n*/\n\nfunction addStructToBridgeSupport(key, structDef) {\n // OK, so this is probably the nastiest hack in this file.\n // We go modify MOBridgeSupportController behind its back and use kvc to add our own definition\n // There isn't another API for this though. So the only other way would be to make a real bridgesupport file.\n const symbols = MOBridgeSupportController.sharedController().valueForKey('symbols');\n if (!symbols) throw Error(\"Something has changed within bridge support so we can't add our definitions\");\n // If someone already added this definition, don't re-register it.\n if (symbols[key] !== null) return;\n const def = MOBridgeSupportStruct.alloc().init();\n setKeys(def, {\n name: key,\n type: structDef.type\n });\n symbols[key] = def;\n};\n\n// This assumes the ivar is an object type. Return value is pretty useless.\nconst object_getInstanceVariable = exports.object_getInstanceVariable = CFunc(\"object_getInstanceVariable\", [{ type: \"@\" }, { type: '*' }, { type: \"^@\" }], { type: \"^{objc_ivar=}\" });\n// Again, ivar is of object type\nconst object_setInstanceVariable = exports.object_setInstanceVariable = CFunc(\"object_setInstanceVariable\", [{ type: \"@\" }, { type: '*' }, { type: \"@\" }], { type: \"^{objc_ivar=}\" });\n\n// We need Mocha to understand what an objc_super is so we can use it as a function argument\naddStructToBridgeSupport('objc_super', { type: objc_super_typeEncoding });","'use strict';\n\n/**\n * @this {Promise}\n */\nfunction finallyConstructor(callback) {\n var constructor = this.constructor;\n return this.then(\n function(value) {\n return constructor.resolve(callback()).then(function() {\n return value;\n });\n },\n function(reason) {\n return constructor.resolve(callback()).then(function() {\n return constructor.reject(reason);\n });\n }\n );\n}\n\n// Store setTimeout reference so promise-polyfill will be unaffected by\n// other code modifying setTimeout (like sinon.useFakeTimers())\nvar setTimeoutFunc = setTimeout;\n\nfunction noop() {}\n\n// Polyfill for Function.prototype.bind\nfunction bind(fn, thisArg) {\n return function() {\n fn.apply(thisArg, arguments);\n };\n}\n\n/**\n * @constructor\n * @param {Function} fn\n */\nfunction Promise(fn) {\n if (!(this instanceof Promise))\n throw new TypeError('Promises must be constructed via new');\n if (typeof fn !== 'function') throw new TypeError('not a function');\n /** @type {!number} */\n this._state = 0;\n /** @type {!boolean} */\n this._handled = false;\n /** @type {Promise|undefined} */\n this._value = undefined;\n /** @type {!Array} */\n this._deferreds = [];\n\n doResolve(fn, this);\n}\n\nfunction handle(self, deferred) {\n while (self._state === 3) {\n self = self._value;\n }\n if (self._state === 0) {\n self._deferreds.push(deferred);\n return;\n }\n self._handled = true;\n Promise._immediateFn(function() {\n var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;\n if (cb === null) {\n (self._state === 1 ? resolve : reject)(deferred.promise, self._value);\n return;\n }\n var ret;\n try {\n ret = cb(self._value);\n } catch (e) {\n reject(deferred.promise, e);\n return;\n }\n resolve(deferred.promise, ret);\n });\n}\n\nfunction resolve(self, newValue) {\n try {\n // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure\n if (newValue === self)\n throw new TypeError('A promise cannot be resolved with itself.');\n if (\n newValue &&\n (typeof newValue === 'object' || typeof newValue === 'function')\n ) {\n var then = newValue.then;\n if (newValue instanceof Promise) {\n self._state = 3;\n self._value = newValue;\n finale(self);\n return;\n } else if (typeof then === 'function') {\n doResolve(bind(then, newValue), self);\n return;\n }\n }\n self._state = 1;\n self._value = newValue;\n finale(self);\n } catch (e) {\n reject(self, e);\n }\n}\n\nfunction reject(self, newValue) {\n self._state = 2;\n self._value = newValue;\n finale(self);\n}\n\nfunction finale(self) {\n if (self._state === 2 && self._deferreds.length === 0) {\n Promise._immediateFn(function() {\n if (!self._handled) {\n Promise._unhandledRejectionFn(self._value);\n }\n });\n }\n\n for (var i = 0, len = self._deferreds.length; i < len; i++) {\n handle(self, self._deferreds[i]);\n }\n self._deferreds = null;\n}\n\n/**\n * @constructor\n */\nfunction Handler(onFulfilled, onRejected, promise) {\n this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;\n this.onRejected = typeof onRejected === 'function' ? onRejected : null;\n this.promise = promise;\n}\n\n/**\n * Take a potentially misbehaving resolver function and make sure\n * onFulfilled and onRejected are only called once.\n *\n * Makes no guarantees about asynchrony.\n */\nfunction doResolve(fn, self) {\n var done = false;\n try {\n fn(\n function(value) {\n if (done) return;\n done = true;\n resolve(self, value);\n },\n function(reason) {\n if (done) return;\n done = true;\n reject(self, reason);\n }\n );\n } catch (ex) {\n if (done) return;\n done = true;\n reject(self, ex);\n }\n}\n\nPromise.prototype['catch'] = function(onRejected) {\n return this.then(null, onRejected);\n};\n\nPromise.prototype.then = function(onFulfilled, onRejected) {\n // @ts-ignore\n var prom = new this.constructor(noop);\n\n handle(this, new Handler(onFulfilled, onRejected, prom));\n return prom;\n};\n\nPromise.prototype['finally'] = finallyConstructor;\n\nPromise.all = function(arr) {\n return new Promise(function(resolve, reject) {\n if (!arr || typeof arr.length === 'undefined')\n throw new TypeError('Promise.all accepts an array');\n var args = Array.prototype.slice.call(arr);\n if (args.length === 0) return resolve([]);\n var remaining = args.length;\n\n function res(i, val) {\n try {\n if (val && (typeof val === 'object' || typeof val === 'function')) {\n var then = val.then;\n if (typeof then === 'function') {\n then.call(\n val,\n function(val) {\n res(i, val);\n },\n reject\n );\n return;\n }\n }\n args[i] = val;\n if (--remaining === 0) {\n resolve(args);\n }\n } catch (ex) {\n reject(ex);\n }\n }\n\n for (var i = 0; i < args.length; i++) {\n res(i, args[i]);\n }\n });\n};\n\nPromise.resolve = function(value) {\n if (value && typeof value === 'object' && value.constructor === Promise) {\n return value;\n }\n\n return new Promise(function(resolve) {\n resolve(value);\n });\n};\n\nPromise.reject = function(value) {\n return new Promise(function(resolve, reject) {\n reject(value);\n });\n};\n\nPromise.race = function(values) {\n return new Promise(function(resolve, reject) {\n for (var i = 0, len = values.length; i < len; i++) {\n values[i].then(resolve, reject);\n }\n });\n};\n\n// Use polyfill for setImmediate for performance gains\nPromise._immediateFn =\n (typeof setImmediate === 'function' &&\n function(fn) {\n setImmediate(fn);\n }) ||\n function(fn) {\n setTimeoutFunc(fn, 0);\n };\n\nPromise._unhandledRejectionFn = function _unhandledRejectionFn(err) {\n if (typeof console !== 'undefined' && console) {\n console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console\n }\n};\n\nmodule.exports = Promise;\n","var COLOR_CLASSES = [\n 'NSColor',\n 'NSCachedWhiteColor',\n 'NSColorSpaceColor',\n 'NSDynamicSystemColor',\n 'NSCachedColorSpaceColor',\n]\nfunction parseHexColor(color) {\n // Check the string for incorrect formatting.\n if (!color || color[0] !== '#') {\n if (\n color &&\n color.class &&\n COLOR_CLASSES.indexOf(String(color.class())) !== -1\n ) {\n return color\n }\n throw new Error(\n 'Incorrect color formating. It should be an hex color: #RRGGBBAA'\n )\n }\n\n // append FF if alpha channel is not specified.\n var source = color.substr(1)\n if (source.length === 3) {\n source += 'F'\n } else if (source.length === 6) {\n source += 'FF'\n }\n // Convert the string from #FFF format to #FFFFFF format.\n var hex\n if (source.length === 4) {\n for (var i = 0; i < 4; i += 1) {\n hex += source[i]\n hex += source[i]\n }\n } else if (source.length === 8) {\n hex = source\n } else {\n return NSColor.whiteColor()\n }\n\n var r = parseInt(hex.slice(0, 2), 16)\n var g = parseInt(hex.slice(2, 4), 16)\n var b = parseInt(hex.slice(4, 6), 16)\n var a = parseInt(hex.slice(6, 8), 16)\n\n return NSColor.colorWithSRGBRed_green_blue_alpha(r, g, b, a)\n}\n\nmodule.exports = function(browserWindow, panel, webview) {\n // keep reference to the subviews\n browserWindow._panel = panel\n browserWindow._webview = webview\n browserWindow._destroyed = false\n\n browserWindow.destroy = function() {\n return panel.close()\n }\n\n browserWindow.close = function() {\n if (panel.delegate().utils.parentWindow) {\n var shouldClose = true\n browserWindow.emit('close', {\n get defaultPrevented() {\n return !shouldClose\n },\n preventDefault: function() {\n shouldClose = false\n },\n })\n if (shouldClose) {\n panel.delegate().utils.parentWindow.endSheet(panel)\n }\n return\n }\n\n if (!browserWindow.isClosable()) {\n return\n }\n\n panel.performClose(null)\n }\n\n function focus(focused) {\n if (browserWindow.isVisible()) {\n return\n }\n if (focused) {\n NSApplication.sharedApplication().activateIgnoringOtherApps(true)\n panel.makeKeyAndOrderFront(null)\n } else {\n panel.orderBack(null)\n }\n }\n\n browserWindow.focus = focus.bind(this, true)\n browserWindow.blur = focus.bind(this, false)\n\n browserWindow.isFocused = function() {\n return panel.isKeyWindow()\n }\n\n browserWindow.isDestroyed = function() {\n return browserWindow._destroyed\n }\n\n browserWindow.show = function() {\n // This method is supposed to put focus on window, however if the app does not\n // have focus then \"makeKeyAndOrderFront\" will only show the window.\n NSApp.activateIgnoringOtherApps(true)\n\n if (panel.delegate().utils.parentWindow) {\n return panel.delegate().utils.parentWindow.beginSheet_completionHandler(\n panel,\n __mocha__.createBlock_function('v16@?0q8', function() {\n browserWindow.emit('closed')\n })\n )\n }\n\n return panel.makeKeyAndOrderFront(null)\n }\n\n browserWindow.showInactive = function() {\n return panel.orderFrontRegardless()\n }\n\n browserWindow.hide = function() {\n return panel.orderOut(null)\n }\n\n browserWindow.isVisible = function() {\n return panel.isVisible()\n }\n\n browserWindow.isModal = function() {\n return false\n }\n\n browserWindow.maximize = function() {\n if (!browserWindow.isMaximized()) {\n panel.zoom(null)\n }\n }\n browserWindow.unmaximize = function() {\n if (browserWindow.isMaximized()) {\n panel.zoom(null)\n }\n }\n\n browserWindow.isMaximized = function() {\n if ((panel.styleMask() & NSResizableWindowMask) !== 0) {\n return panel.isZoomed()\n }\n var rectScreen = NSScreen.mainScreen().visibleFrame()\n var rectWindow = panel.frame()\n return (\n rectScreen.origin.x == rectWindow.origin.x &&\n rectScreen.origin.y == rectWindow.origin.y &&\n rectScreen.size.width == rectWindow.size.width &&\n rectScreen.size.height == rectWindow.size.height\n )\n }\n\n browserWindow.minimize = function() {\n return panel.miniaturize(null)\n }\n\n browserWindow.restore = function() {\n return panel.deminiaturize(null)\n }\n\n browserWindow.isMinimized = function() {\n return panel.isMiniaturized()\n }\n\n browserWindow.setFullScreen = function(fullscreen) {\n if (fullscreen !== browserWindow.isFullscreen()) {\n panel.toggleFullScreen(null)\n }\n }\n\n browserWindow.isFullscreen = function() {\n return panel.styleMask() & NSFullScreenWindowMask\n }\n\n browserWindow.setAspectRatio = function(aspectRatio /* , extraSize */) {\n // Reset the behaviour to default if aspect_ratio is set to 0 or less.\n if (aspectRatio > 0.0) {\n panel.setAspectRatio(NSMakeSize(aspectRatio, 1.0))\n } else {\n panel.setResizeIncrements(NSMakeSize(1.0, 1.0))\n }\n }\n\n browserWindow.setBounds = function(bounds, animate) {\n // Do nothing if in fullscreen mode.\n if (browserWindow.isFullscreen()) {\n return\n }\n\n // TODO: Check size constraints since setFrame does not check it.\n var size = bounds.size\n // size.SetToMax(GetMinimumSize());\n // gfx::Size max_size = GetMaximumSize();\n // if (!max_size.IsEmpty())\n // size.SetToMin(max_size);\n\n var cocoaBounds = NSMakeRect(bounds.origin.x, 0, size.width, size.height)\n // Flip coordinates based on the primary screen.\n var screen = NSScreen.screens().firstObject()\n cocoaBounds.origin.y =\n NSHeight(screen.frame()) - size.height - bounds.origin.y\n\n panel.setFrame_display_animate(cocoaBounds, true, animate)\n }\n\n browserWindow.getBounds = function() {\n return panel.frame()\n }\n\n browserWindow.setContentBounds = function(/* bounds, animate */) {\n // TODO:\n }\n\n browserWindow.getContentBounds = function() {\n // TODO:\n }\n\n browserWindow.setSize = function(width, height, animate) {\n var bounds = browserWindow.getBounds()\n bounds.size.height = height\n bounds.size.width = width\n\n // TODO: handle resizing around center\n\n return browserWindow.setBounds(bounds, animate)\n }\n\n browserWindow.getSize = function() {\n var bounds = browserWindow.getBounds()\n return [bounds.size.width, bounds.size.height]\n }\n\n browserWindow.setContentSize = function(width, height, animate) {\n var bounds = browserWindow.getContentBounds()\n bounds.size.height = height\n bounds.size.width = width\n\n // TODO: handle resizing around center\n\n return browserWindow.setContentBounds(bounds, animate)\n }\n\n browserWindow.getContentSize = function() {\n var bounds = browserWindow.getContentBounds()\n return [bounds.size.width, bounds.size.height]\n }\n\n browserWindow.setMinimumSize = function(width, height) {\n const minSize = { width: width, height: height }\n panel.setContentMinSize(minSize)\n }\n\n browserWindow.getMinimumSize = function() {\n const size = panel.contentMinSize()\n return [size.width, size.height]\n }\n\n browserWindow.setMaximumSize = function(width, height) {\n const minSize = { width: width, height: height }\n panel.setContentMaxSize(minSize)\n }\n\n browserWindow.getMaximumSize = function() {\n const size = panel.contentMaxSize()\n return [size.width, size.height]\n }\n\n browserWindow.setResizable = function(resizable) {\n return browserWindow._setStyleMask(resizable, NSResizableWindowMask)\n }\n\n browserWindow.isResizable = function() {\n return panel.styleMask() & NSResizableWindowMask\n }\n\n browserWindow.setMovable = function(movable) {\n return panel.setMovable(movable)\n }\n browserWindow.isMovable = function() {\n return panel.isMovable()\n }\n\n browserWindow.setMinimizable = function(minimizable) {\n return browserWindow._setStyleMask(minimizable, NSMiniaturizableWindowMask)\n }\n\n browserWindow.isMinimizable = function() {\n return panel.styleMask() & NSMiniaturizableWindowMask\n }\n\n browserWindow.setMaximizable = function(maximizable) {\n if (panel.standardWindowButton(NSWindowZoomButton)) {\n panel.standardWindowButton(NSWindowZoomButton).setEnabled(maximizable)\n }\n }\n\n browserWindow.isMaximizable = function() {\n return (\n panel.standardWindowButton(NSWindowZoomButton) &&\n panel.standardWindowButton(NSWindowZoomButton).isEnabled()\n )\n }\n\n browserWindow.setFullScreenable = function(fullscreenable) {\n browserWindow._setCollectionBehavior(\n fullscreenable,\n NSWindowCollectionBehaviorFullScreenPrimary\n )\n // On EL Capitan this flag is required to hide fullscreen button.\n browserWindow._setCollectionBehavior(\n !fullscreenable,\n NSWindowCollectionBehaviorFullScreenAuxiliary\n )\n }\n\n browserWindow.isFullScreenable = function() {\n var collectionBehavior = panel.collectionBehavior()\n return collectionBehavior & NSWindowCollectionBehaviorFullScreenPrimary\n }\n\n browserWindow.setClosable = function(closable) {\n browserWindow._setStyleMask(closable, NSClosableWindowMask)\n }\n\n browserWindow.isClosable = function() {\n return panel.styleMask() & NSClosableWindowMask\n }\n\n browserWindow.setAlwaysOnTop = function(top, level, relativeLevel) {\n var windowLevel = NSNormalWindowLevel\n var maxWindowLevel = CGWindowLevelForKey(kCGMaximumWindowLevelKey)\n var minWindowLevel = CGWindowLevelForKey(kCGMinimumWindowLevelKey)\n\n if (top) {\n if (level === 'normal') {\n windowLevel = NSNormalWindowLevel\n } else if (level === 'torn-off-menu') {\n windowLevel = NSTornOffMenuWindowLevel\n } else if (level === 'modal-panel') {\n windowLevel = NSModalPanelWindowLevel\n } else if (level === 'main-menu') {\n windowLevel = NSMainMenuWindowLevel\n } else if (level === 'status') {\n windowLevel = NSStatusWindowLevel\n } else if (level === 'pop-up-menu') {\n windowLevel = NSPopUpMenuWindowLevel\n } else if (level === 'screen-saver') {\n windowLevel = NSScreenSaverWindowLevel\n } else if (level === 'dock') {\n // Deprecated by macOS, but kept for backwards compatibility\n windowLevel = NSDockWindowLevel\n } else {\n windowLevel = NSFloatingWindowLevel\n }\n }\n\n var newLevel = windowLevel + (relativeLevel || 0)\n if (newLevel >= minWindowLevel && newLevel <= maxWindowLevel) {\n panel.setLevel(newLevel)\n } else {\n throw new Error(\n 'relativeLevel must be between ' +\n minWindowLevel +\n ' and ' +\n maxWindowLevel\n )\n }\n }\n\n browserWindow.isAlwaysOnTop = function() {\n return panel.level() !== NSNormalWindowLevel\n }\n\n browserWindow.moveTop = function() {\n return panel.orderFrontRegardless()\n }\n\n browserWindow.center = function() {\n panel.center()\n }\n\n browserWindow.setPosition = function(x, y, animate) {\n var bounds = browserWindow.getBounds()\n var mainScreenRect = NSScreen.screens()\n .firstObject()\n .frame()\n bounds.origin.x = x\n bounds.origin.y = Math.round(NSHeight(mainScreenRect) - y)\n\n return browserWindow.setBounds(bounds, animate)\n }\n\n browserWindow.getPosition = function() {\n var bounds = browserWindow.getBounds()\n var mainScreenRect = NSScreen.screens()\n .firstObject()\n .frame()\n return [\n bounds.origin.x,\n Math.round(NSHeight(mainScreenRect) - bounds.origin.y),\n ]\n }\n\n browserWindow.setTitle = function(title) {\n panel.setTitle(title)\n }\n\n browserWindow.getTitle = function() {\n return String(panel.title())\n }\n\n var attentionRequestId = 0\n browserWindow.flashFrame = function(flash) {\n if (flash) {\n attentionRequestId = NSApp.requestUserAttention(NSInformationalRequest)\n } else {\n NSApp.cancelUserAttentionRequest(attentionRequestId)\n attentionRequestId = 0\n }\n }\n\n browserWindow.getNativeWindowHandle = function() {\n return panel\n }\n\n browserWindow.getNativeWebViewHandle = function() {\n return webview\n }\n\n browserWindow.loadURL = function(url) {\n // When frameLocation is a file, prefix it with the Sketch Resources path\n if (/^(?!http|localhost|www|file).*\\.html?$/.test(url)) {\n if (typeof __command !== 'undefined' && __command.pluginBundle()) {\n url =\n 'file://' +\n __command\n .pluginBundle()\n .urlForResourceNamed(url)\n .path()\n }\n }\n\n if (/^file:\\/\\/.*\\.html?$/.test(url)) {\n webview.loadFileURL_allowingReadAccessToURL(\n NSURL.fileURLWithPath(url),\n NSURL.fileURLWithPath('file:///')\n )\n return\n }\n\n webview.loadRequest(NSURLRequest.requestWithURL(NSURL.URLWithString(url)))\n }\n\n browserWindow.reload = function() {\n webview.reload()\n }\n\n browserWindow.setHasShadow = function(hasShadow) {\n return panel.setHasShadow(hasShadow)\n }\n\n browserWindow.hasShadow = function() {\n return panel.hasShadow()\n }\n\n browserWindow.setOpacity = function(opacity) {\n return panel.setAlphaValue(opacity)\n }\n\n browserWindow.getOpacity = function() {\n return panel.alphaValue()\n }\n\n browserWindow.setVisibleOnAllWorkspaces = function(visible) {\n return browserWindow._setCollectionBehavior(\n visible,\n NSWindowCollectionBehaviorCanJoinAllSpaces\n )\n }\n\n browserWindow.isVisibleOnAllWorkspaces = function() {\n var collectionBehavior = panel.collectionBehavior()\n return collectionBehavior & NSWindowCollectionBehaviorCanJoinAllSpaces\n }\n\n browserWindow.setIgnoreMouseEvents = function(ignore) {\n return panel.setIgnoresMouseEvents(ignore)\n }\n\n browserWindow.setContentProtection = function(enable) {\n panel.setSharingType(enable ? NSWindowSharingNone : NSWindowSharingReadOnly)\n }\n\n browserWindow.setAutoHideCursor = function(autoHide) {\n panel.setDisableAutoHideCursor(autoHide)\n }\n\n browserWindow.setVibrancy = function(type) {\n var effectView = browserWindow._vibrantView\n\n if (!type) {\n if (effectView == null) {\n return\n }\n\n effectView.removeFromSuperview()\n panel.setVibrantView(null)\n return\n }\n\n if (effectView == null) {\n var contentView = panel.contentView()\n effectView = NSVisualEffectView.alloc().initWithFrame(\n contentView.bounds()\n )\n browserWindow._vibrantView = effectView\n\n effectView.setAutoresizingMask(NSViewWidthSizable | NSViewHeightSizable)\n effectView.setBlendingMode(NSVisualEffectBlendingModeBehindWindow)\n effectView.setState(NSVisualEffectStateActive)\n effectView.setFrame(contentView.bounds())\n contentView.addSubview_positioned_relativeTo(\n effectView,\n NSWindowBelow,\n null\n )\n }\n\n var vibrancyType = NSVisualEffectMaterialLight\n\n if (type === 'appearance-based') {\n vibrancyType = NSVisualEffectMaterialAppearanceBased\n } else if (type === 'light') {\n vibrancyType = NSVisualEffectMaterialLight\n } else if (type === 'dark') {\n vibrancyType = NSVisualEffectMaterialDark\n } else if (type === 'titlebar') {\n vibrancyType = NSVisualEffectMaterialTitlebar\n } else if (type === 'selection') {\n vibrancyType = NSVisualEffectMaterialSelection\n } else if (type === 'menu') {\n vibrancyType = NSVisualEffectMaterialMenu\n } else if (type === 'popover') {\n vibrancyType = NSVisualEffectMaterialPopover\n } else if (type === 'sidebar') {\n vibrancyType = NSVisualEffectMaterialSidebar\n } else if (type === 'medium-light') {\n vibrancyType = NSVisualEffectMaterialMediumLight\n } else if (type === 'ultra-dark') {\n vibrancyType = NSVisualEffectMaterialUltraDark\n }\n\n effectView.setMaterial(vibrancyType)\n }\n\n browserWindow._setBackgroundColor = function(colorName) {\n var color = parseHexColor(colorName)\n webview.isOpaque = false\n webview.setBackgroundColor(NSColor.clearColor())\n panel.backgroundColor = color\n }\n\n browserWindow._invalidate = function() {\n panel.flushWindow()\n panel.contentView().setNeedsDisplay(true)\n }\n\n browserWindow._setStyleMask = function(on, flag) {\n var wasMaximizable = browserWindow.isMaximizable()\n if (on) {\n panel.setStyleMask(panel.styleMask() | flag)\n } else {\n panel.setStyleMask(panel.styleMask() & ~flag)\n }\n // Change style mask will make the zoom button revert to default, probably\n // a bug of Cocoa or macOS.\n browserWindow.setMaximizable(wasMaximizable)\n }\n\n browserWindow._setCollectionBehavior = function(on, flag) {\n var wasMaximizable = browserWindow.isMaximizable()\n if (on) {\n panel.setCollectionBehavior(panel.collectionBehavior() | flag)\n } else {\n panel.setCollectionBehavior(panel.collectionBehavior() & ~flag)\n }\n // Change collectionBehavior will make the zoom button revert to default,\n // probably a bug of Cocoa or macOS.\n browserWindow.setMaximizable(wasMaximizable)\n }\n\n browserWindow._showWindowButton = function(button) {\n var view = panel.standardWindowButton(button)\n view.superview().addSubview_positioned_relative(view, NSWindowAbove, null)\n }\n}\n","module.exports = {\n JS_BRIDGE: '__skpm_sketchBridge',\n}\n","var tagsToFocus =\n '[\"text\", \"textarea\", \"date\", \"datetime-local\", \"email\", \"number\", \"month\", \"password\", \"search\", \"tel\", \"time\", \"url\", \"week\" ]'\n\nmodule.exports = function(webView, event) {\n var point = webView.convertPoint_fromView(event.locationInWindow(), null)\n var x = point.x\n var y = webView.frame().size.height - point.y // the coord start from the bottom instead of the top\n return (\n 'var el = document.elementFromPoint(' + // get the DOM element that match the event\n x +\n ', ' +\n y +\n '); ' +\n 'if (el && ' + // some tags need to be focused instead of clicked\n tagsToFocus +\n '.indexOf(el.type) >= 0 && ' +\n 'el.focus' +\n ') {' +\n 'el.focus();' + // so focus them\n '} else if (el) {' +\n 'el.dispatchEvent(new Event(\"click\", {bubbles: true}))' + // click the others\n '}'\n )\n}\n","function addEdgeConstraint(edge, subview, view, constant) {\n view.addConstraint(\n NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant(\n subview,\n edge,\n NSLayoutRelationEqual,\n view,\n edge,\n 1,\n constant\n )\n )\n}\nmodule.exports = function fitSubviewToView(subview, view, constants) {\n constants = constants || []\n subview.setTranslatesAutoresizingMaskIntoConstraints(false)\n\n addEdgeConstraint(NSLayoutAttributeLeft, subview, view, constants[0] || 0)\n addEdgeConstraint(NSLayoutAttributeTop, subview, view, constants[1] || 0)\n addEdgeConstraint(NSLayoutAttributeRight, subview, view, constants[2] || 0)\n addEdgeConstraint(NSLayoutAttributeBottom, subview, view, constants[3] || 0)\n}\n","/* let's try to match the API from Electron's Browser window\n(https://github.com/electron/electron/blob/master/docs/api/browser-window.md) */\nvar EventEmitter = require('events')\nvar buildBrowserAPI = require('./browser-api')\nvar buildWebAPI = require('./webview-api')\nvar fitSubviewToView = require('./fitSubview')\nvar dispatchFirstClick = require('./dispatch-first-click')\nvar injectClientMessaging = require('./inject-client-messaging')\nvar setDelegates = require('./set-delegates')\n\nfunction BrowserWindow(options) {\n options = options || {}\n\n var identifier = options.identifier || NSUUID.UUID().UUIDString()\n var threadDictionary = NSThread.mainThread().threadDictionary()\n\n var existingBrowserWindow = BrowserWindow.fromId(identifier)\n\n // if we already have a window opened, reuse it\n if (existingBrowserWindow) {\n return existingBrowserWindow\n }\n\n var browserWindow = new EventEmitter()\n browserWindow.id = identifier\n\n if (options.modal && !options.parent) {\n throw new Error('A modal needs to have a parent.')\n }\n\n // Long-running script\n var fiber = coscript.createFiber()\n\n // Window size\n var width = options.width || 800\n var height = options.height || 600\n var mainScreenRect = NSScreen.screens()\n .firstObject()\n .frame()\n var cocoaBounds = NSMakeRect(\n typeof options.x !== 'undefined'\n ? options.x\n : Math.round((NSWidth(mainScreenRect) - width) / 2),\n typeof options.y !== 'undefined'\n ? options.y\n : Math.round((NSHeight(mainScreenRect) - height) / 2),\n width,\n height\n )\n\n if (options.titleBarStyle && options.titleBarStyle !== 'default') {\n options.frame = false\n }\n\n var useStandardWindow = options.windowType !== 'textured'\n var styleMask = NSTitledWindowMask\n\n // this is commented out because the toolbar doesn't appear otherwise :thinking-face:\n // if (!useStandardWindow || options.frame === false) {\n // styleMask = NSFullSizeContentViewWindowMask\n // }\n if (options.minimizable !== false) {\n styleMask |= NSMiniaturizableWindowMask\n }\n if (options.closable !== false) {\n styleMask |= NSClosableWindowMask\n }\n if (options.resizable !== false) {\n styleMask |= NSResizableWindowMask\n }\n if (!useStandardWindow || options.transparent || options.frame === false) {\n styleMask |= NSTexturedBackgroundWindowMask\n }\n\n var panel = NSPanel.alloc().initWithContentRect_styleMask_backing_defer(\n cocoaBounds,\n styleMask,\n NSBackingStoreBuffered,\n true\n )\n\n var wkwebviewConfig = WKWebViewConfiguration.alloc().init()\n var webView = WKWebView.alloc().initWithFrame_configuration(\n CGRectMake(0, 0, options.width || 800, options.height || 600),\n wkwebviewConfig\n )\n injectClientMessaging(webView)\n webView.setAutoresizingMask(NSViewWidthSizable | NSViewHeightSizable)\n\n buildBrowserAPI(browserWindow, panel, webView)\n buildWebAPI(browserWindow, panel, webView)\n setDelegates(browserWindow, panel, webView, options)\n\n if (options.windowType === 'desktop') {\n panel.setLevel(kCGDesktopWindowLevel - 1)\n // panel.setCanBecomeKeyWindow(false)\n panel.setCollectionBehavior(\n NSWindowCollectionBehaviorCanJoinAllSpaces |\n NSWindowCollectionBehaviorStationary |\n NSWindowCollectionBehaviorIgnoresCycle\n )\n }\n\n if (\n typeof options.minWidth !== 'undefined' ||\n typeof options.minHeight !== 'undefined'\n ) {\n browserWindow.setMinimumSize(options.minWidth || 0, options.minHeight || 0)\n }\n\n if (\n typeof options.maxWidth !== 'undefined' ||\n typeof options.maxHeight !== 'undefined'\n ) {\n browserWindow.setMaximumSize(\n options.maxWidth || 10000,\n options.maxHeight || 10000\n )\n }\n\n // if (options.focusable === false) {\n // panel.setCanBecomeKeyWindow(false)\n // }\n\n if (options.transparent || options.frame === false) {\n panel.titlebarAppearsTransparent = true\n panel.titleVisibility = NSWindowTitleHidden\n panel.setOpaque(0)\n panel.isMovableByWindowBackground = true\n var toolbar2 = NSToolbar.alloc().initWithIdentifier(\n 'titlebarStylingToolbar'\n )\n toolbar2.setShowsBaselineSeparator(false)\n panel.setToolbar(toolbar2)\n }\n\n if (options.titleBarStyle === 'hiddenInset') {\n var toolbar = NSToolbar.alloc().initWithIdentifier('titlebarStylingToolbar')\n toolbar.setShowsBaselineSeparator(false)\n panel.setToolbar(toolbar)\n }\n\n if (options.frame === false || !options.useContentSize) {\n browserWindow.setSize(width, height)\n }\n\n if (options.center) {\n browserWindow.center()\n }\n\n if (options.alwaysOnTop) {\n browserWindow.setAlwaysOnTop(true)\n }\n\n if (options.fullscreen) {\n browserWindow.setFullScreen(true)\n }\n browserWindow.setFullScreenable(!!options.fullscreenable)\n\n const title =\n options.title ||\n (typeof __command !== 'undefined' && __command.pluginBundle()\n ? __command.pluginBundle().name()\n : undefined)\n if (title) {\n browserWindow.setTitle(title)\n }\n\n var backgroundColor = options.backgroundColor\n if (options.transparent) {\n backgroundColor = NSColor.clearColor()\n }\n if (!backgroundColor && options.frame === false && options.vibrancy) {\n backgroundColor = NSColor.clearColor()\n }\n\n browserWindow._setBackgroundColor(\n backgroundColor || NSColor.windowBackgroundColor()\n )\n\n if (options.hasShadow === false) {\n browserWindow.setHasShadow(false)\n }\n\n if (typeof options.opacity !== 'undefined') {\n browserWindow.setOpacity(options.opacity)\n }\n\n options.webPreferences = options.webPreferences || {}\n\n webView\n .configuration()\n .preferences()\n .setValue_forKey(\n options.webPreferences.devTools !== false,\n 'developerExtrasEnabled'\n )\n webView\n .configuration()\n .preferences()\n .setValue_forKey(\n options.webPreferences.devTools !== false,\n 'javaScriptEnabled'\n )\n webView\n .configuration()\n .preferences()\n .setValue_forKey(!!options.webPreferences.plugins, 'plugInsEnabled')\n webView\n .configuration()\n .preferences()\n .setValue_forKey(\n options.webPreferences.minimumFontSize || 0,\n 'minimumFontSize'\n )\n\n if (options.webPreferences.zoomFactor) {\n webView.setMagnification(options.webPreferences.zoomFactor)\n }\n\n var contentView = panel.contentView()\n\n if (options.frame !== false) {\n webView.setFrame(contentView.bounds())\n contentView.addSubview(webView)\n } else {\n // In OSX 10.10, adding subviews to the root view for the NSView hierarchy\n // produces warnings. To eliminate the warnings, we resize the contentView\n // to fill the window, and add subviews to that.\n // http://crbug.com/380412\n contentView.setAutoresizingMask(NSViewWidthSizable | NSViewHeightSizable)\n fitSubviewToView(contentView, contentView.superview())\n\n webView.setFrame(contentView.bounds())\n contentView.addSubview(webView)\n\n // The fullscreen button should always be hidden for frameless window.\n if (panel.standardWindowButton(NSWindowFullScreenButton)) {\n panel.standardWindowButton(NSWindowFullScreenButton).setHidden(true)\n }\n\n if (!options.titleBarStyle || options.titleBarStyle === 'default') {\n // Hide the window buttons.\n panel.standardWindowButton(NSWindowZoomButton).setHidden(true)\n panel.standardWindowButton(NSWindowMiniaturizeButton).setHidden(true)\n panel.standardWindowButton(NSWindowCloseButton).setHidden(true)\n\n // Some third-party macOS utilities check the zoom button's enabled state to\n // determine whether to show custom UI on hover, so we disable it here to\n // prevent them from doing so in a frameless app window.\n panel.standardWindowButton(NSWindowZoomButton).setEnabled(false)\n }\n }\n\n if (options.vibrancy) {\n browserWindow.setVibrancy(options.vibrancy)\n }\n\n // Set maximizable state last to ensure zoom button does not get reset\n // by calls to other APIs.\n browserWindow.setMaximizable(options.maximizable !== false)\n\n if (options.acceptsFirstMouse) {\n browserWindow.on('focus', function(event) {\n if (event.type() === NSEventTypeLeftMouseDown) {\n browserWindow.webContents\n .executeJavaScript(dispatchFirstClick(webView, event))\n .catch(() => {})\n }\n })\n }\n\n if (options.show !== false) {\n browserWindow.show()\n }\n\n browserWindow.on('closed', function() {\n browserWindow._destroyed = true\n threadDictionary.removeObjectForKey(identifier)\n fiber.cleanup()\n })\n\n threadDictionary[identifier] = panel\n\n fiber.onCleanup(function() {\n if (!browserWindow._destroyed) {\n browserWindow.destroy()\n }\n })\n\n return browserWindow\n}\n\nBrowserWindow.fromId = function(identifier) {\n var threadDictionary = NSThread.mainThread().threadDictionary()\n\n if (threadDictionary[identifier]) {\n return BrowserWindow.fromPanel(threadDictionary[identifier], identifier)\n }\n\n return undefined\n}\n\nBrowserWindow.fromPanel = function(panel, identifier) {\n var browserWindow = new EventEmitter()\n browserWindow.id = identifier\n\n if (!panel || !panel.contentView) {\n throw new Error('needs to pass an NSPanel')\n }\n\n var webView = panel.contentView().subviews()[0]\n\n if (!webView) {\n throw new Error('The NSPanel needs to have a webview')\n }\n\n buildBrowserAPI(browserWindow, panel, webView)\n buildWebAPI(browserWindow, panel, webView)\n\n return browserWindow\n}\n\nmodule.exports = BrowserWindow\n","var CONSTANTS = require('./constants')\n\nmodule.exports = function(webView) {\n var source =\n 'window.originalPostMessage = window.postMessage;' +\n 'window.postMessage = function(actionName) {' +\n 'if (!actionName) {' +\n \"throw new Error('missing action name')\" +\n '}' +\n 'window.webkit.messageHandlers.' +\n CONSTANTS.JS_BRIDGE +\n '.postMessage(' +\n 'JSON.stringify([].slice.call(arguments))' +\n ');' +\n '}'\n var script = WKUserScript.alloc().initWithSource_injectionTime_forMainFrameOnly(\n source,\n 0,\n true\n )\n webView\n .configuration()\n .userContentController()\n .addUserScript(script)\n}\n","module.exports = function(webArguments) {\n var args = null\n try {\n args = JSON.parse(webArguments[0])\n } catch (e) {\n // malformed arguments\n }\n\n if (\n !args ||\n !args.constructor ||\n args.constructor !== Array ||\n args.length == 0\n ) {\n return null\n }\n\n return args\n}\n","var ObjCClass = require('cocoascript-class').default\nvar parseWebArguments = require('./parseWebArguments')\nvar CONSTANTS = require('./constants')\n\n// We create one ObjC class for ourselves here\nvar WindowDelegateClass\nvar NavigationDelegateClass\nvar WebScriptHandlerClass\n\n// TODO: events\n// - 'page-favicon-updated'\n// - 'new-window'\n// - 'did-navigate-in-page'\n// - 'will-prevent-unload'\n// - 'crashed'\n// - 'unresponsive'\n// - 'responsive'\n// - 'destroyed'\n// - 'before-input-event'\n// - 'certificate-error'\n// - 'found-in-page'\n// - 'media-started-playing'\n// - 'media-paused'\n// - 'did-change-theme-color'\n// - 'update-target-url'\n// - 'cursor-changed'\n// - 'context-menu'\n// - 'select-bluetooth-device'\n// - 'paint'\n// - 'console-message'\n\nmodule.exports = function(browserWindow, panel, webview, options) {\n if (!WindowDelegateClass) {\n WindowDelegateClass = ObjCClass({\n classname: 'WindowDelegateClass',\n utils: null,\n panel: null,\n\n 'windowDidResize:': function() {\n this.utils.emit('resize')\n },\n\n 'windowDidMiniaturize:': function() {\n this.utils.emit('minimize')\n },\n\n 'windowDidDeminiaturize:': function() {\n this.utils.emit('restore')\n },\n\n 'windowDidEnterFullScreen:': function() {\n this.utils.emit('enter-full-screen')\n },\n\n 'windowDidExitFullScreen:': function() {\n this.utils.emit('leave-full-screen')\n },\n\n 'windowDidMove:': function() {\n this.utils.emit('move')\n this.utils.emit('moved')\n },\n\n 'windowShouldClose:': function() {\n var shouldClose = true\n this.utils.emit('close', {\n get defaultPrevented() {\n return !shouldClose\n },\n preventDefault: function() {\n shouldClose = false\n },\n })\n return shouldClose\n },\n\n 'windowWillClose:': function() {\n this.utils.emit('closed')\n },\n\n 'windowDidBecomeKey:': function() {\n this.utils.emit('focus', this.panel.currentEvent())\n },\n\n 'windowDidResignKey:': function() {\n this.utils.emit('blur')\n },\n })\n }\n\n if (!NavigationDelegateClass) {\n NavigationDelegateClass = ObjCClass({\n classname: 'NavigationDelegateClass',\n state: NSMutableDictionary.dictionaryWithDictionary({\n wasReady: 0,\n }),\n utils: null,\n\n // // Called when the web view begins to receive web content.\n 'webView:didCommitNavigation:': function(webView) {\n this.utils.emit('will-navigate', {}, String(String(webView.url())))\n },\n\n // // Called when web content begins to load in a web view.\n 'webView:didStartProvisionalNavigation:': function() {\n this.utils.emit('did-start-navigation')\n this.utils.emit('did-start-loading')\n },\n\n // Called when a web view receives a server redirect.\n 'webView:didReceiveServerRedirectForProvisionalNavigation:': function() {\n this.utils.emit('did-get-redirect-request')\n },\n\n // // Called when the web view needs to respond to an authentication challenge.\n 'webView:didReceiveAuthenticationChallenge:completionHandler:': function(\n webView,\n challenge,\n completionHandler\n ) {\n function callback(username, password) {\n completionHandler(\n 0,\n NSURLCredential.credentialWithUser_password_persistence(\n username,\n password,\n 1\n )\n )\n }\n var protectionSpace = challenge.protectionSpace()\n this.utils.emit(\n 'login',\n {},\n {\n method: String(protectionSpace.authenticationMethod()),\n url: 'not implemented', // TODO:\n referrer: 'not implemented', // TODO:\n },\n {\n isProxy: !!protectionSpace.isProxy(),\n scheme: String(protectionSpace.protocol()),\n host: String(protectionSpace.host()),\n port: Number(protectionSpace.port()),\n realm: String(protectionSpace.realm()),\n },\n callback\n )\n },\n\n // Called when an error occurs during navigation.\n // 'webView:didFailNavigation:withError:': function(\n // webView,\n // navigation,\n // error\n // ) {},\n\n // Called when an error occurs while the web view is loading content.\n 'webView:didFailProvisionalNavigation:withError:': function(\n webView,\n navigation,\n error\n ) {\n this.utils.emit('did-fail-load', error)\n },\n\n // Called when the navigation is complete.\n 'webView:didFinishNavigation:': function() {\n if (this.state.wasReady == 0) {\n // eslint-disable-line\n this.utils.emitBrowserEvent('ready-to-show')\n this.state.setObject_forKey(1, 'wasReady')\n }\n this.utils.emit('did-navigate')\n this.utils.emit('did-frame-navigate')\n this.utils.emit('did-stop-loading')\n this.utils.emit('did-finish-load')\n this.utils.emit('did-frame-finish-load')\n },\n\n // Called when the web view’s web content process is terminated.\n 'webViewWebContentProcessDidTerminate:': function() {\n this.utils.emit('dom-ready')\n },\n\n // Decides whether to allow or cancel a navigation.\n // webView:decidePolicyForNavigationAction:decisionHandler:\n\n // Decides whether to allow or cancel a navigation after its response is known.\n // webView:decidePolicyForNavigationResponse:decisionHandler:\n })\n }\n\n if (!WebScriptHandlerClass) {\n WebScriptHandlerClass = ObjCClass({\n classname: 'WebScriptHandlerClass',\n utils: null,\n 'userContentController:didReceiveScriptMessage:': function(_, message) {\n var webArguments = JSON.parse(String(message.body()))\n var args = this.utils.parseWebArguments([JSON.stringify(webArguments)])\n if (!args) {\n return\n }\n\n this.utils.emit.apply(this, args)\n },\n })\n }\n\n var navigationDelegate = NavigationDelegateClass.new()\n navigationDelegate.utils = NSDictionary.dictionaryWithDictionary({\n setTitle: browserWindow.setTitle.bind(browserWindow),\n emitBrowserEvent: browserWindow.emit.bind(browserWindow),\n emit: browserWindow.webContents.emit.bind(browserWindow.webContents),\n })\n // reset state as well\n navigationDelegate.state = NSMutableDictionary.dictionaryWithDictionary({\n wasReady: 0,\n })\n\n webview.setNavigationDelegate(navigationDelegate)\n\n var webScriptHandler = WebScriptHandlerClass.new()\n webScriptHandler.utils = NSDictionary.dictionaryWithDictionary({\n emit: browserWindow.webContents.emit.bind(browserWindow.webContents),\n parseWebArguments: parseWebArguments,\n })\n\n webview\n .configuration()\n .userContentController()\n .addScriptMessageHandler_name(webScriptHandler, CONSTANTS.JS_BRIDGE)\n\n var windowDelegate = WindowDelegateClass.new()\n var utils = {\n emit: browserWindow.emit.bind(browserWindow),\n }\n if (options.modal) {\n // find the window of the document\n var msdocument\n if (options.parent.type === 'Document') {\n msdocument = options.parent.sketchObject\n if (msdocument && String(msdocument.class()) === 'MSDocumentData') {\n // we only have an MSDocumentData instead of a MSDocument\n // let's try to get back to the MSDocument\n msdocument = msdocument.delegate()\n }\n } else {\n msdocument = options.parent\n }\n if (msdocument && String(msdocument.class()) === 'MSDocumentData') {\n // we only have an MSDocumentData instead of a MSDocument\n // let's try to get back to the MSDocument\n msdocument = msdocument.delegate()\n }\n utils.parentWindow = msdocument.windowForSheet()\n }\n\n windowDelegate.utils = NSDictionary.dictionaryWithDictionary(utils)\n windowDelegate.panel = panel\n\n panel.setDelegate(windowDelegate)\n}\n","var EventEmitter = require('events')\n\n// let's try to match https://github.com/electron/electron/blob/master/docs/api/web-contents.md\nmodule.exports = function buildAPI(browserWindow, panel, webview) {\n var webContents = new EventEmitter()\n\n webContents.loadURL = browserWindow.loadURL\n\n webContents.loadFile = function(/* filePath */) {\n // TODO:\n console.warn(\n 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)'\n )\n }\n\n webContents.downloadURL = function(/* filePath */) {\n // TODO:\n console.warn(\n 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)'\n )\n }\n\n webContents.getURL = function() {\n return String(webview.url())\n }\n\n webContents.getTitle = function() {\n return String(webview.title())\n }\n\n webContents.isDestroyed = function() {\n // TODO:\n console.warn(\n 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)'\n )\n }\n\n webContents.focus = browserWindow.focus\n webContents.isFocused = browserWindow.isFocused\n\n webContents.isLoading = function() {\n return !!webview.loading()\n }\n\n webContents.isLoadingMainFrame = function() {\n // TODO:\n return !!webview.loading()\n }\n\n webContents.isWaitingForResponse = function() {\n return !webview.loading()\n }\n\n webContents.stop = function() {\n webview.stopLoading()\n }\n webContents.reload = function() {\n webview.reload()\n }\n webContents.reloadIgnoringCache = function() {\n webview.reloadFromOrigin()\n }\n webContents.canGoBack = function() {\n return !!webview.canGoBack()\n }\n webContents.canGoForward = function() {\n return !!webview.canGoForward()\n }\n webContents.canGoToOffset = function(offset) {\n return !!webview.backForwardList().itemAtIndex(offset)\n }\n webContents.clearHistory = function() {\n // TODO:\n console.warn(\n 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)'\n )\n }\n webContents.goBack = function() {\n webview.goBack()\n }\n webContents.goForward = function() {\n webview.goForward()\n }\n webContents.goToIndex = function(index) {\n var backForwardList = webview.backForwardList()\n var backList = backForwardList.backList()\n var backListLength = backList.count()\n if (backListLength > index) {\n webview.loadRequest(NSURLRequest.requestWithURL(backList[index]))\n return\n }\n var forwardList = backForwardList.forwardList()\n if (forwardList.count() > index - backListLength) {\n webview.loadRequest(\n NSURLRequest.requestWithURL(forwardList[index - backListLength])\n )\n return\n }\n throw new Error('Cannot go to index ' + index)\n }\n webContents.goToOffset = function(offset) {\n if (!webContents.canGoToOffset(offset)) {\n throw new Error('Cannot go to offset ' + offset)\n }\n webview.loadRequest(\n NSURLRequest.requestWithURL(webview.backForwardList().itemAtIndex(offset))\n )\n }\n webContents.isCrashed = function() {\n // TODO:\n console.warn(\n 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)'\n )\n }\n webContents.setUserAgent = function(/* userAgent */) {\n // TODO:\n console.warn(\n 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)'\n )\n }\n webContents.getUserAgent = function() {\n const userAgent = webview.customUserAgent()\n return userAgent ? String(userAgent) : undefined\n }\n webContents.insertCSS = function(css) {\n var source =\n \"var style = document.createElement('style'); style.innerHTML = \" +\n css.replace(/\"/, '\\\\\"') +\n '; document.head.appendChild(style);'\n var script = WKUserScript.alloc().initWithSource_injectionTime_forMainFrameOnly(\n source,\n 0,\n true\n )\n webview\n .configuration()\n .userContentController()\n .addUserScript(script)\n }\n webContents.insertJS = function(source) {\n var script = WKUserScript.alloc().initWithSource_injectionTime_forMainFrameOnly(\n source,\n 0,\n true\n )\n webview\n .configuration()\n .userContentController()\n .addUserScript(script)\n }\n webContents.executeJavaScript = function(script, userGesture, callback) {\n if (typeof userGesture === 'function') {\n callback = userGesture\n userGesture = false\n }\n var fiber = coscript.createFiber()\n return new Promise(function(resolve, reject) {\n webview.evaluateJavaScript_completionHandler(\n script,\n __mocha__.createBlock_function('v28@?0@8c16@\"NSError\"20', function(\n result,\n err\n ) {\n var isError =\n err &&\n err.class &&\n (String(err.class()) === 'NSException' ||\n String(err.class()) === 'NSError')\n if (callback) {\n try {\n callback(isError ? err : null, result)\n } catch (error) {\n // /shrug\n }\n resolve()\n } else if (isError) {\n reject(err)\n } else {\n resolve(result)\n }\n fiber.cleanup()\n })\n )\n })\n }\n webContents.setIgnoreMenuShortcuts = function() {\n // TODO:??\n console.warn(\n 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)'\n )\n }\n webContents.setAudioMuted = function(/* muted */) {\n // TODO:??\n console.warn(\n 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)'\n )\n }\n webContents.isAudioMuted = function() {\n // TODO:??\n console.warn(\n 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)'\n )\n }\n webContents.setZoomFactor = function(factor) {\n webview.setMagnification_centeredAtPoint(factor, CGPointMake(0, 0))\n }\n webContents.getZoomFactor = function(callback) {\n callback(Number(webview.magnification()))\n }\n webContents.setZoomLevel = function(level) {\n // eslint-disable-next-line no-restricted-properties\n webContents.setZoomFactor(Math.pow(1.2, level))\n }\n webContents.getZoomLevel = function(callback) {\n // eslint-disable-next-line no-restricted-properties\n callback(Math.log(Number(webview.magnification())) / Math.log(1.2))\n }\n webContents.setVisualZoomLevelLimits = function(/* minimumLevel, maximumLevel */) {\n // TODO:??\n console.warn(\n 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)'\n )\n }\n webContents.setLayoutZoomLevelLimits = function(/* minimumLevel, maximumLevel */) {\n // TODO:??\n console.warn(\n 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)'\n )\n }\n\n // TODO:\n // webContents.undo = function() {\n // webview.undoManager().undo()\n // }\n // webContents.redo = function() {\n // webview.undoManager().redo()\n // }\n // webContents.cut = webview.cut\n // webContents.copy = webview.copy\n // webContents.paste = webview.paste\n // webContents.pasteAndMatchStyle = webview.pasteAsRichText\n // webContents.delete = webview.delete\n // webContents.replace = webview.replaceSelectionWithText\n\n webContents.send = function() {\n const script =\n 'window.postMessage({' +\n 'isSketchMessage: true,' +\n \"origin: '\" +\n String(__command.identifier()) +\n \"',\" +\n 'args: ' +\n JSON.stringify([].slice.call(arguments)) +\n '}, \"*\")'\n webview.evaluateJavaScript_completionHandler(script, null)\n }\n\n webContents.getNativeWebview = function() {\n return webview\n }\n\n browserWindow.webContents = webContents\n}\n","import BrowserWindow from 'sketch-module-web-view'\nimport {GradientMaker} from './gradient'\n\nexport default function () {\n \n //Global Setup\n const options = {\n backgroundColor: '#FFFFFF',\n identifier: 'coolhue.id',\n width: 215,\n height: 450,\n resizable: false,\n movable: true,\n alwaysOnTop: true,\n minimizable: true,\n maximizable: false,\n title: \"CoolHue 2.0\",\n vibrancy: \"appearance-based\",\n }\n const browserWindow = new BrowserWindow(options)\n browserWindow.isAlwaysOnTop()\n browserWindow.loadURL(require('./view.html'))\n browserWindow.webContents.on('nativeGradientApplier', function (fetchedData) {\n GradientMaker(fetchedData.firstColor,fetchedData.secondColor);\n })\n}","import sketch from 'sketch'\nimport UI from 'sketch/ui'\nvar Style = require('sketch/dom').Style\n\nexport function GradientMaker(firstStop, secondStop) {\n var doc = sketch.getSelectedDocument()\n var selectedLayers = doc.selectedLayers\n if (selectedLayers.length != null && selectedLayers.length != 0) {\n \n selectedLayers.forEach(layer => {\n if (layer.type === \"Shape\" || layer.type === \"ShapePath\") {\n layer.style.fills = [{\n fillType: Style.FillType.Gradient,\n fill: 'Gradient',\n gradient: {\n gradientType: Style.GradientType.Linear,\n from: {\n x: 0,\n y: 0,\n },\n to: {\n x: 1,\n y: 1,\n },\n stops: [{\n position: 0,\n color: firstStop,\n },\n {\n position: 1,\n color: secondStop,\n },\n ],\n }\n } ]\n } else {\n UI.message(`🔔 CoolHue can apply gradients on Shape Layer(s) only`)\n }\n })\n } else {\n UI.message(`🛑 Select Shape Layer(s) to apply CoolHue Gradients`)\n }\n}","module.exports = \"file://\" + context.plugin.urlForResourceNamed(\"_webpack_resources/3ff137287832113452bf2ab1649999f2.html\").path();","module.exports = require(\"events\");","module.exports = require(\"sketch\");","module.exports = require(\"sketch/dom\");","module.exports = require(\"sketch/ui\");"],"sourceRoot":""} -------------------------------------------------------------------------------- /distro/CoolHue.sketchplugin/Contents/Sketch/coolhue.js: -------------------------------------------------------------------------------- 1 | var that = this; 2 | function __skpm_run (key, context) { 3 | that.context = context; 4 | 5 | var exports = 6 | /******/ (function(modules) { // webpackBootstrap 7 | /******/ // The module cache 8 | /******/ var installedModules = {}; 9 | /******/ 10 | /******/ // The require function 11 | /******/ function __webpack_require__(moduleId) { 12 | /******/ 13 | /******/ // Check if module is in cache 14 | /******/ if(installedModules[moduleId]) { 15 | /******/ return installedModules[moduleId].exports; 16 | /******/ } 17 | /******/ // Create a new module (and put it into the cache) 18 | /******/ var module = installedModules[moduleId] = { 19 | /******/ i: moduleId, 20 | /******/ l: false, 21 | /******/ exports: {} 22 | /******/ }; 23 | /******/ 24 | /******/ // Execute the module function 25 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 26 | /******/ 27 | /******/ // Flag the module as loaded 28 | /******/ module.l = true; 29 | /******/ 30 | /******/ // Return the exports of the module 31 | /******/ return module.exports; 32 | /******/ } 33 | /******/ 34 | /******/ 35 | /******/ // expose the modules object (__webpack_modules__) 36 | /******/ __webpack_require__.m = modules; 37 | /******/ 38 | /******/ // expose the module cache 39 | /******/ __webpack_require__.c = installedModules; 40 | /******/ 41 | /******/ // define getter function for harmony exports 42 | /******/ __webpack_require__.d = function(exports, name, getter) { 43 | /******/ if(!__webpack_require__.o(exports, name)) { 44 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 45 | /******/ } 46 | /******/ }; 47 | /******/ 48 | /******/ // define __esModule on exports 49 | /******/ __webpack_require__.r = function(exports) { 50 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 51 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 52 | /******/ } 53 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 54 | /******/ }; 55 | /******/ 56 | /******/ // create a fake namespace object 57 | /******/ // mode & 1: value is a module id, require it 58 | /******/ // mode & 2: merge all properties of value into the ns 59 | /******/ // mode & 4: return value when already ns object 60 | /******/ // mode & 8|1: behave like require 61 | /******/ __webpack_require__.t = function(value, mode) { 62 | /******/ if(mode & 1) value = __webpack_require__(value); 63 | /******/ if(mode & 8) return value; 64 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 65 | /******/ var ns = Object.create(null); 66 | /******/ __webpack_require__.r(ns); 67 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 68 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 69 | /******/ return ns; 70 | /******/ }; 71 | /******/ 72 | /******/ // getDefaultExport function for compatibility with non-harmony modules 73 | /******/ __webpack_require__.n = function(module) { 74 | /******/ var getter = module && module.__esModule ? 75 | /******/ function getDefault() { return module['default']; } : 76 | /******/ function getModuleExports() { return module; }; 77 | /******/ __webpack_require__.d(getter, 'a', getter); 78 | /******/ return getter; 79 | /******/ }; 80 | /******/ 81 | /******/ // Object.prototype.hasOwnProperty.call 82 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 83 | /******/ 84 | /******/ // __webpack_public_path__ 85 | /******/ __webpack_require__.p = ""; 86 | /******/ 87 | /******/ 88 | /******/ // Load entry module and return exports 89 | /******/ return __webpack_require__(__webpack_require__.s = "./src/coolhue.js"); 90 | /******/ }) 91 | /************************************************************************/ 92 | /******/ ({ 93 | 94 | /***/ "./node_modules/@skpm/timers/immediate.js": 95 | /*!************************************************!*\ 96 | !*** ./node_modules/@skpm/timers/immediate.js ***! 97 | \************************************************/ 98 | /*! no static exports found */ 99 | /***/ (function(module, exports, __webpack_require__) { 100 | 101 | /* globals coscript, sketch */ 102 | var timeout = __webpack_require__(/*! ./timeout */ "./node_modules/@skpm/timers/timeout.js") 103 | 104 | function setImmediate(func, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) { 105 | return timeout.setTimeout(func, 0, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) 106 | } 107 | 108 | function clearImmediate(id) { 109 | return timeout.clearTimeout(id) 110 | } 111 | 112 | module.exports = { 113 | setImmediate: setImmediate, 114 | clearImmediate: clearImmediate 115 | } 116 | 117 | 118 | /***/ }), 119 | 120 | /***/ "./node_modules/@skpm/timers/test-if-fiber.js": 121 | /*!****************************************************!*\ 122 | !*** ./node_modules/@skpm/timers/test-if-fiber.js ***! 123 | \****************************************************/ 124 | /*! no static exports found */ 125 | /***/ (function(module, exports) { 126 | 127 | module.exports = function () { 128 | return typeof coscript !== 'undefined' && coscript.createFiber 129 | } 130 | 131 | 132 | /***/ }), 133 | 134 | /***/ "./node_modules/@skpm/timers/timeout.js": 135 | /*!**********************************************!*\ 136 | !*** ./node_modules/@skpm/timers/timeout.js ***! 137 | \**********************************************/ 138 | /*! no static exports found */ 139 | /***/ (function(module, exports, __webpack_require__) { 140 | 141 | /* globals coscript, sketch */ 142 | var fiberAvailable = __webpack_require__(/*! ./test-if-fiber */ "./node_modules/@skpm/timers/test-if-fiber.js") 143 | 144 | var setTimeout 145 | var clearTimeout 146 | 147 | var fibers = [] 148 | 149 | if (fiberAvailable()) { 150 | var fibers = [] 151 | 152 | setTimeout = function (func, delay, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) { 153 | // fibers takes care of keeping coscript around 154 | var id = fibers.length 155 | fibers.push(coscript.scheduleWithInterval_jsFunction( 156 | (delay || 0) / 1000, 157 | function () { 158 | func(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) 159 | } 160 | )) 161 | return id 162 | } 163 | 164 | clearTimeout = function (id) { 165 | var timeout = fibers[id] 166 | if (timeout) { 167 | timeout.cancel() // fibers takes care of keeping coscript around 168 | fibers[id] = undefined // garbage collect the fiber 169 | } 170 | } 171 | } else { 172 | setTimeout = function (func, delay, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) { 173 | coscript.shouldKeepAround = true 174 | var id = fibers.length 175 | fibers.push(true) 176 | coscript.scheduleWithInterval_jsFunction( 177 | (delay || 0) / 1000, 178 | function () { 179 | if (fibers[id]) { // if not cleared 180 | func(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) 181 | } 182 | clearTimeout(id) 183 | if (fibers.every(function (_id) { return !_id })) { // if everything is cleared 184 | coscript.shouldKeepAround = false 185 | } 186 | } 187 | ) 188 | return id 189 | } 190 | 191 | clearTimeout = function (id) { 192 | fibers[id] = false 193 | } 194 | } 195 | 196 | module.exports = { 197 | setTimeout: setTimeout, 198 | clearTimeout: clearTimeout 199 | } 200 | 201 | 202 | /***/ }), 203 | 204 | /***/ "./node_modules/cocoascript-class/lib/index.js": 205 | /*!*****************************************************!*\ 206 | !*** ./node_modules/cocoascript-class/lib/index.js ***! 207 | \*****************************************************/ 208 | /*! no static exports found */ 209 | /***/ (function(module, exports, __webpack_require__) { 210 | 211 | "use strict"; 212 | 213 | 214 | Object.defineProperty(exports, "__esModule", { 215 | value: true 216 | }); 217 | exports.SuperCall = undefined; 218 | exports.default = ObjCClass; 219 | 220 | var _runtime = __webpack_require__(/*! ./runtime.js */ "./node_modules/cocoascript-class/lib/runtime.js"); 221 | 222 | exports.SuperCall = _runtime.SuperCall; 223 | 224 | // super when returnType is id and args are void 225 | // id objc_msgSendSuper(struct objc_super *super, SEL op, void) 226 | 227 | const SuperInit = (0, _runtime.SuperCall)(NSStringFromSelector("init"), [], { type: "@" }); 228 | 229 | // Returns a real ObjC class. No need to use new. 230 | function ObjCClass(defn) { 231 | const superclass = defn.superclass || NSObject; 232 | const className = (defn.className || defn.classname || "ObjCClass") + NSUUID.UUID().UUIDString(); 233 | const reserved = new Set(['className', 'classname', 'superclass']); 234 | var cls = MOClassDescription.allocateDescriptionForClassWithName_superclass_(className, superclass); 235 | // Add each handler to the class description 236 | const ivars = []; 237 | for (var key in defn) { 238 | const v = defn[key]; 239 | if (typeof v == 'function' && key !== 'init') { 240 | var selector = NSSelectorFromString(key); 241 | cls.addInstanceMethodWithSelector_function_(selector, v); 242 | } else if (!reserved.has(key)) { 243 | ivars.push(key); 244 | cls.addInstanceVariableWithName_typeEncoding(key, "@"); 245 | } 246 | } 247 | 248 | cls.addInstanceMethodWithSelector_function_(NSSelectorFromString('init'), function () { 249 | const self = SuperInit.call(this); 250 | ivars.map(name => { 251 | Object.defineProperty(self, name, { 252 | get() { 253 | return getIvar(self, name); 254 | }, 255 | set(v) { 256 | (0, _runtime.object_setInstanceVariable)(self, name, v); 257 | } 258 | }); 259 | self[name] = defn[name]; 260 | }); 261 | // If there is a passsed-in init funciton, call it now. 262 | if (typeof defn.init == 'function') defn.init.call(this); 263 | return self; 264 | }); 265 | 266 | return cls.registerClass(); 267 | }; 268 | 269 | function getIvar(obj, name) { 270 | const retPtr = MOPointer.new(); 271 | (0, _runtime.object_getInstanceVariable)(obj, name, retPtr); 272 | return retPtr.value().retain().autorelease(); 273 | } 274 | 275 | /***/ }), 276 | 277 | /***/ "./node_modules/cocoascript-class/lib/runtime.js": 278 | /*!*******************************************************!*\ 279 | !*** ./node_modules/cocoascript-class/lib/runtime.js ***! 280 | \*******************************************************/ 281 | /*! no static exports found */ 282 | /***/ (function(module, exports, __webpack_require__) { 283 | 284 | "use strict"; 285 | 286 | 287 | Object.defineProperty(exports, "__esModule", { 288 | value: true 289 | }); 290 | exports.SuperCall = SuperCall; 291 | exports.CFunc = CFunc; 292 | const objc_super_typeEncoding = '{objc_super="receiver"@"super_class"#}'; 293 | 294 | // You can store this to call your function. this must be bound to the current instance. 295 | function SuperCall(selector, argTypes, returnType) { 296 | const func = CFunc("objc_msgSendSuper", [{ type: '^' + objc_super_typeEncoding }, { type: ":" }, ...argTypes], returnType); 297 | return function (...args) { 298 | const struct = make_objc_super(this, this.superclass()); 299 | const structPtr = MOPointer.alloc().initWithValue_(struct); 300 | return func(structPtr, selector, ...args); 301 | }; 302 | } 303 | 304 | // Recursively create a MOStruct 305 | function makeStruct(def) { 306 | if (typeof def !== 'object' || Object.keys(def).length == 0) { 307 | return def; 308 | } 309 | const name = Object.keys(def)[0]; 310 | const values = def[name]; 311 | 312 | const structure = MOStruct.structureWithName_memberNames_runtime(name, Object.keys(values), Mocha.sharedRuntime()); 313 | 314 | Object.keys(values).map(member => { 315 | structure[member] = makeStruct(values[member]); 316 | }); 317 | 318 | return structure; 319 | } 320 | 321 | function make_objc_super(self, cls) { 322 | return makeStruct({ 323 | objc_super: { 324 | receiver: self, 325 | super_class: cls 326 | } 327 | }); 328 | } 329 | 330 | // Due to particularities of the JS bridge, we can't call into MOBridgeSupport objects directly 331 | // But, we can ask key value coding to do the dirty work for us ;) 332 | function setKeys(o, d) { 333 | const funcDict = NSMutableDictionary.dictionary(); 334 | funcDict.o = o; 335 | Object.keys(d).map(k => funcDict.setValue_forKeyPath(d[k], "o." + k)); 336 | } 337 | 338 | // Use any C function, not just ones with BridgeSupport 339 | function CFunc(name, args, retVal) { 340 | function makeArgument(a) { 341 | if (!a) return null; 342 | const arg = MOBridgeSupportArgument.alloc().init(); 343 | setKeys(arg, { 344 | type64: a.type 345 | }); 346 | return arg; 347 | } 348 | const func = MOBridgeSupportFunction.alloc().init(); 349 | setKeys(func, { 350 | name: name, 351 | arguments: args.map(makeArgument), 352 | returnValue: makeArgument(retVal) 353 | }); 354 | return func; 355 | } 356 | 357 | /* 358 | @encode(char*) = "*" 359 | @encode(id) = "@" 360 | @encode(Class) = "#" 361 | @encode(void*) = "^v" 362 | @encode(CGRect) = "{CGRect={CGPoint=dd}{CGSize=dd}}" 363 | @encode(SEL) = ":" 364 | */ 365 | 366 | function addStructToBridgeSupport(key, structDef) { 367 | // OK, so this is probably the nastiest hack in this file. 368 | // We go modify MOBridgeSupportController behind its back and use kvc to add our own definition 369 | // There isn't another API for this though. So the only other way would be to make a real bridgesupport file. 370 | const symbols = MOBridgeSupportController.sharedController().valueForKey('symbols'); 371 | if (!symbols) throw Error("Something has changed within bridge support so we can't add our definitions"); 372 | // If someone already added this definition, don't re-register it. 373 | if (symbols[key] !== null) return; 374 | const def = MOBridgeSupportStruct.alloc().init(); 375 | setKeys(def, { 376 | name: key, 377 | type: structDef.type 378 | }); 379 | symbols[key] = def; 380 | }; 381 | 382 | // This assumes the ivar is an object type. Return value is pretty useless. 383 | const object_getInstanceVariable = exports.object_getInstanceVariable = CFunc("object_getInstanceVariable", [{ type: "@" }, { type: '*' }, { type: "^@" }], { type: "^{objc_ivar=}" }); 384 | // Again, ivar is of object type 385 | const object_setInstanceVariable = exports.object_setInstanceVariable = CFunc("object_setInstanceVariable", [{ type: "@" }, { type: '*' }, { type: "@" }], { type: "^{objc_ivar=}" }); 386 | 387 | // We need Mocha to understand what an objc_super is so we can use it as a function argument 388 | addStructToBridgeSupport('objc_super', { type: objc_super_typeEncoding }); 389 | 390 | /***/ }), 391 | 392 | /***/ "./node_modules/promise-polyfill/lib/index.js": 393 | /*!****************************************************!*\ 394 | !*** ./node_modules/promise-polyfill/lib/index.js ***! 395 | \****************************************************/ 396 | /*! no static exports found */ 397 | /***/ (function(module, exports, __webpack_require__) { 398 | 399 | "use strict"; 400 | /* WEBPACK VAR INJECTION */(function(setTimeout, setImmediate) { 401 | 402 | /** 403 | * @this {Promise} 404 | */ 405 | function finallyConstructor(callback) { 406 | var constructor = this.constructor; 407 | return this.then( 408 | function(value) { 409 | return constructor.resolve(callback()).then(function() { 410 | return value; 411 | }); 412 | }, 413 | function(reason) { 414 | return constructor.resolve(callback()).then(function() { 415 | return constructor.reject(reason); 416 | }); 417 | } 418 | ); 419 | } 420 | 421 | // Store setTimeout reference so promise-polyfill will be unaffected by 422 | // other code modifying setTimeout (like sinon.useFakeTimers()) 423 | var setTimeoutFunc = setTimeout; 424 | 425 | function noop() {} 426 | 427 | // Polyfill for Function.prototype.bind 428 | function bind(fn, thisArg) { 429 | return function() { 430 | fn.apply(thisArg, arguments); 431 | }; 432 | } 433 | 434 | /** 435 | * @constructor 436 | * @param {Function} fn 437 | */ 438 | function Promise(fn) { 439 | if (!(this instanceof Promise)) 440 | throw new TypeError('Promises must be constructed via new'); 441 | if (typeof fn !== 'function') throw new TypeError('not a function'); 442 | /** @type {!number} */ 443 | this._state = 0; 444 | /** @type {!boolean} */ 445 | this._handled = false; 446 | /** @type {Promise|undefined} */ 447 | this._value = undefined; 448 | /** @type {!Array} */ 449 | this._deferreds = []; 450 | 451 | doResolve(fn, this); 452 | } 453 | 454 | function handle(self, deferred) { 455 | while (self._state === 3) { 456 | self = self._value; 457 | } 458 | if (self._state === 0) { 459 | self._deferreds.push(deferred); 460 | return; 461 | } 462 | self._handled = true; 463 | Promise._immediateFn(function() { 464 | var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected; 465 | if (cb === null) { 466 | (self._state === 1 ? resolve : reject)(deferred.promise, self._value); 467 | return; 468 | } 469 | var ret; 470 | try { 471 | ret = cb(self._value); 472 | } catch (e) { 473 | reject(deferred.promise, e); 474 | return; 475 | } 476 | resolve(deferred.promise, ret); 477 | }); 478 | } 479 | 480 | function resolve(self, newValue) { 481 | try { 482 | // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure 483 | if (newValue === self) 484 | throw new TypeError('A promise cannot be resolved with itself.'); 485 | if ( 486 | newValue && 487 | (typeof newValue === 'object' || typeof newValue === 'function') 488 | ) { 489 | var then = newValue.then; 490 | if (newValue instanceof Promise) { 491 | self._state = 3; 492 | self._value = newValue; 493 | finale(self); 494 | return; 495 | } else if (typeof then === 'function') { 496 | doResolve(bind(then, newValue), self); 497 | return; 498 | } 499 | } 500 | self._state = 1; 501 | self._value = newValue; 502 | finale(self); 503 | } catch (e) { 504 | reject(self, e); 505 | } 506 | } 507 | 508 | function reject(self, newValue) { 509 | self._state = 2; 510 | self._value = newValue; 511 | finale(self); 512 | } 513 | 514 | function finale(self) { 515 | if (self._state === 2 && self._deferreds.length === 0) { 516 | Promise._immediateFn(function() { 517 | if (!self._handled) { 518 | Promise._unhandledRejectionFn(self._value); 519 | } 520 | }); 521 | } 522 | 523 | for (var i = 0, len = self._deferreds.length; i < len; i++) { 524 | handle(self, self._deferreds[i]); 525 | } 526 | self._deferreds = null; 527 | } 528 | 529 | /** 530 | * @constructor 531 | */ 532 | function Handler(onFulfilled, onRejected, promise) { 533 | this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; 534 | this.onRejected = typeof onRejected === 'function' ? onRejected : null; 535 | this.promise = promise; 536 | } 537 | 538 | /** 539 | * Take a potentially misbehaving resolver function and make sure 540 | * onFulfilled and onRejected are only called once. 541 | * 542 | * Makes no guarantees about asynchrony. 543 | */ 544 | function doResolve(fn, self) { 545 | var done = false; 546 | try { 547 | fn( 548 | function(value) { 549 | if (done) return; 550 | done = true; 551 | resolve(self, value); 552 | }, 553 | function(reason) { 554 | if (done) return; 555 | done = true; 556 | reject(self, reason); 557 | } 558 | ); 559 | } catch (ex) { 560 | if (done) return; 561 | done = true; 562 | reject(self, ex); 563 | } 564 | } 565 | 566 | Promise.prototype['catch'] = function(onRejected) { 567 | return this.then(null, onRejected); 568 | }; 569 | 570 | Promise.prototype.then = function(onFulfilled, onRejected) { 571 | // @ts-ignore 572 | var prom = new this.constructor(noop); 573 | 574 | handle(this, new Handler(onFulfilled, onRejected, prom)); 575 | return prom; 576 | }; 577 | 578 | Promise.prototype['finally'] = finallyConstructor; 579 | 580 | Promise.all = function(arr) { 581 | return new Promise(function(resolve, reject) { 582 | if (!arr || typeof arr.length === 'undefined') 583 | throw new TypeError('Promise.all accepts an array'); 584 | var args = Array.prototype.slice.call(arr); 585 | if (args.length === 0) return resolve([]); 586 | var remaining = args.length; 587 | 588 | function res(i, val) { 589 | try { 590 | if (val && (typeof val === 'object' || typeof val === 'function')) { 591 | var then = val.then; 592 | if (typeof then === 'function') { 593 | then.call( 594 | val, 595 | function(val) { 596 | res(i, val); 597 | }, 598 | reject 599 | ); 600 | return; 601 | } 602 | } 603 | args[i] = val; 604 | if (--remaining === 0) { 605 | resolve(args); 606 | } 607 | } catch (ex) { 608 | reject(ex); 609 | } 610 | } 611 | 612 | for (var i = 0; i < args.length; i++) { 613 | res(i, args[i]); 614 | } 615 | }); 616 | }; 617 | 618 | Promise.resolve = function(value) { 619 | if (value && typeof value === 'object' && value.constructor === Promise) { 620 | return value; 621 | } 622 | 623 | return new Promise(function(resolve) { 624 | resolve(value); 625 | }); 626 | }; 627 | 628 | Promise.reject = function(value) { 629 | return new Promise(function(resolve, reject) { 630 | reject(value); 631 | }); 632 | }; 633 | 634 | Promise.race = function(values) { 635 | return new Promise(function(resolve, reject) { 636 | for (var i = 0, len = values.length; i < len; i++) { 637 | values[i].then(resolve, reject); 638 | } 639 | }); 640 | }; 641 | 642 | // Use polyfill for setImmediate for performance gains 643 | Promise._immediateFn = 644 | (typeof setImmediate === 'function' && 645 | function(fn) { 646 | setImmediate(fn); 647 | }) || 648 | function(fn) { 649 | setTimeoutFunc(fn, 0); 650 | }; 651 | 652 | Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) { 653 | if (typeof console !== 'undefined' && console) { 654 | console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console 655 | } 656 | }; 657 | 658 | module.exports = Promise; 659 | 660 | /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./node_modules/@skpm/timers/timeout.js */ "./node_modules/@skpm/timers/timeout.js")["setTimeout"], __webpack_require__(/*! ./node_modules/@skpm/timers/immediate.js */ "./node_modules/@skpm/timers/immediate.js")["setImmediate"])) 661 | 662 | /***/ }), 663 | 664 | /***/ "./node_modules/sketch-module-web-view/lib/browser-api.js": 665 | /*!****************************************************************!*\ 666 | !*** ./node_modules/sketch-module-web-view/lib/browser-api.js ***! 667 | \****************************************************************/ 668 | /*! no static exports found */ 669 | /***/ (function(module, exports) { 670 | 671 | var COLOR_CLASSES = [ 672 | 'NSColor', 673 | 'NSCachedWhiteColor', 674 | 'NSColorSpaceColor', 675 | 'NSDynamicSystemColor', 676 | 'NSCachedColorSpaceColor', 677 | ] 678 | function parseHexColor(color) { 679 | // Check the string for incorrect formatting. 680 | if (!color || color[0] !== '#') { 681 | if ( 682 | color && 683 | color.class && 684 | COLOR_CLASSES.indexOf(String(color.class())) !== -1 685 | ) { 686 | return color 687 | } 688 | throw new Error( 689 | 'Incorrect color formating. It should be an hex color: #RRGGBBAA' 690 | ) 691 | } 692 | 693 | // append FF if alpha channel is not specified. 694 | var source = color.substr(1) 695 | if (source.length === 3) { 696 | source += 'F' 697 | } else if (source.length === 6) { 698 | source += 'FF' 699 | } 700 | // Convert the string from #FFF format to #FFFFFF format. 701 | var hex 702 | if (source.length === 4) { 703 | for (var i = 0; i < 4; i += 1) { 704 | hex += source[i] 705 | hex += source[i] 706 | } 707 | } else if (source.length === 8) { 708 | hex = source 709 | } else { 710 | return NSColor.whiteColor() 711 | } 712 | 713 | var r = parseInt(hex.slice(0, 2), 16) 714 | var g = parseInt(hex.slice(2, 4), 16) 715 | var b = parseInt(hex.slice(4, 6), 16) 716 | var a = parseInt(hex.slice(6, 8), 16) 717 | 718 | return NSColor.colorWithSRGBRed_green_blue_alpha(r, g, b, a) 719 | } 720 | 721 | module.exports = function(browserWindow, panel, webview) { 722 | // keep reference to the subviews 723 | browserWindow._panel = panel 724 | browserWindow._webview = webview 725 | browserWindow._destroyed = false 726 | 727 | browserWindow.destroy = function() { 728 | return panel.close() 729 | } 730 | 731 | browserWindow.close = function() { 732 | if (panel.delegate().utils.parentWindow) { 733 | var shouldClose = true 734 | browserWindow.emit('close', { 735 | get defaultPrevented() { 736 | return !shouldClose 737 | }, 738 | preventDefault: function() { 739 | shouldClose = false 740 | }, 741 | }) 742 | if (shouldClose) { 743 | panel.delegate().utils.parentWindow.endSheet(panel) 744 | } 745 | return 746 | } 747 | 748 | if (!browserWindow.isClosable()) { 749 | return 750 | } 751 | 752 | panel.performClose(null) 753 | } 754 | 755 | function focus(focused) { 756 | if (browserWindow.isVisible()) { 757 | return 758 | } 759 | if (focused) { 760 | NSApplication.sharedApplication().activateIgnoringOtherApps(true) 761 | panel.makeKeyAndOrderFront(null) 762 | } else { 763 | panel.orderBack(null) 764 | } 765 | } 766 | 767 | browserWindow.focus = focus.bind(this, true) 768 | browserWindow.blur = focus.bind(this, false) 769 | 770 | browserWindow.isFocused = function() { 771 | return panel.isKeyWindow() 772 | } 773 | 774 | browserWindow.isDestroyed = function() { 775 | return browserWindow._destroyed 776 | } 777 | 778 | browserWindow.show = function() { 779 | // This method is supposed to put focus on window, however if the app does not 780 | // have focus then "makeKeyAndOrderFront" will only show the window. 781 | NSApp.activateIgnoringOtherApps(true) 782 | 783 | if (panel.delegate().utils.parentWindow) { 784 | return panel.delegate().utils.parentWindow.beginSheet_completionHandler( 785 | panel, 786 | __mocha__.createBlock_function('v16@?0q8', function() { 787 | browserWindow.emit('closed') 788 | }) 789 | ) 790 | } 791 | 792 | return panel.makeKeyAndOrderFront(null) 793 | } 794 | 795 | browserWindow.showInactive = function() { 796 | return panel.orderFrontRegardless() 797 | } 798 | 799 | browserWindow.hide = function() { 800 | return panel.orderOut(null) 801 | } 802 | 803 | browserWindow.isVisible = function() { 804 | return panel.isVisible() 805 | } 806 | 807 | browserWindow.isModal = function() { 808 | return false 809 | } 810 | 811 | browserWindow.maximize = function() { 812 | if (!browserWindow.isMaximized()) { 813 | panel.zoom(null) 814 | } 815 | } 816 | browserWindow.unmaximize = function() { 817 | if (browserWindow.isMaximized()) { 818 | panel.zoom(null) 819 | } 820 | } 821 | 822 | browserWindow.isMaximized = function() { 823 | if ((panel.styleMask() & NSResizableWindowMask) !== 0) { 824 | return panel.isZoomed() 825 | } 826 | var rectScreen = NSScreen.mainScreen().visibleFrame() 827 | var rectWindow = panel.frame() 828 | return ( 829 | rectScreen.origin.x == rectWindow.origin.x && 830 | rectScreen.origin.y == rectWindow.origin.y && 831 | rectScreen.size.width == rectWindow.size.width && 832 | rectScreen.size.height == rectWindow.size.height 833 | ) 834 | } 835 | 836 | browserWindow.minimize = function() { 837 | return panel.miniaturize(null) 838 | } 839 | 840 | browserWindow.restore = function() { 841 | return panel.deminiaturize(null) 842 | } 843 | 844 | browserWindow.isMinimized = function() { 845 | return panel.isMiniaturized() 846 | } 847 | 848 | browserWindow.setFullScreen = function(fullscreen) { 849 | if (fullscreen !== browserWindow.isFullscreen()) { 850 | panel.toggleFullScreen(null) 851 | } 852 | } 853 | 854 | browserWindow.isFullscreen = function() { 855 | return panel.styleMask() & NSFullScreenWindowMask 856 | } 857 | 858 | browserWindow.setAspectRatio = function(aspectRatio /* , extraSize */) { 859 | // Reset the behaviour to default if aspect_ratio is set to 0 or less. 860 | if (aspectRatio > 0.0) { 861 | panel.setAspectRatio(NSMakeSize(aspectRatio, 1.0)) 862 | } else { 863 | panel.setResizeIncrements(NSMakeSize(1.0, 1.0)) 864 | } 865 | } 866 | 867 | browserWindow.setBounds = function(bounds, animate) { 868 | // Do nothing if in fullscreen mode. 869 | if (browserWindow.isFullscreen()) { 870 | return 871 | } 872 | 873 | // TODO: Check size constraints since setFrame does not check it. 874 | var size = bounds.size 875 | // size.SetToMax(GetMinimumSize()); 876 | // gfx::Size max_size = GetMaximumSize(); 877 | // if (!max_size.IsEmpty()) 878 | // size.SetToMin(max_size); 879 | 880 | var cocoaBounds = NSMakeRect(bounds.origin.x, 0, size.width, size.height) 881 | // Flip coordinates based on the primary screen. 882 | var screen = NSScreen.screens().firstObject() 883 | cocoaBounds.origin.y = 884 | NSHeight(screen.frame()) - size.height - bounds.origin.y 885 | 886 | panel.setFrame_display_animate(cocoaBounds, true, animate) 887 | } 888 | 889 | browserWindow.getBounds = function() { 890 | return panel.frame() 891 | } 892 | 893 | browserWindow.setContentBounds = function(/* bounds, animate */) { 894 | // TODO: 895 | } 896 | 897 | browserWindow.getContentBounds = function() { 898 | // TODO: 899 | } 900 | 901 | browserWindow.setSize = function(width, height, animate) { 902 | var bounds = browserWindow.getBounds() 903 | bounds.size.height = height 904 | bounds.size.width = width 905 | 906 | // TODO: handle resizing around center 907 | 908 | return browserWindow.setBounds(bounds, animate) 909 | } 910 | 911 | browserWindow.getSize = function() { 912 | var bounds = browserWindow.getBounds() 913 | return [bounds.size.width, bounds.size.height] 914 | } 915 | 916 | browserWindow.setContentSize = function(width, height, animate) { 917 | var bounds = browserWindow.getContentBounds() 918 | bounds.size.height = height 919 | bounds.size.width = width 920 | 921 | // TODO: handle resizing around center 922 | 923 | return browserWindow.setContentBounds(bounds, animate) 924 | } 925 | 926 | browserWindow.getContentSize = function() { 927 | var bounds = browserWindow.getContentBounds() 928 | return [bounds.size.width, bounds.size.height] 929 | } 930 | 931 | browserWindow.setMinimumSize = function(width, height) { 932 | const minSize = { width: width, height: height } 933 | panel.setContentMinSize(minSize) 934 | } 935 | 936 | browserWindow.getMinimumSize = function() { 937 | const size = panel.contentMinSize() 938 | return [size.width, size.height] 939 | } 940 | 941 | browserWindow.setMaximumSize = function(width, height) { 942 | const minSize = { width: width, height: height } 943 | panel.setContentMaxSize(minSize) 944 | } 945 | 946 | browserWindow.getMaximumSize = function() { 947 | const size = panel.contentMaxSize() 948 | return [size.width, size.height] 949 | } 950 | 951 | browserWindow.setResizable = function(resizable) { 952 | return browserWindow._setStyleMask(resizable, NSResizableWindowMask) 953 | } 954 | 955 | browserWindow.isResizable = function() { 956 | return panel.styleMask() & NSResizableWindowMask 957 | } 958 | 959 | browserWindow.setMovable = function(movable) { 960 | return panel.setMovable(movable) 961 | } 962 | browserWindow.isMovable = function() { 963 | return panel.isMovable() 964 | } 965 | 966 | browserWindow.setMinimizable = function(minimizable) { 967 | return browserWindow._setStyleMask(minimizable, NSMiniaturizableWindowMask) 968 | } 969 | 970 | browserWindow.isMinimizable = function() { 971 | return panel.styleMask() & NSMiniaturizableWindowMask 972 | } 973 | 974 | browserWindow.setMaximizable = function(maximizable) { 975 | if (panel.standardWindowButton(NSWindowZoomButton)) { 976 | panel.standardWindowButton(NSWindowZoomButton).setEnabled(maximizable) 977 | } 978 | } 979 | 980 | browserWindow.isMaximizable = function() { 981 | return ( 982 | panel.standardWindowButton(NSWindowZoomButton) && 983 | panel.standardWindowButton(NSWindowZoomButton).isEnabled() 984 | ) 985 | } 986 | 987 | browserWindow.setFullScreenable = function(fullscreenable) { 988 | browserWindow._setCollectionBehavior( 989 | fullscreenable, 990 | NSWindowCollectionBehaviorFullScreenPrimary 991 | ) 992 | // On EL Capitan this flag is required to hide fullscreen button. 993 | browserWindow._setCollectionBehavior( 994 | !fullscreenable, 995 | NSWindowCollectionBehaviorFullScreenAuxiliary 996 | ) 997 | } 998 | 999 | browserWindow.isFullScreenable = function() { 1000 | var collectionBehavior = panel.collectionBehavior() 1001 | return collectionBehavior & NSWindowCollectionBehaviorFullScreenPrimary 1002 | } 1003 | 1004 | browserWindow.setClosable = function(closable) { 1005 | browserWindow._setStyleMask(closable, NSClosableWindowMask) 1006 | } 1007 | 1008 | browserWindow.isClosable = function() { 1009 | return panel.styleMask() & NSClosableWindowMask 1010 | } 1011 | 1012 | browserWindow.setAlwaysOnTop = function(top, level, relativeLevel) { 1013 | var windowLevel = NSNormalWindowLevel 1014 | var maxWindowLevel = CGWindowLevelForKey(kCGMaximumWindowLevelKey) 1015 | var minWindowLevel = CGWindowLevelForKey(kCGMinimumWindowLevelKey) 1016 | 1017 | if (top) { 1018 | if (level === 'normal') { 1019 | windowLevel = NSNormalWindowLevel 1020 | } else if (level === 'torn-off-menu') { 1021 | windowLevel = NSTornOffMenuWindowLevel 1022 | } else if (level === 'modal-panel') { 1023 | windowLevel = NSModalPanelWindowLevel 1024 | } else if (level === 'main-menu') { 1025 | windowLevel = NSMainMenuWindowLevel 1026 | } else if (level === 'status') { 1027 | windowLevel = NSStatusWindowLevel 1028 | } else if (level === 'pop-up-menu') { 1029 | windowLevel = NSPopUpMenuWindowLevel 1030 | } else if (level === 'screen-saver') { 1031 | windowLevel = NSScreenSaverWindowLevel 1032 | } else if (level === 'dock') { 1033 | // Deprecated by macOS, but kept for backwards compatibility 1034 | windowLevel = NSDockWindowLevel 1035 | } else { 1036 | windowLevel = NSFloatingWindowLevel 1037 | } 1038 | } 1039 | 1040 | var newLevel = windowLevel + (relativeLevel || 0) 1041 | if (newLevel >= minWindowLevel && newLevel <= maxWindowLevel) { 1042 | panel.setLevel(newLevel) 1043 | } else { 1044 | throw new Error( 1045 | 'relativeLevel must be between ' + 1046 | minWindowLevel + 1047 | ' and ' + 1048 | maxWindowLevel 1049 | ) 1050 | } 1051 | } 1052 | 1053 | browserWindow.isAlwaysOnTop = function() { 1054 | return panel.level() !== NSNormalWindowLevel 1055 | } 1056 | 1057 | browserWindow.moveTop = function() { 1058 | return panel.orderFrontRegardless() 1059 | } 1060 | 1061 | browserWindow.center = function() { 1062 | panel.center() 1063 | } 1064 | 1065 | browserWindow.setPosition = function(x, y, animate) { 1066 | var bounds = browserWindow.getBounds() 1067 | var mainScreenRect = NSScreen.screens() 1068 | .firstObject() 1069 | .frame() 1070 | bounds.origin.x = x 1071 | bounds.origin.y = Math.round(NSHeight(mainScreenRect) - y) 1072 | 1073 | return browserWindow.setBounds(bounds, animate) 1074 | } 1075 | 1076 | browserWindow.getPosition = function() { 1077 | var bounds = browserWindow.getBounds() 1078 | var mainScreenRect = NSScreen.screens() 1079 | .firstObject() 1080 | .frame() 1081 | return [ 1082 | bounds.origin.x, 1083 | Math.round(NSHeight(mainScreenRect) - bounds.origin.y), 1084 | ] 1085 | } 1086 | 1087 | browserWindow.setTitle = function(title) { 1088 | panel.setTitle(title) 1089 | } 1090 | 1091 | browserWindow.getTitle = function() { 1092 | return String(panel.title()) 1093 | } 1094 | 1095 | var attentionRequestId = 0 1096 | browserWindow.flashFrame = function(flash) { 1097 | if (flash) { 1098 | attentionRequestId = NSApp.requestUserAttention(NSInformationalRequest) 1099 | } else { 1100 | NSApp.cancelUserAttentionRequest(attentionRequestId) 1101 | attentionRequestId = 0 1102 | } 1103 | } 1104 | 1105 | browserWindow.getNativeWindowHandle = function() { 1106 | return panel 1107 | } 1108 | 1109 | browserWindow.getNativeWebViewHandle = function() { 1110 | return webview 1111 | } 1112 | 1113 | browserWindow.loadURL = function(url) { 1114 | // When frameLocation is a file, prefix it with the Sketch Resources path 1115 | if (/^(?!http|localhost|www|file).*\.html?$/.test(url)) { 1116 | if (typeof __command !== 'undefined' && __command.pluginBundle()) { 1117 | url = 1118 | 'file://' + 1119 | __command 1120 | .pluginBundle() 1121 | .urlForResourceNamed(url) 1122 | .path() 1123 | } 1124 | } 1125 | 1126 | if (/^file:\/\/.*\.html?$/.test(url)) { 1127 | webview.loadFileURL_allowingReadAccessToURL( 1128 | NSURL.fileURLWithPath(url), 1129 | NSURL.fileURLWithPath('file:///') 1130 | ) 1131 | return 1132 | } 1133 | 1134 | webview.loadRequest(NSURLRequest.requestWithURL(NSURL.URLWithString(url))) 1135 | } 1136 | 1137 | browserWindow.reload = function() { 1138 | webview.reload() 1139 | } 1140 | 1141 | browserWindow.setHasShadow = function(hasShadow) { 1142 | return panel.setHasShadow(hasShadow) 1143 | } 1144 | 1145 | browserWindow.hasShadow = function() { 1146 | return panel.hasShadow() 1147 | } 1148 | 1149 | browserWindow.setOpacity = function(opacity) { 1150 | return panel.setAlphaValue(opacity) 1151 | } 1152 | 1153 | browserWindow.getOpacity = function() { 1154 | return panel.alphaValue() 1155 | } 1156 | 1157 | browserWindow.setVisibleOnAllWorkspaces = function(visible) { 1158 | return browserWindow._setCollectionBehavior( 1159 | visible, 1160 | NSWindowCollectionBehaviorCanJoinAllSpaces 1161 | ) 1162 | } 1163 | 1164 | browserWindow.isVisibleOnAllWorkspaces = function() { 1165 | var collectionBehavior = panel.collectionBehavior() 1166 | return collectionBehavior & NSWindowCollectionBehaviorCanJoinAllSpaces 1167 | } 1168 | 1169 | browserWindow.setIgnoreMouseEvents = function(ignore) { 1170 | return panel.setIgnoresMouseEvents(ignore) 1171 | } 1172 | 1173 | browserWindow.setContentProtection = function(enable) { 1174 | panel.setSharingType(enable ? NSWindowSharingNone : NSWindowSharingReadOnly) 1175 | } 1176 | 1177 | browserWindow.setAutoHideCursor = function(autoHide) { 1178 | panel.setDisableAutoHideCursor(autoHide) 1179 | } 1180 | 1181 | browserWindow.setVibrancy = function(type) { 1182 | var effectView = browserWindow._vibrantView 1183 | 1184 | if (!type) { 1185 | if (effectView == null) { 1186 | return 1187 | } 1188 | 1189 | effectView.removeFromSuperview() 1190 | panel.setVibrantView(null) 1191 | return 1192 | } 1193 | 1194 | if (effectView == null) { 1195 | var contentView = panel.contentView() 1196 | effectView = NSVisualEffectView.alloc().initWithFrame( 1197 | contentView.bounds() 1198 | ) 1199 | browserWindow._vibrantView = effectView 1200 | 1201 | effectView.setAutoresizingMask(NSViewWidthSizable | NSViewHeightSizable) 1202 | effectView.setBlendingMode(NSVisualEffectBlendingModeBehindWindow) 1203 | effectView.setState(NSVisualEffectStateActive) 1204 | effectView.setFrame(contentView.bounds()) 1205 | contentView.addSubview_positioned_relativeTo( 1206 | effectView, 1207 | NSWindowBelow, 1208 | null 1209 | ) 1210 | } 1211 | 1212 | var vibrancyType = NSVisualEffectMaterialLight 1213 | 1214 | if (type === 'appearance-based') { 1215 | vibrancyType = NSVisualEffectMaterialAppearanceBased 1216 | } else if (type === 'light') { 1217 | vibrancyType = NSVisualEffectMaterialLight 1218 | } else if (type === 'dark') { 1219 | vibrancyType = NSVisualEffectMaterialDark 1220 | } else if (type === 'titlebar') { 1221 | vibrancyType = NSVisualEffectMaterialTitlebar 1222 | } else if (type === 'selection') { 1223 | vibrancyType = NSVisualEffectMaterialSelection 1224 | } else if (type === 'menu') { 1225 | vibrancyType = NSVisualEffectMaterialMenu 1226 | } else if (type === 'popover') { 1227 | vibrancyType = NSVisualEffectMaterialPopover 1228 | } else if (type === 'sidebar') { 1229 | vibrancyType = NSVisualEffectMaterialSidebar 1230 | } else if (type === 'medium-light') { 1231 | vibrancyType = NSVisualEffectMaterialMediumLight 1232 | } else if (type === 'ultra-dark') { 1233 | vibrancyType = NSVisualEffectMaterialUltraDark 1234 | } 1235 | 1236 | effectView.setMaterial(vibrancyType) 1237 | } 1238 | 1239 | browserWindow._setBackgroundColor = function(colorName) { 1240 | var color = parseHexColor(colorName) 1241 | webview.isOpaque = false 1242 | webview.setBackgroundColor(NSColor.clearColor()) 1243 | panel.backgroundColor = color 1244 | } 1245 | 1246 | browserWindow._invalidate = function() { 1247 | panel.flushWindow() 1248 | panel.contentView().setNeedsDisplay(true) 1249 | } 1250 | 1251 | browserWindow._setStyleMask = function(on, flag) { 1252 | var wasMaximizable = browserWindow.isMaximizable() 1253 | if (on) { 1254 | panel.setStyleMask(panel.styleMask() | flag) 1255 | } else { 1256 | panel.setStyleMask(panel.styleMask() & ~flag) 1257 | } 1258 | // Change style mask will make the zoom button revert to default, probably 1259 | // a bug of Cocoa or macOS. 1260 | browserWindow.setMaximizable(wasMaximizable) 1261 | } 1262 | 1263 | browserWindow._setCollectionBehavior = function(on, flag) { 1264 | var wasMaximizable = browserWindow.isMaximizable() 1265 | if (on) { 1266 | panel.setCollectionBehavior(panel.collectionBehavior() | flag) 1267 | } else { 1268 | panel.setCollectionBehavior(panel.collectionBehavior() & ~flag) 1269 | } 1270 | // Change collectionBehavior will make the zoom button revert to default, 1271 | // probably a bug of Cocoa or macOS. 1272 | browserWindow.setMaximizable(wasMaximizable) 1273 | } 1274 | 1275 | browserWindow._showWindowButton = function(button) { 1276 | var view = panel.standardWindowButton(button) 1277 | view.superview().addSubview_positioned_relative(view, NSWindowAbove, null) 1278 | } 1279 | } 1280 | 1281 | 1282 | /***/ }), 1283 | 1284 | /***/ "./node_modules/sketch-module-web-view/lib/constants.js": 1285 | /*!**************************************************************!*\ 1286 | !*** ./node_modules/sketch-module-web-view/lib/constants.js ***! 1287 | \**************************************************************/ 1288 | /*! no static exports found */ 1289 | /***/ (function(module, exports) { 1290 | 1291 | module.exports = { 1292 | JS_BRIDGE: '__skpm_sketchBridge', 1293 | } 1294 | 1295 | 1296 | /***/ }), 1297 | 1298 | /***/ "./node_modules/sketch-module-web-view/lib/dispatch-first-click.js": 1299 | /*!*************************************************************************!*\ 1300 | !*** ./node_modules/sketch-module-web-view/lib/dispatch-first-click.js ***! 1301 | \*************************************************************************/ 1302 | /*! no static exports found */ 1303 | /***/ (function(module, exports) { 1304 | 1305 | var tagsToFocus = 1306 | '["text", "textarea", "date", "datetime-local", "email", "number", "month", "password", "search", "tel", "time", "url", "week" ]' 1307 | 1308 | module.exports = function(webView, event) { 1309 | var point = webView.convertPoint_fromView(event.locationInWindow(), null) 1310 | var x = point.x 1311 | var y = webView.frame().size.height - point.y // the coord start from the bottom instead of the top 1312 | return ( 1313 | 'var el = document.elementFromPoint(' + // get the DOM element that match the event 1314 | x + 1315 | ', ' + 1316 | y + 1317 | '); ' + 1318 | 'if (el && ' + // some tags need to be focused instead of clicked 1319 | tagsToFocus + 1320 | '.indexOf(el.type) >= 0 && ' + 1321 | 'el.focus' + 1322 | ') {' + 1323 | 'el.focus();' + // so focus them 1324 | '} else if (el) {' + 1325 | 'el.dispatchEvent(new Event("click", {bubbles: true}))' + // click the others 1326 | '}' 1327 | ) 1328 | } 1329 | 1330 | 1331 | /***/ }), 1332 | 1333 | /***/ "./node_modules/sketch-module-web-view/lib/fitSubview.js": 1334 | /*!***************************************************************!*\ 1335 | !*** ./node_modules/sketch-module-web-view/lib/fitSubview.js ***! 1336 | \***************************************************************/ 1337 | /*! no static exports found */ 1338 | /***/ (function(module, exports) { 1339 | 1340 | function addEdgeConstraint(edge, subview, view, constant) { 1341 | view.addConstraint( 1342 | NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant( 1343 | subview, 1344 | edge, 1345 | NSLayoutRelationEqual, 1346 | view, 1347 | edge, 1348 | 1, 1349 | constant 1350 | ) 1351 | ) 1352 | } 1353 | module.exports = function fitSubviewToView(subview, view, constants) { 1354 | constants = constants || [] 1355 | subview.setTranslatesAutoresizingMaskIntoConstraints(false) 1356 | 1357 | addEdgeConstraint(NSLayoutAttributeLeft, subview, view, constants[0] || 0) 1358 | addEdgeConstraint(NSLayoutAttributeTop, subview, view, constants[1] || 0) 1359 | addEdgeConstraint(NSLayoutAttributeRight, subview, view, constants[2] || 0) 1360 | addEdgeConstraint(NSLayoutAttributeBottom, subview, view, constants[3] || 0) 1361 | } 1362 | 1363 | 1364 | /***/ }), 1365 | 1366 | /***/ "./node_modules/sketch-module-web-view/lib/index.js": 1367 | /*!**********************************************************!*\ 1368 | !*** ./node_modules/sketch-module-web-view/lib/index.js ***! 1369 | \**********************************************************/ 1370 | /*! no static exports found */ 1371 | /***/ (function(module, exports, __webpack_require__) { 1372 | 1373 | /* let's try to match the API from Electron's Browser window 1374 | (https://github.com/electron/electron/blob/master/docs/api/browser-window.md) */ 1375 | var EventEmitter = __webpack_require__(/*! events */ "events") 1376 | var buildBrowserAPI = __webpack_require__(/*! ./browser-api */ "./node_modules/sketch-module-web-view/lib/browser-api.js") 1377 | var buildWebAPI = __webpack_require__(/*! ./webview-api */ "./node_modules/sketch-module-web-view/lib/webview-api.js") 1378 | var fitSubviewToView = __webpack_require__(/*! ./fitSubview */ "./node_modules/sketch-module-web-view/lib/fitSubview.js") 1379 | var dispatchFirstClick = __webpack_require__(/*! ./dispatch-first-click */ "./node_modules/sketch-module-web-view/lib/dispatch-first-click.js") 1380 | var injectClientMessaging = __webpack_require__(/*! ./inject-client-messaging */ "./node_modules/sketch-module-web-view/lib/inject-client-messaging.js") 1381 | var setDelegates = __webpack_require__(/*! ./set-delegates */ "./node_modules/sketch-module-web-view/lib/set-delegates.js") 1382 | 1383 | function BrowserWindow(options) { 1384 | options = options || {} 1385 | 1386 | var identifier = options.identifier || NSUUID.UUID().UUIDString() 1387 | var threadDictionary = NSThread.mainThread().threadDictionary() 1388 | 1389 | var existingBrowserWindow = BrowserWindow.fromId(identifier) 1390 | 1391 | // if we already have a window opened, reuse it 1392 | if (existingBrowserWindow) { 1393 | return existingBrowserWindow 1394 | } 1395 | 1396 | var browserWindow = new EventEmitter() 1397 | browserWindow.id = identifier 1398 | 1399 | if (options.modal && !options.parent) { 1400 | throw new Error('A modal needs to have a parent.') 1401 | } 1402 | 1403 | // Long-running script 1404 | var fiber = coscript.createFiber() 1405 | 1406 | // Window size 1407 | var width = options.width || 800 1408 | var height = options.height || 600 1409 | var mainScreenRect = NSScreen.screens() 1410 | .firstObject() 1411 | .frame() 1412 | var cocoaBounds = NSMakeRect( 1413 | typeof options.x !== 'undefined' 1414 | ? options.x 1415 | : Math.round((NSWidth(mainScreenRect) - width) / 2), 1416 | typeof options.y !== 'undefined' 1417 | ? options.y 1418 | : Math.round((NSHeight(mainScreenRect) - height) / 2), 1419 | width, 1420 | height 1421 | ) 1422 | 1423 | if (options.titleBarStyle && options.titleBarStyle !== 'default') { 1424 | options.frame = false 1425 | } 1426 | 1427 | var useStandardWindow = options.windowType !== 'textured' 1428 | var styleMask = NSTitledWindowMask 1429 | 1430 | // this is commented out because the toolbar doesn't appear otherwise :thinking-face: 1431 | // if (!useStandardWindow || options.frame === false) { 1432 | // styleMask = NSFullSizeContentViewWindowMask 1433 | // } 1434 | if (options.minimizable !== false) { 1435 | styleMask |= NSMiniaturizableWindowMask 1436 | } 1437 | if (options.closable !== false) { 1438 | styleMask |= NSClosableWindowMask 1439 | } 1440 | if (options.resizable !== false) { 1441 | styleMask |= NSResizableWindowMask 1442 | } 1443 | if (!useStandardWindow || options.transparent || options.frame === false) { 1444 | styleMask |= NSTexturedBackgroundWindowMask 1445 | } 1446 | 1447 | var panel = NSPanel.alloc().initWithContentRect_styleMask_backing_defer( 1448 | cocoaBounds, 1449 | styleMask, 1450 | NSBackingStoreBuffered, 1451 | true 1452 | ) 1453 | 1454 | var wkwebviewConfig = WKWebViewConfiguration.alloc().init() 1455 | var webView = WKWebView.alloc().initWithFrame_configuration( 1456 | CGRectMake(0, 0, options.width || 800, options.height || 600), 1457 | wkwebviewConfig 1458 | ) 1459 | injectClientMessaging(webView) 1460 | webView.setAutoresizingMask(NSViewWidthSizable | NSViewHeightSizable) 1461 | 1462 | buildBrowserAPI(browserWindow, panel, webView) 1463 | buildWebAPI(browserWindow, panel, webView) 1464 | setDelegates(browserWindow, panel, webView, options) 1465 | 1466 | if (options.windowType === 'desktop') { 1467 | panel.setLevel(kCGDesktopWindowLevel - 1) 1468 | // panel.setCanBecomeKeyWindow(false) 1469 | panel.setCollectionBehavior( 1470 | NSWindowCollectionBehaviorCanJoinAllSpaces | 1471 | NSWindowCollectionBehaviorStationary | 1472 | NSWindowCollectionBehaviorIgnoresCycle 1473 | ) 1474 | } 1475 | 1476 | if ( 1477 | typeof options.minWidth !== 'undefined' || 1478 | typeof options.minHeight !== 'undefined' 1479 | ) { 1480 | browserWindow.setMinimumSize(options.minWidth || 0, options.minHeight || 0) 1481 | } 1482 | 1483 | if ( 1484 | typeof options.maxWidth !== 'undefined' || 1485 | typeof options.maxHeight !== 'undefined' 1486 | ) { 1487 | browserWindow.setMaximumSize( 1488 | options.maxWidth || 10000, 1489 | options.maxHeight || 10000 1490 | ) 1491 | } 1492 | 1493 | // if (options.focusable === false) { 1494 | // panel.setCanBecomeKeyWindow(false) 1495 | // } 1496 | 1497 | if (options.transparent || options.frame === false) { 1498 | panel.titlebarAppearsTransparent = true 1499 | panel.titleVisibility = NSWindowTitleHidden 1500 | panel.setOpaque(0) 1501 | panel.isMovableByWindowBackground = true 1502 | var toolbar2 = NSToolbar.alloc().initWithIdentifier( 1503 | 'titlebarStylingToolbar' 1504 | ) 1505 | toolbar2.setShowsBaselineSeparator(false) 1506 | panel.setToolbar(toolbar2) 1507 | } 1508 | 1509 | if (options.titleBarStyle === 'hiddenInset') { 1510 | var toolbar = NSToolbar.alloc().initWithIdentifier('titlebarStylingToolbar') 1511 | toolbar.setShowsBaselineSeparator(false) 1512 | panel.setToolbar(toolbar) 1513 | } 1514 | 1515 | if (options.frame === false || !options.useContentSize) { 1516 | browserWindow.setSize(width, height) 1517 | } 1518 | 1519 | if (options.center) { 1520 | browserWindow.center() 1521 | } 1522 | 1523 | if (options.alwaysOnTop) { 1524 | browserWindow.setAlwaysOnTop(true) 1525 | } 1526 | 1527 | if (options.fullscreen) { 1528 | browserWindow.setFullScreen(true) 1529 | } 1530 | browserWindow.setFullScreenable(!!options.fullscreenable) 1531 | 1532 | const title = 1533 | options.title || 1534 | (typeof __command !== 'undefined' && __command.pluginBundle() 1535 | ? __command.pluginBundle().name() 1536 | : undefined) 1537 | if (title) { 1538 | browserWindow.setTitle(title) 1539 | } 1540 | 1541 | var backgroundColor = options.backgroundColor 1542 | if (options.transparent) { 1543 | backgroundColor = NSColor.clearColor() 1544 | } 1545 | if (!backgroundColor && options.frame === false && options.vibrancy) { 1546 | backgroundColor = NSColor.clearColor() 1547 | } 1548 | 1549 | browserWindow._setBackgroundColor( 1550 | backgroundColor || NSColor.windowBackgroundColor() 1551 | ) 1552 | 1553 | if (options.hasShadow === false) { 1554 | browserWindow.setHasShadow(false) 1555 | } 1556 | 1557 | if (typeof options.opacity !== 'undefined') { 1558 | browserWindow.setOpacity(options.opacity) 1559 | } 1560 | 1561 | options.webPreferences = options.webPreferences || {} 1562 | 1563 | webView 1564 | .configuration() 1565 | .preferences() 1566 | .setValue_forKey( 1567 | options.webPreferences.devTools !== false, 1568 | 'developerExtrasEnabled' 1569 | ) 1570 | webView 1571 | .configuration() 1572 | .preferences() 1573 | .setValue_forKey( 1574 | options.webPreferences.devTools !== false, 1575 | 'javaScriptEnabled' 1576 | ) 1577 | webView 1578 | .configuration() 1579 | .preferences() 1580 | .setValue_forKey(!!options.webPreferences.plugins, 'plugInsEnabled') 1581 | webView 1582 | .configuration() 1583 | .preferences() 1584 | .setValue_forKey( 1585 | options.webPreferences.minimumFontSize || 0, 1586 | 'minimumFontSize' 1587 | ) 1588 | 1589 | if (options.webPreferences.zoomFactor) { 1590 | webView.setMagnification(options.webPreferences.zoomFactor) 1591 | } 1592 | 1593 | var contentView = panel.contentView() 1594 | 1595 | if (options.frame !== false) { 1596 | webView.setFrame(contentView.bounds()) 1597 | contentView.addSubview(webView) 1598 | } else { 1599 | // In OSX 10.10, adding subviews to the root view for the NSView hierarchy 1600 | // produces warnings. To eliminate the warnings, we resize the contentView 1601 | // to fill the window, and add subviews to that. 1602 | // http://crbug.com/380412 1603 | contentView.setAutoresizingMask(NSViewWidthSizable | NSViewHeightSizable) 1604 | fitSubviewToView(contentView, contentView.superview()) 1605 | 1606 | webView.setFrame(contentView.bounds()) 1607 | contentView.addSubview(webView) 1608 | 1609 | // The fullscreen button should always be hidden for frameless window. 1610 | if (panel.standardWindowButton(NSWindowFullScreenButton)) { 1611 | panel.standardWindowButton(NSWindowFullScreenButton).setHidden(true) 1612 | } 1613 | 1614 | if (!options.titleBarStyle || options.titleBarStyle === 'default') { 1615 | // Hide the window buttons. 1616 | panel.standardWindowButton(NSWindowZoomButton).setHidden(true) 1617 | panel.standardWindowButton(NSWindowMiniaturizeButton).setHidden(true) 1618 | panel.standardWindowButton(NSWindowCloseButton).setHidden(true) 1619 | 1620 | // Some third-party macOS utilities check the zoom button's enabled state to 1621 | // determine whether to show custom UI on hover, so we disable it here to 1622 | // prevent them from doing so in a frameless app window. 1623 | panel.standardWindowButton(NSWindowZoomButton).setEnabled(false) 1624 | } 1625 | } 1626 | 1627 | if (options.vibrancy) { 1628 | browserWindow.setVibrancy(options.vibrancy) 1629 | } 1630 | 1631 | // Set maximizable state last to ensure zoom button does not get reset 1632 | // by calls to other APIs. 1633 | browserWindow.setMaximizable(options.maximizable !== false) 1634 | 1635 | if (options.acceptsFirstMouse) { 1636 | browserWindow.on('focus', function(event) { 1637 | if (event.type() === NSEventTypeLeftMouseDown) { 1638 | browserWindow.webContents 1639 | .executeJavaScript(dispatchFirstClick(webView, event)) 1640 | .catch(() => {}) 1641 | } 1642 | }) 1643 | } 1644 | 1645 | if (options.show !== false) { 1646 | browserWindow.show() 1647 | } 1648 | 1649 | browserWindow.on('closed', function() { 1650 | browserWindow._destroyed = true 1651 | threadDictionary.removeObjectForKey(identifier) 1652 | fiber.cleanup() 1653 | }) 1654 | 1655 | threadDictionary[identifier] = panel 1656 | 1657 | fiber.onCleanup(function() { 1658 | if (!browserWindow._destroyed) { 1659 | browserWindow.destroy() 1660 | } 1661 | }) 1662 | 1663 | return browserWindow 1664 | } 1665 | 1666 | BrowserWindow.fromId = function(identifier) { 1667 | var threadDictionary = NSThread.mainThread().threadDictionary() 1668 | 1669 | if (threadDictionary[identifier]) { 1670 | return BrowserWindow.fromPanel(threadDictionary[identifier], identifier) 1671 | } 1672 | 1673 | return undefined 1674 | } 1675 | 1676 | BrowserWindow.fromPanel = function(panel, identifier) { 1677 | var browserWindow = new EventEmitter() 1678 | browserWindow.id = identifier 1679 | 1680 | if (!panel || !panel.contentView) { 1681 | throw new Error('needs to pass an NSPanel') 1682 | } 1683 | 1684 | var webView = panel.contentView().subviews()[0] 1685 | 1686 | if (!webView) { 1687 | throw new Error('The NSPanel needs to have a webview') 1688 | } 1689 | 1690 | buildBrowserAPI(browserWindow, panel, webView) 1691 | buildWebAPI(browserWindow, panel, webView) 1692 | 1693 | return browserWindow 1694 | } 1695 | 1696 | module.exports = BrowserWindow 1697 | 1698 | 1699 | /***/ }), 1700 | 1701 | /***/ "./node_modules/sketch-module-web-view/lib/inject-client-messaging.js": 1702 | /*!****************************************************************************!*\ 1703 | !*** ./node_modules/sketch-module-web-view/lib/inject-client-messaging.js ***! 1704 | \****************************************************************************/ 1705 | /*! no static exports found */ 1706 | /***/ (function(module, exports, __webpack_require__) { 1707 | 1708 | var CONSTANTS = __webpack_require__(/*! ./constants */ "./node_modules/sketch-module-web-view/lib/constants.js") 1709 | 1710 | module.exports = function(webView) { 1711 | var source = 1712 | 'window.originalPostMessage = window.postMessage;' + 1713 | 'window.postMessage = function(actionName) {' + 1714 | 'if (!actionName) {' + 1715 | "throw new Error('missing action name')" + 1716 | '}' + 1717 | 'window.webkit.messageHandlers.' + 1718 | CONSTANTS.JS_BRIDGE + 1719 | '.postMessage(' + 1720 | 'JSON.stringify([].slice.call(arguments))' + 1721 | ');' + 1722 | '}' 1723 | var script = WKUserScript.alloc().initWithSource_injectionTime_forMainFrameOnly( 1724 | source, 1725 | 0, 1726 | true 1727 | ) 1728 | webView 1729 | .configuration() 1730 | .userContentController() 1731 | .addUserScript(script) 1732 | } 1733 | 1734 | 1735 | /***/ }), 1736 | 1737 | /***/ "./node_modules/sketch-module-web-view/lib/parseWebArguments.js": 1738 | /*!**********************************************************************!*\ 1739 | !*** ./node_modules/sketch-module-web-view/lib/parseWebArguments.js ***! 1740 | \**********************************************************************/ 1741 | /*! no static exports found */ 1742 | /***/ (function(module, exports) { 1743 | 1744 | module.exports = function(webArguments) { 1745 | var args = null 1746 | try { 1747 | args = JSON.parse(webArguments[0]) 1748 | } catch (e) { 1749 | // malformed arguments 1750 | } 1751 | 1752 | if ( 1753 | !args || 1754 | !args.constructor || 1755 | args.constructor !== Array || 1756 | args.length == 0 1757 | ) { 1758 | return null 1759 | } 1760 | 1761 | return args 1762 | } 1763 | 1764 | 1765 | /***/ }), 1766 | 1767 | /***/ "./node_modules/sketch-module-web-view/lib/set-delegates.js": 1768 | /*!******************************************************************!*\ 1769 | !*** ./node_modules/sketch-module-web-view/lib/set-delegates.js ***! 1770 | \******************************************************************/ 1771 | /*! no static exports found */ 1772 | /***/ (function(module, exports, __webpack_require__) { 1773 | 1774 | var ObjCClass = __webpack_require__(/*! cocoascript-class */ "./node_modules/cocoascript-class/lib/index.js").default 1775 | var parseWebArguments = __webpack_require__(/*! ./parseWebArguments */ "./node_modules/sketch-module-web-view/lib/parseWebArguments.js") 1776 | var CONSTANTS = __webpack_require__(/*! ./constants */ "./node_modules/sketch-module-web-view/lib/constants.js") 1777 | 1778 | // We create one ObjC class for ourselves here 1779 | var WindowDelegateClass 1780 | var NavigationDelegateClass 1781 | var WebScriptHandlerClass 1782 | 1783 | // TODO: events 1784 | // - 'page-favicon-updated' 1785 | // - 'new-window' 1786 | // - 'did-navigate-in-page' 1787 | // - 'will-prevent-unload' 1788 | // - 'crashed' 1789 | // - 'unresponsive' 1790 | // - 'responsive' 1791 | // - 'destroyed' 1792 | // - 'before-input-event' 1793 | // - 'certificate-error' 1794 | // - 'found-in-page' 1795 | // - 'media-started-playing' 1796 | // - 'media-paused' 1797 | // - 'did-change-theme-color' 1798 | // - 'update-target-url' 1799 | // - 'cursor-changed' 1800 | // - 'context-menu' 1801 | // - 'select-bluetooth-device' 1802 | // - 'paint' 1803 | // - 'console-message' 1804 | 1805 | module.exports = function(browserWindow, panel, webview, options) { 1806 | if (!WindowDelegateClass) { 1807 | WindowDelegateClass = ObjCClass({ 1808 | classname: 'WindowDelegateClass', 1809 | utils: null, 1810 | panel: null, 1811 | 1812 | 'windowDidResize:': function() { 1813 | this.utils.emit('resize') 1814 | }, 1815 | 1816 | 'windowDidMiniaturize:': function() { 1817 | this.utils.emit('minimize') 1818 | }, 1819 | 1820 | 'windowDidDeminiaturize:': function() { 1821 | this.utils.emit('restore') 1822 | }, 1823 | 1824 | 'windowDidEnterFullScreen:': function() { 1825 | this.utils.emit('enter-full-screen') 1826 | }, 1827 | 1828 | 'windowDidExitFullScreen:': function() { 1829 | this.utils.emit('leave-full-screen') 1830 | }, 1831 | 1832 | 'windowDidMove:': function() { 1833 | this.utils.emit('move') 1834 | this.utils.emit('moved') 1835 | }, 1836 | 1837 | 'windowShouldClose:': function() { 1838 | var shouldClose = true 1839 | this.utils.emit('close', { 1840 | get defaultPrevented() { 1841 | return !shouldClose 1842 | }, 1843 | preventDefault: function() { 1844 | shouldClose = false 1845 | }, 1846 | }) 1847 | return shouldClose 1848 | }, 1849 | 1850 | 'windowWillClose:': function() { 1851 | this.utils.emit('closed') 1852 | }, 1853 | 1854 | 'windowDidBecomeKey:': function() { 1855 | this.utils.emit('focus', this.panel.currentEvent()) 1856 | }, 1857 | 1858 | 'windowDidResignKey:': function() { 1859 | this.utils.emit('blur') 1860 | }, 1861 | }) 1862 | } 1863 | 1864 | if (!NavigationDelegateClass) { 1865 | NavigationDelegateClass = ObjCClass({ 1866 | classname: 'NavigationDelegateClass', 1867 | state: NSMutableDictionary.dictionaryWithDictionary({ 1868 | wasReady: 0, 1869 | }), 1870 | utils: null, 1871 | 1872 | // // Called when the web view begins to receive web content. 1873 | 'webView:didCommitNavigation:': function(webView) { 1874 | this.utils.emit('will-navigate', {}, String(String(webView.url()))) 1875 | }, 1876 | 1877 | // // Called when web content begins to load in a web view. 1878 | 'webView:didStartProvisionalNavigation:': function() { 1879 | this.utils.emit('did-start-navigation') 1880 | this.utils.emit('did-start-loading') 1881 | }, 1882 | 1883 | // Called when a web view receives a server redirect. 1884 | 'webView:didReceiveServerRedirectForProvisionalNavigation:': function() { 1885 | this.utils.emit('did-get-redirect-request') 1886 | }, 1887 | 1888 | // // Called when the web view needs to respond to an authentication challenge. 1889 | 'webView:didReceiveAuthenticationChallenge:completionHandler:': function( 1890 | webView, 1891 | challenge, 1892 | completionHandler 1893 | ) { 1894 | function callback(username, password) { 1895 | completionHandler( 1896 | 0, 1897 | NSURLCredential.credentialWithUser_password_persistence( 1898 | username, 1899 | password, 1900 | 1 1901 | ) 1902 | ) 1903 | } 1904 | var protectionSpace = challenge.protectionSpace() 1905 | this.utils.emit( 1906 | 'login', 1907 | {}, 1908 | { 1909 | method: String(protectionSpace.authenticationMethod()), 1910 | url: 'not implemented', // TODO: 1911 | referrer: 'not implemented', // TODO: 1912 | }, 1913 | { 1914 | isProxy: !!protectionSpace.isProxy(), 1915 | scheme: String(protectionSpace.protocol()), 1916 | host: String(protectionSpace.host()), 1917 | port: Number(protectionSpace.port()), 1918 | realm: String(protectionSpace.realm()), 1919 | }, 1920 | callback 1921 | ) 1922 | }, 1923 | 1924 | // Called when an error occurs during navigation. 1925 | // 'webView:didFailNavigation:withError:': function( 1926 | // webView, 1927 | // navigation, 1928 | // error 1929 | // ) {}, 1930 | 1931 | // Called when an error occurs while the web view is loading content. 1932 | 'webView:didFailProvisionalNavigation:withError:': function( 1933 | webView, 1934 | navigation, 1935 | error 1936 | ) { 1937 | this.utils.emit('did-fail-load', error) 1938 | }, 1939 | 1940 | // Called when the navigation is complete. 1941 | 'webView:didFinishNavigation:': function() { 1942 | if (this.state.wasReady == 0) { 1943 | // eslint-disable-line 1944 | this.utils.emitBrowserEvent('ready-to-show') 1945 | this.state.setObject_forKey(1, 'wasReady') 1946 | } 1947 | this.utils.emit('did-navigate') 1948 | this.utils.emit('did-frame-navigate') 1949 | this.utils.emit('did-stop-loading') 1950 | this.utils.emit('did-finish-load') 1951 | this.utils.emit('did-frame-finish-load') 1952 | }, 1953 | 1954 | // Called when the web view’s web content process is terminated. 1955 | 'webViewWebContentProcessDidTerminate:': function() { 1956 | this.utils.emit('dom-ready') 1957 | }, 1958 | 1959 | // Decides whether to allow or cancel a navigation. 1960 | // webView:decidePolicyForNavigationAction:decisionHandler: 1961 | 1962 | // Decides whether to allow or cancel a navigation after its response is known. 1963 | // webView:decidePolicyForNavigationResponse:decisionHandler: 1964 | }) 1965 | } 1966 | 1967 | if (!WebScriptHandlerClass) { 1968 | WebScriptHandlerClass = ObjCClass({ 1969 | classname: 'WebScriptHandlerClass', 1970 | utils: null, 1971 | 'userContentController:didReceiveScriptMessage:': function(_, message) { 1972 | var webArguments = JSON.parse(String(message.body())) 1973 | var args = this.utils.parseWebArguments([JSON.stringify(webArguments)]) 1974 | if (!args) { 1975 | return 1976 | } 1977 | 1978 | this.utils.emit.apply(this, args) 1979 | }, 1980 | }) 1981 | } 1982 | 1983 | var navigationDelegate = NavigationDelegateClass.new() 1984 | navigationDelegate.utils = NSDictionary.dictionaryWithDictionary({ 1985 | setTitle: browserWindow.setTitle.bind(browserWindow), 1986 | emitBrowserEvent: browserWindow.emit.bind(browserWindow), 1987 | emit: browserWindow.webContents.emit.bind(browserWindow.webContents), 1988 | }) 1989 | // reset state as well 1990 | navigationDelegate.state = NSMutableDictionary.dictionaryWithDictionary({ 1991 | wasReady: 0, 1992 | }) 1993 | 1994 | webview.setNavigationDelegate(navigationDelegate) 1995 | 1996 | var webScriptHandler = WebScriptHandlerClass.new() 1997 | webScriptHandler.utils = NSDictionary.dictionaryWithDictionary({ 1998 | emit: browserWindow.webContents.emit.bind(browserWindow.webContents), 1999 | parseWebArguments: parseWebArguments, 2000 | }) 2001 | 2002 | webview 2003 | .configuration() 2004 | .userContentController() 2005 | .addScriptMessageHandler_name(webScriptHandler, CONSTANTS.JS_BRIDGE) 2006 | 2007 | var windowDelegate = WindowDelegateClass.new() 2008 | var utils = { 2009 | emit: browserWindow.emit.bind(browserWindow), 2010 | } 2011 | if (options.modal) { 2012 | // find the window of the document 2013 | var msdocument 2014 | if (options.parent.type === 'Document') { 2015 | msdocument = options.parent.sketchObject 2016 | if (msdocument && String(msdocument.class()) === 'MSDocumentData') { 2017 | // we only have an MSDocumentData instead of a MSDocument 2018 | // let's try to get back to the MSDocument 2019 | msdocument = msdocument.delegate() 2020 | } 2021 | } else { 2022 | msdocument = options.parent 2023 | } 2024 | if (msdocument && String(msdocument.class()) === 'MSDocumentData') { 2025 | // we only have an MSDocumentData instead of a MSDocument 2026 | // let's try to get back to the MSDocument 2027 | msdocument = msdocument.delegate() 2028 | } 2029 | utils.parentWindow = msdocument.windowForSheet() 2030 | } 2031 | 2032 | windowDelegate.utils = NSDictionary.dictionaryWithDictionary(utils) 2033 | windowDelegate.panel = panel 2034 | 2035 | panel.setDelegate(windowDelegate) 2036 | } 2037 | 2038 | 2039 | /***/ }), 2040 | 2041 | /***/ "./node_modules/sketch-module-web-view/lib/webview-api.js": 2042 | /*!****************************************************************!*\ 2043 | !*** ./node_modules/sketch-module-web-view/lib/webview-api.js ***! 2044 | \****************************************************************/ 2045 | /*! no static exports found */ 2046 | /***/ (function(module, exports, __webpack_require__) { 2047 | 2048 | /* WEBPACK VAR INJECTION */(function(Promise) {var EventEmitter = __webpack_require__(/*! events */ "events") 2049 | 2050 | // let's try to match https://github.com/electron/electron/blob/master/docs/api/web-contents.md 2051 | module.exports = function buildAPI(browserWindow, panel, webview) { 2052 | var webContents = new EventEmitter() 2053 | 2054 | webContents.loadURL = browserWindow.loadURL 2055 | 2056 | webContents.loadFile = function(/* filePath */) { 2057 | // TODO: 2058 | console.warn( 2059 | 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)' 2060 | ) 2061 | } 2062 | 2063 | webContents.downloadURL = function(/* filePath */) { 2064 | // TODO: 2065 | console.warn( 2066 | 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)' 2067 | ) 2068 | } 2069 | 2070 | webContents.getURL = function() { 2071 | return String(webview.url()) 2072 | } 2073 | 2074 | webContents.getTitle = function() { 2075 | return String(webview.title()) 2076 | } 2077 | 2078 | webContents.isDestroyed = function() { 2079 | // TODO: 2080 | console.warn( 2081 | 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)' 2082 | ) 2083 | } 2084 | 2085 | webContents.focus = browserWindow.focus 2086 | webContents.isFocused = browserWindow.isFocused 2087 | 2088 | webContents.isLoading = function() { 2089 | return !!webview.loading() 2090 | } 2091 | 2092 | webContents.isLoadingMainFrame = function() { 2093 | // TODO: 2094 | return !!webview.loading() 2095 | } 2096 | 2097 | webContents.isWaitingForResponse = function() { 2098 | return !webview.loading() 2099 | } 2100 | 2101 | webContents.stop = function() { 2102 | webview.stopLoading() 2103 | } 2104 | webContents.reload = function() { 2105 | webview.reload() 2106 | } 2107 | webContents.reloadIgnoringCache = function() { 2108 | webview.reloadFromOrigin() 2109 | } 2110 | webContents.canGoBack = function() { 2111 | return !!webview.canGoBack() 2112 | } 2113 | webContents.canGoForward = function() { 2114 | return !!webview.canGoForward() 2115 | } 2116 | webContents.canGoToOffset = function(offset) { 2117 | return !!webview.backForwardList().itemAtIndex(offset) 2118 | } 2119 | webContents.clearHistory = function() { 2120 | // TODO: 2121 | console.warn( 2122 | 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)' 2123 | ) 2124 | } 2125 | webContents.goBack = function() { 2126 | webview.goBack() 2127 | } 2128 | webContents.goForward = function() { 2129 | webview.goForward() 2130 | } 2131 | webContents.goToIndex = function(index) { 2132 | var backForwardList = webview.backForwardList() 2133 | var backList = backForwardList.backList() 2134 | var backListLength = backList.count() 2135 | if (backListLength > index) { 2136 | webview.loadRequest(NSURLRequest.requestWithURL(backList[index])) 2137 | return 2138 | } 2139 | var forwardList = backForwardList.forwardList() 2140 | if (forwardList.count() > index - backListLength) { 2141 | webview.loadRequest( 2142 | NSURLRequest.requestWithURL(forwardList[index - backListLength]) 2143 | ) 2144 | return 2145 | } 2146 | throw new Error('Cannot go to index ' + index) 2147 | } 2148 | webContents.goToOffset = function(offset) { 2149 | if (!webContents.canGoToOffset(offset)) { 2150 | throw new Error('Cannot go to offset ' + offset) 2151 | } 2152 | webview.loadRequest( 2153 | NSURLRequest.requestWithURL(webview.backForwardList().itemAtIndex(offset)) 2154 | ) 2155 | } 2156 | webContents.isCrashed = function() { 2157 | // TODO: 2158 | console.warn( 2159 | 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)' 2160 | ) 2161 | } 2162 | webContents.setUserAgent = function(/* userAgent */) { 2163 | // TODO: 2164 | console.warn( 2165 | 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)' 2166 | ) 2167 | } 2168 | webContents.getUserAgent = function() { 2169 | const userAgent = webview.customUserAgent() 2170 | return userAgent ? String(userAgent) : undefined 2171 | } 2172 | webContents.insertCSS = function(css) { 2173 | var source = 2174 | "var style = document.createElement('style'); style.innerHTML = " + 2175 | css.replace(/"/, '\\"') + 2176 | '; document.head.appendChild(style);' 2177 | var script = WKUserScript.alloc().initWithSource_injectionTime_forMainFrameOnly( 2178 | source, 2179 | 0, 2180 | true 2181 | ) 2182 | webview 2183 | .configuration() 2184 | .userContentController() 2185 | .addUserScript(script) 2186 | } 2187 | webContents.insertJS = function(source) { 2188 | var script = WKUserScript.alloc().initWithSource_injectionTime_forMainFrameOnly( 2189 | source, 2190 | 0, 2191 | true 2192 | ) 2193 | webview 2194 | .configuration() 2195 | .userContentController() 2196 | .addUserScript(script) 2197 | } 2198 | webContents.executeJavaScript = function(script, userGesture, callback) { 2199 | if (typeof userGesture === 'function') { 2200 | callback = userGesture 2201 | userGesture = false 2202 | } 2203 | var fiber = coscript.createFiber() 2204 | return new Promise(function(resolve, reject) { 2205 | webview.evaluateJavaScript_completionHandler( 2206 | script, 2207 | __mocha__.createBlock_function('v28@?0@8c16@"NSError"20', function( 2208 | result, 2209 | err 2210 | ) { 2211 | var isError = 2212 | err && 2213 | err.class && 2214 | (String(err.class()) === 'NSException' || 2215 | String(err.class()) === 'NSError') 2216 | if (callback) { 2217 | try { 2218 | callback(isError ? err : null, result) 2219 | } catch (error) { 2220 | // /shrug 2221 | } 2222 | resolve() 2223 | } else if (isError) { 2224 | reject(err) 2225 | } else { 2226 | resolve(result) 2227 | } 2228 | fiber.cleanup() 2229 | }) 2230 | ) 2231 | }) 2232 | } 2233 | webContents.setIgnoreMenuShortcuts = function() { 2234 | // TODO:?? 2235 | console.warn( 2236 | 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)' 2237 | ) 2238 | } 2239 | webContents.setAudioMuted = function(/* muted */) { 2240 | // TODO:?? 2241 | console.warn( 2242 | 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)' 2243 | ) 2244 | } 2245 | webContents.isAudioMuted = function() { 2246 | // TODO:?? 2247 | console.warn( 2248 | 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)' 2249 | ) 2250 | } 2251 | webContents.setZoomFactor = function(factor) { 2252 | webview.setMagnification_centeredAtPoint(factor, CGPointMake(0, 0)) 2253 | } 2254 | webContents.getZoomFactor = function(callback) { 2255 | callback(Number(webview.magnification())) 2256 | } 2257 | webContents.setZoomLevel = function(level) { 2258 | // eslint-disable-next-line no-restricted-properties 2259 | webContents.setZoomFactor(Math.pow(1.2, level)) 2260 | } 2261 | webContents.getZoomLevel = function(callback) { 2262 | // eslint-disable-next-line no-restricted-properties 2263 | callback(Math.log(Number(webview.magnification())) / Math.log(1.2)) 2264 | } 2265 | webContents.setVisualZoomLevelLimits = function(/* minimumLevel, maximumLevel */) { 2266 | // TODO:?? 2267 | console.warn( 2268 | 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)' 2269 | ) 2270 | } 2271 | webContents.setLayoutZoomLevelLimits = function(/* minimumLevel, maximumLevel */) { 2272 | // TODO:?? 2273 | console.warn( 2274 | 'Not implemented yet, please open a PR on https://github.com/skpm/sketch-module-web-view :)' 2275 | ) 2276 | } 2277 | 2278 | // TODO: 2279 | // webContents.undo = function() { 2280 | // webview.undoManager().undo() 2281 | // } 2282 | // webContents.redo = function() { 2283 | // webview.undoManager().redo() 2284 | // } 2285 | // webContents.cut = webview.cut 2286 | // webContents.copy = webview.copy 2287 | // webContents.paste = webview.paste 2288 | // webContents.pasteAndMatchStyle = webview.pasteAsRichText 2289 | // webContents.delete = webview.delete 2290 | // webContents.replace = webview.replaceSelectionWithText 2291 | 2292 | webContents.send = function() { 2293 | const script = 2294 | 'window.postMessage({' + 2295 | 'isSketchMessage: true,' + 2296 | "origin: '" + 2297 | String(__command.identifier()) + 2298 | "'," + 2299 | 'args: ' + 2300 | JSON.stringify([].slice.call(arguments)) + 2301 | '}, "*")' 2302 | webview.evaluateJavaScript_completionHandler(script, null) 2303 | } 2304 | 2305 | webContents.getNativeWebview = function() { 2306 | return webview 2307 | } 2308 | 2309 | browserWindow.webContents = webContents 2310 | } 2311 | 2312 | /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./node_modules/promise-polyfill/lib/index.js */ "./node_modules/promise-polyfill/lib/index.js"))) 2313 | 2314 | /***/ }), 2315 | 2316 | /***/ "./src/coolhue.js": 2317 | /*!************************!*\ 2318 | !*** ./src/coolhue.js ***! 2319 | \************************/ 2320 | /*! exports provided: default */ 2321 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 2322 | 2323 | "use strict"; 2324 | __webpack_require__.r(__webpack_exports__); 2325 | /* harmony import */ var sketch_module_web_view__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sketch-module-web-view */ "./node_modules/sketch-module-web-view/lib/index.js"); 2326 | /* harmony import */ var sketch_module_web_view__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sketch_module_web_view__WEBPACK_IMPORTED_MODULE_0__); 2327 | /* harmony import */ var _gradient__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./gradient */ "./src/gradient.js"); 2328 | 2329 | 2330 | /* harmony default export */ __webpack_exports__["default"] = (function () { 2331 | //Global Setup 2332 | var options = { 2333 | backgroundColor: '#FFFFFF', 2334 | identifier: 'coolhue.id', 2335 | width: 215, 2336 | height: 450, 2337 | resizable: false, 2338 | movable: true, 2339 | alwaysOnTop: true, 2340 | minimizable: true, 2341 | maximizable: false, 2342 | title: "CoolHue 2.0", 2343 | vibrancy: "appearance-based" 2344 | }; 2345 | var browserWindow = new sketch_module_web_view__WEBPACK_IMPORTED_MODULE_0___default.a(options); 2346 | browserWindow.isAlwaysOnTop(); 2347 | browserWindow.loadURL(__webpack_require__(/*! ./view.html */ "./src/view.html")); 2348 | browserWindow.webContents.on('nativeGradientApplier', function (fetchedData) { 2349 | Object(_gradient__WEBPACK_IMPORTED_MODULE_1__["GradientMaker"])(fetchedData.firstColor, fetchedData.secondColor); 2350 | }); 2351 | }); 2352 | 2353 | /***/ }), 2354 | 2355 | /***/ "./src/gradient.js": 2356 | /*!*************************!*\ 2357 | !*** ./src/gradient.js ***! 2358 | \*************************/ 2359 | /*! exports provided: GradientMaker */ 2360 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 2361 | 2362 | "use strict"; 2363 | __webpack_require__.r(__webpack_exports__); 2364 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GradientMaker", function() { return GradientMaker; }); 2365 | /* harmony import */ var sketch__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sketch */ "sketch"); 2366 | /* harmony import */ var sketch__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sketch__WEBPACK_IMPORTED_MODULE_0__); 2367 | /* harmony import */ var sketch_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! sketch/ui */ "sketch/ui"); 2368 | /* harmony import */ var sketch_ui__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(sketch_ui__WEBPACK_IMPORTED_MODULE_1__); 2369 | 2370 | 2371 | 2372 | var Style = __webpack_require__(/*! sketch/dom */ "sketch/dom").Style; 2373 | 2374 | function GradientMaker(firstStop, secondStop) { 2375 | var doc = sketch__WEBPACK_IMPORTED_MODULE_0___default.a.getSelectedDocument(); 2376 | var selectedLayers = doc.selectedLayers; 2377 | 2378 | if (selectedLayers.length != null && selectedLayers.length != 0) { 2379 | selectedLayers.forEach(function (layer) { 2380 | if (layer.type === "Shape" || layer.type === "ShapePath") { 2381 | layer.style.fills = [{ 2382 | fillType: Style.FillType.Gradient, 2383 | fill: 'Gradient', 2384 | gradient: { 2385 | gradientType: Style.GradientType.Linear, 2386 | from: { 2387 | x: 0, 2388 | y: 0 2389 | }, 2390 | to: { 2391 | x: 1, 2392 | y: 1 2393 | }, 2394 | stops: [{ 2395 | position: 0, 2396 | color: firstStop 2397 | }, { 2398 | position: 1, 2399 | color: secondStop 2400 | }] 2401 | } 2402 | }]; 2403 | } else { 2404 | sketch_ui__WEBPACK_IMPORTED_MODULE_1___default.a.message("\uD83D\uDD14 CoolHue can apply gradients on Shape Layer(s) only"); 2405 | } 2406 | }); 2407 | } else { 2408 | sketch_ui__WEBPACK_IMPORTED_MODULE_1___default.a.message("\uD83D\uDED1 Select Shape Layer(s) to apply CoolHue Gradients"); 2409 | } 2410 | } 2411 | 2412 | /***/ }), 2413 | 2414 | /***/ "./src/view.html": 2415 | /*!***********************!*\ 2416 | !*** ./src/view.html ***! 2417 | \***********************/ 2418 | /*! no static exports found */ 2419 | /***/ (function(module, exports) { 2420 | 2421 | module.exports = "file://" + context.plugin.urlForResourceNamed("_webpack_resources/3ff137287832113452bf2ab1649999f2.html").path(); 2422 | 2423 | /***/ }), 2424 | 2425 | /***/ "events": 2426 | /*!*************************!*\ 2427 | !*** external "events" ***! 2428 | \*************************/ 2429 | /*! no static exports found */ 2430 | /***/ (function(module, exports) { 2431 | 2432 | module.exports = require("events"); 2433 | 2434 | /***/ }), 2435 | 2436 | /***/ "sketch": 2437 | /*!*************************!*\ 2438 | !*** external "sketch" ***! 2439 | \*************************/ 2440 | /*! no static exports found */ 2441 | /***/ (function(module, exports) { 2442 | 2443 | module.exports = require("sketch"); 2444 | 2445 | /***/ }), 2446 | 2447 | /***/ "sketch/dom": 2448 | /*!*****************************!*\ 2449 | !*** external "sketch/dom" ***! 2450 | \*****************************/ 2451 | /*! no static exports found */ 2452 | /***/ (function(module, exports) { 2453 | 2454 | module.exports = require("sketch/dom"); 2455 | 2456 | /***/ }), 2457 | 2458 | /***/ "sketch/ui": 2459 | /*!****************************!*\ 2460 | !*** external "sketch/ui" ***! 2461 | \****************************/ 2462 | /*! no static exports found */ 2463 | /***/ (function(module, exports) { 2464 | 2465 | module.exports = require("sketch/ui"); 2466 | 2467 | /***/ }) 2468 | 2469 | /******/ }); 2470 | if (key === 'default' && typeof exports === 'function') { 2471 | exports(context); 2472 | } else { 2473 | exports[key](context); 2474 | } 2475 | } 2476 | that['onRun'] = __skpm_run.bind(this, 'default') 2477 | 2478 | //# sourceMappingURL=coolhue.js.map --------------------------------------------------------------------------------