@asgard-js/react 0.1.22 → 0.1.23

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 CHANGED
@@ -243,6 +243,70 @@ config: {
243
243
 
244
244
  **Backward Compatibility:** Existing code using `endpoint` will continue to work but may show deprecation warnings when `debugMode` is enabled.
245
245
 
246
+ ### EMIT Action
247
+
248
+ EMIT buttons allow you to handle custom actions in your application. Implement the `onTemplateBtnClick` callback to process these events. See the [EMIT Action documentation](https://www.asgard-ai.com/docs/developer-reference/asgard-builtin/message-template-action-object-emit) for details.
249
+
250
+ The callback receives the following parameters:
251
+
252
+ 1. `payload` (optional): Custom data from the button action
253
+ 2. `eventName` (required): Event name specified in the button action
254
+ 3. `raw` (required): Complete SSE response data as JSON string. Use this when you need information beyond `payload` and `eventName`. Parse it to access additional fields from the original SSE response. See [SSE Response documentation](https://www.asgard-ai.com/docs/developer-reference/api-doc/send-message/sse-response/message-complete) for the complete response structure.
255
+
256
+ Configure EMIT buttons in your backend SSE response:
257
+
258
+ ```json
259
+ {
260
+ "template": {
261
+ "type": "BUTTON",
262
+ "title": "Action Menu",
263
+ "text": "Please select an action:",
264
+ "buttons": [
265
+ {
266
+ "label": "Support Request",
267
+ "action": {
268
+ "type": "EMIT",
269
+ "eventName": "support_request",
270
+ "payload": {
271
+ "category": "technical",
272
+ "priority": "high"
273
+ }
274
+ }
275
+ }
276
+ ]
277
+ }
278
+ }
279
+ ```
280
+
281
+ #### EMIT Example
282
+
283
+ ```typescript
284
+ import { useCallback } from 'react';
285
+
286
+ const handleTemplateBtnClick = useCallback((payload: Record<string, unknown>, eventName: string, raw: string): void => {
287
+ if (eventName === 'support_request') {
288
+ // Access payload data
289
+ const category = payload.category as string;
290
+ const priority = payload.priority as string;
291
+
292
+ // Optionally parse raw SSE data to access additional fields
293
+ let customChannelId: string | undefined;
294
+ try {
295
+ const sseData = JSON.parse(raw);
296
+ customChannelId = sseData.customChannelId;
297
+ } catch {
298
+ // Handle parse error if needed
299
+ }
300
+
301
+ const channelInfo = customChannelId ? `\nChannel ID: ${customChannelId}` : '';
302
+ window.alert(`Support request created\n\nCategory: ${category}\nPriority: ${priority}${channelInfo}`);
303
+ }
304
+ }, []);
305
+
306
+ // Pass the handler to Chatbot
307
+ <Chatbot config={config} customChannelId={nanoid()} onTemplateBtnClick={handleTemplateBtnClick} />;
308
+ ```
309
+
246
310
  ### Chatbot Component Props
247
311
 
248
312
  - **title?**: `string` - The title of the chatbot (optional). If not provided, will use the value from the API if available.
@@ -277,6 +341,7 @@ config: {
277
341
  - **onClose**: `() => void` - Callback function when chat is closed
278
342
  - **authState?**: `AuthState` - Authentication state for dynamic API key management. Available states: `'loading'`, `'needApiKey'`, `'authenticated'`, `'error'`, `'invalidApiKey'`
279
343
  - **onApiKeySubmit?**: `(apiKey: string) => Promise<void>` - Callback function when user submits API key for authentication
344
+ - **onTemplateBtnClick?**: `(payload: Record<string, unknown>, eventName: string, raw: string) => void` - Callback for EMIT button actions. See [EMIT Action](#emit-action) section for details.
280
345
  - **onSseMessage**: `(response: SseResponse, ctx: AsgardServiceContextValue) => void` - Callback function when SSE message is received. It would be helpful if using with the ref to provide some context and conversation data and do some proactively actions like sending messages to the bot.
281
346
  - **ref**: `ForwardedRef<ChatbotRef>` - Forwarded ref to access the chatbot instance. It can be used to access the chatbot instance and do some actions like sending messages to the bot. ChatbotRef extends the ref of the chatbot instance and provides some additional methods like `serviceContext.sendMessage` to interact with the chatbot instance.
282
347
 
@@ -1 +1 @@
1
- {"version":3,"file":"button-template.d.ts","sourceRoot":"","sources":["../../../../src/components/templates/button-template/button-template.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyB,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAOlC,UAAU,mBAAmB;IAC3B,OAAO,EAAE,sBAAsB,CAAC;CACjC;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,SAAS,CA+BpE"}
1
+ {"version":3,"file":"button-template.d.ts","sourceRoot":"","sources":["../../../../src/components/templates/button-template/button-template.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyB,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAOlC,UAAU,mBAAmB;IAC3B,OAAO,EAAE,sBAAsB,CAAC;CACjC;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,SAAS,CAgCpE"}
@@ -3,6 +3,7 @@ import { ReactNode, CSSProperties } from 'react';
3
3
 
4
4
  interface CardProps {
5
5
  template: ButtonMessageTemplate | CarouselMessageTemplate['columns'][number];
6
+ raw: string;
6
7
  customStyle?: {
7
8
  style?: CSSProperties;
8
9
  title?: {
@@ -1 +1 @@
1
- {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../../../src/components/templates/button-template/card.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,SAAS,EAAwB,aAAa,EAAE,MAAM,OAAO,CAAC;AAE1F,OAAO,EAAgB,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAM/F,UAAU,SAAS;IACjB,QAAQ,EAAE,qBAAqB,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;IAC7E,WAAW,CAAC,EAAE;QACZ,KAAK,CAAC,EAAE,aAAa,CAAC;QACtB,KAAK,CAAC,EAAE;YACN,KAAK,CAAC,EAAE,aAAa,CAAC;SACvB,CAAC;QACF,WAAW,CAAC,EAAE;YACZ,KAAK,CAAC,EAAE,aAAa,CAAC;SACvB,CAAC;QACF,MAAM,CAAC,EAAE;YACP,KAAK,CAAC,EAAE,aAAa,CAAC;SACvB,CAAC;KACH,CAAC;CACH;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAsFhD"}
1
+ {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../../../src/components/templates/button-template/card.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,SAAS,EAAwB,aAAa,EAAE,MAAM,OAAO,CAAC;AAE1F,OAAO,EAAgB,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAM/F,UAAU,SAAS;IACjB,QAAQ,EAAE,qBAAqB,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE;QACZ,KAAK,CAAC,EAAE,aAAa,CAAC;QACtB,KAAK,CAAC,EAAE;YACN,KAAK,CAAC,EAAE,aAAa,CAAC;SACvB,CAAC;QACF,WAAW,CAAC,EAAE;YACZ,KAAK,CAAC,EAAE,aAAa,CAAC;SACvB,CAAC;QACF,MAAM,CAAC,EAAE;YACP,KAAK,CAAC,EAAE,aAAa,CAAC;SACvB,CAAC;KACH,CAAC;CACH;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAkFhD"}
@@ -1 +1 @@
1
- {"version":3,"file":"carousel-template.d.ts","sourceRoot":"","sources":["../../../../src/components/templates/carousel-template/carousel-template.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKlC,OAAO,EAA2B,sBAAsB,EAAyB,MAAM,iBAAiB,CAAC;AAKzG,UAAU,qBAAqB;IAC7B,OAAO,EAAE,sBAAsB,CAAC;CACjC;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,SAAS,CAyCxE"}
1
+ {"version":3,"file":"carousel-template.d.ts","sourceRoot":"","sources":["../../../../src/components/templates/carousel-template/carousel-template.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKlC,OAAO,EAA2B,sBAAsB,EAAyB,MAAM,iBAAiB,CAAC;AAKzG,UAAU,qBAAqB;IAC7B,OAAO,EAAE,sBAAsB,CAAC;CACjC;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,SAAS,CA0CxE"}
@@ -1,25 +1,17 @@
1
- import { ConversationErrorMessage, FetchSsePayload } from '../../../core/src/index.ts';
1
+ import { ConversationErrorMessage } from '../../../core/src/index.ts';
2
2
  import { PropsWithChildren, ReactNode } from 'react';
3
3
 
4
4
  export interface AsgardTemplateContextValue {
5
5
  onErrorClick?: (message: ConversationErrorMessage) => void;
6
6
  errorMessageRenderer?: (message: ConversationErrorMessage) => ReactNode;
7
- onTemplateBtnClick?: (payload: Record<string, unknown>, { sse, }: {
8
- sse: {
9
- sendMessage: (payload: Pick<FetchSsePayload, 'text'> & Partial<Pick<FetchSsePayload, 'payload'>>) => void;
10
- };
11
- }) => void;
7
+ onTemplateBtnClick?: (payload: Record<string, unknown>, eventName: string, raw: string) => void;
12
8
  defaultLinkTarget?: '_blank' | '_self' | '_parent' | '_top';
13
9
  }
14
10
  export declare const AsgardTemplateContext: import('react').Context<AsgardTemplateContextValue>;
15
11
  interface AsgardTemplateContextProviderProps extends PropsWithChildren {
16
12
  onErrorClick?: (message: ConversationErrorMessage) => void;
17
13
  errorMessageRenderer?: (message: ConversationErrorMessage) => ReactNode;
18
- onTemplateBtnClick?: (payload: Record<string, unknown>, { sse, }: {
19
- sse: {
20
- sendMessage: (payload: Pick<FetchSsePayload, 'text'> & Partial<Pick<FetchSsePayload, 'payload'>>) => void;
21
- };
22
- }) => void;
14
+ onTemplateBtnClick?: (payload: Record<string, unknown>, eventName: string, raw: string) => void;
23
15
  defaultLinkTarget?: '_blank' | '_self' | '_parent' | '_top';
24
16
  }
25
17
  export declare function AsgardTemplateContextProvider(props: AsgardTemplateContextProviderProps): ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"asgard-template-context.d.ts","sourceRoot":"","sources":["../../src/context/asgard-template-context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,iBAAiB,EAAE,SAAS,EAAuB,MAAM,OAAO,CAAC;AACzF,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAE5E,MAAM,WAAW,0BAA0B;IACzC,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAC;IAC3D,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,SAAS,CAAC;IACxE,kBAAkB,CAAC,EAAE,CACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,EACE,GAAG,GACJ,EAAE;QACD,GAAG,EAAE;YACH,WAAW,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC,KAAK,IAAI,CAAC;SAC3G,CAAC;KACH,KACE,IAAI,CAAC;IACV,iBAAiB,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;CAC7D;AAED,eAAO,MAAM,qBAAqB,qDAKhC,CAAC;AAEH,UAAU,kCAAmC,SAAQ,iBAAiB;IACpE,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAC;IAC3D,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,SAAS,CAAC;IACxE,kBAAkB,CAAC,EAAE,CACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,EACE,GAAG,GACJ,EAAE;QACD,GAAG,EAAE;YACH,WAAW,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC,KAAK,IAAI,CAAC;SAC3G,CAAC;KACH,KACE,IAAI,CAAC;IACV,iBAAiB,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;CAC7D;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,kCAAkC,GAAG,SAAS,CAclG;AAED,wBAAgB,wBAAwB,IAAI,0BAA0B,CAErE"}
1
+ {"version":3,"file":"asgard-template-context.d.ts","sourceRoot":"","sources":["../../src/context/asgard-template-context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,iBAAiB,EAAE,SAAS,EAAuB,MAAM,OAAO,CAAC;AACzF,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,MAAM,WAAW,0BAA0B;IACzC,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAC;IAC3D,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,SAAS,CAAC;IACxE,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChG,iBAAiB,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;CAC7D;AAED,eAAO,MAAM,qBAAqB,qDAKhC,CAAC;AAEH,UAAU,kCAAmC,SAAQ,iBAAiB;IACpE,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAC;IAC3D,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,SAAS,CAAC;IACxE,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChG,iBAAiB,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;CAC7D;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,kCAAkC,GAAG,SAAS,CAclG;AAED,wBAAgB,wBAAwB,IAAI,0BAA0B,CAErE"}
package/dist/index.js CHANGED
@@ -1055,11 +1055,11 @@ function F5(e, t, n) {
1055
1055
  return jP(e) ? window.open(e, t, n) : (console.error(`Blocked attempt to open unsafe URI: ${e}`), null);
1056
1056
  }
1057
1057
  function N5(e) {
1058
- var u, c, f;
1059
- const { template: t, customStyle: n } = e, { sendMessage: i } = tn(), { onTemplateBtnClick: r, defaultLinkTarget: o } = $5(), s = Fe(() => {
1060
- var d;
1061
- return ((d = t == null ? void 0 : t.thumbnailImageUrl) == null ? void 0 : d.replace(/^http:/, "").replace(/^https:/, "")) || "https://via.assets.so/img.jpg?w=200&h=270&tc=white&bg=#eeeeee";
1062
- }, [t]), a = Fe(() => {
1058
+ var c, f, d;
1059
+ const { template: t, raw: n, customStyle: i } = e, { sendMessage: r } = tn(), { onTemplateBtnClick: o, defaultLinkTarget: s } = $5(), a = Fe(() => {
1060
+ var h;
1061
+ return ((h = t == null ? void 0 : t.thumbnailImageUrl) == null ? void 0 : h.replace(/^http:/, "").replace(/^https:/, "")) || "https://via.assets.so/img.jpg?w=200&h=270&tc=white&bg=#eeeeee";
1062
+ }, [t]), l = Fe(() => {
1063
1063
  switch (t == null ? void 0 : t.imageAspectRatio) {
1064
1064
  case "square":
1065
1065
  return "1 / 1";
@@ -1067,52 +1067,46 @@ function N5(e) {
1067
1067
  default:
1068
1068
  return "1.51 / 1";
1069
1069
  }
1070
- }, [t]), l = Ce(
1071
- (d) => function() {
1072
- switch (d.type) {
1070
+ }, [t]), u = Ce(
1071
+ (h) => function() {
1072
+ switch (h.type) {
1073
1073
  case "message":
1074
1074
  case "MESSAGE":
1075
- i == null || i({ text: d.text });
1075
+ r == null || r({ text: h.text });
1076
1076
  return;
1077
1077
  case "uri":
1078
1078
  case "URI":
1079
- F5(d.uri, d.target || o || "_blank");
1079
+ F5(h.uri, h.target || s || "_blank");
1080
1080
  return;
1081
1081
  case "emit":
1082
1082
  case "EMIT":
1083
- r == null || r(d.payload, {
1084
- sse: {
1085
- sendMessage: (p) => {
1086
- i == null || i(p);
1087
- }
1088
- }
1089
- });
1083
+ o && o(h.payload || {}, h.eventName || "", n);
1090
1084
  return;
1091
1085
  }
1092
1086
  },
1093
- [i, r, o]
1087
+ [r, o, s, n]
1094
1088
  );
1095
- return /* @__PURE__ */ te("div", { className: ze("asgard-card", Rc.card_root), style: n == null ? void 0 : n.style, children: [
1089
+ return /* @__PURE__ */ te("div", { className: ze("asgard-card", Rc.card_root), style: i == null ? void 0 : i.style, children: [
1096
1090
  (t == null ? void 0 : t.thumbnailImageUrl) && /* @__PURE__ */ k(
1097
1091
  "img",
1098
1092
  {
1099
1093
  alt: t == null ? void 0 : t.title,
1100
- src: s,
1094
+ src: a,
1101
1095
  style: {
1102
1096
  display: "block",
1103
1097
  width: "100%",
1104
1098
  maxHeight: "170px",
1105
1099
  objectFit: t == null ? void 0 : t.imageSize,
1106
- aspectRatio: a
1100
+ aspectRatio: l
1107
1101
  }
1108
1102
  }
1109
1103
  ),
1110
1104
  /* @__PURE__ */ te("div", { className: Rc.card_content, children: [
1111
- /* @__PURE__ */ k("h5", { className: Rc.card_title, style: (u = n == null ? void 0 : n.title) == null ? void 0 : u.style, children: t == null ? void 0 : t.title }),
1112
- /* @__PURE__ */ k("div", { className: Rc.card_description, style: (c = n == null ? void 0 : n.description) == null ? void 0 : c.style, children: t == null ? void 0 : t.text }),
1113
- /* @__PURE__ */ k("div", { className: Rc.card_actions, children: (f = t == null ? void 0 : t.buttons) == null ? void 0 : f.map((d, h) => {
1114
- var p;
1115
- return /* @__PURE__ */ k("button", { onClick: l(d.action), style: (p = n == null ? void 0 : n.button) == null ? void 0 : p.style, children: d.label }, h);
1105
+ /* @__PURE__ */ k("h5", { className: Rc.card_title, style: (c = i == null ? void 0 : i.title) == null ? void 0 : c.style, children: t == null ? void 0 : t.title }),
1106
+ /* @__PURE__ */ k("div", { className: Rc.card_description, style: (f = i == null ? void 0 : i.description) == null ? void 0 : f.style, children: t == null ? void 0 : t.text }),
1107
+ /* @__PURE__ */ k("div", { className: Rc.card_actions, children: (d = t == null ? void 0 : t.buttons) == null ? void 0 : d.map((h, p) => {
1108
+ var g;
1109
+ return /* @__PURE__ */ k("button", { onClick: u(h.action), style: (g = i == null ? void 0 : i.button) == null ? void 0 : g.style, children: h.label }, p);
1116
1110
  }) })
1117
1111
  ] })
1118
1112
  ] });
@@ -1126,6 +1120,7 @@ function qP(e) {
1126
1120
  N5,
1127
1121
  {
1128
1122
  template: r,
1123
+ raw: t.raw,
1129
1124
  customStyle: {
1130
1125
  style: (o = n == null ? void 0 : n.ButtonMessageTemplate) == null ? void 0 : o.style,
1131
1126
  title: {
@@ -1272,6 +1267,7 @@ function XP(e) {
1272
1267
  N5,
1273
1268
  {
1274
1269
  template: a,
1270
+ raw: t.raw,
1275
1271
  customStyle: {
1276
1272
  style: (c = (u = n == null ? void 0 : n.CarouselMessageTemplate) == null ? void 0 : u.card) == null ? void 0 : c.style,
1277
1273
  title: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asgard-js/react",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -48,7 +48,7 @@
48
48
  "vitest": "^1.6.0"
49
49
  },
50
50
  "peerDependencies": {
51
- "@asgard-js/core": "^0.1.22",
51
+ "@asgard-js/core": "^0.1.23",
52
52
  "react": "^18.0.0 || ^19.0.0",
53
53
  "react-dom": "^18.0.0 || ^19.0.0"
54
54
  },