From cb2fea01e6c0ce201b83306c66a55532e107bc3d Mon Sep 17 00:00:00 2001 From: Mathieu Dutour Date: Mon, 25 Nov 2019 17:43:51 +0100 Subject: [PATCH 1/2] renderGroupLayer now has access to the children --- src/flexToSketchJSON.ts | 11 ++++++----- src/renderers/SketchRenderer.ts | 9 ++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/flexToSketchJSON.ts b/src/flexToSketchJSON.ts index 2c31bd6f..f7d239d0 100644 --- a/src/flexToSketchJSON.ts +++ b/src/flexToSketchJSON.ts @@ -45,11 +45,6 @@ const flexToSketchJSON = ( } const renderer = new Renderer(); - const groupLayer = renderer.renderGroupLayer(node); - - if (groupLayer._class === 'symbolInstance') { - return groupLayer; - } const backingLayers = renderer.renderBackingLayers(node); @@ -60,6 +55,12 @@ const flexToSketchJSON = ( // Filter out anything null, undefined const layers = [...backingLayers, ...sublayers].filter(l => l); + const groupLayer = renderer.renderGroupLayer(node, layers); + + if (groupLayer._class === 'symbolInstance') { + return groupLayer; + } + return { ...groupLayer, layers }; }; diff --git a/src/renderers/SketchRenderer.ts b/src/renderers/SketchRenderer.ts index 5f1ef373..0e25dbfe 100644 --- a/src/renderers/SketchRenderer.ts +++ b/src/renderers/SketchRenderer.ts @@ -11,11 +11,10 @@ export default class SketchRenderer { return 'Group'; } - renderGroupLayer({ - layout, - style, - props, - }: TreeNode): + renderGroupLayer( + { layout, style, props }: TreeNode, + _children: FileFormat.AnyLayer[], + ): | FileFormat.SymbolMaster | FileFormat.Artboard | FileFormat.Group From e465bbf86e09b4e4ae3646873d6c18494fe02531 Mon Sep 17 00:00:00 2001 From: Mathieu Dutour Date: Mon, 25 Nov 2019 17:44:07 +0100 Subject: [PATCH 2/2] move extractOverrides logic to separate file --- src/renderers/SymbolInstanceRenderer.ts | 91 +------------------------ src/utils/extractOverrides.ts | 89 ++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 89 deletions(-) create mode 100644 src/utils/extractOverrides.ts diff --git a/src/renderers/SymbolInstanceRenderer.ts b/src/renderers/SymbolInstanceRenderer.ts index 46cf17fd..f953cfce 100644 --- a/src/renderers/SymbolInstanceRenderer.ts +++ b/src/renderers/SymbolInstanceRenderer.ts @@ -9,94 +9,7 @@ import { import { TreeNode } from '../types'; import { getSymbolMasterById, SymbolInstanceProps } from '../symbol'; import getImageDataFromURL from '../utils/getImageDataFromURL'; - -type Override = { - type: 'symbolID' | 'stringValue' | 'layerStyle' | 'textStyle' | 'flowDestination' | 'image'; - path: string; - name: string; - symbolID?: string; -}; - -const findInGroup = (layer: FileFormat.AnyGroup, type: string): FileFormat.AnyLayer | undefined => - layer && layer.layers && layer.layers.find(l => l._class === type); - -const hasImageFill = (layer: FileFormat.AnyLayer): boolean => - // @ts-ignore - !!(layer.style && layer.style.fills && layer.style.fills.some(f => f.image)); - -const removeDuplicateOverrides = (overrides: Array): Array => { - const seen = {}; - - return overrides.filter(({ path }) => { - const isDuplicate = typeof seen[path] !== 'undefined'; - seen[path] = true; - - return !isDuplicate; - }); -}; - -const extractOverridesReducer = (path: string) => ( - overrides: Override[], - layer: FileFormat.AnyLayer, -): Override[] => { - if (layer._class === 'text') { - return overrides.concat({ - type: 'stringValue', - path: `${path}${layer.do_objectID}`, - name: layer.name, - }); - } - - if (layer._class === 'group') { - // here we're doing some look-ahead to see if this group contains a group - // that contains text. this is the structure that will appear if the user - // creates a `` element with a custom name - const subGroup = findInGroup(layer, 'group') as FileFormat.Group; - const textLayer = findInGroup(subGroup, 'text') as FileFormat.Text; - if (textLayer) { - return overrides.concat({ - type: 'stringValue', - path: `${path}${textLayer.do_objectID}`, - name: textLayer.name, - }); - } - - // here we're doing look-ahead to see if this group contains a shapeGroup - // with an image fill. if it does we can do an image override on that - // fill - const shapeGroup = findInGroup(layer, 'shapeGroup'); - if (shapeGroup && hasImageFill(shapeGroup)) { - return overrides.concat({ - type: 'image', - path: `${path}${shapeGroup.do_objectID}`, - name: layer.name, - }); - } - } - - if (layer._class === 'symbolInstance') { - return overrides.concat({ - type: 'symbolID', - path: `${path}${layer.do_objectID}`, - name: layer.name, - symbolID: layer.symbolID, - }); - } - - if ( - (layer._class === 'shapeGroup' || layer._class === 'artboard' || layer._class === 'group') && - layer.layers - ) { - return layer.layers.reduce(extractOverridesReducer(path), overrides); - } - - return overrides; -}; - -const extractOverrides = (layers: FileFormat.AnyLayer[] = [], path?: string): Override[] => { - const overrides = layers.reduce(extractOverridesReducer(path || ''), []); - return removeDuplicateOverrides(overrides); -}; +import { extractOverrides, Override } from '../utils/extractOverrides'; export default class SymbolInstanceRenderer extends SketchRenderer { renderGroupLayer({ layout, props }: TreeNode) { @@ -127,7 +40,7 @@ export default class SymbolInstanceRenderer extends SketchRenderer { const overrideValue = props.overrides[reference.name]; if (typeof overrideValue !== 'function' || typeof overrideValue.symbolID !== 'string') { throw new Error( - `The overriden nested symbol needs to the constructor of another symbol.\n\nIn Symbol Instance: "${props.name}"\nFor Override: "${reference.name}"`, + `The overriden nested symbol needs to be the constructor of another symbol.\n\nIn Symbol Instance: "${props.name}"\nFor Override: "${reference.name}"`, ); } diff --git a/src/utils/extractOverrides.ts b/src/utils/extractOverrides.ts new file mode 100644 index 00000000..f91a57e5 --- /dev/null +++ b/src/utils/extractOverrides.ts @@ -0,0 +1,89 @@ +import { FileFormat1 as FileFormat } from '@sketch-hq/sketch-file-format-ts'; + +export type Override = { + type: 'symbolID' | 'stringValue' | 'layerStyle' | 'textStyle' | 'flowDestination' | 'image'; + path: string; + name: string; + symbolID?: string; +}; + +const findInGroup = (layer: FileFormat.AnyGroup, type: string): FileFormat.AnyLayer | undefined => + layer && layer.layers && layer.layers.find(l => l._class === type); + +const hasImageFill = (layer: FileFormat.AnyLayer): boolean => + // @ts-ignore + !!(layer.style && layer.style.fills && layer.style.fills.some(f => f.image)); + +const removeDuplicateOverrides = (overrides: Array): Array => { + const seen = {}; + + return overrides.filter(({ path }) => { + const isDuplicate = typeof seen[path] !== 'undefined'; + seen[path] = true; + + return !isDuplicate; + }); +}; + +const extractOverridesReducer = (path: string) => ( + overrides: Override[], + layer: FileFormat.AnyLayer, +): Override[] => { + if (layer._class === 'text') { + return overrides.concat({ + type: 'stringValue', + path: `${path}${layer.do_objectID}`, + name: layer.name, + }); + } + + if (layer._class === 'group') { + // here we're doing some look-ahead to see if this group contains a group + // that contains text. this is the structure that will appear if the user + // creates a `` element with a custom name + const subGroup = findInGroup(layer, 'group') as FileFormat.Group; + const textLayer = findInGroup(subGroup, 'text') as FileFormat.Text; + if (textLayer) { + return overrides.concat({ + type: 'stringValue', + path: `${path}${textLayer.do_objectID}`, + name: textLayer.name, + }); + } + + // here we're doing look-ahead to see if this group contains a shapeGroup + // with an image fill. if it does we can do an image override on that + // fill + const shapeGroup = findInGroup(layer, 'shapeGroup'); + if (shapeGroup && hasImageFill(shapeGroup)) { + return overrides.concat({ + type: 'image', + path: `${path}${shapeGroup.do_objectID}`, + name: layer.name, + }); + } + } + + if (layer._class === 'symbolInstance') { + return overrides.concat({ + type: 'symbolID', + path: `${path}${layer.do_objectID}`, + name: layer.name, + symbolID: layer.symbolID, + }); + } + + if ( + (layer._class === 'shapeGroup' || layer._class === 'artboard' || layer._class === 'group') && + layer.layers + ) { + return layer.layers.reduce(extractOverridesReducer(path), overrides); + } + + return overrides; +}; + +export const extractOverrides = (layers: FileFormat.AnyLayer[] = [], path?: string): Override[] => { + const overrides = layers.reduce(extractOverridesReducer(path || ''), []); + return removeDuplicateOverrides(overrides); +};