Skip to content

Selectors

You can’t import Web UI’s components and hooks directly. Use these selectors to get them instead.

Returns Web UI’s React components.

getComponents(): Components

Use the components to build your own interface, or decorate this selector to replace one with your own.

Example
const { getComponents } = getSelectors();
const { App, InkCanvas } = getComponents();

Returns Web UI’s React hooks.

getHooks(): Hooks
Example
const { getHooks } = getSelectors();
const { useLayers } = getHooks();

Returns the interface text for a key, in the reader’s text language.

getI18nValue(context: {
key: string;
values?: Record<string, number | string>;
}): { value: string }

Looks up the key in Web UI’s own translations, first for the reader’s text locale, then for en-US. A key with no entry is returned as written, so a plain sentence works as its own key.

Each {{name}} in the text is replaced with values[name]. A placeholder with no value is left as written.

To add translations, see interface text.

Example
const { getI18nValue } = getSelectors();
const { value } = getI18nValue({ key: "button", values: { index: 20 } });
// "Button 20"

Returns the component that wraps a menu. By default, returns MenuPanel for every menu.

getMenuComponent(context: { schema: MenuSchema }): { component: unknown }

Decorate it to use your own component for a menu.

Example
decorateSelector("getMenuComponent", (context, next) => {
if (context.schema.name !== "journal") return next(context);
return { component: JournalMenu };
});

Returns the component for a menu field. By default, Web UI provides a component for each field type.

getMenuFieldComponent(context: { field: MenuField }): { component: unknown }

The component receives props built from the field. Every field gets name, and label: the field’s text in the reader’s language. The other props depend on the field’s type:

Field typeProps
booleanvalue: boolean, setValue(newValue: boolean)
numbervalue: number, setValue(newValue: number), minimum?, maximum?, step?
stringvalue: string, setValue(newValue: string)
enumvalue: string, setValue(newValue: string), options: Array<{ label: string; value: string }>
buttonaction(): Promise<void>
bindingvalue: Array<string>, setValue(newValue: Array<string>), labels: Array<string>, collisions: Array<string>, captureInput(request: CaptureInputRequest)
separatorOnly name and label

value is always current. The prop types are exported from @inkweaverdev/plugin-web-ui/plugin as MenuBooleanFieldProps, MenuEnumFieldProps, and so on.

value and labels go by position. The first two entries are keyboard or mouse inputs, and the third is a gamepad button.

PropDescription
labelsThe text to show for each input in value. Gamepad buttons are labeled for the first connected controller (Xbox, PlayStation, or Nintendo), or with a generic label if none is connected, through getI18nValue. Other inputs show as written.
collisionsThe inputs in value that another binding in the same scope also uses. These don’t run.
captureInputOpens a dialog that records the reader’s next input.
type CaptureInputRequest = {
type: "gamepad" | "keyboard-mouse";
onClear?: () => void;
onInput: (input: string) => void;
};
FieldDescription
typeWhat to record. "keyboard-mouse" records a key or a click, and "gamepad" records a gamepad button.
onInputCalled with the recorded input.
onClearIf provided, the dialog shows a Clear button that calls it.

In the dialog, Tab moves between buttons, so it can’t be recorded. A modifier key on its own waits for the rest of the key combination.

Example
function Toggle({ label, setValue, value }) {
return (
<button onClick={() => setValue(!value)} type="button">
{label}: {value ? "On" : "Off"}
</button>
);
}
decorateSelector("getMenuFieldComponent", (context, next) => {
if (context.field.type !== "boolean") return next(context);
return { component: Toggle };
});