Skip to content

Commit b322786

Browse files
feat(models): add support for color variables with swatch model (#157)
Fixes #141 Co-authored-by: Lindsay Evans <lindsay.evans@boomworks.com.au>
1 parent b205ae6 commit b322786

14 files changed

Lines changed: 657 additions & 372 deletions

File tree

docs/models.md

Lines changed: 481 additions & 371 deletions
Large diffs are not rendered by default.

models/Color/Color.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,19 @@ class Color {
4040

4141
/**
4242
*
43-
* @param {String|Object} args This is passed to tinycolor 2. As long as tinycolor2 can understand this argument, the color will work.
43+
* @param {String|Object|Color} args If a Color, used as-is, otherwised passed to tinycolor2. As long as tinycolor2 can understand this argument, the color will work.
4444
* @param {Color.Model} json
4545
*/
4646
constructor(args, json) {
4747
if (json) {
4848
Object.assign(this, json);
4949
} else {
5050
const color = TinyColor(args || '#000').toRgb();
51+
52+
if (args && args.swatchID) {
53+
this.swatchID = args.swatchID;
54+
}
55+
5156
Object.assign(this, Color.Model, {
5257
alpha: color.a,
5358
blue: color.b / 255,

models/Color/Color.test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313

1414
const Color = require('./index');
15+
const { Swatch } = require('../index');
1516

1617
const json = {
1718
_class: 'color',
@@ -42,4 +43,21 @@ describe('Color', () => {
4243
color.lighten(100);
4344
expect(color.toHexString()).toEqual('#ffffff');
4445
});
46+
47+
it('should accept swatchID as property along with color components', () => {
48+
const swatchID = '6D02695C-C1FF-471B-9948-A13985E7618E';
49+
const alpha = 0.77;
50+
const color = new Color({ swatchID, r: 1, g: 0, b: 0, a: alpha });
51+
expect(color.swatchID).toEqual(swatchID);
52+
expect(color.alpha).toEqual(alpha);
53+
expect(color.blue).toEqual(0);
54+
});
55+
56+
it('should accept result of swatch.asColor()', () => {
57+
const swatch = new Swatch({ color: new Color('purple') });
58+
const refColor = swatch.asColor();
59+
const color = new Color(refColor);
60+
expect(color.swatchID).toEqual(swatch.do_objectID);
61+
expect(color.red).toEqual(refColor.r / 255);
62+
});
4563
});

models/Color/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ declare class Color {
66
blue: number;
77
green: number;
88
red: number;
9+
swatchID?: string;
910

1011
constructor(args?: any, json?: any);
1112

models/Document/Document.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ class Document {
4949
_class: 'sharedTextStyleContainer',
5050
objects: [],
5151
},
52+
sharedSwatches: {
53+
_class: 'swatchContainer',
54+
objects: [],
55+
},
5256
pages: [],
5357
};
5458
}
@@ -119,6 +123,23 @@ class Document {
119123
return this;
120124
}
121125

126+
/**
127+
* @returns {Swatch[]} An array of Swatches
128+
*/
129+
getSwatches() {
130+
return this.sharedSwatches.objects;
131+
}
132+
133+
/**
134+
*
135+
* @param {Swatch} swatch
136+
* @returns {this}
137+
*/
138+
addSwatch(swatch) {
139+
this.sharedSwatches.objects = this.sharedSwatches.objects.concat(swatch);
140+
return this;
141+
}
142+
122143
/**
123144
*
124145
* @param {String} pageID

models/Document/index.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Color from '../Color';
22
import Page from '../Page';
33
import SharedStyle from '../SharedStyle';
4+
import Swatch from '../Swatch';
45

56
declare class Document {
67
_class: 'document';
@@ -32,6 +33,10 @@ declare class Document {
3233
_class: 'sharedTextStyleContainer';
3334
objects: SharedStyle[];
3435
};
36+
sharedSwatches: {
37+
_class: 'swatchContainer';
38+
objects: Swatch[];
39+
};
3540
pages: Page[];
3641

3742
constructor(args?: any, json?: any);
@@ -46,6 +51,10 @@ declare class Document {
4651

4752
addTextStyle(style: SharedStyle): Document;
4853

54+
getSwatches(): Swatch[];
55+
56+
addSwatch(swatch: Swatch): Document;
57+
4958
addPage(pageID: string): Document;
5059
}
5160

models/Sketch/Sketch.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ class Sketch {
135135
return this.document.getTextStyles();
136136
}
137137

138+
addSwatch(swatch) {
139+
this.document.addSwatch(swatch);
140+
}
141+
142+
getSwatches() {
143+
return this.document.getSwatches();
144+
}
145+
138146
addPage(page, args) {
139147
if (!(page instanceof Page)) {
140148
page = new Page(page);

models/Sketch/index.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import User from '../User';
55
import Document from '../Document';
66
import Page from '../Page';
77
import SharedStyle from '../SharedStyle';
8+
import Swatch from '../Swatch';
89

910
declare class Sketch {
1011
static fromFile(path: fs.PathLike): Promise<Sketch>;
@@ -35,6 +36,10 @@ declare class Sketch {
3536

3637
getTextStyles(): SharedStyle[];
3738

39+
addSwatch(swatch: Swatch): void;
40+
41+
getSwatches(): Swatch[];
42+
3843
addPage(page: any, args?: any): void;
3944

4045
addArtboard(pageID: string, artboard: any): void;

models/Swatch/Swatch.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const uuid = require('uuid-v4');
2+
const Color = require('../Color/Color');
3+
4+
/**
5+
* Also known as 'Color Variables'
6+
*/
7+
class Swatch {
8+
static get Model() {
9+
return {
10+
_class: 'swatch',
11+
};
12+
}
13+
14+
/**
15+
*
16+
* @param {Object} args
17+
* @param {String} args.name
18+
* @param {Color} args.color
19+
* @param {Color.Model} json
20+
*/
21+
constructor(args, json) {
22+
if (json) {
23+
Object.assign(this, Swatch.Model, json);
24+
this.value = new Color(this.value);
25+
} else {
26+
const id = args.id || uuid().toUpperCase();
27+
const name = args.name || args.color.toHex().toUpperCase();
28+
Object.assign(this, Swatch.Model, {
29+
name,
30+
do_objectID: id,
31+
value: args.color,
32+
});
33+
}
34+
}
35+
36+
/**
37+
* Get an object suitable for use in constructing colors
38+
* @returns {Color} A color with the `swatchID` set
39+
*/
40+
asColor() {
41+
return { ...this.value.toRgb(), swatchID: this.do_objectID };
42+
}
43+
}
44+
45+
module.exports = Swatch;

models/Swatch/Swatch.test.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const Color = require('../Color');
2+
const Swatch = require('./index');
3+
4+
const json = {
5+
name: 'Test Color',
6+
value: new Color('#c9c'),
7+
};
8+
9+
describe('Swatch', () => {
10+
it('should work from raw JSON', () => {
11+
const swatch = new Swatch(null, json);
12+
expect(swatch._class).toBe('swatch');
13+
});
14+
15+
it('should have a default name when no name is given', () => {
16+
const lime = new Color('limegreen');
17+
const unnamedSwatch = new Swatch({ color: lime });
18+
expect(unnamedSwatch.name).toBe('32CD32');
19+
20+
const namedSwatch = new Swatch({ name: 'Lime', color: lime });
21+
expect(namedSwatch.name).toBe('Lime');
22+
});
23+
24+
it('asColor should work', () => {
25+
const color = new Color('#F00');
26+
const swatch = new Swatch({ color });
27+
const refColor = swatch.asColor();
28+
expect(refColor.swatchID).not.toBeUndefined();
29+
expect(refColor.swatchID).toBe(swatch.do_objectID);
30+
expect(refColor.r).toBe(255);
31+
expect(refColor.g).toBe(0);
32+
expect(refColor.b).toBe(0);
33+
expect(refColor.a).toBe(1);
34+
});
35+
});

0 commit comments

Comments
 (0)