Skip to content

Commit

Permalink
feat(symbol): added support for symbol overrides (#63)
Browse files Browse the repository at this point in the history
fixes #60

* Updated createInstance to take in an optional list of overrides
* Added updateInstance function to update overrides for existing Symbol Instances
* Nested Symbol overrides are currently not supported
  • Loading branch information
diana-wang authored and dbanksdesign committed Nov 13, 2019
1 parent c945f56 commit dac1e28
Show file tree
Hide file tree
Showing 6 changed files with 496 additions and 16 deletions.
29 changes: 29 additions & 0 deletions models/Layer/Layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,35 @@ class Layer {
return this.layers;
}

/**
* Get all child, grandchild, etc layers, and optionally filter them by a predicate function.
* @param {function} [predicate] - Filter function if you want to only return certain layers
* @returns {Layer[]} An array of all layers. Will return all direct children, grandchildren, etc.
*/
getAllLayers(predicate) {
function getRecursiveLayers(current, list) {
if (current === null || current === undefined) {
return list;
}
const childLayers = current.getLayers();
if (childLayers !== undefined) {
childLayers.forEach(layer => {
list.push(layer);
getRecursiveLayers(layer, list);
});
}
return list;
}

const allLayers = getRecursiveLayers(this, []);

if (predicate) {
return allLayers.filter(predicate);
}

return allLayers;
}

getID() {
return this.do_objectID;
}
Expand Down
68 changes: 65 additions & 3 deletions models/Layer/Layer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,74 @@
* and limitations under the License.
*/

const Layer = require('./index');

const json = {};
const Group = require('../Group');
const Text = require('../Text');

describe('Layer', () => {
it('should work from raw JSON', () => {
expect(true).toBeTruthy();
});
});

describe('getLayers', () => {
it('should get all children layers', () => {
const group = new Group({
name: 'group',
});
const text1 = new Text({
name: 'text1',
});
const text2 = new Text({
name: 'text2',
});

group.addLayer(text1);
group.addLayer(text2);

const layers = group.getLayers().map(l => l.name);

expect(layers.sort()).toEqual(['text1', 'text2'].sort());
});

it('should only get direct children layers', () => {
const outerGroup = new Group({
name: 'outer group',
});

const innerGroup = new Group({
name: 'inner group',
});
const text = new Text({
name: 'text',
});

innerGroup.addLayer(text);
outerGroup.addLayer(innerGroup);

const layers = outerGroup.getLayers().map(l => l.name);

expect(layers.sort()).toEqual(['inner group'].sort());
});
});

describe('getAllLayers', () => {
it('should get all children layers', () => {
const outerGroup = new Group({
name: 'outer group',
});

const innerGroup = new Group({
name: 'inner group',
});
const text = new Text({
name: 'text',
});

innerGroup.addLayer(text);
outerGroup.addLayer(innerGroup);

const layers = outerGroup.getAllLayers().map(l => l.name);

expect(layers.sort()).toEqual(['inner group', 'text'].sort());
});
});
2 changes: 2 additions & 0 deletions models/Layer/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ declare class Layer {

getLayers(predicate?: string | RegExp): Layer[];

getAllLayers(predicate?: string | RegExp): Layer[];

getID(): string;
}

Expand Down
101 changes: 94 additions & 7 deletions models/SymbolMaster/SymbolMaster.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,100 @@ class SymbolMaster extends Artboard {
}

addLayer(layer, canOverride) {
this.overrideProperties.push(
Object.assign(MSImmutableOverrideProperty, {
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: `${layer.do_objectID}_stringValue`,
})
);
overrideName: name,
});
});

super.addLayer(layer);
}

createInstance(args) {
const symbolInstance = new SymbolInstance({ ...args, symbolID: this.symbolID });
/**
* 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',
Expand All @@ -91,6 +174,10 @@ class SymbolMaster extends Artboard {
value: '',
}));

if (args && args.overrideValues) {
this.updateInstance(symbolInstance, args.overrideValues);
}

return symbolInstance;
}
}
Expand Down
Loading

0 comments on commit dac1e28

Please sign in to comment.