Tray

Create a tray icon
const tray = ctx.newTray({
tooltipText: "My plugin",
iconUrl: "https://seanime.rahim.app/logo_2.png",
withContent: true,
})
Add a badge
tray.updateBadge({ number: 1, intent: "alert" })
// Remove the badge
tray.updateBadge({ number: 0 })
intent
: "alert" | "info" | "warning" | "success"
Rendering content
The state
is a mechanism to keep track of variable data over time, enabling components to re-render automatically when the data changes.
The render()
function is used to define how content should be presented in the tray popover. It takes a callback function that returns a tree of components.
Components, like tray.text
and tray.button
, are reusable building blocks of the UI, each responsible for rendering a piece of the interface according to the current state.
The tray will be re-rendered anytime there is a state change even if the state isn't in the render function.
const count = ctx.state(0);
ctx.setInterval(() => {
count.set(c => c + 1);
}, 1000);
tray.render(() => {
return tray.stack({
items: [
tray.text(`Count: ${count.get()}`),
// Show the button when the count reaches 5
count.get() >= 5
? tray.button("Click me", { onClick: "button-clicked" })
: trat.text("Nothing here")
],
})
})
Tray events
tray.onOpen(() => {
// User opened the tray content
})
tray.onClose(() => {
// User closed the tray content
})
tray.onClick(() => {
// User clicked the tray icon
})
// Open the tray
// This will not work on the first page load or if the plugin is not pinned
tray.open()
// Close the tray
tray.close()
// Force the tray content to update
// Not useful is most cases because the tray updates when states change
tray.update()
Event handlers
You can register functions to specific event triggers like onClick
using ctx.registerEventHandler()
in order to define custom behaviors based on user action.
//..
ctx.registerEventHandler("reset-counter", () => {
count.set(0)
})
tray.render(() => {
return tray.stack({
items: [
tray.text(`Count: ${count.get()}`),
tray.button("Reset counter", { onClick: "reset-counter" }),
],
})
})
Tips
You can register inline event handlers. Make sure the first argument is unique to that element.
tray.stack(allItems.map((item) => {
return tray.flex([
tray.text(key),
tray.button({
label: "Open",
size: "sm",
// It takes a unique ID key as first argument!
onClick: ctx.eventHandler(item.id, () => {
// Do something...
}),
intent: "gray-subtle"
}),
], { gap: 1, style: { alignItems: "center" } })
}))
Layout components
tray.div([], { style: {} })
tray.stack([], { style: {} })
tray.flex([], { style: {} })
Fields/Forms
Field components:
input
button
select
radioGroup
checkbox
switch
Use ctx.fieldRef
to get and set a field's value synchronously.
const textInputRef = ctx.fieldRef<string>("Default value")
// When the form is submitted
ctx.registerEventHandler("submit-form", () => {
// We can get the value of the text input
console.log(textInputRef.current)
// We can change the value of the text input
textInputRef.setValue("")
})
tray.render(() => tray.stack([
text.input("A text field", { fieldRef: textInputRef }),
tray.button("Submit", { onClick: "submit-form" }),
]))
Select, RadioGroup
You can create forms easily with ctx.fieldRef
and the available field components.
const selectRef = ctx.fieldRef<string>()
const radioGroupRef = ctx.fieldRef<string>()
tray.render(() => tray.stack([
tray.select("Label", {
placeholder: "Select...",
options: [
{ label: "One Piece", value: "21" },
{ label: "Sakamoto Days", value: "177709" },
],
fieldRef: selectRef,
}),
tray.radioGroup("Label", {
options: [
{ label: "One Piece", value: "21" },
{ label: "Sakamoto Days", value: "177709" },
],
fieldRef: radioGroupRef,
}),
]))
Checkbox, Switch
const checkboxRef = ctx.fieldRef<boolean>()
const switchRef = ctx.fieldRef<boolean>()
tray.render(() => tray.stack([
tray.checkbox("Do something", {
fieldRef: checkboxRef
}),
tray.switch("Do something else", {
fieldRef: switchRef
}),
]))
Last updated