@dannote/figma-use 0.6.0 → 0.6.2
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 +34 -1
- package/README.md +34 -3
- package/SKILL.md +72 -0
- package/bin/figma-use.js +1 -4
- package/dist/cli/index.js +22348 -20440
- package/dist/proxy/index.js +25 -25
- package/package.json +7 -3
- package/packages/cli/src/render/component-set.tsx +30 -21
- package/packages/cli/src/render/components.tsx +40 -16
- package/packages/cli/src/render/index.ts +14 -14
- package/packages/cli/src/render/reconciler.ts +222 -190
- package/packages/cli/src/render/vars.ts +23 -22
- package/packages/plugin/dist/main.js +168 -55
- package/packages/plugin/dist/ui.html +23 -18
- package/packages/plugin/dist/ui.js +44 -43
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Figma Variable Bindings (StyleX-inspired API)
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* @example
|
|
5
5
|
* ```tsx
|
|
6
6
|
* // tokens.figma.ts - with explicit values (recommended)
|
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
* primary: { name: 'Colors/Gray/50', value: '#F8FAFC' },
|
|
9
9
|
* accent: { name: 'Colors/Blue/500', value: '#3B82F6' },
|
|
10
10
|
* })
|
|
11
|
-
*
|
|
11
|
+
*
|
|
12
12
|
* // tokens.figma.ts - name only (value loaded from Figma)
|
|
13
13
|
* export const colors = defineVars({
|
|
14
14
|
* primary: 'Colors/Gray/50',
|
|
15
15
|
* accent: 'Colors/Blue/500',
|
|
16
16
|
* })
|
|
17
|
-
*
|
|
17
|
+
*
|
|
18
18
|
* // Card.figma.tsx
|
|
19
19
|
* <Frame style={{ backgroundColor: colors.primary }}>
|
|
20
20
|
* ```
|
|
@@ -29,9 +29,10 @@ export type VarDef = string | { name: string; value: string }
|
|
|
29
29
|
|
|
30
30
|
export interface FigmaVariable {
|
|
31
31
|
[VAR_SYMBOL]: true
|
|
32
|
-
name: string
|
|
33
|
-
value?: string
|
|
34
|
-
_resolved?: {
|
|
32
|
+
name: string // Variable name like "Colors/Gray/50"
|
|
33
|
+
value?: string // Fallback color value like "#F8FAFC"
|
|
34
|
+
_resolved?: {
|
|
35
|
+
// Filled in at render time
|
|
35
36
|
id: string
|
|
36
37
|
sessionID: number
|
|
37
38
|
localID: number
|
|
@@ -68,7 +69,7 @@ export function loadVariablesIntoRegistry(variables: Array<{ id: string; name: s
|
|
|
68
69
|
variableRegistry.set(v.name, {
|
|
69
70
|
id: v.id,
|
|
70
71
|
sessionID: parseInt(match[1], 10),
|
|
71
|
-
localID: parseInt(match[2], 10)
|
|
72
|
+
localID: parseInt(match[2], 10)
|
|
72
73
|
})
|
|
73
74
|
}
|
|
74
75
|
}
|
|
@@ -83,30 +84,30 @@ export function resolveVariable(variable: FigmaVariable): ResolvedVariable {
|
|
|
83
84
|
if (variable._resolved) {
|
|
84
85
|
return variable._resolved
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
+
|
|
87
88
|
// Check if it's an ID format (legacy support)
|
|
88
89
|
const idMatch = variable.name.match(/^(?:VariableID:)?(\d+):(\d+)$/)
|
|
89
90
|
if (idMatch) {
|
|
90
91
|
const resolved = {
|
|
91
92
|
id: `VariableID:${idMatch[1]}:${idMatch[2]}`,
|
|
92
93
|
sessionID: parseInt(idMatch[1], 10),
|
|
93
|
-
localID: parseInt(idMatch[2], 10)
|
|
94
|
+
localID: parseInt(idMatch[2], 10)
|
|
94
95
|
}
|
|
95
96
|
variable._resolved = resolved
|
|
96
97
|
return resolved
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
+
|
|
99
100
|
// Lookup by name
|
|
100
101
|
const resolved = variableRegistry.get(variable.name)
|
|
101
102
|
if (!resolved) {
|
|
102
103
|
const available = Array.from(variableRegistry.keys()).slice(0, 5).join(', ')
|
|
103
104
|
throw new Error(
|
|
104
105
|
`Variable "${variable.name}" not found. ` +
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
`Available: ${available}${variableRegistry.size > 5 ? '...' : ''}. ` +
|
|
107
|
+
`Make sure variables are loaded before render.`
|
|
107
108
|
)
|
|
108
109
|
}
|
|
109
|
-
|
|
110
|
+
|
|
110
111
|
variable._resolved = resolved
|
|
111
112
|
return resolved
|
|
112
113
|
}
|
|
@@ -127,7 +128,7 @@ export function getRegistrySize(): number {
|
|
|
127
128
|
|
|
128
129
|
/**
|
|
129
130
|
* Define Figma variables for use in styles
|
|
130
|
-
*
|
|
131
|
+
*
|
|
131
132
|
* @example
|
|
132
133
|
* ```ts
|
|
133
134
|
* // With explicit fallback values (recommended)
|
|
@@ -135,12 +136,12 @@ export function getRegistrySize(): number {
|
|
|
135
136
|
* primary: { name: 'Colors/Gray/50', value: '#F8FAFC' },
|
|
136
137
|
* accent: { name: 'Colors/Blue/500', value: '#3B82F6' },
|
|
137
138
|
* })
|
|
138
|
-
*
|
|
139
|
+
*
|
|
139
140
|
* // Name only (value loaded from Figma registry)
|
|
140
141
|
* export const colors = defineVars({
|
|
141
142
|
* primary: 'Colors/Gray/50',
|
|
142
143
|
* })
|
|
143
|
-
*
|
|
144
|
+
*
|
|
144
145
|
* // Use in components:
|
|
145
146
|
* <Frame style={{ backgroundColor: colors.primary }} />
|
|
146
147
|
* ```
|
|
@@ -149,28 +150,28 @@ export function defineVars<T extends Record<string, VarDef>>(
|
|
|
149
150
|
vars: T
|
|
150
151
|
): { [K in keyof T]: FigmaVariable } {
|
|
151
152
|
const result = {} as { [K in keyof T]: FigmaVariable }
|
|
152
|
-
|
|
153
|
+
|
|
153
154
|
for (const [key, def] of Object.entries(vars)) {
|
|
154
155
|
if (typeof def === 'string') {
|
|
155
156
|
result[key as keyof T] = {
|
|
156
157
|
[VAR_SYMBOL]: true,
|
|
157
|
-
name: def
|
|
158
|
+
name: def
|
|
158
159
|
}
|
|
159
160
|
} else {
|
|
160
161
|
result[key as keyof T] = {
|
|
161
162
|
[VAR_SYMBOL]: true,
|
|
162
163
|
name: def.name,
|
|
163
|
-
value: def.value
|
|
164
|
+
value: def.value
|
|
164
165
|
}
|
|
165
166
|
}
|
|
166
167
|
}
|
|
167
|
-
|
|
168
|
+
|
|
168
169
|
return result
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
/**
|
|
172
173
|
* Shorthand for single variable
|
|
173
|
-
*
|
|
174
|
+
*
|
|
174
175
|
* @example
|
|
175
176
|
* ```ts
|
|
176
177
|
* const primaryColor = figmaVar('Colors/Gray/50', '#F8FAFC')
|
|
@@ -180,6 +181,6 @@ export function figmaVar(name: string, value?: string): FigmaVariable {
|
|
|
180
181
|
return {
|
|
181
182
|
[VAR_SYMBOL]: true,
|
|
182
183
|
name,
|
|
183
|
-
value
|
|
184
|
+
value
|
|
184
185
|
}
|
|
185
186
|
}
|
|
@@ -1372,7 +1372,11 @@
|
|
|
1372
1372
|
return serializeTreeNode(node);
|
|
1373
1373
|
}
|
|
1374
1374
|
case "get-all-components": {
|
|
1375
|
-
const {
|
|
1375
|
+
const {
|
|
1376
|
+
name,
|
|
1377
|
+
limit = 50,
|
|
1378
|
+
page
|
|
1379
|
+
} = args || {};
|
|
1376
1380
|
const components = [];
|
|
1377
1381
|
const nameLower = name == null ? void 0 : name.toLowerCase();
|
|
1378
1382
|
const searchNode = (node) => {
|
|
@@ -1389,7 +1393,9 @@
|
|
|
1389
1393
|
}
|
|
1390
1394
|
return components.length < limit;
|
|
1391
1395
|
};
|
|
1392
|
-
const pages = page ? figma.root.children.filter(
|
|
1396
|
+
const pages = page ? figma.root.children.filter(
|
|
1397
|
+
(p) => p.id === page || p.name === page || p.name.includes(page)
|
|
1398
|
+
) : figma.root.children;
|
|
1393
1399
|
for (const pageNode of pages) {
|
|
1394
1400
|
if (components.length >= limit) break;
|
|
1395
1401
|
for (const child of pageNode.children) {
|
|
@@ -1450,7 +1456,10 @@
|
|
|
1450
1456
|
result.effectStyles = styles.map((s) => ({
|
|
1451
1457
|
id: s.id,
|
|
1452
1458
|
name: s.name,
|
|
1453
|
-
effects: s.effects.map((e) => ({
|
|
1459
|
+
effects: s.effects.map((e) => ({
|
|
1460
|
+
type: e.type,
|
|
1461
|
+
radius: "radius" in e ? e.radius : void 0
|
|
1462
|
+
}))
|
|
1454
1463
|
}));
|
|
1455
1464
|
}
|
|
1456
1465
|
}
|
|
@@ -1547,7 +1556,22 @@
|
|
|
1547
1556
|
}
|
|
1548
1557
|
// ==================== CREATE CONTAINERS ====================
|
|
1549
1558
|
case "create-frame": {
|
|
1550
|
-
const {
|
|
1559
|
+
const {
|
|
1560
|
+
x,
|
|
1561
|
+
y,
|
|
1562
|
+
width,
|
|
1563
|
+
height,
|
|
1564
|
+
name,
|
|
1565
|
+
parentId,
|
|
1566
|
+
fill,
|
|
1567
|
+
stroke,
|
|
1568
|
+
strokeWeight,
|
|
1569
|
+
radius,
|
|
1570
|
+
opacity,
|
|
1571
|
+
layoutMode,
|
|
1572
|
+
itemSpacing,
|
|
1573
|
+
padding
|
|
1574
|
+
} = args;
|
|
1551
1575
|
const frame = figma.createFrame();
|
|
1552
1576
|
frame.x = x;
|
|
1553
1577
|
frame.y = y;
|
|
@@ -1655,22 +1679,26 @@
|
|
|
1655
1679
|
style.name = name;
|
|
1656
1680
|
const rgba = color ? hexToRgba(color) : { r: 0, g: 0, b: 0, a: 0.25 };
|
|
1657
1681
|
if (type === "DROP_SHADOW" || type === "INNER_SHADOW") {
|
|
1658
|
-
style.effects = [
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1682
|
+
style.effects = [
|
|
1683
|
+
{
|
|
1684
|
+
type,
|
|
1685
|
+
color: rgba,
|
|
1686
|
+
offset: { x: offsetX || 0, y: offsetY || 4 },
|
|
1687
|
+
radius: radius || 10,
|
|
1688
|
+
spread: 0,
|
|
1689
|
+
visible: true,
|
|
1690
|
+
blendMode: "NORMAL"
|
|
1691
|
+
}
|
|
1692
|
+
];
|
|
1667
1693
|
} else if (type === "BLUR" || type === "BACKGROUND_BLUR") {
|
|
1668
|
-
style.effects = [
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1694
|
+
style.effects = [
|
|
1695
|
+
{
|
|
1696
|
+
type,
|
|
1697
|
+
blurType: "NORMAL",
|
|
1698
|
+
radius: radius || 10,
|
|
1699
|
+
visible: true
|
|
1700
|
+
}
|
|
1701
|
+
];
|
|
1674
1702
|
}
|
|
1675
1703
|
return { id: style.id, name: style.name, key: style.key };
|
|
1676
1704
|
}
|
|
@@ -1690,6 +1718,7 @@
|
|
|
1690
1718
|
if ("resize" in node) {
|
|
1691
1719
|
node.resize(width, height);
|
|
1692
1720
|
} else if ("width" in node && "height" in node) {
|
|
1721
|
+
;
|
|
1693
1722
|
node.resizeWithoutConstraints(width, height);
|
|
1694
1723
|
} else {
|
|
1695
1724
|
throw new Error("Node cannot be resized");
|
|
@@ -1710,11 +1739,19 @@
|
|
|
1710
1739
|
if (!node || !("strokes" in node)) throw new Error("Node not found");
|
|
1711
1740
|
node.strokes = [{ type: "SOLID", color: hexToRgb(color) }];
|
|
1712
1741
|
if (weight !== void 0 && "strokeWeight" in node) node.strokeWeight = weight;
|
|
1713
|
-
if (align && "strokeAlign" in node)
|
|
1742
|
+
if (align && "strokeAlign" in node)
|
|
1743
|
+
node.strokeAlign = align;
|
|
1714
1744
|
return serializeNode(node);
|
|
1715
1745
|
}
|
|
1716
1746
|
case "set-corner-radius": {
|
|
1717
|
-
const {
|
|
1747
|
+
const {
|
|
1748
|
+
id,
|
|
1749
|
+
cornerRadius,
|
|
1750
|
+
topLeftRadius,
|
|
1751
|
+
topRightRadius,
|
|
1752
|
+
bottomLeftRadius,
|
|
1753
|
+
bottomRightRadius
|
|
1754
|
+
} = args;
|
|
1718
1755
|
const node = yield figma.getNodeByIdAsync(id);
|
|
1719
1756
|
if (!node || !("cornerRadius" in node)) throw new Error("Node not found");
|
|
1720
1757
|
node.cornerRadius = cornerRadius;
|
|
@@ -1736,11 +1773,13 @@
|
|
|
1736
1773
|
const node = yield figma.getNodeByIdAsync(id);
|
|
1737
1774
|
if (!node || !("fills" in node)) throw new Error("Node not found");
|
|
1738
1775
|
const image = yield figma.createImageAsync(url);
|
|
1739
|
-
node.fills = [
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1776
|
+
node.fills = [
|
|
1777
|
+
{
|
|
1778
|
+
type: "IMAGE",
|
|
1779
|
+
imageHash: image.hash,
|
|
1780
|
+
scaleMode: scaleMode || "FILL"
|
|
1781
|
+
}
|
|
1782
|
+
];
|
|
1744
1783
|
return serializeNode(node);
|
|
1745
1784
|
}
|
|
1746
1785
|
// ==================== UPDATE PROPERTIES ====================
|
|
@@ -1771,22 +1810,26 @@
|
|
|
1771
1810
|
if (!node || !("effects" in node)) throw new Error("Node not found");
|
|
1772
1811
|
const rgba = color ? hexToRgba(color) : { r: 0, g: 0, b: 0, a: 0.25 };
|
|
1773
1812
|
if (type === "DROP_SHADOW" || type === "INNER_SHADOW") {
|
|
1774
|
-
node.effects = [
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1813
|
+
node.effects = [
|
|
1814
|
+
{
|
|
1815
|
+
type,
|
|
1816
|
+
color: rgba,
|
|
1817
|
+
offset: { x: offsetX != null ? offsetX : 0, y: offsetY != null ? offsetY : 4 },
|
|
1818
|
+
radius: radius != null ? radius : 8,
|
|
1819
|
+
spread: spread != null ? spread : 0,
|
|
1820
|
+
visible: true,
|
|
1821
|
+
blendMode: "NORMAL"
|
|
1822
|
+
}
|
|
1823
|
+
];
|
|
1783
1824
|
} else if (type === "BLUR") {
|
|
1784
|
-
node.effects = [
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1825
|
+
node.effects = [
|
|
1826
|
+
{
|
|
1827
|
+
type: "LAYER_BLUR",
|
|
1828
|
+
blurType: "NORMAL",
|
|
1829
|
+
radius: radius != null ? radius : 8,
|
|
1830
|
+
visible: true
|
|
1831
|
+
}
|
|
1832
|
+
];
|
|
1790
1833
|
}
|
|
1791
1834
|
return serializeNode(node);
|
|
1792
1835
|
}
|
|
@@ -1856,7 +1899,12 @@
|
|
|
1856
1899
|
return node.children.map((c) => serializeWithDepth(c, 1));
|
|
1857
1900
|
}
|
|
1858
1901
|
case "find-by-name": {
|
|
1859
|
-
const {
|
|
1902
|
+
const {
|
|
1903
|
+
name,
|
|
1904
|
+
type,
|
|
1905
|
+
exact,
|
|
1906
|
+
limit = 100
|
|
1907
|
+
} = args;
|
|
1860
1908
|
const results = [];
|
|
1861
1909
|
const nameLower = name == null ? void 0 : name.toLowerCase();
|
|
1862
1910
|
const searchNode = (node) => {
|
|
@@ -1901,7 +1949,18 @@
|
|
|
1901
1949
|
return serializeNode(node);
|
|
1902
1950
|
}
|
|
1903
1951
|
case "set-auto-layout": {
|
|
1904
|
-
const {
|
|
1952
|
+
const {
|
|
1953
|
+
id,
|
|
1954
|
+
mode,
|
|
1955
|
+
wrap,
|
|
1956
|
+
itemSpacing,
|
|
1957
|
+
counterSpacing,
|
|
1958
|
+
padding,
|
|
1959
|
+
primaryAlign,
|
|
1960
|
+
counterAlign,
|
|
1961
|
+
sizingH,
|
|
1962
|
+
sizingV
|
|
1963
|
+
} = args;
|
|
1905
1964
|
const node = yield figma.getNodeByIdAsync(id);
|
|
1906
1965
|
if (!node || !("layoutMode" in node)) throw new Error("Frame not found");
|
|
1907
1966
|
if (mode) node.layoutMode = mode;
|
|
@@ -1925,12 +1984,15 @@
|
|
|
1925
1984
|
const node = yield figma.getNodeByIdAsync(id);
|
|
1926
1985
|
if (!node) throw new Error("Node not found");
|
|
1927
1986
|
if (horizontalSizing && "layoutSizingHorizontal" in node) {
|
|
1987
|
+
;
|
|
1928
1988
|
node.layoutSizingHorizontal = horizontalSizing;
|
|
1929
1989
|
}
|
|
1930
1990
|
if (verticalSizing && "layoutSizingVertical" in node) {
|
|
1991
|
+
;
|
|
1931
1992
|
node.layoutSizingVertical = verticalSizing;
|
|
1932
1993
|
}
|
|
1933
1994
|
if (positioning && "layoutPositioning" in node) {
|
|
1995
|
+
;
|
|
1934
1996
|
node.layoutPositioning = positioning;
|
|
1935
1997
|
}
|
|
1936
1998
|
if (positioning === "ABSOLUTE") {
|
|
@@ -1940,7 +2002,17 @@
|
|
|
1940
2002
|
return serializeNode(node);
|
|
1941
2003
|
}
|
|
1942
2004
|
case "set-text-properties": {
|
|
1943
|
-
const {
|
|
2005
|
+
const {
|
|
2006
|
+
id,
|
|
2007
|
+
lineHeight,
|
|
2008
|
+
letterSpacing,
|
|
2009
|
+
textAlign,
|
|
2010
|
+
verticalAlign,
|
|
2011
|
+
autoResize,
|
|
2012
|
+
maxLines,
|
|
2013
|
+
paragraphSpacing,
|
|
2014
|
+
paragraphIndent
|
|
2015
|
+
} = args;
|
|
1944
2016
|
const node = yield figma.getNodeByIdAsync(id);
|
|
1945
2017
|
if (!node || node.type !== "TEXT") throw new Error("Text node not found");
|
|
1946
2018
|
const fontName = node.fontName;
|
|
@@ -2114,7 +2186,8 @@
|
|
|
2114
2186
|
if (!propKey) throw new Error("Property not found");
|
|
2115
2187
|
const propDef = props[propKey];
|
|
2116
2188
|
let parsedDefault = defaultValue;
|
|
2117
|
-
if (propDef.type === "BOOLEAN")
|
|
2189
|
+
if (propDef.type === "BOOLEAN")
|
|
2190
|
+
parsedDefault = defaultValue === "true" || defaultValue === true;
|
|
2118
2191
|
component.editComponentProperty(propKey, {
|
|
2119
2192
|
name,
|
|
2120
2193
|
defaultValue: parsedDefault,
|
|
@@ -2195,7 +2268,10 @@
|
|
|
2195
2268
|
}
|
|
2196
2269
|
}
|
|
2197
2270
|
}
|
|
2198
|
-
const bytes = yield frame.exportAsync({
|
|
2271
|
+
const bytes = yield frame.exportAsync({
|
|
2272
|
+
format: "PNG",
|
|
2273
|
+
constraint: { type: "SCALE", value: scale || 1 }
|
|
2274
|
+
});
|
|
2199
2275
|
frame.remove();
|
|
2200
2276
|
return { data: figma.base64Encode(bytes) };
|
|
2201
2277
|
}
|
|
@@ -2272,7 +2348,11 @@
|
|
|
2272
2348
|
return { paths: node.vectorPaths };
|
|
2273
2349
|
}
|
|
2274
2350
|
case "path-set": {
|
|
2275
|
-
const {
|
|
2351
|
+
const {
|
|
2352
|
+
id,
|
|
2353
|
+
path,
|
|
2354
|
+
windingRule = "NONZERO"
|
|
2355
|
+
} = args;
|
|
2276
2356
|
const node = yield figma.getNodeByIdAsync(id);
|
|
2277
2357
|
if (!node || node.type !== "VECTOR") throw new Error("Vector node not found");
|
|
2278
2358
|
node.vectorPaths = [{ windingRule, data: path }];
|
|
@@ -2358,6 +2438,7 @@
|
|
|
2358
2438
|
const parentId = `${pending.parentGUID.sessionID}:${pending.parentGUID.localID}`;
|
|
2359
2439
|
const parent = yield figma.getNodeByIdAsync(parentId);
|
|
2360
2440
|
if (parent && "appendChild" in parent) {
|
|
2441
|
+
;
|
|
2361
2442
|
parent.appendChild(instance);
|
|
2362
2443
|
}
|
|
2363
2444
|
}
|
|
@@ -2399,7 +2480,9 @@
|
|
|
2399
2480
|
// ==================== VARIABLES ====================
|
|
2400
2481
|
case "get-variables": {
|
|
2401
2482
|
const { type, simple } = args;
|
|
2402
|
-
const variables = yield figma.variables.getLocalVariablesAsync(
|
|
2483
|
+
const variables = yield figma.variables.getLocalVariablesAsync(
|
|
2484
|
+
type
|
|
2485
|
+
);
|
|
2403
2486
|
if (simple) {
|
|
2404
2487
|
return variables.map((v) => ({ id: v.id, name: v.name }));
|
|
2405
2488
|
}
|
|
@@ -2415,7 +2498,11 @@
|
|
|
2415
2498
|
const { name, collectionId, type, value } = args;
|
|
2416
2499
|
const collection = yield figma.variables.getVariableCollectionByIdAsync(collectionId);
|
|
2417
2500
|
if (!collection) throw new Error("Collection not found");
|
|
2418
|
-
const variable = figma.variables.createVariable(
|
|
2501
|
+
const variable = figma.variables.createVariable(
|
|
2502
|
+
name,
|
|
2503
|
+
collection,
|
|
2504
|
+
type
|
|
2505
|
+
);
|
|
2419
2506
|
if (value !== void 0 && collection.modes.length > 0) {
|
|
2420
2507
|
const modeId = collection.modes[0].modeId;
|
|
2421
2508
|
variable.setValueForMode(modeId, parseVariableValue(value, type));
|
|
@@ -2443,6 +2530,7 @@
|
|
|
2443
2530
|
const variable = yield figma.variables.getVariableByIdAsync(variableId);
|
|
2444
2531
|
if (!variable) throw new Error("Variable not found");
|
|
2445
2532
|
if ("setBoundVariable" in node) {
|
|
2533
|
+
;
|
|
2446
2534
|
node.setBoundVariable(field, variable);
|
|
2447
2535
|
} else {
|
|
2448
2536
|
throw new Error("Node does not support variable binding");
|
|
@@ -2450,7 +2538,11 @@
|
|
|
2450
2538
|
return serializeNode(node);
|
|
2451
2539
|
}
|
|
2452
2540
|
case "bind-fill-variable": {
|
|
2453
|
-
const {
|
|
2541
|
+
const {
|
|
2542
|
+
nodeId,
|
|
2543
|
+
variableId,
|
|
2544
|
+
paintIndex = 0
|
|
2545
|
+
} = args;
|
|
2454
2546
|
const node = yield figma.getNodeByIdAsync(nodeId);
|
|
2455
2547
|
if (!node) throw new Error("Node not found");
|
|
2456
2548
|
if (!("fills" in node)) throw new Error("Node does not have fills");
|
|
@@ -2459,11 +2551,19 @@
|
|
|
2459
2551
|
const fills = node.fills;
|
|
2460
2552
|
if (!fills[paintIndex]) throw new Error("Paint not found at index " + paintIndex);
|
|
2461
2553
|
const newFill = figma.variables.setBoundVariableForPaint(fills[paintIndex], "color", variable);
|
|
2462
|
-
node.fills = [
|
|
2554
|
+
node.fills = [
|
|
2555
|
+
...fills.slice(0, paintIndex),
|
|
2556
|
+
newFill,
|
|
2557
|
+
...fills.slice(paintIndex + 1)
|
|
2558
|
+
];
|
|
2463
2559
|
return serializeNode(node);
|
|
2464
2560
|
}
|
|
2465
2561
|
case "bind-stroke-variable": {
|
|
2466
|
-
const {
|
|
2562
|
+
const {
|
|
2563
|
+
nodeId,
|
|
2564
|
+
variableId,
|
|
2565
|
+
paintIndex = 0
|
|
2566
|
+
} = args;
|
|
2467
2567
|
const node = yield figma.getNodeByIdAsync(nodeId);
|
|
2468
2568
|
if (!node) throw new Error("Node not found");
|
|
2469
2569
|
if (!("strokes" in node)) throw new Error("Node does not have strokes");
|
|
@@ -2471,8 +2571,16 @@
|
|
|
2471
2571
|
if (!variable) throw new Error("Variable not found");
|
|
2472
2572
|
const strokes = node.strokes;
|
|
2473
2573
|
if (!strokes[paintIndex]) throw new Error("Paint not found at index " + paintIndex);
|
|
2474
|
-
const newStroke = figma.variables.setBoundVariableForPaint(
|
|
2475
|
-
|
|
2574
|
+
const newStroke = figma.variables.setBoundVariableForPaint(
|
|
2575
|
+
strokes[paintIndex],
|
|
2576
|
+
"color",
|
|
2577
|
+
variable
|
|
2578
|
+
);
|
|
2579
|
+
node.strokes = [
|
|
2580
|
+
...strokes.slice(0, paintIndex),
|
|
2581
|
+
newStroke,
|
|
2582
|
+
...strokes.slice(paintIndex + 1)
|
|
2583
|
+
];
|
|
2476
2584
|
return serializeNode(node);
|
|
2477
2585
|
}
|
|
2478
2586
|
// ==================== VARIABLE COLLECTIONS ====================
|
|
@@ -2556,7 +2664,12 @@
|
|
|
2556
2664
|
base.layoutMode = node.layoutMode;
|
|
2557
2665
|
if ("itemSpacing" in node) base.itemSpacing = node.itemSpacing;
|
|
2558
2666
|
if ("paddingLeft" in node && (node.paddingLeft || node.paddingRight || node.paddingTop || node.paddingBottom)) {
|
|
2559
|
-
base.padding = {
|
|
2667
|
+
base.padding = {
|
|
2668
|
+
left: node.paddingLeft,
|
|
2669
|
+
right: node.paddingRight,
|
|
2670
|
+
top: node.paddingTop,
|
|
2671
|
+
bottom: node.paddingBottom
|
|
2672
|
+
};
|
|
2560
2673
|
}
|
|
2561
2674
|
}
|
|
2562
2675
|
if (node.type === "TEXT") {
|
|
@@ -1,21 +1,26 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html>
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
3
|
+
<head>
|
|
4
|
+
<style>
|
|
5
|
+
body {
|
|
6
|
+
font-family: Inter, system-ui, sans-serif;
|
|
7
|
+
font-size: 12px;
|
|
8
|
+
padding: 16px;
|
|
9
|
+
margin: 0;
|
|
10
|
+
}
|
|
11
|
+
h1 {
|
|
12
|
+
font-size: 14px;
|
|
13
|
+
margin: 0 0 16px;
|
|
14
|
+
}
|
|
15
|
+
#status {
|
|
16
|
+
font-weight: 500;
|
|
17
|
+
}
|
|
18
|
+
</style>
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<h1>Figma Bridge</h1>
|
|
22
|
+
<p id="status">○ Connecting...</p>
|
|
23
|
+
<script>"use strict";
|
|
19
24
|
(() => {
|
|
20
25
|
var __defProp = Object.defineProperty;
|
|
21
26
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
@@ -74,5 +79,5 @@
|
|
|
74
79
|
});
|
|
75
80
|
})();
|
|
76
81
|
</script>
|
|
77
|
-
</body>
|
|
82
|
+
</body>
|
|
78
83
|
</html>
|