次世代プラグイン開発環境【UXP】CEP時代から悩まされていたカラーテーマのライト・ダーク切り替え問題がついに解決した!

先日「トプリクス for Photoshop」をリリースし、続きInDesign版を着手したところ何故かカラーテーマを切り替えてもうまくいかないゾ?となったのでいろいろ問題点を試行錯誤して解決してみました。


まずはこんな感じでPhotoshop Pluginのテンプレート「quick-layers-starter」からPhotoshop・InDesign両用のサンプルを作成しました。

HTML

<!DOCTYPE html>
<html>
<head>
    <script src="main.js"></script> 
    <link rel="stylesheet" href="styles.css">  
</head>
<body>
  <h1 id="title">Layers</h1>
  <sp-body id="layers">
    No layers
  </sp-body>
  <footer>
    <div id="layerIcon"></div>
  </footer>
</body>
</html>

CSS

body {
    padding: 0 16px;
}
li:before {
    content: '• ';
    width: 3em;
}
#layers {
    border: 1px solid #808080;
    border-radius: 4px;
    padding: 16px;
}
h1{
    color: var(--uxp-host-text-color);
    border-radius: 10px;
    padding: 10px;
}
#layerIcon{
    width: 32px;
    height: 32px;
    margin-right: 5px;
    background-image: url("layer/dark.png");
}
#layerIcon:hover{
    background-image: url("layer/light.png");
}
#layerIcon:active{
    background-image: url("layer/dark.png");
}

javascript

const {entrypoints} = require("uxp");
const APID=require("uxp").host.name;
entrypoints.setup({
    panels: {
        vanilla: {
            show(node) {
            }
        }
    }
});
document.getElementById("layerIcon").addEventListener("click",async function(){
    let allLayerNames;
    if(APID=="InDesign"){
        const allLayers = require("indesign").app.activeDocument.layers;
        let al=[];
        for(let l=0;l<allLayers.length;l++){
            al.push(allLayers.item(l).name);
        }
        allLayerNames = al.map(layer => layer);
    }else{
        const app = require("photoshop").app;
        const allLayers = app.activeDocument.layers;
        allLayerNames = allLayers.map(layer => layer.name);
    };
    const sortedNames = allLayerNames.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
    document.getElementById("layers").innerHTML = `
      <ul>${
        sortedNames.map(name => `<li>${name}</li>`).join("")
      }</ul>`;
});

※manifest.jsonは割愛
改変したところはInDesign対応にしたのとh1タグを使用、ボタンを画像にしたところです。これをデバッグしてみます。まずはPhotoshop

文字のカラーはちゃんと切り替わります。もちろんこのままでは画像は切り替わりません。でもなんで画像がギザギザ?。
お次はInDesignでデバッグ

bodyタグ内にあるh1タグの色が変更されない…。まぁsp-bodyタグ内に配置すればいいんですがね。

スポンサーリンク

まずテーマの切り替えを検知してみた

実は「トプリクス for Photoshop」ではテーマの切り替えを検知して画像を切り替えたりしていました。今回のInDesign用に書くとこんな感じです。

javascript

document.theme.onUpdated.addListener(async(theme)=>{
    const btElement=document.getElementById("layerIcon");
    const h1Element=document.getElementById("title");
    if(theme=="light" || theme=="lightest"){
        h1Element.style.color="#424242";
        btElement.style.backgroundImage='url("layer/light.png")';
    }else{
        h1Element.style.color="#ffffff";
        btElement.style.backgroundImage='url("layer/dark.png")';
    }
});

しかし、これだと起動時にどのテーマか分からないのでエラいことになります。それにhover・activeの設定がよくわかりません。動かすとこんな感じです。

一度でも切り替えすれば、上手くいきます。「トプリクス for Photoshop」では切り替えた時のテーマをローカルに保存して次回以降上手くいくようにしていました。

var(–uxp-host-text-color)が効かない問題

まぁまず前提としてUXPでは「Spectrum UXP widgets」というのがありまして頭に「sp」がつくやつです。「sp-label」とか「sp-body」とかですね。
こやつら使用するとテーマを切り替えても問題なく上手いことやってくれます(サンプルのレイヤー名のとこですな)。
しかし「トプリクス」ではツリー表示をするために「aタグ」やら何やらを使用しており「sp」を使用できないのです。
もしかしたら「sp-body」内に作成するようにすれば行けたかもしれませんが…。とにかくInDesign版は何故か

CSS

color: var(--uxp-host-text-color);

が効かないので、起動時に現在のテーマをチェックできないか調べたところ見つからず…。しかし意外なところに解決策はありました。

それはCSSでした

なんと公式の「CSS Reference」のところに「prefers-color-scheme」というモノがありテーマに合わせてCSSで使用できる変数を定義できたのです。
Photoshopで使用できる「–uxp-host-text-color」もデフォルトでこういう感じで定義されていたのか!
ということで今回のサンプルだと

CSS

:root {
    --uxp-host-font-size: 13px;
    --uxp-host-font-size-smaller: 12px;
    --uxp-host-font-size-larger: 14px;
    --uxp-host-text-color: #ffffff;
    --uxp-host-border-color: #454545;
    --uxp-host-background-color: #535353;
    --layer-png: url("layer/dark.png");
    --layer-hover-png: url("layer/light.png");
}
@media (prefers-color-scheme: darkest) {
    :root {
        --uxp-host-text-color: #ffffff;
        --uxp-host-border-color: #292929;
        --uxp-host-background-color: #323232;
        --layer-png: url("layer/dark.png");
        --layer-hover-png: url("layer/light.png");
    }
}
@media (prefers-color-scheme:light) {
    :root {
        --uxp-host-text-color: #424242;
        --uxp-host-border-color: #9c9c9c;
        --uxp-host-background-color: #b8b8b8;
        --layer-png: url("layer/light.png");
        --layer-hover-png: url("layer/dark.png");
    }
}
@media (prefers-color-scheme: lightest) {
    :root {
        --uxp-host-text-color: #4b4b4b; 
        --uxp-host-border-color: #d1d1d1;
        --uxp-host-background-color: #f0f0f0;
        --layer-png: url("layer/light.png");
        --layer-hover-png: url("layer/dark.png");
    }
}

こういう感じでrootに定義しました。ちなみに画像以外の定義はPhotoshopのデフォルトを調べて定義しているのでご参考にどうぞ。
使い方はこんな感じです。

CSS

h1{
    color: var(--uxp-host-text-color);
    border-radius: 10px;
    padding: 10px;
}
#layerIcon{
    width: 32px;
    height: 32px;
    margin-right: 5px;
    background-image: var(--layer-png);
}
#layerIcon:hover{
    background-image: var(--layer-hover-png);
}
#layerIcon:active{
    background-image: var(--layer-hover-png);
}

そいつを動かすとこんな感じで切り替えが完璧に動作します。

やっと機能開発に専念できる…

これでやっと安心して眠れます。じゃなくてインターフェース関係にストレスがちょっと減って機能開発に重点がおけます。良かった…。
完成したサンプルコードをgitHubのコチラに上げておきました。ご自由にお使いください。

スポンサーリンク

スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です