Skip to content

Commit

Permalink
Run on Nodejs (#359)
Browse files Browse the repository at this point in the history
* generate json for text layers

* allow to generate json format in nodejs

* support shared text styles

* mock sketch version

* fix mock

* fix typo

* avoid bundling nodobjc

* move resizeConstraint out of hack file

* change mocked sketch version to 47

* look for italic fonts

* fix tests

* fix lint

* fix tests
  • Loading branch information
mathieudutour authored Sep 21, 2018
1 parent 45a34db commit 2f96c56
Show file tree
Hide file tree
Showing 24 changed files with 780 additions and 253 deletions.
4 changes: 0 additions & 4 deletions __tests__/jest/jsonUtils/hacksForJSONImpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,4 @@ describe('API', () => {
it('exports makeEncodedAttributedString', () => {
expect(hacks.makeEncodedAttributedString).toBeInstanceOf(Function);
});

it('exports makeTextStyle', () => {
expect(hacks.makeTextStyle).toBeInstanceOf(Function);
});
});
15 changes: 12 additions & 3 deletions __tests__/jest/sharedStyles/TextStyles.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ let sharedTextStyles;

beforeEach(() => {
jest.resetModules();
jest.mock('sketchapp-json-plugin', () => ({
jest.mock('@skpm/sketchapp-json-plugin', () => ({
appVersionSupported: jest.fn(() => true),
fromSJSONDictionary: jest.fn(),
toSJSON: jest.fn(),
}));

jest.mock('../../../src/utils/getSketchVersion.js', () => ({
default: jest.fn(() => 47),
}));

TextStyles = require('../../../src/sharedStyles/TextStyles');

sharedTextStyles = require('../../../src/wrappers/sharedTextStyles');
Expand All @@ -22,8 +26,13 @@ beforeEach(() => {
TextStyles = TextStyles.default;
sharedTextStyles = sharedTextStyles.default;

sharedTextStyles.addStyle = jest.fn();
sharedTextStyles.setStyles = jest.fn();
sharedTextStyles.setContext = jest.fn(ctx => {
if (!ctx) {
throw new Error('Please provide a context');
}
});
sharedTextStyles.addStyle = jest.fn(() => 'styleId');
sharedTextStyles.setStyles = jest.fn(() => sharedTextStyles);

context = jest.fn();
});
Expand Down
21 changes: 21 additions & 0 deletions examples/lona-sketch-example-master/symbol.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as React from 'react';
import generateId from 'sketch-file/generateId';

import { renderToJSON } from '../../lib';

let id = 0;
const nextId = () => ++id; // eslint-disable-line

const displayName = Component =>
Component.displayName || Component.name || `UnknownSymbol${nextId()}`;

export default function createSymbol(Component, name) {
const masterName = name || displayName(Component);
const symbolID = generateId(masterName);
const symbolMaster = renderToJSON(
<symbolmaster symbolID={symbolID} name={masterName}>
<Component />
</symbolmaster>,
);
return symbolMaster;
}
8 changes: 5 additions & 3 deletions flow-typed/pegjs.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// @flow

declare module 'pegjs' {
declare var generate: (template: string) => {
parse: (s: string) => any
}
declare var generate: (
template: string,
) => {
parse: (s: string) => any,
};
}
4 changes: 2 additions & 2 deletions flow-typed/sketchapp-json-plugin.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow

declare module 'sketchapp-json-plugin' {
declare var fromSJSONDictionary: (json: Object) => any
declare module '@skpm/sketchapp-json-plugin' {
declare var fromSJSONDictionary: (json: Object, version?: string) => any
declare var appVersionSupported: () => bool
declare var toSJSON: (nativeLayer: any) => string
}
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"watch": "npm run build:react -- --watch"
},
"dependencies": {
"@skpm/sketchapp-json-plugin": "^0.2.0",
"airbnb-prop-types": "^2.10.0",
"error-stack-parser": "^2.0.0",
"invariant": "^2.2.2",
Expand All @@ -48,13 +49,15 @@
"pegjs": "^0.10.0",
"prop-types": "^15.5.8",
"sketch-constants": "^1.0.2",
"sketchapp-json-plugin": "^0.1.2",
"yoga-layout": "^1.9.3"
},
"peerDependencies": {
"react": "*",
"react-test-renderer": "*"
},
"optionalDependencies": {
"nodobjc": "^2.1.0"
},
"keywords": [
"sketch",
"sketchapp",
Expand Down Expand Up @@ -115,7 +118,7 @@
"react": "^16.3.2",
"react-test-renderer": "^16.3.2",
"rimraf": "^2.5.4",
"sketchapp-json-flow-types": "^0.3.3"
"sketchapp-json-flow-types": "^0.3.4"
},
"skpm": {
"test": {
Expand Down
187 changes: 21 additions & 166 deletions src/jsonUtils/hacksForJSONImpl.js
Original file line number Diff line number Diff line change
@@ -1,106 +1,16 @@
// @flow
// We need native macOS fonts and colors for these hacks so import the old utils
import type { SJTextStyle } from 'sketchapp-json-flow-types';
import { TextAlignment } from 'sketch-constants';
import { toSJSON } from 'sketchapp-json-plugin';
import { toSJSON } from '@skpm/sketchapp-json-plugin';
import {
TEXT_ALIGN,
TEXT_DECORATION_UNDERLINE,
TEXT_DECORATION_LINETHROUGH,
TEXT_TRANSFORM,
} from '../utils/constants';
import findFont from '../utils/findFont';
import getSketchVersion from '../utils/getSketchVersion';
import type { TextNodes, TextNode, TextStyle, ResizeConstraints, LayoutInfo } from '../types';
import type { TextNodes, TextNode, TextStyle, LayoutInfo } from '../types';
import { makeColorFromCSS } from './models';
import { makeStyle } from './style';

export const TEXT_ALIGN = {
auto: TextAlignment.Left,
left: TextAlignment.Left,
right: TextAlignment.Right,
center: TextAlignment.Center,
justify: TextAlignment.Justified,
};

export const TEXT_DECORATION_UNDERLINE = {
none: 0,
underline: 1,
double: 9,
};

export const TEXT_DECORATION_LINETHROUGH = {
none: 0,
'line-through': 1,
};

// this doesn't exist in constants
export const TEXT_TRANSFORM = {
uppercase: 1,
lowercase: 2,
initial: 0,
inherit: 0,
none: 0,
capitalize: 0,
};

/*
RESIZE CONSTRAINT RULES
Order of properties as map keys:
1. top
2. right
3. bottom
4: left
5. fixedHeight
6. fixedWidth
*/

const RESIZE_CONSTRAINTS = {
top_left_fixedHeight_fixedWidth: 9,
top_right_left_fixedHeight: 10,
top_left_fixedHeight: 11,
top_right_fixedHeight_fixedWidth: 12,
top_fixedHeight_fixedWidth: 13,
top_right_fixedHeight: 14,
top_fixedHeight: 15,
top_bottom_left_fixedWidth: 17,
top_right_bottom_left: 18,
top_bottom_left: 19,
top_right_bottom_fixedWidth: 20,
top_bottom_fixedWidth: 21,
top_right_bottom: 22,
top_bottom: 23,
top_left_fixedWidth: 25,
top_right_left: 26,
top_left: 27,
top_right_fixedWidth: 28,
top_fixedWidth: 29,
top_right: 30,
top: 31,
bottom_left_fixedHeight_fixedWidth: 33,
right_bottom_left_fixedHeight: 34,
bottom_left_fixedHeight: 35,
right_bottom_fixedHeight_fixedWidth: 36,
bottom_fixedHeight_fixedWidth: 37,
right_bottom_fixedHeight: 38,
bottom_fixedHeight: 39,
left_fixedHeight_fixedWidth: 41,
right_left_fixedHeight: 42,
left_fixedHeight: 43,
right_fixedHeight_fixedWidth: 44,
fixedHeight_fixedWidth: 45,
right_fixedHeight: 46,
fixedHeight: 47,
bottom_left_fixedWidth: 49,
right_bottom_left: 50,
bottom_left: 51,
right_bottom_fixedWidth: 52,
bottom_fixedWidth: 53,
right_bottom: 54,
bottom: 55,
left_fixedWidth: 57,
right_left: 58,
left: 59,
right_fixedWidth: 60,
fixedWidth: 61,
right: 62,
none: 63,
};

// NOTE(gold): toSJSON doesn't recursively parse JS objects
// https://github.com/airbnb/react-sketchapp/pull/73#discussion_r108529703
Expand Down Expand Up @@ -166,48 +76,6 @@ export const makeImageDataFromUrl = (url: string): MSImageData => {
return MSImageData.alloc().initWithImage(image);
};

export function makeResizeConstraint(resizingConstraint: ?ResizeConstraints): number {
if (resizingConstraint) {
const constraints = [];
const { top, right, bottom, left, fixedHeight, fixedWidth } = resizingConstraint;

if (top) {
constraints.push('top');
}
if (right) {
constraints.push('right');
}
if (bottom) {
constraints.push('bottom');
}
if (left) {
constraints.push('left');
}
if (fixedHeight) {
constraints.push('fixedHeight');
}
if (fixedWidth) {
constraints.push('fixedWidth');
}

if (constraints.length > 0) {
const constraint = RESIZE_CONSTRAINTS[constraints.join('_')];
if (!constraint) {
throw new Error(
`\n${JSON.stringify(
resizingConstraint,
null,
2,
)}\nconstraint is not a valid combination.`,
);
}
return constraint;
}
}

return RESIZE_CONSTRAINTS.none; // No constraints
}

// This shouldn't need to call into Sketch, but it does currently, which is bad for perf :(
function createStringAttributes(textStyles: TextStyle): Object {
const font = findFont(textStyles);
Expand All @@ -225,8 +93,8 @@ function createStringAttributes(textStyles: TextStyle): Object {
};

const color = makeColorFromCSS(textStyles.color || 'black');

if (getSketchVersion() >= 50) {
const sketchVersion = getSketchVersion();
if (sketchVersion === 'NodeJS' || sketchVersion >= 50) {
attribs.MSAttributedStringColorAttribute = color;
} else {
attribs.NSColor = NSColor.colorWithDeviceRed_green_blue_alpha(
Expand Down Expand Up @@ -270,37 +138,24 @@ export function makeEncodedAttributedString(textNodes: TextNodes) {
return encodeSketchJSON(msAttribStr);
}

export function makeTextStyle(textStyle: TextStyle) {
export function makeEncodedTextStyleAttributes(textStyle: TextStyle) {
const pStyle = makeParagraphStyle(textStyle);

const font = findFont(textStyle);

const color = makeColorFromCSS(textStyle.color || 'black');

const value: SJTextStyle = {
_class: 'textStyle',
encodedAttributes: {
MSAttributedStringFontAttribute: encodeSketchJSON(font.fontDescriptor()),
NSFont: font,
NSColor: encodeSketchJSON(
NSColor.colorWithDeviceRed_green_blue_alpha(
color.red,
color.green,
color.blue,
color.alpha,
),
),
NSParagraphStyle: encodeSketchJSON(pStyle),
NSKern: textStyle.letterSpacing || 0,
MSAttributedStringTextTransformAttribute:
TEXT_TRANSFORM[textStyle.textTransform || 'initial'] * 1,
},
return {
MSAttributedStringFontAttribute: encodeSketchJSON(font.fontDescriptor()),
NSFont: font,
NSColor: encodeSketchJSON(
NSColor.colorWithDeviceRed_green_blue_alpha(color.red, color.green, color.blue, color.alpha),
),
NSParagraphStyle: encodeSketchJSON(pStyle),
NSKern: textStyle.letterSpacing || 0,
MSAttributedStringTextTransformAttribute:
TEXT_TRANSFORM[textStyle.textTransform || 'initial'] * 1,
};

const json = makeStyle(textStyle);
json.textStyle = value;

return json;
}

export function makeSvgLayer(layout: LayoutInfo, name: string, svg: string) {
Expand Down
Loading

0 comments on commit 2f96c56

Please sign in to comment.