FigmaのFrameをいい感じにJSONに変換してくれるFigma Plugin。
※ ChatGPT(GPT-4)との共作です。
ChatGPTとの会話ログ
## Figma JSON ExporterStarted on: 2023/3/16 10:11:18
Figma の特定の Frame から Json を出力するカスタムプラグインを作ってほしい
Figma の API を使用して、特定の Frame から JSON を出力するカスタムプラグインを作成する方法を説明します。以下のステップに従ってください。
- Figma のプラグインを作成する:
Figma アカウントで、メニューバーから「Plugins」>「Manage plugins」>「Create new plugin」を選択します。新しいプラグインに名前と説明を入力し、「Create Plugin」をクリックして作成します。
- プラグインコードを編集する:
プラグインが作成されたら、code.ts
ファイルを開き、以下のコードを貼り付けます。
// This plugin will export JSON data from a specific frame in Figma.
figma.showUI(__html__, { width: 400, height: 300 });
figma.ui.onmessage = async (msg) => {
if (msg.type === "export-frame") {
const frameName = msg.frameName;
const frame = figma.currentPage.findOne(
(node) => node.type === "FRAME" && node.name === frameName
);
if (!frame) {
figma.ui.postMessage({
type: "error",
message: `Frame not found with name "${frameName}".`,
});
return;
}
const jsonData = JSON.stringify(frame, null, 2);
await figma.clientStorage.setAsync(frameName, jsonData);
figma.ui.postMessage({
type: "success",
message: `JSON data exported for frame "${frameName}".`,
});
}
};
- プラグインの UI を作成する:
プラグインのui.html
ファイルを開き、以下のコードを貼り付けます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Figma Frame to JSON Exporter</title>
<style>
/* Add your custom styles here */
</style>
</head>
<body>
<h1>Figma Frame to JSON Exporter</h1>
<p>Enter the frame name you want to export as JSON:</p>
<input type="text" id="frameName" />
<button id="exportButton">Export JSON</button>
<p id="message"></p>
<script>
document.getElementById("exportButton").onclick = () => {
const frameName = document.getElementById("frameName").value;
parent.postMessage(
{ pluginMessage: { type: "export-frame", frameName } },
"*"
);
};
window.onmessage = (event) => {
const msg = event.data.pluginMessage;
if (msg.type === "success" || msg.type === "error") {
document.getElementById("message").innerText = msg.message;
}
};
</script>
</body>
</html>
- プラグインをテストする:
Figma でプラグインを実行して、特定の Frame から JSON データを出力する機能をテストできます。プラグインを実行するには、「Plugins」メニューからプラグイン名を選択します。UI が表示されたら、Frame の名前を入力し、「Export JSON」ボタン
最新の UI を加味して Figma のプラグインの作り方の手順をもう一度教えてもらってもいい?
もちろんです!最新の Figma UI を考慮して、プラグインの作成手順を以下に示します。
- Figma のプラグインを作成する:
Figma アカウントで、右上の「Community」アイコンをクリックし、下部メニューで「Create new」>「Plugin」を選択します。新しいプラグインに名前と説明を入力し、「Create Plugin」をクリックして作成します。
- プラグインコードを編集する:
プラグインが作成されたら、code.ts
ファイルを開き、以下のコードを貼り付けます。
// This plugin will export JSON data from a specific frame in Figma.
figma.showUI(__html__, { width: 400, height: 300 });
figma.ui.onmessage = async (msg) => {
if (msg.type === "export-frame") {
const frameName = msg.frameName;
const frame = figma.currentPage.findOne(
(node) => node.type === "FRAME" && node.name === frameName
);
if (!frame) {
figma.ui.postMessage({
type: "error",
message: `Frame not found with name "${frameName}".`,
});
return;
}
const jsonData = JSON.stringify(frame, null, 2);
await figma.clientStorage.setAsync(frameName, jsonData);
figma.ui.postMessage({
type: "success",
message: `JSON data exported for frame "${frameName}".`,
});
}
};
- プラグインの UI を作成する:
プラグインのui.html
ファイルを開き、以下のコードを貼り付けます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Figma Frame to JSON Exporter</title>
<style>
/* Add your custom styles here */
</style>
</head>
<body>
<h1>Figma Frame to JSON Exporter</h1>
<p>Enter the frame name you want to export as JSON:</p>
<input type="text" id="frameName" />
<button id="exportButton">Export JSON</button>
<p id="message"></p>
<script>
document.getElementById("exportButton").onclick = () => {
const frameName = document.getElementById("frameName").value;
parent.postMessage(
{ pluginMessage: { type: "export-frame", frameName } },
"*"
);
};
window.onmessage = (event) => {
const msg = event.data.pluginMessage;
if (msg.type === "success" || msg.type === "error") {
document.getElementById("message").innerText = msg.message;
}
};
</script>
</body>
</html>
- プラグインをテストする:
Figma でプラグインを実行して、特定の Frame から JSON データを出力する機能をテストできます。プラグインを実行するには、「Plugins」メニューからプラグイン名を選択します。UI が表示されたら、Frame の名前を入力し、「Export JSON」ボタンをクリック
json はどこに保存されるの?
上記のプラグインコードでは、JSON データは Figma のクライアントストレージに保存されています。figma.clientStorage.setAsync
関数を使用して、指定したキー(この場合はフレーム名)に対して JSON データを保存しています。
ただし、この方法では、データは Figma のローカルストレージに保存され、ユーザーが直接アクセスできません。代わりに、JSON データをダウンロード可能なファイルとして保存する方法を紹介します。
code.ts
ファイルの変更:
以下のコードをcode.ts
ファイルに追加し、figma.ui.postMessage
関数を使用して JSON データを UI に送信します。
// Replace the following line:
// await figma.clientStorage.setAsync(frameName, jsonData);
// With these lines:
figma.ui.postMessage({ type: "json-data", jsonData: jsonData });
ui.html
ファイルの変更:
以下の関数をui.html
ファイルの<script>
タグ内に追加して、受信した JSON データをダウンロード可能なファイルとして保存します。
function downloadJson(jsonData, fileName) {
const a = document.createElement("a");
const file = new Blob([jsonData], { type: "application/json" });
a.href = URL.createObjectURL(file);
a.download = fileName;
a.click();
}
次に、window.onmessage
関数を以下のように変更して、新しいdownloadJson
関数を呼び出します。
window.onmessage = (event) => {
const msg = event.data.pluginMessage;
if (msg.type === "success" || msg.type === "error") {
document.getElementById("message").innerText = msg.message;
} else if (msg.type === "json-data") {
downloadJson(msg.jsonData, "frame-data.json");
}
};
これで、プラグインを実行してフレームをエクスポートすると、JSON データがframe-data.json
という名前のファイルとしてダウンロードされます。
input に入力された frame 名をもとに該当 Frame を Figma の API を使って Json 形式に変換してダウンロードできるように script を書き直して
以下に、指定されたフレーム名を元に該当フレームを Figma の API を使って JSON 形式に変換し、ダウンロードできるようにスクリプトを書き直します。
code.ts
ファイルを更新:
// This plugin will export JSON data from a specific frame in Figma.
figma.showUI(__html__, { width: 400, height: 300 });
figma.ui.onmessage = async (msg) => {
if (msg.type === "export-frame") {
const frameName = msg.frameName;
const frame = figma.currentPage.findOne(
(node) => node.type === "FRAME" && node.name === frameName
);
if (!frame) {
figma.ui.postMessage({
type: "error",
message: `Frame not found with name "${frameName}".`,
});
return;
}
const jsonData = JSON.stringify(frame, null, 2);
figma.ui.postMessage({ type: "json-data", jsonData: jsonData });
}
};
ui.html
ファイルを更新:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Figma Frame to JSON Exporter</title>
<style>
/* Add your custom styles here */
</style>
</head>
<body>
<h1>Figma Frame to JSON Exporter</h1>
<p>Enter the frame name you want to export as JSON:</p>
<input type="text" id="frameName" />
<button id="exportButton">Export JSON</button>
<p id="message"></p>
<script>
document.getElementById("exportButton").onclick = () => {
const frameName = document.getElementById("frameName").value;
parent.postMessage(
{ pluginMessage: { type: "export-frame", frameName } },
"*"
);
};
function downloadJson(jsonData, fileName) {
const a = document.createElement("a");
const file = new Blob([jsonData], { type: "application/json" });
a.href = URL.createObjectURL(file);
a.download = fileName;
a.click();
}
window.onmessage = (event) => {
const msg = event.data.pluginMessage;
if (msg.type === "error") {
document.getElementById("message").innerText = msg.message;
} else if (msg.type === "json-data") {
downloadJson(msg.jsonData, "frame-data.json");
}
};
</script>
</body>
</html>
これで、入力されたフレーム名を元に該当フレームを JSON 形式に変換し、ダウンロードできるようになりました。プラグインを実行して、フレーム名を入力し、「Export JSON」ボタンをクリックすると、JSON データが frame-data.json
という名前のファイルとしてダウンロードされます。
Frame の中身の構造まで取得して Json 化したい
Figma API を使って、フレームの内部構造を含む JSON データを作成するには、以下の手順でコードを更新します。
code.ts
ファイルの更新:
フレームの内部構造を含む JSON データを作成するために、新しい関数processNode
を追加します。この関数は、ノードとその子孫を再帰的に処理して、フレームの内部構造を保持するオブジェクトを作成します。
function processNode(node) {
const processedNode = {
id: node.id,
name: node.name,
type: node.type,
visible: node.visible,
locked: node.locked,
children: [],
};
if ("children" in node) {
processedNode.children = node.children.map((child) => processNode(child));
}
return processedNode;
}
// This plugin will export JSON data from a specific frame in Figma, including its structure.
figma.showUI(__html__, { width: 400, height: 300 });
figma.ui.onmessage = async (msg) => {
if (msg.type === "export-frame") {
const frameName = msg.frameName;
const frame = figma.currentPage.findOne(
(node) => node.type === "FRAME" && node.name === frameName
);
if (!frame) {
figma.ui.postMessage({
type: "error",
message: `Frame not found with name "${frameName}".`,
});
return;
}
const processedFrame = processNode(frame);
const jsonData = JSON.stringify(processedFrame, null, 2);
figma.ui.postMessage({ type: "json-data", jsonData: jsonData });
}
};
ui.html
ファイルをそのまま使用します。これは以前の回答で提供したものと同じです。
これで、指定されたフレーム名を元に、フレームの内部構造を含む JSON データが作成され、ダウンロードできるようになります。プラグインを実行し、「Export JSON」ボタンをクリックすると、フレームの内部構造を含む JSON データがframe-data.json
という名前のファイルとしてダウンロードされます。
processNode の引数の node の型がなくて怒られます
すみません。型を指定していないことによるエラーが発生していました。processNode
関数の引数node
に型を追加しましょう。SceneNode
型を使用して、以下のように修正します。
code.ts
ファイルの更新:
import { SceneNode } from "@figma/plugin-typings";
function processNode(node: SceneNode) {
const processedNode = {
id: node.id,
name: node.name,
type: node.type,
visible: node.visible,
locked: node.locked,
children: [],
};
if ("children" in node) {
processedNode.children = (node as any).children.map((child: SceneNode) =>
processNode(child)
);
}
return processedNode;
}
// This plugin will export JSON data from a specific frame in Figma, including its structure.
figma.showUI(__html__, { width: 400, height: 300 });
figma.ui.onmessage = async (msg) => {
if (msg.type === "export-frame") {
const frameName = msg.frameName;
const frame = figma.currentPage.findOne(
(node) => node.type === "FRAME" && node.name === frameName
);
if (!frame) {
figma.ui.postMessage({
type: "error",
message: `Frame not found with name "${frameName}".`,
});
return;
}
const processedFrame = processNode(frame);
const jsonData = JSON.stringify(processedFrame, null, 2);
figma.ui.postMessage({ type: "json-data", jsonData: jsonData });
}
};
SceneNode
型をインポートして、processNode
関数の引数node
に型SceneNode
を追加しました。また、node
がchildren
プロパティを持つ場合、node
をany
型にキャストして子要素を処理します。
これで、型エラーが解消されるはずです。再度プラグインを実行して、フレームの内部構造を含む JSON データをエクスポートできることを確認してください。
@figma/plugin-typings は yarn でインストールすれば良い?
いいえ、@figma/plugin-typings
はfigma/plugin-typings
として提供されており、インストールする必要はありません。Figma プラグインを開発する際、型定義ファイルは既にプロジェクトに含まれています。
通常、プロジェクトのtsconfig.json
ファイルに"types": ["figma/plugin-typings"]
が追加されており、Figma プラグインの型定義が提供されています。そのため、import { SceneNode } from "@figma/plugin-typings";
のようなインポート文を使用する必要はありません。
代わりに、次のように修正してSceneNode
型を使用できます。
code.ts
ファイルの更新:
function processNode(node: SceneNode) {
const processedNode = {
id: node.id,
name: node.name,
type: node.type,
visible: node.visible,
locked: node.locked,
children: [],
};
if ("children" in node) {
processedNode.children = (node as any).children.map((child: SceneNode) =>
processNode(child)
);
}
return processedNode;
}
// This plugin will export JSON data from a specific frame in Figma, including its structure.
figma.showUI(__html__, { width: 400, height: 300 });
figma.ui.onmessage = async (msg) => {
if (msg.type === "export-frame") {
const frameName = msg.frameName;
const frame = figma.currentPage.findOne(
(node) => node.type === "FRAME" && node.name === frameName
);
if (!frame) {
figma.ui.postMessage({
type: "error",
message: `Frame not found with name "${frameName}".`,
});
return;
}
const processedFrame = processNode(frame);
const jsonData = JSON.stringify(processedFrame, null, 2);
figma.ui.postMessage({ type: "json-data", jsonData: jsonData });
}
};
import { SceneNode } from "@figma/plugin-typings";
のインポート文を削除しました。それ以外のコードは前回の回答と同じです。
これで、型エラーが解消され、フレームの内部構造を含む JSON データをエクスポートできるはずです。プラグインを実行して確認してください。
https://github.dev/kazuyaseki/figma-to-react/blob/c4c0e6986bc81806dd98ddfd3253bea67819edc8/src/buildTagTree.ts このコードを参考にリファクタできる?
このコードを参考にして、processNode
関数をリファクタリングして、より構造化された方法でフレームの内部構造を含む JSON データを生成できます。以下に、リファクタリングされたprocessNode
関数を示します。
code.ts
ファイルの更新:
interface ProcessedNode {
id: string;
name: string;
type: string;
visible: boolean;
locked: boolean;
children?: ProcessedNode[];
}
function processNode(node: SceneNode): ProcessedNode {
const baseNode: ProcessedNode = {
id: node.id,
name: node.name,
type: node.type,
visible: node.visible,
locked: node.locked,
};
if ("children" in node) {
baseNode.children = (node as any).children.map((child: SceneNode) =>
processNode(child)
);
}
return baseNode;
}
// This plugin will export JSON data from a specific frame in Figma, including its structure.
figma.showUI(__html__, { width: 400, height: 300 });
figma.ui.onmessage = async (msg) => {
if (msg.type === "export-frame") {
const frameName = msg.frameName;
const frame = figma.currentPage.findOne(
(node) => node.type === "FRAME" && node.name === frameName
);
if (!frame) {
figma.ui.postMessage({
type: "error",
message: `Frame not found with name "${frameName}".`,
});
return;
}
const processedFrame = processNode(frame);
const jsonData = JSON.stringify(processedFrame, null, 2);
figma.ui.postMessage({ type: "json-data", jsonData: jsonData });
}
};
リファクタリングでは、ProcessedNode
インターフェイスを作成し、processNode
関数が返すオブジェクトの型を明示的に指定しました。これにより、関数の入出力がより明確になり、コードの可読性が向上します。
また、processNode
関数内でベースノードを作成し、子ノードが存在する場合にchildren
プロパティを追加しています。
このリファクタリングにより、コードがより構造化され、可読性が向上します。プラグインを実行し、フレームの内部構造を含む JSON データをエクスポートできることを確認してください。
スタイルの情報って加味できない?
もちろん、スタイル情報を加味して JSON データを生成することができます。以下に、スタイル情報を含めたリファクタリングされたprocessNode
関数を示します。
code.ts
ファイルの更新:
interface ProcessedNode {
id: string;
name: string;
type: string;
visible: boolean;
locked: boolean;
children?: ProcessedNode[];
style?: object;
}
function processNode(node: SceneNode): ProcessedNode {
const baseNode: ProcessedNode = {
id: node.id,
name: node.name,
type: node.type,
visible: node.visible,
locked: node.locked,
};
if (
node.type === "RECTANGLE" ||
node.type === "TEXT" ||
node.type === "VECTOR" ||
node.type === "ELLIPSE" ||
node.type === "POLYGON" ||
node.type === "STAR" ||
node.type === "LINE"
) {
baseNode.style = {
fills: (node as GeometryMixin).fills,
strokes: (node as GeometryMixin).strokes,
strokeWeight: (node as GeometryMixin).strokeWeight,
cornerRadius: (node as CornerMixin).cornerRadius,
blendMode: (node as BlendMixin).blendMode,
opacity: (node as BlendMixin).opacity,
};
}
if ("children" in node) {
baseNode.children = (node as any).children.map((child: SceneNode) =>
processNode(child)
);
}
return baseNode;
}
// This plugin will export JSON data from a specific frame in Figma, including its structure and styles.
figma.showUI(__html__, { width: 400, height: 300 });
figma.ui.onmessage = async (msg) => {
if (msg.type === "export-frame") {
const frameName = msg.frameName;
const frame = figma.currentPage.findOne(
(node) => node.type === "FRAME" && node.name === frameName
);
if (!frame) {
figma.ui.postMessage({
type: "error",
message: `Frame not found with name "${frameName}".`,
});
return;
}
const processedFrame = processNode(frame);
const jsonData = JSON.stringify(processedFrame, null, 2);
figma.ui.postMessage({ type: "json-data", jsonData: jsonData });
}
};
ProcessedNode
インターフェイスにstyle
プロパティを追加しました。processNode
関数内で、対象のノードタイプがスタイル情報を持っている場合(例: RECTANGLE、TEXT、VECTOR、ELLIPSE、POLYGON、STAR、LINE など)、そのスタイル情報を取得し、style
プロパティに割り当てます。
このリファクタリングにより、各ノードのスタイル情報も JSON データに含まれるようになります。プラグインを実行し、フレームの内部構造とスタイル情報を含む JSON データをエクスポートできることを確認してください。
fontsize とかも考慮できる?
もちろん、フォントサイズやその他のテキスト関連のスタイル情報も考慮できます。以下に、processNode
関数を更新して、テキストノードの場合にフォントサイズやその他のテキストスタイル情報を含める方法を示します。
code.ts
ファイルの更新:
interface ProcessedNode {
id: string;
name: string;
type: string;
visible: boolean;
locked: boolean;
children?: ProcessedNode[];
style?: object;
textStyle?: object;
}
function processNode(node: SceneNode): ProcessedNode {
const baseNode: ProcessedNode = {
id: node.id,
name: node.name,
type: node.type,
visible: node.visible,
locked: node.locked,
};
if (
node.type === "RECTANGLE" ||
node.type === "TEXT" ||
node.type === "VECTOR" ||
node.type === "ELLIPSE" ||
node.type === "POLYGON" ||
node.type === "STAR" ||
node.type === "LINE"
) {
baseNode.style = {
fills: (node as GeometryMixin).fills,
strokes: (node as GeometryMixin).strokes,
strokeWeight: (node as GeometryMixin).strokeWeight,
cornerRadius: (node as CornerMixin).cornerRadius,
blendMode: (node as BlendMixin).blendMode,
opacity: (node as BlendMixin).opacity,
};
}
if (node.type === "TEXT") {
baseNode.textStyle = {
fontSize: (node as TextNode).fontSize,
fontFamily: (node as TextNode).fontName,
fontWeight: (node as TextNode).fontWeight,
textAlignHorizontal: (node as TextNode).textAlignHorizontal,
textAlignVertical: (node as TextNode).textAlignVertical,
letterSpacing: (node as TextNode).letterSpacing,
lineHeight: (node as TextNode).lineHeight,
};
}
if ("children" in node) {
baseNode.children = (node as any).children.map((child: SceneNode) =>
processNode(child)
);
}
return baseNode;
}
// This plugin will export JSON data from a specific frame in Figma, including its structure and styles.
figma.showUI(__html__, { width: 400, height: 300 });
figma.ui.onmessage = async (msg) => {
if (msg.type === "export-frame") {
const frameName = msg.frameName;
const frame = figma.currentPage.findOne(
(node) => node.type === "FRAME" && node.name === frameName
);
if (!frame) {
figma.ui.postMessage({
type: "error",
message: `Frame not found with name "${frameName}".`,
});
return;
}
const processedFrame = processNode(frame);
const jsonData = JSON.stringify(processedFrame, null, 2);
figma.ui.postMessage({ type: "json-data", jsonData: jsonData });
}
};
ProcessedNode
インターフェイスにtextStyle
プロパティを追加しました。processNode
関数内で、対象のノードタイプがTEXT
の場合、フォントサイズやその他のテキストスタイル情報を取得し、textStyle
プロパティに割り当てます。
このリファク
続けて
タリングにより、テキストノードのフォントサイズやその他のテキストスタイル情報も JSON データに含まれるようになります。プラグインを実行し、フレームの内部構造、スタイル情報、およびテキストスタイル情報を含む JSON データをエクスポートできることを確認してください。
同じように node.type のそれぞれについて詳細にスタイルを出力してほしい
了解しました。それぞれのノードタイプに応じて、詳細なスタイル情報を含むようにprocessNode
関数を更新します。
code.ts
ファイルの更新:
interface ProcessedNode {
id: string;
name: string;
type: string;
visible: boolean;
locked: boolean;
children?: ProcessedNode[];
style?: object;
}
function processNode(node: SceneNode): ProcessedNode {
const baseNode: ProcessedNode = {
id: node.id,
name: node.name,
type: node.type,
visible: node.visible,
locked: node.locked,
};
if ("fills" in node) {
baseNode.style = {
fills: node.fills,
};
}
if ("strokes" in node) {
if (!baseNode.style) baseNode.style = {};
baseNode.style = {
...baseNode.style,
strokes: node.strokes,
strokeWeight: node.strokeWeight,
strokeMiterLimit: node.strokeMiterLimit,
strokeCap: node.strokeCap,
strokeJoin: node.strokeJoin,
};
}
if ("cornerRadius" in node) {
if (!baseNode.style) baseNode.style = {};
baseNode.style = {
...baseNode.style,
cornerRadius: node.cornerRadius,
};
}
if ("blendMode" in node) {
if (!baseNode.style) baseNode.style = {};
baseNode.style = {
...baseNode.style,
blendMode: node.blendMode,
opacity: node.opacity,
};
}
if (node.type === "TEXT") {
if (!baseNode.style) baseNode.style = {};
baseNode.style = {
...baseNode.style,
fontSize: node.fontSize,
fontFamily: node.fontName,
fontWeight: node.fontWeight,
textAlignHorizontal: node.textAlignHorizontal,
textAlignVertical: node.textAlignVertical,
letterSpacing: node.letterSpacing,
lineHeight: node.lineHeight,
textDecoration: node.textDecoration,
textCase: node.textCase,
textAutoResize: node.textAutoResize,
paragraphIndent: node.paragraphIndent,
paragraphSpacing: node.paragraphSpacing,
autoRename: node.autoRename,
};
}
if ("children" in node) {
baseNode.children = (node as any).children.map((child: SceneNode) =>
processNode(child)
);
}
return baseNode;
}
// This plugin will export JSON data from a specific frame in Figma, including its structure and styles.
figma.showUI(__html__, { width: 400, height: 300 });
figma.ui.onmessage = async (msg) => {
if (msg.type === "export-frame") {
const frameName = msg.frameName;
const frame = figma.currentPage.findOne(
(node) => node.type === "FRAME" && node.name === frameName
);
if (!frame) {
figma.ui.postMessage({
type: "error",
message: `Frame not found with name "${frameName}".`,
});
return;
}
const processedFrame = processNode(frame);
const jsonData = JSON.stringify(processedFrame, null, 2);
figma.ui.postMessage({ type: "json-data", jsonData: jsonData });
}
};
processNode
関数では、各ノードタイプごとに詳細なスタイル情報を持つstyle
プロパ
続けて
パティを割り当てます。例えば、テキストノードにはフォントサイズ、フォントファミリー、フォントウェイト、テキストアラインメント、行間、段落のインデント、段落のスペーシングなどの情報が含まれます。それぞれのノードタイプに対して、適切なスタイル情報が含まれるようになりました。
これで、プラグインはフレームの内部構造、各ノードの詳細なスタイル情報を含む JSON データをエクスポートできるようになります。プラグインを実行し、期待される JSON データが正しくエクスポートされることを確認してください。
node.strokeMiterLimit と node.strokeCap で型エラーが出ます
失礼しました。それらのプロパティはすべてのノードには存在しないため、GeometryMixin
インターフェイスを持つノードでのみアクセスできます。これを修正するには、processNode
関数でstrokes
プロパティを持つノードをチェックし、それらのプロパティにアクセスする前に型アサーションを使用します。
以下が修正されたprocessNode
関数の一部です。
if ("strokes" in node) {
if (!baseNode.style) baseNode.style = {};
const geometryNode = node as GeometryMixin;
baseNode.style = {
...baseNode.style,
strokes: geometryNode.strokes,
strokeWeight: geometryNode.strokeWeight,
strokeMiterLimit: geometryNode.strokeMiterLimit,
strokeCap: geometryNode.strokeCap,
strokeJoin: geometryNode.strokeJoin,
};
}
この修正により、node.strokeMiterLimit
とnode.strokeCap
に関する型エラーが解決されるはずです。プラグインを再度実行し、期待される JSON データが正しくエクスポートされることを確認してください。
ありがとう。 それと、入力された frame 名でファイル保存できるようにしたい。
了解しました。入力されたフレーム名を使ってファイルを保存するようにプラグインを更新します。まず、ui.html
ファイルを更新して、保存ボタンを追加し、フレーム名をメッセージとして送信できるようにします。
ui.html
ファイルの更新:
<!DOCTYPE html>
<html>
<head>
<style>
/* Add your styles here */
</style>
</head>
<body>
<label for="frame-name">Frame name:</label>
<input type="text" id="frame-name" />
<button id="export-button">Export Frame as JSON</button>
<script>
document.getElementById("export-button").onclick = () => {
const frameName = document.getElementById("frame-name").value;
parent.postMessage(
{ pluginMessage: { type: "export-frame", frameName: frameName } },
"*"
);
};
onmessage = (event) => {
const message = event.data.pluginMessage;
if (message.type === "json-data") {
const jsonData = message.jsonData;
const blob = new Blob([jsonData], { type: "application/json" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = `${frameName}.json`; // Use the frameName as the file name
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
};
</script>
</body>
</html>
次に、code.ts
ファイルのメッセージハンドラを更新して、フレーム名を含む JSON データをui.html
に送信します。
code.ts
ファイルの更新:
figma.ui.onmessage = async (msg) => {
if (msg.type === "export-frame") {
const frameName = msg.frameName;
const frame = figma.currentPage.findOne(
(node) => node.type === "FRAME" && node.name === frameName
);
if (!frame) {
figma.ui.postMessage({
type: "error",
message: `Frame not found with name "${frameName}".`,
});
return;
}
const processedFrame = processNode(frame);
const jsonData = JSON.stringify(processedFrame, null, 2);
figma.ui.postMessage({
type: "json-data",
jsonData: jsonData,
frameName: frameName,
}); // Send the frameName along with jsonData
}
};
これで、プラグインはフレーム名を使って JSON ファイルを保存できるようになります。プラグインを実行し、期待される JSON データがフレーム名を持つファイルとして正しく保存されることを確認してください。
ui.html
この時点でのコード
code.ts
この時点でのコード
この二つのファイルが現在のコードなんだけど、これを加味してもう一度作ってもらってもいい?
もちろんです!ui.html
とcode.ts
の両方のファイルを加味して、フレーム名を使用してファイルを保存するようにプラグインを修正します。
ui.html
ファイルの更新:
<!DOCTYPE html>
<html lang="en">
<!-- head の中身は省略 -->
<body>
<!-- 省略... -->
<script>
document.getElementById("export-button").onclick = () => {
const frameName = document.getElementById("frame-name").value;
parent.postMessage(
{ pluginMessage: { type: "export-frame", frameName: frameName } },
"*"
);
};
onmessage = (event) => {
const message = event.data.pluginMessage;
if (message.type === "json-data") {
const jsonData = message.jsonData;
const frameName = message.frameName;
const blob = new Blob([jsonData], { type: "application/json" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = `${frameName}.json`; // Use the frameName as the file name
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
};
</script>
</body>
</html>
code.ts
ファイルの更新:
// 既存のインターフェースと関数は省略
// This plugin will export JSON data from a specific frame in Figma, including its structure and styles.
figma.showUI(__html__, { width: 400, height: 300 });
figma.ui.onmessage = async (msg) => {
if (msg.type === "export-frame") {
const frameName = msg.frameName;
const frame = figma.currentPage.findOne(
(node) => node.type === "FRAME" && node.name === frameName
);
if (!frame) {
figma.ui.postMessage({
type: "error",
message: `Frame not found with name "${frameName}".`,
});
return;
}
const processedFrame = processNode(frame);
const jsonData = JSON.stringify(processedFrame, null, 2);
figma.ui.postMessage({
type: "json-data",
jsonData: jsonData,
frameName: frameName,
}); // Send the frameName along with jsonData
}
};
これで、プラグインはフレーム名を使って JSON ファイルを保存できるようになります。プラグインを実行し、期待される JSON データがフレーム名を持つファイルとして正しく保存されることを確認してください。
message が出なくなっちゃったんだけどどうしたらいい?
失礼しました。ui.html
の onmessage
イベントハンドラでエラーメッセージを処理する部分を追加し忘れていました。次のように ui.html
の <script>
タグ内にエラーメッセージを処理するコードを追加してください。
<!-- 他の部分は省略 -->
<script>
// 既存のコードは省略
onmessage = (event) => {
const message = event.data.pluginMessage;
if (message.type === "json-data") {
// 既存のコードは省略
} else if (message.type === "error") {
const logElement = document.getElementById("message");
logElement.textContent = message.message;
}
};
</script>
<!-- 他の部分は省略 -->
これで、エラーメッセージが正しく表示されるはずです。プラグインを再度実行して、エラーメッセージが表示されることを確認してください。
治った!ありがとう! ボタンにもアニメーションつけたい
ボタンにアニメーションを追加するには、ui.html
の <style>
タグ内に CSS アニメーションを定義しましょう。ここでは、ボタンにホバー(マウスオーバー)したときに背景色が変わるアニメーションを追加してみます。
<!DOCTYPE html>
<html lang="en">
<head>
<!-- 省略... -->
<style>
/* 既存のスタイルは省略 */
.button {
/* 既存のスタイルは省略 */
transition: background-color 0.3s ease; /* アニメーションを追加 */
}
.button:hover {
background-color: #61c0c3; /* ホバー時の背景色を変更 */
}
</style>
</head>
<body>
<!-- 省略... -->
</body>
</html>
このコードは、ボタンにマウスオーバーしたときに背景色が徐々に変わるアニメーションを追加します。transition
プロパティで、アニメーションするプロパティ(ここでは background-color
)、アニメーションの持続時間(0.3s
)、およびアニメーションのタイミング関数(ease
)を指定しています。
さらに別のアニメーション効果を追加したい場合は、同様に CSS を編集してください。たとえば、ボタンの境界線の色も変更するには、次のようにコードを追加します。
<style>
/* 既存のスタイルは省略 */
.button {
/* 既存のスタイルは省略 */
transition: background-color 0.3s ease, border-color 0.3s ease; /* 境界線の色もアニメーションするように変更 */
}
.button:hover {
background-color: #61c0c3; /* ホバー時の背景色を変更 */
border-color: #61c0c3; /* ホバー時の境界線の色を変更 */
}
</style>
プラグインを再度実行して、ボタンのアニメーションが期待通りに動作することを確認してください。
押下中もいい感じにスタイリングできない?
もちろんできます!ボタンが押下中(クリック中)のスタイリングを追加するには、:active
疑似クラスを使用します。ここでは、ボタンが押下中のときに背景色と境界線の色をさらに暗くします。
<!DOCTYPE html>
<html lang="en">
<head>
<!-- 省略... -->
<style>
/* 既存のスタイルは省略 */
.button {
/* 既存のスタイルは省略 */
transition: background-color 0.3s ease, border-color 0.3s ease;
}
.button:hover {
background-color: #61c0c3; /* ホバー時の背景色を変更 */
border-color: #61c0c3; /* ホバー時の境界線の色を変更 */
}
.button:active {
background-color: #4a999a; /* 押下中の背景色を変更 */
border-color: #4a999a; /* 押下中の境界線の色を変更 */
}
</style>
</head>
<body>
<!-- 省略... -->
</body>
</html>
これで、ボタンが押下されている間、背景色と境界線の色が暗くなります。プラグインを再度実行して、ボタンのスタイリングが期待通りに動作することを確認してください。
綺麗な感じになったありがと!
どういたしまして!お手伝いできてうれしいです。
これからも Figma プラグインや他の開発に関する質問があれば、どんどんお聞きください。お手伝いできることがあれば喜んで対応します。プロジェクトがうまく進むことを願っています!
出力されたJSONを以下の命令の中にコピペしてChatGPTに投げるとコンポーネントの叩きを作ってくれます。
例:
# 命令書
あなたは、プロのフロントエンドエンジニアです。
以下の Figma の Frame から出力された「元となる JSON」から「制約条件」満たすを最高のプログラムを出力してください。
# 元となる JSON
```json
<ここにjsonを書く>
```
# 制約条件
- React の関数型記述でコンポーネントを作成すること
- Typescript を使用すること
- スタイリングは CSS Module の形式に則ること
- Sass で書くこと
- ファイル数はなるべく少なくすること