@wz927/codedesign 0.3.6 → 0.3.8
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/dist/main.js +1 -1
- package/figma-plugin/dist/code.js +85 -43
- package/package.json +1 -1
|
@@ -8,11 +8,53 @@
|
|
|
8
8
|
* Incoming messages from CLI (via UI): { id, op, params }
|
|
9
9
|
* Outgoing responses to CLI (via UI): { id, ok, data?, error? }
|
|
10
10
|
*/
|
|
11
|
-
const PLUGIN_VERSION = '0.
|
|
11
|
+
const PLUGIN_VERSION = '0.2.0';
|
|
12
12
|
figma.showUI(__html__, { width: 360, height: 360, themeColors: true });
|
|
13
13
|
function send(msg) {
|
|
14
14
|
figma.ui.postMessage({ __kind: 'to_cli', msg });
|
|
15
15
|
}
|
|
16
|
+
// ─── Async API compatibility ─────────────────────────────────────────────
|
|
17
|
+
// Figma made many sync APIs deprecated in 2024 (dynamic-page mode throws on
|
|
18
|
+
// them). Prefer async versions; fall back to sync for older Figma builds.
|
|
19
|
+
async function getNode(id) {
|
|
20
|
+
const anyFigma = figma;
|
|
21
|
+
if (typeof anyFigma.getNodeByIdAsync === 'function') {
|
|
22
|
+
return await anyFigma.getNodeByIdAsync(id);
|
|
23
|
+
}
|
|
24
|
+
return figma.getNodeById(id);
|
|
25
|
+
}
|
|
26
|
+
async function getLocalPaint() {
|
|
27
|
+
const anyFigma = figma;
|
|
28
|
+
if (typeof anyFigma.getLocalPaintStylesAsync === 'function') {
|
|
29
|
+
return await anyFigma.getLocalPaintStylesAsync();
|
|
30
|
+
}
|
|
31
|
+
return figma.getLocalPaintStyles();
|
|
32
|
+
}
|
|
33
|
+
async function getLocalText() {
|
|
34
|
+
const anyFigma = figma;
|
|
35
|
+
if (typeof anyFigma.getLocalTextStylesAsync === 'function') {
|
|
36
|
+
return await anyFigma.getLocalTextStylesAsync();
|
|
37
|
+
}
|
|
38
|
+
return figma.getLocalTextStyles();
|
|
39
|
+
}
|
|
40
|
+
async function getLocalEffect() {
|
|
41
|
+
const anyFigma = figma;
|
|
42
|
+
if (typeof anyFigma.getLocalEffectStylesAsync === 'function') {
|
|
43
|
+
return await anyFigma.getLocalEffectStylesAsync();
|
|
44
|
+
}
|
|
45
|
+
return figma.getLocalEffectStyles();
|
|
46
|
+
}
|
|
47
|
+
async function findAllComponents(types) {
|
|
48
|
+
const anyFigma = figma;
|
|
49
|
+
// dynamic-page mode requires loading all pages before findAll-style queries
|
|
50
|
+
if (typeof anyFigma.loadAllPagesAsync === 'function') {
|
|
51
|
+
try {
|
|
52
|
+
await anyFigma.loadAllPagesAsync();
|
|
53
|
+
}
|
|
54
|
+
catch { }
|
|
55
|
+
}
|
|
56
|
+
return figma.root.findAllWithCriteria({ types: types });
|
|
57
|
+
}
|
|
16
58
|
async function sendHello() {
|
|
17
59
|
var _a;
|
|
18
60
|
const page = figma.currentPage;
|
|
@@ -75,10 +117,10 @@ function toPaint(p) {
|
|
|
75
117
|
}
|
|
76
118
|
throw new Error('Unsupported paint type ' + p.type);
|
|
77
119
|
}
|
|
78
|
-
function getParent(id) {
|
|
120
|
+
async function getParent(id) {
|
|
79
121
|
if (!id)
|
|
80
122
|
return figma.currentPage;
|
|
81
|
-
const n =
|
|
123
|
+
const n = await getNode(id);
|
|
82
124
|
if (!n)
|
|
83
125
|
throw new Error('Parent not found: ' + id);
|
|
84
126
|
if (!('appendChild' in n))
|
|
@@ -152,7 +194,7 @@ async function handle(req) {
|
|
|
152
194
|
case 'getSelection':
|
|
153
195
|
return figma.currentPage.selection.map(nodeSummary);
|
|
154
196
|
case 'getNode': {
|
|
155
|
-
const n =
|
|
197
|
+
const n = await getNode(p.id);
|
|
156
198
|
if (!n)
|
|
157
199
|
throw new Error('Not found: ' + p.id);
|
|
158
200
|
const base = nodeSummary(n);
|
|
@@ -166,14 +208,14 @@ async function handle(req) {
|
|
|
166
208
|
}
|
|
167
209
|
case 'createFrame': {
|
|
168
210
|
const frame = figma.createFrame();
|
|
169
|
-
getParent(p.parentId).appendChild(frame);
|
|
211
|
+
(await getParent(p.parentId)).appendChild(frame);
|
|
170
212
|
applyFrameProps(frame, p);
|
|
171
213
|
return nodeSummary(frame);
|
|
172
214
|
}
|
|
173
215
|
case 'createText': {
|
|
174
216
|
const font = await loadFontFor(p);
|
|
175
217
|
const t = figma.createText();
|
|
176
|
-
getParent(p.parentId).appendChild(t);
|
|
218
|
+
(await getParent(p.parentId)).appendChild(t);
|
|
177
219
|
t.fontName = { family: font.family, style: font.style };
|
|
178
220
|
t.characters = (_b = p.characters) !== null && _b !== void 0 ? _b : '';
|
|
179
221
|
if (typeof p.x === 'number')
|
|
@@ -200,7 +242,7 @@ async function handle(req) {
|
|
|
200
242
|
}
|
|
201
243
|
case 'createRectangle': {
|
|
202
244
|
const r = figma.createRectangle();
|
|
203
|
-
getParent(p.parentId).appendChild(r);
|
|
245
|
+
(await getParent(p.parentId)).appendChild(r);
|
|
204
246
|
if (typeof p.x === 'number')
|
|
205
247
|
r.x = p.x;
|
|
206
248
|
if (typeof p.y === 'number')
|
|
@@ -220,7 +262,7 @@ async function handle(req) {
|
|
|
220
262
|
}
|
|
221
263
|
case 'createEllipse': {
|
|
222
264
|
const e = figma.createEllipse();
|
|
223
|
-
getParent(p.parentId).appendChild(e);
|
|
265
|
+
(await getParent(p.parentId)).appendChild(e);
|
|
224
266
|
if (typeof p.x === 'number')
|
|
225
267
|
e.x = p.x;
|
|
226
268
|
if (typeof p.y === 'number')
|
|
@@ -237,7 +279,7 @@ async function handle(req) {
|
|
|
237
279
|
return nodeSummary(e);
|
|
238
280
|
}
|
|
239
281
|
case 'setProps': {
|
|
240
|
-
const n =
|
|
282
|
+
const n = (await getNode(p.id));
|
|
241
283
|
if (!n)
|
|
242
284
|
throw new Error('Not found: ' + p.id);
|
|
243
285
|
const patch = (_c = p.patch) !== null && _c !== void 0 ? _c : {};
|
|
@@ -254,7 +296,6 @@ async function handle(req) {
|
|
|
254
296
|
if (patch[k] !== undefined)
|
|
255
297
|
n[k] = patch[k];
|
|
256
298
|
}
|
|
257
|
-
// cornerRadius: number → uniform; [tl,tr,br,bl] → per-corner
|
|
258
299
|
if (patch.cornerRadius !== undefined) {
|
|
259
300
|
const cr = patch.cornerRadius;
|
|
260
301
|
if (typeof cr === 'number') {
|
|
@@ -267,7 +308,6 @@ async function handle(req) {
|
|
|
267
308
|
n.bottomLeftRadius = cr[3];
|
|
268
309
|
}
|
|
269
310
|
}
|
|
270
|
-
// Also support explicit per-corner keys
|
|
271
311
|
if (patch.topLeftRadius !== undefined)
|
|
272
312
|
n.topLeftRadius = patch.topLeftRadius;
|
|
273
313
|
if (patch.topRightRadius !== undefined)
|
|
@@ -283,7 +323,7 @@ async function handle(req) {
|
|
|
283
323
|
return nodeSummary(n);
|
|
284
324
|
}
|
|
285
325
|
case 'setAutoLayout': {
|
|
286
|
-
const n =
|
|
326
|
+
const n = (await getNode(p.id));
|
|
287
327
|
if (!n)
|
|
288
328
|
throw new Error('Not found: ' + p.id);
|
|
289
329
|
n.layoutMode = p.layoutMode;
|
|
@@ -302,27 +342,27 @@ async function handle(req) {
|
|
|
302
342
|
return nodeSummary(n);
|
|
303
343
|
}
|
|
304
344
|
case 'appendChild': {
|
|
305
|
-
const par = getParent(p.parentId);
|
|
306
|
-
const child =
|
|
345
|
+
const par = await getParent(p.parentId);
|
|
346
|
+
const child = (await getNode(p.childId));
|
|
307
347
|
if (!child)
|
|
308
348
|
throw new Error('Child not found');
|
|
309
349
|
par.appendChild(child);
|
|
310
350
|
return nodeSummary(child);
|
|
311
351
|
}
|
|
312
352
|
case 'deleteNode': {
|
|
313
|
-
const n =
|
|
353
|
+
const n = await getNode(p.id);
|
|
314
354
|
if (!n)
|
|
315
355
|
throw new Error('Not found');
|
|
316
356
|
n.remove();
|
|
317
357
|
return { deleted: p.id };
|
|
318
358
|
}
|
|
319
359
|
case 'cloneNode': {
|
|
320
|
-
const n =
|
|
360
|
+
const n = (await getNode(p.id));
|
|
321
361
|
if (!n || !('clone' in n))
|
|
322
362
|
throw new Error('Cannot clone');
|
|
323
363
|
const c = n.clone();
|
|
324
364
|
if (p.parentId)
|
|
325
|
-
getParent(p.parentId).appendChild(c);
|
|
365
|
+
(await getParent(p.parentId)).appendChild(c);
|
|
326
366
|
else
|
|
327
367
|
(_f = n.parent) === null || _f === void 0 ? void 0 : _f.appendChild(c);
|
|
328
368
|
if (typeof p.dx === 'number')
|
|
@@ -331,20 +371,21 @@ async function handle(req) {
|
|
|
331
371
|
c.y += p.dy;
|
|
332
372
|
return nodeSummary(c);
|
|
333
373
|
}
|
|
334
|
-
case 'listStyles':
|
|
374
|
+
case 'listStyles': {
|
|
375
|
+
const [paint, text, effect] = await Promise.all([getLocalPaint(), getLocalText(), getLocalEffect()]);
|
|
335
376
|
return {
|
|
336
|
-
paint:
|
|
337
|
-
text:
|
|
338
|
-
effect:
|
|
377
|
+
paint: paint.map((s) => ({ id: s.id, key: s.key, name: s.name })),
|
|
378
|
+
text: text.map((s) => ({ id: s.id, key: s.key, name: s.name })),
|
|
379
|
+
effect: effect.map((s) => ({ id: s.id, key: s.key, name: s.name })),
|
|
339
380
|
};
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}));
|
|
381
|
+
}
|
|
382
|
+
case 'listComponents': {
|
|
383
|
+
const comps = await findAllComponents(['COMPONENT', 'COMPONENT_SET']);
|
|
384
|
+
return comps.map((c) => ({ id: c.id, key: c.key, name: c.name, type: c.type }));
|
|
385
|
+
}
|
|
344
386
|
case 'createInstance': {
|
|
345
|
-
const all =
|
|
387
|
+
const all = (await findAllComponents(['COMPONENT']));
|
|
346
388
|
let comp = all.find((c) => c.key === p.componentKey || c.id === p.componentKey);
|
|
347
|
-
// If not found locally, try to import from a team library by component key.
|
|
348
389
|
if (!comp && p.componentKey) {
|
|
349
390
|
try {
|
|
350
391
|
comp = await figma.importComponentByKeyAsync(p.componentKey);
|
|
@@ -354,7 +395,7 @@ async function handle(req) {
|
|
|
354
395
|
if (!comp)
|
|
355
396
|
throw new Error('Component not found: ' + p.componentKey);
|
|
356
397
|
const inst = comp.createInstance();
|
|
357
|
-
getParent(p.parentId).appendChild(inst);
|
|
398
|
+
(await getParent(p.parentId)).appendChild(inst);
|
|
358
399
|
if (typeof p.x === 'number')
|
|
359
400
|
inst.x = p.x;
|
|
360
401
|
if (typeof p.y === 'number')
|
|
@@ -364,10 +405,8 @@ async function handle(req) {
|
|
|
364
405
|
return nodeSummary(inst);
|
|
365
406
|
}
|
|
366
407
|
case 'createVector': {
|
|
367
|
-
// Draw an icon/shape using SVG path data.
|
|
368
|
-
// params: { parentId?, vectorPaths: [{windingRule, data}], fills, strokes, strokeWeight, x, y, width, height, name }
|
|
369
408
|
const vec = figma.createVector();
|
|
370
|
-
getParent(p.parentId).appendChild(vec);
|
|
409
|
+
(await getParent(p.parentId)).appendChild(vec);
|
|
371
410
|
if (p.vectorPaths)
|
|
372
411
|
vec.vectorPaths = p.vectorPaths;
|
|
373
412
|
if (p.fills)
|
|
@@ -387,10 +426,8 @@ async function handle(req) {
|
|
|
387
426
|
return nodeSummary(vec);
|
|
388
427
|
}
|
|
389
428
|
case 'createLine': {
|
|
390
|
-
// A simple line / divider.
|
|
391
|
-
// params: { parentId?, x, y, length, vertical?, strokeWeight, color:{r,g,b}, name }
|
|
392
429
|
const line = figma.createLine();
|
|
393
|
-
getParent(p.parentId).appendChild(line);
|
|
430
|
+
(await getParent(p.parentId)).appendChild(line);
|
|
394
431
|
if (typeof p.x === 'number')
|
|
395
432
|
line.x = p.x;
|
|
396
433
|
if (typeof p.y === 'number')
|
|
@@ -406,23 +443,28 @@ async function handle(req) {
|
|
|
406
443
|
return nodeSummary(line);
|
|
407
444
|
}
|
|
408
445
|
case 'applyStyle': {
|
|
409
|
-
|
|
410
|
-
// params: { id, fillStyleId?, strokeStyleId?, textStyleId?, effectStyleId? }
|
|
411
|
-
const n = figma.getNodeById(p.id);
|
|
446
|
+
const n = (await getNode(p.id));
|
|
412
447
|
if (!n)
|
|
413
448
|
throw new Error('Not found: ' + p.id);
|
|
449
|
+
// In dynamic-page mode, style setters are async (setFillStyleIdAsync etc.)
|
|
450
|
+
async function setStyle(prop, async, val) {
|
|
451
|
+
if (typeof n[async] === 'function')
|
|
452
|
+
await n[async](val);
|
|
453
|
+
else
|
|
454
|
+
n[prop] = val;
|
|
455
|
+
}
|
|
414
456
|
if (p.fillStyleId !== undefined)
|
|
415
|
-
|
|
457
|
+
await setStyle('fillStyleId', 'setFillStyleIdAsync', p.fillStyleId);
|
|
416
458
|
if (p.strokeStyleId !== undefined)
|
|
417
|
-
|
|
459
|
+
await setStyle('strokeStyleId', 'setStrokeStyleIdAsync', p.strokeStyleId);
|
|
418
460
|
if (p.textStyleId !== undefined)
|
|
419
|
-
|
|
461
|
+
await setStyle('textStyleId', 'setTextStyleIdAsync', p.textStyleId);
|
|
420
462
|
if (p.effectStyleId !== undefined)
|
|
421
|
-
|
|
463
|
+
await setStyle('effectStyleId', 'setEffectStyleIdAsync', p.effectStyleId);
|
|
422
464
|
return nodeSummary(n);
|
|
423
465
|
}
|
|
424
466
|
case 'viewport': {
|
|
425
|
-
const n =
|
|
467
|
+
const n = (await getNode(p.id));
|
|
426
468
|
if (!n)
|
|
427
469
|
throw new Error('Not found');
|
|
428
470
|
figma.viewport.scrollAndZoomIntoView([n]);
|
|
@@ -431,7 +473,7 @@ async function handle(req) {
|
|
|
431
473
|
return { ok: true };
|
|
432
474
|
}
|
|
433
475
|
case 'exportNode': {
|
|
434
|
-
const n =
|
|
476
|
+
const n = (await getNode(p.id));
|
|
435
477
|
if (!n || !('exportAsync' in n))
|
|
436
478
|
throw new Error('Node not exportable');
|
|
437
479
|
const format = ((_j = p.format) !== null && _j !== void 0 ? _j : 'PNG').toUpperCase();
|