@reqdesk/widget 0.2.0 → 0.3.1
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/README.md +334 -334
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{react-DYAKyC3I.d.ts → react-Bmwfo1Qg.d.ts} +7 -7
- package/dist/{react-DYAKyC3I.d.ts.map → react-Bmwfo1Qg.d.ts.map} +1 -1
- package/dist/{react-PYPqwxcj.d.cts → react-cnsZAJCx.d.cts} +7 -7
- package/dist/{react-PYPqwxcj.d.cts.map → react-cnsZAJCx.d.cts.map} +1 -1
- package/dist/react.cjs +21 -11
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +21 -11
- package/dist/react.js.map +1 -1
- package/dist/{storage-PjDHb5v7.js → storage-BG7rsgWE.js} +34 -2
- package/dist/storage-BG7rsgWE.js.map +1 -0
- package/dist/{storage-DqhhTxeh.cjs → storage-Cx5p1yP-.cjs} +38 -0
- package/package.json +81 -81
- package/dist/storage-PjDHb5v7.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,334 +1,334 @@
|
|
|
1
|
-
# @reqdesk/widget
|
|
2
|
-
|
|
3
|
-
Embeddable support widget SDK for [Reqdesk](https://reqdesk.com). Add a floating support button to any website — ticket submission with file attachments, ticket tracking, My Tickets, and optional Keycloak SSO authentication.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **Floating Action Button** — circular FAB that opens a slide-up support panel
|
|
8
|
-
- **Submit Tickets** — form with title, description, email, priority, and file attachments (drag-drop)
|
|
9
|
-
- **My Tickets** — view ticket history by email or automatically when authenticated
|
|
10
|
-
- **Ticket Detail** — full ticket view with reply thread, attachments, and reply composer
|
|
11
|
-
- **Track by Token** — anonymous ticket tracking via tracking tokens
|
|
12
|
-
- **Dual Auth** — API key mode (anonymous/email) + optional Keycloak OIDC login
|
|
13
|
-
- **Preferences** — end-user language (EN/AR with RTL), theme (light/dark/system), accent color
|
|
14
|
-
- **Branding** — custom logo, brand name, and "Powered by Reqdesk" footer (hideable)
|
|
15
|
-
- **Shadow DOM** — fully isolated styles, no CSS conflicts with host page
|
|
16
|
-
- **i18n** — English and Arabic built-in, custom translations supported
|
|
17
|
-
|
|
18
|
-
## Installation
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
npm install @reqdesk/widget
|
|
22
|
-
# or
|
|
23
|
-
bun add @reqdesk/widget
|
|
24
|
-
# or
|
|
25
|
-
yarn add @reqdesk/widget
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Quick Start
|
|
29
|
-
|
|
30
|
-
### Script Tag (any website)
|
|
31
|
-
|
|
32
|
-
```html
|
|
33
|
-
<script src="https://unpkg.com/@reqdesk/widget/dist/index.iife.js"></script>
|
|
34
|
-
<script>
|
|
35
|
-
ReqdeskWidget.init({
|
|
36
|
-
apiKey: 'rqd_live_your_api_key_here',
|
|
37
|
-
position: 'bottom-right',
|
|
38
|
-
language: 'en',
|
|
39
|
-
theme: {
|
|
40
|
-
primaryColor: '#42b983',
|
|
41
|
-
mode: 'light',
|
|
42
|
-
brandName: 'Acme Support',
|
|
43
|
-
logo: 'https://example.com/logo.png',
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
</script>
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### React Component
|
|
50
|
-
|
|
51
|
-
```tsx
|
|
52
|
-
import { ReqdeskProvider, FloatingWidget } from '@reqdesk/widget/react';
|
|
53
|
-
|
|
54
|
-
function App() {
|
|
55
|
-
return (
|
|
56
|
-
<ReqdeskProvider
|
|
57
|
-
apiKey="rqd_live_your_api_key_here"
|
|
58
|
-
language="en"
|
|
59
|
-
theme={{ primaryColor: '#42b983', mode: 'light' }}
|
|
60
|
-
>
|
|
61
|
-
<FloatingWidget position="bottom-right" />
|
|
62
|
-
</ReqdeskProvider>
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Configuration
|
|
68
|
-
|
|
69
|
-
### `ReqdeskWidgetConfig`
|
|
70
|
-
|
|
71
|
-
| Property | Type | Required | Default | Description |
|
|
72
|
-
|----------|------|----------|---------|-------------|
|
|
73
|
-
| `apiKey` | `string` | Yes | — | Project API key from Reqdesk dashboard |
|
|
74
|
-
| `auth` | `OidcAuthConfig` | No | — | Keycloak OIDC config for authenticated mode |
|
|
75
|
-
| `position` | `'bottom-right' \| 'bottom-left'` | No | `'bottom-right'` | FAB button position |
|
|
76
|
-
| `language` | `string` | No | `'en'` | Language code (`'en'` or `'ar'`) |
|
|
77
|
-
| `theme` | `ThemeConfig` | No | — | Visual customization |
|
|
78
|
-
| `customer` | `CustomerConfig` | No | — | Pre-fill customer info |
|
|
79
|
-
| `translations` | `Record<string, string>` | No | — | Override built-in translations |
|
|
80
|
-
| `inline` | `boolean` | No | `false` | Render inline instead of floating |
|
|
81
|
-
| `container` | `string \| HTMLElement` | No | — | Target element for inline mode |
|
|
82
|
-
|
|
83
|
-
### `ThemeConfig`
|
|
84
|
-
|
|
85
|
-
| Property | Type | Default | Description |
|
|
86
|
-
|----------|------|---------|-------------|
|
|
87
|
-
| `primaryColor` | `string` | `'#42b983'` | Accent color (hex) |
|
|
88
|
-
| `mode` | `'light' \| 'dark' \| 'auto'` | `'light'` | Color scheme |
|
|
89
|
-
| `borderRadius` | `string` | `'8px'` | Border radius for panels and inputs |
|
|
90
|
-
| `fontFamily` | `string` | `'inherit'` | Font family |
|
|
91
|
-
| `zIndex` | `number` | `9999` | Z-index for FAB and panel |
|
|
92
|
-
| `logo` | `string` | — | URL to brand logo (shown in header) |
|
|
93
|
-
| `brandName` | `string` | — | Brand name (shown in header instead of "Support") |
|
|
94
|
-
| `hideBranding` | `boolean` | `false` | Hide "Powered by Reqdesk" footer |
|
|
95
|
-
|
|
96
|
-
### `OidcAuthConfig`
|
|
97
|
-
|
|
98
|
-
| Property | Type | Description |
|
|
99
|
-
|----------|------|-------------|
|
|
100
|
-
| `issuerUri` | `string` | Keycloak realm URL (e.g., `https://auth.example.com/realms/reqdesk`) |
|
|
101
|
-
| `clientId` | `string` | Keycloak client ID (e.g., `reqdesk-widget`) |
|
|
102
|
-
|
|
103
|
-
## Authentication
|
|
104
|
-
|
|
105
|
-
The widget supports two authentication modes that can be used together:
|
|
106
|
-
|
|
107
|
-
### API Key Mode (default)
|
|
108
|
-
|
|
109
|
-
Every widget requires an API key. In this mode:
|
|
110
|
-
|
|
111
|
-
- Visitors submit tickets anonymously or with an email address
|
|
112
|
-
- Email identifies the visitor for "My Tickets" (trust-based, like a contact form)
|
|
113
|
-
- Tracking tokens allow anonymous ticket access from any browser
|
|
114
|
-
- A "Remember me" checkbox saves the email to localStorage
|
|
115
|
-
|
|
116
|
-
```ts
|
|
117
|
-
ReqdeskWidget.init({
|
|
118
|
-
apiKey: 'rqd_live_your_api_key_here',
|
|
119
|
-
});
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### Keycloak OIDC Mode (optional)
|
|
123
|
-
|
|
124
|
-
When `auth` config is provided, the widget shows a Login button. After authenticating via Keycloak:
|
|
125
|
-
|
|
126
|
-
- User is automatically identified (no email entry needed)
|
|
127
|
-
- "My Tickets" shows all tickets instantly
|
|
128
|
-
- Tickets are attributed to the real Keycloak user account
|
|
129
|
-
- Session persists via silent refresh (one-time login)
|
|
130
|
-
|
|
131
|
-
```ts
|
|
132
|
-
ReqdeskWidget.init({
|
|
133
|
-
apiKey: 'rqd_live_your_api_key_here',
|
|
134
|
-
auth: {
|
|
135
|
-
issuerUri: 'https://auth.example.com/realms/reqdesk',
|
|
136
|
-
clientId: 'reqdesk-widget',
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
The widget's OIDC session is **completely independent** from your host app's auth. It uses its own Keycloak client (`reqdesk-widget`) with separate tokens.
|
|
142
|
-
|
|
143
|
-
#### Keycloak Client Setup
|
|
144
|
-
|
|
145
|
-
Add a `reqdesk-widget` client to your Keycloak realm:
|
|
146
|
-
|
|
147
|
-
- **Client Type**: Public (`publicClient: true`)
|
|
148
|
-
- **Flow**: Authorization Code with PKCE (`standardFlowEnabled: true`)
|
|
149
|
-
- **Redirect URIs**: `*` (or restrict to your domains)
|
|
150
|
-
- **Web Origins**: `+` (CORS for any origin)
|
|
151
|
-
- **Client Scopes**: `basic, openid, profile, email`
|
|
152
|
-
|
|
153
|
-
## Events
|
|
154
|
-
|
|
155
|
-
```ts
|
|
156
|
-
// Vanilla JS
|
|
157
|
-
ReqdeskWidget.on('ticket:created', (ticket) => {
|
|
158
|
-
console.log('Ticket created:', ticket.ticketNumber);
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
ReqdeskWidget.on('open', () => console.log('Widget opened'));
|
|
162
|
-
ReqdeskWidget.on('close', () => console.log('Widget closed'));
|
|
163
|
-
ReqdeskWidget.on('error', (err) => console.error(err));
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
| Event | Payload | Description |
|
|
167
|
-
|-------|---------|-------------|
|
|
168
|
-
| `open` | — | Widget panel opened |
|
|
169
|
-
| `close` | — | Widget panel closed |
|
|
170
|
-
| `ticket:created` | `TicketResult` | Ticket submitted successfully |
|
|
171
|
-
| `ticket:tracked` | `TrackedTicketResult` | Ticket tracked by token |
|
|
172
|
-
| `reply:sent` | — | Reply submitted |
|
|
173
|
-
| `error` | `WidgetError` | Error occurred |
|
|
174
|
-
|
|
175
|
-
## Vanilla JS API
|
|
176
|
-
|
|
177
|
-
```ts
|
|
178
|
-
ReqdeskWidget.init(config) // Initialize the widget
|
|
179
|
-
ReqdeskWidget.open() // Open the panel
|
|
180
|
-
ReqdeskWidget.close() // Close the panel
|
|
181
|
-
ReqdeskWidget.toggle() // Toggle open/close
|
|
182
|
-
ReqdeskWidget.setLanguage('ar') // Change language (supports RTL)
|
|
183
|
-
ReqdeskWidget.setTheme({ mode: 'dark' }) // Update theme
|
|
184
|
-
ReqdeskWidget.identify({ email: 'user@example.com', name: 'Alice' })
|
|
185
|
-
ReqdeskWidget.on(event, callback)
|
|
186
|
-
ReqdeskWidget.destroy() // Remove widget from DOM
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
## React API
|
|
190
|
-
|
|
191
|
-
### Components
|
|
192
|
-
|
|
193
|
-
```tsx
|
|
194
|
-
import {
|
|
195
|
-
ReqdeskProvider, // Context provider (required wrapper)
|
|
196
|
-
FloatingWidget, // FAB + slide-up panel
|
|
197
|
-
TicketForm, // Standalone ticket form (inline mode)
|
|
198
|
-
SupportPortal, // Standalone support portal
|
|
199
|
-
ShadowRoot, // Shadow DOM wrapper for custom components
|
|
200
|
-
} from '@reqdesk/widget/react';
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
### `ReqdeskProvider` Props
|
|
204
|
-
|
|
205
|
-
| Prop | Type | Required | Description |
|
|
206
|
-
|------|------|----------|-------------|
|
|
207
|
-
| `apiKey` | `string` | Yes | Project API key |
|
|
208
|
-
| `auth` | `OidcAuthConfig` | No | Keycloak OIDC config |
|
|
209
|
-
| `theme` | `ThemeConfig` | No | Visual customization |
|
|
210
|
-
| `language` | `string` | No | Language code |
|
|
211
|
-
| `customer` | `CustomerConfig` | No | Pre-fill customer info |
|
|
212
|
-
| `translations` | `Record<string, string>` | No | Custom translations |
|
|
213
|
-
|
|
214
|
-
### `FloatingWidget` Props
|
|
215
|
-
|
|
216
|
-
| Prop | Type | Default | Description |
|
|
217
|
-
|------|------|---------|-------------|
|
|
218
|
-
| `position` | `'bottom-right' \| 'bottom-left'` | `'bottom-right'` | FAB position |
|
|
219
|
-
| `contained` | `boolean` | `false` | Use absolute positioning (for previews) |
|
|
220
|
-
| `onTicketCreated` | `(ticket: TicketResult) => void` | — | Callback on ticket creation |
|
|
221
|
-
| `onError` | `(error: WidgetError) => void` | — | Callback on error |
|
|
222
|
-
|
|
223
|
-
### Hooks
|
|
224
|
-
|
|
225
|
-
```tsx
|
|
226
|
-
import { useReqdesk } from '@reqdesk/widget/react';
|
|
227
|
-
|
|
228
|
-
function CustomForm() {
|
|
229
|
-
const { submitTicket, trackTicket, isLoading, error } = useReqdesk();
|
|
230
|
-
|
|
231
|
-
const handleSubmit = async () => {
|
|
232
|
-
const result = await submitTicket({
|
|
233
|
-
title: 'Bug report',
|
|
234
|
-
email: 'user@example.com',
|
|
235
|
-
priority: 'high',
|
|
236
|
-
});
|
|
237
|
-
console.log('Created:', result.ticketNumber);
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
## File Attachments
|
|
243
|
-
|
|
244
|
-
The widget supports file attachments on ticket submission and replies:
|
|
245
|
-
|
|
246
|
-
- **Drag-and-drop** or click to browse
|
|
247
|
-
- **Max 5 files** per submission, 5 per reply
|
|
248
|
-
- **Max 10MB** per file (configurable per project)
|
|
249
|
-
- **Allowed types**: Images (JPEG, PNG, GIF, WebP), PDF, Office documents, text, CSV, ZIP
|
|
250
|
-
- **Blocked**: Executables (.exe, .bat, .cmd, .sh, .ps1, .msi, .dll, .scr)
|
|
251
|
-
- **Upload progress** shown per-file after submission
|
|
252
|
-
|
|
253
|
-
Files are uploaded sequentially after the ticket/reply is created.
|
|
254
|
-
|
|
255
|
-
## Customization
|
|
256
|
-
|
|
257
|
-
### Custom Translations
|
|
258
|
-
|
|
259
|
-
Override any built-in string:
|
|
260
|
-
|
|
261
|
-
```ts
|
|
262
|
-
ReqdeskWidget.init({
|
|
263
|
-
apiKey: '...',
|
|
264
|
-
translations: {
|
|
265
|
-
'widget.title': 'Help Center',
|
|
266
|
-
'form.submit': 'Send Request',
|
|
267
|
-
'menu.newTicket': 'New Request',
|
|
268
|
-
},
|
|
269
|
-
});
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
See `src/i18n/en.ts` for all available translation keys.
|
|
273
|
-
|
|
274
|
-
### RTL Support
|
|
275
|
-
|
|
276
|
-
Set `language: 'ar'` for full RTL layout. The widget automatically mirrors all UI elements.
|
|
277
|
-
|
|
278
|
-
### End-User Preferences
|
|
279
|
-
|
|
280
|
-
Visitors can customize their experience from the Preferences menu:
|
|
281
|
-
|
|
282
|
-
- **Language**: English / Arabic toggle
|
|
283
|
-
- **Theme**: Light / Dark / System
|
|
284
|
-
- **Accent Color**: 5 preset colors (green, blue, purple, orange, red)
|
|
285
|
-
|
|
286
|
-
Preferences are persisted to `localStorage` per API key.
|
|
287
|
-
|
|
288
|
-
## Architecture
|
|
289
|
-
|
|
290
|
-
- **Shadow DOM**: Complete CSS isolation — host page styles cannot affect the widget
|
|
291
|
-
- **Zero global state**: Widget context is self-contained, no window globals
|
|
292
|
-
- **ofetch**: HTTP client with automatic retry, timeout, and auth interceptors
|
|
293
|
-
- **TanStack Query**: Data fetching with caching, optimistic updates, and loading states (React only)
|
|
294
|
-
- **Optional dependencies**: React, oidc-spa, and TanStack Query are all optional peer deps
|
|
295
|
-
|
|
296
|
-
### Bundle Sizes
|
|
297
|
-
|
|
298
|
-
| Entry | Size (gzip) |
|
|
299
|
-
|-------|-------------|
|
|
300
|
-
| `index.iife.js` (vanilla) | ~12 KB |
|
|
301
|
-
| `react.js` (ESM) | ~6 KB |
|
|
302
|
-
|
|
303
|
-
React, oidc-spa, and TanStack Query are **not bundled** — they're peer dependencies.
|
|
304
|
-
|
|
305
|
-
## Environment Variables
|
|
306
|
-
|
|
307
|
-
See `.env.example` for all available environment variables. These are for use in your application's build process — the widget SDK receives configuration via props/init, not directly from env vars.
|
|
308
|
-
|
|
309
|
-
## TypeScript
|
|
310
|
-
|
|
311
|
-
Full TypeScript support with exported types:
|
|
312
|
-
|
|
313
|
-
```ts
|
|
314
|
-
import type {
|
|
315
|
-
ReqdeskWidgetConfig,
|
|
316
|
-
ThemeConfig,
|
|
317
|
-
OidcAuthConfig,
|
|
318
|
-
CustomerConfig,
|
|
319
|
-
TicketResult,
|
|
320
|
-
WidgetError,
|
|
321
|
-
TrackedTicketResult,
|
|
322
|
-
PublicReply,
|
|
323
|
-
SubmitTicketData,
|
|
324
|
-
WidgetConfigPersist,
|
|
325
|
-
} from '@reqdesk/widget/react';
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
## Browser Support
|
|
329
|
-
|
|
330
|
-
Chrome, Firefox, Safari, and Edge (latest versions). Requires Shadow DOM support.
|
|
331
|
-
|
|
332
|
-
## License
|
|
333
|
-
|
|
334
|
-
Proprietary. See LICENSE file for details.
|
|
1
|
+
# @reqdesk/widget
|
|
2
|
+
|
|
3
|
+
Embeddable support widget SDK for [Reqdesk](https://reqdesk.com). Add a floating support button to any website — ticket submission with file attachments, ticket tracking, My Tickets, and optional Keycloak SSO authentication.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Floating Action Button** — circular FAB that opens a slide-up support panel
|
|
8
|
+
- **Submit Tickets** — form with title, description, email, priority, and file attachments (drag-drop)
|
|
9
|
+
- **My Tickets** — view ticket history by email or automatically when authenticated
|
|
10
|
+
- **Ticket Detail** — full ticket view with reply thread, attachments, and reply composer
|
|
11
|
+
- **Track by Token** — anonymous ticket tracking via tracking tokens
|
|
12
|
+
- **Dual Auth** — API key mode (anonymous/email) + optional Keycloak OIDC login
|
|
13
|
+
- **Preferences** — end-user language (EN/AR with RTL), theme (light/dark/system), accent color
|
|
14
|
+
- **Branding** — custom logo, brand name, and "Powered by Reqdesk" footer (hideable)
|
|
15
|
+
- **Shadow DOM** — fully isolated styles, no CSS conflicts with host page
|
|
16
|
+
- **i18n** — English and Arabic built-in, custom translations supported
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @reqdesk/widget
|
|
22
|
+
# or
|
|
23
|
+
bun add @reqdesk/widget
|
|
24
|
+
# or
|
|
25
|
+
yarn add @reqdesk/widget
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
### Script Tag (any website)
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<script src="https://unpkg.com/@reqdesk/widget/dist/index.iife.js"></script>
|
|
34
|
+
<script>
|
|
35
|
+
ReqdeskWidget.init({
|
|
36
|
+
apiKey: 'rqd_live_your_api_key_here',
|
|
37
|
+
position: 'bottom-right',
|
|
38
|
+
language: 'en',
|
|
39
|
+
theme: {
|
|
40
|
+
primaryColor: '#42b983',
|
|
41
|
+
mode: 'light',
|
|
42
|
+
brandName: 'Acme Support',
|
|
43
|
+
logo: 'https://example.com/logo.png',
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
</script>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### React Component
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { ReqdeskProvider, FloatingWidget } from '@reqdesk/widget/react';
|
|
53
|
+
|
|
54
|
+
function App() {
|
|
55
|
+
return (
|
|
56
|
+
<ReqdeskProvider
|
|
57
|
+
apiKey="rqd_live_your_api_key_here"
|
|
58
|
+
language="en"
|
|
59
|
+
theme={{ primaryColor: '#42b983', mode: 'light' }}
|
|
60
|
+
>
|
|
61
|
+
<FloatingWidget position="bottom-right" />
|
|
62
|
+
</ReqdeskProvider>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Configuration
|
|
68
|
+
|
|
69
|
+
### `ReqdeskWidgetConfig`
|
|
70
|
+
|
|
71
|
+
| Property | Type | Required | Default | Description |
|
|
72
|
+
|----------|------|----------|---------|-------------|
|
|
73
|
+
| `apiKey` | `string` | Yes | — | Project API key from Reqdesk dashboard |
|
|
74
|
+
| `auth` | `OidcAuthConfig` | No | — | Keycloak OIDC config for authenticated mode |
|
|
75
|
+
| `position` | `'bottom-right' \| 'bottom-left'` | No | `'bottom-right'` | FAB button position |
|
|
76
|
+
| `language` | `string` | No | `'en'` | Language code (`'en'` or `'ar'`) |
|
|
77
|
+
| `theme` | `ThemeConfig` | No | — | Visual customization |
|
|
78
|
+
| `customer` | `CustomerConfig` | No | — | Pre-fill customer info |
|
|
79
|
+
| `translations` | `Record<string, string>` | No | — | Override built-in translations |
|
|
80
|
+
| `inline` | `boolean` | No | `false` | Render inline instead of floating |
|
|
81
|
+
| `container` | `string \| HTMLElement` | No | — | Target element for inline mode |
|
|
82
|
+
|
|
83
|
+
### `ThemeConfig`
|
|
84
|
+
|
|
85
|
+
| Property | Type | Default | Description |
|
|
86
|
+
|----------|------|---------|-------------|
|
|
87
|
+
| `primaryColor` | `string` | `'#42b983'` | Accent color (hex) |
|
|
88
|
+
| `mode` | `'light' \| 'dark' \| 'auto'` | `'light'` | Color scheme |
|
|
89
|
+
| `borderRadius` | `string` | `'8px'` | Border radius for panels and inputs |
|
|
90
|
+
| `fontFamily` | `string` | `'inherit'` | Font family |
|
|
91
|
+
| `zIndex` | `number` | `9999` | Z-index for FAB and panel |
|
|
92
|
+
| `logo` | `string` | — | URL to brand logo (shown in header) |
|
|
93
|
+
| `brandName` | `string` | — | Brand name (shown in header instead of "Support") |
|
|
94
|
+
| `hideBranding` | `boolean` | `false` | Hide "Powered by Reqdesk" footer |
|
|
95
|
+
|
|
96
|
+
### `OidcAuthConfig`
|
|
97
|
+
|
|
98
|
+
| Property | Type | Description |
|
|
99
|
+
|----------|------|-------------|
|
|
100
|
+
| `issuerUri` | `string` | Keycloak realm URL (e.g., `https://auth.example.com/realms/reqdesk`) |
|
|
101
|
+
| `clientId` | `string` | Keycloak client ID (e.g., `reqdesk-widget`) |
|
|
102
|
+
|
|
103
|
+
## Authentication
|
|
104
|
+
|
|
105
|
+
The widget supports two authentication modes that can be used together:
|
|
106
|
+
|
|
107
|
+
### API Key Mode (default)
|
|
108
|
+
|
|
109
|
+
Every widget requires an API key. In this mode:
|
|
110
|
+
|
|
111
|
+
- Visitors submit tickets anonymously or with an email address
|
|
112
|
+
- Email identifies the visitor for "My Tickets" (trust-based, like a contact form)
|
|
113
|
+
- Tracking tokens allow anonymous ticket access from any browser
|
|
114
|
+
- A "Remember me" checkbox saves the email to localStorage
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
ReqdeskWidget.init({
|
|
118
|
+
apiKey: 'rqd_live_your_api_key_here',
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Keycloak OIDC Mode (optional)
|
|
123
|
+
|
|
124
|
+
When `auth` config is provided, the widget shows a Login button. After authenticating via Keycloak:
|
|
125
|
+
|
|
126
|
+
- User is automatically identified (no email entry needed)
|
|
127
|
+
- "My Tickets" shows all tickets instantly
|
|
128
|
+
- Tickets are attributed to the real Keycloak user account
|
|
129
|
+
- Session persists via silent refresh (one-time login)
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
ReqdeskWidget.init({
|
|
133
|
+
apiKey: 'rqd_live_your_api_key_here',
|
|
134
|
+
auth: {
|
|
135
|
+
issuerUri: 'https://auth.example.com/realms/reqdesk',
|
|
136
|
+
clientId: 'reqdesk-widget',
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The widget's OIDC session is **completely independent** from your host app's auth. It uses its own Keycloak client (`reqdesk-widget`) with separate tokens.
|
|
142
|
+
|
|
143
|
+
#### Keycloak Client Setup
|
|
144
|
+
|
|
145
|
+
Add a `reqdesk-widget` client to your Keycloak realm:
|
|
146
|
+
|
|
147
|
+
- **Client Type**: Public (`publicClient: true`)
|
|
148
|
+
- **Flow**: Authorization Code with PKCE (`standardFlowEnabled: true`)
|
|
149
|
+
- **Redirect URIs**: `*` (or restrict to your domains)
|
|
150
|
+
- **Web Origins**: `+` (CORS for any origin)
|
|
151
|
+
- **Client Scopes**: `basic, openid, profile, email`
|
|
152
|
+
|
|
153
|
+
## Events
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
// Vanilla JS
|
|
157
|
+
ReqdeskWidget.on('ticket:created', (ticket) => {
|
|
158
|
+
console.log('Ticket created:', ticket.ticketNumber);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
ReqdeskWidget.on('open', () => console.log('Widget opened'));
|
|
162
|
+
ReqdeskWidget.on('close', () => console.log('Widget closed'));
|
|
163
|
+
ReqdeskWidget.on('error', (err) => console.error(err));
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
| Event | Payload | Description |
|
|
167
|
+
|-------|---------|-------------|
|
|
168
|
+
| `open` | — | Widget panel opened |
|
|
169
|
+
| `close` | — | Widget panel closed |
|
|
170
|
+
| `ticket:created` | `TicketResult` | Ticket submitted successfully |
|
|
171
|
+
| `ticket:tracked` | `TrackedTicketResult` | Ticket tracked by token |
|
|
172
|
+
| `reply:sent` | — | Reply submitted |
|
|
173
|
+
| `error` | `WidgetError` | Error occurred |
|
|
174
|
+
|
|
175
|
+
## Vanilla JS API
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
ReqdeskWidget.init(config) // Initialize the widget
|
|
179
|
+
ReqdeskWidget.open() // Open the panel
|
|
180
|
+
ReqdeskWidget.close() // Close the panel
|
|
181
|
+
ReqdeskWidget.toggle() // Toggle open/close
|
|
182
|
+
ReqdeskWidget.setLanguage('ar') // Change language (supports RTL)
|
|
183
|
+
ReqdeskWidget.setTheme({ mode: 'dark' }) // Update theme
|
|
184
|
+
ReqdeskWidget.identify({ email: 'user@example.com', name: 'Alice' })
|
|
185
|
+
ReqdeskWidget.on(event, callback)
|
|
186
|
+
ReqdeskWidget.destroy() // Remove widget from DOM
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## React API
|
|
190
|
+
|
|
191
|
+
### Components
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
import {
|
|
195
|
+
ReqdeskProvider, // Context provider (required wrapper)
|
|
196
|
+
FloatingWidget, // FAB + slide-up panel
|
|
197
|
+
TicketForm, // Standalone ticket form (inline mode)
|
|
198
|
+
SupportPortal, // Standalone support portal
|
|
199
|
+
ShadowRoot, // Shadow DOM wrapper for custom components
|
|
200
|
+
} from '@reqdesk/widget/react';
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### `ReqdeskProvider` Props
|
|
204
|
+
|
|
205
|
+
| Prop | Type | Required | Description |
|
|
206
|
+
|------|------|----------|-------------|
|
|
207
|
+
| `apiKey` | `string` | Yes | Project API key |
|
|
208
|
+
| `auth` | `OidcAuthConfig` | No | Keycloak OIDC config |
|
|
209
|
+
| `theme` | `ThemeConfig` | No | Visual customization |
|
|
210
|
+
| `language` | `string` | No | Language code |
|
|
211
|
+
| `customer` | `CustomerConfig` | No | Pre-fill customer info |
|
|
212
|
+
| `translations` | `Record<string, string>` | No | Custom translations |
|
|
213
|
+
|
|
214
|
+
### `FloatingWidget` Props
|
|
215
|
+
|
|
216
|
+
| Prop | Type | Default | Description |
|
|
217
|
+
|------|------|---------|-------------|
|
|
218
|
+
| `position` | `'bottom-right' \| 'bottom-left'` | `'bottom-right'` | FAB position |
|
|
219
|
+
| `contained` | `boolean` | `false` | Use absolute positioning (for previews) |
|
|
220
|
+
| `onTicketCreated` | `(ticket: TicketResult) => void` | — | Callback on ticket creation |
|
|
221
|
+
| `onError` | `(error: WidgetError) => void` | — | Callback on error |
|
|
222
|
+
|
|
223
|
+
### Hooks
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
import { useReqdesk } from '@reqdesk/widget/react';
|
|
227
|
+
|
|
228
|
+
function CustomForm() {
|
|
229
|
+
const { submitTicket, trackTicket, isLoading, error } = useReqdesk();
|
|
230
|
+
|
|
231
|
+
const handleSubmit = async () => {
|
|
232
|
+
const result = await submitTicket({
|
|
233
|
+
title: 'Bug report',
|
|
234
|
+
email: 'user@example.com',
|
|
235
|
+
priority: 'high',
|
|
236
|
+
});
|
|
237
|
+
console.log('Created:', result.ticketNumber);
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## File Attachments
|
|
243
|
+
|
|
244
|
+
The widget supports file attachments on ticket submission and replies:
|
|
245
|
+
|
|
246
|
+
- **Drag-and-drop** or click to browse
|
|
247
|
+
- **Max 5 files** per submission, 5 per reply
|
|
248
|
+
- **Max 10MB** per file (configurable per project)
|
|
249
|
+
- **Allowed types**: Images (JPEG, PNG, GIF, WebP), PDF, Office documents, text, CSV, ZIP
|
|
250
|
+
- **Blocked**: Executables (.exe, .bat, .cmd, .sh, .ps1, .msi, .dll, .scr)
|
|
251
|
+
- **Upload progress** shown per-file after submission
|
|
252
|
+
|
|
253
|
+
Files are uploaded sequentially after the ticket/reply is created.
|
|
254
|
+
|
|
255
|
+
## Customization
|
|
256
|
+
|
|
257
|
+
### Custom Translations
|
|
258
|
+
|
|
259
|
+
Override any built-in string:
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
ReqdeskWidget.init({
|
|
263
|
+
apiKey: '...',
|
|
264
|
+
translations: {
|
|
265
|
+
'widget.title': 'Help Center',
|
|
266
|
+
'form.submit': 'Send Request',
|
|
267
|
+
'menu.newTicket': 'New Request',
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
See `src/i18n/en.ts` for all available translation keys.
|
|
273
|
+
|
|
274
|
+
### RTL Support
|
|
275
|
+
|
|
276
|
+
Set `language: 'ar'` for full RTL layout. The widget automatically mirrors all UI elements.
|
|
277
|
+
|
|
278
|
+
### End-User Preferences
|
|
279
|
+
|
|
280
|
+
Visitors can customize their experience from the Preferences menu:
|
|
281
|
+
|
|
282
|
+
- **Language**: English / Arabic toggle
|
|
283
|
+
- **Theme**: Light / Dark / System
|
|
284
|
+
- **Accent Color**: 5 preset colors (green, blue, purple, orange, red)
|
|
285
|
+
|
|
286
|
+
Preferences are persisted to `localStorage` per API key.
|
|
287
|
+
|
|
288
|
+
## Architecture
|
|
289
|
+
|
|
290
|
+
- **Shadow DOM**: Complete CSS isolation — host page styles cannot affect the widget
|
|
291
|
+
- **Zero global state**: Widget context is self-contained, no window globals
|
|
292
|
+
- **ofetch**: HTTP client with automatic retry, timeout, and auth interceptors
|
|
293
|
+
- **TanStack Query**: Data fetching with caching, optimistic updates, and loading states (React only)
|
|
294
|
+
- **Optional dependencies**: React, oidc-spa, and TanStack Query are all optional peer deps
|
|
295
|
+
|
|
296
|
+
### Bundle Sizes
|
|
297
|
+
|
|
298
|
+
| Entry | Size (gzip) |
|
|
299
|
+
|-------|-------------|
|
|
300
|
+
| `index.iife.js` (vanilla) | ~12 KB |
|
|
301
|
+
| `react.js` (ESM) | ~6 KB |
|
|
302
|
+
|
|
303
|
+
React, oidc-spa, and TanStack Query are **not bundled** — they're peer dependencies.
|
|
304
|
+
|
|
305
|
+
## Environment Variables
|
|
306
|
+
|
|
307
|
+
See `.env.example` for all available environment variables. These are for use in your application's build process — the widget SDK receives configuration via props/init, not directly from env vars.
|
|
308
|
+
|
|
309
|
+
## TypeScript
|
|
310
|
+
|
|
311
|
+
Full TypeScript support with exported types:
|
|
312
|
+
|
|
313
|
+
```ts
|
|
314
|
+
import type {
|
|
315
|
+
ReqdeskWidgetConfig,
|
|
316
|
+
ThemeConfig,
|
|
317
|
+
OidcAuthConfig,
|
|
318
|
+
CustomerConfig,
|
|
319
|
+
TicketResult,
|
|
320
|
+
WidgetError,
|
|
321
|
+
TrackedTicketResult,
|
|
322
|
+
PublicReply,
|
|
323
|
+
SubmitTicketData,
|
|
324
|
+
WidgetConfigPersist,
|
|
325
|
+
} from '@reqdesk/widget/react';
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Browser Support
|
|
329
|
+
|
|
330
|
+
Chrome, Firefox, Safari, and Edge (latest versions). Requires Shadow DOM support.
|
|
331
|
+
|
|
332
|
+
## License
|
|
333
|
+
|
|
334
|
+
Proprietary. See LICENSE file for details.
|