From 11879d821f77eb618c31ab0b29b8a7871c82359d Mon Sep 17 00:00:00 2001 From: Brian Heston <47367562+bheston@users.noreply.github.com> Date: Thu, 5 Sep 2024 19:39:31 -0700 Subject: [PATCH 1/3] Designer: Added support for individual border thickness --- .../src/figma/node.ts | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/packages/adaptive-ui-designer-figma-plugin/src/figma/node.ts b/packages/adaptive-ui-designer-figma-plugin/src/figma/node.ts index 36c10cc1..4d709547 100644 --- a/packages/adaptive-ui-designer-figma-plugin/src/figma/node.ts +++ b/packages/adaptive-ui-designer-figma-plugin/src/figma/node.ts @@ -83,6 +83,13 @@ function isShapeNode(node: BaseNode): node is ].some((test: (node: BaseNode) => boolean) => test(node)); } +function isIndividualStrokesShapeNode(node: BaseNode): node is + RectangleNode { + return [ + isRectangleNode, + ].some((test: (node: BaseNode) => boolean) => test(node)); +} + function canHaveChildren(node: BaseNode): node is | DocumentNode | PageNode @@ -391,7 +398,7 @@ export class FigmaPluginNode extends PluginNode { case StyleProperty.gap: return [ isContainerNode, - ].some((test: (node: BaseNode) => boolean) => test(this._node)); + ].some((test: (node: BaseNode) => boolean) => test(this._node)); case StyleProperty.cornerRadiusTopLeft: case StyleProperty.cornerRadiusTopRight: case StyleProperty.cornerRadiusBottomRight: @@ -591,7 +598,7 @@ export class FigmaPluginNode extends PluginNode { case StyleProperty.borderThicknessBottom: case StyleProperty.borderThicknessLeft: this.setBoxSizing(); - this.paintStrokeWidth(value); + this.paintStrokeWidth(target, value); break; case StyleProperty.cornerRadiusTopLeft: case StyleProperty.cornerRadiusTopRight: @@ -879,16 +886,42 @@ export class FigmaPluginNode extends PluginNode { (this._node as MinimalFillsMixin).fills = paint ? [paint] : [SOLID_BLACK]; break; case StyleProperty.borderFillTop: + case StyleProperty.borderFillRight: + case StyleProperty.borderFillBottom: + case StyleProperty.borderFillLeft: // TODO: Figma only supports one border color, though it can be hacked using inner shadow. (this._node as MinimalStrokesMixin).strokes = paintValue; break; } } - private paintStrokeWidth(value: string): void { - (this._node as MinimalStrokesMixin).strokeWeight = this.safeNumber(value); - if ((this._node as MinimalStrokesMixin).strokes.length === 0) { - (this._node as MinimalStrokesMixin).strokes = [SOLID_TRANSPARENT]; + private paintStrokeWidth(target: StyleProperty, value: string): void { + try { + const numValue = this.safeNumber(value); + if (isContainerNode(this._node) || isIndividualStrokesShapeNode(this._node)) { + switch (target) { + case StyleProperty.borderThicknessTop: + (this._node as IndividualStrokesMixin).strokeTopWeight = numValue; + break; + case StyleProperty.borderThicknessRight: + (this._node as IndividualStrokesMixin).strokeRightWeight = numValue; + break; + case StyleProperty.borderThicknessBottom: + (this._node as IndividualStrokesMixin).strokeBottomWeight = numValue; + break; + case StyleProperty.borderThicknessLeft: + (this._node as IndividualStrokesMixin).strokeLeftWeight = numValue; + break; + } + } else { + (this._node as MinimalStrokesMixin).strokeWeight = this.safeNumber(value); + } + + if ((this._node as MinimalStrokesMixin).strokes.length === 0) { + (this._node as MinimalStrokesMixin).strokes = [SOLID_TRANSPARENT]; + } + } catch (error) { + console.error("paintStrokeWidth", { target, value, error, ...this.debugInfo }); } } @@ -1010,7 +1043,7 @@ export class FigmaPluginNode extends PluginNode { }] }]; - y += restComponent.height + spacing; + y += restComponent.height + spacing; }); this._node.resize(x - spacing + paddingRight, y - spacing + paddingBottom); From 2c481dc0f6794b2707c8be749fb5966ea69455a1 Mon Sep 17 00:00:00 2001 From: Brian Heston <47367562+bheston@users.noreply.github.com> Date: Fri, 6 Sep 2024 09:56:23 -0700 Subject: [PATCH 2/3] Fix an issue with resetting strokes --- .../src/figma/node.ts | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/adaptive-ui-designer-figma-plugin/src/figma/node.ts b/packages/adaptive-ui-designer-figma-plugin/src/figma/node.ts index 4d709547..9f785c35 100644 --- a/packages/adaptive-ui-designer-figma-plugin/src/figma/node.ts +++ b/packages/adaptive-ui-designer-figma-plugin/src/figma/node.ts @@ -517,7 +517,7 @@ export class FigmaPluginNode extends PluginNode { } protected handleFontFamily(node: FigmaPluginNode, values: AppliedStyleValues) { - const fontFamily = values?.get(StyleProperty.fontFamily)?.value; + const fontFamily = values.get(StyleProperty.fontFamily)?.value; // We'll only set the font if the family is provided. if (fontFamily) { if (isTextNode(node._node)) { @@ -548,6 +548,40 @@ export class FigmaPluginNode extends PluginNode { } } + /** + * Cleans up stroke values based on what we're about to apply. + * + * @remarks + * Figma has a default invisible stroke width of `1`. If you add a stroke in the UI + * it sets the weight to `1` and adds a default color. + * If you change the weight, then remove the strokes (nothing visible) it maintains + * the old stroke weight, but when you add again it resets to `1`. + * + * @param node - The Figma node + * @param values - The entire list of values to be applied + */ + private handleStroke(values: AppliedStyleValues) { + const applyingFill = values.has(StyleProperty.borderFillTop) + || values.has(StyleProperty.borderFillRight) + || values.has(StyleProperty.borderFillBottom) + || values.has(StyleProperty.borderFillLeft); + const applyingThickness = values.has(StyleProperty.borderThicknessTop) + || values.has(StyleProperty.borderThicknessRight) + || values.has(StyleProperty.borderThicknessBottom) + || values.has(StyleProperty.borderThicknessLeft); + + if (applyingFill && applyingThickness) { + if (isContainerNode(this._node) || isIndividualStrokesShapeNode(this._node)) { + (this._node as IndividualStrokesMixin).strokeTopWeight = 0; + (this._node as IndividualStrokesMixin).strokeRightWeight = 0; + (this._node as IndividualStrokesMixin).strokeBottomWeight = 0; + (this._node as IndividualStrokesMixin).strokeLeftWeight = 0; + } else { + // If it's not "individual" we're going to set it anyway. + } + } + } + protected safeNumber(value: string, defaultValue: number = 0) { return value === STYLE_REMOVE ? defaultValue : Number.parseFloat(value); } @@ -556,6 +590,8 @@ export class FigmaPluginNode extends PluginNode { // Fonts are complicated in Figma, so pull them out of the normal loop. this.handleFontFamily(this, values); + this.handleStroke(values); + // Paint all applied design tokens on the node values.forEach((styleValue, target) => { // console.log("applied design token eval", target, applied); From fd0d3bfe744768e36bdaf6d31c9ff8d1b4a523a7 Mon Sep 17 00:00:00 2001 From: Brian Heston <47367562+bheston@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:54:55 -0700 Subject: [PATCH 3/3] Address review comments --- .../src/figma/node.ts | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/adaptive-ui-designer-figma-plugin/src/figma/node.ts b/packages/adaptive-ui-designer-figma-plugin/src/figma/node.ts index 9f785c35..a7c39da2 100644 --- a/packages/adaptive-ui-designer-figma-plugin/src/figma/node.ts +++ b/packages/adaptive-ui-designer-figma-plugin/src/figma/node.ts @@ -83,22 +83,26 @@ function isShapeNode(node: BaseNode): node is ].some((test: (node: BaseNode) => boolean) => test(node)); } -function isIndividualStrokesShapeNode(node: BaseNode): node is +function canHaveIndividualStrokes(node: BaseNode): node is + FrameNode | + ComponentNode | + InstanceNode | RectangleNode { return [ + isContainerNode, isRectangleNode, ].some((test: (node: BaseNode) => boolean) => test(node)); } function canHaveChildren(node: BaseNode): node is - | DocumentNode - | PageNode - | FrameNode - | GroupNode - | BooleanOperationNode - | InstanceNode - | ComponentNode - | ComponentSetNode { + DocumentNode | + PageNode | + FrameNode | + GroupNode | + BooleanOperationNode | + InstanceNode | + ComponentNode | + ComponentSetNode { return [ isDocumentNode, isPageNode, @@ -557,7 +561,6 @@ export class FigmaPluginNode extends PluginNode { * If you change the weight, then remove the strokes (nothing visible) it maintains * the old stroke weight, but when you add again it resets to `1`. * - * @param node - The Figma node * @param values - The entire list of values to be applied */ private handleStroke(values: AppliedStyleValues) { @@ -571,13 +574,12 @@ export class FigmaPluginNode extends PluginNode { || values.has(StyleProperty.borderThicknessLeft); if (applyingFill && applyingThickness) { - if (isContainerNode(this._node) || isIndividualStrokesShapeNode(this._node)) { + // We only need to reset "individual" strokes here since we'll set a common stroke later anyway. + if (canHaveIndividualStrokes(this._node)) { (this._node as IndividualStrokesMixin).strokeTopWeight = 0; (this._node as IndividualStrokesMixin).strokeRightWeight = 0; (this._node as IndividualStrokesMixin).strokeBottomWeight = 0; (this._node as IndividualStrokesMixin).strokeLeftWeight = 0; - } else { - // If it's not "individual" we're going to set it anyway. } } } @@ -934,7 +936,7 @@ export class FigmaPluginNode extends PluginNode { private paintStrokeWidth(target: StyleProperty, value: string): void { try { const numValue = this.safeNumber(value); - if (isContainerNode(this._node) || isIndividualStrokesShapeNode(this._node)) { + if (canHaveIndividualStrokes(this._node)) { switch (target) { case StyleProperty.borderThicknessTop: (this._node as IndividualStrokesMixin).strokeTopWeight = numValue;