From d4b5f073066456ac533e6b75f0ac76135d879143 Mon Sep 17 00:00:00 2001 From: Matt Chaffe Date: Wed, 5 Feb 2025 17:42:46 +0000 Subject: [PATCH 1/3] feat(PD-407): work on strokes --- src/processors/border.processor.ts | 122 +- .../border-processors.test.ts.snap | 19 + src/tests/border-processors.test.ts | 19 + .../figma-test-data_border-color.json | 1080 +++++++++++++++++ .../figma-test-data_border-position.json | 882 ++++++++++++++ src/utils/test.utils.ts | 73 +- visualizer/styles.css | 25 +- 7 files changed, 2139 insertions(+), 81 deletions(-) create mode 100644 src/tests/__snapshots__/border-processors.test.ts.snap create mode 100644 src/tests/border-processors.test.ts create mode 100644 src/tests/fixtures/figma-test-data_border-color.json create mode 100644 src/tests/fixtures/figma-test-data_border-position.json diff --git a/src/processors/border.processor.ts b/src/processors/border.processor.ts index 2d98419..7d4708f 100644 --- a/src/processors/border.processor.ts +++ b/src/processors/border.processor.ts @@ -3,45 +3,135 @@ import { rgbaToString } from '../utils/index'; export const borderProcessors: StyleProcessor[] = [ { - property: "border-color", + property: "border", bindingKey: "strokes", process: async (variables, node?: SceneNode): Promise => { - const borderVariable = variables.find(v => v.property === 'strokes'); - if (borderVariable) { + // Check if we are Centre alignment + if (node && ('strokeAlign' in node && node.strokeAlign !== 'CENTER' || !('strokeAlign' in node))) { + return null; + } + + const borderColorVariable = variables.find(v => v.property === 'border'); + const borderLeftVariable = variables.find(v => v.property === "strokeLeftWeight"); + const borderRightVariable = variables.find(v => v.property === "strokeRightWeight"); + const borderTopVariable = variables.find(v => v.property === "strokeTopWeight"); + const borderBottomVariable = variables.find(v => v.property === "strokeBottomWeight"); + + if (borderLeftVariable && borderRightVariable && borderTopVariable && borderBottomVariable && + !(borderLeftVariable.value === borderRightVariable.value && borderTopVariable.value === borderBottomVariable.value)) { + return null; + } + + const width = node && 'strokeWeight' in node ? `${String(node.strokeWeight)}px` : null; + const type = node && 'dashPattern' in node && node.dashPattern.length > 0 ? 'dashed' : 'solid'; + + if (width && borderColorVariable) { + const value = `${borderLeftVariable?.value || width} ${type} ${borderColorVariable.value}`; + const rawValue = `${borderLeftVariable?.rawValue || width} ${type} ${borderColorVariable.rawValue}`; + + return { + value: value, + rawValue: rawValue, + valueType: "px" + }; + } + + if (node && 'strokes' in node && Array.isArray(node.strokes) && node.strokes.length > 0) { + const stroke = node.strokes[0] as Paint; + + let color = null; + if (stroke?.type === "SOLID") { + const { r, g, b } = stroke.color; + const a = stroke.opacity ?? 1; + color = rgbaToString(r, g, b, a); + } + + if (width && color) { + const value = `${borderLeftVariable?.value || width} ${type} ${color}`; + const rawValue = `${borderLeftVariable?.rawValue || width} ${type} ${color}`; + return { value, rawValue, valueType: "px" }; + } + } + return null; + } + }, + { + property: "outline", + bindingKey: undefined, + process: async (variables, node?: SceneNode): Promise => { + if (node && 'strokeAlign' in node && node.strokeAlign !== 'OUTSIDE') { + return null; + } + // Get box sizing based on strokeAlign + const borderVariable = variables.find(v => v.property === 'border'); + const width = node && 'strokeWeight' in node ? `${String(node.strokeWeight)}px` : null; + const type = node && 'dashPattern' in node && node.dashPattern.length > 0 ? 'dashed' : 'solid'; + + if (width && borderVariable) { + const value = `${width} ${type} ${borderVariable.value}`; + const rawValue = `${width} ${type} ${borderVariable.rawValue}`; + return { - value: borderVariable.value, - rawValue: borderVariable.rawValue + value: value, + rawValue: rawValue, + valueType: "px" }; } if (node && 'strokes' in node && Array.isArray(node.strokes) && node.strokes.length > 0) { const stroke = node.strokes[0] as Paint; + + let color = null; if (stroke?.type === "SOLID") { const { r, g, b } = stroke.color; const a = stroke.opacity ?? 1; - const value = rgbaToString(r, g, b, a); - return { value, rawValue: value }; + color = rgbaToString(r, g, b, a); + } + + if (width && color) { + const value = `${width} ${type} ${color}`; + return { value, rawValue: value, valueType: "px" }; } } return null; } }, { - property: "border-width", - bindingKey: "strokeWeight", + property: "box-shadow", + bindingKey: undefined, process: async (variables, node?: SceneNode): Promise => { - const widthVariable = variables.find(v => v.property === 'strokeWeight'); - if (widthVariable) { + if (node && 'strokeAlign' in node && node.strokeAlign !== 'INSIDE') { + return null; + } + // Get box sizing based on strokeAlign + const borderVariable = variables.find(v => v.property === 'border'); + console.log({ borderVariable, variables }); + const width = node && 'strokeWeight' in node ? `${String(node.strokeWeight)}px` : null; + + if (width && borderVariable) { + const value = `inset 0 0 0 ${width} ${borderVariable.value}`; + const rawValue = `inset 0 0 0 ${width} ${borderVariable.rawValue}`; + return { - value: widthVariable.value, - rawValue: widthVariable.rawValue + value: value, + rawValue: rawValue, + valueType: "px" }; } if (node && 'strokes' in node && Array.isArray(node.strokes) && node.strokes.length > 0) { - if ('strokeWeight' in node && node.strokeWeight) { - const value = `${String(node.strokeWeight)}px`; - return { value, rawValue: value }; + const stroke = node.strokes[0] as Paint; + + let color = null; + if (stroke?.type === "SOLID") { + const { r, g, b } = stroke.color; + const a = stroke.opacity ?? 1; + color = rgbaToString(r, g, b, a); + } + + if (width && color) { + const value = `inset 0 0 0 ${width} ${color}`; + return { value, rawValue: value, valueType: "px" }; } } return null; diff --git a/src/tests/__snapshots__/border-processors.test.ts.snap b/src/tests/__snapshots__/border-processors.test.ts.snap new file mode 100644 index 0000000..23d2928 --- /dev/null +++ b/src/tests/__snapshots__/border-processors.test.ts.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Border Processors should process border correctly: border 1`] = ` +"// Generated SCSS Variables +$border-size-primary: 0.25rem +$border-primary: #687879 + +// Generated SCSS Mixins +@mixin position-inside-custom + box-shadow: inset 0 0 0 0.25rem #687879 + +@mixin position-center-custom + border: $border-size-primary solid $border-primary + +@mixin position-outside-custom + outline: 0.25rem solid #687879 + +" +`; diff --git a/src/tests/border-processors.test.ts b/src/tests/border-processors.test.ts new file mode 100644 index 0000000..818c68e --- /dev/null +++ b/src/tests/border-processors.test.ts @@ -0,0 +1,19 @@ +import { collectTokens } from '../services'; +import { transformToScss } from '../transformers'; +import testData from './fixtures/figma-test-data_border-position.json'; +import { createTestData } from '../utils/test.utils'; + + +describe('Border Processors', () => { + it('should process border correctly', async () => { + const { setupTest } = createTestData(testData); + const testSetup = await setupTest(); + + global.figma = testSetup.figma; + + const tokens = await collectTokens(); + const { result} = transformToScss(tokens); + + expect(result).toMatchSnapshot('border'); + }); +}); \ No newline at end of file diff --git a/src/tests/fixtures/figma-test-data_border-color.json b/src/tests/fixtures/figma-test-data_border-color.json new file mode 100644 index 0000000..809a007 --- /dev/null +++ b/src/tests/fixtures/figma-test-data_border-color.json @@ -0,0 +1,1080 @@ +{ + "id": "6:2", + "parent": { + "id": "0:0" + }, + "name": "color", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "children": [ + { + "id": "6:6", + "parent": { + "id": "6:2" + }, + "name": "color-custom", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": {}, + "boundVariables": {}, + "resolvedVariableModes": {}, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": {} + } + ], + "strokeStyleId": "", + "strokeWeight": 4, + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [ + 8, + 8 + ], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -2 L-2 -2 L-2 0 L0 0 Z M100 0 L102 0 L102 -2 L100 -2 L100 0 Z M100 100 L100 102 L102 102 L102 100 L100 100 Z M0 100 L-2 100 L-2 102 L0 102 L0 100 Z M-2 0 L-2 4.16667 L2 4.16667 L2 0 L-2 0 Z M-2 12.5 L-2 20.8333 L2 20.8333 L2 12.5 L-2 12.5 Z M-2 29.1667 L-2 37.5 L2 37.5 L2 29.1667 L-2 29.1667 Z M-2 45.8333 L-2 54.1667 L2 54.1667 L2 45.8333 L-2 45.8333 Z M-2 62.5 L-2 70.8333 L2 70.8333 L2 62.5 L-2 62.5 Z M-2 79.1667 L-2 87.5 L2 87.5 L2 79.1667 L-2 79.1667 Z M-2 95.8333 L-2 100 L2 100 L2 95.8333 L-2 95.8333 Z M0 102 L4.16667 102 L4.16667 98 L0 98 L0 102 Z M12.5 102 L20.8333 102 L20.8333 98 L12.5 98 L12.5 102 Z M29.1667 102 L37.5 102 L37.5 98 L29.1667 98 L29.1667 102 Z M45.8333 102 L54.1667 102 L54.1667 98 L45.8333 98 L45.8333 102 Z M62.5 102 L70.8333 102 L70.8333 98 L62.5 98 L62.5 102 Z M79.1667 102 L87.5 102 L87.5 98 L79.1667 98 L79.1667 102 Z M95.8333 102 L100 102 L100 98 L95.8333 98 L95.8333 102 Z M102 100 L102 95.8333 L98 95.8333 L98 100 L102 100 Z M102 87.5 L102 79.1667 L98 79.1667 L98 87.5 L102 87.5 Z M102 70.8333 L102 62.5 L98 62.5 L98 70.8333 L102 70.8333 Z M102 54.1667 L102 45.8333 L98 45.8333 L98 54.1667 L102 54.1667 Z M102 37.5 L102 29.1667 L98 29.1667 L98 37.5 L102 37.5 Z M102 20.8333 L102 12.5 L98 12.5 L98 20.8333 L102 20.8333 Z M102 4.16666 L102 0 L98 0 L98 4.16666 L102 4.16666 Z M100 -2 L95.8333 -2 L95.8333 2 L100 2 L100 -2 Z M87.5 -2 L79.1667 -2 L79.1667 2 L87.5 2 L87.5 -2 Z M70.8333 -2 L62.5 -2 L62.5 2 L70.8333 2 L70.8333 -2 Z M54.1667 -2 L45.8333 -2 L45.8333 2 L54.1667 2 L54.1667 -2 Z M37.5 -2 L29.1667 -2 L29.1667 2 L37.5 2 L37.5 -2 Z M20.8333 -2 L12.5 -2 L12.5 2 L20.8333 2 L20.8333 -2 Z M4.16666 -2 L0 -2 L0 2 L4.16666 2 L4.16666 -2 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -890 + ], + [ + 0, + 1, + -51 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -890 + ], + [ + 0, + 1, + -51 + ] + ], + "x": -890, + "y": -51, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -890, + "y": -51, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -892, + "y": -53, + "width": 104, + "height": 104 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 4, + "strokeBottomWeight": 4, + "strokeLeftWeight": 4, + "strokeRightWeight": 4, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": {} + }, + { + "id": "6:11", + "parent": { + "id": "6:2" + }, + "name": "color-variable", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": {}, + "boundVariables": { + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeWeight": 4, + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -2 L-2 -2 L-2 0 L0 0 Z M100 0 L102 0 L102 -2 L100 -2 L100 0 Z M100 100 L100 102 L102 102 L102 100 L100 100 Z M0 100 L-2 100 L-2 102 L0 102 L0 100 Z M0 2 L100 2 L100 -2 L0 -2 L0 2 Z M98 0 L98 100 L102 100 L102 0 L98 0 Z M100 98 L0 98 L0 102 L100 102 L100 98 Z M2 100 L2 0 L-2 0 L-2 100 L2 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -770 + ], + [ + 0, + 1, + -51 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -770 + ], + [ + 0, + 1, + -51 + ] + ], + "x": -770, + "y": -51, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -770, + "y": -51, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -772, + "y": -53, + "width": 104, + "height": 104 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 4, + "strokeBottomWeight": 4, + "strokeLeftWeight": 4, + "strokeRightWeight": 4, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + }, + { + "id": "6:7", + "parent": { + "id": "6:2" + }, + "name": "color-style", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": {}, + "boundVariables": { + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:5:14" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0, + "g": 0.27450981736183167, + "b": 0.29019609093666077 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:5:14" + } + } + } + ], + "strokeStyleId": "S:50b363d2072e40f2323cce80e01be2c22d117c7a,", + "strokeWeight": 4, + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -2 L-2 -2 L-2 0 L0 0 Z M100 0 L102 0 L102 -2 L100 -2 L100 0 Z M100 100 L100 102 L102 102 L102 100 L100 100 Z M0 100 L-2 100 L-2 102 L0 102 L0 100 Z M0 2 L100 2 L100 -2 L0 -2 L0 2 Z M98 0 L98 100 L102 100 L102 0 L98 0 Z M100 98 L0 98 L0 102 L100 102 L100 98 Z M2 100 L2 0 L-2 0 L-2 100 L2 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -650 + ], + [ + 0, + 1, + -51 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -650 + ], + [ + 0, + 1, + -51 + ] + ], + "x": -650, + "y": -51, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -650, + "y": -51, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -652, + "y": -53, + "width": 104, + "height": 104 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 4, + "strokeBottomWeight": 4, + "strokeLeftWeight": 4, + "strokeRightWeight": 4, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:5:14": { + "id": "VariableID:5:14", + "name": "teal-800", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0, + "g": 0.27450981736183167, + "b": 0.29019609093666077, + "a": 1 + } + } + } + } + }, + { + "id": "9:52", + "parent": { + "id": "6:2" + }, + "name": "color-alpha-custom", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": {}, + "boundVariables": {}, + "resolvedVariableModes": {}, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 0.5, + "blendMode": "NORMAL", + "color": { + "r": 0.5254902243614197, + "g": 0.5843137502670288, + "b": 0.5921568870544434 + }, + "boundVariables": {} + } + ], + "strokeStyleId": "", + "strokeWeight": 4, + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -2 L-2 -2 L-2 0 L0 0 Z M100 0 L102 0 L102 -2 L100 -2 L100 0 Z M100 100 L100 102 L102 102 L102 100 L100 100 Z M0 100 L-2 100 L-2 102 L0 102 L0 100 Z M0 2 L100 2 L100 -2 L0 -2 L0 2 Z M98 0 L98 100 L102 100 L102 0 L98 0 Z M100 98 L0 98 L0 102 L100 102 L100 98 Z M2 100 L2 0 L-2 0 L-2 100 L2 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -890 + ], + [ + 0, + 1, + 89 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -890 + ], + [ + 0, + 1, + 89 + ] + ], + "x": -890, + "y": 89, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -890, + "y": 89, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -892, + "y": 87, + "width": 104, + "height": 104 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 4, + "strokeBottomWeight": 4, + "strokeLeftWeight": 4, + "strokeRightWeight": 4, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": {} + }, + { + "id": "9:68", + "parent": { + "id": "6:2" + }, + "name": "color-alpha-variable", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": {}, + "boundVariables": { + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:23" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 0.5, + "blendMode": "NORMAL", + "color": { + "r": 0.5254902243614197, + "g": 0.5843137502670288, + "b": 0.5921568870544434 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:23" + } + } + } + ], + "strokeStyleId": "", + "strokeWeight": 4, + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -2 L-2 -2 L-2 0 L0 0 Z M100 0 L102 0 L102 -2 L100 -2 L100 0 Z M100 100 L100 102 L102 102 L102 100 L100 100 Z M0 100 L-2 100 L-2 102 L0 102 L0 100 Z M0 2 L100 2 L100 -2 L0 -2 L0 2 Z M98 0 L98 100 L102 100 L102 0 L98 0 Z M100 98 L0 98 L0 102 L100 102 L100 98 Z M2 100 L2 0 L-2 0 L-2 100 L2 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -770 + ], + [ + 0, + 1, + 89 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -770 + ], + [ + 0, + 1, + 89 + ] + ], + "x": -770, + "y": 89, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -770, + "y": 89, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -772, + "y": 87, + "width": 104, + "height": 104 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 4, + "strokeBottomWeight": 4, + "strokeLeftWeight": 4, + "strokeRightWeight": 4, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:6:23": { + "id": "VariableID:6:23", + "name": "gray-500-50", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.5254902243614197, + "g": 0.5843137502670288, + "b": 0.5921568870544434, + "a": 0.5 + } + } + } + } + }, + { + "id": "9:63", + "parent": { + "id": "6:2" + }, + "name": "color-alpha-style", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": {}, + "boundVariables": { + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:5:22" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 0.5, + "blendMode": "NORMAL", + "color": { + "r": 0, + "g": 0.27450981736183167, + "b": 0.29019609093666077 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:5:22" + } + } + } + ], + "strokeStyleId": "S:3457669bf470bb81ac6140345a73205103b7ac57,", + "strokeWeight": 4, + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -2 L-2 -2 L-2 0 L0 0 Z M100 0 L102 0 L102 -2 L100 -2 L100 0 Z M100 100 L100 102 L102 102 L102 100 L100 100 Z M0 100 L-2 100 L-2 102 L0 102 L0 100 Z M0 2 L100 2 L100 -2 L0 -2 L0 2 Z M98 0 L98 100 L102 100 L102 0 L98 0 Z M100 98 L0 98 L0 102 L100 102 L100 98 Z M2 100 L2 0 L-2 0 L-2 100 L2 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -650 + ], + [ + 0, + 1, + 89 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -650 + ], + [ + 0, + 1, + 89 + ] + ], + "x": -650, + "y": 89, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -650, + "y": 89, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -652, + "y": 87, + "width": 104, + "height": 104 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 4, + "strokeBottomWeight": 4, + "strokeLeftWeight": 4, + "strokeRightWeight": 4, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:5:22": { + "id": "VariableID:5:22", + "name": "teal-800-50", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0, + "g": 0.27450981736183167, + "b": 0.29019609093666077, + "a": 0.5 + } + } + } + } + } + ], + "guides": [], + "selection": [ + { + "id": "6:6" + } + ], + "selectedTextRange": null, + "backgrounds": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "boundVariables": {} + } + ], + "exportSettings": [], + "prototypeStartNode": null, + "explicitVariableModes": {}, + "flowStartingPoints": [], + "prototypeBackgrounds": [ + { + "type": "SOLID", + "visible": true, + "opacity": 0, + "blendMode": "NORMAL", + "color": { + "r": 0, + "g": 0, + "b": 0 + }, + "boundVariables": {} + } + ], + "isPageDivider": false, + "type": "PAGE", + "variables": { + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:5:14": { + "id": "VariableID:5:14", + "name": "teal-800", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0, + "g": 0.27450981736183167, + "b": 0.29019609093666077, + "a": 1 + } + } + }, + "VariableID:6:23": { + "id": "VariableID:6:23", + "name": "gray-500-50", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.5254902243614197, + "g": 0.5843137502670288, + "b": 0.5921568870544434, + "a": 0.5 + } + } + }, + "VariableID:5:22": { + "id": "VariableID:5:22", + "name": "teal-800-50", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0, + "g": 0.27450981736183167, + "b": 0.29019609093666077, + "a": 0.5 + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } +} \ No newline at end of file diff --git a/src/tests/fixtures/figma-test-data_border-position.json b/src/tests/fixtures/figma-test-data_border-position.json new file mode 100644 index 0000000..ddeb315 --- /dev/null +++ b/src/tests/fixtures/figma-test-data_border-position.json @@ -0,0 +1,882 @@ +{ + "id": "213:278", + "parent": { + "id": "0:0" + }, + "name": "position", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "children": [ + { + "id": "213:279", + "parent": { + "id": "213:278" + }, + "name": "position-inside-custom", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": { + "BORDER_TOP_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_BOTTOM_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_LEFT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_RIGHT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + } + }, + "boundVariables": { + "strokeTopWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeBottomWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeLeftWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeRightWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeWeight": 4, + "strokeAlign": "INSIDE", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -4 L-4 -4 L-4 0 L0 0 Z M100 0 L104 0 L104 -4 L100 -4 L100 0 Z M100 100 L100 104 L104 104 L104 100 L100 100 Z M0 100 L-4 100 L-4 104 L0 104 L0 100 Z M0 4 L100 4 L100 -4 L0 -4 L0 4 Z M96 0 L96 100 L104 100 L104 0 L96 0 Z M100 96 L0 96 L0 104 L100 104 L100 96 Z M4 100 L4 0 L-4 0 L-4 100 L4 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -890 + ], + [ + 0, + 1, + -51 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -890 + ], + [ + 0, + 1, + -51 + ] + ], + "x": -890, + "y": -51, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -890, + "y": -51, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -890, + "y": -51, + "width": 100, + "height": 100 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 4, + "strokeBottomWeight": 4, + "strokeLeftWeight": 4, + "strokeRightWeight": 4, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + }, + { + "id": "213:282", + "parent": { + "id": "213:278" + }, + "name": "position-center-custom", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": { + "BORDER_TOP_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_BOTTOM_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_LEFT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_RIGHT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + } + }, + "boundVariables": { + "strokeTopWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeBottomWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeLeftWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeRightWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeWeight": 4, + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -2 L-2 -2 L-2 0 L0 0 Z M100 0 L102 0 L102 -2 L100 -2 L100 0 Z M100 100 L100 102 L102 102 L102 100 L100 100 Z M0 100 L-2 100 L-2 102 L0 102 L0 100 Z M0 2 L100 2 L100 -2 L0 -2 L0 2 Z M98 0 L98 100 L102 100 L102 0 L98 0 Z M100 98 L0 98 L0 102 L100 102 L100 98 Z M2 100 L2 0 L-2 0 L-2 100 L2 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -770 + ], + [ + 0, + 1, + -51 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -770 + ], + [ + 0, + 1, + -51 + ] + ], + "x": -770, + "y": -51, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -770, + "y": -51, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -772, + "y": -53, + "width": 104, + "height": 104 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 4, + "strokeBottomWeight": 4, + "strokeLeftWeight": 4, + "strokeRightWeight": 4, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + }, + { + "id": "213:281", + "parent": { + "id": "213:278" + }, + "name": "position-outside-custom", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": { + "BORDER_TOP_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_BOTTOM_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_LEFT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_RIGHT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + } + }, + "boundVariables": { + "strokeTopWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeBottomWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeLeftWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeRightWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeWeight": 4, + "strokeAlign": "OUTSIDE", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -4 L-4 -4 L-4 0 L0 0 Z M100 0 L104 0 L104 -4 L100 -4 L100 0 Z M100 100 L100 104 L104 104 L104 100 L100 100 Z M0 100 L-4 100 L-4 104 L0 104 L0 100 Z M0 4 L100 4 L100 -4 L0 -4 L0 4 Z M96 0 L96 100 L104 100 L104 0 L96 0 Z M100 96 L0 96 L0 104 L100 104 L100 96 Z M4 100 L4 0 L-4 0 L-4 100 L4 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -650 + ], + [ + 0, + 1, + -51 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -650 + ], + [ + 0, + 1, + -51 + ] + ], + "x": -650, + "y": -51, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -650, + "y": -51, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -654, + "y": -55, + "width": 108, + "height": 108 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 4, + "strokeBottomWeight": 4, + "strokeLeftWeight": 4, + "strokeRightWeight": 4, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + } + ], + "guides": [], + "selection": [ + { + "id": "213:281" + } + ], + "selectedTextRange": null, + "backgrounds": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "boundVariables": {} + } + ], + "exportSettings": [], + "prototypeStartNode": null, + "explicitVariableModes": {}, + "flowStartingPoints": [], + "prototypeBackgrounds": [ + { + "type": "SOLID", + "visible": true, + "opacity": 0, + "blendMode": "NORMAL", + "color": { + "r": 0, + "g": 0, + "b": 0 + }, + "boundVariables": {} + } + ], + "isPageDivider": false, + "type": "PAGE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } +} \ No newline at end of file diff --git a/src/utils/test.utils.ts b/src/utils/test.utils.ts index 85a6c52..0c5560f 100644 --- a/src/utils/test.utils.ts +++ b/src/utils/test.utils.ts @@ -1,52 +1,33 @@ export async function serializeFigmaData(node: BaseNode): Promise { - const baseData: any = { - id: node.id, - name: node.name, - type: node.type, - }; - - // Add specific node properties based on type - if ('fills' in node) baseData.fills = node.fills; - if ('strokes' in node) baseData.strokes = node.strokes; - if ('strokeWeight' in node) baseData.strokeWeight = node.strokeWeight; - if ('cornerRadius' in node) baseData.cornerRadius = node.cornerRadius; - - // Add layout properties - if ('layoutMode' in node) baseData.layoutMode = node.layoutMode; - if ('layoutAlign' in node) baseData.layoutAlign = node.layoutAlign; - if ('primaryAxisAlignItems' in node) baseData.primaryAxisAlignItems = node.primaryAxisAlignItems; - if ('counterAxisAlignItems' in node) baseData.counterAxisAlignItems = node.counterAxisAlignItems; - if ('primaryAxisSizingMode' in node) baseData.primaryAxisSizingMode = node.primaryAxisSizingMode; - if ('counterAxisSizingMode' in node) baseData.counterAxisSizingMode = node.counterAxisSizingMode; - if ('itemSpacing' in node) baseData.itemSpacing = node.itemSpacing; + // Properties to exclude from serialization + const excludedProps = new Set([ + 'inferredVariables', + 'availableInferredVariables', + // Add other properties to exclude here + ]); + + // Create base data with all enumerable properties + const baseData: any = {}; - // Add size properties - if ('width' in node) baseData.width = node.width; - if ('height' in node) baseData.height = node.height; - if ('minWidth' in node) baseData.minWidth = node.minWidth; - if ('maxWidth' in node) baseData.maxWidth = node.maxWidth; - if ('minHeight' in node) baseData.minHeight = node.minHeight; - if ('maxHeight' in node) baseData.maxHeight = node.maxHeight; - - // Add padding properties - if ('paddingTop' in node) { - baseData.paddingTop = node.paddingTop; - baseData.paddingRight = node.paddingRight; - baseData.paddingBottom = node.paddingBottom; - baseData.paddingLeft = node.paddingLeft; - } + // Get all properties from the node + for (const key in node) { + try { + // Skip excluded properties + if (excludedProps.has(key)) { + continue; + } - // Add text properties - if ('fontSize' in node) baseData.fontSize = node.fontSize; - if ('fontName' in node) baseData.fontName = node.fontName; - if ('lineHeight' in node) baseData.lineHeight = node.lineHeight; - if ('letterSpacing' in node) baseData.letterSpacing = node.letterSpacing; - - // Add variables and constraints - if ('boundVariables' in node) baseData.boundVariables = node.boundVariables; - if ('constraints' in node) baseData.constraints = node.constraints; - if ('layoutGrow' in node) baseData.layoutGrow = node.layoutGrow; - if ('layoutPositioning' in node) baseData.layoutPositioning = node.layoutPositioning; + const value = (node as any)[key]; + // Skip functions and undefined values + if (typeof value === 'function' || value === undefined) { + continue; + } + baseData[key] = value; + } catch (error) { + // Some properties might throw when accessed, skip those + continue; + } + } // Recursively process children if ('children' in node) { diff --git a/visualizer/styles.css b/visualizer/styles.css index c6657db..d2bf401 100644 --- a/visualizer/styles.css +++ b/visualizer/styles.css @@ -1,25 +1,12 @@ /* Generated CSS */ -.nested { - background: #ffffff; - gap: 0.5rem; - padding: 1rem; +.position-inside-custom { + box-shadow: inset 0 0 0 0.25rem #687879; } -.nested_auto-layout { - display: flex; - flex-direction: row; - align-items: center; - gap: 0.5rem; +.position-center-custom { + border: 0.25rem solid #687879; } -.nested_auto-layout_padding-1 { - background: #00464a; -} - -.nested_auto-layout_padding-2 { - background: #00464a; -} - -.nested_auto-layout_padding-3 { - background: #00464a; +.position-outside-custom { + outline: 0.25rem solid #687879; } From 9aa088c03288e751a28bd5060e43a4528ff92b73 Mon Sep 17 00:00:00 2001 From: Matt Chaffe Date: Wed, 5 Feb 2025 20:37:25 +0000 Subject: [PATCH 2/3] continue: getting individual sides working --- src/processors/border.processor.ts | 321 ++- .../border-processors.test.ts.snap | 49 +- src/tests/border-processors.test.ts | 15 +- .../figma-test-data_border-shape.json | 1336 +++++++++++ .../figma-test-data_border-sides.json | 2122 +++++++++++++++++ src/transformers/scss.transformer.ts | 4 +- visualizer/styles.css | 2 +- 7 files changed, 3750 insertions(+), 99 deletions(-) create mode 100644 src/tests/fixtures/figma-test-data_border-shape.json create mode 100644 src/tests/fixtures/figma-test-data_border-sides.json diff --git a/src/processors/border.processor.ts b/src/processors/border.processor.ts index 7d4708f..df687eb 100644 --- a/src/processors/border.processor.ts +++ b/src/processors/border.processor.ts @@ -1,60 +1,104 @@ import { StyleProcessor, ProcessedValue } from '../types'; import { rgbaToString } from '../utils/index'; +interface BorderWeights { + top: number; + right: number; + bottom: number; + left: number; +} + +interface BorderColor { + value: string; + rawValue: string; + variable?: any; +} + +interface BorderWidth { + value: string; + rawValue: string; + variable?: any; +} + +interface BorderSideConfig { + weightKey: keyof BorderWeights; + propertyKey: string; +} + export const borderProcessors: StyleProcessor[] = [ { property: "border", bindingKey: "strokes", process: async (variables, node?: SceneNode): Promise => { - // Check if we are Centre alignment if (node && ('strokeAlign' in node && node.strokeAlign !== 'CENTER' || !('strokeAlign' in node))) { return null; } - const borderColorVariable = variables.find(v => v.property === 'border'); - const borderLeftVariable = variables.find(v => v.property === "strokeLeftWeight"); - const borderRightVariable = variables.find(v => v.property === "strokeRightWeight"); - const borderTopVariable = variables.find(v => v.property === "strokeTopWeight"); - const borderBottomVariable = variables.find(v => v.property === "strokeBottomWeight"); - - if (borderLeftVariable && borderRightVariable && borderTopVariable && borderBottomVariable && - !(borderLeftVariable.value === borderRightVariable.value && borderTopVariable.value === borderBottomVariable.value)) { + const weights = getBorderWeights(node); + if (!shouldUseShorthand(weights)) { return null; } - const width = node && 'strokeWeight' in node ? `${String(node.strokeWeight)}px` : null; - const type = node && 'dashPattern' in node && node.dashPattern.length > 0 ? 'dashed' : 'solid'; - - if (width && borderColorVariable) { - const value = `${borderLeftVariable?.value || width} ${type} ${borderColorVariable.value}`; - const rawValue = `${borderLeftVariable?.rawValue || width} ${type} ${borderColorVariable.rawValue}`; + const color = getBorderColor(node, variables); + if (!color) return null; - return { - value: value, - rawValue: rawValue, - valueType: "px" - }; - } + const width = getBorderWidth('strokeTopWeight', weights.top, variables); + const type = node && 'dashPattern' in node && node.dashPattern.length > 0 ? 'dashed' : 'solid'; - if (node && 'strokes' in node && Array.isArray(node.strokes) && node.strokes.length > 0) { - const stroke = node.strokes[0] as Paint; - - let color = null; - if (stroke?.type === "SOLID") { - const { r, g, b } = stroke.color; - const a = stroke.opacity ?? 1; - color = rgbaToString(r, g, b, a); - } - - if (width && color) { - const value = `${borderLeftVariable?.value || width} ${type} ${color}`; - const rawValue = `${borderLeftVariable?.rawValue || width} ${type} ${color}`; - return { value, rawValue, valueType: "px" }; - } - } - return null; + const value = `${width.value} ${type} ${color.value}`; + const rawValue = `${width.rawValue} ${type} ${color.rawValue}`; + + return { + value, + rawValue, + valueType: "px", + }; } }, + { + property: "border-top", + bindingKey: "strokes", + process: async (variables, node?: SceneNode, processedProperties?: Set) => + processBorderSide( + { weightKey: 'top', propertyKey: 'strokeTopWeight' }, + variables, + node, + processedProperties + ) + }, + { + property: "border-right", + bindingKey: "strokes", + process: async (variables, node?: SceneNode, processedProperties?: Set) => + processBorderSide( + { weightKey: 'right', propertyKey: 'strokeRightWeight' }, + variables, + node, + processedProperties + ) + }, + { + property: "border-bottom", + bindingKey: "strokes", + process: async (variables, node?: SceneNode, processedProperties?: Set) => + processBorderSide( + { weightKey: 'bottom', propertyKey: 'strokeBottomWeight' }, + variables, + node, + processedProperties + ) + }, + { + property: "border-left", + bindingKey: "strokes", + process: async (variables, node?: SceneNode, processedProperties?: Set) => + processBorderSide( + { weightKey: 'left', propertyKey: 'strokeLeftWeight' }, + variables, + node, + processedProperties + ) + }, { property: "outline", bindingKey: undefined, @@ -62,38 +106,26 @@ export const borderProcessors: StyleProcessor[] = [ if (node && 'strokeAlign' in node && node.strokeAlign !== 'OUTSIDE') { return null; } - // Get box sizing based on strokeAlign - const borderVariable = variables.find(v => v.property === 'border'); - const width = node && 'strokeWeight' in node ? `${String(node.strokeWeight)}px` : null; - const type = node && 'dashPattern' in node && node.dashPattern.length > 0 ? 'dashed' : 'solid'; - - if (width && borderVariable) { - const value = `${width} ${type} ${borderVariable.value}`; - const rawValue = `${width} ${type} ${borderVariable.rawValue}`; - return { - value: value, - rawValue: rawValue, - valueType: "px" - }; + const weights = getBorderWeights(node); + if (!hasAnyBorder(weights) || !areAllBordersEqual(weights)) { + return null; } - if (node && 'strokes' in node && Array.isArray(node.strokes) && node.strokes.length > 0) { - const stroke = node.strokes[0] as Paint; + const color = getBorderColor(node, variables); + if (!color) return null; - let color = null; - if (stroke?.type === "SOLID") { - const { r, g, b } = stroke.color; - const a = stroke.opacity ?? 1; - color = rgbaToString(r, g, b, a); - } + const width = getBorderWidth('strokeLeftWeight', Object.values(weights).find(w => w > 0), variables); + const type = node && 'dashPattern' in node && node.dashPattern.length > 0 ? 'dashed' : 'solid'; - if (width && color) { - const value = `${width} ${type} ${color}`; - return { value, rawValue: value, valueType: "px" }; - } - } - return null; + const value = `${width.value} ${type} ${color.value}`; + const rawValue = `${width.rawValue} ${type} ${color.rawValue}`; + + return { + value, + rawValue, + valueType: "px", + }; } }, { @@ -103,38 +135,49 @@ export const borderProcessors: StyleProcessor[] = [ if (node && 'strokeAlign' in node && node.strokeAlign !== 'INSIDE') { return null; } - // Get box sizing based on strokeAlign - const borderVariable = variables.find(v => v.property === 'border'); - console.log({ borderVariable, variables }); - const width = node && 'strokeWeight' in node ? `${String(node.strokeWeight)}px` : null; - - if (width && borderVariable) { - const value = `inset 0 0 0 ${width} ${borderVariable.value}`; - const rawValue = `inset 0 0 0 ${width} ${borderVariable.rawValue}`; - return { - value: value, - rawValue: rawValue, - valueType: "px" - }; + const weights = getBorderWeights(node); + if (!hasAnyBorder(weights)) { + return null; } - if (node && 'strokes' in node && Array.isArray(node.strokes) && node.strokes.length > 0) { - const stroke = node.strokes[0] as Paint; + const color = getBorderColor(node, variables); + if (!color) return null; - let color = null; - if (stroke?.type === "SOLID") { - const { r, g, b } = stroke.color; - const a = stroke.opacity ?? 1; - color = rgbaToString(r, g, b, a); - } + // Get width variables for each side + const topWidth = getBorderWidth('strokeTopWeight', weights.top, variables); + const rightWidth = getBorderWidth('strokeRightWeight', weights.right, variables); + const bottomWidth = getBorderWidth('strokeBottomWeight', weights.bottom, variables); + const leftWidth = getBorderWidth('strokeLeftWeight', weights.left, variables); - if (width && color) { - const value = `inset 0 0 0 ${width} ${color}`; - return { value, rawValue: value, valueType: "px" }; - } + const shadows = []; + const rawShadows = []; + + if (weights.top > 0) { + shadows.push(`inset 0 ${topWidth.value} 0 0 ${color.value}`); + rawShadows.push(`inset 0 ${topWidth.rawValue} 0 0 ${color.rawValue}`); } - return null; + if (weights.right > 0) { + shadows.push(`inset -${rightWidth.value} 0 0 0 ${color.value}`); + rawShadows.push(`inset -${rightWidth.rawValue} 0 0 0 ${color.rawValue}`); + } + if (weights.bottom > 0) { + shadows.push(`inset 0 -${bottomWidth.value} 0 0 ${color.value}`); + rawShadows.push(`inset 0 -${bottomWidth.rawValue} 0 0 ${color.rawValue}`); + } + if (weights.left > 0) { + shadows.push(`inset ${leftWidth.value} 0 0 0 ${color.value}`); + rawShadows.push(`inset ${leftWidth.rawValue} 0 0 0 ${color.rawValue}`); + } + + const value = shadows.join(', '); + const rawValue = rawShadows.join(', '); + + return { + value, + rawValue, + valueType: "px", + }; } }, { @@ -156,4 +199,98 @@ export const borderProcessors: StyleProcessor[] = [ return null; } }, -]; \ No newline at end of file +]; + +// Utility functions for border processing +const getBorderWeights = (node?: SceneNode): BorderWeights => ({ + top: node && 'strokeTopWeight' in node ? node.strokeTopWeight : 0, + right: node && 'strokeRightWeight' in node ? node.strokeRightWeight : 0, + bottom: node && 'strokeBottomWeight' in node ? node.strokeBottomWeight : 0, + left: node && 'strokeLeftWeight' in node ? node.strokeLeftWeight : 0 +}); + +const hasAnyBorder = (weights: BorderWeights): boolean => + weights.top > 0 || weights.right > 0 || weights.bottom > 0 || weights.left > 0; + +const hasFullBorder = (weights: BorderWeights): boolean => + weights.top > 0 && weights.right > 0 && weights.bottom > 0 && weights.left > 0; + +const areAllBordersEqual = (weights: BorderWeights): boolean => { + const nonZeroWeights = Object.values(weights).filter(w => w !== 0); + return nonZeroWeights.length > 0 && nonZeroWeights.every(w => w === nonZeroWeights[0]); +}; + +const shouldUseShorthand = (weights: BorderWeights): boolean => + hasFullBorder(weights) && areAllBordersEqual(weights); + +const getBorderColor = (node?: SceneNode, variables?: any[]): BorderColor | null => { + const borderVariable = variables?.find(v => v.property === 'strokes'); + if (borderVariable) { + return { + value: borderVariable.value, + rawValue: borderVariable.rawValue, + variable: borderVariable + }; + } + + if (node && 'strokes' in node && Array.isArray(node.strokes) && node.strokes.length > 0) { + const stroke = node.strokes[0] as Paint; + if (stroke?.type === "SOLID") { + const { r, g, b } = stroke.color; + const a = stroke.opacity ?? 1; + const color = rgbaToString(r, g, b, a); + return { + value: color, + rawValue: color + }; + } + } + return null; +}; + +const getBorderWidth = (property: string, width: number, variables?: any[]): BorderWidth => { + const widthVariable = variables?.find(v => v.property === property); + if (widthVariable) { + return { + value: widthVariable.value, + rawValue: widthVariable.rawValue, + }; + } + + const value = `${String(width)}px`; + return { + value, + rawValue: value + }; +}; + +const processBorderSide = async ( + config: BorderSideConfig, + variables: any[], + node?: SceneNode, + processedProperties?: Set +): Promise => { + const weights = getBorderWeights(node); + + // Skip if using shorthand or no border on this side + if (processedProperties?.has('border') || + weights[config.weightKey] === 0 || + shouldUseShorthand(weights)) { + return null; + } + + const color = getBorderColor(node, variables); + if (!color) return null; + + const width = getBorderWidth(config.propertyKey, weights[config.weightKey], variables); + const type = node && 'dashPattern' in node && node.dashPattern.length > 0 ? 'dashed' : 'solid'; + + const value = `${width.value} ${type} ${color.value}`; + const rawValue = `${width.rawValue} ${type} ${color.rawValue}`; + + return { + value, + rawValue, + valueType: "px", + }; +}; \ No newline at end of file diff --git a/src/tests/__snapshots__/border-processors.test.ts.snap b/src/tests/__snapshots__/border-processors.test.ts.snap index 23d2928..18eb45a 100644 --- a/src/tests/__snapshots__/border-processors.test.ts.snap +++ b/src/tests/__snapshots__/border-processors.test.ts.snap @@ -7,13 +7,58 @@ $border-primary: #687879 // Generated SCSS Mixins @mixin position-inside-custom - box-shadow: inset 0 0 0 0.25rem #687879 + box-shadow: inset 0 $border-size-primary 0 0 $border-primary, inset -$border-size-primary 0 0 0 $border-primary, inset 0 -$border-size-primary 0 0 $border-primary, inset $border-size-primary 0 0 0 $border-primary @mixin position-center-custom border: $border-size-primary solid $border-primary @mixin position-outside-custom - outline: 0.25rem solid #687879 + outline: $border-size-primary solid $border-primary + +" +`; + +exports[`Border Processors should process border sides correctly: border-sides 1`] = ` +"// Generated SCSS Variables +$border-size-primary: 0.25rem +$size-null: 0rem +$border-primary: #687879 +$size-16: 1rem + +// Generated SCSS Mixins +@mixin border-center-solid-custom-topleft + border-top: 0.125rem solid #869597 + border-left: 0.125rem solid #869597 + +@mixin border-center-solid-custom-top + border: 0.125rem solid #869597 + +@mixin border-center-solid-variable-topleft + border-top: $border-size-primary solid $border-primary + border-left: $border-size-primary solid $border-primary + +@mixin border-center-solid-variable-top + border: $border-size-primary solid $border-primary + +@mixin border-center-solid-custom-left + border-right: 0.5rem solid #869597 + border-left: 0.125rem solid #869597 + +@mixin border-center-solid-variable-left + border-right: $size-16 solid $border-primary + border-left: $border-size-primary solid $border-primary + +@mixin border-center-solid-custom-right + border-right: 0.125rem solid #869597 + +@mixin border-center-solid-variable-right + border-right: $border-size-primary solid $border-primary + +@mixin border-center-solid-custom-bottom + border-bottom: 0.125rem solid #869597 + +@mixin border-center-solid-variable-bottom + border-bottom: $border-size-primary solid $border-primary " `; diff --git a/src/tests/border-processors.test.ts b/src/tests/border-processors.test.ts index 818c68e..494c91e 100644 --- a/src/tests/border-processors.test.ts +++ b/src/tests/border-processors.test.ts @@ -1,7 +1,8 @@ import { collectTokens } from '../services'; import { transformToScss } from '../transformers'; -import testData from './fixtures/figma-test-data_border-position.json'; import { createTestData } from '../utils/test.utils'; +import testData from './fixtures/figma-test-data_border-position.json'; +import testDataSides from './fixtures/figma-test-data_border-sides.json'; describe('Border Processors', () => { @@ -16,4 +17,16 @@ describe('Border Processors', () => { expect(result).toMatchSnapshot('border'); }); + + it('should process border sides correctly', async () => { + const { setupTest } = createTestData(testDataSides); + const testSetup = await setupTest(); + + global.figma = testSetup.figma; + + const tokens = await collectTokens(); + const { result} = transformToScss(tokens); + + expect(result).toMatchSnapshot('border-sides'); + }); }); \ No newline at end of file diff --git a/src/tests/fixtures/figma-test-data_border-shape.json b/src/tests/fixtures/figma-test-data_border-shape.json new file mode 100644 index 0000000..3b0ded5 --- /dev/null +++ b/src/tests/fixtures/figma-test-data_border-shape.json @@ -0,0 +1,1336 @@ +{ + "id": "269:2", + "parent": { + "id": "0:0" + }, + "name": "shape", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "children": [ + { + "id": "269:3", + "parent": { + "id": "269:2" + }, + "name": "shape-rectangle", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": { + "BORDER_TOP_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_BOTTOM_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_LEFT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_RIGHT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + } + }, + "boundVariables": { + "strokeTopWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeBottomWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeLeftWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeRightWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeWeight": 4, + "strokeAlign": "INSIDE", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -4 L-4 -4 L-4 0 L0 0 Z M100 0 L104 0 L104 -4 L100 -4 L100 0 Z M100 100 L100 104 L104 104 L104 100 L100 100 Z M0 100 L-4 100 L-4 104 L0 104 L0 100 Z M0 4 L100 4 L100 -4 L0 -4 L0 4 Z M96 0 L96 100 L104 100 L104 0 L96 0 Z M100 96 L0 96 L0 104 L100 104 L100 96 Z M4 100 L4 0 L-4 0 L-4 100 L4 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -890 + ], + [ + 0, + 1, + -54 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -890 + ], + [ + 0, + 1, + -54 + ] + ], + "x": -890, + "y": -54, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -890, + "y": -54, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -890, + "y": -54, + "width": 100, + "height": 100 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 4, + "strokeBottomWeight": 4, + "strokeLeftWeight": 4, + "strokeRightWeight": 4, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + }, + { + "id": "269:6", + "parent": { + "id": "269:2" + }, + "name": "shape-rounded-rectangle", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": { + "BORDER_TOP_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_BOTTOM_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_LEFT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_RIGHT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + } + }, + "boundVariables": { + "strokeTopWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeBottomWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeLeftWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeRightWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeWeight": 4, + "strokeAlign": "INSIDE", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 20 C0 8.9543 8.95431 0 20 0 L80 0 C91.0457 0 100 8.95431 100 20 L100 80 C100 91.0457 91.0457 100 80 100 L20 100 C8.9543 100 0 91.0457 0 80 L0 20 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M20 4 L80 4 L80 -4 L20 -4 L20 4 Z M96 20 L96 80 L104 80 L104 20 L96 20 Z M80 96 L20 96 L20 104 L80 104 L80 96 Z M4 80 L4 20 L-4 20 L-4 80 L4 80 Z M20 96 C11.1634 96 4 88.8366 4 80 L-4 80 C-4 93.2548 6.74516 104 20 104 L20 96 Z M96 80 C96 88.8366 88.8366 96 80 96 L80 104 C93.2548 104 104 93.2548 104 80 L96 80 Z M80 4 C88.8366 4 96 11.1634 96 20 L104 20 C104 6.74517 93.2548 -4 80 -4 L80 4 Z M20 -4 C6.74517 -4 -4 6.74516 -4 20 L4 20 C4 11.1634 11.1634 4 20 4 L20 -4 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -750 + ], + [ + 0, + 1, + -54 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -750 + ], + [ + 0, + 1, + -54 + ] + ], + "x": -750, + "y": -54, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -750, + "y": -54, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -750, + "y": -54, + "width": 100, + "height": 100 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 20, + "cornerSmoothing": 0, + "topLeftRadius": 20, + "topRightRadius": 20, + "bottomLeftRadius": 20, + "bottomRightRadius": 20, + "reactions": [], + "strokeTopWeight": 4, + "strokeBottomWeight": 4, + "strokeLeftWeight": 4, + "strokeRightWeight": 4, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + }, + { + "id": "269:7", + "parent": { + "id": "269:2" + }, + "name": "shape-ellipse", + "removed": false, + "isAsset": true, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": { + "STROKE_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + } + }, + "boundVariables": { + "strokeWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeWeight": 4, + "strokeAlign": "INSIDE", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M100 50 C100 77.6142 77.6142 100 50 100 C22.3858 100 0 77.6142 0 50 C0 22.3858 22.3858 0 50 0 C77.6142 0 100 22.3858 100 50 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M96 50 C96 75.4051 75.4051 96 50 96 L50 104 C79.8234 104 104 79.8234 104 50 L96 50 Z M50 96 C24.5949 96 4 75.4051 4 50 L-4 50 C-4 79.8234 20.1766 104 50 104 L50 96 Z M4 50 C4 24.5949 24.5949 4 50 4 L50 -4 C20.1766 -4 -4 20.1766 -4 50 L4 50 Z M50 4 C75.4051 4 96 24.5949 96 50 L104 50 C104 20.1766 79.8234 -4 50 -4 L50 4 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -610 + ], + [ + 0, + 1, + -54 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -610 + ], + [ + 0, + 1, + -54 + ] + ], + "x": -610, + "y": -54, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -610, + "y": -54, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -610, + "y": -54, + "width": 100, + "height": 100 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": true, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "arcData": { + "startingAngle": 0, + "endingAngle": 6.2831854820251465, + "innerRadius": 0 + }, + "reactions": [], + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "ELLIPSE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + }, + { + "id": "269:8", + "parent": { + "id": "269:2" + }, + "name": "shape-line-straight", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": { + "STROKE_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + } + }, + "boundVariables": { + "strokeWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeWeight": 4, + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 -4 L0 -4 L0 0 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -470 + ], + [ + 0, + 1, + -1 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -470 + ], + [ + 0, + 1, + -1 + ] + ], + "x": -470, + "y": -1, + "width": 100, + "height": 0, + "absoluteBoundingBox": { + "x": -470, + "y": -1, + "width": 100, + "height": 0 + }, + "absoluteRenderBounds": { + "x": -470, + "y": -5, + "width": 100, + "height": 4 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "reactions": [], + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "LINE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + }, + { + "id": "269:9", + "parent": { + "id": "269:2" + }, + "name": "shape-line-curved", + "removed": false, + "isAsset": true, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": { + "STROKE_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + } + }, + "boundVariables": { + "strokeWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeWeight": 4, + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 2 C27.9659 2 40.3261 8.99437 45.9821 18.0568 C48.8579 22.6647 50.1467 28.0174 50.6955 33.7543 C51.2478 39.5267 51.0391 45.4661 51.0391 51.3464 L55.0391 51.3464 C55.0391 45.6596 55.2536 39.3972 54.6774 33.3733 C54.0977 27.314 52.7063 21.276 49.3754 15.939 C42.618 5.11178 28.4587 -2 0 -2 L0 2 Z M51.0391 51.3464 C51.0391 62.763 50.9815 75.8125 57.3418 85.9141 C63.8568 96.2616 76.6817 103 101 103 L101 99 C77.3574 99 66.2018 92.4787 60.7267 83.7828 C55.0967 74.8411 55.0391 63.0638 55.0391 51.3464 L51.0391 51.3464 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -330 + ], + [ + 0, + 1, + -54 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -330 + ], + [ + 0, + 1, + -54 + ] + ], + "x": -330, + "y": -54, + "width": 101, + "height": 101, + "absoluteBoundingBox": { + "x": -330, + "y": -54, + "width": 101, + "height": 101 + }, + "absoluteRenderBounds": { + "x": -330, + "y": -56, + "width": 101, + "height": 105 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "vectorNetwork": { + "vertices": [ + { + "x": 0, + "y": 0, + "strokeCap": "NONE", + "strokeJoin": "MITER", + "cornerRadius": 0, + "handleMirroring": "ANGLE_AND_LENGTH" + }, + { + "x": 53.03910827636719, + "y": 51.346370697021484, + "strokeCap": "NONE", + "strokeJoin": "MITER", + "cornerRadius": 0, + "handleMirroring": "ANGLE_AND_LENGTH" + }, + { + "x": 101, + "y": 101, + "strokeCap": "NONE", + "strokeJoin": "MITER", + "cornerRadius": 0, + "handleMirroring": "ANGLE_AND_LENGTH" + } + ], + "segments": [ + { + "start": 0, + "end": 1, + "tangentStart": { + "x": 56.424583435058594, + "y": 0 + }, + "tangentEnd": { + "x": 0, + "y": -23.134078979492188 + } + }, + { + "start": 1, + "end": 2, + "tangentStart": { + "x": 0, + "y": 23.134078979492188 + }, + "tangentEnd": { + "x": -47.96089553833008, + "y": 3.207366148930482e-14 + } + } + ], + "regions": [] + }, + "vectorPaths": [ + { + "windingRule": "NONE", + "data": "M 0 0 C 56.424583435058594 0 53.03910827636719 28.212291717529297 53.03910827636719 51.346370697021484 C 53.03910827636719 74.48044967651367 53.03910446166992 101.00000000000003 101 101" + } + ], + "handleMirroring": "ANGLE_AND_LENGTH", + "reactions": [], + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "VECTOR", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + } + ], + "guides": [], + "selection": [], + "selectedTextRange": null, + "backgrounds": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "boundVariables": {} + } + ], + "exportSettings": [], + "prototypeStartNode": null, + "explicitVariableModes": {}, + "flowStartingPoints": [], + "prototypeBackgrounds": [ + { + "type": "SOLID", + "visible": true, + "opacity": 0, + "blendMode": "NORMAL", + "color": { + "r": 0, + "g": 0, + "b": 0 + }, + "boundVariables": {} + } + ], + "isPageDivider": false, + "type": "PAGE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } +} \ No newline at end of file diff --git a/src/tests/fixtures/figma-test-data_border-sides.json b/src/tests/fixtures/figma-test-data_border-sides.json new file mode 100644 index 0000000..4827599 --- /dev/null +++ b/src/tests/fixtures/figma-test-data_border-sides.json @@ -0,0 +1,2122 @@ +{ + "id": "9:96", + "parent": { + "id": "0:0" + }, + "name": "sides", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "children": [ + { + "id": "9:107", + "parent": { + "id": "9:96" + }, + "name": "border-center-solid-custom-topleft", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": {}, + "boundVariables": {}, + "resolvedVariableModes": {}, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.5254902243614197, + "g": 0.5843137502670288, + "b": 0.5921568870544434 + }, + "boundVariables": {} + } + ], + "strokeStyleId": "", + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -1 L-1 -1 L-1 0 L0 0 Z M0 1 L100 1 L100 -1 L0 -1 L0 1 Z M1 100 L1 0 L-1 0 L-1 100 L1 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -210 + ], + [ + 0, + 1, + 19 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -210 + ], + [ + 0, + 1, + 19 + ] + ], + "x": -210, + "y": 19, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -210, + "y": 19, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -211, + "y": 18, + "width": 101, + "height": 101 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 2, + "strokeBottomWeight": 0, + "strokeLeftWeight": 2, + "strokeRightWeight": 0, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": {} + }, + { + "id": "9:109", + "parent": { + "id": "9:96" + }, + "name": "border-center-solid-custom-top", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": {}, + "boundVariables": {}, + "resolvedVariableModes": {}, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.5254902243614197, + "g": 0.5843137502670288, + "b": 0.5921568870544434 + }, + "boundVariables": {} + } + ], + "strokeStyleId": "", + "strokeWeight": 2, + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -1 L-1 -1 L-1 0 L0 0 Z M100 0 L101 0 L101 -1 L100 -1 L100 0 Z M100 100 L100 101 L101 101 L101 100 L100 100 Z M0 100 L-1 100 L-1 101 L0 101 L0 100 Z M0 1 L100 1 L100 -1 L0 -1 L0 1 Z M99 0 L99 100 L101 100 L101 0 L99 0 Z M100 99 L0 99 L0 101 L100 101 L100 99 Z M1 100 L1 0 L-1 0 L-1 100 L1 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -770 + ], + [ + 0, + 1, + 19 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -770 + ], + [ + 0, + 1, + 19 + ] + ], + "x": -770, + "y": 19, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -770, + "y": 19, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -771, + "y": 18, + "width": 102, + "height": 102 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 2, + "strokeBottomWeight": 2, + "strokeLeftWeight": 2, + "strokeRightWeight": 2, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": {} + }, + { + "id": "9:100", + "parent": { + "id": "9:96" + }, + "name": "border-center-solid-variable-topleft", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": { + "BORDER_TOP_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_BOTTOM_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:141" + }, + "BORDER_LEFT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_RIGHT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:141" + } + }, + "boundVariables": { + "strokeTopWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeBottomWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:141" + }, + "strokeLeftWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeRightWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:141" + }, + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -2 L-2 -2 L-2 0 L0 0 Z M0 2 L100 2 L100 -2 L0 -2 L0 2 Z M2 100 L2 0 L-2 0 L-2 100 L2 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -210 + ], + [ + 0, + 1, + -361 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -210 + ], + [ + 0, + 1, + -361 + ] + ], + "x": -210, + "y": -361, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -210, + "y": -361, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -212, + "y": -363, + "width": 102, + "height": 102 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 4, + "strokeBottomWeight": 0, + "strokeLeftWeight": 4, + "strokeRightWeight": 0, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:9:141": { + "id": "VariableID:9:141", + "name": "size-null", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:140" + } + } + }, + "VariableID:9:140": { + "id": "VariableID:9:140", + "name": "size-0", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:139" + } + } + }, + "VariableID:9:139": { + "id": "VariableID:9:139", + "name": "spacing-0", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 0 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + }, + { + "id": "9:102", + "parent": { + "id": "9:96" + }, + "name": "border-center-solid-variable-top", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": { + "BORDER_TOP_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_BOTTOM_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_LEFT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_RIGHT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + } + }, + "boundVariables": { + "strokeTopWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeBottomWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeLeftWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeRightWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeWeight": 4, + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L0 -2 L-2 -2 L-2 0 L0 0 Z M100 0 L102 0 L102 -2 L100 -2 L100 0 Z M100 100 L100 102 L102 102 L102 100 L100 100 Z M0 100 L-2 100 L-2 102 L0 102 L0 100 Z M0 2 L100 2 L100 -2 L0 -2 L0 2 Z M98 0 L98 100 L102 100 L102 0 L98 0 Z M100 98 L0 98 L0 102 L100 102 L100 98 Z M2 100 L2 0 L-2 0 L-2 100 L2 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -770 + ], + [ + 0, + 1, + -361 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -770 + ], + [ + 0, + 1, + -361 + ] + ], + "x": -770, + "y": -361, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -770, + "y": -361, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -772, + "y": -363, + "width": 104, + "height": 104 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 4, + "strokeBottomWeight": 4, + "strokeLeftWeight": 4, + "strokeRightWeight": 4, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + }, + { + "id": "226:296", + "parent": { + "id": "9:96" + }, + "name": "border-center-solid-custom-left", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": {}, + "boundVariables": {}, + "resolvedVariableModes": {}, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.5254902243614197, + "g": 0.5843137502670288, + "b": 0.5921568870544434 + }, + "boundVariables": {} + } + ], + "strokeStyleId": "", + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M96 0 L96 100 L104 100 L104 0 L96 0 Z M1 100 L1 0 L-1 0 L-1 100 L1 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -630 + ], + [ + 0, + 1, + 19 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -630 + ], + [ + 0, + 1, + 19 + ] + ], + "x": -630, + "y": 19, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -630, + "y": 19, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -631, + "y": 19, + "width": 105, + "height": 100 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 0, + "strokeBottomWeight": 0, + "strokeLeftWeight": 2, + "strokeRightWeight": 8, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": {} + }, + { + "id": "226:300", + "parent": { + "id": "9:96" + }, + "name": "border-center-solid-variable-left", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": { + "BORDER_TOP_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:141" + }, + "BORDER_LEFT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + }, + "BORDER_RIGHT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:137" + } + }, + "boundVariables": { + "strokeTopWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:141" + }, + "strokeLeftWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokeRightWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:137" + }, + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M92 0 L92 100 L108 100 L108 0 L92 0 Z M2 100 L2 0 L-2 0 L-2 100 L2 100 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -630 + ], + [ + 0, + 1, + -361 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -630 + ], + [ + 0, + 1, + -361 + ] + ], + "x": -630, + "y": -361, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -630, + "y": -361, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -632, + "y": -361, + "width": 110, + "height": 100 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 0, + "strokeBottomWeight": 0, + "strokeLeftWeight": 4, + "strokeRightWeight": 16, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:9:141": { + "id": "VariableID:9:141", + "name": "size-null", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:140" + } + } + }, + "VariableID:9:140": { + "id": "VariableID:9:140", + "name": "size-0", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:139" + } + } + }, + "VariableID:9:139": { + "id": "VariableID:9:139", + "name": "spacing-0", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 0 + } + }, + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:9:137": { + "id": "VariableID:9:137", + "name": "size-16", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:136" + } + } + }, + "VariableID:9:136": { + "id": "VariableID:9:136", + "name": "spacing-5", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 16 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + }, + { + "id": "226:305", + "parent": { + "id": "9:96" + }, + "name": "border-center-solid-custom-right", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": {}, + "boundVariables": {}, + "resolvedVariableModes": {}, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.5254902243614197, + "g": 0.5843137502670288, + "b": 0.5921568870544434 + }, + "boundVariables": {} + } + ], + "strokeStyleId": "", + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M99 0 L99 100 L101 100 L101 0 L99 0 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -490 + ], + [ + 0, + 1, + 19 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -490 + ], + [ + 0, + 1, + 19 + ] + ], + "x": -490, + "y": 19, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -490, + "y": 19, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -391, + "y": 19, + "width": 2, + "height": 100 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 0, + "strokeBottomWeight": 0, + "strokeLeftWeight": 0, + "strokeRightWeight": 2, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": {} + }, + { + "id": "226:309", + "parent": { + "id": "9:96" + }, + "name": "border-center-solid-variable-right", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": { + "BORDER_RIGHT_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + } + }, + "boundVariables": { + "strokeRightWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M98 0 L98 100 L102 100 L102 0 L98 0 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -490 + ], + [ + 0, + 1, + -361 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -490 + ], + [ + 0, + 1, + -361 + ] + ], + "x": -490, + "y": -361, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -490, + "y": -361, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -392, + "y": -361, + "width": 4, + "height": 100 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 0, + "strokeBottomWeight": 0, + "strokeLeftWeight": 0, + "strokeRightWeight": 4, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + }, + { + "id": "226:314", + "parent": { + "id": "9:96" + }, + "name": "border-center-solid-custom-bottom", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": {}, + "boundVariables": {}, + "resolvedVariableModes": {}, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.5254902243614197, + "g": 0.5843137502670288, + "b": 0.5921568870544434 + }, + "boundVariables": {} + } + ], + "strokeStyleId": "", + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M100 99 L0 99 L0 101 L100 101 L100 99 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -350 + ], + [ + 0, + 1, + 19 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -350 + ], + [ + 0, + 1, + 19 + ] + ], + "x": -350, + "y": 19, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -350, + "y": 19, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -350, + "y": 118, + "width": 100, + "height": 2 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 0, + "strokeBottomWeight": 2, + "strokeLeftWeight": 0, + "strokeRightWeight": 0, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": {} + }, + { + "id": "226:318", + "parent": { + "id": "9:96" + }, + "name": "border-center-solid-variable-bottom", + "removed": false, + "isAsset": false, + "detachedInfo": null, + "visible": true, + "locked": false, + "stuckNodes": [], + "attachedConnectors": [], + "componentPropertyReferences": null, + "variableConsumptionMap": { + "BORDER_BOTTOM_WEIGHT": { + "type": 3, + "resolvedType": 1, + "value": "VariableID:9:49" + } + }, + "boundVariables": { + "strokeBottomWeight": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:49" + }, + "strokes": [ + { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + ] + }, + "resolvedVariableModes": { + "VariableCollectionId:5:13": "5:0", + "VariableCollectionId:5:16": "5:1", + "VariableCollectionId:5:19": "5:2" + }, + "explicitVariableModes": {}, + "opacity": 1, + "blendMode": "PASS_THROUGH", + "isMask": false, + "maskType": "ALPHA", + "effects": [], + "effectStyleId": "", + "fills": [], + "fillStyleId": "", + "strokes": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027 + }, + "boundVariables": { + "color": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:25" + } + } + } + ], + "strokeStyleId": "", + "strokeAlign": "CENTER", + "strokeJoin": "MITER", + "dashPattern": [], + "strokeCap": "NONE", + "strokeMiterLimit": 4, + "fillGeometry": [ + { + "windingRule": "NONZERO", + "data": "M0 0 L100 0 L100 100 L0 100 L0 0 Z" + } + ], + "strokeGeometry": [ + { + "windingRule": "NONZERO", + "data": "M100 98 L0 98 L0 102 L100 102 L100 98 Z" + } + ], + "relativeTransform": [ + [ + 1, + 0, + -350 + ], + [ + 0, + 1, + -361 + ] + ], + "absoluteTransform": [ + [ + 1, + 0, + -350 + ], + [ + 0, + 1, + -361 + ] + ], + "x": -350, + "y": -361, + "width": 100, + "height": 100, + "absoluteBoundingBox": { + "x": -350, + "y": -361, + "width": 100, + "height": 100 + }, + "absoluteRenderBounds": { + "x": -350, + "y": -263, + "width": 100, + "height": 4 + }, + "rotation": 0, + "layoutAlign": "INHERIT", + "constrainProportions": false, + "layoutGrow": 0, + "layoutPositioning": "AUTO", + "minWidth": null, + "minHeight": null, + "maxWidth": null, + "maxHeight": null, + "layoutSizingHorizontal": "FIXED", + "layoutSizingVertical": "FIXED", + "exportSettings": [], + "constraints": { + "horizontal": "MIN", + "vertical": "MIN" + }, + "cornerRadius": 0, + "cornerSmoothing": 0, + "topLeftRadius": 0, + "topRightRadius": 0, + "bottomLeftRadius": 0, + "bottomRightRadius": 0, + "reactions": [], + "strokeTopWeight": 0, + "strokeBottomWeight": 4, + "strokeLeftWeight": 0, + "strokeRightWeight": 0, + "playbackSettings": { + "autoplay": true, + "loop": true, + "muted": false + }, + "annotations": [], + "type": "RECTANGLE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + } + } + } + ], + "guides": [], + "selection": [ + { + "id": "9:107" + } + ], + "selectedTextRange": null, + "backgrounds": [ + { + "type": "SOLID", + "visible": true, + "opacity": 1, + "blendMode": "NORMAL", + "color": { + "r": 0.11764705926179886, + "g": 0.11764705926179886, + "b": 0.11764705926179886 + }, + "boundVariables": {} + } + ], + "exportSettings": [], + "prototypeStartNode": null, + "explicitVariableModes": {}, + "flowStartingPoints": [], + "prototypeBackgrounds": [ + { + "type": "SOLID", + "visible": true, + "opacity": 0, + "blendMode": "NORMAL", + "color": { + "r": 0, + "g": 0, + "b": 0 + }, + "boundVariables": {} + } + ], + "isPageDivider": false, + "type": "PAGE", + "variables": { + "VariableID:9:49": { + "id": "VariableID:9:49", + "name": "border-size-primary", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:48" + } + } + }, + "VariableID:9:141": { + "id": "VariableID:9:141", + "name": "size-null", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:140" + } + } + }, + "VariableID:9:48": { + "id": "VariableID:9:48", + "name": "size-4", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:47" + } + } + }, + "VariableID:9:140": { + "id": "VariableID:9:140", + "name": "size-0", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:139" + } + } + }, + "VariableID:9:47": { + "id": "VariableID:9:47", + "name": "spacing-3", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 4 + } + }, + "VariableID:9:139": { + "id": "VariableID:9:139", + "name": "spacing-0", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 0 + } + }, + "VariableID:6:25": { + "id": "VariableID:6:25", + "name": "border-primary", + "resolvedType": "COLOR", + "valuesByMode": { + "5:2": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:24" + } + } + }, + "VariableID:6:24": { + "id": "VariableID:6:24", + "name": "gray-medium", + "resolvedType": "COLOR", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:6:22" + } + } + }, + "VariableID:6:22": { + "id": "VariableID:6:22", + "name": "gray-500", + "resolvedType": "COLOR", + "valuesByMode": { + "5:0": { + "r": 0.40784314274787903, + "g": 0.47058823704719543, + "b": 0.4745098054409027, + "a": 1 + } + } + }, + "VariableID:9:137": { + "id": "VariableID:9:137", + "name": "size-16", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:1": { + "type": "VARIABLE_ALIAS", + "id": "VariableID:9:136" + } + } + }, + "VariableID:9:136": { + "id": "VariableID:9:136", + "name": "spacing-5", + "resolvedType": "FLOAT", + "valuesByMode": { + "5:0": 16 + } + } + } +} \ No newline at end of file diff --git a/src/transformers/scss.transformer.ts b/src/transformers/scss.transformer.ts index 493d7a5..6f21b86 100644 --- a/src/transformers/scss.transformer.ts +++ b/src/transformers/scss.transformer.ts @@ -85,9 +85,7 @@ export function transformToScss(tokens: TokenCollection): TransformerResult { output += ` ${token.property}: ${value}\n`; } } else { - const isVariable = token.value !== token.rawValue; - const value = isVariable ? token.value : token.valueType === 'px' ? rem(token.rawValue!) : token.value; - output += ` ${token.property}: ${value}\n`; + output += ` ${token.property}: ${rem(token.value!)}\n`; } }); output += "\n"; diff --git a/visualizer/styles.css b/visualizer/styles.css index d2bf401..fd20ff8 100644 --- a/visualizer/styles.css +++ b/visualizer/styles.css @@ -1,6 +1,6 @@ /* Generated CSS */ .position-inside-custom { - box-shadow: inset 0 0 0 0.25rem #687879; + box-shadow: inset 0 0.25rem 0 0 #687879, inset -0.25rem 0 0 0 #687879, inset 0 -0.25rem 0 0 #687879, inset 0.25rem 0 0 0 #687879; } .position-center-custom { From 1761bfc1cb5d7796fdf29c21efd3f848cb2d6927 Mon Sep 17 00:00:00 2001 From: Matt Chaffe Date: Wed, 5 Feb 2025 21:07:13 +0000 Subject: [PATCH 3/3] continue: added more to shape --- src/processors/border.processor.ts | 123 +++++++++++++----- src/processors/index.ts | 1 + .../border-processors.test.ts.snap | 21 +++ src/tests/border-processors.test.ts | 14 +- visualizer/styles.css | 42 +++++- 5 files changed, 161 insertions(+), 40 deletions(-) diff --git a/src/processors/border.processor.ts b/src/processors/border.processor.ts index df687eb..1de6b9a 100644 --- a/src/processors/border.processor.ts +++ b/src/processors/border.processor.ts @@ -30,25 +30,33 @@ export const borderProcessors: StyleProcessor[] = [ property: "border", bindingKey: "strokes", process: async (variables, node?: SceneNode): Promise => { - if (node && ('strokeAlign' in node && node.strokeAlign !== 'CENTER' || !('strokeAlign' in node))) { + if (!node) return null; + + // For non-rectangular shapes, we don't care about strokeAlign + const isRectangular = node.type === 'RECTANGLE' || node.type === 'COMPONENT' || node.type === 'INSTANCE'; + if (isRectangular && ('strokeAlign' in node && node.strokeAlign !== 'CENTER' || !('strokeAlign' in node))) { return null; } const weights = getBorderWeights(node); - if (!shouldUseShorthand(weights)) { + if (!shouldUseShorthand(node, weights)) { return null; } const color = getBorderColor(node, variables); if (!color) return null; - const width = getBorderWidth('strokeTopWeight', weights.top, variables); + // For lines, vectors, and ellipses, use strokeWeight + const width = node.type === 'LINE' || node.type === 'VECTOR' || node.type === 'ELLIPSE' + ? getBorderWidth('strokeWeight', 'strokeWeight' in node ? Number(node.strokeWeight) : 0, variables) + : getBorderWidth('strokeTopWeight', weights.top, variables); + const type = node && 'dashPattern' in node && node.dashPattern.length > 0 ? 'dashed' : 'solid'; const value = `${width.value} ${type} ${color.value}`; const rawValue = `${width.rawValue} ${type} ${color.rawValue}`; - - return { + + return { value, rawValue, valueType: "px", @@ -58,7 +66,7 @@ export const borderProcessors: StyleProcessor[] = [ { property: "border-top", bindingKey: "strokes", - process: async (variables, node?: SceneNode, processedProperties?: Set) => + process: async (variables, node?: SceneNode, processedProperties?: Set) => processBorderSide( { weightKey: 'top', propertyKey: 'strokeTopWeight' }, variables, @@ -69,7 +77,7 @@ export const borderProcessors: StyleProcessor[] = [ { property: "border-right", bindingKey: "strokes", - process: async (variables, node?: SceneNode, processedProperties?: Set) => + process: async (variables, node?: SceneNode, processedProperties?: Set) => processBorderSide( { weightKey: 'right', propertyKey: 'strokeRightWeight' }, variables, @@ -80,7 +88,7 @@ export const borderProcessors: StyleProcessor[] = [ { property: "border-bottom", bindingKey: "strokes", - process: async (variables, node?: SceneNode, processedProperties?: Set) => + process: async (variables, node?: SceneNode, processedProperties?: Set) => processBorderSide( { weightKey: 'bottom', propertyKey: 'strokeBottomWeight' }, variables, @@ -91,7 +99,7 @@ export const borderProcessors: StyleProcessor[] = [ { property: "border-left", bindingKey: "strokes", - process: async (variables, node?: SceneNode, processedProperties?: Set) => + process: async (variables, node?: SceneNode, processedProperties?: Set) => processBorderSide( { weightKey: 'left', propertyKey: 'strokeLeftWeight' }, variables, @@ -115,13 +123,13 @@ export const borderProcessors: StyleProcessor[] = [ const color = getBorderColor(node, variables); if (!color) return null; - const width = getBorderWidth('strokeLeftWeight', Object.values(weights).find(w => w > 0), variables); + const width = getBorderWidth('strokeLeftWeight', Object.values(weights).find(w => w > 0) || 0, variables); const type = node && 'dashPattern' in node && node.dashPattern.length > 0 ? 'dashed' : 'solid'; const value = `${width.value} ${type} ${color.value}`; const rawValue = `${width.rawValue} ${type} ${color.rawValue}`; - - return { + + return { value, rawValue, valueType: "px", @@ -172,8 +180,8 @@ export const borderProcessors: StyleProcessor[] = [ const value = shadows.join(', '); const rawValue = rawShadows.join(', '); - - return { + + return { value, rawValue, valueType: "px", @@ -192,6 +200,24 @@ export const borderProcessors: StyleProcessor[] = [ }; } + // Handle ELLIPSE nodes + if (node?.type === 'ELLIPSE') { + const EPSILON = 0.00001; + if ( + !('arcData' in node) || + ( + Math.abs(node.arcData.startingAngle - 0) < EPSILON && + Math.abs(node.arcData.endingAngle - (2 * Math.PI)) < EPSILON && + node.arcData.innerRadius === 0 + ) + ) { + return { value: '50%', rawValue: '50%' }; + } + // For partial circles or donuts, don't apply border-radius + return null; + } + + // Handle other nodes with cornerRadius if (node && 'cornerRadius' in node && node.cornerRadius) { const value = `${String(node.cornerRadius)}px`; return { value, rawValue: value }; @@ -199,20 +225,36 @@ export const borderProcessors: StyleProcessor[] = [ return null; } }, -]; +]; // Utility functions for border processing -const getBorderWeights = (node?: SceneNode): BorderWeights => ({ - top: node && 'strokeTopWeight' in node ? node.strokeTopWeight : 0, - right: node && 'strokeRightWeight' in node ? node.strokeRightWeight : 0, - bottom: node && 'strokeBottomWeight' in node ? node.strokeBottomWeight : 0, - left: node && 'strokeLeftWeight' in node ? node.strokeLeftWeight : 0 -}); - -const hasAnyBorder = (weights: BorderWeights): boolean => +const getBorderWeights = (node?: SceneNode): BorderWeights => { + if (!node) return { top: 0, right: 0, bottom: 0, left: 0 }; + + // For lines, vectors, and ellipses, they use a single strokeWeight + if (node.type === 'LINE' || node.type === 'VECTOR' || node.type === 'ELLIPSE') { + const weight: number = 'strokeWeight' in node ? Number(node.strokeWeight) : 0; + return { + top: weight, + right: weight, + bottom: weight, + left: weight + }; + } + + // For rectangles and other shapes that support individual side weights + return { + top: 'strokeTopWeight' in node ? node.strokeTopWeight : 0, + right: 'strokeRightWeight' in node ? node.strokeRightWeight : 0, + bottom: 'strokeBottomWeight' in node ? node.strokeBottomWeight : 0, + left: 'strokeLeftWeight' in node ? node.strokeLeftWeight : 0 + }; +}; + +const hasAnyBorder = (weights: BorderWeights): boolean => weights.top > 0 || weights.right > 0 || weights.bottom > 0 || weights.left > 0; -const hasFullBorder = (weights: BorderWeights): boolean => +const hasFullBorder = (weights: BorderWeights): boolean => weights.top > 0 && weights.right > 0 && weights.bottom > 0 && weights.left > 0; const areAllBordersEqual = (weights: BorderWeights): boolean => { @@ -220,8 +262,17 @@ const areAllBordersEqual = (weights: BorderWeights): boolean => { return nonZeroWeights.length > 0 && nonZeroWeights.every(w => w === nonZeroWeights[0]); }; -const shouldUseShorthand = (weights: BorderWeights): boolean => - hasFullBorder(weights) && areAllBordersEqual(weights); +const shouldUseShorthand = (node?: SceneNode, weights?: BorderWeights): boolean => { + if (!node || !weights) return false; + + // For lines, vectors, and ellipses, always use shorthand + if (node.type === 'LINE' || node.type === 'VECTOR' || node.type === 'ELLIPSE') { + return hasAnyBorder(weights); + } + + // For rectangles and other shapes, use original logic + return hasFullBorder(weights) && areAllBordersEqual(weights); +}; const getBorderColor = (node?: SceneNode, variables?: any[]): BorderColor | null => { const borderVariable = variables?.find(v => v.property === 'strokes'); @@ -270,12 +321,16 @@ const processBorderSide = async ( node?: SceneNode, processedProperties?: Set ): Promise => { + // For lines, vectors, and ellipses, don't process individual sides + if (node && (node.type === 'LINE' || node.type === 'VECTOR' || node.type === 'ELLIPSE')) { + return null; + } + const weights = getBorderWeights(node); - - // Skip if using shorthand or no border on this side - if (processedProperties?.has('border') || - weights[config.weightKey] === 0 || - shouldUseShorthand(weights)) { + + if (processedProperties?.has('border') || + weights[config.weightKey] === 0 || + shouldUseShorthand(node, weights)) { return null; } @@ -284,11 +339,11 @@ const processBorderSide = async ( const width = getBorderWidth(config.propertyKey, weights[config.weightKey], variables); const type = node && 'dashPattern' in node && node.dashPattern.length > 0 ? 'dashed' : 'solid'; - + const value = `${width.value} ${type} ${color.value}`; const rawValue = `${width.rawValue} ${type} ${color.rawValue}`; - - return { + + return { value, rawValue, valueType: "px", diff --git a/src/processors/index.ts b/src/processors/index.ts index c7fc23a..d1ac1d8 100644 --- a/src/processors/index.ts +++ b/src/processors/index.ts @@ -14,6 +14,7 @@ export function getProcessorsForNode(node: SceneNode): StyleProcessor[] { case "FRAME": case "RECTANGLE": case "INSTANCE": + case "ELLIPSE": return [ backgroundProcessor, ...layoutProcessors, diff --git a/src/tests/__snapshots__/border-processors.test.ts.snap b/src/tests/__snapshots__/border-processors.test.ts.snap index 18eb45a..d81e52a 100644 --- a/src/tests/__snapshots__/border-processors.test.ts.snap +++ b/src/tests/__snapshots__/border-processors.test.ts.snap @@ -18,6 +18,27 @@ $border-primary: #687879 " `; +exports[`Border Processors should process border shape correctly: border-shape 1`] = ` +"// Generated SCSS Variables +$border-size-primary: 0.25rem +$border-primary: #687879 + +// Generated SCSS Mixins +@mixin shape-rectangle + box-shadow: inset 0 $border-size-primary 0 0 $border-primary, inset -$border-size-primary 0 0 0 $border-primary, inset 0 -$border-size-primary 0 0 $border-primary, inset $border-size-primary 0 0 0 $border-primary + +@mixin shape-rounded-rectangle + box-shadow: inset 0 $border-size-primary 0 0 $border-primary, inset -$border-size-primary 0 0 0 $border-primary, inset 0 -$border-size-primary 0 0 $border-primary, inset $border-size-primary 0 0 0 $border-primary + border-radius: 1.25rem + +@mixin shape-ellipse + border: $border-size-primary solid $border-primary + box-shadow: inset 0 0.25rem 0 0 $border-primary, inset -0.25rem 0 0 0 $border-primary, inset 0 -0.25rem 0 0 $border-primary, inset 0.25rem 0 0 0 $border-primary + border-radius: 50% + +" +`; + exports[`Border Processors should process border sides correctly: border-sides 1`] = ` "// Generated SCSS Variables $border-size-primary: 0.25rem diff --git a/src/tests/border-processors.test.ts b/src/tests/border-processors.test.ts index 494c91e..52e2b83 100644 --- a/src/tests/border-processors.test.ts +++ b/src/tests/border-processors.test.ts @@ -3,7 +3,7 @@ import { transformToScss } from '../transformers'; import { createTestData } from '../utils/test.utils'; import testData from './fixtures/figma-test-data_border-position.json'; import testDataSides from './fixtures/figma-test-data_border-sides.json'; - +import testDataShape from './fixtures/figma-test-data_border-shape.json'; describe('Border Processors', () => { it('should process border correctly', async () => { @@ -29,4 +29,16 @@ describe('Border Processors', () => { expect(result).toMatchSnapshot('border-sides'); }); + + it('should process border shape correctly', async () => { + const { setupTest } = createTestData(testDataShape); + const testSetup = await setupTest(); + + global.figma = testSetup.figma; + + const tokens = await collectTokens(); + const { result} = transformToScss(tokens); + + expect(result).toMatchSnapshot('border-shape'); + }); }); \ No newline at end of file diff --git a/visualizer/styles.css b/visualizer/styles.css index fd20ff8..86c8394 100644 --- a/visualizer/styles.css +++ b/visualizer/styles.css @@ -1,12 +1,44 @@ /* Generated CSS */ -.position-inside-custom { - box-shadow: inset 0 0.25rem 0 0 #687879, inset -0.25rem 0 0 0 #687879, inset 0 -0.25rem 0 0 #687879, inset 0.25rem 0 0 0 #687879; +.border-center-solid-custom-topleft { + border-top: 0.125rem solid #869597; + border-left: 0.125rem solid #869597; } -.position-center-custom { +.border-center-solid-custom-top { + border: 0.125rem solid #869597; +} + +.border-center-solid-variable-topleft { + border-top: 0.25rem solid #687879; + border-left: 0.25rem solid #687879; +} + +.border-center-solid-variable-top { border: 0.25rem solid #687879; } -.position-outside-custom { - outline: 0.25rem solid #687879; +.border-center-solid-custom-left { + border-right: 0.5rem solid #869597; + border-left: 0.125rem solid #869597; +} + +.border-center-solid-variable-left { + border-right: 1rem solid #687879; + border-left: 0.25rem solid #687879; +} + +.border-center-solid-custom-right { + border-right: 0.125rem solid #869597; +} + +.border-center-solid-variable-right { + border-right: 0.25rem solid #687879; +} + +.border-center-solid-custom-bottom { + border-bottom: 0.125rem solid #869597; +} + +.border-center-solid-variable-bottom { + border-bottom: 0.25rem solid #687879; }