├── .appcast.xml
├── .gitignore
├── LICENSE
├── README.md
├── assets
└── icon.png
├── context-menu.png
├── html-fontbook-export.png
├── icon.png
├── json-export.png
├── package-lock.json
├── package.json
├── sass-export.png
├── src
├── css-export.js
├── custom-export.js
├── export
│ ├── export-components.js
│ └── open-export-dialog.js
├── html-fontbook-export.js
├── json-export.js
├── manifest.json
├── sass-mixins-export.js
└── util
│ ├── export.js
│ ├── number.js
│ ├── sketch.js
│ ├── string.js
│ ├── ui.js
│ └── util.js
└── typex.sketchplugin
└── Contents
├── Resources
└── icon.png
└── Sketch
├── advanced-json-export.js
├── advanced-json-export.js.map
├── css-export.js
├── css-export.js.map
├── custom-export.js
├── custom-export.js.map
├── html-export.js
├── html-export.js.map
├── html-fontbook-export.js
├── html-fontbook-export.js.map
├── json-export.js
├── json-export.js.map
├── manifest.json
├── my-command.js.map
├── sass-mixins-export.js
├── sass-mixins-export.js.map
├── web-export.js
├── web-export.js.map
├── window-test.js
└── window-test.js.map
/.appcast.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 | -
8 |
9 |
10 | -
11 |
12 |
13 | -
14 |
15 |
16 | -
17 |
18 |
19 | -
20 |
21 |
22 | -
23 |
24 |
25 | -
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # build artifacts
2 | plugin.sketchplugin
3 |
4 | # npm
5 | node_modules
6 | .npm
7 | npm-debug.log
8 |
9 | # mac
10 | .DS_Store
11 |
12 | # WebStorm
13 | .idea
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2018, Rein Van Oyen
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Export your text styles to CSS, SASS mixins, JSON, HTML, ...
6 | Highly configurable (Including rem, em units, etc)
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | # Installation
15 | 1. Download the plugin.
16 | 2. Unzip the downloaded file.
17 | 3. Double click on typex.sketchplugin
18 |
19 | # Typex?
20 |
21 | Typex is a Sketch plugin which provides you with all the tools you need to export your text styles to the web platform, ready for your developer to put them to use. Instead of just giving you the typical simplistic copy-pastable CSS snippet for your text styles, you can now actually configure how to export them to CSS, SASS mixins and JSON.
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/reinvanoyen/typex/297f2b00d5fb21793b0fa6060a1b031a326299b0/assets/icon.png
--------------------------------------------------------------------------------
/context-menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/reinvanoyen/typex/297f2b00d5fb21793b0fa6060a1b031a326299b0/context-menu.png
--------------------------------------------------------------------------------
/html-fontbook-export.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/reinvanoyen/typex/297f2b00d5fb21793b0fa6060a1b031a326299b0/html-fontbook-export.png
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/reinvanoyen/typex/297f2b00d5fb21793b0fa6060a1b031a326299b0/icon.png
--------------------------------------------------------------------------------
/json-export.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/reinvanoyen/typex/297f2b00d5fb21793b0fa6060a1b031a326299b0/json-export.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "typex",
3 | "version": "1.1.0",
4 | "description": "Text styles to CSS, SASS mixins, HTML, JSON, ...",
5 | "repository": {
6 | "type": "git",
7 | "url": "git+https://github.com/reinvanoyen/typex"
8 | },
9 | "engines": {
10 | "sketch": ">=3.0"
11 | },
12 | "skpm": {
13 | "name": "typex",
14 | "manifest": "src/manifest.json",
15 | "main": "typex.sketchplugin",
16 | "assets": [
17 | "assets/**/*"
18 | ]
19 | },
20 | "scripts": {
21 | "build": "skpm-build",
22 | "watch": "skpm-build --watch",
23 | "start": "skpm-build --watch --run",
24 | "postinstall": "npm run build && skpm-link"
25 | },
26 | "devDependencies": {
27 | "@skpm/builder": "^0.5.2"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/sass-export.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/reinvanoyen/typex/297f2b00d5fb21793b0fa6060a1b031a326299b0/sass-export.png
--------------------------------------------------------------------------------
/src/css-export.js:
--------------------------------------------------------------------------------
1 | import ui from './util/ui';
2 | import stringUtils from './util/string';
3 | import exportUtils from './util/export';
4 |
5 | import openExportDialog from './export/open-export-dialog';
6 |
7 | export default function(context) {
8 |
9 | openExportDialog(context, {
10 | title: 'CSS classes export',
11 | informativeText: 'Export each text style as a class'
12 | }, (textStyles, data) => {
13 |
14 | let css = {};
15 |
16 | textStyles.forEach(textStyle => {
17 | css[stringUtils.slugify(textStyle.name)] = exportUtils.createCssProps(textStyle, data);
18 | });
19 |
20 | let output = '';
21 | let i = 0;
22 |
23 | for (let identifier in css) {
24 | if (css.hasOwnProperty(identifier)) {
25 |
26 | let className = data.namingPrefix + '-' + (data.namingConvention === 'Numeric' ? i+1 : identifier);
27 |
28 | output += ( i !== 0 ? "\n" : '' ) + '.' + className + "\n";
29 | output += '{'+"\n";
30 | output += exportUtils.createStyleBlock(css[identifier]);
31 | output += '}'+"\n";
32 | i++;
33 | }
34 | }
35 |
36 | ui.createSavePanel('typex-stylesheet.css', output);
37 | });
38 | };
--------------------------------------------------------------------------------
/src/custom-export.js:
--------------------------------------------------------------------------------
1 | import ui from './util/ui';
2 |
3 | import openExportDialog from './export/open-export-dialog';
4 |
5 | export default function(context) {
6 |
7 | openExportDialog(context, {
8 | title: 'Custom script export',
9 | informativeText: 'Export each text style by using a custom export script in Javascript'
10 | }, (textStyles, data) => {
11 |
12 | ui.createSettingsDialog(context, {
13 | title: 'Custom export script',
14 | informativeText: 'Customize your export by using Javascript'
15 | }, [
16 | {
17 | type: 'text',
18 | id: 'customScript',
19 | value: 'console.log(output)',
20 | label: 'Custom Javascript export'
21 | }
22 | ], (customData) => {
23 |
24 | // @TODO
25 | });
26 | });
27 | };
--------------------------------------------------------------------------------
/src/export/export-components.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | type: 'checkbox',
4 | id: 'merge',
5 | label: 'Merge',
6 | value: 'Merge identical styles'
7 | },
8 | {
9 | type: 'multicheckbox',
10 | id: 'excludeProps',
11 | label: 'Exclude properties',
12 | values: [
13 | 'Color',
14 | 'Line height'
15 | ]
16 | },
17 | {
18 | type: 'select',
19 | id: 'cssUnit',
20 | options: [
21 | 'px',
22 | 'em',
23 | 'rem',
24 | '%',
25 | 'vh',
26 | 'vw',
27 | 'No unit'
28 | ],
29 | label: 'CSS unit'
30 | },
31 | {
32 | type: 'text',
33 | id: 'scalingFactor',
34 | value: 1,
35 | label: 'Size scaling factor'
36 | },
37 | {
38 | type: 'text',
39 | id: 'maxDecimalPlaces',
40 | value: 2,
41 | label: 'Maximal decimal places'
42 | },
43 | {
44 | type: 'text',
45 | id: 'namingPrefix',
46 | value: 'type',
47 | label: 'Naming prefix'
48 | },
49 | {
50 | type: 'select',
51 | id: 'namingConvention',
52 | options: [
53 | 'Numeric',
54 | 'Text style name'
55 | ],
56 | label: 'Naming convention'
57 | }
58 | ];
--------------------------------------------------------------------------------
/src/export/open-export-dialog.js:
--------------------------------------------------------------------------------
1 | import ui from '../util/ui';
2 | import exportUtils from '../util/export';
3 | import sketchUtils from '../util/sketch';
4 |
5 | import exportComponents from './export-components';
6 |
7 | export default function(context, opts, cb) {
8 |
9 | ui.createSettingsDialog(context, opts, exportComponents, (data) => {
10 |
11 | // Defaults
12 | data.propertyNamingConvention = data.propertyNamingConvention || 'Numeric';
13 | data.cssUnit = (data.cssUnit === 'No unit' ? 0 : data.cssUnit);
14 |
15 | // First store the properties we should exclude
16 | let excludeProps = [];
17 | if (data['excludeProps']['Color']) {
18 | excludeProps.push('color');
19 | }
20 |
21 | if (data['excludeProps']['Line height']) {
22 | excludeProps.push('lineHeight');
23 | }
24 |
25 | // Get the text styles from the Sketch document
26 | let textStyles = sketchUtils.getTextStyles(context);
27 | textStyles = exportUtils.sortTextStyles(textStyles);
28 | textStyles = exportUtils.excludeTextStyleProperties(textStyles, excludeProps);
29 |
30 | if (data['merge']) {
31 | textStyles = exportUtils.removeDoubleTextStyles(textStyles);
32 | }
33 |
34 | cb(textStyles, data);
35 | });
36 | };
--------------------------------------------------------------------------------
/src/html-fontbook-export.js:
--------------------------------------------------------------------------------
1 | import ui from './util/ui';
2 | import exportUtils from './util/export';
3 | import openExportDialog from "./export/open-export-dialog";
4 |
5 | export default function(context) {
6 |
7 | openExportDialog(context, {
8 | title: 'Create HTML fontbook',
9 | informativeText: 'Create a handy HTML fontbook from your text styles',
10 | confirmBtnText: 'Export HTML fontbook'
11 | }, (textStyles, data) => {
12 |
13 | // Create a HTML fontbook with these styles
14 | let html = exportUtils.createHtmlFontbook(textStyles, data);
15 |
16 | // Ask the user to save the file
17 | ui.createSavePanel('typex-fontbook.html', html);
18 | });
19 | };
--------------------------------------------------------------------------------
/src/json-export.js:
--------------------------------------------------------------------------------
1 | import ui from './util/ui';
2 | import stringUtils from './util/string';
3 | import exportUtils from './util/export';
4 |
5 | import openExportDialog from './export/open-export-dialog';
6 |
7 | export default function(context) {
8 |
9 | openExportDialog(context, {
10 | title: 'JSON export',
11 | informativeText: 'Export text styles in JSON format'
12 | }, (textStyles, data) => {
13 |
14 | // Export as JSON
15 | let textStyleJson = {};
16 |
17 | textStyles.forEach((textStyle, i) => {
18 |
19 | let textStyleIdentifier = stringUtils.slugify(textStyle.name);
20 | let stylePropertyNaming = data.namingPrefix + '-' + (data.namingConvention === 'Numeric' ? (i+1) : textStyleIdentifier);
21 |
22 | textStyleJson[stylePropertyNaming] = exportUtils.createCssProps(textStyle, data);
23 | });
24 |
25 | // Ask the user to save the file
26 | ui.createSavePanel('typex-text-styles.json', JSON.stringify(textStyleJson));
27 | });
28 | };
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "compatibleVersion": 3,
3 | "bundleVersion": 1,
4 | "icon": "icon.png",
5 | "commands": [
6 | {
7 | "name": "HTML fontbook",
8 | "shortcut": "ctrl shift f",
9 | "identifier": "html-fontbook-export",
10 | "script": "./html-fontbook-export.js"
11 | },
12 | {
13 | "name": "JSON",
14 | "shortcut": "ctrl shift j",
15 | "identifier": "json-export",
16 | "script": "./json-export.js"
17 | },
18 | {
19 | "name": "CSS classes",
20 | "shortcut": "ctrl shift c",
21 | "identifier": "css-export",
22 | "script": "./css-export.js"
23 | },
24 | {
25 | "name": "SASS mixins",
26 | "shortcut": "ctrl shift s",
27 | "identifier": "sass-mixins-export",
28 | "script": "./sass-mixins-export.js"
29 | }
30 | ],
31 | "menu": {
32 | "title": "Typex (Text style export)",
33 | "items": [
34 | {
35 | "title": "Export",
36 | "items": [
37 | "html-fontbook-export",
38 | "json-export",
39 | "css-export",
40 | "sass-mixins-export"
41 | ]
42 | }
43 | ]
44 | }
45 | }
--------------------------------------------------------------------------------
/src/sass-mixins-export.js:
--------------------------------------------------------------------------------
1 | import ui from './util/ui';
2 | import stringUtils from './util/string';
3 | import exportUtils from './util/export';
4 |
5 | import openExportDialog from './export/open-export-dialog';
6 |
7 | export default function(context) {
8 |
9 | openExportDialog(context, {
10 | title: 'SASS mixins export',
11 | informativeText: 'Export each text style as a SASS mixin'
12 | }, (textStyles, data) => {
13 |
14 | let sass = {};
15 |
16 | textStyles.forEach(textStyle => {
17 | sass[stringUtils.slugify(textStyle.name)] = exportUtils.createCssProps(textStyle, data);
18 | });
19 |
20 | let output = '';
21 | let i = 0;
22 |
23 | for (let identifier in sass) {
24 |
25 | if (sass.hasOwnProperty(identifier)) {
26 |
27 | let mixinName = data.namingPrefix + '-' + (data.namingConvention === 'Numeric' ? i+1 : identifier);
28 |
29 | output += ( i !== 0 ? "\n" : '' ) + '@mixin ' + mixinName + "\n";
30 | output += '{'+"\n";
31 | output += exportUtils.createStyleBlock(sass[identifier]);
32 | output += '}'+"\n";
33 | i++;
34 | }
35 | }
36 |
37 | ui.createSavePanel('typex-mixins.scss', output);
38 | });
39 | };
--------------------------------------------------------------------------------
/src/util/export.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | import util from './util';
4 | import numberUtils from './number';
5 |
6 | const exportUtils = {
7 | sortTextStyles(textStyles) {
8 |
9 | // Sort text styles by size
10 | textStyles.sort((a, b) => {
11 | return a.fontSize - b.fontSize;
12 | });
13 |
14 | return textStyles;
15 | },
16 | excludeTextStyleProperties(textStyles, excludedProps = []) {
17 |
18 | textStyles.forEach(textStyle => {
19 | excludedProps.forEach(prop => {
20 | if (textStyle[prop]) {
21 | delete textStyle[prop];
22 | }
23 | });
24 | });
25 |
26 | return textStyles;
27 | },
28 | removeDoubleTextStyles(textStyles) {
29 |
30 | let uniqueTextStyles = {};
31 | let filtered = [];
32 |
33 | textStyles.forEach((textStyle, i) => {
34 |
35 | let id = util.createTextStyleId(textStyle);
36 |
37 | if (! uniqueTextStyles[id]) {
38 | uniqueTextStyles[id] = true;
39 | filtered.push(textStyle);
40 | }
41 | });
42 |
43 | return filtered;
44 | },
45 | createCssProps(textStyle, opts = {}) {
46 |
47 | opts.cssUnit = opts.cssUnit || 0;
48 | opts.scalingFactor = opts.scalingFactor || 1;
49 | opts.maxDecimalPlaces = opts.maxDecimalPlaces || 2;
50 |
51 | let cssProps = {};
52 |
53 | cssProps['font-family'] = textStyle.fontFamily;
54 | cssProps['font-weight'] = 400;
55 | cssProps['text-transform'] = 'none';
56 |
57 | let fontParts = textStyle.fontFamily.split('-');
58 |
59 | let fontWeightMap = {
60 | 'Thin': 100,
61 | 'Light': 300,
62 | 'Regular': 400,
63 | 'Medium': 500,
64 | 'Bold': 700,
65 | 'Black': 900
66 | };
67 |
68 | if (fontParts[1] && fontWeightMap[fontParts[1]]) {
69 | cssProps['font-family'] = fontParts[0];
70 | cssProps['font-weight'] = fontWeightMap[fontParts[1]];
71 | }
72 |
73 | cssProps['font-size'] = numberUtils.parseFloatMaxDecimal(opts.scalingFactor * textStyle.fontSize, opts.maxDecimalPlaces)+opts.cssUnit;
74 | cssProps['letter-spacing'] = numberUtils.parseFloatMaxDecimal(opts.scalingFactor * textStyle.letterSpacing, opts.maxDecimalPlaces)+opts.cssUnit;
75 |
76 | if (textStyle.textTransform === 1) {
77 | cssProps['text-transform'] = 'uppercase';
78 | }
79 |
80 | if (textStyle.textTransform === 2) {
81 | cssProps['text-transform'] = 'lowercase';
82 | }
83 |
84 | if (textStyle.lineHeight) {
85 | cssProps['line-height'] = numberUtils.parseFloatMaxDecimal(1 + (textStyle.lineHeight - textStyle.fontSize) / textStyle.lineHeight, opts.maxDecimalPlaces);
86 | }
87 |
88 | if (textStyle.color) {
89 | cssProps['color'] = exportUtils.createRgbaString(textStyle.color);
90 | }
91 |
92 | return cssProps;
93 | },
94 | createRgbaString(colorObj) {
95 | return 'rgba('+exportUtils.createColorValue(colorObj.r)+', '+exportUtils.createColorValue(colorObj.g)+', '+exportUtils.createColorValue(colorObj.b)+', '+colorObj.a+')';
96 | },
97 | createColorValue(normalizedValue) {
98 | return Math.round(normalizedValue * 255);
99 | },
100 | createStyleBlock(cssProps) {
101 |
102 | let output = '';
103 |
104 | for (let prop in cssProps) {
105 | output += "\t"+prop+': '+cssProps[prop]+';'+"\n";
106 | }
107 |
108 | return output;
109 | },
110 | createInlineStyleString(cssProps) {
111 |
112 | let styleString = '';
113 |
114 | for (let prop in cssProps) {
115 | styleString += prop + ': ' + cssProps[prop] +'; ';
116 | }
117 |
118 | return styleString;
119 | },
120 | createHtmlFontbook(textStyles, opts = {}) {
121 |
122 | let output = `
123 |
124 |
125 |
126 |
127 | Typex text styles
128 |
129 |
130 | `;
131 |
132 | textStyles.forEach((textStyle, i) => {
133 |
134 | let cssProps = exportUtils.createCssProps(textStyle, opts);
135 | let inlineStyleString = exportUtils.createInlineStyleString(cssProps);
136 | let cssPropsBlock = exportUtils.createStyleBlock(cssProps);
137 |
138 | let textStyleName;
139 |
140 | if (opts.namingConvention === 'Numeric') {
141 |
142 | textStyleName = opts.namingPrefix + ' ' + (i+1);
143 |
144 | } else if (opts.namingConvention === 'Text style name') {
145 |
146 | textStyleName = opts.namingPrefix + ' ' + textStyle.name;
147 |
148 | } else {
149 |
150 | textStyleName = opts.namingPrefix + ' ' + (i+1) + ' ('+textStyle.name+')';
151 | }
152 |
153 | output += `
154 |
155 |
156 | ${i+1}.
157 |
158 | ${textStyleName}
159 |
160 |
161 |
162 |
163 | The quick brown fox jumps over the lazy dog
164 |
165 |
166 |
167 |
168 |
169 |
170 | `;
171 | });
172 |
173 | output += `
174 |
175 |
176 | `;
177 |
178 | return output;
179 | }
180 | };
181 |
182 | export default exportUtils;
--------------------------------------------------------------------------------
/src/util/number.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const number = {
4 | parseFloatMaxDecimal(number, maxDecimalPlaces) {
5 | return Number(number.toFixed(maxDecimalPlaces).replace(/[.,]00$/, ''));
6 | }
7 | };
8 |
9 | export default number;
--------------------------------------------------------------------------------
/src/util/sketch.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const sketch = {
4 | getTextStyles(context) {
5 |
6 | let texts = context.document.documentData().layerTextStyles().objects();
7 | let rawTextStyles = [];
8 |
9 | texts.forEach((text, i) => {
10 |
11 | rawTextStyles.push({
12 | attributes: text.style().textStyle().attributes(),
13 | textStyle: text,
14 | name: text.name()
15 | });
16 | });
17 |
18 | let textStyles = [];
19 |
20 | rawTextStyles.forEach(rawTextStyle => {
21 |
22 | let textStyle = {};
23 |
24 | textStyle.name = rawTextStyle.name;
25 | textStyle.fontFamily = String(rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontNameAttribute));
26 | textStyle.fontSize = rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontSizeAttribute);
27 | textStyle.paragraph = rawTextStyle.attributes.NSParagraphStyle;
28 |
29 | if (textStyle.paragraph) {
30 | textStyle.lineHeight = textStyle.paragraph.maximumLineHeight();
31 | }
32 |
33 | let color = rawTextStyle.attributes.MSAttributedStringColorAttribute;
34 |
35 | if (color) {
36 | let r = color.red();
37 | let g = color.green();
38 | let b = color.blue();
39 | let a = color.alpha();
40 |
41 | textStyle.color = {
42 | r: r,
43 | g: g,
44 | b: b,
45 | a: a
46 | };
47 | }
48 |
49 | textStyle.letterSpacing = rawTextStyle.attributes.NSKern || 0;
50 | textStyle.textTransform = parseInt(rawTextStyle.attributes.MSAttributedStringTextTransformAttribute || 0);
51 |
52 | // @TODO strikethrough & underline, or is this not needed?
53 |
54 | textStyles.push(textStyle);
55 | });
56 |
57 | return textStyles;
58 | }
59 | };
60 |
61 | export default sketch;
--------------------------------------------------------------------------------
/src/util/string.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const string = {
4 | slugify(str) {
5 |
6 | str = str.replace(/^\s+|\s+$/g, ''); // trim
7 | str = str.toLowerCase();
8 |
9 | // remove accents, swap ñ for n, etc
10 | let from = 'àáäâèéëêìíïîòóöôùúüûñç·/_,:;';
11 | let to = 'aaaaeeeeiiiioooouuuunc------';
12 |
13 | for (let i = 0, l = from.length; i < l; i++) {
14 | str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
15 | }
16 |
17 | str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
18 | .replace(/\s+/g, '-') // collapse whitespace and replace by -
19 | .replace(/-+/g, '-') // collapse dashes
20 | ;
21 |
22 | return str;
23 | }
24 | };
25 |
26 | export default string;
--------------------------------------------------------------------------------
/src/util/ui.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const ui = {
4 | createSavePanel(defaultFileName, contents) {
5 |
6 | let save = NSSavePanel.savePanel();
7 |
8 | save.setNameFieldStringValue(defaultFileName);
9 | save.setAllowsOtherFileTypes(false);
10 | save.setExtensionHidden(false);
11 |
12 | if (save.runModal()) {
13 |
14 | let file = NSString.stringWithString(contents);
15 | let path = save.URL().path();
16 |
17 | file.writeToFile_atomically_encoding_error(path, true, NSUTF8StringEncoding, null);
18 | }
19 | },
20 | createLabel: (text = '') => {
21 |
22 | let label = NSTextField.alloc().init();
23 |
24 | label.setStringValue(text);
25 | label.setFont(NSFont.boldSystemFontOfSize(12));
26 | label.setBezeled(false);
27 | label.setDrawsBackground(false);
28 | label.setEditable(false);
29 | label.setSelectable(false);
30 |
31 | return label;
32 | },
33 | createTextField(value) {
34 |
35 | let field = NSTextField.alloc().init();
36 |
37 | field.setStringValue(value);
38 |
39 | return field;
40 | },
41 | createSelect: (options) => {
42 |
43 | let comboBox = NSPopUpButton.alloc().init();
44 |
45 | comboBox.addItemsWithTitles(options);
46 | comboBox.selectItemAtIndex(0);
47 |
48 | return comboBox;
49 | },
50 | createStepper: (value) => {
51 |
52 | let stepper = NSStepper.alloc().init();
53 | return stepper;
54 | },
55 | createCheckbox: (title) => {
56 |
57 | let checkbox = NSButton.alloc().init();
58 | checkbox.setButtonType(NSSwitchButton);
59 | checkbox.title = title;
60 | return checkbox;
61 | },
62 | createSettingsDialog(context, opts = {}, components, cb) {
63 |
64 | opts.title = opts.title || 'Alert';
65 | opts.informativeText = opts.informativeText || '';
66 | opts.cancelBtnText = opts.cancelBtnText || 'Cancel';
67 | opts.confirmBtnText = opts.confirmBtnText || 'Ok';
68 |
69 | let dialog = NSAlert.alloc().init();
70 | let dialogIconPath = context.plugin.urlForResourceNamed('icon.png').path();
71 | let dialogIcon = NSImage.alloc().initByReferencingFile(dialogIconPath);
72 |
73 | dialog.setIcon(dialogIcon);
74 | dialog.setMessageText(opts.title);
75 | dialog.setInformativeText(opts.informativeText);
76 |
77 | let btnConfirm = dialog.addButtonWithTitle(opts.confirmBtnText);
78 | let btnCancel = dialog.addButtonWithTitle(opts.cancelBtnText);
79 |
80 | // Create grid view
81 | let gridView = NSGridView.alloc().init();
82 |
83 | // Create object to hold all inputs
84 | let inputs = {};
85 | let height = 0;
86 |
87 | let rowSpacing = 8;
88 |
89 | // Loop each component
90 | components.forEach(c => {
91 |
92 | let label, field;
93 |
94 | switch (c.type) {
95 |
96 | case 'text':
97 |
98 | label = ui.createLabel(c.label);
99 | field = ui.createTextField(c.value);
100 | height += 22 + rowSpacing;
101 | gridView.addRowWithViews([label, field]);
102 |
103 | break;
104 |
105 | case 'stepper':
106 |
107 | label = ui.createLabel(c.label);
108 | field = ui.createStepper(c.value);
109 | height += 22 + rowSpacing;
110 | gridView.addRowWithViews([label, field]);
111 |
112 | break;
113 |
114 | case 'checkbox':
115 |
116 | label = ui.createLabel(c.label);
117 | field = ui.createCheckbox(c.value);
118 | height += 22 + rowSpacing;
119 | gridView.addRowWithViews([label, field]);
120 |
121 | break;
122 |
123 | case 'multicheckbox':
124 |
125 | field = [];
126 |
127 | c.values.forEach((v, i) => {
128 |
129 | label = (i ? ui.createLabel() : ui.createLabel(c.label));
130 |
131 | let checkbox = ui.createCheckbox(v);
132 | height += 22 + rowSpacing;
133 |
134 | field.push(checkbox);
135 | gridView.addRowWithViews([label, checkbox]);
136 | });
137 |
138 | break;
139 |
140 | case 'select':
141 |
142 | label = ui.createLabel(c.label);
143 | field = ui.createSelect(c.options);
144 | height += 28 + rowSpacing;
145 | gridView.addRowWithViews([label, field]);
146 |
147 | break;
148 | }
149 |
150 | inputs[c.id] = field;
151 | });
152 |
153 | // Set grid view as view of dialog
154 | dialog.accessoryView = gridView;
155 |
156 | gridView.columnSpacing = 30;
157 | gridView.rowSpacing = rowSpacing;
158 | gridView.frame = NSMakeRect(0, 0, 400, height);
159 |
160 | // Open the dialog and store the response code
161 | let responseCode = dialog.runModal();
162 |
163 | // The dialog is being 'submitted'
164 | if (responseCode === 1000) {
165 |
166 | let data = {};
167 |
168 | components.forEach(c => {
169 |
170 | switch (c.type) {
171 | case 'text':
172 | data[c.id] = inputs[c.id].stringValue();
173 | break;
174 | case 'select':
175 | data[c.id] = c.options[inputs[c.id].indexOfSelectedItem()];
176 | break;
177 | case 'checkbox':
178 | data[c.id] = (inputs[c.id].state() === 1);
179 | break;
180 |
181 | case 'multicheckbox':
182 | let values = {};
183 |
184 | c.values.forEach((v, i) => {
185 | values[v] = ( inputs[c.id][i].state() === 1 );
186 | });
187 |
188 | data[c.id] = values;
189 | }
190 | });
191 |
192 | cb(data);
193 | return;
194 | }
195 |
196 | return dialog;
197 | }
198 | };
199 |
200 | export default ui;
--------------------------------------------------------------------------------
/src/util/util.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const util = {
4 | createTextStyleId(textStyle) {
5 |
6 | let textStyleId = '';
7 |
8 | // Make sure this id incorporates every possible property of the text style
9 |
10 | textStyleId += textStyle.fontFamily;
11 | textStyleId += '-'+textStyle.fontSize;
12 | textStyleId += '-'+textStyle.letterSpacing;
13 | textStyleId += '-'+textStyle.textTransform;
14 |
15 | if (textStyle.lineHeight) {
16 | textStyleId += '-'+textStyle.lineHeight;
17 | }
18 |
19 | if (textStyle.color) {
20 | textStyleId += '-'+textStyle.color.r+'-'+textStyle.color.g+'-'+textStyle.color.b+'-'+textStyle.color.a;
21 | }
22 |
23 | return textStyleId;
24 | }
25 | };
26 |
27 | export default util;
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Resources/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/reinvanoyen/typex/297f2b00d5fb21793b0fa6060a1b031a326299b0/typex.sketchplugin/Contents/Resources/icon.png
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/advanced-json-export.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/advanced-json-export.js");
90 | /******/ })
91 | /************************************************************************/
92 | /******/ ({
93 |
94 | /***/ "./src/advanced-json-export.js":
95 | /*!*************************************!*\
96 | !*** ./src/advanced-json-export.js ***!
97 | \*************************************/
98 | /*! exports provided: default */
99 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
100 |
101 | "use strict";
102 | __webpack_require__.r(__webpack_exports__);
103 | /* harmony import */ var _util_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util/ui */ "./src/util/ui.js");
104 | /* harmony import */ var _util_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./util/string */ "./src/util/string.js");
105 | /* harmony import */ var _util_export__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./util/export */ "./src/util/export.js");
106 | /* harmony import */ var _export_open_export_dialog__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./export/open-export-dialog */ "./src/export/open-export-dialog.js");
107 |
108 |
109 |
110 |
111 | /* harmony default export */ __webpack_exports__["default"] = (function (context) {
112 | Object(_export_open_export_dialog__WEBPACK_IMPORTED_MODULE_3__["default"])(context, {
113 | title: 'JSON export',
114 | informativeText: 'Export text styles in JSON format'
115 | }, function (textStyles, data) {
116 | // Export as JSON
117 | var textStyleJson = {};
118 | textStyles.forEach(function (textStyle, i) {
119 | var textStyleIdentifier = _util_string__WEBPACK_IMPORTED_MODULE_1__["default"].slugify(textStyle.name);
120 | var stylePropertyNaming = data.namingPrefix + '-' + (data.namingConvention === 'Numeric' ? i + 1 : textStyleIdentifier);
121 | textStyleJson[stylePropertyNaming] = _util_export__WEBPACK_IMPORTED_MODULE_2__["default"].createCssProps(textStyle, data);
122 | }); // Ask the user to save the file
123 |
124 | _util_ui__WEBPACK_IMPORTED_MODULE_0__["default"].createSavePanel('typex-text-styles.json', JSON.stringify(textStyleJson));
125 | });
126 | });
127 | ;
128 |
129 | /***/ }),
130 |
131 | /***/ "./src/export/export-components.js":
132 | /*!*****************************************!*\
133 | !*** ./src/export/export-components.js ***!
134 | \*****************************************/
135 | /*! exports provided: default */
136 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
137 |
138 | "use strict";
139 | __webpack_require__.r(__webpack_exports__);
140 | /* harmony default export */ __webpack_exports__["default"] = ([{
141 | type: 'checkbox',
142 | id: 'merge',
143 | label: 'Merge',
144 | value: 'Merge identical styles'
145 | }, {
146 | type: 'multicheckbox',
147 | id: 'excludeProps',
148 | label: 'Exclude properties',
149 | values: ['Color', 'Line height']
150 | }, {
151 | type: 'select',
152 | id: 'cssUnit',
153 | options: ['px', 'em', 'rem', '%', 'vh', 'vw', 'No unit'],
154 | label: 'CSS unit'
155 | }, {
156 | type: 'text',
157 | id: 'scalingFactor',
158 | value: 1,
159 | label: 'Size scaling factor'
160 | }, {
161 | type: 'text',
162 | id: 'maxDecimalPlaces',
163 | value: 2,
164 | label: 'Maximal decimal places'
165 | }, {
166 | type: 'text',
167 | id: 'namingPrefix',
168 | value: 'type',
169 | label: 'Naming prefix'
170 | }, {
171 | type: 'select',
172 | id: 'namingConvention',
173 | options: ['Numeric', 'Text style name'],
174 | label: 'Naming convention'
175 | }]);
176 |
177 | /***/ }),
178 |
179 | /***/ "./src/export/open-export-dialog.js":
180 | /*!******************************************!*\
181 | !*** ./src/export/open-export-dialog.js ***!
182 | \******************************************/
183 | /*! exports provided: default */
184 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
185 |
186 | "use strict";
187 | __webpack_require__.r(__webpack_exports__);
188 | /* harmony import */ var _util_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../util/ui */ "./src/util/ui.js");
189 | /* harmony import */ var _util_export__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../util/export */ "./src/util/export.js");
190 | /* harmony import */ var _util_sketch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../util/sketch */ "./src/util/sketch.js");
191 | /* harmony import */ var _export_components__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./export-components */ "./src/export/export-components.js");
192 |
193 |
194 |
195 |
196 | /* harmony default export */ __webpack_exports__["default"] = (function (context, opts, cb) {
197 | _util_ui__WEBPACK_IMPORTED_MODULE_0__["default"].createSettingsDialog(context, opts, _export_components__WEBPACK_IMPORTED_MODULE_3__["default"], function (data) {
198 | // Defaults
199 | data.propertyNamingConvention = data.propertyNamingConvention || 'Numeric';
200 | data.cssUnit = data.cssUnit === 'No unit' ? 0 : data.cssUnit; // First store the properties we should exclude
201 |
202 | var excludeProps = [];
203 |
204 | if (data['excludeProps']['Color']) {
205 | excludeProps.push('color');
206 | }
207 |
208 | if (data['excludeProps']['Line height']) {
209 | excludeProps.push('lineHeight');
210 | } // Get the text styles from the Sketch document
211 |
212 |
213 | var textStyles = _util_sketch__WEBPACK_IMPORTED_MODULE_2__["default"].getTextStyles(context);
214 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].sortTextStyles(textStyles);
215 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].excludeTextStyleProperties(textStyles, excludeProps);
216 |
217 | if (data['merge']) {
218 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].removeDoubleTextStyles(textStyles);
219 | }
220 |
221 | cb(textStyles, data);
222 | });
223 | });
224 | ;
225 |
226 | /***/ }),
227 |
228 | /***/ "./src/util/export.js":
229 | /*!****************************!*\
230 | !*** ./src/util/export.js ***!
231 | \****************************/
232 | /*! exports provided: default */
233 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
234 |
235 | "use strict";
236 | __webpack_require__.r(__webpack_exports__);
237 | /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util */ "./src/util/util.js");
238 | /* harmony import */ var _number__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./number */ "./src/util/number.js");
239 |
240 |
241 |
242 |
243 | var exportUtils = {
244 | sortTextStyles: function sortTextStyles(textStyles) {
245 | // Sort text styles by size
246 | textStyles.sort(function (a, b) {
247 | return a.fontSize - b.fontSize;
248 | });
249 | return textStyles;
250 | },
251 | excludeTextStyleProperties: function excludeTextStyleProperties(textStyles) {
252 | var excludedProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
253 | textStyles.forEach(function (textStyle) {
254 | excludedProps.forEach(function (prop) {
255 | if (textStyle[prop]) {
256 | delete textStyle[prop];
257 | }
258 | });
259 | });
260 | return textStyles;
261 | },
262 | removeDoubleTextStyles: function removeDoubleTextStyles(textStyles) {
263 | var uniqueTextStyles = {};
264 | var filtered = [];
265 | textStyles.forEach(function (textStyle, i) {
266 | var id = _util__WEBPACK_IMPORTED_MODULE_0__["default"].createTextStyleId(textStyle);
267 |
268 | if (!uniqueTextStyles[id]) {
269 | uniqueTextStyles[id] = true;
270 | filtered.push(textStyle);
271 | }
272 | });
273 | return filtered;
274 | },
275 | createCssProps: function createCssProps(textStyle) {
276 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
277 | opts.cssUnit = opts.cssUnit || 0;
278 | opts.scalingFactor = opts.scalingFactor || 1;
279 | opts.maxDecimalPlaces = opts.maxDecimalPlaces || 2;
280 | var cssProps = {};
281 | cssProps['font-family'] = textStyle.fontFamily;
282 | cssProps['font-weight'] = 400;
283 | cssProps['text-transform'] = 'none';
284 | var fontParts = textStyle.fontFamily.split('-');
285 | var fontWeightMap = {
286 | 'Thin': 100,
287 | 'Light': 300,
288 | 'Regular': 400,
289 | 'Medium': 500,
290 | 'Bold': 700,
291 | 'Black': 900
292 | };
293 |
294 | if (fontParts[1] && fontWeightMap[fontParts[1]]) {
295 | cssProps['font-family'] = fontParts[0];
296 | cssProps['font-weight'] = fontWeightMap[fontParts[1]];
297 | }
298 |
299 | cssProps['font-size'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(opts.scalingFactor * textStyle.fontSize, opts.maxDecimalPlaces) + opts.cssUnit;
300 | cssProps['letter-spacing'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(opts.scalingFactor * textStyle.letterSpacing, opts.maxDecimalPlaces) + opts.cssUnit;
301 |
302 | if (textStyle.textTransform === 1) {
303 | cssProps['text-transform'] = 'uppercase';
304 | }
305 |
306 | if (textStyle.textTransform === 2) {
307 | cssProps['text-transform'] = 'lowercase';
308 | }
309 |
310 | if (textStyle.lineHeight) {
311 | cssProps['line-height'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(1 + (textStyle.lineHeight - textStyle.fontSize) / textStyle.lineHeight, opts.maxDecimalPlaces);
312 | }
313 |
314 | if (textStyle.color) {
315 | cssProps['color'] = exportUtils.createRgbaString(textStyle.color);
316 | }
317 |
318 | return cssProps;
319 | },
320 | createRgbaString: function createRgbaString(colorObj) {
321 | return 'rgba(' + exportUtils.createColorValue(colorObj.r) + ', ' + exportUtils.createColorValue(colorObj.g) + ', ' + exportUtils.createColorValue(colorObj.b) + ', ' + colorObj.a + ')';
322 | },
323 | createColorValue: function createColorValue(normalizedValue) {
324 | return Math.round(normalizedValue * 255);
325 | },
326 | createStyleBlock: function createStyleBlock(cssProps) {
327 | var output = '';
328 |
329 | for (var prop in cssProps) {
330 | output += "\t" + prop + ': ' + cssProps[prop] + ';' + "\n";
331 | }
332 |
333 | return output;
334 | },
335 | createInlineStyleString: function createInlineStyleString(cssProps) {
336 | var styleString = '';
337 |
338 | for (var prop in cssProps) {
339 | styleString += prop + ': ' + cssProps[prop] + '; ';
340 | }
341 |
342 | return styleString;
343 | },
344 | createHtmlFontbook: function createHtmlFontbook(textStyles) {
345 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
346 | var output = "\n \n \n \n \n Typex text styles\n \n \n ";
347 | textStyles.forEach(function (textStyle, i) {
348 | var cssProps = exportUtils.createCssProps(textStyle, opts);
349 | var inlineStyleString = exportUtils.createInlineStyleString(cssProps);
350 | var cssPropsBlock = exportUtils.createStyleBlock(cssProps);
351 | var textStyleName;
352 |
353 | if (opts.namingConvention === 'Numeric') {
354 | textStyleName = opts.namingPrefix + ' ' + (i + 1);
355 | } else if (opts.namingConvention === 'Text style name') {
356 | textStyleName = opts.namingPrefix + ' ' + textStyle.name;
357 | } else {
358 | textStyleName = opts.namingPrefix + ' ' + (i + 1) + ' (' + textStyle.name + ')';
359 | }
360 |
361 | output += "\n \n
\n ".concat(i + 1, ".\n \n ").concat(textStyleName, "\n \n
\n
\n
\n The quick brown fox jumps over the lazy dog\n
\n
\n \n
\n
\n
\n ");
362 | });
363 | output += "\n \n \n ";
364 | return output;
365 | }
366 | };
367 | /* harmony default export */ __webpack_exports__["default"] = (exportUtils);
368 |
369 | /***/ }),
370 |
371 | /***/ "./src/util/number.js":
372 | /*!****************************!*\
373 | !*** ./src/util/number.js ***!
374 | \****************************/
375 | /*! exports provided: default */
376 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
377 |
378 | "use strict";
379 | __webpack_require__.r(__webpack_exports__);
380 |
381 |
382 | var number = {
383 | parseFloatMaxDecimal: function parseFloatMaxDecimal(number, maxDecimalPlaces) {
384 | return Number(number.toFixed(maxDecimalPlaces).replace(/[.,]00$/, ''));
385 | }
386 | };
387 | /* harmony default export */ __webpack_exports__["default"] = (number);
388 |
389 | /***/ }),
390 |
391 | /***/ "./src/util/sketch.js":
392 | /*!****************************!*\
393 | !*** ./src/util/sketch.js ***!
394 | \****************************/
395 | /*! exports provided: default */
396 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
397 |
398 | "use strict";
399 | __webpack_require__.r(__webpack_exports__);
400 |
401 |
402 | var sketch = {
403 | getTextStyles: function getTextStyles(context) {
404 | var texts = context.document.documentData().layerTextStyles().objects();
405 | var rawTextStyles = [];
406 | texts.forEach(function (text, i) {
407 | rawTextStyles.push({
408 | attributes: text.style().textStyle().attributes(),
409 | textStyle: text,
410 | name: text.name()
411 | });
412 | });
413 | var textStyles = [];
414 | rawTextStyles.forEach(function (rawTextStyle) {
415 | var textStyle = {};
416 | textStyle.name = rawTextStyle.name;
417 | textStyle.fontFamily = String(rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontNameAttribute));
418 | textStyle.fontSize = rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontSizeAttribute);
419 | textStyle.paragraph = rawTextStyle.attributes.NSParagraphStyle;
420 |
421 | if (textStyle.paragraph) {
422 | textStyle.lineHeight = textStyle.paragraph.maximumLineHeight();
423 | }
424 |
425 | var color = rawTextStyle.attributes.MSAttributedStringColorAttribute;
426 |
427 | if (color) {
428 | var r = color.red();
429 | var g = color.green();
430 | var b = color.blue();
431 | var a = color.alpha();
432 | textStyle.color = {
433 | r: r,
434 | g: g,
435 | b: b,
436 | a: a
437 | };
438 | }
439 |
440 | textStyle.letterSpacing = rawTextStyle.attributes.NSKern || 0;
441 | textStyle.textTransform = parseInt(rawTextStyle.attributes.MSAttributedStringTextTransformAttribute || 0); // @TODO strikethrough & underline, or is this not needed?
442 |
443 | textStyles.push(textStyle);
444 | });
445 | return textStyles;
446 | }
447 | };
448 | /* harmony default export */ __webpack_exports__["default"] = (sketch);
449 |
450 | /***/ }),
451 |
452 | /***/ "./src/util/string.js":
453 | /*!****************************!*\
454 | !*** ./src/util/string.js ***!
455 | \****************************/
456 | /*! exports provided: default */
457 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
458 |
459 | "use strict";
460 | __webpack_require__.r(__webpack_exports__);
461 |
462 |
463 | var string = {
464 | slugify: function slugify(str) {
465 | str = str.replace(/^\s+|\s+$/g, ''); // trim
466 |
467 | str = str.toLowerCase(); // remove accents, swap ñ for n, etc
468 |
469 | var from = 'àáäâèéëêìíïîòóöôùúüûñç·/_,:;';
470 | var to = 'aaaaeeeeiiiioooouuuunc------';
471 |
472 | for (var i = 0, l = from.length; i < l; i++) {
473 | str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
474 | }
475 |
476 | str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
477 | .replace(/\s+/g, '-') // collapse whitespace and replace by -
478 | .replace(/-+/g, '-') // collapse dashes
479 | ;
480 | return str;
481 | }
482 | };
483 | /* harmony default export */ __webpack_exports__["default"] = (string);
484 |
485 | /***/ }),
486 |
487 | /***/ "./src/util/ui.js":
488 | /*!************************!*\
489 | !*** ./src/util/ui.js ***!
490 | \************************/
491 | /*! exports provided: default */
492 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
493 |
494 | "use strict";
495 | __webpack_require__.r(__webpack_exports__);
496 |
497 |
498 | var ui = {
499 | createSavePanel: function createSavePanel(defaultFileName, contents) {
500 | var save = NSSavePanel.savePanel();
501 | save.setNameFieldStringValue(defaultFileName);
502 | save.setAllowsOtherFileTypes(false);
503 | save.setExtensionHidden(false);
504 |
505 | if (save.runModal()) {
506 | var file = NSString.stringWithString(contents);
507 | var path = save.URL().path();
508 | file.writeToFile_atomically_encoding_error(path, true, NSUTF8StringEncoding, null);
509 | }
510 | },
511 | createLabel: function createLabel() {
512 | var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
513 | var label = NSTextField.alloc().init();
514 | label.setStringValue(text);
515 | label.setFont(NSFont.boldSystemFontOfSize(12));
516 | label.setBezeled(false);
517 | label.setDrawsBackground(false);
518 | label.setEditable(false);
519 | label.setSelectable(false);
520 | return label;
521 | },
522 | createTextField: function createTextField(value) {
523 | var field = NSTextField.alloc().init();
524 | field.setStringValue(value);
525 | return field;
526 | },
527 | createSelect: function createSelect(options) {
528 | var comboBox = NSPopUpButton.alloc().init();
529 | comboBox.addItemsWithTitles(options);
530 | comboBox.selectItemAtIndex(0);
531 | return comboBox;
532 | },
533 | createStepper: function createStepper(value) {
534 | var stepper = NSStepper.alloc().init();
535 | return stepper;
536 | },
537 | createCheckbox: function createCheckbox(title) {
538 | var checkbox = NSButton.alloc().init();
539 | checkbox.setButtonType(NSSwitchButton);
540 | checkbox.title = title;
541 | return checkbox;
542 | },
543 | createSettingsDialog: function createSettingsDialog(context) {
544 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
545 | var components = arguments.length > 2 ? arguments[2] : undefined;
546 | var cb = arguments.length > 3 ? arguments[3] : undefined;
547 | opts.title = opts.title || 'Alert';
548 | opts.informativeText = opts.informativeText || '';
549 | opts.cancelBtnText = opts.cancelBtnText || 'Cancel';
550 | opts.confirmBtnText = opts.confirmBtnText || 'Ok';
551 | var dialog = NSAlert.alloc().init();
552 | var dialogIconPath = context.plugin.urlForResourceNamed('icon.png').path();
553 | var dialogIcon = NSImage.alloc().initByReferencingFile(dialogIconPath);
554 | dialog.setIcon(dialogIcon);
555 | dialog.setMessageText(opts.title);
556 | dialog.setInformativeText(opts.informativeText);
557 | var btnConfirm = dialog.addButtonWithTitle(opts.confirmBtnText);
558 | var btnCancel = dialog.addButtonWithTitle(opts.cancelBtnText); // Create grid view
559 |
560 | var gridView = NSGridView.alloc().init(); // Create object to hold all inputs
561 |
562 | var inputs = {};
563 | var height = 0;
564 | var rowSpacing = 8; // Loop each component
565 |
566 | components.forEach(function (c) {
567 | var label, field;
568 |
569 | switch (c.type) {
570 | case 'text':
571 | label = ui.createLabel(c.label);
572 | field = ui.createTextField(c.value);
573 | height += 22 + rowSpacing;
574 | gridView.addRowWithViews([label, field]);
575 | break;
576 |
577 | case 'stepper':
578 | label = ui.createLabel(c.label);
579 | field = ui.createStepper(c.value);
580 | height += 22 + rowSpacing;
581 | gridView.addRowWithViews([label, field]);
582 | break;
583 |
584 | case 'checkbox':
585 | label = ui.createLabel(c.label);
586 | field = ui.createCheckbox(c.value);
587 | height += 22 + rowSpacing;
588 | gridView.addRowWithViews([label, field]);
589 | break;
590 |
591 | case 'multicheckbox':
592 | field = [];
593 | c.values.forEach(function (v, i) {
594 | label = i ? ui.createLabel() : ui.createLabel(c.label);
595 | var checkbox = ui.createCheckbox(v);
596 | height += 22 + rowSpacing;
597 | field.push(checkbox);
598 | gridView.addRowWithViews([label, checkbox]);
599 | });
600 | break;
601 |
602 | case 'select':
603 | label = ui.createLabel(c.label);
604 | field = ui.createSelect(c.options);
605 | height += 28 + rowSpacing;
606 | gridView.addRowWithViews([label, field]);
607 | break;
608 | }
609 |
610 | inputs[c.id] = field;
611 | }); // Set grid view as view of dialog
612 |
613 | dialog.accessoryView = gridView;
614 | gridView.columnSpacing = 30;
615 | gridView.rowSpacing = rowSpacing;
616 | gridView.frame = NSMakeRect(0, 0, 400, height); // Open the dialog and store the response code
617 |
618 | var responseCode = dialog.runModal(); // The dialog is being 'submitted'
619 |
620 | if (responseCode === 1000) {
621 | var data = {};
622 | components.forEach(function (c) {
623 | switch (c.type) {
624 | case 'text':
625 | data[c.id] = inputs[c.id].stringValue();
626 | break;
627 |
628 | case 'select':
629 | data[c.id] = c.options[inputs[c.id].indexOfSelectedItem()];
630 | break;
631 |
632 | case 'checkbox':
633 | data[c.id] = inputs[c.id].state() === 1;
634 | break;
635 |
636 | case 'multicheckbox':
637 | var values = {};
638 | c.values.forEach(function (v, i) {
639 | values[v] = inputs[c.id][i].state() === 1;
640 | });
641 | data[c.id] = values;
642 | }
643 | });
644 | cb(data);
645 | return;
646 | }
647 |
648 | return dialog;
649 | }
650 | };
651 | /* harmony default export */ __webpack_exports__["default"] = (ui);
652 |
653 | /***/ }),
654 |
655 | /***/ "./src/util/util.js":
656 | /*!**************************!*\
657 | !*** ./src/util/util.js ***!
658 | \**************************/
659 | /*! exports provided: default */
660 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
661 |
662 | "use strict";
663 | __webpack_require__.r(__webpack_exports__);
664 |
665 |
666 | var util = {
667 | createTextStyleId: function createTextStyleId(textStyle) {
668 | var textStyleId = ''; // Make sure this id incorporates every possible property of the text style
669 |
670 | textStyleId += textStyle.fontFamily;
671 | textStyleId += '-' + textStyle.fontSize;
672 | textStyleId += '-' + textStyle.letterSpacing;
673 | textStyleId += '-' + textStyle.textTransform;
674 |
675 | if (textStyle.lineHeight) {
676 | textStyleId += '-' + textStyle.lineHeight;
677 | }
678 |
679 | if (textStyle.color) {
680 | textStyleId += '-' + textStyle.color.r + '-' + textStyle.color.g + '-' + textStyle.color.b + '-' + textStyle.color.a;
681 | }
682 |
683 | return textStyleId;
684 | }
685 | };
686 | /* harmony default export */ __webpack_exports__["default"] = (util);
687 |
688 | /***/ })
689 |
690 | /******/ });
691 | if (key === 'default' && typeof exports === 'function') {
692 | exports(context);
693 | } else {
694 | exports[key](context);
695 | }
696 | }
697 | that['onRun'] = __skpm_run.bind(this, 'default')
698 |
699 | //# sourceMappingURL=advanced-json-export.js.map
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/css-export.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/css-export.js");
90 | /******/ })
91 | /************************************************************************/
92 | /******/ ({
93 |
94 | /***/ "./src/css-export.js":
95 | /*!***************************!*\
96 | !*** ./src/css-export.js ***!
97 | \***************************/
98 | /*! exports provided: default */
99 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
100 |
101 | "use strict";
102 | __webpack_require__.r(__webpack_exports__);
103 | /* harmony import */ var _util_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util/ui */ "./src/util/ui.js");
104 | /* harmony import */ var _util_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./util/string */ "./src/util/string.js");
105 | /* harmony import */ var _util_export__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./util/export */ "./src/util/export.js");
106 | /* harmony import */ var _export_open_export_dialog__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./export/open-export-dialog */ "./src/export/open-export-dialog.js");
107 |
108 |
109 |
110 |
111 | /* harmony default export */ __webpack_exports__["default"] = (function (context) {
112 | Object(_export_open_export_dialog__WEBPACK_IMPORTED_MODULE_3__["default"])(context, {
113 | title: 'CSS classes export',
114 | informativeText: 'Export each text style as a class'
115 | }, function (textStyles, data) {
116 | var css = {};
117 | textStyles.forEach(function (textStyle) {
118 | css[_util_string__WEBPACK_IMPORTED_MODULE_1__["default"].slugify(textStyle.name)] = _util_export__WEBPACK_IMPORTED_MODULE_2__["default"].createCssProps(textStyle, data);
119 | });
120 | var output = '';
121 | var i = 0;
122 |
123 | for (var identifier in css) {
124 | if (css.hasOwnProperty(identifier)) {
125 | var className = data.namingPrefix + '-' + (data.namingConvention === 'Numeric' ? i + 1 : identifier);
126 | output += (i !== 0 ? "\n" : '') + '.' + className + "\n";
127 | output += '{' + "\n";
128 | output += _util_export__WEBPACK_IMPORTED_MODULE_2__["default"].createStyleBlock(css[identifier]);
129 | output += '}' + "\n";
130 | i++;
131 | }
132 | }
133 |
134 | _util_ui__WEBPACK_IMPORTED_MODULE_0__["default"].createSavePanel('typex-stylesheet.css', output);
135 | });
136 | });
137 | ;
138 |
139 | /***/ }),
140 |
141 | /***/ "./src/export/export-components.js":
142 | /*!*****************************************!*\
143 | !*** ./src/export/export-components.js ***!
144 | \*****************************************/
145 | /*! exports provided: default */
146 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
147 |
148 | "use strict";
149 | __webpack_require__.r(__webpack_exports__);
150 | /* harmony default export */ __webpack_exports__["default"] = ([{
151 | type: 'checkbox',
152 | id: 'merge',
153 | label: 'Merge',
154 | value: 'Merge identical styles'
155 | }, {
156 | type: 'multicheckbox',
157 | id: 'excludeProps',
158 | label: 'Exclude properties',
159 | values: ['Color', 'Line height']
160 | }, {
161 | type: 'select',
162 | id: 'cssUnit',
163 | options: ['px', 'em', 'rem', '%', 'vh', 'vw', 'No unit'],
164 | label: 'CSS unit'
165 | }, {
166 | type: 'text',
167 | id: 'scalingFactor',
168 | value: 1,
169 | label: 'Size scaling factor'
170 | }, {
171 | type: 'text',
172 | id: 'maxDecimalPlaces',
173 | value: 2,
174 | label: 'Maximal decimal places'
175 | }, {
176 | type: 'text',
177 | id: 'namingPrefix',
178 | value: 'type',
179 | label: 'Naming prefix'
180 | }, {
181 | type: 'select',
182 | id: 'namingConvention',
183 | options: ['Numeric', 'Text style name'],
184 | label: 'Naming convention'
185 | }]);
186 |
187 | /***/ }),
188 |
189 | /***/ "./src/export/open-export-dialog.js":
190 | /*!******************************************!*\
191 | !*** ./src/export/open-export-dialog.js ***!
192 | \******************************************/
193 | /*! exports provided: default */
194 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
195 |
196 | "use strict";
197 | __webpack_require__.r(__webpack_exports__);
198 | /* harmony import */ var _util_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../util/ui */ "./src/util/ui.js");
199 | /* harmony import */ var _util_export__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../util/export */ "./src/util/export.js");
200 | /* harmony import */ var _util_sketch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../util/sketch */ "./src/util/sketch.js");
201 | /* harmony import */ var _export_components__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./export-components */ "./src/export/export-components.js");
202 |
203 |
204 |
205 |
206 | /* harmony default export */ __webpack_exports__["default"] = (function (context, opts, cb) {
207 | _util_ui__WEBPACK_IMPORTED_MODULE_0__["default"].createSettingsDialog(context, opts, _export_components__WEBPACK_IMPORTED_MODULE_3__["default"], function (data) {
208 | // Defaults
209 | data.propertyNamingConvention = data.propertyNamingConvention || 'Numeric';
210 | data.cssUnit = data.cssUnit === 'No unit' ? 0 : data.cssUnit; // First store the properties we should exclude
211 |
212 | var excludeProps = [];
213 |
214 | if (data['excludeProps']['Color']) {
215 | excludeProps.push('color');
216 | }
217 |
218 | if (data['excludeProps']['Line height']) {
219 | excludeProps.push('lineHeight');
220 | } // Get the text styles from the Sketch document
221 |
222 |
223 | var textStyles = _util_sketch__WEBPACK_IMPORTED_MODULE_2__["default"].getTextStyles(context);
224 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].sortTextStyles(textStyles);
225 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].excludeTextStyleProperties(textStyles, excludeProps);
226 |
227 | if (data['merge']) {
228 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].removeDoubleTextStyles(textStyles);
229 | }
230 |
231 | cb(textStyles, data);
232 | });
233 | });
234 | ;
235 |
236 | /***/ }),
237 |
238 | /***/ "./src/util/export.js":
239 | /*!****************************!*\
240 | !*** ./src/util/export.js ***!
241 | \****************************/
242 | /*! exports provided: default */
243 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
244 |
245 | "use strict";
246 | __webpack_require__.r(__webpack_exports__);
247 | /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util */ "./src/util/util.js");
248 | /* harmony import */ var _number__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./number */ "./src/util/number.js");
249 |
250 |
251 |
252 |
253 | var exportUtils = {
254 | sortTextStyles: function sortTextStyles(textStyles) {
255 | // Sort text styles by size
256 | textStyles.sort(function (a, b) {
257 | return a.fontSize - b.fontSize;
258 | });
259 | return textStyles;
260 | },
261 | excludeTextStyleProperties: function excludeTextStyleProperties(textStyles) {
262 | var excludedProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
263 | textStyles.forEach(function (textStyle) {
264 | excludedProps.forEach(function (prop) {
265 | if (textStyle[prop]) {
266 | delete textStyle[prop];
267 | }
268 | });
269 | });
270 | return textStyles;
271 | },
272 | removeDoubleTextStyles: function removeDoubleTextStyles(textStyles) {
273 | var uniqueTextStyles = {};
274 | var filtered = [];
275 | textStyles.forEach(function (textStyle, i) {
276 | var id = _util__WEBPACK_IMPORTED_MODULE_0__["default"].createTextStyleId(textStyle);
277 |
278 | if (!uniqueTextStyles[id]) {
279 | uniqueTextStyles[id] = true;
280 | filtered.push(textStyle);
281 | }
282 | });
283 | return filtered;
284 | },
285 | createCssProps: function createCssProps(textStyle) {
286 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
287 | opts.cssUnit = opts.cssUnit || 0;
288 | opts.scalingFactor = opts.scalingFactor || 1;
289 | opts.maxDecimalPlaces = opts.maxDecimalPlaces || 2;
290 | var cssProps = {};
291 | cssProps['font-family'] = textStyle.fontFamily;
292 | cssProps['font-weight'] = 400;
293 | cssProps['text-transform'] = 'none';
294 | var fontParts = textStyle.fontFamily.split('-');
295 | var fontWeightMap = {
296 | 'Thin': 100,
297 | 'Light': 300,
298 | 'Regular': 400,
299 | 'Medium': 500,
300 | 'Bold': 700,
301 | 'Black': 900
302 | };
303 |
304 | if (fontParts[1] && fontWeightMap[fontParts[1]]) {
305 | cssProps['font-family'] = fontParts[0];
306 | cssProps['font-weight'] = fontWeightMap[fontParts[1]];
307 | }
308 |
309 | cssProps['font-size'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(opts.scalingFactor * textStyle.fontSize, opts.maxDecimalPlaces) + opts.cssUnit;
310 | cssProps['letter-spacing'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(opts.scalingFactor * textStyle.letterSpacing, opts.maxDecimalPlaces) + opts.cssUnit;
311 |
312 | if (textStyle.textTransform === 1) {
313 | cssProps['text-transform'] = 'uppercase';
314 | }
315 |
316 | if (textStyle.textTransform === 2) {
317 | cssProps['text-transform'] = 'lowercase';
318 | }
319 |
320 | if (textStyle.lineHeight) {
321 | cssProps['line-height'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(1 + (textStyle.lineHeight - textStyle.fontSize) / textStyle.lineHeight, opts.maxDecimalPlaces);
322 | }
323 |
324 | if (textStyle.color) {
325 | cssProps['color'] = exportUtils.createRgbaString(textStyle.color);
326 | }
327 |
328 | return cssProps;
329 | },
330 | createRgbaString: function createRgbaString(colorObj) {
331 | return 'rgba(' + exportUtils.createColorValue(colorObj.r) + ', ' + exportUtils.createColorValue(colorObj.g) + ', ' + exportUtils.createColorValue(colorObj.b) + ', ' + colorObj.a + ')';
332 | },
333 | createColorValue: function createColorValue(normalizedValue) {
334 | return Math.round(normalizedValue * 255);
335 | },
336 | createStyleBlock: function createStyleBlock(cssProps) {
337 | var output = '';
338 |
339 | for (var prop in cssProps) {
340 | output += "\t" + prop + ': ' + cssProps[prop] + ';' + "\n";
341 | }
342 |
343 | return output;
344 | },
345 | createInlineStyleString: function createInlineStyleString(cssProps) {
346 | var styleString = '';
347 |
348 | for (var prop in cssProps) {
349 | styleString += prop + ': ' + cssProps[prop] + '; ';
350 | }
351 |
352 | return styleString;
353 | },
354 | createHtmlFontbook: function createHtmlFontbook(textStyles) {
355 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
356 | var output = "\n \n \n \n \n Typex text styles\n \n \n ";
357 | textStyles.forEach(function (textStyle, i) {
358 | var cssProps = exportUtils.createCssProps(textStyle, opts);
359 | var inlineStyleString = exportUtils.createInlineStyleString(cssProps);
360 | var cssPropsBlock = exportUtils.createStyleBlock(cssProps);
361 | var textStyleName;
362 |
363 | if (opts.namingConvention === 'Numeric') {
364 | textStyleName = opts.namingPrefix + ' ' + (i + 1);
365 | } else if (opts.namingConvention === 'Text style name') {
366 | textStyleName = opts.namingPrefix + ' ' + textStyle.name;
367 | } else {
368 | textStyleName = opts.namingPrefix + ' ' + (i + 1) + ' (' + textStyle.name + ')';
369 | }
370 |
371 | output += "\n \n
\n ".concat(i + 1, ".\n \n ").concat(textStyleName, "\n \n
\n
\n
\n The quick brown fox jumps over the lazy dog\n
\n
\n \n
\n
\n
\n ");
372 | });
373 | output += "\n \n \n ";
374 | return output;
375 | }
376 | };
377 | /* harmony default export */ __webpack_exports__["default"] = (exportUtils);
378 |
379 | /***/ }),
380 |
381 | /***/ "./src/util/number.js":
382 | /*!****************************!*\
383 | !*** ./src/util/number.js ***!
384 | \****************************/
385 | /*! exports provided: default */
386 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
387 |
388 | "use strict";
389 | __webpack_require__.r(__webpack_exports__);
390 |
391 |
392 | var number = {
393 | parseFloatMaxDecimal: function parseFloatMaxDecimal(number, maxDecimalPlaces) {
394 | return Number(number.toFixed(maxDecimalPlaces).replace(/[.,]00$/, ''));
395 | }
396 | };
397 | /* harmony default export */ __webpack_exports__["default"] = (number);
398 |
399 | /***/ }),
400 |
401 | /***/ "./src/util/sketch.js":
402 | /*!****************************!*\
403 | !*** ./src/util/sketch.js ***!
404 | \****************************/
405 | /*! exports provided: default */
406 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
407 |
408 | "use strict";
409 | __webpack_require__.r(__webpack_exports__);
410 |
411 |
412 | var sketch = {
413 | getTextStyles: function getTextStyles(context) {
414 | var texts = context.document.documentData().layerTextStyles().objects();
415 | var rawTextStyles = [];
416 | texts.forEach(function (text, i) {
417 | rawTextStyles.push({
418 | attributes: text.style().textStyle().attributes(),
419 | textStyle: text,
420 | name: text.name()
421 | });
422 | });
423 | var textStyles = [];
424 | rawTextStyles.forEach(function (rawTextStyle) {
425 | var textStyle = {};
426 | textStyle.name = rawTextStyle.name;
427 | textStyle.fontFamily = String(rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontNameAttribute));
428 | textStyle.fontSize = rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontSizeAttribute);
429 | textStyle.paragraph = rawTextStyle.attributes.NSParagraphStyle;
430 |
431 | if (textStyle.paragraph) {
432 | textStyle.lineHeight = textStyle.paragraph.maximumLineHeight();
433 | }
434 |
435 | var color = rawTextStyle.attributes.MSAttributedStringColorAttribute;
436 |
437 | if (color) {
438 | var r = color.red();
439 | var g = color.green();
440 | var b = color.blue();
441 | var a = color.alpha();
442 | textStyle.color = {
443 | r: r,
444 | g: g,
445 | b: b,
446 | a: a
447 | };
448 | }
449 |
450 | textStyle.letterSpacing = rawTextStyle.attributes.NSKern || 0;
451 | textStyle.textTransform = parseInt(rawTextStyle.attributes.MSAttributedStringTextTransformAttribute || 0); // @TODO strikethrough & underline, or is this not needed?
452 |
453 | textStyles.push(textStyle);
454 | });
455 | return textStyles;
456 | }
457 | };
458 | /* harmony default export */ __webpack_exports__["default"] = (sketch);
459 |
460 | /***/ }),
461 |
462 | /***/ "./src/util/string.js":
463 | /*!****************************!*\
464 | !*** ./src/util/string.js ***!
465 | \****************************/
466 | /*! exports provided: default */
467 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
468 |
469 | "use strict";
470 | __webpack_require__.r(__webpack_exports__);
471 |
472 |
473 | var string = {
474 | slugify: function slugify(str) {
475 | str = str.replace(/^\s+|\s+$/g, ''); // trim
476 |
477 | str = str.toLowerCase(); // remove accents, swap ñ for n, etc
478 |
479 | var from = 'àáäâèéëêìíïîòóöôùúüûñç·/_,:;';
480 | var to = 'aaaaeeeeiiiioooouuuunc------';
481 |
482 | for (var i = 0, l = from.length; i < l; i++) {
483 | str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
484 | }
485 |
486 | str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
487 | .replace(/\s+/g, '-') // collapse whitespace and replace by -
488 | .replace(/-+/g, '-') // collapse dashes
489 | ;
490 | return str;
491 | }
492 | };
493 | /* harmony default export */ __webpack_exports__["default"] = (string);
494 |
495 | /***/ }),
496 |
497 | /***/ "./src/util/ui.js":
498 | /*!************************!*\
499 | !*** ./src/util/ui.js ***!
500 | \************************/
501 | /*! exports provided: default */
502 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
503 |
504 | "use strict";
505 | __webpack_require__.r(__webpack_exports__);
506 |
507 |
508 | var ui = {
509 | createSavePanel: function createSavePanel(defaultFileName, contents) {
510 | var save = NSSavePanel.savePanel();
511 | save.setNameFieldStringValue(defaultFileName);
512 | save.setAllowsOtherFileTypes(false);
513 | save.setExtensionHidden(false);
514 |
515 | if (save.runModal()) {
516 | var file = NSString.stringWithString(contents);
517 | var path = save.URL().path();
518 | file.writeToFile_atomically_encoding_error(path, true, NSUTF8StringEncoding, null);
519 | }
520 | },
521 | createLabel: function createLabel() {
522 | var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
523 | var label = NSTextField.alloc().init();
524 | label.setStringValue(text);
525 | label.setFont(NSFont.boldSystemFontOfSize(12));
526 | label.setBezeled(false);
527 | label.setDrawsBackground(false);
528 | label.setEditable(false);
529 | label.setSelectable(false);
530 | return label;
531 | },
532 | createTextField: function createTextField(value) {
533 | var field = NSTextField.alloc().init();
534 | field.setStringValue(value);
535 | return field;
536 | },
537 | createSelect: function createSelect(options) {
538 | var comboBox = NSPopUpButton.alloc().init();
539 | comboBox.addItemsWithTitles(options);
540 | comboBox.selectItemAtIndex(0);
541 | return comboBox;
542 | },
543 | createStepper: function createStepper(value) {
544 | var stepper = NSStepper.alloc().init();
545 | return stepper;
546 | },
547 | createCheckbox: function createCheckbox(title) {
548 | var checkbox = NSButton.alloc().init();
549 | checkbox.setButtonType(NSSwitchButton);
550 | checkbox.title = title;
551 | return checkbox;
552 | },
553 | createSettingsDialog: function createSettingsDialog(context) {
554 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
555 | var components = arguments.length > 2 ? arguments[2] : undefined;
556 | var cb = arguments.length > 3 ? arguments[3] : undefined;
557 | opts.title = opts.title || 'Alert';
558 | opts.informativeText = opts.informativeText || '';
559 | opts.cancelBtnText = opts.cancelBtnText || 'Cancel';
560 | opts.confirmBtnText = opts.confirmBtnText || 'Ok';
561 | var dialog = NSAlert.alloc().init();
562 | var dialogIconPath = context.plugin.urlForResourceNamed('icon.png').path();
563 | var dialogIcon = NSImage.alloc().initByReferencingFile(dialogIconPath);
564 | dialog.setIcon(dialogIcon);
565 | dialog.setMessageText(opts.title);
566 | dialog.setInformativeText(opts.informativeText);
567 | var btnConfirm = dialog.addButtonWithTitle(opts.confirmBtnText);
568 | var btnCancel = dialog.addButtonWithTitle(opts.cancelBtnText); // Create grid view
569 |
570 | var gridView = NSGridView.alloc().init(); // Create object to hold all inputs
571 |
572 | var inputs = {};
573 | var height = 0;
574 | var rowSpacing = 8; // Loop each component
575 |
576 | components.forEach(function (c) {
577 | var label, field;
578 |
579 | switch (c.type) {
580 | case 'text':
581 | label = ui.createLabel(c.label);
582 | field = ui.createTextField(c.value);
583 | height += 22 + rowSpacing;
584 | gridView.addRowWithViews([label, field]);
585 | break;
586 |
587 | case 'stepper':
588 | label = ui.createLabel(c.label);
589 | field = ui.createStepper(c.value);
590 | height += 22 + rowSpacing;
591 | gridView.addRowWithViews([label, field]);
592 | break;
593 |
594 | case 'checkbox':
595 | label = ui.createLabel(c.label);
596 | field = ui.createCheckbox(c.value);
597 | height += 22 + rowSpacing;
598 | gridView.addRowWithViews([label, field]);
599 | break;
600 |
601 | case 'multicheckbox':
602 | field = [];
603 | c.values.forEach(function (v, i) {
604 | label = i ? ui.createLabel() : ui.createLabel(c.label);
605 | var checkbox = ui.createCheckbox(v);
606 | height += 22 + rowSpacing;
607 | field.push(checkbox);
608 | gridView.addRowWithViews([label, checkbox]);
609 | });
610 | break;
611 |
612 | case 'select':
613 | label = ui.createLabel(c.label);
614 | field = ui.createSelect(c.options);
615 | height += 28 + rowSpacing;
616 | gridView.addRowWithViews([label, field]);
617 | break;
618 | }
619 |
620 | inputs[c.id] = field;
621 | }); // Set grid view as view of dialog
622 |
623 | dialog.accessoryView = gridView;
624 | gridView.columnSpacing = 30;
625 | gridView.rowSpacing = rowSpacing;
626 | gridView.frame = NSMakeRect(0, 0, 400, height); // Open the dialog and store the response code
627 |
628 | var responseCode = dialog.runModal(); // The dialog is being 'submitted'
629 |
630 | if (responseCode === 1000) {
631 | var data = {};
632 | components.forEach(function (c) {
633 | switch (c.type) {
634 | case 'text':
635 | data[c.id] = inputs[c.id].stringValue();
636 | break;
637 |
638 | case 'select':
639 | data[c.id] = c.options[inputs[c.id].indexOfSelectedItem()];
640 | break;
641 |
642 | case 'checkbox':
643 | data[c.id] = inputs[c.id].state() === 1;
644 | break;
645 |
646 | case 'multicheckbox':
647 | var values = {};
648 | c.values.forEach(function (v, i) {
649 | values[v] = inputs[c.id][i].state() === 1;
650 | });
651 | data[c.id] = values;
652 | }
653 | });
654 | cb(data);
655 | return;
656 | }
657 |
658 | return dialog;
659 | }
660 | };
661 | /* harmony default export */ __webpack_exports__["default"] = (ui);
662 |
663 | /***/ }),
664 |
665 | /***/ "./src/util/util.js":
666 | /*!**************************!*\
667 | !*** ./src/util/util.js ***!
668 | \**************************/
669 | /*! exports provided: default */
670 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
671 |
672 | "use strict";
673 | __webpack_require__.r(__webpack_exports__);
674 |
675 |
676 | var util = {
677 | createTextStyleId: function createTextStyleId(textStyle) {
678 | var textStyleId = ''; // Make sure this id incorporates every possible property of the text style
679 |
680 | textStyleId += textStyle.fontFamily;
681 | textStyleId += '-' + textStyle.fontSize;
682 | textStyleId += '-' + textStyle.letterSpacing;
683 | textStyleId += '-' + textStyle.textTransform;
684 |
685 | if (textStyle.lineHeight) {
686 | textStyleId += '-' + textStyle.lineHeight;
687 | }
688 |
689 | if (textStyle.color) {
690 | textStyleId += '-' + textStyle.color.r + '-' + textStyle.color.g + '-' + textStyle.color.b + '-' + textStyle.color.a;
691 | }
692 |
693 | return textStyleId;
694 | }
695 | };
696 | /* harmony default export */ __webpack_exports__["default"] = (util);
697 |
698 | /***/ })
699 |
700 | /******/ });
701 | if (key === 'default' && typeof exports === 'function') {
702 | exports(context);
703 | } else {
704 | exports[key](context);
705 | }
706 | }
707 | that['onRun'] = __skpm_run.bind(this, 'default')
708 |
709 | //# sourceMappingURL=css-export.js.map
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/custom-export.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/custom-export.js");
90 | /******/ })
91 | /************************************************************************/
92 | /******/ ({
93 |
94 | /***/ "./src/custom-export.js":
95 | /*!******************************!*\
96 | !*** ./src/custom-export.js ***!
97 | \******************************/
98 | /*! exports provided: default */
99 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
100 |
101 | "use strict";
102 | __webpack_require__.r(__webpack_exports__);
103 | /* harmony import */ var _util_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util/ui */ "./src/util/ui.js");
104 | /* harmony import */ var _export_open_export_dialog__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./export/open-export-dialog */ "./src/export/open-export-dialog.js");
105 |
106 |
107 | /* harmony default export */ __webpack_exports__["default"] = (function (context) {
108 | Object(_export_open_export_dialog__WEBPACK_IMPORTED_MODULE_1__["default"])(context, {
109 | title: 'Custom script export',
110 | informativeText: 'Export each text style by using a custom export script in Javascript'
111 | }, function (textStyles, data) {
112 | _util_ui__WEBPACK_IMPORTED_MODULE_0__["default"].createSettingsDialog(context, {
113 | title: 'Custom export script',
114 | informativeText: 'Customize your export by using Javascript'
115 | }, [{
116 | type: 'text',
117 | id: 'customScript',
118 | value: 'console.log(output)',
119 | label: 'Custom Javascript export'
120 | }], function (customData) {// @TODO
121 | });
122 | });
123 | });
124 | ;
125 |
126 | /***/ }),
127 |
128 | /***/ "./src/export/export-components.js":
129 | /*!*****************************************!*\
130 | !*** ./src/export/export-components.js ***!
131 | \*****************************************/
132 | /*! exports provided: default */
133 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
134 |
135 | "use strict";
136 | __webpack_require__.r(__webpack_exports__);
137 | /* harmony default export */ __webpack_exports__["default"] = ([{
138 | type: 'checkbox',
139 | id: 'merge',
140 | label: 'Merge',
141 | value: 'Merge identical styles'
142 | }, {
143 | type: 'multicheckbox',
144 | id: 'excludeProps',
145 | label: 'Exclude properties',
146 | values: ['Color', 'Line height']
147 | }, {
148 | type: 'select',
149 | id: 'cssUnit',
150 | options: ['px', 'em', 'rem', '%', 'vh', 'vw', 'No unit'],
151 | label: 'CSS unit'
152 | }, {
153 | type: 'text',
154 | id: 'scalingFactor',
155 | value: 1,
156 | label: 'Size scaling factor'
157 | }, {
158 | type: 'text',
159 | id: 'maxDecimalPlaces',
160 | value: 2,
161 | label: 'Maximal decimal places'
162 | }, {
163 | type: 'text',
164 | id: 'namingPrefix',
165 | value: 'type',
166 | label: 'Naming prefix'
167 | }, {
168 | type: 'select',
169 | id: 'namingConvention',
170 | options: ['Numeric', 'Text style name'],
171 | label: 'Naming convention'
172 | }]);
173 |
174 | /***/ }),
175 |
176 | /***/ "./src/export/open-export-dialog.js":
177 | /*!******************************************!*\
178 | !*** ./src/export/open-export-dialog.js ***!
179 | \******************************************/
180 | /*! exports provided: default */
181 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
182 |
183 | "use strict";
184 | __webpack_require__.r(__webpack_exports__);
185 | /* harmony import */ var _util_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../util/ui */ "./src/util/ui.js");
186 | /* harmony import */ var _util_export__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../util/export */ "./src/util/export.js");
187 | /* harmony import */ var _util_sketch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../util/sketch */ "./src/util/sketch.js");
188 | /* harmony import */ var _export_components__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./export-components */ "./src/export/export-components.js");
189 |
190 |
191 |
192 |
193 | /* harmony default export */ __webpack_exports__["default"] = (function (context, opts, cb) {
194 | _util_ui__WEBPACK_IMPORTED_MODULE_0__["default"].createSettingsDialog(context, opts, _export_components__WEBPACK_IMPORTED_MODULE_3__["default"], function (data) {
195 | // Defaults
196 | data.propertyNamingConvention = data.propertyNamingConvention || 'Numeric';
197 | data.cssUnit = data.cssUnit === 'No unit' ? 0 : data.cssUnit; // First store the properties we should exclude
198 |
199 | var excludeProps = [];
200 |
201 | if (data['excludeProps']['Color']) {
202 | excludeProps.push('color');
203 | }
204 |
205 | if (data['excludeProps']['Line height']) {
206 | excludeProps.push('lineHeight');
207 | } // Get the text styles from the Sketch document
208 |
209 |
210 | var textStyles = _util_sketch__WEBPACK_IMPORTED_MODULE_2__["default"].getTextStyles(context);
211 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].sortTextStyles(textStyles);
212 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].excludeTextStyleProperties(textStyles, excludeProps);
213 |
214 | if (data['merge']) {
215 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].removeDoubleTextStyles(textStyles);
216 | }
217 |
218 | cb(textStyles, data);
219 | });
220 | });
221 | ;
222 |
223 | /***/ }),
224 |
225 | /***/ "./src/util/export.js":
226 | /*!****************************!*\
227 | !*** ./src/util/export.js ***!
228 | \****************************/
229 | /*! exports provided: default */
230 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
231 |
232 | "use strict";
233 | __webpack_require__.r(__webpack_exports__);
234 | /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util */ "./src/util/util.js");
235 | /* harmony import */ var _number__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./number */ "./src/util/number.js");
236 |
237 |
238 |
239 |
240 | var exportUtils = {
241 | sortTextStyles: function sortTextStyles(textStyles) {
242 | // Sort text styles by size
243 | textStyles.sort(function (a, b) {
244 | return a.fontSize - b.fontSize;
245 | });
246 | return textStyles;
247 | },
248 | excludeTextStyleProperties: function excludeTextStyleProperties(textStyles) {
249 | var excludedProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
250 | textStyles.forEach(function (textStyle) {
251 | excludedProps.forEach(function (prop) {
252 | if (textStyle[prop]) {
253 | delete textStyle[prop];
254 | }
255 | });
256 | });
257 | return textStyles;
258 | },
259 | removeDoubleTextStyles: function removeDoubleTextStyles(textStyles) {
260 | var uniqueTextStyles = {};
261 | var filtered = [];
262 | textStyles.forEach(function (textStyle, i) {
263 | var id = _util__WEBPACK_IMPORTED_MODULE_0__["default"].createTextStyleId(textStyle);
264 |
265 | if (!uniqueTextStyles[id]) {
266 | uniqueTextStyles[id] = true;
267 | filtered.push(textStyle);
268 | }
269 | });
270 | return filtered;
271 | },
272 | createCssProps: function createCssProps(textStyle) {
273 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
274 | opts.cssUnit = opts.cssUnit || 0;
275 | opts.scalingFactor = opts.scalingFactor || 1;
276 | opts.maxDecimalPlaces = opts.maxDecimalPlaces || 2;
277 | var cssProps = {};
278 | cssProps['font-family'] = textStyle.fontFamily;
279 | cssProps['font-weight'] = 400;
280 | cssProps['text-transform'] = 'none';
281 | var fontParts = textStyle.fontFamily.split('-');
282 | var fontWeightMap = {
283 | 'Thin': 100,
284 | 'Light': 300,
285 | 'Regular': 400,
286 | 'Medium': 500,
287 | 'Bold': 700,
288 | 'Black': 900
289 | };
290 |
291 | if (fontParts[1] && fontWeightMap[fontParts[1]]) {
292 | cssProps['font-family'] = fontParts[0];
293 | cssProps['font-weight'] = fontWeightMap[fontParts[1]];
294 | }
295 |
296 | cssProps['font-size'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(opts.scalingFactor * textStyle.fontSize, opts.maxDecimalPlaces) + opts.cssUnit;
297 | cssProps['letter-spacing'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(opts.scalingFactor * textStyle.letterSpacing, opts.maxDecimalPlaces) + opts.cssUnit;
298 |
299 | if (textStyle.textTransform === 1) {
300 | cssProps['text-transform'] = 'uppercase';
301 | }
302 |
303 | if (textStyle.textTransform === 2) {
304 | cssProps['text-transform'] = 'lowercase';
305 | }
306 |
307 | if (textStyle.lineHeight) {
308 | cssProps['line-height'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(1 + (textStyle.lineHeight - textStyle.fontSize) / textStyle.lineHeight, opts.maxDecimalPlaces);
309 | }
310 |
311 | if (textStyle.color) {
312 | cssProps['color'] = exportUtils.createRgbaString(textStyle.color);
313 | }
314 |
315 | return cssProps;
316 | },
317 | createRgbaString: function createRgbaString(colorObj) {
318 | return 'rgba(' + exportUtils.createColorValue(colorObj.r) + ', ' + exportUtils.createColorValue(colorObj.g) + ', ' + exportUtils.createColorValue(colorObj.b) + ', ' + colorObj.a + ')';
319 | },
320 | createColorValue: function createColorValue(normalizedValue) {
321 | return Math.round(normalizedValue * 255);
322 | },
323 | createStyleBlock: function createStyleBlock(cssProps) {
324 | var output = '';
325 |
326 | for (var prop in cssProps) {
327 | output += "\t" + prop + ': ' + cssProps[prop] + ';' + "\n";
328 | }
329 |
330 | return output;
331 | },
332 | createInlineStyleString: function createInlineStyleString(cssProps) {
333 | var styleString = '';
334 |
335 | for (var prop in cssProps) {
336 | styleString += prop + ': ' + cssProps[prop] + '; ';
337 | }
338 |
339 | return styleString;
340 | },
341 | createHtmlFontbook: function createHtmlFontbook(textStyles) {
342 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
343 | var output = "\n \n \n \n \n Typex text styles\n \n \n ";
344 | textStyles.forEach(function (textStyle, i) {
345 | var cssProps = exportUtils.createCssProps(textStyle, opts);
346 | var inlineStyleString = exportUtils.createInlineStyleString(cssProps);
347 | var cssPropsBlock = exportUtils.createStyleBlock(cssProps);
348 | var textStyleName;
349 |
350 | if (opts.namingConvention === 'Numeric') {
351 | textStyleName = opts.namingPrefix + ' ' + (i + 1);
352 | } else if (opts.namingConvention === 'Text style name') {
353 | textStyleName = opts.namingPrefix + ' ' + textStyle.name;
354 | } else {
355 | textStyleName = opts.namingPrefix + ' ' + (i + 1) + ' (' + textStyle.name + ')';
356 | }
357 |
358 | output += "\n \n
\n ".concat(i + 1, ".\n \n ").concat(textStyleName, "\n \n
\n
\n
\n The quick brown fox jumps over the lazy dog\n
\n
\n \n
\n
\n
\n ");
359 | });
360 | output += "\n \n \n ";
361 | return output;
362 | }
363 | };
364 | /* harmony default export */ __webpack_exports__["default"] = (exportUtils);
365 |
366 | /***/ }),
367 |
368 | /***/ "./src/util/number.js":
369 | /*!****************************!*\
370 | !*** ./src/util/number.js ***!
371 | \****************************/
372 | /*! exports provided: default */
373 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
374 |
375 | "use strict";
376 | __webpack_require__.r(__webpack_exports__);
377 |
378 |
379 | var number = {
380 | parseFloatMaxDecimal: function parseFloatMaxDecimal(number, maxDecimalPlaces) {
381 | return Number(number.toFixed(maxDecimalPlaces).replace(/[.,]00$/, ''));
382 | }
383 | };
384 | /* harmony default export */ __webpack_exports__["default"] = (number);
385 |
386 | /***/ }),
387 |
388 | /***/ "./src/util/sketch.js":
389 | /*!****************************!*\
390 | !*** ./src/util/sketch.js ***!
391 | \****************************/
392 | /*! exports provided: default */
393 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
394 |
395 | "use strict";
396 | __webpack_require__.r(__webpack_exports__);
397 |
398 |
399 | var sketch = {
400 | getTextStyles: function getTextStyles(context) {
401 | var texts = context.document.documentData().layerTextStyles().objects();
402 | var rawTextStyles = [];
403 | texts.forEach(function (text, i) {
404 | rawTextStyles.push({
405 | attributes: text.style().textStyle().attributes(),
406 | textStyle: text,
407 | name: text.name()
408 | });
409 | });
410 | var textStyles = [];
411 | rawTextStyles.forEach(function (rawTextStyle) {
412 | var textStyle = {};
413 | textStyle.name = rawTextStyle.name;
414 | textStyle.fontFamily = String(rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontNameAttribute));
415 | textStyle.fontSize = rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontSizeAttribute);
416 | textStyle.paragraph = rawTextStyle.attributes.NSParagraphStyle;
417 |
418 | if (textStyle.paragraph) {
419 | textStyle.lineHeight = textStyle.paragraph.maximumLineHeight();
420 | }
421 |
422 | var color = rawTextStyle.attributes.MSAttributedStringColorAttribute;
423 |
424 | if (color) {
425 | var r = color.red();
426 | var g = color.green();
427 | var b = color.blue();
428 | var a = color.alpha();
429 | textStyle.color = {
430 | r: r,
431 | g: g,
432 | b: b,
433 | a: a
434 | };
435 | }
436 |
437 | textStyle.letterSpacing = rawTextStyle.attributes.NSKern || 0;
438 | textStyle.textTransform = parseInt(rawTextStyle.attributes.MSAttributedStringTextTransformAttribute || 0); // @TODO strikethrough & underline, or is this not needed?
439 |
440 | textStyles.push(textStyle);
441 | });
442 | return textStyles;
443 | }
444 | };
445 | /* harmony default export */ __webpack_exports__["default"] = (sketch);
446 |
447 | /***/ }),
448 |
449 | /***/ "./src/util/ui.js":
450 | /*!************************!*\
451 | !*** ./src/util/ui.js ***!
452 | \************************/
453 | /*! exports provided: default */
454 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
455 |
456 | "use strict";
457 | __webpack_require__.r(__webpack_exports__);
458 |
459 |
460 | var ui = {
461 | createSavePanel: function createSavePanel(defaultFileName, contents) {
462 | var save = NSSavePanel.savePanel();
463 | save.setNameFieldStringValue(defaultFileName);
464 | save.setAllowsOtherFileTypes(false);
465 | save.setExtensionHidden(false);
466 |
467 | if (save.runModal()) {
468 | var file = NSString.stringWithString(contents);
469 | var path = save.URL().path();
470 | file.writeToFile_atomically_encoding_error(path, true, NSUTF8StringEncoding, null);
471 | }
472 | },
473 | createLabel: function createLabel() {
474 | var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
475 | var label = NSTextField.alloc().init();
476 | label.setStringValue(text);
477 | label.setFont(NSFont.boldSystemFontOfSize(12));
478 | label.setBezeled(false);
479 | label.setDrawsBackground(false);
480 | label.setEditable(false);
481 | label.setSelectable(false);
482 | return label;
483 | },
484 | createTextField: function createTextField(value) {
485 | var field = NSTextField.alloc().init();
486 | field.setStringValue(value);
487 | return field;
488 | },
489 | createSelect: function createSelect(options) {
490 | var comboBox = NSPopUpButton.alloc().init();
491 | comboBox.addItemsWithTitles(options);
492 | comboBox.selectItemAtIndex(0);
493 | return comboBox;
494 | },
495 | createStepper: function createStepper(value) {
496 | var stepper = NSStepper.alloc().init();
497 | return stepper;
498 | },
499 | createCheckbox: function createCheckbox(title) {
500 | var checkbox = NSButton.alloc().init();
501 | checkbox.setButtonType(NSSwitchButton);
502 | checkbox.title = title;
503 | return checkbox;
504 | },
505 | createSettingsDialog: function createSettingsDialog(context) {
506 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
507 | var components = arguments.length > 2 ? arguments[2] : undefined;
508 | var cb = arguments.length > 3 ? arguments[3] : undefined;
509 | opts.title = opts.title || 'Alert';
510 | opts.informativeText = opts.informativeText || '';
511 | opts.cancelBtnText = opts.cancelBtnText || 'Cancel';
512 | opts.confirmBtnText = opts.confirmBtnText || 'Ok';
513 | var dialog = NSAlert.alloc().init();
514 | var dialogIconPath = context.plugin.urlForResourceNamed('icon.png').path();
515 | var dialogIcon = NSImage.alloc().initByReferencingFile(dialogIconPath);
516 | dialog.setIcon(dialogIcon);
517 | dialog.setMessageText(opts.title);
518 | dialog.setInformativeText(opts.informativeText);
519 | var btnConfirm = dialog.addButtonWithTitle(opts.confirmBtnText);
520 | var btnCancel = dialog.addButtonWithTitle(opts.cancelBtnText); // Create grid view
521 |
522 | var gridView = NSGridView.alloc().init(); // Create object to hold all inputs
523 |
524 | var inputs = {};
525 | var height = 0;
526 | var rowSpacing = 8; // Loop each component
527 |
528 | components.forEach(function (c) {
529 | var label, field;
530 |
531 | switch (c.type) {
532 | case 'text':
533 | label = ui.createLabel(c.label);
534 | field = ui.createTextField(c.value);
535 | height += 22 + rowSpacing;
536 | gridView.addRowWithViews([label, field]);
537 | break;
538 |
539 | case 'stepper':
540 | label = ui.createLabel(c.label);
541 | field = ui.createStepper(c.value);
542 | height += 22 + rowSpacing;
543 | gridView.addRowWithViews([label, field]);
544 | break;
545 |
546 | case 'checkbox':
547 | label = ui.createLabel(c.label);
548 | field = ui.createCheckbox(c.value);
549 | height += 22 + rowSpacing;
550 | gridView.addRowWithViews([label, field]);
551 | break;
552 |
553 | case 'multicheckbox':
554 | field = [];
555 | c.values.forEach(function (v, i) {
556 | label = i ? ui.createLabel() : ui.createLabel(c.label);
557 | var checkbox = ui.createCheckbox(v);
558 | height += 22 + rowSpacing;
559 | field.push(checkbox);
560 | gridView.addRowWithViews([label, checkbox]);
561 | });
562 | break;
563 |
564 | case 'select':
565 | label = ui.createLabel(c.label);
566 | field = ui.createSelect(c.options);
567 | height += 28 + rowSpacing;
568 | gridView.addRowWithViews([label, field]);
569 | break;
570 | }
571 |
572 | inputs[c.id] = field;
573 | }); // Set grid view as view of dialog
574 |
575 | dialog.accessoryView = gridView;
576 | gridView.columnSpacing = 30;
577 | gridView.rowSpacing = rowSpacing;
578 | gridView.frame = NSMakeRect(0, 0, 400, height); // Open the dialog and store the response code
579 |
580 | var responseCode = dialog.runModal(); // The dialog is being 'submitted'
581 |
582 | if (responseCode === 1000) {
583 | var data = {};
584 | components.forEach(function (c) {
585 | switch (c.type) {
586 | case 'text':
587 | data[c.id] = inputs[c.id].stringValue();
588 | break;
589 |
590 | case 'select':
591 | data[c.id] = c.options[inputs[c.id].indexOfSelectedItem()];
592 | break;
593 |
594 | case 'checkbox':
595 | data[c.id] = inputs[c.id].state() === 1;
596 | break;
597 |
598 | case 'multicheckbox':
599 | var values = {};
600 | c.values.forEach(function (v, i) {
601 | values[v] = inputs[c.id][i].state() === 1;
602 | });
603 | data[c.id] = values;
604 | }
605 | });
606 | cb(data);
607 | return;
608 | }
609 |
610 | return dialog;
611 | }
612 | };
613 | /* harmony default export */ __webpack_exports__["default"] = (ui);
614 |
615 | /***/ }),
616 |
617 | /***/ "./src/util/util.js":
618 | /*!**************************!*\
619 | !*** ./src/util/util.js ***!
620 | \**************************/
621 | /*! exports provided: default */
622 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
623 |
624 | "use strict";
625 | __webpack_require__.r(__webpack_exports__);
626 |
627 |
628 | var util = {
629 | createTextStyleId: function createTextStyleId(textStyle) {
630 | var textStyleId = ''; // Make sure this id incorporates every possible property of the text style
631 |
632 | textStyleId += textStyle.fontFamily;
633 | textStyleId += '-' + textStyle.fontSize;
634 | textStyleId += '-' + textStyle.letterSpacing;
635 | textStyleId += '-' + textStyle.textTransform;
636 |
637 | if (textStyle.lineHeight) {
638 | textStyleId += '-' + textStyle.lineHeight;
639 | }
640 |
641 | if (textStyle.color) {
642 | textStyleId += '-' + textStyle.color.r + '-' + textStyle.color.g + '-' + textStyle.color.b + '-' + textStyle.color.a;
643 | }
644 |
645 | return textStyleId;
646 | }
647 | };
648 | /* harmony default export */ __webpack_exports__["default"] = (util);
649 |
650 | /***/ })
651 |
652 | /******/ });
653 | if (key === 'default' && typeof exports === 'function') {
654 | exports(context);
655 | } else {
656 | exports[key](context);
657 | }
658 | }
659 | that['onRun'] = __skpm_run.bind(this, 'default')
660 |
661 | //# sourceMappingURL=custom-export.js.map
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/html-export.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/html-export.js");
90 | /******/ })
91 | /************************************************************************/
92 | /******/ ({
93 |
94 | /***/ "./src/html-export.js":
95 | /*!****************************!*\
96 | !*** ./src/html-export.js ***!
97 | \****************************/
98 | /*! exports provided: default */
99 | /***/ (function(module, exports) {
100 |
101 | throw new Error("Module build failed (from ./node_modules/babel-loader/lib/index.js):\nError: ENOENT: no such file or directory, open '/Users/rein/Workspace/sketch-plugins/typex/src/html-export.js'");
102 |
103 | /***/ })
104 |
105 | /******/ });
106 | if (key === 'default' && typeof exports === 'function') {
107 | exports(context);
108 | } else {
109 | exports[key](context);
110 | }
111 | }
112 | that['onRun'] = __skpm_run.bind(this, 'default')
113 |
114 | //# sourceMappingURL=html-export.js.map
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/html-export.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap"],"names":[],"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","file":"html-export.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/html-export.js\");\n"],"sourceRoot":""}
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/html-fontbook-export.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/html-fontbook-export.js");
90 | /******/ })
91 | /************************************************************************/
92 | /******/ ({
93 |
94 | /***/ "./src/export/export-components.js":
95 | /*!*****************************************!*\
96 | !*** ./src/export/export-components.js ***!
97 | \*****************************************/
98 | /*! exports provided: default */
99 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
100 |
101 | "use strict";
102 | __webpack_require__.r(__webpack_exports__);
103 | /* harmony default export */ __webpack_exports__["default"] = ([{
104 | type: 'checkbox',
105 | id: 'merge',
106 | label: 'Merge',
107 | value: 'Merge identical styles'
108 | }, {
109 | type: 'multicheckbox',
110 | id: 'excludeProps',
111 | label: 'Exclude properties',
112 | values: ['Color', 'Line height']
113 | }, {
114 | type: 'select',
115 | id: 'cssUnit',
116 | options: ['px', 'em', 'rem', '%', 'vh', 'vw', 'No unit'],
117 | label: 'CSS unit'
118 | }, {
119 | type: 'text',
120 | id: 'scalingFactor',
121 | value: 1,
122 | label: 'Size scaling factor'
123 | }, {
124 | type: 'text',
125 | id: 'maxDecimalPlaces',
126 | value: 2,
127 | label: 'Maximal decimal places'
128 | }, {
129 | type: 'text',
130 | id: 'namingPrefix',
131 | value: 'type',
132 | label: 'Naming prefix'
133 | }, {
134 | type: 'select',
135 | id: 'namingConvention',
136 | options: ['Numeric', 'Text style name'],
137 | label: 'Naming convention'
138 | }]);
139 |
140 | /***/ }),
141 |
142 | /***/ "./src/export/open-export-dialog.js":
143 | /*!******************************************!*\
144 | !*** ./src/export/open-export-dialog.js ***!
145 | \******************************************/
146 | /*! exports provided: default */
147 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
148 |
149 | "use strict";
150 | __webpack_require__.r(__webpack_exports__);
151 | /* harmony import */ var _util_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../util/ui */ "./src/util/ui.js");
152 | /* harmony import */ var _util_export__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../util/export */ "./src/util/export.js");
153 | /* harmony import */ var _util_sketch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../util/sketch */ "./src/util/sketch.js");
154 | /* harmony import */ var _export_components__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./export-components */ "./src/export/export-components.js");
155 |
156 |
157 |
158 |
159 | /* harmony default export */ __webpack_exports__["default"] = (function (context, opts, cb) {
160 | _util_ui__WEBPACK_IMPORTED_MODULE_0__["default"].createSettingsDialog(context, opts, _export_components__WEBPACK_IMPORTED_MODULE_3__["default"], function (data) {
161 | // Defaults
162 | data.propertyNamingConvention = data.propertyNamingConvention || 'Numeric';
163 | data.cssUnit = data.cssUnit === 'No unit' ? 0 : data.cssUnit; // First store the properties we should exclude
164 |
165 | var excludeProps = [];
166 |
167 | if (data['excludeProps']['Color']) {
168 | excludeProps.push('color');
169 | }
170 |
171 | if (data['excludeProps']['Line height']) {
172 | excludeProps.push('lineHeight');
173 | } // Get the text styles from the Sketch document
174 |
175 |
176 | var textStyles = _util_sketch__WEBPACK_IMPORTED_MODULE_2__["default"].getTextStyles(context);
177 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].sortTextStyles(textStyles);
178 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].excludeTextStyleProperties(textStyles, excludeProps);
179 |
180 | if (data['merge']) {
181 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].removeDoubleTextStyles(textStyles);
182 | }
183 |
184 | cb(textStyles, data);
185 | });
186 | });
187 | ;
188 |
189 | /***/ }),
190 |
191 | /***/ "./src/html-fontbook-export.js":
192 | /*!*************************************!*\
193 | !*** ./src/html-fontbook-export.js ***!
194 | \*************************************/
195 | /*! exports provided: default */
196 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
197 |
198 | "use strict";
199 | __webpack_require__.r(__webpack_exports__);
200 | /* harmony import */ var _util_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util/ui */ "./src/util/ui.js");
201 | /* harmony import */ var _util_export__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./util/export */ "./src/util/export.js");
202 | /* harmony import */ var _export_open_export_dialog__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./export/open-export-dialog */ "./src/export/open-export-dialog.js");
203 |
204 |
205 |
206 | /* harmony default export */ __webpack_exports__["default"] = (function (context) {
207 | Object(_export_open_export_dialog__WEBPACK_IMPORTED_MODULE_2__["default"])(context, {
208 | title: 'Create HTML fontbook',
209 | informativeText: 'Create a handy HTML fontbook from your text styles',
210 | confirmBtnText: 'Export HTML fontbook'
211 | }, function (textStyles, data) {
212 | // Create a HTML fontbook with these styles
213 | var html = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].createHtmlFontbook(textStyles, data); // Ask the user to save the file
214 |
215 | _util_ui__WEBPACK_IMPORTED_MODULE_0__["default"].createSavePanel('typex-fontbook.html', html);
216 | });
217 | });
218 | ;
219 |
220 | /***/ }),
221 |
222 | /***/ "./src/util/export.js":
223 | /*!****************************!*\
224 | !*** ./src/util/export.js ***!
225 | \****************************/
226 | /*! exports provided: default */
227 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
228 |
229 | "use strict";
230 | __webpack_require__.r(__webpack_exports__);
231 | /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util */ "./src/util/util.js");
232 | /* harmony import */ var _number__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./number */ "./src/util/number.js");
233 |
234 |
235 |
236 |
237 | var exportUtils = {
238 | sortTextStyles: function sortTextStyles(textStyles) {
239 | // Sort text styles by size
240 | textStyles.sort(function (a, b) {
241 | return a.fontSize - b.fontSize;
242 | });
243 | return textStyles;
244 | },
245 | excludeTextStyleProperties: function excludeTextStyleProperties(textStyles) {
246 | var excludedProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
247 | textStyles.forEach(function (textStyle) {
248 | excludedProps.forEach(function (prop) {
249 | if (textStyle[prop]) {
250 | delete textStyle[prop];
251 | }
252 | });
253 | });
254 | return textStyles;
255 | },
256 | removeDoubleTextStyles: function removeDoubleTextStyles(textStyles) {
257 | var uniqueTextStyles = {};
258 | var filtered = [];
259 | textStyles.forEach(function (textStyle, i) {
260 | var id = _util__WEBPACK_IMPORTED_MODULE_0__["default"].createTextStyleId(textStyle);
261 |
262 | if (!uniqueTextStyles[id]) {
263 | uniqueTextStyles[id] = true;
264 | filtered.push(textStyle);
265 | }
266 | });
267 | return filtered;
268 | },
269 | createCssProps: function createCssProps(textStyle) {
270 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
271 | opts.cssUnit = opts.cssUnit || 0;
272 | opts.scalingFactor = opts.scalingFactor || 1;
273 | opts.maxDecimalPlaces = opts.maxDecimalPlaces || 2;
274 | var cssProps = {};
275 | cssProps['font-family'] = textStyle.fontFamily;
276 | cssProps['font-weight'] = 400;
277 | cssProps['text-transform'] = 'none';
278 | var fontParts = textStyle.fontFamily.split('-');
279 | var fontWeightMap = {
280 | 'Thin': 100,
281 | 'Light': 300,
282 | 'Regular': 400,
283 | 'Medium': 500,
284 | 'Bold': 700,
285 | 'Black': 900
286 | };
287 |
288 | if (fontParts[1] && fontWeightMap[fontParts[1]]) {
289 | cssProps['font-family'] = fontParts[0];
290 | cssProps['font-weight'] = fontWeightMap[fontParts[1]];
291 | }
292 |
293 | cssProps['font-size'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(opts.scalingFactor * textStyle.fontSize, opts.maxDecimalPlaces) + opts.cssUnit;
294 | cssProps['letter-spacing'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(opts.scalingFactor * textStyle.letterSpacing, opts.maxDecimalPlaces) + opts.cssUnit;
295 |
296 | if (textStyle.textTransform === 1) {
297 | cssProps['text-transform'] = 'uppercase';
298 | }
299 |
300 | if (textStyle.textTransform === 2) {
301 | cssProps['text-transform'] = 'lowercase';
302 | }
303 |
304 | if (textStyle.lineHeight) {
305 | cssProps['line-height'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(1 + (textStyle.lineHeight - textStyle.fontSize) / textStyle.lineHeight, opts.maxDecimalPlaces);
306 | }
307 |
308 | if (textStyle.color) {
309 | cssProps['color'] = exportUtils.createRgbaString(textStyle.color);
310 | }
311 |
312 | return cssProps;
313 | },
314 | createRgbaString: function createRgbaString(colorObj) {
315 | return 'rgba(' + exportUtils.createColorValue(colorObj.r) + ', ' + exportUtils.createColorValue(colorObj.g) + ', ' + exportUtils.createColorValue(colorObj.b) + ', ' + colorObj.a + ')';
316 | },
317 | createColorValue: function createColorValue(normalizedValue) {
318 | return Math.round(normalizedValue * 255);
319 | },
320 | createStyleBlock: function createStyleBlock(cssProps) {
321 | var output = '';
322 |
323 | for (var prop in cssProps) {
324 | output += "\t" + prop + ': ' + cssProps[prop] + ';' + "\n";
325 | }
326 |
327 | return output;
328 | },
329 | createInlineStyleString: function createInlineStyleString(cssProps) {
330 | var styleString = '';
331 |
332 | for (var prop in cssProps) {
333 | styleString += prop + ': ' + cssProps[prop] + '; ';
334 | }
335 |
336 | return styleString;
337 | },
338 | createHtmlFontbook: function createHtmlFontbook(textStyles) {
339 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
340 | var output = "\n \n \n \n \n Typex text styles\n \n \n ";
341 | textStyles.forEach(function (textStyle, i) {
342 | var cssProps = exportUtils.createCssProps(textStyle, opts);
343 | var inlineStyleString = exportUtils.createInlineStyleString(cssProps);
344 | var cssPropsBlock = exportUtils.createStyleBlock(cssProps);
345 | var textStyleName;
346 |
347 | if (opts.namingConvention === 'Numeric') {
348 | textStyleName = opts.namingPrefix + ' ' + (i + 1);
349 | } else if (opts.namingConvention === 'Text style name') {
350 | textStyleName = opts.namingPrefix + ' ' + textStyle.name;
351 | } else {
352 | textStyleName = opts.namingPrefix + ' ' + (i + 1) + ' (' + textStyle.name + ')';
353 | }
354 |
355 | output += "\n \n
\n ".concat(i + 1, ".\n \n ").concat(textStyleName, "\n \n
\n
\n
\n The quick brown fox jumps over the lazy dog\n
\n
\n \n
\n
\n
\n ");
356 | });
357 | output += "\n \n \n ";
358 | return output;
359 | }
360 | };
361 | /* harmony default export */ __webpack_exports__["default"] = (exportUtils);
362 |
363 | /***/ }),
364 |
365 | /***/ "./src/util/number.js":
366 | /*!****************************!*\
367 | !*** ./src/util/number.js ***!
368 | \****************************/
369 | /*! exports provided: default */
370 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
371 |
372 | "use strict";
373 | __webpack_require__.r(__webpack_exports__);
374 |
375 |
376 | var number = {
377 | parseFloatMaxDecimal: function parseFloatMaxDecimal(number, maxDecimalPlaces) {
378 | return Number(number.toFixed(maxDecimalPlaces).replace(/[.,]00$/, ''));
379 | }
380 | };
381 | /* harmony default export */ __webpack_exports__["default"] = (number);
382 |
383 | /***/ }),
384 |
385 | /***/ "./src/util/sketch.js":
386 | /*!****************************!*\
387 | !*** ./src/util/sketch.js ***!
388 | \****************************/
389 | /*! exports provided: default */
390 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
391 |
392 | "use strict";
393 | __webpack_require__.r(__webpack_exports__);
394 |
395 |
396 | var sketch = {
397 | getTextStyles: function getTextStyles(context) {
398 | var texts = context.document.documentData().layerTextStyles().objects();
399 | var rawTextStyles = [];
400 | texts.forEach(function (text, i) {
401 | rawTextStyles.push({
402 | attributes: text.style().textStyle().attributes(),
403 | textStyle: text,
404 | name: text.name()
405 | });
406 | });
407 | var textStyles = [];
408 | rawTextStyles.forEach(function (rawTextStyle) {
409 | var textStyle = {};
410 | textStyle.name = rawTextStyle.name;
411 | textStyle.fontFamily = String(rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontNameAttribute));
412 | textStyle.fontSize = rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontSizeAttribute);
413 | textStyle.paragraph = rawTextStyle.attributes.NSParagraphStyle;
414 |
415 | if (textStyle.paragraph) {
416 | textStyle.lineHeight = textStyle.paragraph.maximumLineHeight();
417 | }
418 |
419 | var color = rawTextStyle.attributes.MSAttributedStringColorAttribute;
420 |
421 | if (color) {
422 | var r = color.red();
423 | var g = color.green();
424 | var b = color.blue();
425 | var a = color.alpha();
426 | textStyle.color = {
427 | r: r,
428 | g: g,
429 | b: b,
430 | a: a
431 | };
432 | }
433 |
434 | textStyle.letterSpacing = rawTextStyle.attributes.NSKern || 0;
435 | textStyle.textTransform = parseInt(rawTextStyle.attributes.MSAttributedStringTextTransformAttribute || 0); // @TODO strikethrough & underline, or is this not needed?
436 |
437 | textStyles.push(textStyle);
438 | });
439 | return textStyles;
440 | }
441 | };
442 | /* harmony default export */ __webpack_exports__["default"] = (sketch);
443 |
444 | /***/ }),
445 |
446 | /***/ "./src/util/ui.js":
447 | /*!************************!*\
448 | !*** ./src/util/ui.js ***!
449 | \************************/
450 | /*! exports provided: default */
451 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
452 |
453 | "use strict";
454 | __webpack_require__.r(__webpack_exports__);
455 |
456 |
457 | var ui = {
458 | createSavePanel: function createSavePanel(defaultFileName, contents) {
459 | var save = NSSavePanel.savePanel();
460 | save.setNameFieldStringValue(defaultFileName);
461 | save.setAllowsOtherFileTypes(false);
462 | save.setExtensionHidden(false);
463 |
464 | if (save.runModal()) {
465 | var file = NSString.stringWithString(contents);
466 | var path = save.URL().path();
467 | file.writeToFile_atomically_encoding_error(path, true, NSUTF8StringEncoding, null);
468 | }
469 | },
470 | createLabel: function createLabel() {
471 | var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
472 | var label = NSTextField.alloc().init();
473 | label.setStringValue(text);
474 | label.setFont(NSFont.boldSystemFontOfSize(12));
475 | label.setBezeled(false);
476 | label.setDrawsBackground(false);
477 | label.setEditable(false);
478 | label.setSelectable(false);
479 | return label;
480 | },
481 | createTextField: function createTextField(value) {
482 | var field = NSTextField.alloc().init();
483 | field.setStringValue(value);
484 | return field;
485 | },
486 | createSelect: function createSelect(options) {
487 | var comboBox = NSPopUpButton.alloc().init();
488 | comboBox.addItemsWithTitles(options);
489 | comboBox.selectItemAtIndex(0);
490 | return comboBox;
491 | },
492 | createStepper: function createStepper(value) {
493 | var stepper = NSStepper.alloc().init();
494 | return stepper;
495 | },
496 | createCheckbox: function createCheckbox(title) {
497 | var checkbox = NSButton.alloc().init();
498 | checkbox.setButtonType(NSSwitchButton);
499 | checkbox.title = title;
500 | return checkbox;
501 | },
502 | createSettingsDialog: function createSettingsDialog(context) {
503 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
504 | var components = arguments.length > 2 ? arguments[2] : undefined;
505 | var cb = arguments.length > 3 ? arguments[3] : undefined;
506 | opts.title = opts.title || 'Alert';
507 | opts.informativeText = opts.informativeText || '';
508 | opts.cancelBtnText = opts.cancelBtnText || 'Cancel';
509 | opts.confirmBtnText = opts.confirmBtnText || 'Ok';
510 | var dialog = NSAlert.alloc().init();
511 | var dialogIconPath = context.plugin.urlForResourceNamed('icon.png').path();
512 | var dialogIcon = NSImage.alloc().initByReferencingFile(dialogIconPath);
513 | dialog.setIcon(dialogIcon);
514 | dialog.setMessageText(opts.title);
515 | dialog.setInformativeText(opts.informativeText);
516 | var btnConfirm = dialog.addButtonWithTitle(opts.confirmBtnText);
517 | var btnCancel = dialog.addButtonWithTitle(opts.cancelBtnText); // Create grid view
518 |
519 | var gridView = NSGridView.alloc().init(); // Create object to hold all inputs
520 |
521 | var inputs = {};
522 | var height = 0;
523 | var rowSpacing = 8; // Loop each component
524 |
525 | components.forEach(function (c) {
526 | var label, field;
527 |
528 | switch (c.type) {
529 | case 'text':
530 | label = ui.createLabel(c.label);
531 | field = ui.createTextField(c.value);
532 | height += 22 + rowSpacing;
533 | gridView.addRowWithViews([label, field]);
534 | break;
535 |
536 | case 'stepper':
537 | label = ui.createLabel(c.label);
538 | field = ui.createStepper(c.value);
539 | height += 22 + rowSpacing;
540 | gridView.addRowWithViews([label, field]);
541 | break;
542 |
543 | case 'checkbox':
544 | label = ui.createLabel(c.label);
545 | field = ui.createCheckbox(c.value);
546 | height += 22 + rowSpacing;
547 | gridView.addRowWithViews([label, field]);
548 | break;
549 |
550 | case 'multicheckbox':
551 | field = [];
552 | c.values.forEach(function (v, i) {
553 | label = i ? ui.createLabel() : ui.createLabel(c.label);
554 | var checkbox = ui.createCheckbox(v);
555 | height += 22 + rowSpacing;
556 | field.push(checkbox);
557 | gridView.addRowWithViews([label, checkbox]);
558 | });
559 | break;
560 |
561 | case 'select':
562 | label = ui.createLabel(c.label);
563 | field = ui.createSelect(c.options);
564 | height += 28 + rowSpacing;
565 | gridView.addRowWithViews([label, field]);
566 | break;
567 | }
568 |
569 | inputs[c.id] = field;
570 | }); // Set grid view as view of dialog
571 |
572 | dialog.accessoryView = gridView;
573 | gridView.columnSpacing = 30;
574 | gridView.rowSpacing = rowSpacing;
575 | gridView.frame = NSMakeRect(0, 0, 400, height); // Open the dialog and store the response code
576 |
577 | var responseCode = dialog.runModal(); // The dialog is being 'submitted'
578 |
579 | if (responseCode === 1000) {
580 | var data = {};
581 | components.forEach(function (c) {
582 | switch (c.type) {
583 | case 'text':
584 | data[c.id] = inputs[c.id].stringValue();
585 | break;
586 |
587 | case 'select':
588 | data[c.id] = c.options[inputs[c.id].indexOfSelectedItem()];
589 | break;
590 |
591 | case 'checkbox':
592 | data[c.id] = inputs[c.id].state() === 1;
593 | break;
594 |
595 | case 'multicheckbox':
596 | var values = {};
597 | c.values.forEach(function (v, i) {
598 | values[v] = inputs[c.id][i].state() === 1;
599 | });
600 | data[c.id] = values;
601 | }
602 | });
603 | cb(data);
604 | return;
605 | }
606 |
607 | return dialog;
608 | }
609 | };
610 | /* harmony default export */ __webpack_exports__["default"] = (ui);
611 |
612 | /***/ }),
613 |
614 | /***/ "./src/util/util.js":
615 | /*!**************************!*\
616 | !*** ./src/util/util.js ***!
617 | \**************************/
618 | /*! exports provided: default */
619 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
620 |
621 | "use strict";
622 | __webpack_require__.r(__webpack_exports__);
623 |
624 |
625 | var util = {
626 | createTextStyleId: function createTextStyleId(textStyle) {
627 | var textStyleId = ''; // Make sure this id incorporates every possible property of the text style
628 |
629 | textStyleId += textStyle.fontFamily;
630 | textStyleId += '-' + textStyle.fontSize;
631 | textStyleId += '-' + textStyle.letterSpacing;
632 | textStyleId += '-' + textStyle.textTransform;
633 |
634 | if (textStyle.lineHeight) {
635 | textStyleId += '-' + textStyle.lineHeight;
636 | }
637 |
638 | if (textStyle.color) {
639 | textStyleId += '-' + textStyle.color.r + '-' + textStyle.color.g + '-' + textStyle.color.b + '-' + textStyle.color.a;
640 | }
641 |
642 | return textStyleId;
643 | }
644 | };
645 | /* harmony default export */ __webpack_exports__["default"] = (util);
646 |
647 | /***/ })
648 |
649 | /******/ });
650 | if (key === 'default' && typeof exports === 'function') {
651 | exports(context);
652 | } else {
653 | exports[key](context);
654 | }
655 | }
656 | that['onRun'] = __skpm_run.bind(this, 'default')
657 |
658 | //# sourceMappingURL=html-fontbook-export.js.map
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/json-export.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/json-export.js");
90 | /******/ })
91 | /************************************************************************/
92 | /******/ ({
93 |
94 | /***/ "./src/export/export-components.js":
95 | /*!*****************************************!*\
96 | !*** ./src/export/export-components.js ***!
97 | \*****************************************/
98 | /*! exports provided: default */
99 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
100 |
101 | "use strict";
102 | __webpack_require__.r(__webpack_exports__);
103 | /* harmony default export */ __webpack_exports__["default"] = ([{
104 | type: 'checkbox',
105 | id: 'merge',
106 | label: 'Merge',
107 | value: 'Merge identical styles'
108 | }, {
109 | type: 'multicheckbox',
110 | id: 'excludeProps',
111 | label: 'Exclude properties',
112 | values: ['Color', 'Line height']
113 | }, {
114 | type: 'select',
115 | id: 'cssUnit',
116 | options: ['px', 'em', 'rem', '%', 'vh', 'vw', 'No unit'],
117 | label: 'CSS unit'
118 | }, {
119 | type: 'text',
120 | id: 'scalingFactor',
121 | value: 1,
122 | label: 'Size scaling factor'
123 | }, {
124 | type: 'text',
125 | id: 'maxDecimalPlaces',
126 | value: 2,
127 | label: 'Maximal decimal places'
128 | }, {
129 | type: 'text',
130 | id: 'namingPrefix',
131 | value: 'type',
132 | label: 'Naming prefix'
133 | }, {
134 | type: 'select',
135 | id: 'namingConvention',
136 | options: ['Numeric', 'Text style name'],
137 | label: 'Naming convention'
138 | }]);
139 |
140 | /***/ }),
141 |
142 | /***/ "./src/export/open-export-dialog.js":
143 | /*!******************************************!*\
144 | !*** ./src/export/open-export-dialog.js ***!
145 | \******************************************/
146 | /*! exports provided: default */
147 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
148 |
149 | "use strict";
150 | __webpack_require__.r(__webpack_exports__);
151 | /* harmony import */ var _util_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../util/ui */ "./src/util/ui.js");
152 | /* harmony import */ var _util_export__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../util/export */ "./src/util/export.js");
153 | /* harmony import */ var _util_sketch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../util/sketch */ "./src/util/sketch.js");
154 | /* harmony import */ var _export_components__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./export-components */ "./src/export/export-components.js");
155 |
156 |
157 |
158 |
159 | /* harmony default export */ __webpack_exports__["default"] = (function (context, opts, cb) {
160 | _util_ui__WEBPACK_IMPORTED_MODULE_0__["default"].createSettingsDialog(context, opts, _export_components__WEBPACK_IMPORTED_MODULE_3__["default"], function (data) {
161 | // Defaults
162 | data.propertyNamingConvention = data.propertyNamingConvention || 'Numeric';
163 | data.cssUnit = data.cssUnit === 'No unit' ? 0 : data.cssUnit; // First store the properties we should exclude
164 |
165 | var excludeProps = [];
166 |
167 | if (data['excludeProps']['Color']) {
168 | excludeProps.push('color');
169 | }
170 |
171 | if (data['excludeProps']['Line height']) {
172 | excludeProps.push('lineHeight');
173 | } // Get the text styles from the Sketch document
174 |
175 |
176 | var textStyles = _util_sketch__WEBPACK_IMPORTED_MODULE_2__["default"].getTextStyles(context);
177 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].sortTextStyles(textStyles);
178 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].excludeTextStyleProperties(textStyles, excludeProps);
179 |
180 | if (data['merge']) {
181 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].removeDoubleTextStyles(textStyles);
182 | }
183 |
184 | cb(textStyles, data);
185 | });
186 | });
187 | ;
188 |
189 | /***/ }),
190 |
191 | /***/ "./src/json-export.js":
192 | /*!****************************!*\
193 | !*** ./src/json-export.js ***!
194 | \****************************/
195 | /*! exports provided: default */
196 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
197 |
198 | "use strict";
199 | __webpack_require__.r(__webpack_exports__);
200 | /* harmony import */ var _util_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util/ui */ "./src/util/ui.js");
201 | /* harmony import */ var _util_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./util/string */ "./src/util/string.js");
202 | /* harmony import */ var _util_export__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./util/export */ "./src/util/export.js");
203 | /* harmony import */ var _export_open_export_dialog__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./export/open-export-dialog */ "./src/export/open-export-dialog.js");
204 |
205 |
206 |
207 |
208 | /* harmony default export */ __webpack_exports__["default"] = (function (context) {
209 | Object(_export_open_export_dialog__WEBPACK_IMPORTED_MODULE_3__["default"])(context, {
210 | title: 'JSON export',
211 | informativeText: 'Export text styles in JSON format'
212 | }, function (textStyles, data) {
213 | // Export as JSON
214 | var textStyleJson = {};
215 | textStyles.forEach(function (textStyle, i) {
216 | var textStyleIdentifier = _util_string__WEBPACK_IMPORTED_MODULE_1__["default"].slugify(textStyle.name);
217 | var stylePropertyNaming = data.namingPrefix + '-' + (data.namingConvention === 'Numeric' ? i + 1 : textStyleIdentifier);
218 | textStyleJson[stylePropertyNaming] = _util_export__WEBPACK_IMPORTED_MODULE_2__["default"].createCssProps(textStyle, data);
219 | }); // Ask the user to save the file
220 |
221 | _util_ui__WEBPACK_IMPORTED_MODULE_0__["default"].createSavePanel('typex-text-styles.json', JSON.stringify(textStyleJson));
222 | });
223 | });
224 | ;
225 |
226 | /***/ }),
227 |
228 | /***/ "./src/util/export.js":
229 | /*!****************************!*\
230 | !*** ./src/util/export.js ***!
231 | \****************************/
232 | /*! exports provided: default */
233 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
234 |
235 | "use strict";
236 | __webpack_require__.r(__webpack_exports__);
237 | /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util */ "./src/util/util.js");
238 | /* harmony import */ var _number__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./number */ "./src/util/number.js");
239 |
240 |
241 |
242 |
243 | var exportUtils = {
244 | sortTextStyles: function sortTextStyles(textStyles) {
245 | // Sort text styles by size
246 | textStyles.sort(function (a, b) {
247 | return a.fontSize - b.fontSize;
248 | });
249 | return textStyles;
250 | },
251 | excludeTextStyleProperties: function excludeTextStyleProperties(textStyles) {
252 | var excludedProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
253 | textStyles.forEach(function (textStyle) {
254 | excludedProps.forEach(function (prop) {
255 | if (textStyle[prop]) {
256 | delete textStyle[prop];
257 | }
258 | });
259 | });
260 | return textStyles;
261 | },
262 | removeDoubleTextStyles: function removeDoubleTextStyles(textStyles) {
263 | var uniqueTextStyles = {};
264 | var filtered = [];
265 | textStyles.forEach(function (textStyle, i) {
266 | var id = _util__WEBPACK_IMPORTED_MODULE_0__["default"].createTextStyleId(textStyle);
267 |
268 | if (!uniqueTextStyles[id]) {
269 | uniqueTextStyles[id] = true;
270 | filtered.push(textStyle);
271 | }
272 | });
273 | return filtered;
274 | },
275 | createCssProps: function createCssProps(textStyle) {
276 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
277 | opts.cssUnit = opts.cssUnit || 0;
278 | opts.scalingFactor = opts.scalingFactor || 1;
279 | opts.maxDecimalPlaces = opts.maxDecimalPlaces || 2;
280 | var cssProps = {};
281 | cssProps['font-family'] = textStyle.fontFamily;
282 | cssProps['font-weight'] = 400;
283 | cssProps['text-transform'] = 'none';
284 | var fontParts = textStyle.fontFamily.split('-');
285 | var fontWeightMap = {
286 | 'Thin': 100,
287 | 'Light': 300,
288 | 'Regular': 400,
289 | 'Medium': 500,
290 | 'Bold': 700,
291 | 'Black': 900
292 | };
293 |
294 | if (fontParts[1] && fontWeightMap[fontParts[1]]) {
295 | cssProps['font-family'] = fontParts[0];
296 | cssProps['font-weight'] = fontWeightMap[fontParts[1]];
297 | }
298 |
299 | cssProps['font-size'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(opts.scalingFactor * textStyle.fontSize, opts.maxDecimalPlaces) + opts.cssUnit;
300 | cssProps['letter-spacing'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(opts.scalingFactor * textStyle.letterSpacing, opts.maxDecimalPlaces) + opts.cssUnit;
301 |
302 | if (textStyle.textTransform === 1) {
303 | cssProps['text-transform'] = 'uppercase';
304 | }
305 |
306 | if (textStyle.textTransform === 2) {
307 | cssProps['text-transform'] = 'lowercase';
308 | }
309 |
310 | if (textStyle.lineHeight) {
311 | cssProps['line-height'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(1 + (textStyle.lineHeight - textStyle.fontSize) / textStyle.lineHeight, opts.maxDecimalPlaces);
312 | }
313 |
314 | if (textStyle.color) {
315 | cssProps['color'] = exportUtils.createRgbaString(textStyle.color);
316 | }
317 |
318 | return cssProps;
319 | },
320 | createRgbaString: function createRgbaString(colorObj) {
321 | return 'rgba(' + exportUtils.createColorValue(colorObj.r) + ', ' + exportUtils.createColorValue(colorObj.g) + ', ' + exportUtils.createColorValue(colorObj.b) + ', ' + colorObj.a + ')';
322 | },
323 | createColorValue: function createColorValue(normalizedValue) {
324 | return Math.round(normalizedValue * 255);
325 | },
326 | createStyleBlock: function createStyleBlock(cssProps) {
327 | var output = '';
328 |
329 | for (var prop in cssProps) {
330 | output += "\t" + prop + ': ' + cssProps[prop] + ';' + "\n";
331 | }
332 |
333 | return output;
334 | },
335 | createInlineStyleString: function createInlineStyleString(cssProps) {
336 | var styleString = '';
337 |
338 | for (var prop in cssProps) {
339 | styleString += prop + ': ' + cssProps[prop] + '; ';
340 | }
341 |
342 | return styleString;
343 | },
344 | createHtmlFontbook: function createHtmlFontbook(textStyles) {
345 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
346 | var output = "\n \n \n \n \n Typex text styles\n \n \n ";
347 | textStyles.forEach(function (textStyle, i) {
348 | var cssProps = exportUtils.createCssProps(textStyle, opts);
349 | var inlineStyleString = exportUtils.createInlineStyleString(cssProps);
350 | var cssPropsBlock = exportUtils.createStyleBlock(cssProps);
351 | var textStyleName;
352 |
353 | if (opts.namingConvention === 'Numeric') {
354 | textStyleName = opts.namingPrefix + ' ' + (i + 1);
355 | } else if (opts.namingConvention === 'Text style name') {
356 | textStyleName = opts.namingPrefix + ' ' + textStyle.name;
357 | } else {
358 | textStyleName = opts.namingPrefix + ' ' + (i + 1) + ' (' + textStyle.name + ')';
359 | }
360 |
361 | output += "\n \n
\n ".concat(i + 1, ".\n \n ").concat(textStyleName, "\n \n
\n
\n
\n The quick brown fox jumps over the lazy dog\n
\n
\n \n
\n
\n
\n ");
362 | });
363 | output += "\n \n \n ";
364 | return output;
365 | }
366 | };
367 | /* harmony default export */ __webpack_exports__["default"] = (exportUtils);
368 |
369 | /***/ }),
370 |
371 | /***/ "./src/util/number.js":
372 | /*!****************************!*\
373 | !*** ./src/util/number.js ***!
374 | \****************************/
375 | /*! exports provided: default */
376 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
377 |
378 | "use strict";
379 | __webpack_require__.r(__webpack_exports__);
380 |
381 |
382 | var number = {
383 | parseFloatMaxDecimal: function parseFloatMaxDecimal(number, maxDecimalPlaces) {
384 | return Number(number.toFixed(maxDecimalPlaces).replace(/[.,]00$/, ''));
385 | }
386 | };
387 | /* harmony default export */ __webpack_exports__["default"] = (number);
388 |
389 | /***/ }),
390 |
391 | /***/ "./src/util/sketch.js":
392 | /*!****************************!*\
393 | !*** ./src/util/sketch.js ***!
394 | \****************************/
395 | /*! exports provided: default */
396 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
397 |
398 | "use strict";
399 | __webpack_require__.r(__webpack_exports__);
400 |
401 |
402 | var sketch = {
403 | getTextStyles: function getTextStyles(context) {
404 | var texts = context.document.documentData().layerTextStyles().objects();
405 | var rawTextStyles = [];
406 | texts.forEach(function (text, i) {
407 | rawTextStyles.push({
408 | attributes: text.style().textStyle().attributes(),
409 | textStyle: text,
410 | name: text.name()
411 | });
412 | });
413 | var textStyles = [];
414 | rawTextStyles.forEach(function (rawTextStyle) {
415 | var textStyle = {};
416 | textStyle.name = rawTextStyle.name;
417 | textStyle.fontFamily = String(rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontNameAttribute));
418 | textStyle.fontSize = rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontSizeAttribute);
419 | textStyle.paragraph = rawTextStyle.attributes.NSParagraphStyle;
420 |
421 | if (textStyle.paragraph) {
422 | textStyle.lineHeight = textStyle.paragraph.maximumLineHeight();
423 | }
424 |
425 | var color = rawTextStyle.attributes.MSAttributedStringColorAttribute;
426 |
427 | if (color) {
428 | var r = color.red();
429 | var g = color.green();
430 | var b = color.blue();
431 | var a = color.alpha();
432 | textStyle.color = {
433 | r: r,
434 | g: g,
435 | b: b,
436 | a: a
437 | };
438 | }
439 |
440 | textStyle.letterSpacing = rawTextStyle.attributes.NSKern || 0;
441 | textStyle.textTransform = parseInt(rawTextStyle.attributes.MSAttributedStringTextTransformAttribute || 0); // @TODO strikethrough & underline, or is this not needed?
442 |
443 | textStyles.push(textStyle);
444 | });
445 | return textStyles;
446 | }
447 | };
448 | /* harmony default export */ __webpack_exports__["default"] = (sketch);
449 |
450 | /***/ }),
451 |
452 | /***/ "./src/util/string.js":
453 | /*!****************************!*\
454 | !*** ./src/util/string.js ***!
455 | \****************************/
456 | /*! exports provided: default */
457 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
458 |
459 | "use strict";
460 | __webpack_require__.r(__webpack_exports__);
461 |
462 |
463 | var string = {
464 | slugify: function slugify(str) {
465 | str = str.replace(/^\s+|\s+$/g, ''); // trim
466 |
467 | str = str.toLowerCase(); // remove accents, swap ñ for n, etc
468 |
469 | var from = 'àáäâèéëêìíïîòóöôùúüûñç·/_,:;';
470 | var to = 'aaaaeeeeiiiioooouuuunc------';
471 |
472 | for (var i = 0, l = from.length; i < l; i++) {
473 | str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
474 | }
475 |
476 | str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
477 | .replace(/\s+/g, '-') // collapse whitespace and replace by -
478 | .replace(/-+/g, '-') // collapse dashes
479 | ;
480 | return str;
481 | }
482 | };
483 | /* harmony default export */ __webpack_exports__["default"] = (string);
484 |
485 | /***/ }),
486 |
487 | /***/ "./src/util/ui.js":
488 | /*!************************!*\
489 | !*** ./src/util/ui.js ***!
490 | \************************/
491 | /*! exports provided: default */
492 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
493 |
494 | "use strict";
495 | __webpack_require__.r(__webpack_exports__);
496 |
497 |
498 | var ui = {
499 | createSavePanel: function createSavePanel(defaultFileName, contents) {
500 | var save = NSSavePanel.savePanel();
501 | save.setNameFieldStringValue(defaultFileName);
502 | save.setAllowsOtherFileTypes(false);
503 | save.setExtensionHidden(false);
504 |
505 | if (save.runModal()) {
506 | var file = NSString.stringWithString(contents);
507 | var path = save.URL().path();
508 | file.writeToFile_atomically_encoding_error(path, true, NSUTF8StringEncoding, null);
509 | }
510 | },
511 | createLabel: function createLabel() {
512 | var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
513 | var label = NSTextField.alloc().init();
514 | label.setStringValue(text);
515 | label.setFont(NSFont.boldSystemFontOfSize(12));
516 | label.setBezeled(false);
517 | label.setDrawsBackground(false);
518 | label.setEditable(false);
519 | label.setSelectable(false);
520 | return label;
521 | },
522 | createTextField: function createTextField(value) {
523 | var field = NSTextField.alloc().init();
524 | field.setStringValue(value);
525 | return field;
526 | },
527 | createSelect: function createSelect(options) {
528 | var comboBox = NSPopUpButton.alloc().init();
529 | comboBox.addItemsWithTitles(options);
530 | comboBox.selectItemAtIndex(0);
531 | return comboBox;
532 | },
533 | createStepper: function createStepper(value) {
534 | var stepper = NSStepper.alloc().init();
535 | return stepper;
536 | },
537 | createCheckbox: function createCheckbox(title) {
538 | var checkbox = NSButton.alloc().init();
539 | checkbox.setButtonType(NSSwitchButton);
540 | checkbox.title = title;
541 | return checkbox;
542 | },
543 | createSettingsDialog: function createSettingsDialog(context) {
544 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
545 | var components = arguments.length > 2 ? arguments[2] : undefined;
546 | var cb = arguments.length > 3 ? arguments[3] : undefined;
547 | opts.title = opts.title || 'Alert';
548 | opts.informativeText = opts.informativeText || '';
549 | opts.cancelBtnText = opts.cancelBtnText || 'Cancel';
550 | opts.confirmBtnText = opts.confirmBtnText || 'Ok';
551 | var dialog = NSAlert.alloc().init();
552 | var dialogIconPath = context.plugin.urlForResourceNamed('icon.png').path();
553 | var dialogIcon = NSImage.alloc().initByReferencingFile(dialogIconPath);
554 | dialog.setIcon(dialogIcon);
555 | dialog.setMessageText(opts.title);
556 | dialog.setInformativeText(opts.informativeText);
557 | var btnConfirm = dialog.addButtonWithTitle(opts.confirmBtnText);
558 | var btnCancel = dialog.addButtonWithTitle(opts.cancelBtnText); // Create grid view
559 |
560 | var gridView = NSGridView.alloc().init(); // Create object to hold all inputs
561 |
562 | var inputs = {};
563 | var height = 0;
564 | var rowSpacing = 8; // Loop each component
565 |
566 | components.forEach(function (c) {
567 | var label, field;
568 |
569 | switch (c.type) {
570 | case 'text':
571 | label = ui.createLabel(c.label);
572 | field = ui.createTextField(c.value);
573 | height += 22 + rowSpacing;
574 | gridView.addRowWithViews([label, field]);
575 | break;
576 |
577 | case 'stepper':
578 | label = ui.createLabel(c.label);
579 | field = ui.createStepper(c.value);
580 | height += 22 + rowSpacing;
581 | gridView.addRowWithViews([label, field]);
582 | break;
583 |
584 | case 'checkbox':
585 | label = ui.createLabel(c.label);
586 | field = ui.createCheckbox(c.value);
587 | height += 22 + rowSpacing;
588 | gridView.addRowWithViews([label, field]);
589 | break;
590 |
591 | case 'multicheckbox':
592 | field = [];
593 | c.values.forEach(function (v, i) {
594 | label = i ? ui.createLabel() : ui.createLabel(c.label);
595 | var checkbox = ui.createCheckbox(v);
596 | height += 22 + rowSpacing;
597 | field.push(checkbox);
598 | gridView.addRowWithViews([label, checkbox]);
599 | });
600 | break;
601 |
602 | case 'select':
603 | label = ui.createLabel(c.label);
604 | field = ui.createSelect(c.options);
605 | height += 28 + rowSpacing;
606 | gridView.addRowWithViews([label, field]);
607 | break;
608 | }
609 |
610 | inputs[c.id] = field;
611 | }); // Set grid view as view of dialog
612 |
613 | dialog.accessoryView = gridView;
614 | gridView.columnSpacing = 30;
615 | gridView.rowSpacing = rowSpacing;
616 | gridView.frame = NSMakeRect(0, 0, 400, height); // Open the dialog and store the response code
617 |
618 | var responseCode = dialog.runModal(); // The dialog is being 'submitted'
619 |
620 | if (responseCode === 1000) {
621 | var data = {};
622 | components.forEach(function (c) {
623 | switch (c.type) {
624 | case 'text':
625 | data[c.id] = inputs[c.id].stringValue();
626 | break;
627 |
628 | case 'select':
629 | data[c.id] = c.options[inputs[c.id].indexOfSelectedItem()];
630 | break;
631 |
632 | case 'checkbox':
633 | data[c.id] = inputs[c.id].state() === 1;
634 | break;
635 |
636 | case 'multicheckbox':
637 | var values = {};
638 | c.values.forEach(function (v, i) {
639 | values[v] = inputs[c.id][i].state() === 1;
640 | });
641 | data[c.id] = values;
642 | }
643 | });
644 | cb(data);
645 | return;
646 | }
647 |
648 | return dialog;
649 | }
650 | };
651 | /* harmony default export */ __webpack_exports__["default"] = (ui);
652 |
653 | /***/ }),
654 |
655 | /***/ "./src/util/util.js":
656 | /*!**************************!*\
657 | !*** ./src/util/util.js ***!
658 | \**************************/
659 | /*! exports provided: default */
660 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
661 |
662 | "use strict";
663 | __webpack_require__.r(__webpack_exports__);
664 |
665 |
666 | var util = {
667 | createTextStyleId: function createTextStyleId(textStyle) {
668 | var textStyleId = ''; // Make sure this id incorporates every possible property of the text style
669 |
670 | textStyleId += textStyle.fontFamily;
671 | textStyleId += '-' + textStyle.fontSize;
672 | textStyleId += '-' + textStyle.letterSpacing;
673 | textStyleId += '-' + textStyle.textTransform;
674 |
675 | if (textStyle.lineHeight) {
676 | textStyleId += '-' + textStyle.lineHeight;
677 | }
678 |
679 | if (textStyle.color) {
680 | textStyleId += '-' + textStyle.color.r + '-' + textStyle.color.g + '-' + textStyle.color.b + '-' + textStyle.color.a;
681 | }
682 |
683 | return textStyleId;
684 | }
685 | };
686 | /* harmony default export */ __webpack_exports__["default"] = (util);
687 |
688 | /***/ })
689 |
690 | /******/ });
691 | if (key === 'default' && typeof exports === 'function') {
692 | exports(context);
693 | } else {
694 | exports[key](context);
695 | }
696 | }
697 | that['onRun'] = __skpm_run.bind(this, 'default')
698 |
699 | //# sourceMappingURL=json-export.js.map
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "compatibleVersion": 3,
3 | "bundleVersion": 1,
4 | "icon": "icon.png",
5 | "commands": [
6 | {
7 | "name": "HTML fontbook",
8 | "shortcut": "ctrl shift f",
9 | "identifier": "html-fontbook-export",
10 | "script": "html-fontbook-export.js"
11 | },
12 | {
13 | "name": "JSON",
14 | "shortcut": "ctrl shift j",
15 | "identifier": "json-export",
16 | "script": "json-export.js"
17 | },
18 | {
19 | "name": "CSS classes",
20 | "shortcut": "ctrl shift c",
21 | "identifier": "css-export",
22 | "script": "css-export.js"
23 | },
24 | {
25 | "name": "SASS mixins",
26 | "shortcut": "ctrl shift s",
27 | "identifier": "sass-mixins-export",
28 | "script": "sass-mixins-export.js"
29 | }
30 | ],
31 | "menu": {
32 | "title": "Typex (Text style export)",
33 | "items": [
34 | {
35 | "title": "Export",
36 | "items": [
37 | "html-fontbook-export",
38 | "json-export",
39 | "css-export",
40 | "sass-mixins-export"
41 | ]
42 | }
43 | ]
44 | },
45 | "version": "1.0.0",
46 | "description": "Text styles to CSS, SASS mixins, HTML, JSON, ...",
47 | "name": "typex",
48 | "identifier": "typex",
49 | "disableCocoaScriptPreprocessor": true,
50 | "appcast": "https://raw.githubusercontent.com/reinvanoyen/typex/master/.appcast.xml"
51 | }
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/my-command.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap","webpack://exports/./src/my-command.js"],"names":["context","document","showMessage"],"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,+DAAe,UAASA,OAAT,EAAkB;AAC/BA,SAAO,CAACC,QAAR,CAAiBC,WAAjB,CAA6B,eAA7B;AACD,C","file":"my-command.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/my-command.js\");\n","export default function(context) {\n context.document.showMessage(\"It's alive 🙌\")\n}\n"],"sourceRoot":""}
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/sass-mixins-export.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/sass-mixins-export.js");
90 | /******/ })
91 | /************************************************************************/
92 | /******/ ({
93 |
94 | /***/ "./src/export/export-components.js":
95 | /*!*****************************************!*\
96 | !*** ./src/export/export-components.js ***!
97 | \*****************************************/
98 | /*! exports provided: default */
99 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
100 |
101 | "use strict";
102 | __webpack_require__.r(__webpack_exports__);
103 | /* harmony default export */ __webpack_exports__["default"] = ([{
104 | type: 'checkbox',
105 | id: 'merge',
106 | label: 'Merge',
107 | value: 'Merge identical styles'
108 | }, {
109 | type: 'multicheckbox',
110 | id: 'excludeProps',
111 | label: 'Exclude properties',
112 | values: ['Color', 'Line height']
113 | }, {
114 | type: 'select',
115 | id: 'cssUnit',
116 | options: ['px', 'em', 'rem', '%', 'vh', 'vw', 'No unit'],
117 | label: 'CSS unit'
118 | }, {
119 | type: 'text',
120 | id: 'scalingFactor',
121 | value: 1,
122 | label: 'Size scaling factor'
123 | }, {
124 | type: 'text',
125 | id: 'maxDecimalPlaces',
126 | value: 2,
127 | label: 'Maximal decimal places'
128 | }, {
129 | type: 'text',
130 | id: 'namingPrefix',
131 | value: 'type',
132 | label: 'Naming prefix'
133 | }, {
134 | type: 'select',
135 | id: 'namingConvention',
136 | options: ['Numeric', 'Text style name'],
137 | label: 'Naming convention'
138 | }]);
139 |
140 | /***/ }),
141 |
142 | /***/ "./src/export/open-export-dialog.js":
143 | /*!******************************************!*\
144 | !*** ./src/export/open-export-dialog.js ***!
145 | \******************************************/
146 | /*! exports provided: default */
147 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
148 |
149 | "use strict";
150 | __webpack_require__.r(__webpack_exports__);
151 | /* harmony import */ var _util_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../util/ui */ "./src/util/ui.js");
152 | /* harmony import */ var _util_export__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../util/export */ "./src/util/export.js");
153 | /* harmony import */ var _util_sketch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../util/sketch */ "./src/util/sketch.js");
154 | /* harmony import */ var _export_components__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./export-components */ "./src/export/export-components.js");
155 |
156 |
157 |
158 |
159 | /* harmony default export */ __webpack_exports__["default"] = (function (context, opts, cb) {
160 | _util_ui__WEBPACK_IMPORTED_MODULE_0__["default"].createSettingsDialog(context, opts, _export_components__WEBPACK_IMPORTED_MODULE_3__["default"], function (data) {
161 | // Defaults
162 | data.propertyNamingConvention = data.propertyNamingConvention || 'Numeric';
163 | data.cssUnit = data.cssUnit === 'No unit' ? 0 : data.cssUnit; // First store the properties we should exclude
164 |
165 | var excludeProps = [];
166 |
167 | if (data['excludeProps']['Color']) {
168 | excludeProps.push('color');
169 | }
170 |
171 | if (data['excludeProps']['Line height']) {
172 | excludeProps.push('lineHeight');
173 | } // Get the text styles from the Sketch document
174 |
175 |
176 | var textStyles = _util_sketch__WEBPACK_IMPORTED_MODULE_2__["default"].getTextStyles(context);
177 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].sortTextStyles(textStyles);
178 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].excludeTextStyleProperties(textStyles, excludeProps);
179 |
180 | if (data['merge']) {
181 | textStyles = _util_export__WEBPACK_IMPORTED_MODULE_1__["default"].removeDoubleTextStyles(textStyles);
182 | }
183 |
184 | cb(textStyles, data);
185 | });
186 | });
187 | ;
188 |
189 | /***/ }),
190 |
191 | /***/ "./src/sass-mixins-export.js":
192 | /*!***********************************!*\
193 | !*** ./src/sass-mixins-export.js ***!
194 | \***********************************/
195 | /*! exports provided: default */
196 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
197 |
198 | "use strict";
199 | __webpack_require__.r(__webpack_exports__);
200 | /* harmony import */ var _util_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util/ui */ "./src/util/ui.js");
201 | /* harmony import */ var _util_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./util/string */ "./src/util/string.js");
202 | /* harmony import */ var _util_export__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./util/export */ "./src/util/export.js");
203 | /* harmony import */ var _export_open_export_dialog__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./export/open-export-dialog */ "./src/export/open-export-dialog.js");
204 |
205 |
206 |
207 |
208 | /* harmony default export */ __webpack_exports__["default"] = (function (context) {
209 | Object(_export_open_export_dialog__WEBPACK_IMPORTED_MODULE_3__["default"])(context, {
210 | title: 'SASS mixins export',
211 | informativeText: 'Export each text style as a SASS mixin'
212 | }, function (textStyles, data) {
213 | var sass = {};
214 | textStyles.forEach(function (textStyle) {
215 | sass[_util_string__WEBPACK_IMPORTED_MODULE_1__["default"].slugify(textStyle.name)] = _util_export__WEBPACK_IMPORTED_MODULE_2__["default"].createCssProps(textStyle, data);
216 | });
217 | var output = '';
218 | var i = 0;
219 |
220 | for (var identifier in sass) {
221 | if (sass.hasOwnProperty(identifier)) {
222 | var mixinName = data.namingPrefix + '-' + (data.namingConvention === 'Numeric' ? i + 1 : identifier);
223 | output += (i !== 0 ? "\n" : '') + '@mixin ' + mixinName + "\n";
224 | output += '{' + "\n";
225 | output += _util_export__WEBPACK_IMPORTED_MODULE_2__["default"].createStyleBlock(sass[identifier]);
226 | output += '}' + "\n";
227 | i++;
228 | }
229 | }
230 |
231 | _util_ui__WEBPACK_IMPORTED_MODULE_0__["default"].createSavePanel('typex-mixins.scss', output);
232 | });
233 | });
234 | ;
235 |
236 | /***/ }),
237 |
238 | /***/ "./src/util/export.js":
239 | /*!****************************!*\
240 | !*** ./src/util/export.js ***!
241 | \****************************/
242 | /*! exports provided: default */
243 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
244 |
245 | "use strict";
246 | __webpack_require__.r(__webpack_exports__);
247 | /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util */ "./src/util/util.js");
248 | /* harmony import */ var _number__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./number */ "./src/util/number.js");
249 |
250 |
251 |
252 |
253 | var exportUtils = {
254 | sortTextStyles: function sortTextStyles(textStyles) {
255 | // Sort text styles by size
256 | textStyles.sort(function (a, b) {
257 | return a.fontSize - b.fontSize;
258 | });
259 | return textStyles;
260 | },
261 | excludeTextStyleProperties: function excludeTextStyleProperties(textStyles) {
262 | var excludedProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
263 | textStyles.forEach(function (textStyle) {
264 | excludedProps.forEach(function (prop) {
265 | if (textStyle[prop]) {
266 | delete textStyle[prop];
267 | }
268 | });
269 | });
270 | return textStyles;
271 | },
272 | removeDoubleTextStyles: function removeDoubleTextStyles(textStyles) {
273 | var uniqueTextStyles = {};
274 | var filtered = [];
275 | textStyles.forEach(function (textStyle, i) {
276 | var id = _util__WEBPACK_IMPORTED_MODULE_0__["default"].createTextStyleId(textStyle);
277 |
278 | if (!uniqueTextStyles[id]) {
279 | uniqueTextStyles[id] = true;
280 | filtered.push(textStyle);
281 | }
282 | });
283 | return filtered;
284 | },
285 | createCssProps: function createCssProps(textStyle) {
286 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
287 | opts.cssUnit = opts.cssUnit || 0;
288 | opts.scalingFactor = opts.scalingFactor || 1;
289 | opts.maxDecimalPlaces = opts.maxDecimalPlaces || 2;
290 | var cssProps = {};
291 | cssProps['font-family'] = textStyle.fontFamily;
292 | cssProps['font-weight'] = 400;
293 | cssProps['text-transform'] = 'none';
294 | var fontParts = textStyle.fontFamily.split('-');
295 | var fontWeightMap = {
296 | 'Thin': 100,
297 | 'Light': 300,
298 | 'Regular': 400,
299 | 'Medium': 500,
300 | 'Bold': 700,
301 | 'Black': 900
302 | };
303 |
304 | if (fontParts[1] && fontWeightMap[fontParts[1]]) {
305 | cssProps['font-family'] = fontParts[0];
306 | cssProps['font-weight'] = fontWeightMap[fontParts[1]];
307 | }
308 |
309 | cssProps['font-size'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(opts.scalingFactor * textStyle.fontSize, opts.maxDecimalPlaces) + opts.cssUnit;
310 | cssProps['letter-spacing'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(opts.scalingFactor * textStyle.letterSpacing, opts.maxDecimalPlaces) + opts.cssUnit;
311 |
312 | if (textStyle.textTransform === 1) {
313 | cssProps['text-transform'] = 'uppercase';
314 | }
315 |
316 | if (textStyle.textTransform === 2) {
317 | cssProps['text-transform'] = 'lowercase';
318 | }
319 |
320 | if (textStyle.lineHeight) {
321 | cssProps['line-height'] = _number__WEBPACK_IMPORTED_MODULE_1__["default"].parseFloatMaxDecimal(1 + (textStyle.lineHeight - textStyle.fontSize) / textStyle.lineHeight, opts.maxDecimalPlaces);
322 | }
323 |
324 | if (textStyle.color) {
325 | cssProps['color'] = exportUtils.createRgbaString(textStyle.color);
326 | }
327 |
328 | return cssProps;
329 | },
330 | createRgbaString: function createRgbaString(colorObj) {
331 | return 'rgba(' + exportUtils.createColorValue(colorObj.r) + ', ' + exportUtils.createColorValue(colorObj.g) + ', ' + exportUtils.createColorValue(colorObj.b) + ', ' + colorObj.a + ')';
332 | },
333 | createColorValue: function createColorValue(normalizedValue) {
334 | return Math.round(normalizedValue * 255);
335 | },
336 | createStyleBlock: function createStyleBlock(cssProps) {
337 | var output = '';
338 |
339 | for (var prop in cssProps) {
340 | output += "\t" + prop + ': ' + cssProps[prop] + ';' + "\n";
341 | }
342 |
343 | return output;
344 | },
345 | createInlineStyleString: function createInlineStyleString(cssProps) {
346 | var styleString = '';
347 |
348 | for (var prop in cssProps) {
349 | styleString += prop + ': ' + cssProps[prop] + '; ';
350 | }
351 |
352 | return styleString;
353 | },
354 | createHtmlFontbook: function createHtmlFontbook(textStyles) {
355 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
356 | var output = "\n \n \n \n \n Typex text styles\n \n \n ";
357 | textStyles.forEach(function (textStyle, i) {
358 | var cssProps = exportUtils.createCssProps(textStyle, opts);
359 | var inlineStyleString = exportUtils.createInlineStyleString(cssProps);
360 | var cssPropsBlock = exportUtils.createStyleBlock(cssProps);
361 | var textStyleName;
362 |
363 | if (opts.namingConvention === 'Numeric') {
364 | textStyleName = opts.namingPrefix + ' ' + (i + 1);
365 | } else if (opts.namingConvention === 'Text style name') {
366 | textStyleName = opts.namingPrefix + ' ' + textStyle.name;
367 | } else {
368 | textStyleName = opts.namingPrefix + ' ' + (i + 1) + ' (' + textStyle.name + ')';
369 | }
370 |
371 | output += "\n \n
\n ".concat(i + 1, ".\n \n ").concat(textStyleName, "\n \n
\n
\n
\n The quick brown fox jumps over the lazy dog\n
\n
\n \n
\n
\n
\n ");
372 | });
373 | output += "\n \n \n ";
374 | return output;
375 | }
376 | };
377 | /* harmony default export */ __webpack_exports__["default"] = (exportUtils);
378 |
379 | /***/ }),
380 |
381 | /***/ "./src/util/number.js":
382 | /*!****************************!*\
383 | !*** ./src/util/number.js ***!
384 | \****************************/
385 | /*! exports provided: default */
386 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
387 |
388 | "use strict";
389 | __webpack_require__.r(__webpack_exports__);
390 |
391 |
392 | var number = {
393 | parseFloatMaxDecimal: function parseFloatMaxDecimal(number, maxDecimalPlaces) {
394 | return Number(number.toFixed(maxDecimalPlaces).replace(/[.,]00$/, ''));
395 | }
396 | };
397 | /* harmony default export */ __webpack_exports__["default"] = (number);
398 |
399 | /***/ }),
400 |
401 | /***/ "./src/util/sketch.js":
402 | /*!****************************!*\
403 | !*** ./src/util/sketch.js ***!
404 | \****************************/
405 | /*! exports provided: default */
406 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
407 |
408 | "use strict";
409 | __webpack_require__.r(__webpack_exports__);
410 |
411 |
412 | var sketch = {
413 | getTextStyles: function getTextStyles(context) {
414 | var texts = context.document.documentData().layerTextStyles().objects();
415 | var rawTextStyles = [];
416 | texts.forEach(function (text, i) {
417 | rawTextStyles.push({
418 | attributes: text.style().textStyle().attributes(),
419 | textStyle: text,
420 | name: text.name()
421 | });
422 | });
423 | var textStyles = [];
424 | rawTextStyles.forEach(function (rawTextStyle) {
425 | var textStyle = {};
426 | textStyle.name = rawTextStyle.name;
427 | textStyle.fontFamily = String(rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontNameAttribute));
428 | textStyle.fontSize = rawTextStyle.attributes.NSFont.fontDescriptor().objectForKey(NSFontSizeAttribute);
429 | textStyle.paragraph = rawTextStyle.attributes.NSParagraphStyle;
430 |
431 | if (textStyle.paragraph) {
432 | textStyle.lineHeight = textStyle.paragraph.maximumLineHeight();
433 | }
434 |
435 | var color = rawTextStyle.attributes.MSAttributedStringColorAttribute;
436 |
437 | if (color) {
438 | var r = color.red();
439 | var g = color.green();
440 | var b = color.blue();
441 | var a = color.alpha();
442 | textStyle.color = {
443 | r: r,
444 | g: g,
445 | b: b,
446 | a: a
447 | };
448 | }
449 |
450 | textStyle.letterSpacing = rawTextStyle.attributes.NSKern || 0;
451 | textStyle.textTransform = parseInt(rawTextStyle.attributes.MSAttributedStringTextTransformAttribute || 0); // @TODO strikethrough & underline, or is this not needed?
452 |
453 | textStyles.push(textStyle);
454 | });
455 | return textStyles;
456 | }
457 | };
458 | /* harmony default export */ __webpack_exports__["default"] = (sketch);
459 |
460 | /***/ }),
461 |
462 | /***/ "./src/util/string.js":
463 | /*!****************************!*\
464 | !*** ./src/util/string.js ***!
465 | \****************************/
466 | /*! exports provided: default */
467 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
468 |
469 | "use strict";
470 | __webpack_require__.r(__webpack_exports__);
471 |
472 |
473 | var string = {
474 | slugify: function slugify(str) {
475 | str = str.replace(/^\s+|\s+$/g, ''); // trim
476 |
477 | str = str.toLowerCase(); // remove accents, swap ñ for n, etc
478 |
479 | var from = 'àáäâèéëêìíïîòóöôùúüûñç·/_,:;';
480 | var to = 'aaaaeeeeiiiioooouuuunc------';
481 |
482 | for (var i = 0, l = from.length; i < l; i++) {
483 | str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
484 | }
485 |
486 | str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
487 | .replace(/\s+/g, '-') // collapse whitespace and replace by -
488 | .replace(/-+/g, '-') // collapse dashes
489 | ;
490 | return str;
491 | }
492 | };
493 | /* harmony default export */ __webpack_exports__["default"] = (string);
494 |
495 | /***/ }),
496 |
497 | /***/ "./src/util/ui.js":
498 | /*!************************!*\
499 | !*** ./src/util/ui.js ***!
500 | \************************/
501 | /*! exports provided: default */
502 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
503 |
504 | "use strict";
505 | __webpack_require__.r(__webpack_exports__);
506 |
507 |
508 | var ui = {
509 | createSavePanel: function createSavePanel(defaultFileName, contents) {
510 | var save = NSSavePanel.savePanel();
511 | save.setNameFieldStringValue(defaultFileName);
512 | save.setAllowsOtherFileTypes(false);
513 | save.setExtensionHidden(false);
514 |
515 | if (save.runModal()) {
516 | var file = NSString.stringWithString(contents);
517 | var path = save.URL().path();
518 | file.writeToFile_atomically_encoding_error(path, true, NSUTF8StringEncoding, null);
519 | }
520 | },
521 | createLabel: function createLabel() {
522 | var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
523 | var label = NSTextField.alloc().init();
524 | label.setStringValue(text);
525 | label.setFont(NSFont.boldSystemFontOfSize(12));
526 | label.setBezeled(false);
527 | label.setDrawsBackground(false);
528 | label.setEditable(false);
529 | label.setSelectable(false);
530 | return label;
531 | },
532 | createTextField: function createTextField(value) {
533 | var field = NSTextField.alloc().init();
534 | field.setStringValue(value);
535 | return field;
536 | },
537 | createSelect: function createSelect(options) {
538 | var comboBox = NSPopUpButton.alloc().init();
539 | comboBox.addItemsWithTitles(options);
540 | comboBox.selectItemAtIndex(0);
541 | return comboBox;
542 | },
543 | createStepper: function createStepper(value) {
544 | var stepper = NSStepper.alloc().init();
545 | return stepper;
546 | },
547 | createCheckbox: function createCheckbox(title) {
548 | var checkbox = NSButton.alloc().init();
549 | checkbox.setButtonType(NSSwitchButton);
550 | checkbox.title = title;
551 | return checkbox;
552 | },
553 | createSettingsDialog: function createSettingsDialog(context) {
554 | var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
555 | var components = arguments.length > 2 ? arguments[2] : undefined;
556 | var cb = arguments.length > 3 ? arguments[3] : undefined;
557 | opts.title = opts.title || 'Alert';
558 | opts.informativeText = opts.informativeText || '';
559 | opts.cancelBtnText = opts.cancelBtnText || 'Cancel';
560 | opts.confirmBtnText = opts.confirmBtnText || 'Ok';
561 | var dialog = NSAlert.alloc().init();
562 | var dialogIconPath = context.plugin.urlForResourceNamed('icon.png').path();
563 | var dialogIcon = NSImage.alloc().initByReferencingFile(dialogIconPath);
564 | dialog.setIcon(dialogIcon);
565 | dialog.setMessageText(opts.title);
566 | dialog.setInformativeText(opts.informativeText);
567 | var btnConfirm = dialog.addButtonWithTitle(opts.confirmBtnText);
568 | var btnCancel = dialog.addButtonWithTitle(opts.cancelBtnText); // Create grid view
569 |
570 | var gridView = NSGridView.alloc().init(); // Create object to hold all inputs
571 |
572 | var inputs = {};
573 | var height = 0;
574 | var rowSpacing = 8; // Loop each component
575 |
576 | components.forEach(function (c) {
577 | var label, field;
578 |
579 | switch (c.type) {
580 | case 'text':
581 | label = ui.createLabel(c.label);
582 | field = ui.createTextField(c.value);
583 | height += 22 + rowSpacing;
584 | gridView.addRowWithViews([label, field]);
585 | break;
586 |
587 | case 'stepper':
588 | label = ui.createLabel(c.label);
589 | field = ui.createStepper(c.value);
590 | height += 22 + rowSpacing;
591 | gridView.addRowWithViews([label, field]);
592 | break;
593 |
594 | case 'checkbox':
595 | label = ui.createLabel(c.label);
596 | field = ui.createCheckbox(c.value);
597 | height += 22 + rowSpacing;
598 | gridView.addRowWithViews([label, field]);
599 | break;
600 |
601 | case 'multicheckbox':
602 | field = [];
603 | c.values.forEach(function (v, i) {
604 | label = i ? ui.createLabel() : ui.createLabel(c.label);
605 | var checkbox = ui.createCheckbox(v);
606 | height += 22 + rowSpacing;
607 | field.push(checkbox);
608 | gridView.addRowWithViews([label, checkbox]);
609 | });
610 | break;
611 |
612 | case 'select':
613 | label = ui.createLabel(c.label);
614 | field = ui.createSelect(c.options);
615 | height += 28 + rowSpacing;
616 | gridView.addRowWithViews([label, field]);
617 | break;
618 | }
619 |
620 | inputs[c.id] = field;
621 | }); // Set grid view as view of dialog
622 |
623 | dialog.accessoryView = gridView;
624 | gridView.columnSpacing = 30;
625 | gridView.rowSpacing = rowSpacing;
626 | gridView.frame = NSMakeRect(0, 0, 400, height); // Open the dialog and store the response code
627 |
628 | var responseCode = dialog.runModal(); // The dialog is being 'submitted'
629 |
630 | if (responseCode === 1000) {
631 | var data = {};
632 | components.forEach(function (c) {
633 | switch (c.type) {
634 | case 'text':
635 | data[c.id] = inputs[c.id].stringValue();
636 | break;
637 |
638 | case 'select':
639 | data[c.id] = c.options[inputs[c.id].indexOfSelectedItem()];
640 | break;
641 |
642 | case 'checkbox':
643 | data[c.id] = inputs[c.id].state() === 1;
644 | break;
645 |
646 | case 'multicheckbox':
647 | var values = {};
648 | c.values.forEach(function (v, i) {
649 | values[v] = inputs[c.id][i].state() === 1;
650 | });
651 | data[c.id] = values;
652 | }
653 | });
654 | cb(data);
655 | return;
656 | }
657 |
658 | return dialog;
659 | }
660 | };
661 | /* harmony default export */ __webpack_exports__["default"] = (ui);
662 |
663 | /***/ }),
664 |
665 | /***/ "./src/util/util.js":
666 | /*!**************************!*\
667 | !*** ./src/util/util.js ***!
668 | \**************************/
669 | /*! exports provided: default */
670 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
671 |
672 | "use strict";
673 | __webpack_require__.r(__webpack_exports__);
674 |
675 |
676 | var util = {
677 | createTextStyleId: function createTextStyleId(textStyle) {
678 | var textStyleId = ''; // Make sure this id incorporates every possible property of the text style
679 |
680 | textStyleId += textStyle.fontFamily;
681 | textStyleId += '-' + textStyle.fontSize;
682 | textStyleId += '-' + textStyle.letterSpacing;
683 | textStyleId += '-' + textStyle.textTransform;
684 |
685 | if (textStyle.lineHeight) {
686 | textStyleId += '-' + textStyle.lineHeight;
687 | }
688 |
689 | if (textStyle.color) {
690 | textStyleId += '-' + textStyle.color.r + '-' + textStyle.color.g + '-' + textStyle.color.b + '-' + textStyle.color.a;
691 | }
692 |
693 | return textStyleId;
694 | }
695 | };
696 | /* harmony default export */ __webpack_exports__["default"] = (util);
697 |
698 | /***/ })
699 |
700 | /******/ });
701 | if (key === 'default' && typeof exports === 'function') {
702 | exports(context);
703 | } else {
704 | exports[key](context);
705 | }
706 | }
707 | that['onRun'] = __skpm_run.bind(this, 'default')
708 |
709 | //# sourceMappingURL=sass-mixins-export.js.map
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/web-export.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/web-export.js");
90 | /******/ })
91 | /************************************************************************/
92 | /******/ ({
93 |
94 | /***/ "./src/web-export.js":
95 | /*!***************************!*\
96 | !*** ./src/web-export.js ***!
97 | \***************************/
98 | /*! exports provided: default */
99 | /***/ (function(module, exports) {
100 |
101 | throw new Error("Module build failed (from ./node_modules/babel-loader/lib/index.js):\nError: ENOENT: no such file or directory, open '/Users/rein/Workspace/sketch-plugins/typex/src/web-export.js'");
102 |
103 | /***/ })
104 |
105 | /******/ });
106 | if (key === 'default' && typeof exports === 'function') {
107 | exports(context);
108 | } else {
109 | exports[key](context);
110 | }
111 | }
112 | that['onRun'] = __skpm_run.bind(this, 'default')
113 |
114 | //# sourceMappingURL=web-export.js.map
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/web-export.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap"],"names":[],"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","file":"web-export.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/web-export.js\");\n"],"sourceRoot":""}
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/window-test.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/window-test.js");
90 | /******/ })
91 | /************************************************************************/
92 | /******/ ({
93 |
94 | /***/ "./src/window-test.js":
95 | /*!****************************!*\
96 | !*** ./src/window-test.js ***!
97 | \****************************/
98 | /*! exports provided: default */
99 | /***/ (function(module, exports) {
100 |
101 | throw new Error("Module build failed (from ./node_modules/babel-loader/lib/index.js):\nError: ENOENT: no such file or directory, open '/Users/rein/Workspace/sketch-plugins/typex/src/window-test.js'");
102 |
103 | /***/ })
104 |
105 | /******/ });
106 | if (key === 'default' && typeof exports === 'function') {
107 | exports(context);
108 | } else {
109 | exports[key](context);
110 | }
111 | }
112 | that['onRun'] = __skpm_run.bind(this, 'default')
113 |
114 | //# sourceMappingURL=window-test.js.map
--------------------------------------------------------------------------------
/typex.sketchplugin/Contents/Sketch/window-test.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap"],"names":[],"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","file":"window-test.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/window-test.js\");\n"],"sourceRoot":""}
--------------------------------------------------------------------------------