UNPKG

sketch-constructor

Version:

Read/write/manipulate Sketch files in Node without Sketch plugins!

189 lines (170 loc) 6.35 kB
/* * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is located at * * http://www.apache.org/licenses/LICENSE-2.0 * * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions * and limitations under the License. */ const uuid = require('uuid-v4'); const Artboard = require('../Artboard'); const ExportOptions = require('../ExportOptions'); const Rect = require('../Rect'); const Style = require('../Style'); const Color = require('../Color'); const RulerData = require('../RulerData'); const SymbolInstance = require('../SymbolInstance'); let changeIdentifier = 1; const MSImmutableOverrideProperty = { _class: 'MSImmutableOverrideProperty', canOverride: true, overrideName: '', }; class SymbolMaster extends Artboard { /** * The underlying JSON object structure in a Sketch document. * @mixes Artboard.Model * @property {string} symbolID * @property {int} changeIdentifier * @property {MSImmutableOverrideProperty[]} overrideProperties * @property {boolean} allowsOverrides */ static get Model() { return Object.assign(Artboard.Model, { _class: 'symbolMaster', symbolID: '', changeIdentifier, overrideProperties: [], allowsOverrides: true, }); } constructor(args, json) { super(args, json); if (!json) { const id = args.id || uuid().toUpperCase(); const symbolID = args.symbolID || uuid().toUpperCase(); Object.assign(this, SymbolMaster.Model, { do_objectID: id, symbolID, exportOptions: new ExportOptions(args.exportOptions), frame: new Rect(args.frame || {}), name: args.name || id, style: new Style(args.style), layers: args.layers || [], backgroundColor: new Color(args.backgroundColor || '#fff'), horizontalRulerData: new RulerData(args.horizontalRulerData), verticalRulerData: new RulerData(args.verticalRulerData), allowsOverrides: args.allowsOverrides, }); // I don't know exactly what changeIdentifier does, but it appears to be // a unique int. changeIdentifier += 1; } return this; } addLayer(layer, canOverride) { const getOverrideNames = (prop, overrideNames) => { switch (prop._class) { case 'symbolInstance': overrideNames.push(`${prop.do_objectID}_symbolID`); break; case 'text': overrideNames.push(`${prop.do_objectID}_stringValue`); if (prop.sharedStyleID !== null && prop.sharedStyleID !== undefined) { overrideNames.push(`${prop.do_objectID}_textStyle`); } break; case 'rectangle': case 'star': case 'triangle': case 'polygon': case 'shapePath': if (prop.sharedStyleID !== null && prop.sharedStyleID !== undefined) { overrideNames.push(`${prop.do_objectID}_layerStyle`); } break; case 'group': prop.layers.forEach((l) => { getOverrideNames(l, overrideNames); }); break; default: break; } return overrideNames; }; getOverrideNames(layer, []).forEach((name) => { this.overrideProperties.push({ ...MSImmutableOverrideProperty, canOverride, overrideName: name, }); }); super.addLayer(layer); } /** * Update existing SymbolInstance * Nested Symbols are not currently supported * @property {symbolInstance} SymbolInstance * @property {Object} args - overrides * @property {string} args[].name - name of the override being set * @property {string|Object} [args[].value] - the value set, for Layer Styles pass in object or do_objectID * @property {string|Object} [args[].style] - for textStyles only, pass in TextStyle object or do_objectID */ updateInstance(symbolInstance, args) { args.forEach((arg) => { const overrideLayer = this.getAllLayers().find((l) => l.name === arg.name); if (overrideLayer !== undefined) { const overrideName = overrideLayer.do_objectID; symbolInstance.overrideValues .filter((prop) => prop.overrideName.split('_')[0] === overrideName) .forEach((prop) => { if (prop.overrideName.includes('_stringValue')) { prop.value = arg.value; } if (prop.overrideName.includes('_layerStyle')) { prop.value = arg.value instanceof Object ? arg.value.do_objectID : arg.value; } if (arg.extStyle && prop.overrideName.includes('_textStyle')) { prop.value = arg.style instanceof Object ? arg.style.do_objectID : arg.style.do_objectID; } }); } }); } /** * Creates a new SymbolInstance with overrides * Nested Symbols are not currently supported * @property {Object} [args] * @property {Object[]} [args.overrideValues] - overrides * @property {string} [args.overrideValues[].name] - name of the override being set * @property {string|Object} [args.overrideValues[].value] - the value set, for Layer Styles pass in object or do_objectID * @property {string|Object} [args.overrideValues[].style] - for textStyles only, pass in TextStyle object or do_objectID * @returns {SymbolInstance} */ createInstance(args = {}) { const symbolInstance = new SymbolInstance({ ...args, symbolID: this.symbolID, frame: new Rect(this.frame || {}), name: args.name || '', style: new Style(this.style), allowsOverrides: this.allowsOverrides, }); symbolInstance.overrideValues = this.overrideProperties.map((prop) => ({ _class: 'overrideValue', do_objectID: uuid().toUpperCase(), overrideName: prop.overrideName, value: '', })); if (args && args.overrideValues) { this.updateInstance(symbolInstance, args.overrideValues); } return symbolInstance; } } module.exports = SymbolMaster;