@phantomclient/plugin/vue
Composables for reaching Phantom from a component, and Phantom’s own components, for building a plugin’s pages, panels and command views. Building UI with Vue shows them in use. This list is generated from the source when the site builds.
import { usePlugin, usePhantom, useGames, usePreferences, useConfig, useSnags, useAutomation, useKept, useAutomations, useThemeMode, Preferences, Avatar, Badge, Button, Callout, Checkbox, EmptyState, FieldFrame, InfoTip, Input, PageHeader, SegmentedControl, Select, Spinner, Switch, Tooltip } from '@phantomclient/plugin/vue';Composables
Each reads the frame’s reactive state, so a component using one re-renders when Phantom changes it.
usePlugin
usePlugin() => PluginContextThe plugin's context, as setup and commands get it: usePlugin().toast('Saved'). Its games(), granted and preferences are reactive, so a computed reading them follows them.
usePhantom
usePhantom(id?: string | undefined) => PluginPhantomOne game, as the SDK reaches it: const { aj } = usePhantom(); (await aj.room.current())?.name. Without an id, the game this view works with (a panel's, a command view's); a page names one from useGames(). What it starts goes when the view does.
useGames
useGames() => ComputedRef<readonly PluginGameView[]>The games this view may work with, as they are now, following every change Phantom sends.
usePreferences
usePreferences() => ComputedRef<Readonly<Record<string, PreferenceValue>>>What the player set in the plugin's preferences, following their changes.
useConfig
useConfig() => ComputedRef<Readonly<Record<string, PreferenceValue>>>The plugin's settings, typed as ctx.config is, following their changes: for the game this view is bound to, a player's own values over the plugin's.
useSnags
useSnags() => ComputedRef<readonly PluginSnag[]>What the plugin has said it cannot do, as it stands (ctx.snag), following every change.
<Preferences /> shows each beside the preference of the same name, so most plugins need this only to draw a snag of their own somewhere else.
useAutomation
useAutomation<Notes extends AutomationNotes = AutomationNotes>(automation: string, game?: string | undefined) => ComputedRef<AutomationStatus<Notes> | null>Where one of the plugin's automations has got to, and what its run has written down, following every change (definePlugin's automations).
This is what a panel draws instead of keeping a second copy of the run's state in the plugin's storage and reading it on a timer. notes here is the very object the loop has in hand, so the panel cannot disagree with the run about how many sweets it has counted.
Without a game it reads the one this view works with, which is a panel's own game; a page names one from useGames(). Null where Phantom is not supervising it, which is the plugin's code not running on that game yet.
const run = useAutomation<{ sweets: number }>('sweets');
const sweets = computed(() => run.value?.notes.sweets ?? 0);useKept
useKept<Value extends KeptShape>(name: string, starting: Value, game?: string | undefined) => ComputedRef<Value>What the plugin keeps under a name, following every change (ctx.keep).
A panel reads it rather than keeping a copy of its own: this is the very value the plugin's background code has in hand, so the two cannot drift apart, and the panel needs no timer. A supervised automation's notes are kept under automation:<id>, which forAutomation names.
starting is what it reads before the plugin's background code has said anything, so a panel never has to deal with undefined on its first draw.
const notes = useKept('advertiser', { said: 0 });
const said = computed(() => notes.value.said);useAutomations
useAutomations() => ComputedRef<readonly AutomationStatus[]>Every automation of the plugin Phantom is supervising, for a page that lists them all.
useThemeMode
useThemeMode() => ComputedRef<"light" | "dark">The theme's mode, for the rare drawing that needs it; colours come from the tokens.
Components
The components the app itself uses. Each follows the theme through the --phantom-* colour tokens, so it works in light, dark and any theme the player picks.
Preferences
The plugin's own preferences, drawn by Phantom inside the plugin's own panel or page.
Props
| Prop | Type | Default | |
|---|---|---|---|
group | string | undefined | Only the fields under this group, for a panel that lays its sections out itself. |
game | string | undefined | Which game's player the player scoped preferences belong to; the bound one by default. |
omit | readonly string[] | undefined | Settings left out by name, for a panel that draws one of them its own way. |
Avatar
Someone's picture, round: their image when there is one and it loads, else the first letters of their name on a grey disc, so a list of people never has gaps where pictures failed.
Props
| Prop | Type | Default | |
|---|---|---|---|
name required | string | Whose it is: its first letters stand in when there is no image, and it names the image. | |
imageUrl | string | null | null | The picture's address. Null, or one that fails to load, shows the initials instead. |
size | "sm" | "md" | "lg" | "xl" | 'md' | 24, 32, 40 or 64 pixels across. |
Badge
A short label in a tinted fill: a state, such as a game that is playing or stopped, or a kind of thing, such as a plugin or a script. Use a tone for a state and a hue for a kind.
Props
| Prop | Type | Default | |
|---|---|---|---|
tone | "neutral" | "success" | "warning" | "danger" | "info" | "blue" | "violet" | "aqua" | "orange" | "magenta" | 'neutral' | A state (neutral, success, warning, danger, info), or a hue that names a kind of thing rather than a state (blue, violet, aqua, orange, magenta). |
dot | boolean | false | A dot of the tone before the words, for a live state such as a game that is playing. |
size | "sm" | "md" | 'md' | sm is the tag at the end of a dense row, such as an account's on a saved account or primary beside an index: small enough not to outweigh the name it follows. |
quiet | boolean | false | The everyday state, such as an account that is active: the tone as a dot only, beside the word in grey. A column where most rows say the same thing is then quiet, and the rows that say something else, in a full colour, stand out. |
Slots
default
Button
A button, or a link drawn as one when it has an href. Its words say what pressing it does; an icon on its own needs an aria-label.
Props
| Prop | Type | Default | |
|---|---|---|---|
variant | "success" | "danger" | "primary" | "secondary" | "outline" | "ghost" | 'primary' | How much it stands out: primary for the one main action, secondary and outline beside it, ghost for quiet ones in toolbars and rows, danger for what cannot be undone, success to confirm. |
size | "sm" | "md" | "lg" | "xl" | "xs" | 'md' | From xs in a dense row to xl for the one action on an empty page. |
disabled | boolean | false | Shown but not pressable. |
loading | boolean | false | A spinner in place of the icon while the action runs; it cannot be pressed meanwhile. |
icon | Component | A Lucide icon before the words, or alone for an icon button (give it an aria-label). | |
iconRight | Component | A Lucide icon after the words, such as an arrow. | |
type | "button" | "submit" | "reset" | 'button' | The <button>'s own type: submit in a form's main button. |
fullWidth | boolean | false | As wide as the space it is in. |
href | string | Where it goes, for a button that is a link: it is drawn as an <a> with the same look, so a page's links and buttons match. Without one it is a <button>. | |
shortcut | string | The keys that do the same, written inside the button after its words ("Run Ctrl Enter"), as they are said, with spaces between keys. A shortcut belongs to its button, never in a cap floating beside it. |
Events
| Event | Payload | |
|---|---|---|
click | [e: MouseEvent] | Pressed. Not sent while it is disabled or loading. |
Slots
default
Callout
A message that belongs to the page it is on rather than floating over it as a toast: why a game could not be started, or that a plugin was installed.
Props
| Prop | Type | Default | |
|---|---|---|---|
tone | any | 'neutral' | What kind of message: danger is also announced as an alert. |
icon | Component | undefined | A Lucide icon at the start. Each tone has one of its own when this is left out. |
Slots
default
Checkbox
A box to tick, for picking items out of a list or a choice that is saved with a form, drawn in Phantom's colours rather than the platform's bright white square. A choice that takes effect as it is flipped is a Switch. A real checkbox underneath keeps the keyboard, labels and screen readers working as they always do.
Props
| Prop | Type | Default | |
|---|---|---|---|
modelValue required | boolean | Whether it is ticked, for v-model. | |
label | string | undefined | What it ticks, for screen readers when no visible label is in the slot or around it. |
indeterminate | boolean | false | Drawn with a dash, for a box standing for several others that are partly ticked. |
disabled | boolean | false | Shown but not tickable. |
block | boolean | false | With a slot: the row takes the full width it is given. |
align | "center" | "start" | 'center' | With a slot: start keeps the box by the first line of a label that runs to several. |
id | string | undefined | An id for the checkbox itself, for a <label for> elsewhere. |
Events
| Event | Payload | |
|---|---|---|
update:modelValue | [value: boolean] | Ticked or unticked, with whether it is now ticked, for v-model. |
Slots
default
EmptyState
Where content would be, when there is none yet or none to show: a line saying why, and what to do about it in the slot (a button, a hint). A dashed outline marks it as a place rather than a message, as the dashboard's widgets do when they have nothing in range.
Nobody here
Nobody else is in this room.
No games yet
Allow the plugin on a game in Plugins, then open it.
Props
| Prop | Type | Default | |
|---|---|---|---|
title required | string | What is empty, in a few words: "No games yet". | |
description | string | undefined | What to do about it, in a sentence. |
icon | Component | undefined | A Lucide icon above the words. |
size | "sm" | "lg" | 'sm' | sm inside a panel or list; lg for a whole page that has nothing yet. |
plain | boolean | false | No outline, for a place that already has one: an empty chart inside its card, an empty table inside its panel. |
variant | "quiet" | "framed" | undefined | Quiet (no outline, small icon) or framed (dashed outline, icon on a tile). |
Slots
default
FieldFrame
What goes around every form control, so an Input, a Textarea and a Select line up and read the same: the label, an "i" whose tooltip says what the label has no room for, "Optional" where most of a form is needed, the control itself, and a line under it with help or with what is wrong.
Props
| Prop | Type | Default | |
|---|---|---|---|
for required | string | The control's id, which the label is for. | |
label | string | undefined | The words above the control. |
info | string | undefined | What the field is for, in a tooltip on an "i" beside the label. |
optional | boolean | false | Says "Optional" beside the label, for a form where most fields are needed. |
hint | string | undefined | A line of help under the control. |
error | string | null | undefined | What is wrong with the value, shown under the control in place of the hint. |
disabled | boolean | false | Greys the label along with a disabled control. |
Slots
label · default
InfoTip
A small "i" beside a field's label that says more about the field when pointed at or focused: what it is for, what format it takes, where the value comes from. The label stays short and the explanation is one step away, for whoever needs it.
Props
| Prop | Type | Default | |
|---|---|---|---|
text required | string | What the tooltip says. | |
label | string | The field it is about, for the button's name: "About Password". |
Input
A text field: its label, an icon for what it holds, the box, and a line under it for help or for what is wrong.
Only you can see it.
There is no room by that name.
Props
| Prop | Type | Default | |
|---|---|---|---|
modelValue | InputValue | '' | The value, for v-model. |
id | string | undefined | The field's id, which its label points at. One is made when it is left out. |
label | string | undefined | The words above the box. |
type | "number" | "text" | "email" | "password" | "search" | "tel" | "url" | "date" | 'text' | The <input>'s type. A password field has a button to show what was typed. |
placeholder | string | undefined | A hint inside the empty box, such as an example of what goes in it. |
icon | Component | undefined | A Lucide icon inside the box, at the start. |
disabled | boolean | false | Shown but not editable. |
required | boolean | false | Must be filled in for its form to be sent. |
suggestions | readonly string[] | undefined | Values offered as it is typed in, any of which can still be typed over. |
size | "sm" | "md" | "lg" | "xs" | 'md' | sm for a field inside a dense grid, such as a table's columns; lg for a field that stands on its own on a page, such as a sign in form. xs is the compact field of a row of words and fields, such as a plugin's settings row. |
hint | string | undefined | A line of help under the box. |
error | string | null | undefined | What is wrong with the value, shown under the box in place of the hint. |
info | string | undefined | What the field is for, in a tooltip on an "i" beside the label. |
optional | boolean | false | Says "Optional" beside the label, for a form where most fields are needed. |
Events
| Event | Payload | |
|---|---|---|
update:modelValue | [value: InputValue] | Each change, as it is typed, for v-model. |
Slots
label · trailing
PageHeader
The single entry point at the top of a page.
Room watch
Rooms
Each game Room watch runs on, and where it is.
Props
| Prop | Type | Default | |
|---|---|---|---|
title required | string | The page's name, as its heading. | |
eyebrow | string | undefined | A word or two above the title, such as the section the page is in. |
description | string | undefined | What the page is for, in a sentence under the title. |
Slots
actions · tabs
SegmentedControl
A row of mutually exclusive choices, where the selected one is a filled pill.
Props
| Prop | Type | Default | |
|---|---|---|---|
modelValue required | string | The chosen option's value, for v-model. | |
options required | SegmentedOption[] | The choices, each a value and the label shown for it. | |
variant | "pill" | "underline" | 'pill' | A sliding pill behind the chosen one, or a line under it, as tabs have. |
size | "sm" | "md" | 'md' | sm in a toolbar or card header; md elsewhere. |
track | boolean | false | A track behind the pills, so the control reads as one thing to choose from rather than a row of words. For a choice that stands on its own, such as a setting. |
block | boolean | false | Fills the width it is given, each choice taking an equal share of it. |
Events
| Event | Payload | |
|---|---|---|
update:modelValue | [value: string] | The value of the option chosen, for v-model. |
Select
A dropdown drawn by Phantom rather than the browser: the field shows the chosen option with a chevron, and opens a list of the choices with a tick beside the chosen one. A native <select> can only be styled while shut; its open list is the operating system's, a white menu in the middle of a dark app.
Props
| Prop | Type | Default | |
|---|---|---|---|
modelValue required | SelectValue | The chosen option's value, for v-model. | |
options | readonly SelectOption<SelectValue>[] | undefined | The choices. Without them, the <option> children are read instead. |
ariaLabel | string | undefined | Names the field for screen readers when there is no label. |
label | string | undefined | Written above the field, as Input writes its label, so forms line the two up. |
info | string | undefined | What the field is for, in a tooltip on an "i" beside the label, as Input's. |
hint | string | undefined | A line of help under the field. |
error | string | null | undefined | What is wrong with the choice, in place of the hint. |
optional | boolean | false | Says "Optional" beside the label. |
icon | Component | undefined | A lucide icon at the start of the field, as Input has. Not drawn on a ghost dropdown. |
disabled | boolean | false | Shown but cannot be opened. |
placeholder | string | 'Choose one' | Shown when the value matches no option. |
size | "sm" | "md" | "lg" | 'md' | sm for a toolbar or a dense row, md in a form, and lg for a page's main control, as tall and round as the website's buttons. |
variant | "ghost" | "default" | 'default' | ghost draws no box, only the words and the chevron in the colour around it, for a dropdown that is part of a sentence or a toolbar rather than a field in a form. |
id | string | undefined | An id for the field itself, for a <label for> outside it. |
Events
| Event | Payload | |
|---|---|---|
update:modelValue | [value: SelectValue] | The value of the option chosen, for v-model. Not sent when the chosen one is picked again. |
Spinner
Something is on its way: the turning circle shown beside "Loading" and in a busy button. It takes the colour of the text around it, and a caller adds shrink-0 or a tone as it would to any icon. The size is the icon's, in pixels, as Lucide's are.
Props
| Prop | Type | Default | |
|---|---|---|---|
size | number | 13 | Its width and height, in pixels. |
Switch
An on/off switch, for a choice that takes effect as it is flipped. A real checkbox underneath, so a <label> around its row flips it from anywhere on the row, and the keyboard and screen readers treat it as the switch it is.
Props
| Prop | Type | Default | |
|---|---|---|---|
modelValue required | boolean | Whether it is on, for v-model. | |
label | string | undefined | What it turns on, for screen readers when no visible label is around it. |
disabled | boolean | false | Shown but not flippable. |
Events
| Event | Payload | |
|---|---|---|
update:modelValue | [value: boolean] | Flipped, with whether it is now on, for v-model. |
Tooltip
A few words about the thing under the pointer, beside it: its name, what it does, and a note in amber when there is a catch, such as the plan it needs. It is fixed to the window in a portal, so a list that scrolls or clips never cuts it off, and it takes no clicks.
Props
| Prop | Type | Default | |
|---|---|---|---|
at required | { top: number; left: number; } | null | Where it points from, in window pixels. Null hides it. | |
title required | string | The thing's name, in bold. | |
description | string | undefined | What it does, in a sentence. |
note | string | undefined | A catch, in amber, such as the plan it needs. |
place | "beside" | "below" | 'beside' | Beside the thing, or under it. |
Helpers
tooltipBeside: where to put aTooltipbeside the element it is about. Pass the element and it gives theatprop.