@weavix/sdk-react 0.0.38 → 0.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +409 -25
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,49 +1,433 @@
1
1
  # @weavix/sdk-react
2
2
 
3
- Generic plugin SDK React package framework-agnostic `PluginProvider`, hooks, and components.
4
-
5
- Automatically includes [`@weavix/sdk-core`](https://www.npmjs.com/package/@weavix/sdk-core) as a dependency.
3
+ React wrapper for [`@weavix/sdk-core`](https://www.npmjs.com/package/@weavix/sdk-core). Provides a provider component and reactive hooks for theme, language, slot context, and UI operations.
6
4
 
7
5
  ## Installation
8
6
 
9
7
  ```bash
10
8
  npm install @weavix/sdk-react
11
- # @weavix/sdk-core is installed automatically
12
9
  ```
13
10
 
14
- ## Usage
11
+ Peer dependencies: `react >= 18.0.0`, `react-dom >= 18.0.0`.
12
+
13
+ ## Quick start
15
14
 
16
15
  ```tsx
17
- import { PluginProvider, usePluginContext } from '@weavix/sdk-react';
16
+ import { createRoot } from 'react-dom/client';
17
+ import { PluginProvider, usePluginContext, useTheme } from '@weavix/sdk-react';
18
18
 
19
- // Wrap your app
20
- root.render(
19
+ function App() {
20
+ const { slot, language } = usePluginContext();
21
+ const theme = useTheme();
22
+
23
+ return <div data-theme={theme}>Slot: {slot}, language: {language}</div>;
24
+ }
25
+
26
+ createRoot(document.getElementById('root')!).render(
21
27
  <PluginProvider>
22
28
  <App />
23
- </PluginProvider>,
29
+ </PluginProvider>
30
+ );
31
+ ```
32
+
33
+ ---
34
+
35
+ ## PluginProvider
36
+
37
+ 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.
38
+
39
+ ```tsx
40
+ import { PluginProvider, PluginLoader } from '@weavix/sdk-react';
41
+
42
+ root.render(
43
+ <PluginProvider
44
+ autoResize={true}
45
+ autoNotifyReady={true}
46
+ fallback={<PluginLoader />}
47
+ errorFallback={(error) => <div>Error: {error.message}</div>}
48
+ >
49
+ <App />
50
+ </PluginProvider>
24
51
  );
52
+ ```
53
+
54
+ ### Props
55
+
56
+ | Prop | Type | Default | Description |
57
+ |------|------|---------|-------------|
58
+ | `autoResize` | `boolean` | `true` | Automatically resize the iframe height when content changes |
59
+ | `autoNotifyReady` | `boolean` | `true` | Send `plugin.ready` to the host after initialisation |
60
+ | `fallback` | `ReactNode` | `undefined` | What to show during initialisation |
61
+ | `errorFallback` | `(error: Error) => ReactNode` | `<PluginError />` | What to show on initialisation error |
62
+ | `children` | `ReactNode` | — | Plugin content |
63
+
64
+ **Behaviour:**
65
+ - Intercepts clicks on external links (`<a href>`, `data-href`) and calls `uiApi.navigate`, preventing direct navigation from the iframe.
66
+ - Protected against double-initialisation in React StrictMode.
67
+ - Wraps the application in an `ErrorBoundary`.
68
+
69
+ ---
70
+
71
+ ## Hooks
72
+
73
+ ### `usePluginContext(level?)`
74
+
75
+ Main hook for accessing host data. All values are reactive — they update when push events are received from the host.
76
+
77
+ ```tsx
78
+ import { usePluginContext } from '@weavix/sdk-react';
25
79
 
26
- // Use in components
27
80
  function App() {
28
- const { slot, slotContext, theme, language, registerHandler } = usePluginContext();
81
+ // basic (default) slotContext contains only { entityId }
82
+ const { theme, language, slot, slotContext, userId, orgId } = usePluginContext();
29
83
 
30
- return <div>Slot: {slot}</div>;
84
+ // full — slotContext contains the full slot object
85
+ const { slotContext: fullCtx } = usePluginContext('full');
31
86
  }
87
+ ```
88
+
89
+ > Requires `contextLevel: "full"` in the plugin manifest for the `'full'` level. Throws at runtime if there is a mismatch.
90
+
91
+ **Return value (`PluginContextValue`):**
92
+
93
+ | Field | Type | Description |
94
+ |-------|------|-------------|
95
+ | `theme` | `Theme \| undefined` | Current theme (`'light'`, `'dark'`, `'light-hc'`, `'dark-hc'`, `'system'`) |
96
+ | `language` | `string \| undefined` | Current language (`'ru'`, `'en'`, ...) |
97
+ | `slot` | `string` | Current slot name |
98
+ | `service` | `string` | Service identifier |
99
+ | `origin` | `string` | Host origin |
100
+ | `innerUrl` | `string` | Plugin URL |
101
+ | `queryParams` | `Record<string, string>` | Plugin query parameters |
102
+ | `userId` | `string \| undefined` | Current user ID |
103
+ | `orgId` | `string \| undefined` | Organisation ID |
104
+ | `isYateam` | `boolean \| undefined` | Yandex-Team environment flag |
105
+ | `isOrbita` | `boolean \| undefined` | Orbita flag |
106
+ | `contextLevel` | `'basic' \| 'full'` | Context level declared in the manifest |
107
+ | `slotContext` | `BasicContext \| unknown \| undefined` | Slot context |
108
+ | `registerHandler` | `RegisterHandlerFunction` | Register a handler for incoming host RPC requests |
109
+
110
+ **`BasicContext`** (when `contextLevel: 'basic'`):
111
+
112
+ ```typescript
113
+ { entityId: string; entityMeta?: Record<string, string> }
114
+ ```
115
+
116
+ ### `useTheme()`
117
+
118
+ Reactive current host theme. Updates on `theme.changed`.
32
119
 
33
- // Full context (requires contextLevel: "full" in manifest)
34
- function AppFull() {
35
- const { slotContext } = usePluginContext('full');
36
- // slotContext: unknown — cast to your type
37
- const ctx = slotContext as { entityId: string };
38
- return <div>Entity: {ctx.entityId}</div>;
120
+ ```tsx
121
+ import { useTheme } from '@weavix/sdk-react';
122
+
123
+ function App() {
124
+ const theme = useTheme(); // 'light' | 'dark' | 'light-hc' | 'dark-hc' | 'system' | undefined
125
+ return <div data-theme={theme}>...</div>;
39
126
  }
40
127
  ```
41
128
 
42
- ## What's included
129
+ ### `useLanguage()`
130
+
131
+ Reactive current host language. Updates on `language.changed`.
132
+
133
+ ```tsx
134
+ import { useLanguage } from '@weavix/sdk-react';
135
+
136
+ const language = useLanguage(); // 'ru' | 'en' | ... | undefined
137
+ ```
138
+
139
+ ### `useUserId()`
140
+
141
+ Reactive current user ID. Updates on `userId.changed`.
142
+
143
+ ```tsx
144
+ import { useUserId } from '@weavix/sdk-react';
145
+
146
+ const userId = useUserId(); // string | undefined
147
+ ```
148
+
149
+ ### `useOrgId()`
150
+
151
+ Reactive organisation ID. Updates on `orgId.changed`.
152
+
153
+ ```tsx
154
+ import { useOrgId } from '@weavix/sdk-react';
155
+
156
+ const orgId = useOrgId(); // string | undefined
157
+ ```
158
+
159
+ ### `useIsYateam()`
160
+
161
+ Reactive Yandex-Team environment flag. Updates on `isYateam.changed`.
162
+
163
+ ```tsx
164
+ import { useIsYateam } from '@weavix/sdk-react';
165
+
166
+ const isYateam = useIsYateam(); // boolean | undefined
167
+ ```
168
+
169
+ ### `useIsOrbita()`
170
+
171
+ Reactive Orbita flag. Updates on `isOrbita.changed`.
172
+
173
+ ```tsx
174
+ import { useIsOrbita } from '@weavix/sdk-react';
175
+
176
+ const isOrbita = useIsOrbita(); // boolean | undefined
177
+ ```
178
+
179
+ ### `useToaster()`
180
+
181
+ Hook for showing toast notifications in the host application.
182
+
183
+ > **Permission:** Requires `"toaster"` in `permissions.ui` of the plugin manifest.
184
+
185
+ ```tsx
186
+ import { useToaster } from '@weavix/sdk-react';
187
+
188
+ function SaveButton() {
189
+ const toaster = useToaster();
190
+
191
+ const handleSave = async () => {
192
+ await save();
193
+ toaster.add({ title: 'Saved', theme: 'success' });
194
+ };
195
+
196
+ return <button onClick={handleSave}>Save</button>;
197
+ }
198
+ ```
199
+
200
+ Returns `{ add: (options: ToastOptions) => Promise<{ name: string }> }`.
201
+
202
+ **`ToastOptions`:**
203
+
204
+ | Parameter | Type | Default | Description |
205
+ |-----------|------|---------|-------------|
206
+ | `title` | `string` | — | Toast title (required, max 200 chars) |
207
+ | `name` | `string` | auto | Unique key for deduplication |
208
+ | `theme` | `'success' \| 'danger' \| 'warning' \| 'info'` | `'info'` | Theme |
209
+ | `content` | `string` | — | Body text (max 500 chars) |
210
+ | `autoHiding` | `number` | `5000` | Display time in ms (1000–30000) |
211
+ | `isClosable` | `boolean` | `true` | Show close button |
212
+ | `actions` | `ToastAction[]` | — | Action buttons (max 2): `{ label: string; onClick: () => void }` |
213
+
214
+ ### `useConfirm()`
215
+
216
+ Hook for showing a confirmation dialog.
217
+
218
+ > **Permission:** Requires `"confirm"` in `permissions.ui` of the plugin manifest.
219
+
220
+ ```tsx
221
+ import { useConfirm } from '@weavix/sdk-react';
222
+
223
+ function DeleteButton() {
224
+ const confirm = useConfirm();
225
+
226
+ const handleDelete = async () => {
227
+ const { confirmed } = await confirm.show({
228
+ title: 'Delete issue?',
229
+ message: 'This action cannot be undone.',
230
+ theme: 'danger',
231
+ });
232
+ if (confirmed) {
233
+ await deleteItem();
234
+ }
235
+ };
236
+
237
+ return <button onClick={handleDelete}>Delete</button>;
238
+ }
239
+ ```
240
+
241
+ Returns `{ show: (options: ConfirmOptions) => Promise<ConfirmResult> }`.
242
+
243
+ **`ConfirmOptions`:**
244
+
245
+ | Parameter | Type | Default | Description |
246
+ |-----------|------|---------|-------------|
247
+ | `message` | `string` | — | Dialog body text (required) |
248
+ | `title` | `string` | — | Dialog title |
249
+ | `textButtonApply` | `string` | — | Confirm button label |
250
+ | `textButtonCancel` | `string` | — | Cancel button label |
251
+ | `theme` | `'normal' \| 'danger'` | `'normal'` | Confirm button theme |
252
+
253
+ ### `useLocalizedString(fallbackLanguage?)`
254
+
255
+ Returns a resolver function that resolves a `LocalizedString` based on the current host language.
256
+
257
+ ```tsx
258
+ import { useLocalizedString } from '@weavix/sdk-react';
259
+
260
+ function Label({ text }: { text: { ru: string; en: string } }) {
261
+ const t = useLocalizedString();
262
+ return <span>{t(text)}</span>;
263
+ }
264
+ ```
265
+
266
+ | Parameter | Type | Default | Description |
267
+ |-----------|------|---------|-------------|
268
+ | `fallbackLanguage` | `string` | `'ru'` | Fallback language if the current language is not resolved |
269
+
270
+ Returns `(value: LocalizedString) => string`.
271
+
272
+ ### `usePluginBootstrap(options?)`
273
+
274
+ Low-level bootstrap hook. Use it when `PluginProvider` does not fit your use case (e.g. custom lifecycle or non-standard rendering).
275
+
276
+ ```tsx
277
+ import { usePluginBootstrap } from '@weavix/sdk-react';
278
+
279
+ function Root() {
280
+ const { loading, error, theme, language, context, host } = usePluginBootstrap({ autoResize: true });
281
+
282
+ if (loading) return <Spinner />;
283
+ if (error) return <div>Error: {error}</div>;
284
+
285
+ return <App theme={theme} language={language} context={context} host={host} />;
286
+ }
287
+ ```
288
+
289
+ | Parameter | Type | Default | Description |
290
+ |-----------|------|---------|-------------|
291
+ | `autoResize` | `boolean` | `true` | Automatically resize the iframe height |
292
+
293
+ **Returns `PluginBootstrapState<TContext>`:**
294
+
295
+ | Field | Type | Description |
296
+ |-------|------|-------------|
297
+ | `host` | `HostApi<TContext>` | Isolated `HostApi` instance (not the global `hostApi`) |
298
+ | `loading` | `boolean` | `true` until initialisation completes |
299
+ | `error` | `string \| null` | Error message or `null` |
300
+ | `theme` | `Theme \| undefined` | Current theme |
301
+ | `language` | `string \| undefined` | Current language |
302
+ | `context` | `TContext \| undefined` | Slot context (only when `contextLevel: 'full'`) |
303
+ | `userId` | `string \| undefined` | User ID |
304
+ | `orgId` | `string \| undefined` | Organisation ID |
305
+ | `isYateam` | `boolean \| undefined` | Yandex-Team flag |
306
+ | `isOrbita` | `boolean \| undefined` | Orbita flag |
307
+
308
+ ---
309
+
310
+ ## Components
311
+
312
+ ### `PluginLoader`
313
+
314
+ Built-in loading indicator to display during initialisation.
315
+
316
+ ```tsx
317
+ import { PluginProvider, PluginLoader } from '@weavix/sdk-react';
318
+
319
+ root.render(
320
+ <PluginProvider fallback={<PluginLoader />}>
321
+ <App />
322
+ </PluginProvider>
323
+ );
324
+ ```
325
+
326
+ No props.
327
+
328
+ ### `PluginError`
329
+
330
+ Built-in component for displaying an initialisation error. Used as the default `errorFallback` in `PluginProvider`.
331
+
332
+ ```tsx
333
+ import { PluginError } from '@weavix/sdk-react';
334
+
335
+ <PluginProvider errorFallback={(error) => <PluginError error={error} />}>
336
+ <App />
337
+ </PluginProvider>
338
+ ```
339
+
340
+ | Prop | Type | Description |
341
+ |------|------|-------------|
342
+ | `error` | `Error` | Error to display |
343
+
344
+ ### `ErrorBoundary`
345
+
346
+ React Error Boundary. Can be used independently to wrap parts of the application.
347
+
348
+ ```tsx
349
+ import { ErrorBoundary, PluginError } from '@weavix/sdk-react';
350
+
351
+ <ErrorBoundary fallback={(error) => <PluginError error={error} />}>
352
+ <RiskyComponent />
353
+ </ErrorBoundary>
354
+ ```
355
+
356
+ ---
357
+
358
+ ## Utilities
359
+
360
+ ### `isInternalUrl(url)`
361
+
362
+ Checks whether a URL is internal (same origin as the plugin).
363
+
364
+ ```typescript
365
+ import { isInternalUrl } from '@weavix/sdk-react';
366
+
367
+ isInternalUrl('/local/path'); // true
368
+ isInternalUrl('https://ext.com'); // false
369
+ ```
370
+
371
+ ---
372
+
373
+ ## Common patterns
374
+
375
+ ### Theme-aware rendering
376
+
377
+ ```tsx
378
+ function App() {
379
+ const theme = useTheme();
380
+ return (
381
+ <div className={`app app--${theme ?? 'light'}`}>
382
+ ...
383
+ </div>
384
+ );
385
+ }
386
+ ```
387
+
388
+ ### Localised strings
389
+
390
+ ```tsx
391
+ const LABELS = {
392
+ save: { ru: 'Сохранить', en: 'Save' },
393
+ cancel: { ru: 'Отмена', en: 'Cancel' },
394
+ };
395
+
396
+ function Form() {
397
+ const t = useLocalizedString();
398
+ return (
399
+ <form>
400
+ <button type="submit">{t(LABELS.save)}</button>
401
+ <button type="button">{t(LABELS.cancel)}</button>
402
+ </form>
403
+ );
404
+ }
405
+ ```
406
+
407
+ ### Registering a host RPC handler
408
+
409
+ ```tsx
410
+ function App() {
411
+ const { registerHandler } = usePluginContext();
412
+
413
+ useEffect(() => {
414
+ registerHandler('getData', () => ({ version: '1.0', status: 'ready' }));
415
+ }, [registerHandler]);
416
+
417
+ return <div>...</div>;
418
+ }
419
+ ```
420
+
421
+ ---
422
+
423
+ ## Related packages
424
+
425
+ | Package | Purpose |
426
+ |---------|---------|
427
+ | [`@weavix/sdk-core`](https://www.npmjs.com/package/@weavix/sdk-core) | Base runtime (hostApi, uiApi, storageApi, events) |
428
+ | [`@weavix/tracker-plugin-sdk`](https://www.npmjs.com/package/@weavix/tracker-plugin-sdk) | Typed wrapper for Tracker plugins |
429
+ | [`@weavix/tracker-plugin-sdk-react`](https://www.npmjs.com/package/@weavix/tracker-plugin-sdk-react) | React integration for Tracker plugins |
430
+
431
+ ## License
43
432
 
44
- - **`PluginProvider`** initializes the plugin, manages lifecycle, provides context
45
- - **`usePluginContext()`** — hook for accessing theme, language, slot, slotContext, registerHandler
46
- - **`isInternalUrl()`** — utility for checking if a URL is internal
47
- - **Hooks**: `useTheme`, `useLanguage`, `useIsYateam`, `useUserId`, `useOrgId`, `useIsOrbita`, `useConfirm`, `useToaster`, `useLocalizedString`
48
- - **Components**: `PluginError`, `PluginLoader`, `ErrorBoundary`
49
- - **Re-exports from `@weavix/sdk-core`**: `hostApi`, `uiApi`, `on`, `dispatchHostEvent`, error codes, types
433
+ SEE LICENSE IN LICENSE
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weavix/sdk-react",
3
- "version": "0.0.38",
3
+ "version": "0.0.40",
4
4
  "exports": {
5
5
  ".": {
6
6
  "types": "./dist/index.d.ts",
@@ -14,7 +14,7 @@
14
14
  ],
15
15
  "license": "SEE LICENSE IN LICENSE",
16
16
  "dependencies": {
17
- "@weavix/sdk-core": "0.0.38"
17
+ "@weavix/sdk-core": "0.0.40"
18
18
  },
19
19
  "peerDependencies": {
20
20
  "react": "^18.0.0"