@dannote/figma-use 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +77 -1
- package/README.md +114 -256
- package/SKILL.md +82 -20
- package/dist/cli/index.js +3947 -380
- package/dist/proxy/index.js +8 -6
- package/package.json +8 -1
- package/packages/cli/src/render/component-set.tsx +7 -3
- package/packages/cli/src/render/components.tsx +16 -47
- package/packages/cli/src/render/icon.ts +163 -0
- package/packages/cli/src/render/index.ts +7 -1
- package/packages/cli/src/render/reconciler.ts +96 -34
- package/packages/cli/src/render/shorthands.ts +129 -0
- package/packages/cli/src/render/vars.ts +4 -5
- package/packages/plugin/dist/main.js +127 -33
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { FigmaVariable } from './vars.ts'
|
|
2
|
+
|
|
3
|
+
export type StyleValue = string | number | boolean | FigmaVariable
|
|
4
|
+
|
|
5
|
+
export interface StyleProps {
|
|
6
|
+
// Size
|
|
7
|
+
w?: number
|
|
8
|
+
h?: number
|
|
9
|
+
width?: number
|
|
10
|
+
height?: number
|
|
11
|
+
// Colors
|
|
12
|
+
bg?: string | FigmaVariable
|
|
13
|
+
backgroundColor?: string | FigmaVariable
|
|
14
|
+
// Border
|
|
15
|
+
rounded?: number
|
|
16
|
+
borderRadius?: number
|
|
17
|
+
// Padding
|
|
18
|
+
p?: number
|
|
19
|
+
pt?: number
|
|
20
|
+
pr?: number
|
|
21
|
+
pb?: number
|
|
22
|
+
pl?: number
|
|
23
|
+
px?: number
|
|
24
|
+
py?: number
|
|
25
|
+
padding?: number
|
|
26
|
+
paddingTop?: number
|
|
27
|
+
paddingRight?: number
|
|
28
|
+
paddingBottom?: number
|
|
29
|
+
paddingLeft?: number
|
|
30
|
+
// Text
|
|
31
|
+
size?: number
|
|
32
|
+
font?: string
|
|
33
|
+
weight?: string | number
|
|
34
|
+
fontSize?: number
|
|
35
|
+
fontFamily?: string
|
|
36
|
+
fontWeight?: string | number
|
|
37
|
+
// Layout
|
|
38
|
+
flex?: 'row' | 'col' | 'column'
|
|
39
|
+
flexDirection?: 'row' | 'column'
|
|
40
|
+
justify?: 'start' | 'end' | 'center' | 'between' | 'evenly'
|
|
41
|
+
justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-evenly'
|
|
42
|
+
items?: 'start' | 'end' | 'center' | 'stretch'
|
|
43
|
+
alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch'
|
|
44
|
+
gap?: number
|
|
45
|
+
// Other
|
|
46
|
+
opacity?: number
|
|
47
|
+
color?: string
|
|
48
|
+
[key: string]: StyleValue | undefined
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Simple shorthand → full property mapping */
|
|
52
|
+
export const shorthands: Record<string, string> = {
|
|
53
|
+
w: 'width',
|
|
54
|
+
h: 'height',
|
|
55
|
+
bg: 'backgroundColor',
|
|
56
|
+
rounded: 'borderRadius',
|
|
57
|
+
p: 'padding',
|
|
58
|
+
pt: 'paddingTop',
|
|
59
|
+
pr: 'paddingRight',
|
|
60
|
+
pb: 'paddingBottom',
|
|
61
|
+
pl: 'paddingLeft',
|
|
62
|
+
size: 'fontSize',
|
|
63
|
+
font: 'fontFamily',
|
|
64
|
+
weight: 'fontWeight'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Value transformations for specific properties */
|
|
68
|
+
export const valueTransforms: Record<string, Record<string, string>> = {
|
|
69
|
+
flexDirection: { col: 'column' },
|
|
70
|
+
justifyContent: {
|
|
71
|
+
start: 'flex-start',
|
|
72
|
+
end: 'flex-end',
|
|
73
|
+
between: 'space-between',
|
|
74
|
+
evenly: 'space-evenly'
|
|
75
|
+
},
|
|
76
|
+
alignItems: { start: 'flex-start', end: 'flex-end' }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Normalize Tailwind-like shorthand style props to full names */
|
|
80
|
+
export function normalizeStyle(style: StyleProps): StyleProps {
|
|
81
|
+
const result: StyleProps = {}
|
|
82
|
+
|
|
83
|
+
// First pass: expand simple shorthands and copy non-shorthand keys
|
|
84
|
+
for (const [key, value] of Object.entries(style)) {
|
|
85
|
+
// Skip special shorthands handled separately
|
|
86
|
+
if (key === 'px' || key === 'py' || key === 'flex' || key === 'justify' || key === 'items') {
|
|
87
|
+
continue
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const fullKey = shorthands[key] || key
|
|
91
|
+
// Full property takes precedence - check if it exists in original style
|
|
92
|
+
if (shorthands[key] && style[fullKey] !== undefined) {
|
|
93
|
+
continue
|
|
94
|
+
}
|
|
95
|
+
if (result[fullKey] === undefined) {
|
|
96
|
+
const transform = valueTransforms[fullKey]
|
|
97
|
+
result[fullKey] = transform?.[value as string] ?? value
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Expand px/py to individual padding properties
|
|
102
|
+
if (style.px !== undefined) {
|
|
103
|
+
if (result.paddingLeft === undefined) result.paddingLeft = style.px
|
|
104
|
+
if (result.paddingRight === undefined) result.paddingRight = style.px
|
|
105
|
+
}
|
|
106
|
+
if (style.py !== undefined) {
|
|
107
|
+
if (result.paddingTop === undefined) result.paddingTop = style.py
|
|
108
|
+
if (result.paddingBottom === undefined) result.paddingBottom = style.py
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Expand flex shorthand
|
|
112
|
+
if (style.flex !== undefined && result.flexDirection === undefined) {
|
|
113
|
+
const transform = valueTransforms.flexDirection
|
|
114
|
+
const value = transform?.[style.flex] ?? style.flex
|
|
115
|
+
result.flexDirection = value === 'col' ? 'column' : (value as StyleProps['flexDirection'])
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Expand justify/items shorthands
|
|
119
|
+
if (style.justify !== undefined && result.justifyContent === undefined) {
|
|
120
|
+
const transform = valueTransforms.justifyContent
|
|
121
|
+
result.justifyContent = (transform?.[style.justify] ?? style.justify) as StyleProps['justifyContent']
|
|
122
|
+
}
|
|
123
|
+
if (style.items !== undefined && result.alignItems === undefined) {
|
|
124
|
+
const transform = valueTransforms.alignItems
|
|
125
|
+
result.alignItems = (transform?.[style.items] ?? style.items) as StyleProps['alignItems']
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return result
|
|
129
|
+
}
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
import { parseColor } from '../color.ts'
|
|
24
23
|
|
|
25
24
|
const VAR_SYMBOL = Symbol.for('figma.variable')
|
|
26
25
|
|
|
@@ -68,8 +67,8 @@ export function loadVariablesIntoRegistry(variables: Array<{ id: string; name: s
|
|
|
68
67
|
if (match) {
|
|
69
68
|
variableRegistry.set(v.name, {
|
|
70
69
|
id: v.id,
|
|
71
|
-
sessionID: parseInt(match[1]
|
|
72
|
-
localID: parseInt(match[2]
|
|
70
|
+
sessionID: parseInt(match[1]!, 10),
|
|
71
|
+
localID: parseInt(match[2]!, 10)
|
|
73
72
|
})
|
|
74
73
|
}
|
|
75
74
|
}
|
|
@@ -90,8 +89,8 @@ export function resolveVariable(variable: FigmaVariable): ResolvedVariable {
|
|
|
90
89
|
if (idMatch) {
|
|
91
90
|
const resolved = {
|
|
92
91
|
id: `VariableID:${idMatch[1]}:${idMatch[2]}`,
|
|
93
|
-
sessionID: parseInt(idMatch[1]
|
|
94
|
-
localID: parseInt(idMatch[2]
|
|
92
|
+
sessionID: parseInt(idMatch[1]!, 10),
|
|
93
|
+
localID: parseInt(idMatch[2]!, 10)
|
|
95
94
|
}
|
|
96
95
|
variable._resolved = resolved
|
|
97
96
|
return resolved
|
|
@@ -1085,6 +1085,20 @@
|
|
|
1085
1085
|
// src/main.ts
|
|
1086
1086
|
var import_svgpath = __toESM(require_svgpath2(), 1);
|
|
1087
1087
|
console.log("[Figma Bridge] Plugin main loaded at", (/* @__PURE__ */ new Date()).toISOString());
|
|
1088
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1089
|
+
function retry(fn, maxAttempts = 10, delayMs = 50, backoff = "fixed") {
|
|
1090
|
+
return __async(this, null, function* () {
|
|
1091
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
1092
|
+
const result = yield fn();
|
|
1093
|
+
if (result) return result;
|
|
1094
|
+
if (attempt < maxAttempts - 1) {
|
|
1095
|
+
const delay = backoff === "linear" ? delayMs * (attempt + 1) : backoff === "exponential" ? delayMs * Math.pow(2, attempt) : delayMs;
|
|
1096
|
+
yield sleep(delay);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
return null;
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1088
1102
|
figma.showUI(__html__, { width: 300, height: 200 });
|
|
1089
1103
|
var loadedFonts = /* @__PURE__ */ new Set();
|
|
1090
1104
|
var fontLoadPromises = /* @__PURE__ */ new Map();
|
|
@@ -1113,7 +1127,6 @@
|
|
|
1113
1127
|
width,
|
|
1114
1128
|
height,
|
|
1115
1129
|
name,
|
|
1116
|
-
parentId,
|
|
1117
1130
|
fill,
|
|
1118
1131
|
stroke,
|
|
1119
1132
|
strokeWeight,
|
|
@@ -1135,8 +1148,8 @@
|
|
|
1135
1148
|
frame.y = y;
|
|
1136
1149
|
frame.resize(width || 100, height || 100);
|
|
1137
1150
|
if (name) frame.name = name;
|
|
1138
|
-
if (fill) frame.fills = [{ type: "SOLID", color: hexToRgb(fill) }];
|
|
1139
|
-
if (stroke) frame.strokes = [{ type: "SOLID", color: hexToRgb(stroke) }];
|
|
1151
|
+
if (fill) frame.fills = [{ type: "SOLID", color: hexToRgb(getHexColor(fill)) }];
|
|
1152
|
+
if (stroke) frame.strokes = [{ type: "SOLID", color: hexToRgb(getHexColor(stroke)) }];
|
|
1140
1153
|
if (strokeWeight) frame.strokeWeight = strokeWeight;
|
|
1141
1154
|
if (typeof radius === "number") frame.cornerRadius = radius;
|
|
1142
1155
|
if (typeof opacity === "number") frame.opacity = opacity;
|
|
@@ -1157,8 +1170,8 @@
|
|
|
1157
1170
|
rect.y = y;
|
|
1158
1171
|
rect.resize(width || 100, height || 100);
|
|
1159
1172
|
if (name) rect.name = name;
|
|
1160
|
-
if (fill) rect.fills = [{ type: "SOLID", color: hexToRgb(fill) }];
|
|
1161
|
-
if (stroke) rect.strokes = [{ type: "SOLID", color: hexToRgb(stroke) }];
|
|
1173
|
+
if (fill) rect.fills = [{ type: "SOLID", color: hexToRgb(getHexColor(fill)) }];
|
|
1174
|
+
if (stroke) rect.strokes = [{ type: "SOLID", color: hexToRgb(getHexColor(stroke)) }];
|
|
1162
1175
|
if (strokeWeight) rect.strokeWeight = strokeWeight;
|
|
1163
1176
|
if (typeof radius === "number") rect.cornerRadius = radius;
|
|
1164
1177
|
if (typeof opacity === "number") rect.opacity = opacity;
|
|
@@ -1171,8 +1184,8 @@
|
|
|
1171
1184
|
ellipse.y = y;
|
|
1172
1185
|
ellipse.resize(width || 100, height || 100);
|
|
1173
1186
|
if (name) ellipse.name = name;
|
|
1174
|
-
if (fill) ellipse.fills = [{ type: "SOLID", color: hexToRgb(fill) }];
|
|
1175
|
-
if (stroke) ellipse.strokes = [{ type: "SOLID", color: hexToRgb(stroke) }];
|
|
1187
|
+
if (fill) ellipse.fills = [{ type: "SOLID", color: hexToRgb(getHexColor(fill)) }];
|
|
1188
|
+
if (stroke) ellipse.strokes = [{ type: "SOLID", color: hexToRgb(getHexColor(stroke)) }];
|
|
1176
1189
|
if (strokeWeight) ellipse.strokeWeight = strokeWeight;
|
|
1177
1190
|
if (typeof opacity === "number") ellipse.opacity = opacity;
|
|
1178
1191
|
node = ellipse;
|
|
@@ -1189,7 +1202,7 @@
|
|
|
1189
1202
|
textNode.y = y;
|
|
1190
1203
|
if (name) textNode.name = name;
|
|
1191
1204
|
if (fontSize) textNode.fontSize = fontSize;
|
|
1192
|
-
if (fill) textNode.fills = [{ type: "SOLID", color: hexToRgb(fill) }];
|
|
1205
|
+
if (fill) textNode.fills = [{ type: "SOLID", color: hexToRgb(getHexColor(fill)) }];
|
|
1193
1206
|
if (typeof opacity === "number") textNode.opacity = opacity;
|
|
1194
1207
|
node = textNode;
|
|
1195
1208
|
break;
|
|
@@ -1489,8 +1502,8 @@
|
|
|
1489
1502
|
rect.y = y;
|
|
1490
1503
|
rect.resize(width, height);
|
|
1491
1504
|
if (name) rect.name = name;
|
|
1492
|
-
if (fill) rect.fills = [
|
|
1493
|
-
if (stroke) rect.strokes = [
|
|
1505
|
+
if (fill) rect.fills = [yield createSolidPaint(fill)];
|
|
1506
|
+
if (stroke) rect.strokes = [yield createSolidPaint(stroke)];
|
|
1494
1507
|
if (strokeWeight !== void 0) rect.strokeWeight = strokeWeight;
|
|
1495
1508
|
if (radius !== void 0) rect.cornerRadius = radius;
|
|
1496
1509
|
if (opacity !== void 0) rect.opacity = opacity;
|
|
@@ -1504,21 +1517,23 @@
|
|
|
1504
1517
|
ellipse.y = y;
|
|
1505
1518
|
ellipse.resize(width, height);
|
|
1506
1519
|
if (name) ellipse.name = name;
|
|
1507
|
-
if (fill) ellipse.fills = [
|
|
1508
|
-
if (stroke) ellipse.strokes = [
|
|
1520
|
+
if (fill) ellipse.fills = [yield createSolidPaint(fill)];
|
|
1521
|
+
if (stroke) ellipse.strokes = [yield createSolidPaint(stroke)];
|
|
1509
1522
|
if (strokeWeight !== void 0) ellipse.strokeWeight = strokeWeight;
|
|
1510
1523
|
if (opacity !== void 0) ellipse.opacity = opacity;
|
|
1511
1524
|
yield appendToParent(ellipse, parentId);
|
|
1512
1525
|
return serializeNode(ellipse);
|
|
1513
1526
|
}
|
|
1514
1527
|
case "create-line": {
|
|
1515
|
-
const { x, y, length, rotation, name, parentId } = args;
|
|
1528
|
+
const { x, y, length, rotation, name, parentId, stroke, strokeWeight } = args;
|
|
1516
1529
|
const line = figma.createLine();
|
|
1517
1530
|
line.x = x;
|
|
1518
1531
|
line.y = y;
|
|
1519
1532
|
line.resize(length, 0);
|
|
1520
1533
|
if (rotation) line.rotation = rotation;
|
|
1521
1534
|
if (name) line.name = name;
|
|
1535
|
+
if (stroke) line.strokes = [yield createSolidPaint(stroke)];
|
|
1536
|
+
if (strokeWeight !== void 0) line.strokeWeight = strokeWeight;
|
|
1522
1537
|
yield appendToParent(line, parentId);
|
|
1523
1538
|
return serializeNode(line);
|
|
1524
1539
|
}
|
|
@@ -1577,8 +1592,8 @@
|
|
|
1577
1592
|
frame.y = y;
|
|
1578
1593
|
frame.resize(width, height);
|
|
1579
1594
|
if (name) frame.name = name;
|
|
1580
|
-
if (fill) frame.fills = [
|
|
1581
|
-
if (stroke) frame.strokes = [
|
|
1595
|
+
if (fill) frame.fills = [yield createSolidPaint(fill)];
|
|
1596
|
+
if (stroke) frame.strokes = [yield createSolidPaint(stroke)];
|
|
1582
1597
|
if (strokeWeight !== void 0) frame.strokeWeight = strokeWeight;
|
|
1583
1598
|
if (radius !== void 0) frame.cornerRadius = radius;
|
|
1584
1599
|
if (opacity !== void 0) frame.opacity = opacity;
|
|
@@ -1625,7 +1640,7 @@
|
|
|
1625
1640
|
textNode.fontName = { family, style };
|
|
1626
1641
|
textNode.characters = text;
|
|
1627
1642
|
if (fontSize) textNode.fontSize = fontSize;
|
|
1628
|
-
if (fill) textNode.fills = [
|
|
1643
|
+
if (fill) textNode.fills = [yield createSolidPaint(fill)];
|
|
1629
1644
|
if (opacity !== void 0) textNode.opacity = opacity;
|
|
1630
1645
|
if (name) textNode.name = name;
|
|
1631
1646
|
yield appendToParent(textNode, parentId);
|
|
@@ -1643,9 +1658,13 @@
|
|
|
1643
1658
|
return serializeNode(instance);
|
|
1644
1659
|
}
|
|
1645
1660
|
case "create-component": {
|
|
1646
|
-
const { name, parentId } = args;
|
|
1661
|
+
const { name, parentId, x, y, width, height, fill } = args;
|
|
1647
1662
|
const component = figma.createComponent();
|
|
1648
1663
|
component.name = name;
|
|
1664
|
+
if (x !== void 0) component.x = x;
|
|
1665
|
+
if (y !== void 0) component.y = y;
|
|
1666
|
+
if (width && height) component.resize(width, height);
|
|
1667
|
+
if (fill) component.fills = [yield createSolidPaint(fill)];
|
|
1649
1668
|
yield appendToParent(component, parentId);
|
|
1650
1669
|
return serializeNode(component);
|
|
1651
1670
|
}
|
|
@@ -1656,12 +1675,19 @@
|
|
|
1656
1675
|
const clone = node.clone();
|
|
1657
1676
|
return serializeNode(clone);
|
|
1658
1677
|
}
|
|
1678
|
+
case "convert-to-component": {
|
|
1679
|
+
const { id } = args;
|
|
1680
|
+
const node = yield figma.getNodeByIdAsync(id);
|
|
1681
|
+
if (!node) throw new Error("Node not found");
|
|
1682
|
+
const component = figma.createComponentFromNode(node);
|
|
1683
|
+
return serializeNode(component);
|
|
1684
|
+
}
|
|
1659
1685
|
// ==================== CREATE STYLES ====================
|
|
1660
1686
|
case "create-paint-style": {
|
|
1661
1687
|
const { name, color } = args;
|
|
1662
1688
|
const style = figma.createPaintStyle();
|
|
1663
1689
|
style.name = name;
|
|
1664
|
-
style.paints = [
|
|
1690
|
+
style.paints = [yield createSolidPaint(color)];
|
|
1665
1691
|
return { id: style.id, name: style.name, key: style.key };
|
|
1666
1692
|
}
|
|
1667
1693
|
case "create-text-style": {
|
|
@@ -1730,14 +1756,14 @@
|
|
|
1730
1756
|
const { id, color } = args;
|
|
1731
1757
|
const node = yield figma.getNodeByIdAsync(id);
|
|
1732
1758
|
if (!node || !("fills" in node)) throw new Error("Node not found");
|
|
1733
|
-
node.fills = [
|
|
1759
|
+
node.fills = [yield createSolidPaint(color)];
|
|
1734
1760
|
return serializeNode(node);
|
|
1735
1761
|
}
|
|
1736
1762
|
case "set-stroke-color": {
|
|
1737
1763
|
const { id, color, weight, align } = args;
|
|
1738
1764
|
const node = yield figma.getNodeByIdAsync(id);
|
|
1739
1765
|
if (!node || !("strokes" in node)) throw new Error("Node not found");
|
|
1740
|
-
node.strokes = [
|
|
1766
|
+
node.strokes = [yield createSolidPaint(color)];
|
|
1741
1767
|
if (weight !== void 0 && "strokeWeight" in node) node.strokeWeight = weight;
|
|
1742
1768
|
if (align && "strokeAlign" in node)
|
|
1743
1769
|
node.strokeAlign = align;
|
|
@@ -1790,6 +1816,34 @@
|
|
|
1790
1816
|
node.name = name;
|
|
1791
1817
|
return serializeNode(node);
|
|
1792
1818
|
}
|
|
1819
|
+
case "bind-fill-variable-by-name": {
|
|
1820
|
+
let bindFills2 = function(n) {
|
|
1821
|
+
if ("fills" in n && Array.isArray(n.fills) && n.fills.length > 0) {
|
|
1822
|
+
const fills = [...n.fills];
|
|
1823
|
+
for (let i = 0; i < fills.length; i++) {
|
|
1824
|
+
if (fills[i].type === "SOLID") {
|
|
1825
|
+
fills[i] = figma.variables.setBoundVariableForPaint(fills[i], "color", variable);
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
;
|
|
1829
|
+
n.fills = fills;
|
|
1830
|
+
}
|
|
1831
|
+
if (recursive && "children" in n) {
|
|
1832
|
+
for (const child of n.children) {
|
|
1833
|
+
bindFills2(child);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
};
|
|
1837
|
+
var bindFills = bindFills2;
|
|
1838
|
+
const { id, variableName, recursive } = args;
|
|
1839
|
+
const node = yield figma.getNodeByIdAsync(id);
|
|
1840
|
+
if (!node) throw new Error("Node not found");
|
|
1841
|
+
const variables = yield figma.variables.getLocalVariablesAsync("COLOR");
|
|
1842
|
+
const variable = variables.find((v) => v.name === variableName);
|
|
1843
|
+
if (!variable) throw new Error(`Variable "${variableName}" not found`);
|
|
1844
|
+
bindFills2(node);
|
|
1845
|
+
return serializeNode(node);
|
|
1846
|
+
}
|
|
1793
1847
|
case "set-visible": {
|
|
1794
1848
|
const { id, visible } = args;
|
|
1795
1849
|
const node = yield figma.getNodeByIdAsync(id);
|
|
@@ -1843,12 +1897,13 @@
|
|
|
1843
1897
|
return serializeNode(node);
|
|
1844
1898
|
}
|
|
1845
1899
|
case "import-svg": {
|
|
1846
|
-
const { svg, x, y, name, parentId } = args;
|
|
1900
|
+
const { svg, x, y, name, parentId, noFill, insertIndex } = args;
|
|
1847
1901
|
const node = figma.createNodeFromSvg(svg);
|
|
1848
1902
|
if (x !== void 0) node.x = x;
|
|
1849
1903
|
if (y !== void 0) node.y = y;
|
|
1850
1904
|
if (name) node.name = name;
|
|
1851
|
-
|
|
1905
|
+
if (noFill) node.fills = [];
|
|
1906
|
+
yield appendToParent(node, parentId, insertIndex);
|
|
1852
1907
|
return serializeNode(node);
|
|
1853
1908
|
}
|
|
1854
1909
|
case "set-font": {
|
|
@@ -1878,8 +1933,7 @@
|
|
|
1878
1933
|
node.setRangeFontSize(start, end, size);
|
|
1879
1934
|
}
|
|
1880
1935
|
if (color) {
|
|
1881
|
-
|
|
1882
|
-
node.setRangeFills(start, end, [{ type: "SOLID", color: rgb }]);
|
|
1936
|
+
node.setRangeFills(start, end, [yield createSolidPaint(color)]);
|
|
1883
1937
|
}
|
|
1884
1938
|
return serializeNode(node);
|
|
1885
1939
|
}
|
|
@@ -2405,12 +2459,12 @@
|
|
|
2405
2459
|
// ==================== LAYOUT ====================
|
|
2406
2460
|
case "trigger-layout": {
|
|
2407
2461
|
const { nodeId, pendingComponentSetInstances } = args;
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2462
|
+
const root = yield retry(
|
|
2463
|
+
() => figma.getNodeByIdAsync(nodeId),
|
|
2464
|
+
10,
|
|
2465
|
+
100,
|
|
2466
|
+
"linear"
|
|
2467
|
+
);
|
|
2414
2468
|
if (!root) return null;
|
|
2415
2469
|
if (pendingComponentSetInstances && pendingComponentSetInstances.length > 0) {
|
|
2416
2470
|
for (const pending of pendingComponentSetInstances) {
|
|
@@ -2611,14 +2665,23 @@
|
|
|
2611
2665
|
}
|
|
2612
2666
|
});
|
|
2613
2667
|
}
|
|
2614
|
-
function appendToParent(node, parentId) {
|
|
2668
|
+
function appendToParent(node, parentId, insertIndex) {
|
|
2615
2669
|
return __async(this, null, function* () {
|
|
2616
2670
|
if (parentId) {
|
|
2617
|
-
const parent = yield
|
|
2671
|
+
const parent = yield retry(
|
|
2672
|
+
() => figma.getNodeByIdAsync(parentId),
|
|
2673
|
+
10,
|
|
2674
|
+
50
|
|
2675
|
+
);
|
|
2618
2676
|
if (parent && "appendChild" in parent) {
|
|
2619
|
-
parent
|
|
2677
|
+
if (insertIndex !== void 0 && "insertChild" in parent) {
|
|
2678
|
+
parent.insertChild(insertIndex, node);
|
|
2679
|
+
} else {
|
|
2680
|
+
parent.appendChild(node);
|
|
2681
|
+
}
|
|
2620
2682
|
return;
|
|
2621
2683
|
}
|
|
2684
|
+
console.warn(`Parent ${parentId} not found after retries, appending to page`);
|
|
2622
2685
|
}
|
|
2623
2686
|
figma.currentPage.appendChild(node);
|
|
2624
2687
|
});
|
|
@@ -2730,6 +2793,37 @@
|
|
|
2730
2793
|
b: parseInt(clean.slice(4, 6), 16) / 255
|
|
2731
2794
|
};
|
|
2732
2795
|
}
|
|
2796
|
+
function parsestring(color) {
|
|
2797
|
+
const varMatch = color.match(/^(?:var:|[$])(.+)$/);
|
|
2798
|
+
if (varMatch) {
|
|
2799
|
+
return { variable: varMatch[1] };
|
|
2800
|
+
}
|
|
2801
|
+
return { hex: color };
|
|
2802
|
+
}
|
|
2803
|
+
function getHexColor(color) {
|
|
2804
|
+
const parsed = parsestring(color);
|
|
2805
|
+
return parsed.hex || "#000000";
|
|
2806
|
+
}
|
|
2807
|
+
function createSolidPaint(color) {
|
|
2808
|
+
return __async(this, null, function* () {
|
|
2809
|
+
const parsed = parsestring(color);
|
|
2810
|
+
if (parsed.hex) {
|
|
2811
|
+
return { type: "SOLID", color: hexToRgb(parsed.hex) };
|
|
2812
|
+
}
|
|
2813
|
+
const variables = yield figma.variables.getLocalVariablesAsync("COLOR");
|
|
2814
|
+
const variable = variables.find((v) => v.name === parsed.variable);
|
|
2815
|
+
if (!variable) {
|
|
2816
|
+
console.warn(`Variable "${parsed.variable}" not found, using black`);
|
|
2817
|
+
return { type: "SOLID", color: { r: 0, g: 0, b: 0 } };
|
|
2818
|
+
}
|
|
2819
|
+
const paint = {
|
|
2820
|
+
type: "SOLID",
|
|
2821
|
+
color: { r: 0, g: 0, b: 0 }
|
|
2822
|
+
// Will be overridden by variable
|
|
2823
|
+
};
|
|
2824
|
+
return figma.variables.setBoundVariableForPaint(paint, "color", variable);
|
|
2825
|
+
});
|
|
2826
|
+
}
|
|
2733
2827
|
function hexToRgba(hex) {
|
|
2734
2828
|
const clean = expandHex(hex);
|
|
2735
2829
|
const hasAlpha = clean.length === 8;
|