モダンなデザインで軽量なJavaScriptのコンテキストメニューのライブラリーを作った

## どんなものを作ったのか

Fluent Designに影響を受けた、モダンで美しく軽量なJavaScriptのコンテキストメニューのライブラリー「[modernContext.js](https://github.com/Robot-Inventor/modern-context.js)」を作りました。

コンテキストメニューが表示されるときにはちゃんとアニメーションも付いています！また、背景はブラーがかかった半透明のデザインです。

![ライトモードのときのスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420120/e2bdee7f-a454-711d-f26a-55a6396aa0b7.png)

また、ダークモードをサポートしています。ブラウザーがダークモードに設定されている場合、自動で黒を基調としたデザインに切り替わります。

![ダークモードのときのスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420120/1eceb568-ce0a-c489-ed34-cad589f6fdc6.png)

## なぜ作ったのか

ネットでコンテキストメニューのライブラリーを探すとたくさん出てくるものの古いデザインのものが多く、カッコいいもの（とくにFluent Designのような見た目のもの）はなかなか見つかりませんでした。

また、依存しているものがなく単体で動作してほしい（jQueryやだ）ということもあり、自作しました。

## 対応ブラウザー

WindowsとAndroidのChromeとFirefoxで動作確認しています。SafariやiOS版のChromeについては、動作確認していません。

## 使い方

npmパッケージとして[配布](https://www.npmjs.com/package/modern-context)しています。

```console
npm install modern-context
```

また、単体のJavaScriptファイルとしても[配布](https://github.com/Robot-Inventor/modern-context.js/blob/main/dist/modern-context.min.js)していますので、お好きな方をどうぞ。

詳しい使い方はGitHubの[README](https://github.com/Robot-Inventor/modern-context.js)と[ドキュメント](https://github.com/Robot-Inventor/modern-context.js/blob/main/docs/classes/Context.md)に書いてありますが、軽く説明します。

```javascript
// npmパッケージを使う場合
import { Context } from "modern-context";
// 単体のJSファイルを使う場合
import { Context } from "./dist/modern-context.min.js"

// コンテキストメニューの中身を定義
const contents = [
    {
        type: "item",
        label: "Alert",
        callback: () => {
            alert("Clicked!");
        }
    },
    {
        type: "separator"
    },
    {
        type: "item",
        label: "No Callback"
    },
];
// コンテキストメニューの初期化
const context = new Context("#target", contents);
```

非常にシンプルです。

``new Context("#target", contents)``の第1引数はターゲットとする要素です。この場合は``id="target"``が設定された要素を右クリックすると、コンテキストメニューが表示されます。

第2引数はコンテキストメニューの中身の情報で、オブジェクトの配列になっています。第2引数は省略可能です。

配列に入っているオブジェクトはアイテムとセパレーターの2種類です。アイテムは文字どおりアイテム、セパレーターはアイテム間の区切り線です。アイテムをグループ化したいときにセパレーターを使います。

アイテムの場合、各プロパティーは次のような意味です。

```javascript
{
    type: "item", //固定。アイテムを指定しているいうことを表す
    label: "Alert", //ラベル。コンテキストメニューにはこのテキストが表示される
    callback: () => { //コールバック関数。アイテムがクリックされたときに実行される。省略可能
        alert("Clicked!");
    }
}
```

また、セパレーターの場合、次のようになっています。

```javascript
{
    type: "separator" //固定。セパレーターを指定しているということを表す
}
```

セパレーターは``type``以外の他のプロパティーを指定しても無視されます。

使い方はこんな感じです。ほかにも、インスタンスの作成後にアイテムやセパレーターを追加する関数もあります。詳細はドキュメントを確認してください。

## カスタマイズ

CSS変数で見た目をカスタマイズできます。

| プロパティー名        | デフォルト値                                                                 | 説明                                 |
| :-------------------- | :--------------------------------------------------------------------------- | :----------------------------------- |
| --mc-text-color       | ``#333333`` (ダークモードのときは``white``)                                  | コンテキストメニューの文字色         |
| --mc-background-color | ``rgba(255, 255, 255, 0.7)`` (ダークモードのときは``rgba(51, 51, 51, 0.7)``) | コンテキストメニューの背景色         |
| --mc-corner-radius    | ``0.25em``                                                                   | コンテキストメニューの角の丸みの半径 |
| --mc-font-family      | ``sans-serif``                                                               | フォント                             |

## 更新履歴

### 2023/02/18

modernContext.jsのv2.0リリースとnpmパッケージの公開に合わせて、記事を更新しました。なお、v2.0はv1系との互換性はありませんので、ご注意ください。