Adobe XDでアセットをSCSS用に変数とmixinを書き出すプラグインを開発する

## はじめに
AdobeXDを使ってデザインを作ってると「**アセットをこのままCSSに書き出せたらなぁ**」って一度は思いますよね。自分は思いました。
2019年5月のアップデートで今までの「シンボル」の概念から「コンポーネント」という概念に変わり、よりコンポーネントの扱いが便利になりました。

今回はAdobeXDで登録したカラーアセットとフォントスタイルをSCSSで使える変数やmixinに書き出すプラグインを作ってみました。
動作は下の動画のようになります。
![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109953/3ae91406-fbc0-b496-cb17-1e5d823655e0.gif)


## 開発環境
AdobeXDのプラグインはES2018で開発ができます。
今回はTypeScriptで開発をしました。
理由はいくつかあるのですが、大きな理由としてAdobe公式の型定義ファイルが用意されているので**コード補完が効く**という点があります。かなり独自のクラスが多いのでTypeScriptで開発をすることをおすすめします。

また、今回はダイアログでのユーザー操作はあまり発生しないプラグインなのでフロントエンドフレームワークを使用せずに開発を行いました。

開発環境の構築はこちらの記事を参考にさせていただきました。
[Adobe XDプラグインをVueとBabel/TypeScriptで開発する方法](https://qiita.com/clockmaker/items/6ded50e81a7b9f556ae7)

上記の記事にも記載されていますが、[AdobeXD/xdpm](https://github.com/AdobeXD/xdpm)という開発補助ツールが便利です。

## アセットを取得する
アセットを取得するのは意外と簡単で`assets`モジュールを使うと簡単に取得できます。

### まずはカラーアセット
以下のコードのように`.get()` メソッドを実行することでカラーアセットの配列を取得できます。

```typescript
let palettes = assets.colors.get() as assets.ColorAsset[];
```

取得した配列をforEachでループを回して各要素の色を取得します。
`colorToCss（)`というアルファ値を持っていたらrgba()で、持っていなかったら１６進数表記で返すようなメソッドを作成します。(基本的にアルファ値を持った色はアセットにしないと思いますが…)
取得してきた色情報をもとにSCSSで使う変数名を生成し、カラーコードを代入します。

```typescript
colorPaletteToCSS(palettes: assets.ColorAsset[]) {
	palettes.forEach(p => {
		let c = this.colorToCss(p.color);
		let name = `$color-${c.replace('#', '')}`;
		this.resultCSS += `${name}: ${c};\n`;
	});
}

colorToCss(c:sg.Color):string {
	if (c.a !== 255) {
		return `rgba(${c.r}, ${c.g}, ${c.b}, ${this.num(c.a / 255)})`;
	} else {
		/* sg.Colorは１６進数でカラーコードを返してくれるメソッドが用意されています */
		return c.toHex(true);
	}
}
/* 数値を丸め込む */
num(value:number):number {
	return Math.round(value * 100) / 100;
}
```

### 次にフォントアセット
フォントアセットは`characterStyles`の`.get()`メソッドを実行することで取得できます。

```typescript
let styles = assets.characterStyles.get();
```

そして、同様にforEachでループを回してフォントスタイルを取得します。

```typescript
fontAssetToCSS(styles: assets.CharacterStyleAsset[]) {
	styles.forEach(item => {
		let mixinName = `${item.style.fontFamily.replace(/ /g, "")}-${item.style.fontStyle.replace(/ /g, "")}-${Math.floor(item.style.fontSize)}px`;
		this.resultCSS += `@mixin ${mixinName} { \n`;
		this.resultCSS += this.fontStyleToCSS(item.style);
		this.resultCSS += `}\n`
	});
}

fontStyleToCSS(f: assets.CharacterStyle):string {
	let result = "";

	// font-familyを取得
	// フォント名に空白があるか確認
	if (f.fontFamily.includes(' ')) {
		result += `font-family: "${f.fontFamily}";\n`;
	} else {
		result += `font-family: '${f.fontFamily}';\n`;
	}

	//font-weightを取得
	result += `font-weight: ${this.fontweightToCSS(f.fontStyle)};\n`;

	// 斜体の場合
	if (this.isItalic(f.fontStyle)) {
		result += `font-style: italic;\n`;
	}

	// 下線がある場合
	if (f.underline) {
		result += `text-decoration: underline;\n`;
	}

	result += `font-size: ${this.num(f.fontSize)}px;\n`;

	return result;
}

isItalic(f: string): boolean {
	return /\bItalic\b/i.test(f);
}
```

基本的にAdobeXDのフォントスタイルの値はそのままCSSに流用することができます。
しかし、`font-weight`は使用しているフォントによって太さの単位が違ったりする(例：W3、Regularなど)ので、これらを判別するメソッドを作りCSS用の値に変換する必要があります。
また、斜体に関しても同様に斜体であるかどうかを判別するメソッドを作成しました。

```typescript
fontweightToCSS(f: string):string {
	let fontWeight = f;

	switch (true) {
		case /\bBold\b/i.test(fontWeight):
			return "bold";

		/* 省略 */

		case /\bW[0-9]\b/i.test(fontWeight):
			let weight = fontWeight.replace(/W/i, "");
			let result = 100 * Number(weight);

			return String(result);

		default:
			return "normal";
	}
}
```

## クリップボードにコピーする
生成したSCSSのコードをクリップボードに渡します。
クリップボードにコピーするのはとても簡単です。
`clipboard`モジュールが用意されているので`.copyText()`メソッドを呼び出して引数に文字列を渡してあげるだけでクリップボードに文字列がコピーされます。

```typescript
clipboard.copyText(generateCSS.resultCSS);
```

## 完了ダイアログを出す
今回は完了をお知らせするという、すごくシンプルなダイアログを出します。
ダイアログ要素を生成しbody要素に追加します。WebのDOM操作と同じ感覚で開発できます。

今回は様々な完了メッセージを出力することを想定して、メッセージの文字列を引数としています。

```typescript
function createDialog(message:string) {
	const container = document.createElement('div');
	container.style.maxWidth = "320px";

	const title = document.createElement('h1');
	title.textContent = "XD to Sass！";
	title.style.paddingBottom = '20px';
	container.appendChild(title);

	const p = document.createElement('p');
	p.textContent = message;
	container.appendChild(p);

	const btnClose = document.createElement("button");
	btnClose.textContent = "close";
	btnClose.style.marginTop = "20px";
	container.appendChild(btnClose);
	btnClose.onclick = e => {
		dialog.close();
	};

	const dialog = document.createElement("dialog");
	document.body.appendChild(dialog);
	dialog.appendChild(container);
	dialog.showModal();
}
```

## まとめ
今回はカラーアセットとフォントアセットをSCSSの変数やmixinとして書き出すプラグインを開発することができました。
XDで作ったデザインをCSSとしてエクスポートする事によって、コーディングをより効率化させることができます。

また、このプラグインはこれからも機能開発を続けていこうと考えています。
次に実装したいのは、アートボード上のマスターコンポーネントをSCSSのコードで書き出すという機能ですかね…。
いずれはこのプラグインを公開したいと思います。

皆さんもAdobeXDを使ってコーディングを効率化させていきましょう！

## 参考サイト
- [Adobe XD Platform](https://adobexdplatform.com/)
- [Adobe XDプラグインをVueとBabel/TypeScriptで開発する方法](https://qiita.com/clockmaker/items/6ded50e81a7b9f556ae7)