This starter is an example of a UXP plugin that uses React and Spectrum Web Components (SWC) to support the changing UI brightness in Photoshop.
It is adapted from Photoshop React-based SWC starter plugin (since UXP v7.3), with modifications to avoid errors and to make it easier to create a new plugin. The usage is almost the same as that.
Pre-requisites
- NodeJS (>= v 16.0.0)
- Yarn package manager
- UXP Developer Tool (UDT)
- UXP >= 7.3
Build and run
- Start by installing the dependencies
yarn install
. - Prepare the bundle using Webpack
yarn build
. You will notice a dist folder after this step. - (Optional)
yarn watch
to automatically build the project every time you update a source file andyarn start
to keep the plugin running and automatically build after every change.
Load the plugin into the application via UDT
- Make sure the application is running and you can see it under 'Connected apps'.
- Click on 'Add Plugin' button and select the
manifest.json
of this plugin. - Configure the
dist
folder of your plugin by using 'More' -> 'Advanced' option from the action menu•••
- Click on the ••• menu on the corresponding plugin row. Select 'Load' to view the plugin inside your application.
- (Optional) Select 'Watch' from plugin actions ••• to dynamically load the latest plugin changes. Note that a manifest change would need you to 'Unload' and 'Load' the plugin from scratch.
You should be able to see a banner in Photoshop plugin.
This repository has been modified by sttk3 from the original. The main changes are as follows.
When generating source maps, use a configuration without "eval" to prevent errors, for example "cheap-source-map".
webpack.config.js
devtool: (mode === "production") ? false : "cheap-source-map",
Modules such as uxp and photoshop must be made externally dependent.
webpack.config.js
externals: {
uxp: 'commonjs2 uxp',
photoshop: 'commonjs2 photoshop',
os: 'commonjs2 os',
fs: 'commonjs2 fs',
},
- host is an object, not an array. Maybe in the future it should be an array, but for now it is not necessary
- minVersion is "24.4" instead of "24.4.0"
manifest.json
"host": {
"app": "PS",
"minVersion": "24.4"
},
Change "request"
to "fullAccess"
if the plugin requires full access to the file. Since the property is already written, it is easy to edit.
manifest.json
"requiredPermissions": {
"localFileSystem": "request"
},
Icons that do not change color for plugin, and icons that change color in two steps (dark and light) for panels are provided.
Folder
swc-uxp-react-theme
├── icons
│ ├── dark-panel@1x.png
│ ├── dark-panel@2x.png
│ ├── light-panel@1x.png
│ ├── light-panel@2x.png
│ ├── plugin@1x.png
│ └── plugin@2x.png
webpack.config.js
{
from: "icons",
context: resolve("./"),
to: resolve("dist/icons"),
},
manifest.json
"icons": [
{
"width": 48, "height": 48, "path": "icons/plugin.png", "scale": [ 1, 2 ],
"theme": [ "darkest", "dark", "medium", "light", "lightest" ],
"species": [ "pluginList" ]
}
],
manifest.json
"icons": [
{
"width": 23, "height": 23, "path": "icons/dark-panel.png", "scale": [ 1, 2 ],
"theme": [ "darkest", "dark", "medium" ], "species": [ "chrome" ]
},
{
"width": 23, "height": 23, "path": "icons/light-panel.png", "scale": [ 1, 2 ],
"theme": [ "light", "lightest" ], "species": [ "chrome" ]
}
]
Use entrypoints.setup
to specify both panels and commands.
index.js
entrypoints.setup({
commands: {
showCurrentTheme: showCurrentTheme,
},
panels: {
themePanel: {
create,
show,
},
},
}) ;
manifest.json
{
"type": "command",
"id": "showCurrentTheme",
"label": {
"default": "Show Current Theme"
}
}
Add functions to capture theme changes and to get the current theme name, respectively.
App.jsx
const App = () => {
const [colorTheme, setColorTheme] = useState('dark') ;
const handleThemeChanged = (theme) => {
setColorTheme(theme) ;
} ;
useEffect(() => {
// apply current color theme on componentDidMount
(async () => {
setColorTheme(await getColorTheme()) ;
})() ;
// add an listener for theme on componentDidMount
document.theme.onUpdated.addListener(handleThemeChanged) ;
return () => {
// remove an listener for theme on componentDidUnmount
document.theme.onUpdated.removeListener(handleThemeChanged) ;
} ;
}, []) ;
theme.js
/**
* get current color theme of photoshop.
* reference: https://gist.github.com/tokyosheep/24403f1fe1d5fcda54f8267e14c619f6
* @return {Promise<'darkest'|'dark'|'light'|'lightest'>}
*/
export const getColorTheme = async () => {
const result = await action.batchPlay(
[
{
"_obj": "get",
"_target": [
{"_property": "kuiBrightnessLevel"},
{
"_ref": "application",
"_enum": "ordinal",
"_value": "targetEnum",
},
],
"_options": {"dialogOptions": "dontDisplay"},
},
],
{}
) ;
const brightnessKey = result[0].kuiBrightnessLevel._value ;
const brightnessTable = {
'kPanelBrightnessDarkGray': 'darkest',
'kPanelBrightnessMediumGray': 'dark',
'kPanelBrightnessLightGray': 'light',
'kPanelBrightnessOriginal': 'lightest',
} ;
const colorTheme = brightnessTable[brightnessKey] || 'dark' ;
return colorTheme ;
} ;
This color varies in density depending on Theme (sp-theme) of SWC. It is better to use instead of --uxp-host-text-color
.
App.jsx
<p
style={ {
color: 'var(--spectrum-gray-800)',
marginBottom: '8px',
} }
>
Text
</p>