@sangheepark/figma-ds-mcp 0.2.7 → 0.2.9
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/tools/pipeline-tools.js +47 -5
- package/package.json +1 -1
|
@@ -233,19 +233,32 @@ function enrichSpec(traversal, mapping) {
|
|
|
233
233
|
if (typeof lh === 'number') {
|
|
234
234
|
node.style['line-height'] = `${Math.round(lh * 100)}%`;
|
|
235
235
|
}
|
|
236
|
+
// opacity 정규화: string → number (V11 fix)
|
|
237
|
+
const op = node.style['opacity'];
|
|
238
|
+
if (typeof op === 'string') {
|
|
239
|
+
const parsed = parseFloat(op);
|
|
240
|
+
if (!isNaN(parsed)) {
|
|
241
|
+
node.style['opacity'] = parsed;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
236
244
|
}
|
|
237
245
|
// _ds_type 제거 (downstream 미소비 — build 전에 정리)
|
|
238
246
|
if ('_ds_type' in node) {
|
|
239
247
|
delete node['_ds_type'];
|
|
240
248
|
}
|
|
241
249
|
// Step 6: CSS → Figma 정규화
|
|
242
|
-
// 6-pre: overflow →
|
|
243
|
-
const
|
|
244
|
-
if (
|
|
250
|
+
// 6-pre: overflow → clip-content 변환 (style 또는 layout 어디에 있든 처리)
|
|
251
|
+
const styleOverflow = node.style && node.style['overflow'];
|
|
252
|
+
if (styleOverflow === 'hidden' || styleOverflow === 'scroll' || styleOverflow === 'auto') {
|
|
245
253
|
node.layout = node.layout || {};
|
|
246
254
|
node.layout['clip-content'] = true;
|
|
247
255
|
delete node.style['overflow'];
|
|
248
256
|
}
|
|
257
|
+
const layoutOverflow = node.layout && node.layout['overflow'];
|
|
258
|
+
if (layoutOverflow === 'hidden' || layoutOverflow === 'scroll' || layoutOverflow === 'auto') {
|
|
259
|
+
node.layout['clip-content'] = true;
|
|
260
|
+
delete node.layout['overflow'];
|
|
261
|
+
}
|
|
249
262
|
// 6-A: CSS-only 속성 필터링 (Figma가 지원하지 않는 CSS 속성 제거)
|
|
250
263
|
if (node.style) {
|
|
251
264
|
for (const key of Object.keys(node.style)) {
|
|
@@ -254,6 +267,25 @@ function enrichSpec(traversal, mapping) {
|
|
|
254
267
|
}
|
|
255
268
|
}
|
|
256
269
|
}
|
|
270
|
+
// 6-A2: layout에서 CSS position 키 → Figma x/y 변환 후 non-layout 키 제거
|
|
271
|
+
if (node.layout) {
|
|
272
|
+
const lay = node.layout;
|
|
273
|
+
// CSS top/left → Figma y/x (absolute positioning만)
|
|
274
|
+
if (lay['positioning'] === 'absolute') {
|
|
275
|
+
if (lay['top'] !== undefined && lay['y'] === undefined) {
|
|
276
|
+
lay['y'] = String(lay['top']);
|
|
277
|
+
}
|
|
278
|
+
if (lay['left'] !== undefined && lay['x'] === undefined) {
|
|
279
|
+
lay['x'] = String(lay['left']);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
// non-layout 키 제거 (top, bottom, left, right, aspect-ratio, overflow 잔존 등)
|
|
283
|
+
for (const key of Object.keys(lay)) {
|
|
284
|
+
if (!LAYOUT_KEYS.has(key)) {
|
|
285
|
+
delete lay[key];
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
257
289
|
// 6-B: direction 기본값 column (children 있는 frame/component에 direction 없으면)
|
|
258
290
|
if ((node.type === 'frame' || node.type === 'component') && node.children && node.children.length > 0) {
|
|
259
291
|
if (!node.layout?.direction) {
|
|
@@ -1156,10 +1188,20 @@ If no reviewNeeded, completes in 1 pass.`, {
|
|
|
1156
1188
|
// Also produce manifest + section files for incremental build
|
|
1157
1189
|
const outputDir = dirname(outputPath);
|
|
1158
1190
|
const manifests = [];
|
|
1159
|
-
|
|
1160
|
-
const manifest = splitSections(
|
|
1191
|
+
if (allPages.length === 1) {
|
|
1192
|
+
const manifest = splitSections(allPages[0], allComponents, outputDir);
|
|
1161
1193
|
manifests.push(manifest);
|
|
1162
1194
|
}
|
|
1195
|
+
else {
|
|
1196
|
+
for (let i = 0; i < allPages.length; i++) {
|
|
1197
|
+
const pageDir = join(outputDir, `page_${i}`);
|
|
1198
|
+
mkdirSync(pageDir, { recursive: true });
|
|
1199
|
+
const manifest = splitSections(allPages[i], allComponents, pageDir);
|
|
1200
|
+
manifests.push(manifest);
|
|
1201
|
+
}
|
|
1202
|
+
// Save combined manifest at root level
|
|
1203
|
+
writeFileSync(join(outputDir, 'manifest.json'), JSON.stringify(manifests, null, 2));
|
|
1204
|
+
}
|
|
1163
1205
|
// Save full specs (legacy format) alongside manifest
|
|
1164
1206
|
if (finalSpecs.length === 1) {
|
|
1165
1207
|
writeFileSync(outputPath, JSON.stringify(finalSpecs[0], null, 2));
|
package/package.json
CHANGED