@qumra/jisr 1.0.0
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.
- package/LICENSE +15 -0
- package/README.md +430 -0
- package/dist/hooks/context.d.ts +41 -0
- package/dist/hooks/context.d.ts.map +1 -0
- package/dist/hooks/context.js +52 -0
- package/dist/hooks/context.js.map +1 -0
- package/dist/hooks/useAppBridge.d.ts +31 -0
- package/dist/hooks/useAppBridge.d.ts.map +1 -0
- package/dist/hooks/useAppBridge.js +33 -0
- package/dist/hooks/useAppBridge.js.map +1 -0
- package/dist/hooks/useAuthenticatedFetch.d.ts +27 -0
- package/dist/hooks/useAuthenticatedFetch.d.ts.map +1 -0
- package/dist/hooks/useAuthenticatedFetch.js +43 -0
- package/dist/hooks/useAuthenticatedFetch.js.map +1 -0
- package/dist/hooks/useFullscreen.d.ts +39 -0
- package/dist/hooks/useFullscreen.d.ts.map +1 -0
- package/dist/hooks/useFullscreen.js +42 -0
- package/dist/hooks/useFullscreen.js.map +1 -0
- package/dist/hooks/useModal.d.ts +46 -0
- package/dist/hooks/useModal.d.ts.map +1 -0
- package/dist/hooks/useModal.js +48 -0
- package/dist/hooks/useModal.js.map +1 -0
- package/dist/hooks/useNavigate.d.ts +26 -0
- package/dist/hooks/useNavigate.d.ts.map +1 -0
- package/dist/hooks/useNavigate.js +33 -0
- package/dist/hooks/useNavigate.js.map +1 -0
- package/dist/hooks/useSaveBar.d.ts +48 -0
- package/dist/hooks/useSaveBar.d.ts.map +1 -0
- package/dist/hooks/useSaveBar.js +50 -0
- package/dist/hooks/useSaveBar.js.map +1 -0
- package/dist/hooks/useTitleBar.d.ts +40 -0
- package/dist/hooks/useTitleBar.d.ts.map +1 -0
- package/dist/hooks/useTitleBar.js +41 -0
- package/dist/hooks/useTitleBar.js.map +1 -0
- package/dist/hooks/useToast.d.ts +42 -0
- package/dist/hooks/useToast.d.ts.map +1 -0
- package/dist/hooks/useToast.js +45 -0
- package/dist/hooks/useToast.js.map +1 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/actions.d.ts +161 -0
- package/dist/utils/actions.d.ts.map +1 -0
- package/dist/utils/actions.js +188 -0
- package/dist/utils/actions.js.map +1 -0
- package/dist/utils/app-bridge.d.ts +90 -0
- package/dist/utils/app-bridge.d.ts.map +1 -0
- package/dist/utils/app-bridge.js +143 -0
- package/dist/utils/app-bridge.js.map +1 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Qumra
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
# @qumra/jisr
|
|
2
|
+
|
|
3
|
+
React hooks and utilities for communicating with the Qumra Admin from embedded apps running in an iframe.
|
|
4
|
+
|
|
5
|
+
This package mirrors the functionality of Shopify's `@shopify/app-bridge-react` and provides a seamless integration layer for apps running within the Qumra Admin environment.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @qumra/jisr react react-dom
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
### Setup the Provider
|
|
16
|
+
|
|
17
|
+
Wrap your application with `QumraAppBridgeProvider` at the root level:
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import React from 'react';
|
|
21
|
+
import { QumraAppBridgeProvider } from '@qumra/jisr';
|
|
22
|
+
import { App } from './App';
|
|
23
|
+
|
|
24
|
+
export default function Root() {
|
|
25
|
+
return (
|
|
26
|
+
<QumraAppBridgeProvider config={{ apiKey: 'your-app-api-key' }}>
|
|
27
|
+
<App />
|
|
28
|
+
</QumraAppBridgeProvider>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Using Hooks in Your Components
|
|
34
|
+
|
|
35
|
+
Once the provider is set up, you can use any of the available hooks in your components:
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import React from 'react';
|
|
39
|
+
import {
|
|
40
|
+
useNavigate,
|
|
41
|
+
useToast,
|
|
42
|
+
useSaveBar,
|
|
43
|
+
} from '@qumra/jisr';
|
|
44
|
+
|
|
45
|
+
export function ProductSettings() {
|
|
46
|
+
const navigate = useNavigate();
|
|
47
|
+
const toast = useToast();
|
|
48
|
+
const saveBar = useSaveBar();
|
|
49
|
+
const [hasChanges, setHasChanges] = React.useState(false);
|
|
50
|
+
|
|
51
|
+
const handleChange = () => {
|
|
52
|
+
setHasChanges(true);
|
|
53
|
+
saveBar.show({
|
|
54
|
+
saveLabel: 'Save Changes',
|
|
55
|
+
discardLabel: 'Discard',
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const handleSave = async () => {
|
|
60
|
+
try {
|
|
61
|
+
toast.show({ message: 'Saving...' });
|
|
62
|
+
// Save your data here
|
|
63
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
64
|
+
toast.show({ message: 'Saved successfully!' });
|
|
65
|
+
saveBar.hide();
|
|
66
|
+
setHasChanges(false);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
toast.show({
|
|
69
|
+
message: 'Error saving changes',
|
|
70
|
+
isError: true,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<div>
|
|
77
|
+
<input
|
|
78
|
+
type="text"
|
|
79
|
+
placeholder="Product name"
|
|
80
|
+
onChange={handleChange}
|
|
81
|
+
/>
|
|
82
|
+
<button onClick={handleSave}>Save</button>
|
|
83
|
+
<button onClick={() => navigate('/products')}>
|
|
84
|
+
Back to Products
|
|
85
|
+
</button>
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Available Hooks
|
|
92
|
+
|
|
93
|
+
### useAppBridge()
|
|
94
|
+
|
|
95
|
+
Get direct access to the AppBridge instance for advanced use cases:
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import { useAppBridge } from '@qumra/jisr';
|
|
99
|
+
|
|
100
|
+
export function MyComponent() {
|
|
101
|
+
const bridge = useAppBridge();
|
|
102
|
+
|
|
103
|
+
const handleCustomAction = () => {
|
|
104
|
+
bridge.dispatch({
|
|
105
|
+
type: 'APP::CUSTOM_ACTION',
|
|
106
|
+
payload: { /* your data */ },
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Subscribe to events
|
|
110
|
+
const unsubscribe = bridge.subscribe('HOST::RESPONSE', (data) => {
|
|
111
|
+
console.log('Received:', data);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return () => unsubscribe();
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
return <button onClick={handleCustomAction}>Custom Action</button>;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### useNavigate()
|
|
122
|
+
|
|
123
|
+
Navigate within the Qumra Admin:
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import { useNavigate } from '@qumra/jisr';
|
|
127
|
+
|
|
128
|
+
export function NavigationComponent() {
|
|
129
|
+
const navigate = useNavigate();
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<div>
|
|
133
|
+
<button onClick={() => navigate('/products')}>
|
|
134
|
+
View Products
|
|
135
|
+
</button>
|
|
136
|
+
<button
|
|
137
|
+
onClick={() => navigate('https://example.com', {
|
|
138
|
+
external: true,
|
|
139
|
+
})}
|
|
140
|
+
>
|
|
141
|
+
Open External Site
|
|
142
|
+
</button>
|
|
143
|
+
</div>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### useToast()
|
|
149
|
+
|
|
150
|
+
Show and hide toast notifications:
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
import { useToast } from '@qumra/jisr';
|
|
154
|
+
|
|
155
|
+
export function ToastExample() {
|
|
156
|
+
const toast = useToast();
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<div>
|
|
160
|
+
<button
|
|
161
|
+
onClick={() =>
|
|
162
|
+
toast.show({
|
|
163
|
+
message: 'Operation completed successfully!',
|
|
164
|
+
duration: 3000,
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
>
|
|
168
|
+
Show Success Toast
|
|
169
|
+
</button>
|
|
170
|
+
<button
|
|
171
|
+
onClick={() =>
|
|
172
|
+
toast.show({
|
|
173
|
+
message: 'An error occurred',
|
|
174
|
+
isError: true,
|
|
175
|
+
duration: 5000,
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
>
|
|
179
|
+
Show Error Toast
|
|
180
|
+
</button>
|
|
181
|
+
<button onClick={() => toast.hide()}>
|
|
182
|
+
Hide Toast
|
|
183
|
+
</button>
|
|
184
|
+
</div>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### useModal()
|
|
190
|
+
|
|
191
|
+
Open and close modal dialogs:
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
import { useModal } from '@qumra/jisr';
|
|
195
|
+
|
|
196
|
+
export function ModalExample() {
|
|
197
|
+
const modal = useModal();
|
|
198
|
+
|
|
199
|
+
const handleOpenSettings = () => {
|
|
200
|
+
modal.open({
|
|
201
|
+
title: 'App Settings',
|
|
202
|
+
url: '/settings',
|
|
203
|
+
size: 'large',
|
|
204
|
+
primaryAction: {
|
|
205
|
+
content: 'Save',
|
|
206
|
+
onAction: () => {
|
|
207
|
+
console.log('Save clicked');
|
|
208
|
+
modal.close();
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
secondaryActions: [
|
|
212
|
+
{
|
|
213
|
+
content: 'Cancel',
|
|
214
|
+
onAction: () => {
|
|
215
|
+
modal.close();
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
return <button onClick={handleOpenSettings}>Open Settings</button>;
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### useSaveBar()
|
|
227
|
+
|
|
228
|
+
Show a save bar for unsaved changes:
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
import { useSaveBar } from '@qumra/jisr';
|
|
232
|
+
|
|
233
|
+
export function FormWithSaveBar() {
|
|
234
|
+
const saveBar = useSaveBar();
|
|
235
|
+
const [isDirty, setIsDirty] = React.useState(false);
|
|
236
|
+
|
|
237
|
+
const handleChange = () => {
|
|
238
|
+
if (!isDirty) {
|
|
239
|
+
setIsDirty(true);
|
|
240
|
+
saveBar.show();
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const handleSave = async () => {
|
|
245
|
+
await saveData();
|
|
246
|
+
setIsDirty(false);
|
|
247
|
+
saveBar.hide();
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
return (
|
|
251
|
+
<form>
|
|
252
|
+
<input onChange={handleChange} />
|
|
253
|
+
<button onClick={handleSave}>Save</button>
|
|
254
|
+
</form>
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### useTitleBar()
|
|
260
|
+
|
|
261
|
+
Update the title bar:
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
import { useTitleBar } from '@qumra/jisr';
|
|
265
|
+
|
|
266
|
+
export function PageWithTitle() {
|
|
267
|
+
const titleBar = useTitleBar();
|
|
268
|
+
|
|
269
|
+
React.useEffect(() => {
|
|
270
|
+
titleBar.update({
|
|
271
|
+
title: 'Products',
|
|
272
|
+
subtitle: 'Manage your store products',
|
|
273
|
+
breadcrumbs: [
|
|
274
|
+
{ content: 'Admin', url: '/' },
|
|
275
|
+
{ content: 'Products' },
|
|
276
|
+
],
|
|
277
|
+
});
|
|
278
|
+
}, [titleBar]);
|
|
279
|
+
|
|
280
|
+
return <div>Products page content</div>;
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### useFullscreen()
|
|
285
|
+
|
|
286
|
+
Enter and exit fullscreen mode:
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
import { useFullscreen } from '@qumra/jisr';
|
|
290
|
+
|
|
291
|
+
export function FullscreenComponent() {
|
|
292
|
+
const fullscreen = useFullscreen();
|
|
293
|
+
|
|
294
|
+
return (
|
|
295
|
+
<div>
|
|
296
|
+
<button onClick={() => fullscreen.enter()}>
|
|
297
|
+
Enter Fullscreen
|
|
298
|
+
</button>
|
|
299
|
+
<button onClick={() => fullscreen.exit()}>
|
|
300
|
+
Exit Fullscreen
|
|
301
|
+
</button>
|
|
302
|
+
</div>
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### useAuthenticatedFetch()
|
|
308
|
+
|
|
309
|
+
Make authenticated API requests with automatic session token injection:
|
|
310
|
+
|
|
311
|
+
```tsx
|
|
312
|
+
import { useAuthenticatedFetch } from '@qumra/jisr';
|
|
313
|
+
|
|
314
|
+
export function DataFetcher() {
|
|
315
|
+
const authenticatedFetch = useAuthenticatedFetch();
|
|
316
|
+
const [data, setData] = React.useState(null);
|
|
317
|
+
|
|
318
|
+
const loadData = async () => {
|
|
319
|
+
try {
|
|
320
|
+
const response = await authenticatedFetch('/api/products');
|
|
321
|
+
const result = await response.json();
|
|
322
|
+
setData(result);
|
|
323
|
+
} catch (error) {
|
|
324
|
+
console.error('Error fetching data:', error);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
React.useEffect(() => {
|
|
329
|
+
loadData();
|
|
330
|
+
}, []);
|
|
331
|
+
|
|
332
|
+
return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## API Reference
|
|
337
|
+
|
|
338
|
+
### ActionType
|
|
339
|
+
|
|
340
|
+
Constants for all available action types:
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
import { ActionType } from '@qumra/jisr';
|
|
344
|
+
|
|
345
|
+
const actions = {
|
|
346
|
+
NAVIGATE: ActionType.NAVIGATE,
|
|
347
|
+
TOAST_SHOW: ActionType.TOAST_SHOW,
|
|
348
|
+
TOAST_HIDE: ActionType.TOAST_HIDE,
|
|
349
|
+
MODAL_OPEN: ActionType.MODAL_OPEN,
|
|
350
|
+
MODAL_CLOSE: ActionType.MODAL_CLOSE,
|
|
351
|
+
SAVE_BAR_SHOW: ActionType.SAVE_BAR_SHOW,
|
|
352
|
+
SAVE_BAR_HIDE: ActionType.SAVE_BAR_HIDE,
|
|
353
|
+
TITLE_BAR_UPDATE: ActionType.TITLE_BAR_UPDATE,
|
|
354
|
+
LOADING_START: ActionType.LOADING_START,
|
|
355
|
+
LOADING_STOP: ActionType.LOADING_STOP,
|
|
356
|
+
FULLSCREEN_ENTER: ActionType.FULLSCREEN_ENTER,
|
|
357
|
+
FULLSCREEN_EXIT: ActionType.FULLSCREEN_EXIT,
|
|
358
|
+
};
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Action Creator Functions
|
|
362
|
+
|
|
363
|
+
Helper functions to create properly formatted actions:
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
import {
|
|
367
|
+
navigate,
|
|
368
|
+
showToast,
|
|
369
|
+
hideToast,
|
|
370
|
+
openModal,
|
|
371
|
+
closeModal,
|
|
372
|
+
showSaveBar,
|
|
373
|
+
hideSaveBar,
|
|
374
|
+
updateTitleBar,
|
|
375
|
+
startLoading,
|
|
376
|
+
stopLoading,
|
|
377
|
+
enterFullscreen,
|
|
378
|
+
exitFullscreen,
|
|
379
|
+
} from '@qumra/jisr';
|
|
380
|
+
|
|
381
|
+
// Use with useAppBridge()
|
|
382
|
+
const bridge = useAppBridge();
|
|
383
|
+
bridge.dispatch(navigate('/products'));
|
|
384
|
+
bridge.dispatch(showToast('Success!'));
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## Type Definitions
|
|
388
|
+
|
|
389
|
+
All types are exported for TypeScript projects:
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
import type {
|
|
393
|
+
AppBridgeConfig,
|
|
394
|
+
AppBridgeAction,
|
|
395
|
+
AppBridgeState,
|
|
396
|
+
AppContext,
|
|
397
|
+
NavigateOptions,
|
|
398
|
+
ToastOptions,
|
|
399
|
+
ModalOptions,
|
|
400
|
+
SaveBarOptions,
|
|
401
|
+
TitleBarOptions,
|
|
402
|
+
UseToastResult,
|
|
403
|
+
UseModalResult,
|
|
404
|
+
UseSaveBarResult,
|
|
405
|
+
UseFullscreenResult,
|
|
406
|
+
UseTitleBarResult,
|
|
407
|
+
} from '@qumra/jisr';
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
## Error Handling
|
|
411
|
+
|
|
412
|
+
All hooks require the `QumraAppBridgeProvider` to be set up. Using them outside the provider will throw an error:
|
|
413
|
+
|
|
414
|
+
```
|
|
415
|
+
Error: useAppBridge must be used within a QumraAppBridgeProvider
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
Make sure your component is wrapped with the provider or is a child of a component that is wrapped.
|
|
419
|
+
|
|
420
|
+
## Best Practices
|
|
421
|
+
|
|
422
|
+
1. **Always set up the provider at the root level** of your application
|
|
423
|
+
2. **Use the specific hooks** instead of `useAppBridge()` for most use cases
|
|
424
|
+
3. **Handle errors gracefully** when making API calls
|
|
425
|
+
4. **Clean up subscriptions** if you use direct subscriptions via `useAppBridge()`
|
|
426
|
+
5. **Use TypeScript** for better type safety and IDE autocomplete
|
|
427
|
+
|
|
428
|
+
## License
|
|
429
|
+
|
|
430
|
+
ISC
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Context and Provider for AppBridge.
|
|
3
|
+
* Provides the AppBridge instance to all child components.
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { AppBridge, type AppBridgeConfig } from '../utils/app-bridge.js';
|
|
7
|
+
/**
|
|
8
|
+
* Props for QumraAppBridgeProvider
|
|
9
|
+
*/
|
|
10
|
+
export interface QumraAppBridgeProviderProps {
|
|
11
|
+
/** Child components that will have access to the AppBridge */
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
/** Configuration for the AppBridge instance */
|
|
14
|
+
config: AppBridgeConfig;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Provider component for AppBridge
|
|
18
|
+
* Must wrap your application to provide the AppBridge to all hooks
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* import { QumraAppBridgeProvider } from '@qumra/app-bridge-react';
|
|
23
|
+
*
|
|
24
|
+
* export default function App() {
|
|
25
|
+
* return (
|
|
26
|
+
* <QumraAppBridgeProvider config={{ apiKey: 'your-api-key' }}>
|
|
27
|
+
* <YourApp />
|
|
28
|
+
* </QumraAppBridgeProvider>
|
|
29
|
+
* );
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function QumraAppBridgeProvider({ children, config, }: QumraAppBridgeProviderProps): JSX.Element;
|
|
34
|
+
/**
|
|
35
|
+
* Internal hook to get the AppBridge context
|
|
36
|
+
* @internal
|
|
37
|
+
* @returns The AppBridge instance from context
|
|
38
|
+
* @throws Error if used outside of QumraAppBridgeProvider
|
|
39
|
+
*/
|
|
40
|
+
export declare function useAppBridgeContext(): AppBridge;
|
|
41
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/hooks/context.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAKzE;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,8DAA8D;IAC9D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,+CAA+C;IAC/C,MAAM,EAAE,eAAe,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,MAAM,GACP,EAAE,2BAA2B,GAAG,GAAG,CAAC,OAAO,CAkB3C;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,SAAS,CAU/C"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* React Context and Provider for AppBridge.
|
|
4
|
+
* Provides the AppBridge instance to all child components.
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { AppBridge } from '../utils/app-bridge.js';
|
|
8
|
+
/** React Context for AppBridge instance */
|
|
9
|
+
const AppBridgeContext = React.createContext(null);
|
|
10
|
+
/**
|
|
11
|
+
* Provider component for AppBridge
|
|
12
|
+
* Must wrap your application to provide the AppBridge to all hooks
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* import { QumraAppBridgeProvider } from '@qumra/app-bridge-react';
|
|
17
|
+
*
|
|
18
|
+
* export default function App() {
|
|
19
|
+
* return (
|
|
20
|
+
* <QumraAppBridgeProvider config={{ apiKey: 'your-api-key' }}>
|
|
21
|
+
* <YourApp />
|
|
22
|
+
* </QumraAppBridgeProvider>
|
|
23
|
+
* );
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function QumraAppBridgeProvider({ children, config, }) {
|
|
28
|
+
const [bridge] = React.useState(() => new AppBridge(config));
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
// Signal to the host that the app is ready
|
|
31
|
+
bridge.ready();
|
|
32
|
+
// Cleanup on unmount
|
|
33
|
+
return () => {
|
|
34
|
+
bridge.destroy();
|
|
35
|
+
};
|
|
36
|
+
}, [bridge]);
|
|
37
|
+
return (_jsx(AppBridgeContext.Provider, { value: bridge, children: children }));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Internal hook to get the AppBridge context
|
|
41
|
+
* @internal
|
|
42
|
+
* @returns The AppBridge instance from context
|
|
43
|
+
* @throws Error if used outside of QumraAppBridgeProvider
|
|
44
|
+
*/
|
|
45
|
+
export function useAppBridgeContext() {
|
|
46
|
+
const context = React.useContext(AppBridgeContext);
|
|
47
|
+
if (!context) {
|
|
48
|
+
throw new Error('useAppBridge must be used within a QumraAppBridgeProvider');
|
|
49
|
+
}
|
|
50
|
+
return context;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/hooks/context.tsx"],"names":[],"mappings":";AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAwB,MAAM,wBAAwB,CAAC;AAEzE,2CAA2C;AAC3C,MAAM,gBAAgB,GAAG,KAAK,CAAC,aAAa,CAAmB,IAAI,CAAC,CAAC;AAYrE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,sBAAsB,CAAC,EACrC,QAAQ,EACR,MAAM,GACsB;IAC5B,MAAM,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAE7D,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,2CAA2C;QAC3C,MAAM,CAAC,KAAK,EAAE,CAAC;QAEf,qBAAqB;QACrB,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,OAAO,CACL,KAAC,gBAAgB,CAAC,QAAQ,IAAC,KAAK,EAAE,MAAM,YACrC,QAAQ,GACiB,CAC7B,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAEnD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook to access the AppBridge instance
|
|
3
|
+
*/
|
|
4
|
+
import type { AppBridge } from '../utils/app-bridge.js';
|
|
5
|
+
/**
|
|
6
|
+
* Get the AppBridge instance from context
|
|
7
|
+
* Must be used within a QumraAppBridgeProvider
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useAppBridge } from '@qumra/app-bridge-react';
|
|
12
|
+
*
|
|
13
|
+
* export function MyComponent() {
|
|
14
|
+
* const bridge = useAppBridge();
|
|
15
|
+
*
|
|
16
|
+
* const handleClick = () => {
|
|
17
|
+
* bridge.dispatch({
|
|
18
|
+
* type: 'APP::NAVIGATE',
|
|
19
|
+
* payload: { url: '/page' }
|
|
20
|
+
* });
|
|
21
|
+
* };
|
|
22
|
+
*
|
|
23
|
+
* return <button onClick={handleClick}>Navigate</button>;
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @returns The AppBridge instance
|
|
28
|
+
* @throws Error if used outside of QumraAppBridgeProvider
|
|
29
|
+
*/
|
|
30
|
+
export declare function useAppBridge(): AppBridge;
|
|
31
|
+
//# sourceMappingURL=useAppBridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAppBridge.d.ts","sourceRoot":"","sources":["../../src/hooks/useAppBridge.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,YAAY,IAAI,SAAS,CAExC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook to access the AppBridge instance
|
|
3
|
+
*/
|
|
4
|
+
import { useAppBridgeContext } from './context.js';
|
|
5
|
+
/**
|
|
6
|
+
* Get the AppBridge instance from context
|
|
7
|
+
* Must be used within a QumraAppBridgeProvider
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useAppBridge } from '@qumra/app-bridge-react';
|
|
12
|
+
*
|
|
13
|
+
* export function MyComponent() {
|
|
14
|
+
* const bridge = useAppBridge();
|
|
15
|
+
*
|
|
16
|
+
* const handleClick = () => {
|
|
17
|
+
* bridge.dispatch({
|
|
18
|
+
* type: 'APP::NAVIGATE',
|
|
19
|
+
* payload: { url: '/page' }
|
|
20
|
+
* });
|
|
21
|
+
* };
|
|
22
|
+
*
|
|
23
|
+
* return <button onClick={handleClick}>Navigate</button>;
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @returns The AppBridge instance
|
|
28
|
+
* @throws Error if used outside of QumraAppBridgeProvider
|
|
29
|
+
*/
|
|
30
|
+
export function useAppBridge() {
|
|
31
|
+
return useAppBridgeContext();
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=useAppBridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAppBridge.js","sourceRoot":"","sources":["../../src/hooks/useAppBridge.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGnD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,mBAAmB,EAAE,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for making authenticated fetch requests
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Hook to make authenticated fetch requests with automatic session token injection
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { useAuthenticatedFetch } from '@qumra/app-bridge-react';
|
|
10
|
+
*
|
|
11
|
+
* export function MyComponent() {
|
|
12
|
+
* const authenticatedFetch = useAuthenticatedFetch();
|
|
13
|
+
*
|
|
14
|
+
* const handleLoadData = async () => {
|
|
15
|
+
* const response = await authenticatedFetch('/api/products');
|
|
16
|
+
* const data = await response.json();
|
|
17
|
+
* console.log(data);
|
|
18
|
+
* };
|
|
19
|
+
*
|
|
20
|
+
* return <button onClick={handleLoadData}>Load Data</button>;
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @returns A fetch function that automatically adds Authorization header
|
|
25
|
+
*/
|
|
26
|
+
export declare function useAuthenticatedFetch(): (url: string, init?: RequestInit) => Promise<Response>;
|
|
27
|
+
//# sourceMappingURL=useAuthenticatedFetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAuthenticatedFetch.d.ts","sourceRoot":"","sources":["../../src/hooks/useAuthenticatedFetch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,IAAI,CACvC,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,WAAW,KACf,OAAO,CAAC,QAAQ,CAAC,CAqBrB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for making authenticated fetch requests
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback } from 'react';
|
|
5
|
+
import { useAppBridge } from './useAppBridge.js';
|
|
6
|
+
/**
|
|
7
|
+
* Hook to make authenticated fetch requests with automatic session token injection
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useAuthenticatedFetch } from '@qumra/app-bridge-react';
|
|
12
|
+
*
|
|
13
|
+
* export function MyComponent() {
|
|
14
|
+
* const authenticatedFetch = useAuthenticatedFetch();
|
|
15
|
+
*
|
|
16
|
+
* const handleLoadData = async () => {
|
|
17
|
+
* const response = await authenticatedFetch('/api/products');
|
|
18
|
+
* const data = await response.json();
|
|
19
|
+
* console.log(data);
|
|
20
|
+
* };
|
|
21
|
+
*
|
|
22
|
+
* return <button onClick={handleLoadData}>Load Data</button>;
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @returns A fetch function that automatically adds Authorization header
|
|
27
|
+
*/
|
|
28
|
+
export function useAuthenticatedFetch() {
|
|
29
|
+
const bridge = useAppBridge();
|
|
30
|
+
return useCallback(async (url, init) => {
|
|
31
|
+
const state = bridge.getState();
|
|
32
|
+
const sessionToken = state.context?.sessionToken;
|
|
33
|
+
const headers = new Headers(init?.headers || {});
|
|
34
|
+
if (sessionToken) {
|
|
35
|
+
headers.set('Authorization', `Bearer ${sessionToken}`);
|
|
36
|
+
}
|
|
37
|
+
return fetch(url, {
|
|
38
|
+
...init,
|
|
39
|
+
headers,
|
|
40
|
+
});
|
|
41
|
+
}, [bridge]);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=useAuthenticatedFetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAuthenticatedFetch.js","sourceRoot":"","sources":["../../src/hooks/useAuthenticatedFetch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,qBAAqB;IAInC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAE9B,OAAO,WAAW,CAChB,KAAK,EAAE,GAAW,EAAE,IAAkB,EAAE,EAAE;QACxC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;QAChC,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,EAAE,YAAY,CAAC;QAEjD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;QAEjD,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,YAAY,EAAE,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,KAAK,CAAC,GAAG,EAAE;YAChB,GAAG,IAAI;YACP,OAAO;SACR,CAAC,CAAC;IACL,CAAC,EACD,CAAC,MAAM,CAAC,CACT,CAAC;AACJ,CAAC"}
|