Skip to content

fartinmartin/extendscript-ui

Repository files navigation

extendscript-ui

JSX templating for ScriptUI/ExtendScript

Have you ever wanted to compose ScriptUI with JSX-like syntax, like so:

<dialog text="Neat!" properties={{ closeButton: true }}>
  <button text="Click me!" size={[100, 200]} onClick={() => alert("Doink!")} />
</dialog>

Well, now you can! Plus, TypeScript will guide you through each prop with auto completions!

You can even create functional components:

const Header = ({ text }: { text: string }) => (
  <group orientation={"row"} alignChildren={"fill"}>
    <static-text text={text}></static-text>
  </group>
);

const ui = (
  <dialog text="Could it be?!" properties={{ resizeable: true }}>
    <Header text="Neat!" />
  </dialog>
);

Try it

Tip

For a super basic example, check out /examples/basic!

Prerequisites

You'll need TypeScript and a bundler for your code. Here are some ExtendScript starters with TypeScript support to check out:

Installation

npm i extendscript-ui

Configuration

Update your tsconfig.json:

{
  "compilerOptions": {
    // ...your other config options, then:
    // tell TypeScript how to find extendscript-ui's jsx.d.ts declarations:
    "typeRoots": ["./node_modules/extendscript-ui/dist"],
    "types": ["types/jsx.d.ts"],
    // tell TypeScript how to transform your JSX code and the name of the jsxFactory fn to use when doing so:
    "jsx": "react",
    "jsxFactory": "jsx" // this is the fn that extendscript-ui exports!
  }
  // ...any other options
}

Usage

Be sure to use .tsx files for JSX syntax highlighting. Import jsx to satisfy TypeScript and for code completion:

// index.tsx
import { jsx } from "extendscript-ui";

export const ui = (
  <dialog text="Neat!" properties={{ closeButton: true }}>
    <button text="Click me!" onClick={() => alert("Doink!")} />
  </dialog>
);

You can create custom components too:

const Header = ({ text }: { text: string }) => (
  <group orientation={"row"} alignChildren={"fill"}>
    <static-text text={text}></static-text>
  </group>
);

// later

const ui = (
  <dialog text="Neat!" properties={{ resizeable: true }}>
    <Header text="Could it be?!" />
    // other stuff...
  </dialog>
);

Use renderSpec to render your template. This will create a Window and wire up your onClick events. It will then return an object with your Window as well as a cleanup fn:

import { renderSpec } from "extendscript-ui";

const { window, destroy } = renderSpec(ui);
window.show();

Warning

The renderSpec API might evolve, but it's functional for now...

How?

extendscript-ui uses a custom jsxFactory to transform JSX into a ScriptUI Resource Specifications-compliant string. This string is passed to new Window(specString) to build the UI. Once the UI is built, renderSpec adds any event handlers to the created UI elements.

TODO

  • Test/add more ScriptUI functionality beyond onClick...
  • More type safety:
    • renderSpec should only accept specString with a root of type Window
    • remove type attribute since it's defined by tag (generally, make sure all attrs are cleaned up)
  • Figure out TreeView | ListBox | DropDownList rendering
  • Default text nodes to text attr and/or <static-text/>? e.g <button>hello!</button> === <button text="hello!"/>
  • ProgressBar helpers, etc?
  • Look up how to auto import jsx, though this may just be documentation/guidance rather than a feature as it will probably depend on user's build setup?
  • Likely other things I've not thought of...

About

JSX templating for Adobe ScriptUI/ExtendScript

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published