@weavix/tracker-plugin-sdk-react
v1.0.0
Published
React hooks for Tracker plugin SDK
Readme
@weavix/tracker-plugin-sdk-react
React SDK for Tracker plugins (Weavix / npm).
Provides TrackerPluginProvider, typed useTrackerPluginContext, hooks for theme, language, and UI operations. Re-exports trackerApi, hostApi, storageApi, and uiApi from @weavix/tracker-plugin-sdk.
Installation
npm install @weavix/tracker-plugin-sdk-reactPeer dependencies: react >= 18.0.0, react-dom >= 18.0.0.
Quick start
import { createRoot } from 'react-dom/client';
import { TrackerPluginProvider, useTrackerPluginContext } from '@weavix/tracker-plugin-sdk-react';
function App() {
const { theme, language, slot, slotContext } = useTrackerPluginContext();
return (
<div data-theme={theme}>
Slot: {slot}, language: {language}, entityId: {slotContext?.entityId}
</div>
);
}
createRoot(document.getElementById('root')!).render(
<TrackerPluginProvider>
<App />
</TrackerPluginProvider>
);TrackerPluginProvider
Root plugin component. Initialises the bridge, fetches initial values (theme, language, context, userId, orgId), notifies the host that the plugin is ready, and provides context to all child components.
A typed wrapper over PluginProvider from @weavix/sdk-react: adds Tracker-typed registerHandler based on SlotContextMap.
import { TrackerPluginProvider, PluginLoader } from '@weavix/tracker-plugin-sdk-react';
root.render(
<TrackerPluginProvider
autoResize={true}
autoNotifyReady={true}
fallback={<PluginLoader />}
errorFallback={(error) => <div>Error: {error.message}</div>}
>
<App />
</TrackerPluginProvider>
);Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| autoResize | boolean | true | Automatically resize the iframe height when content changes |
| autoNotifyReady | boolean | true | Send plugin.ready to the host after initialisation |
| fallback | ReactNode | undefined | What to show during initialisation |
| errorFallback | (error: Error) => ReactNode | <PluginError /> | What to show on initialisation error |
| children | ReactNode | — | Plugin content |
Behaviour:
- Intercepts clicks on external links and calls
uiApi.navigate. - Protected against double-initialisation in React StrictMode.
- Wraps the application in an
ErrorBoundary.
Manual notifyReady
import { TrackerPluginProvider, hostApi } from '@weavix/tracker-plugin-sdk-react';
function App() {
useEffect(() => {
initializeApp().then(() => {
hostApi.notifyReady();
});
}, []);
return <div>My Plugin</div>;
}
root.render(
<TrackerPluginProvider autoNotifyReady={false}>
<App />
</TrackerPluginProvider>
);useTrackerPluginContext(level?)
Main hook for accessing host data. Typed for Tracker — slotContext has type SlotContextMap[TSlot]. All values are reactive.
import { useTrackerPluginContext } from '@weavix/tracker-plugin-sdk-react';
function App() {
// basic (default) — slotContext: { entityId, entityMeta? }
const { theme, language, slot, slotContext } = useTrackerPluginContext();
return (
<div className={theme}>
<p>Language: {language}</p>
<p>Slot: {slot}</p>
<p>Entity: {slotContext?.entityId}</p>
</div>
);
}Full slot context
Requires contextLevel: "full" in the plugin manifest.
import { useTrackerPluginContext } from '@weavix/tracker-plugin-sdk-react';
function IssuePlugin() {
const { slotContext } = useTrackerPluginContext<'issue.action'>('full');
// slotContext: Issue | undefined
return (
<div>
<h1>Issue: {slotContext?.key}</h1>
<p>Status: {slotContext?.status?.key}</p>
<p>Version: {slotContext?.version}</p>
</div>
);
}contextLevel in the manifest
| Manifest | useTrackerPluginContext() | useTrackerPluginContext('full') |
|----------|---------------------------|----------------------------------|
| contextLevel: "basic" (default) | slotContext: BasicContext \| undefined | runtime error |
| contextLevel: "full" | slotContext: BasicContext \| undefined | slotContext: SlotContextMap[TSlot] \| undefined |
Return value
BasicTrackerPluginContextValue<TSlot> (level: 'basic'):
| Field | Type | Description |
|-------|------|-------------|
| theme | Theme \| undefined | Current theme ('light', 'dark', 'light-hc', 'dark-hc', 'system') |
| language | string \| undefined | Current language ('ru', 'en', ...) |
| slot | TSlot | Current slot name |
| service | string | Service identifier |
| origin | string | Host origin |
| innerUrl | string | Plugin URL |
| queryParams | Record<string, string> | Plugin query parameters |
| userId | string \| undefined | Current user ID |
| orgId | string \| undefined | Organisation ID |
| isYateam | boolean \| undefined | Yandex-Team environment flag |
| isOrbita | boolean \| undefined | Orbita flag |
| contextLevel | 'basic' | Context level from the manifest |
| slotContext | BasicContext \| undefined | { entityId, entityMeta? } |
| registerHandler | RegisterHandlerFunction<TSlot> | Register a Tracker-typed handler for host RPC |
FullTrackerPluginContextValue<TSlot> (level: 'full'): same fields, but slotContext: SlotContextMap[TSlot] | undefined.
registerHandler
Registers a Tracker-typed handler for incoming host RPC requests.
function App() {
const { registerHandler } = useTrackerPluginContext<'issue.action'>();
useEffect(() => {
// For 'getData', the handler type is derived from GetDataResultMap[TSlot]
registerHandler('getData', () => ({
key: 'QUEUE-1',
summary: 'Data from plugin',
}));
}, [registerHandler]);
return <div>...</div>;
}Hooks
useTheme()
import { useTheme } from '@weavix/tracker-plugin-sdk-react';
const theme = useTheme(); // 'light' | 'dark' | 'light-hc' | 'dark-hc' | 'system' | undefineduseLanguage()
import { useLanguage } from '@weavix/tracker-plugin-sdk-react';
const language = useLanguage(); // 'ru' | 'en' | ... | undefineduseToaster()
Show toast notifications in the host application.
Permission: Requires
"toaster"inpermissions.uiof the plugin manifest.
import { useToaster } from '@weavix/tracker-plugin-sdk-react';
function SaveButton() {
const toaster = useToaster();
const handleSave = async () => {
await save();
toaster.add({ title: 'Saved', theme: 'success' });
};
return <button onClick={handleSave}>Save</button>;
}Returns { add: (options: ToastOptions) => Promise<{ name: string }> }.
ToastOptions:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| title | string | — | Toast title (required, max 200 chars) |
| name | string | auto | Unique key for deduplication |
| theme | 'success' \| 'danger' \| 'warning' \| 'info' | 'info' | Theme |
| content | string | — | Body text (max 500 chars) |
| autoHiding | number | 5000 | Display time in ms (1000–30000) |
| isClosable | boolean | true | Show close button |
| actions | ToastAction[] | — | Action buttons (max 2): { label: string; onClick: () => void } |
useConfirm()
Show a confirmation dialog.
Permission: Requires
"confirm"inpermissions.uiof the plugin manifest.
import { useConfirm } from '@weavix/tracker-plugin-sdk-react';
function DeleteButton() {
const confirm = useConfirm();
const handleDelete = async () => {
const { confirmed } = await confirm.show({
title: 'Delete issue?',
message: 'This action cannot be undone.',
theme: 'danger',
});
if (confirmed) {
await deleteItem();
}
};
return <button onClick={handleDelete}>Delete</button>;
}Returns { show: (options: ConfirmOptions) => Promise<ConfirmResult> }.
ConfirmOptions:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| message | string | — | Dialog body text (required) |
| title | string | — | Dialog title |
| textButtonApply | string | — | Confirm button label |
| textButtonCancel | string | — | Cancel button label |
| theme | 'normal' \| 'danger' | 'normal' | Confirm button theme |
useLocalizedString(fallbackLanguage?)
Returns a resolver function that resolves a LocalizedString based on the current host language.
import { useLocalizedString } from '@weavix/tracker-plugin-sdk-react';
function Label({ text }: { text: { ru: string; en: string } }) {
const t = useLocalizedString();
return <span>{t(text)}</span>;
}useIsOrbita()
import { useIsOrbita } from '@weavix/tracker-plugin-sdk-react';
const isOrbita = useIsOrbita(); // boolean | undefinedComponents
PluginLoader
Built-in loading indicator to display during initialisation.
import { TrackerPluginProvider, PluginLoader } from '@weavix/tracker-plugin-sdk-react';
root.render(
<TrackerPluginProvider fallback={<PluginLoader />}>
<App />
</TrackerPluginProvider>
);No props.
PluginError
Built-in component for displaying an initialisation error.
import { PluginError } from '@weavix/tracker-plugin-sdk-react';
<TrackerPluginProvider errorFallback={(error) => <PluginError error={error} />}>
<App />
</TrackerPluginProvider>| Prop | Type | Description |
|------|------|-------------|
| error | Error | Error to display |
Common patterns
Theme-aware rendering
function App() {
const theme = useTheme();
return (
<div className={`app app--${theme ?? 'light'}`}>
...
</div>
);
}Localised strings
const LABELS = {
save: { ru: 'Сохранить', en: 'Save' },
cancel: { ru: 'Отмена', en: 'Cancel' },
};
function Form() {
const t = useLocalizedString();
return (
<form>
<button type="submit">{t(LABELS.save)}</button>
<button type="button">{t(LABELS.cancel)}</button>
</form>
);
}Reading the current issue (full context)
function IssueActions() {
const { slotContext: issue } = useTrackerPluginContext<'issue.action'>('full');
// issue: Issue | undefined
if (!issue) return null;
return (
<div>
<h2>{issue.key}: {issue.summary}</h2>
<p>Queue: {issue.queue?.key}</p>
<p>Assignee: {issue.assignee?.login}</p>
</div>
);
}Calling the Tracker API
import { trackerApi } from '@weavix/tracker-plugin-sdk-react';
function IssueList() {
const [issues, setIssues] = useState([]);
useEffect(() => {
trackerApi.v3.post['/v2/issues/_search']({
bodyParams: { filter: { queue: 'MYQUEUE' } },
}).then(({ data }) => setIssues(data));
}, []);
return <ul>{issues.map(i => <li key={i.id}>{i.summary}</li>)}</ul>;
}Related packages
| Package | Purpose |
|---------|---------|
| @weavix/tracker-plugin-sdk | Core SDK: trackerApi, hostApi, storageApi |
| @weavix/tracker-api-types | Tracker Public API v3 types |
| @weavix/sdk-react | Base React wrapper |
| @weavix/sdk-core | Base runtime |
License
SEE LICENSE IN LICENSE
