@telia-ace/widget-conversation 1.0.15 → 1.0.18

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 (52) hide show
  1. package/LICENSE.txt +5 -5
  2. package/README.md +273 -256
  3. package/dist/agent.d.ts +17 -17
  4. package/dist/{ui → components}/conversation/conversation.d.ts +6 -6
  5. package/dist/{ui/conversation/conversation-component.d.ts → components/conversation/plugin.d.ts} +43 -37
  6. package/dist/components/conversation/ui/content.d.ts +2 -0
  7. package/dist/{ui/conversation/conversation-input.d.ts → components/conversation/ui/input.d.ts} +6 -6
  8. package/dist/{ui/conversation/conversation-loader.d.ts → components/conversation/ui/loader.d.ts} +8 -8
  9. package/dist/components/conversation/ui/message-list-items/button-list.d.ts +8 -0
  10. package/dist/{ui/conversation/message-types/custom-message-list-item.d.ts → components/conversation/ui/message-list-items/custom.d.ts} +9 -9
  11. package/dist/components/conversation/ui/message-list-items/html.d.ts +5 -0
  12. package/dist/components/conversation/ui/message-list-items/link-list.d.ts +8 -0
  13. package/dist/components/conversation/ui/message-list-items/separator.d.ts +2 -0
  14. package/dist/components/conversation/ui/message-list-items/text.d.ts +6 -0
  15. package/dist/{ui/conversation → components/conversation/ui}/message-types/agent.d.ts +11 -11
  16. package/dist/{ui/conversation → components/conversation/ui}/message-types/index.d.ts +4 -5
  17. package/dist/components/conversation/ui/message-types/message-list.d.ts +9 -0
  18. package/dist/{ui/conversation → components/conversation/ui}/message-types/system.d.ts +12 -12
  19. package/dist/{ui/conversation → components/conversation/ui}/message-types/timestamp.d.ts +8 -8
  20. package/dist/{ui/conversation → components/conversation/ui}/message-types/user.d.ts +8 -8
  21. package/dist/components/conversation/ui/message.d.ts +7 -0
  22. package/dist/components/conversation/ui/overlay-outlets.d.ts +13 -0
  23. package/dist/components/conversation/ui/styles.d.ts +27 -0
  24. package/dist/{ui/return-button/return-button-component.d.ts → components/return-button/plugin.d.ts} +18 -19
  25. package/dist/{ui → components}/return-button/return-button.d.ts +6 -6
  26. package/dist/conversation-controller.d.ts +88 -88
  27. package/dist/conversation-form-adapter.d.ts +7 -7
  28. package/dist/conversation-platform.d.ts +49 -50
  29. package/dist/conversation-provider.d.ts +22 -22
  30. package/dist/conversation.js +862 -118
  31. package/dist/conversation.js.map +1 -1
  32. package/dist/index.d.ts +10 -9
  33. package/dist/index.js +885 -9
  34. package/dist/index.js.map +1 -1
  35. package/dist/resolve-entity-value.d.ts +10 -10
  36. package/dist/return-button.js.map +1 -1
  37. package/dist/types.d.ts +96 -110
  38. package/dist/user.d.ts +7 -7
  39. package/dist/utils/custom-message.d.ts +3 -3
  40. package/dist/utils/index.d.ts +1 -1
  41. package/dist/utils/map-actions.d.ts +1 -0
  42. package/dist/utils/open-chat-widget.d.ts +4 -4
  43. package/package.json +8 -8
  44. package/dist/index2.js +0 -1678
  45. package/dist/index2.js.map +0 -1
  46. package/dist/ui/conversation/conversation-content.d.ts +0 -12
  47. package/dist/ui/conversation/conversation-message.d.ts +0 -7
  48. package/dist/ui/conversation/conversation-styles.d.ts +0 -11
  49. package/dist/ui/conversation/index.d.ts +0 -3
  50. package/dist/ui/conversation/message-types/custom.d.ts +0 -9
  51. package/dist/ui/index.d.ts +0 -2
  52. package/dist/ui/return-button/index.d.ts +0 -2
@@ -1,4 +1,6 @@
1
1
  var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
2
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
4
6
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
@@ -14,6 +16,7 @@ var __spreadValues = (a, b) => {
14
16
  }
15
17
  return a;
16
18
  };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
17
20
  var __objRest = (source, exclude) => {
18
21
  var target = {};
19
22
  for (var prop in source)
@@ -26,12 +29,12 @@ var __objRest = (source, exclude) => {
26
29
  }
27
30
  return target;
28
31
  };
29
- import { Input, Button, borderTabStyle, SymbolBadge, useDispatch, useProperties, useScroll, invertedHoverButton, Html, List, buttonCss, Lightbox, useTransitionEnd, headingElement } from "@telia-ace/widget-ui";
30
- import { appendClassNames } from "@telia-ace/widget-utilities";
31
- import React, { useState, useEffect, useRef, useCallback } from "react";
32
- import styled, { css } from "styled-components";
33
- import { C as ContentBundle, M as MessageContainer, a as MessageContent, L as Loader, b as ConversationMessageType, S as SystemMessage, c as ConversationContent, A as AgentMessage, U as UserMessage } from "./index2.js";
32
+ import { Input, Button, borderTabStyle, SymbolBadge, useDispatch, useProperties, useScroll, Typography, invertedHoverButton, List, buttonCss, Html as Html$1, genericHtml, Lightbox, ItemList, itemList, useComponent, list, headingElement, usePrevious, useTransitionEnd, WidgetOverlayOutlet } from "@telia-ace/widget-ui";
33
+ import { appendClassNames, uuid } from "@telia-ace/widget-utilities";
34
+ import React, { useState, useEffect, Suspense, useCallback, useRef } from "react";
35
+ import styled, { css, keyframes } from "styled-components";
34
36
  import { FormComponent } from "@telia-ace/widget-forms";
37
+ import { ConversationMessageListItemType, ConversationMessageType } from "./index.js";
35
38
  import "@telia-ace/widget-core";
36
39
  import "@telia-ace/widget-services";
37
40
  import "@telia-ace/widget-plugins";
@@ -79,7 +82,9 @@ const ConversationInput = ({ className }) => {
79
82
  return;
80
83
  }
81
84
  e.preventDefault();
82
- dispatch("action", secondaryAction.action);
85
+ dispatch("action", __spreadValues({
86
+ actionKey: secondaryAction.action
87
+ }, secondaryAction));
83
88
  };
84
89
  const calculateHeight = (value) => {
85
90
  if (multiline && inputRef.current) {
@@ -114,7 +119,7 @@ const ConversationInput = ({ className }) => {
114
119
  className: appendClassNames("humany-conversation-input", className),
115
120
  "data-has-focus": inputFocus,
116
121
  scrollableCss
117
- }, secondaryAction && /* @__PURE__ */ React.createElement(StyledButton, {
122
+ }, secondaryAction && /* @__PURE__ */ React.createElement(SecondaryActionButton, {
118
123
  disabled: inputDisabled,
119
124
  onClick: onSecondaryActionButtonClick,
120
125
  title: secondaryAction.label,
@@ -161,13 +166,10 @@ const StyledTextArea = styled(Input)`
161
166
  line-height: 1.2em;
162
167
  height: 1.2em;
163
168
  padding: 0;
164
- margin: ${(p) => {
169
+ margin: calc(${(p) => {
165
170
  var _a;
166
171
  return (_a = p.theme.sizes) == null ? void 0 : _a.small;
167
- }} ${(p) => {
168
- var _a;
169
- return (_a = p.theme.sizes) == null ? void 0 : _a.medium;
170
- }};
172
+ }} * 2);
171
173
  font-size: ${(p) => {
172
174
  var _a;
173
175
  return (_a = p.theme.fonts) == null ? void 0 : _a.normal;
@@ -219,6 +221,13 @@ const StyledButton = styled(Button)`
219
221
  }};
220
222
  }
221
223
  `;
224
+ const SecondaryActionButton = styled(StyledButton)`
225
+ border-right: ${(p) => p.theme.border};
226
+ margin: ${(p) => {
227
+ var _a;
228
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
229
+ }} 0;
230
+ `;
222
231
  const Wrapper$1 = styled.div`
223
232
  ${(p) => p.grow ? css`
224
233
  min-height: 50px;
@@ -260,6 +269,281 @@ const SendSymbol = styled((_a) => {
260
269
  }};
261
270
  }
262
271
  `;
272
+ const Avatar = styled.div`
273
+ width: ${(p) => p.avatarSize || "32px"};
274
+ height: ${(p) => p.avatarSize || "32px"};
275
+ border-radius: 50%;
276
+ background-color: ${(p) => {
277
+ var _a;
278
+ return (_a = p.theme.colors) == null ? void 0 : _a.accent;
279
+ }};
280
+ border: ${(p) => p.theme.border};
281
+ grid-area: avatar;
282
+ align-self: flex-end;
283
+ justify-self: center;
284
+ overflow: hidden;
285
+ margin-right: ${(p) => {
286
+ var _a;
287
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
288
+ }};
289
+ display: flex;
290
+ justify-content: center;
291
+ align-items: center;
292
+ color: ${(p) => {
293
+ var _a;
294
+ return (_a = p.theme.colors) == null ? void 0 : _a.text;
295
+ }};
296
+
297
+ > img {
298
+ height: 100%;
299
+ width: 100%;
300
+ object-fit: cover;
301
+ }
302
+
303
+ > svg {
304
+ width: 90%;
305
+ height: 90%;
306
+ padding: 10%;
307
+ color: ${(p) => {
308
+ var _a;
309
+ return (_a = p.theme.colors) == null ? void 0 : _a.text;
310
+ }};
311
+
312
+ line,
313
+ path,
314
+ circle,
315
+ fill {
316
+ stroke: ${(p) => {
317
+ var _a;
318
+ return (_a = p.theme.colors) == null ? void 0 : _a.text;
319
+ }};
320
+ }
321
+ }
322
+ `;
323
+ const LoaderAnimation = keyframes`
324
+ 0% {
325
+ opacity: 0;
326
+ }
327
+ 75% {
328
+ opacity: 1;
329
+ }
330
+ 100% {
331
+ opacity: 0;
332
+ }
333
+ `;
334
+ const Loader = styled.div`
335
+ display: flex;
336
+ justify-content: center;
337
+ > div {
338
+ height: 10px;
339
+ width: 10px;
340
+ border-radius: 50%;
341
+ margin: 5px;
342
+ background-color: ${(p) => {
343
+ var _a;
344
+ return (_a = p.theme.colors) == null ? void 0 : _a.text;
345
+ }};
346
+ animation: ${LoaderAnimation} 1s infinite;
347
+ }
348
+ > div:nth-child(2) {
349
+ animation-delay: 100ms;
350
+ }
351
+ > div:nth-child(3) {
352
+ animation-delay: 200ms;
353
+ }
354
+ `;
355
+ const ContentBundle = styled.div`
356
+ grid-area: content;
357
+ max-width: 100%;
358
+ `;
359
+ const MessageTitle = styled(Typography)`
360
+ font-size: ${(p) => {
361
+ var _a;
362
+ return (_a = p.theme.fonts) == null ? void 0 : _a.normal;
363
+ }};
364
+ font-weight: normal;
365
+ margin: 0;
366
+ `;
367
+ const MessageContainer = styled.div`
368
+ display: flex;
369
+ justify-content: ${(p) => p.user ? "end" : "start"};
370
+ `;
371
+ const MessageContent = styled.div`
372
+ ${(p) => !p.user && p.stacked && nonUserMessageStyling(p.stacked, p.theme)}
373
+ ${(p) => p.user && p.stacked && userMessageStyling(p.stacked, p.theme)}
374
+
375
+ display: inline-block;
376
+ margin-top: ${(p) => {
377
+ var _a;
378
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
379
+ }};
380
+ && > * {
381
+ overflow-wrap: break-word;
382
+ word-wrap: break-word;
383
+ word-break: break-all;
384
+ word-break: break-word;
385
+ hyphens: auto;
386
+ }
387
+ max-width: 100%;
388
+ ${(p) => p.fullWidth && "width: 100%;"}
389
+ `;
390
+ const nonUserMessageStyling = (stacked, theme) => {
391
+ var _a, _b;
392
+ const colors = css`
393
+ background-color: ${(_a = theme.colors) == null ? void 0 : _a.accent};
394
+ color: ${(_b = theme.colors) == null ? void 0 : _b.text};
395
+ ${theme.border && `border: ${theme.border};`};
396
+ `;
397
+ if (!theme.borderRadius) {
398
+ return colors;
399
+ }
400
+ return css`
401
+ ${colors}
402
+
403
+ border-top-right-radius: ${theme.borderRadius};
404
+ border-bottom-right-radius: ${theme.borderRadius};
405
+
406
+ ${stacked === "first" && `
407
+ border-top-left-radius: ${theme.borderRadius};
408
+ `}
409
+
410
+ ${stacked === "last" && `
411
+ border-bottom-left-radius: ${theme.borderRadius};
412
+ `}
413
+ `;
414
+ };
415
+ const userMessageStyling = (stacked, theme) => {
416
+ var _a, _b;
417
+ const colors = css`
418
+ background-color: ${(_a = theme.colors) == null ? void 0 : _a.primary};
419
+ color: ${(_b = theme.colors) == null ? void 0 : _b.accent};
420
+ `;
421
+ if (!theme.borderRadius) {
422
+ return colors;
423
+ }
424
+ return css`
425
+ ${colors}
426
+
427
+ border-top-left-radius: ${theme.borderRadius};
428
+ border-bottom-left-radius: ${theme.borderRadius};
429
+
430
+ ${stacked === "first" && `
431
+ border-top-right-radius: ${theme.borderRadius};
432
+ `}
433
+
434
+ ${stacked === "last" && `
435
+ border-bottom-right-radius: ${theme.borderRadius};
436
+ `}
437
+ `;
438
+ };
439
+ const MessageContentPart = styled.div`
440
+ margin-bottom: ${(p) => {
441
+ var _a;
442
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
443
+ }};
444
+ &:last-child {
445
+ margin-bottom: 0;
446
+ }
447
+ `;
448
+ const messageContentPadding = css`
449
+ margin: ${(p) => {
450
+ var _a;
451
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
452
+ }} 0;
453
+ padding: 0 ${(p) => {
454
+ var _a;
455
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
456
+ }};
457
+ `;
458
+ const StyledForm = styled(FormComponent)`
459
+ margin: ${(p) => {
460
+ var _a;
461
+ return (_a = p.theme.sizes) == null ? void 0 : _a.medium;
462
+ }} 0;
463
+ padding: 0 ${(p) => {
464
+ var _a;
465
+ return (_a = p.theme.sizes) == null ? void 0 : _a.medium;
466
+ }};
467
+ & button.humany-form-component-button {
468
+ ${(p) => {
469
+ var _a, _b;
470
+ return invertedHoverButton({
471
+ active: false,
472
+ primaryColor: (_a = p.theme.colors) == null ? void 0 : _a.primary,
473
+ secondaryColor: (_b = p.theme.colors) == null ? void 0 : _b.accent
474
+ });
475
+ }};
476
+ display: block;
477
+ width: 100%;
478
+ margin-bottom: ${(p) => {
479
+ var _a;
480
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
481
+ }};
482
+ }
483
+ & button.humany-form-component-submit {
484
+ width: 100%;
485
+ margin: 0;
486
+ :not(:last-child) {
487
+ margin-bottom: ${(p) => {
488
+ var _a;
489
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
490
+ }};
491
+ }
492
+ }
493
+ `;
494
+ const StyledActionList = styled(List)`
495
+ padding: 0;
496
+ list-style: none;
497
+ button {
498
+ font-size: inherit;
499
+ }
500
+ margin: ${(p) => {
501
+ var _a;
502
+ return (_a = p.theme.sizes) == null ? void 0 : _a.medium;
503
+ }} 0;
504
+ padding: 0 ${(p) => {
505
+ var _a;
506
+ return (_a = p.theme.sizes) == null ? void 0 : _a.medium;
507
+ }};
508
+ display: flex;
509
+ gap: ${(p) => {
510
+ var _a;
511
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
512
+ }};
513
+ `;
514
+ const StyledActionButton = styled.button`
515
+ ${buttonCss};
516
+ display: block;
517
+ background-color: ${(p) => {
518
+ var _a;
519
+ return (_a = p.theme.colors) == null ? void 0 : _a.primary;
520
+ }};
521
+ width: 100%;
522
+ color: #fff;
523
+ margin: ${(p) => {
524
+ var _a;
525
+ return (_a = p.theme.sizes) == null ? void 0 : _a.medium;
526
+ }} 0;
527
+ padding: 0 ${(p) => {
528
+ var _a;
529
+ return (_a = p.theme.sizes) == null ? void 0 : _a.medium;
530
+ }};
531
+ font-family: Lato;
532
+ font-size: ${(p) => {
533
+ var _a;
534
+ return (_a = p.theme.fonts) == null ? void 0 : _a.huge;
535
+ }};
536
+ font-weight: 300;
537
+ &:focus {
538
+ ${(p) => {
539
+ var _a;
540
+ return ((_a = p.theme.accessibility) == null ? void 0 : _a.isTabbing) && css`
541
+ ${borderTabStyle}
542
+ background-color: transparent;
543
+ `;
544
+ }}
545
+ }
546
+ `;
263
547
  const ConversationLoader = ({ className, agentData }) => {
264
548
  return /* @__PURE__ */ React.createElement(ContentBundle, null, /* @__PURE__ */ React.createElement(MessageContainer, null, /* @__PURE__ */ React.createElement(MessageContent, null, /* @__PURE__ */ React.createElement(Loader, null, /* @__PURE__ */ React.createElement("div", null), /* @__PURE__ */ React.createElement("div", null), /* @__PURE__ */ React.createElement("div", null)))));
265
549
  };
@@ -271,21 +555,389 @@ const htmlParseInstructions = {
271
555
  img: imageLightboxRenderer
272
556
  }
273
557
  };
274
- const ConversationMessageComponent = ({
558
+ const Html = ({ body }) => {
559
+ return /* @__PURE__ */ React.createElement(StyledHtml, {
560
+ html: body,
561
+ htmlParseInstruction: htmlParseInstructions
562
+ });
563
+ };
564
+ const StyledHtml = styled(Html$1)`
565
+ ${genericHtml}
566
+ color: inherit;
567
+ white-space: pre-wrap;
568
+ ${messageContentPadding}
569
+ a {
570
+ color: ${(p) => p.theme.colors.link};
571
+ &:focus {
572
+ ${(p) => {
573
+ var _a;
574
+ return ((_a = p.theme.accessibility) == null ? void 0 : _a.isTabbing) && borderTabStyle;
575
+ }};
576
+ }
577
+ }
578
+ `;
579
+ const StyledTimestamp = styled.p`
580
+ && {
581
+ font-size: ${(p) => {
582
+ var _a;
583
+ return (_a = p.theme.fonts) == null ? void 0 : _a.small;
584
+ }};
585
+ font-weight: 300;
586
+ }
587
+ padding-top: ${(p) => {
588
+ var _a;
589
+ return (_a = p.theme.sizes) == null ? void 0 : _a.small;
590
+ }};
591
+ margin: 0;
592
+ line-height: 1.5em;
593
+ grid-area: info;
594
+ color: ${(p) => {
595
+ var _a;
596
+ return (_a = p.theme.colors) == null ? void 0 : _a.text;
597
+ }};
598
+ `;
599
+ const getTimestamp = (raw) => {
600
+ return new Date(raw).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
601
+ };
602
+ const Timestamp = ({ className, name, timestamp }) => {
603
+ if (!name && !timestamp) {
604
+ return null;
605
+ }
606
+ let output = "";
607
+ if (name) {
608
+ if (timestamp) {
609
+ output = `${name}: ${getTimestamp(timestamp)}`;
610
+ } else {
611
+ output = name;
612
+ }
613
+ } else if (timestamp) {
614
+ output = getTimestamp(timestamp);
615
+ }
616
+ return /* @__PURE__ */ React.createElement(StyledTimestamp, null, output);
617
+ };
618
+ const AgentMessage = ({ className, children, sender, timestamp }) => {
619
+ const { avatar, name } = sender;
620
+ const { avatarSize } = useProperties();
621
+ return /* @__PURE__ */ React.createElement(StyledAgentMessage, {
622
+ hasAvatar: !!avatar,
623
+ className: appendClassNames(className, "humany-conversation-agent-message")
624
+ }, avatar && /* @__PURE__ */ React.createElement(Avatar, {
625
+ avatarSize
626
+ }, typeof avatar === "string" ? /* @__PURE__ */ React.createElement("img", {
627
+ src: avatar
628
+ }) : /* @__PURE__ */ React.createElement(SymbolBadge, {
629
+ symbol: avatar
630
+ })), children, /* @__PURE__ */ React.createElement(Timestamp, {
631
+ name,
632
+ timestamp
633
+ }));
634
+ };
635
+ const StyledAgentMessage = styled.div`
636
+ display: grid;
637
+ margin-right: 10%;
638
+ width: 90%;
639
+ ${(p) => p.hasAvatar ? css`
640
+ grid-template-columns: auto 1fr;
641
+ grid-template-rows: 1fr auto;
642
+ grid-template-areas:
643
+ 'avatar content'
644
+ '. info';
645
+ ` : css`
646
+ grid-template-columns: 1fr;
647
+ grid-template-rows: 1fr auto;
648
+ grid-template-areas:
649
+ 'content'
650
+ 'info';
651
+ `};
652
+ `;
653
+ const SystemMessage = ({
654
+ className,
655
+ children,
656
+ timestamp,
657
+ discrete,
658
+ fullWidth
659
+ }) => {
660
+ return /* @__PURE__ */ React.createElement(StyledSystemMessage, {
661
+ className: appendClassNames(className, "humany-conversation-system-message"),
662
+ fullWidth
663
+ }, discrete ? /* @__PURE__ */ React.createElement(Discrete, {
664
+ className: "humany-conversation-discrete-message"
665
+ }, children, /* @__PURE__ */ React.createElement(Timestamp, {
666
+ timestamp
667
+ })) : /* @__PURE__ */ React.createElement(React.Fragment, null, children, /* @__PURE__ */ React.createElement(Timestamp, {
668
+ timestamp
669
+ })));
670
+ };
671
+ const StyledSystemMessage = styled.div`
672
+ ${(p) => p.fullWidth && "width: 100%"};
673
+ padding: 0 ${(p) => {
674
+ var _a;
675
+ return (_a = p.theme.sizes) == null ? void 0 : _a.large;
676
+ }};
677
+ overflow: auto;
678
+ `;
679
+ const Discrete = styled.div`
680
+ text-align: center;
681
+ word-wrap: break-word;
682
+ font-size: ${(p) => {
683
+ var _a;
684
+ return (_a = p.theme.fonts) == null ? void 0 : _a.normal;
685
+ }};
686
+ color: ${(p) => {
687
+ var _a;
688
+ return (_a = p.theme.colors) == null ? void 0 : _a.text;
689
+ }};
690
+ > p {
691
+ margin: 0;
692
+ }
693
+ `;
694
+ const UserMessage = ({ className, children, timestamp }) => {
695
+ const { userLabel = "" } = useProperties();
696
+ return /* @__PURE__ */ React.createElement(StyledUserMessage, {
697
+ className: appendClassNames(className, "humany-conversation-user-message")
698
+ }, children, /* @__PURE__ */ React.createElement(Timestamp, {
699
+ name: userLabel,
700
+ timestamp
701
+ }));
702
+ };
703
+ const StyledUserMessage = styled.div`
704
+ margin-left: 10%;
705
+ width: 90%;
706
+ display: flex;
707
+ flex-direction: column;
708
+ align-items: flex-end;
709
+ `;
710
+ const mapActions = (actions) => Array.isArray(actions) ? actions : Object.keys(actions).map((i) => {
711
+ return {
712
+ label: actions[i],
713
+ actionKey: i
714
+ };
715
+ });
716
+ const ButtonList = ({ header, actions, dispatch }) => {
717
+ return /* @__PURE__ */ React.createElement(StyledButtonList, {
718
+ header,
719
+ items: mapActions(actions),
720
+ renderItem: (item) => {
721
+ return /* @__PURE__ */ React.createElement("li", {
722
+ key: item.actionKey
723
+ }, /* @__PURE__ */ React.createElement(StyledButtonListButton, {
724
+ onClick: () => {
725
+ dispatch("action", item);
726
+ },
727
+ "aria-label": item.label,
728
+ title: item.label
729
+ }, /* @__PURE__ */ React.createElement(SymbolBadge, {
730
+ symbol: item.symbol
731
+ }), item.label));
732
+ }
733
+ });
734
+ };
735
+ const StyledButtonList = styled(ItemList)`
736
+ ${itemList}
737
+ > ul {
738
+ display: flex;
739
+ flex-wrap: wrap;
740
+ gap: ${(p) => {
741
+ var _a;
742
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
743
+ }};
744
+ > li {
745
+ margin: 0;
746
+ }
747
+ }
748
+ ${messageContentPadding}
749
+ `;
750
+ const StyledButtonListButton = styled(Button)`
751
+ ${buttonCss};
752
+
753
+ display: block;
754
+ padding: ${(p) => {
755
+ var _a;
756
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
757
+ }};
758
+ background-color: ${(p) => {
759
+ var _a;
760
+ return (_a = p.theme.colors) == null ? void 0 : _a.primary;
761
+ }};
762
+ width: 100%;
763
+ color: #ffffff;
764
+ &:focus {
765
+ ${(p) => {
766
+ var _a;
767
+ return ((_a = p.theme.accessibility) == null ? void 0 : _a.isTabbing) && css`
768
+ ${borderTabStyle}
769
+ background-color: transparent;
770
+ `;
771
+ }}
772
+ }
773
+
774
+ i,
775
+ svg {
776
+ margin-right: ${(p) => {
777
+ var _a;
778
+ return (_a = p.theme.sizes) == null ? void 0 : _a.small;
779
+ }};
780
+ }
781
+ `;
782
+ const Custom = ({ type, content = {} }) => {
783
+ const Component = useComponent(type);
784
+ if (!Component || !type) {
785
+ return null;
786
+ }
787
+ return /* @__PURE__ */ React.createElement(Suspense, {
788
+ fallback: null
789
+ }, /* @__PURE__ */ React.createElement(Component, __spreadValues({}, content)));
790
+ };
791
+ const LinkList = ({ header, actions, dispatch }) => {
792
+ return /* @__PURE__ */ React.createElement(StyledLinkList, {
793
+ header,
794
+ items: mapActions(actions),
795
+ renderItem: (item) => {
796
+ return /* @__PURE__ */ React.createElement("li", {
797
+ key: item.actionKey
798
+ }, /* @__PURE__ */ React.createElement(StyledLinkButton, {
799
+ help: item.actionKey === "help",
800
+ onClick: () => {
801
+ dispatch("action", item);
802
+ },
803
+ "aria-label": item.label,
804
+ title: item.label
805
+ }, item.label, item.actionKey === "help" && /* @__PURE__ */ React.createElement(SymbolBadge, {
806
+ size: 14,
807
+ symbol: {
808
+ type: "Svg",
809
+ content: "caret-down"
810
+ }
811
+ })));
812
+ }
813
+ });
814
+ };
815
+ const StyledLinkList = styled(ItemList)`
816
+ ${itemList}
817
+ ${messageContentPadding}
818
+ > ul {
819
+ display: flex;
820
+ flex-direction: column;
821
+ gap: ${(p) => {
822
+ var _a;
823
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
824
+ }};
825
+ > li {
826
+ margin: 0;
827
+ }
828
+ }
829
+ `;
830
+ const StyledLinkButton = styled(Button)`
831
+ display: block;
832
+ text-align: left;
833
+ font-weight: 300;
834
+ color: ${(p) => {
835
+ var _a;
836
+ return (_a = p.theme.colors) == null ? void 0 : _a.primary;
837
+ }};
838
+
839
+ ${(p) => {
840
+ var _a, _b;
841
+ return p.help && css`
842
+ color: ${(_a = p.theme.colors) == null ? void 0 : _a.text};
843
+ text-decoration: underline;
844
+
845
+ i,
846
+ svg {
847
+ margin-left: ${(_b = p.theme.sizes) == null ? void 0 : _b.small};
848
+ }
849
+ `;
850
+ }}
851
+
852
+ &:focus {
853
+ ${(p) => {
854
+ var _a, _b;
855
+ return ((_a = p.theme.accessibility) == null ? void 0 : _a.isTabbing) && css`
856
+ ${borderTabStyle}
857
+ span {
858
+ color: ${(_b = p.theme.colors) == null ? void 0 : _b.primary};
859
+ text-decoration: underline;
860
+ }
861
+ `;
862
+ }};
863
+ }
864
+ `;
865
+ const Separator = () => {
866
+ return /* @__PURE__ */ React.createElement(StyledSeparator, null);
867
+ };
868
+ const StyledSeparator = styled.div`
869
+ ${(p) => p.theme.border && `border-bottom: ${p.theme.border};`}
870
+ width: 100%;
871
+ `;
872
+ const Text = ({ text }) => {
873
+ return /* @__PURE__ */ React.createElement(StyledTypography, {
874
+ variant: "span"
875
+ }, text);
876
+ };
877
+ const StyledTypography = styled(Typography)`
878
+ ${messageContentPadding}
879
+ `;
880
+ const mapItem = ([type, content]) => {
881
+ return { type, content, id: uuid() };
882
+ };
883
+ const MessageList = ({ items, dispatch }) => {
884
+ return /* @__PURE__ */ React.createElement(StyledList, {
885
+ items: items.map(mapItem),
886
+ renderLi: true,
887
+ renderItem: (item) => {
888
+ switch (item.type) {
889
+ case ConversationMessageListItemType.Text: {
890
+ return /* @__PURE__ */ React.createElement(Text, {
891
+ text: item.content
892
+ });
893
+ }
894
+ case ConversationMessageListItemType.HTML: {
895
+ return /* @__PURE__ */ React.createElement(Html, __spreadValues({}, item.content));
896
+ }
897
+ case ConversationMessageListItemType.Separator: {
898
+ return /* @__PURE__ */ React.createElement(Separator, __spreadValues({}, item.content));
899
+ }
900
+ case ConversationMessageListItemType.LinkList: {
901
+ return /* @__PURE__ */ React.createElement(LinkList, __spreadProps(__spreadValues({}, item.content), {
902
+ dispatch
903
+ }));
904
+ }
905
+ case ConversationMessageListItemType.ButtonList: {
906
+ return /* @__PURE__ */ React.createElement(ButtonList, __spreadProps(__spreadValues({}, item.content), {
907
+ dispatch
908
+ }));
909
+ }
910
+ default: {
911
+ return /* @__PURE__ */ React.createElement(Custom, {
912
+ type: item.type,
913
+ content: item.content
914
+ });
915
+ }
916
+ }
917
+ }
918
+ });
919
+ };
920
+ const StyledList = styled(List)`
921
+ ${list}
922
+
923
+ > li {
924
+ margin: 0;
925
+ }
926
+ `;
927
+ const ConversationMessage = ({
275
928
  className,
276
929
  timestamp,
277
930
  sender,
278
931
  type,
279
932
  content
280
933
  }) => {
281
- useDispatch();
282
- const getMessageStackPosition = (index) => {
283
- let messageOrder = void 0;
934
+ const getMessageStackPosition = useCallback((index) => {
935
+ let messageOrder = "first";
284
936
  if (content.length > 1) {
285
937
  messageOrder = index === 0 ? "first" : index + 1 === content.length ? "last" : "middle";
286
938
  }
287
939
  return messageOrder;
288
- };
940
+ }, [content]);
289
941
  const createSystemMessage = () => {
290
942
  return /* @__PURE__ */ React.createElement(React.Fragment, null, content.map((item) => {
291
943
  const { key, body, title, form, actions } = item;
@@ -297,9 +949,8 @@ const ConversationMessageComponent = ({
297
949
  timestamp,
298
950
  fullWidth: !!form || !!actions
299
951
  }, discrete && body ? /* @__PURE__ */ React.createElement(Html, {
300
- html: body,
301
- htmlParseInstruction: htmlParseInstructions
302
- }) : /* @__PURE__ */ React.createElement(ConversationContent, {
952
+ body
953
+ }) : /* @__PURE__ */ React.createElement(Message, {
303
954
  content: item,
304
955
  isUser: false
305
956
  }));
@@ -313,7 +964,7 @@ const ConversationMessageComponent = ({
313
964
  }, /* @__PURE__ */ React.createElement(ContentBundle, null, content.map((item, index) => {
314
965
  return /* @__PURE__ */ React.createElement(MessageContainer, {
315
966
  key: item.key
316
- }, /* @__PURE__ */ React.createElement(ConversationContent, {
967
+ }, /* @__PURE__ */ React.createElement(Message, {
317
968
  content: item,
318
969
  isUser: false,
319
970
  stacked: getMessageStackPosition(index)
@@ -326,8 +977,9 @@ const ConversationMessageComponent = ({
326
977
  className
327
978
  }, /* @__PURE__ */ React.createElement(ContentBundle, null, content.map((item, index) => {
328
979
  return /* @__PURE__ */ React.createElement(MessageContainer, {
980
+ user: true,
329
981
  key: item.key
330
- }, /* @__PURE__ */ React.createElement(ConversationContent, {
982
+ }, /* @__PURE__ */ React.createElement(Message, {
331
983
  content: item,
332
984
  isUser: true,
333
985
  stacked: getMessageStackPosition(index)
@@ -345,86 +997,51 @@ const ConversationMessageComponent = ({
345
997
  return null;
346
998
  }
347
999
  };
348
- styled(FormComponent)`
349
- & button.humany-form-component-button {
350
- ${(p) => {
351
- var _a, _b;
352
- return invertedHoverButton({
353
- active: false,
354
- primaryColor: (_a = p.theme.colors) == null ? void 0 : _a.primary,
355
- secondaryColor: (_b = p.theme.colors) == null ? void 0 : _b.accent
356
- });
357
- }};
358
- display: block;
359
- width: 100%;
360
- margin-bottom: ${(p) => {
361
- var _a;
362
- return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
363
- }};
364
- }
365
-
366
- & button.humany-form-component-submit {
367
- width: 100%;
368
- margin: 0;
369
- :not(:last-child) {
370
- margin-bottom: ${(p) => {
371
- var _a;
372
- return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
373
- }};
374
- }
1000
+ const Message = ({ content, isUser, stacked }) => {
1001
+ const dispatch = useDispatch();
1002
+ const { title, body, actions, form, items } = content;
1003
+ return /* @__PURE__ */ React.createElement(MessageContent, {
1004
+ user: isUser,
1005
+ stacked,
1006
+ fullWidth: !!form || !!actions
1007
+ }, title && /* @__PURE__ */ React.createElement(MessageContentPart, null, /* @__PURE__ */ React.createElement(MessageTitle, {
1008
+ variant: "h2"
1009
+ }, title)), body && /* @__PURE__ */ React.createElement(MessageContentPart, null, /* @__PURE__ */ React.createElement(Html, {
1010
+ body
1011
+ })), form && /* @__PURE__ */ React.createElement(MessageContentPart, null, /* @__PURE__ */ React.createElement(StyledForm, __spreadProps(__spreadValues({}, form), {
1012
+ onChange: (key, data) => {
1013
+ dispatch("form", {
1014
+ data,
1015
+ formKey: form.schema.id,
1016
+ actionKey: key
1017
+ });
375
1018
  }
376
- `;
377
- styled(Html)`
378
- white-space: pre-wrap;
379
-
380
- a {
381
- color: ${(p) => p.theme.colors.link};
382
- &:focus {
383
- ${(p) => {
384
- var _a;
385
- return ((_a = p.theme.accessibility) == null ? void 0 : _a.isTabbing) && borderTabStyle;
386
- }};
1019
+ }))), actions && /* @__PURE__ */ React.createElement(MessageContentPart, null, /* @__PURE__ */ React.createElement(StyledActionList, {
1020
+ items: Object.keys(actions).map((i) => {
1021
+ return { label: actions[i], actionKey: i };
1022
+ }),
1023
+ renderItem: (item) => {
1024
+ return /* @__PURE__ */ React.createElement("li", {
1025
+ key: item.actionKey
1026
+ }, /* @__PURE__ */ React.createElement(StyledActionButton, {
1027
+ onClick: () => {
1028
+ dispatch("action", item.actionKey);
387
1029
  }
1030
+ }, item.label));
388
1031
  }
389
- `;
390
- styled(List)`
391
- padding: 0;
392
- list-style: none;
393
- margin: 0 -${(p) => {
394
- var _a;
395
- return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
396
- }};
397
- > li {
398
- margin: ${(p) => {
399
- var _a;
400
- return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
401
- }};
402
- }
403
- `;
404
- styled.button`
405
- ${buttonCss};
406
- display: block;
407
- background-color: ${(p) => {
408
- var _a;
409
- return (_a = p.theme.colors) == null ? void 0 : _a.primary;
410
- }};
411
- width: 100%;
412
- color: #fff;
413
- &:focus {
414
- ${(p) => {
415
- var _a;
416
- return ((_a = p.theme.accessibility) == null ? void 0 : _a.isTabbing) && css`
417
- ${borderTabStyle}
418
- background-color: transparent;
419
- `;
420
- }}
421
- }
422
- `;
423
- const Conversation = ({ className }) => {
1032
+ })), items && /* @__PURE__ */ React.createElement(MessageList, {
1033
+ key: uuid(),
1034
+ items,
1035
+ dispatch
1036
+ }));
1037
+ };
1038
+ const ConversationContent = () => {
424
1039
  const lastEntry = useRef(document.createElement("div"));
425
1040
  const [scrollableCss, viewElem] = useScroll(true);
426
1041
  const { messages, loading, typingActors } = useProperties();
427
1042
  const [canSmooth, setCanSmooth] = useState(false);
1043
+ const previousMessages = usePrevious(messages);
1044
+ const previousTypingActors = usePrevious(typingActors);
428
1045
  const scrollView = useCallback((lastEntry2, smooth = true) => {
429
1046
  if (lastEntry2 !== null && lastEntry2.current !== null) {
430
1047
  if (messages && messages.length === 1) {
@@ -440,12 +1057,23 @@ const Conversation = ({ className }) => {
440
1057
  behavior: smooth ? "smooth" : "auto"
441
1058
  });
442
1059
  }
443
- }, 0);
1060
+ }, 150);
444
1061
  }
445
1062
  }, [lastEntry]);
446
1063
  useEffect(() => {
447
1064
  if (canSmooth) {
448
- scrollView(lastEntry);
1065
+ const messageCountChanged = messages.length !== (previousMessages == null ? void 0 : previousMessages.length);
1066
+ const typingActorCountChanged = typingActors.length !== (previousTypingActors == null ? void 0 : previousTypingActors.length);
1067
+ const messageContentCountChanged = messages.reduce((changed, message, index) => {
1068
+ var _a;
1069
+ if (((_a = previousMessages == null ? void 0 : previousMessages[index]) == null ? void 0 : _a.content.length) !== message.content.length) {
1070
+ return true;
1071
+ }
1072
+ return changed;
1073
+ }, false);
1074
+ if (messageCountChanged || messageContentCountChanged || typingActorCountChanged) {
1075
+ scrollView(lastEntry);
1076
+ }
449
1077
  }
450
1078
  }, [messages, typingActors]);
451
1079
  useTransitionEnd(() => {
@@ -467,9 +1095,7 @@ const Conversation = ({ className }) => {
467
1095
  }
468
1096
  return null;
469
1097
  };
470
- return /* @__PURE__ */ React.createElement(Wrapper, {
471
- className: appendClassNames(className, "humany-conversation-component")
472
- }, /* @__PURE__ */ React.createElement(Scrollable, {
1098
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Scrollable, {
473
1099
  tabIndex: 0,
474
1100
  scrollableCss,
475
1101
  ref: viewElem
@@ -480,19 +1106,9 @@ const Conversation = ({ className }) => {
480
1106
  tabIndex: -1,
481
1107
  key: `${type}_${sender == null ? void 0 : sender.name}_${timestamp}_${content[0].key}`,
482
1108
  ref: index + 1 < messages.length ? null : typingActors.length ? null : lastEntry
483
- }, /* @__PURE__ */ React.createElement(ConversationMessageComponent, __spreadValues({}, message)));
1109
+ }, /* @__PURE__ */ React.createElement(ConversationMessage, __spreadValues({}, message)));
484
1110
  }) : null, renderTypingActors(), loading && /* @__PURE__ */ React.createElement(MessageEntry, null, /* @__PURE__ */ React.createElement(ConversationLoader, null))), /* @__PURE__ */ React.createElement(ConversationInput, null));
485
1111
  };
486
- const Wrapper = styled.div`
487
- position: absolute;
488
- right: 0;
489
- left: 0;
490
- bottom: 0;
491
- top: 0;
492
- overflow: hidden;
493
- display: flex;
494
- flex-direction: column;
495
- `;
496
1112
  const Scrollable = styled.div`
497
1113
  display: flex;
498
1114
  flex-direction: column;
@@ -531,13 +1147,6 @@ const MessageEntry = styled.div`
531
1147
  }};
532
1148
  }
533
1149
 
534
- * {
535
- font-size: ${(p) => {
536
- var _a;
537
- return (_a = p.theme.fonts) == null ? void 0 : _a.normal;
538
- }};
539
- }
540
-
541
1150
  & span,
542
1151
  p,
543
1152
  a,
@@ -554,5 +1163,140 @@ const MessageEntry = styled.div`
554
1163
  font-weight: normal;
555
1164
  `)}
556
1165
  `;
1166
+ const OverlayOutlet = ({ dispatch }) => {
1167
+ const wrapperRef = useRef(null);
1168
+ useEffect(() => {
1169
+ if (wrapperRef.current && wrapperRef.current.parentNode) {
1170
+ dispatch("overlay-outlet-mounted", wrapperRef.current);
1171
+ }
1172
+ }, [wrapperRef]);
1173
+ return /* @__PURE__ */ React.createElement(WidgetOverlayOutlet, {
1174
+ portalId: "humany-conversation-overlay-portal",
1175
+ className: "humany-conversation-overlay-outlet",
1176
+ ref: wrapperRef
1177
+ });
1178
+ };
1179
+ const ConversationOverlayOutlet = ({
1180
+ dispatch,
1181
+ header,
1182
+ buttonLabel
1183
+ }) => {
1184
+ return /* @__PURE__ */ React.createElement(StyledWidgetOverlayOutlet, {
1185
+ portalId: "humany-conversation-portal",
1186
+ className: "humany-conversation-outlet"
1187
+ }, /* @__PURE__ */ React.createElement(ConversationOverlayHead, {
1188
+ className: "humany-conversation-outlet-head"
1189
+ }, /* @__PURE__ */ React.createElement(ConversationOverlayHeadButton, {
1190
+ className: "humany-conversation-outlet-head-button",
1191
+ "aria-label": buttonLabel,
1192
+ title: buttonLabel,
1193
+ onClick: () => dispatch("hide-overlay-conversation")
1194
+ }, /* @__PURE__ */ React.createElement(SymbolBadge, {
1195
+ symbol: {
1196
+ type: "Svg",
1197
+ content: "caret-down"
1198
+ },
1199
+ size: 20
1200
+ })), header && /* @__PURE__ */ React.createElement(ConversationOverlayHeader, {
1201
+ className: "humany-conversation-outlet-header",
1202
+ variant: "h1"
1203
+ }, header)), /* @__PURE__ */ React.createElement(ConversationContent, null));
1204
+ };
1205
+ const StyledWidgetOverlayOutlet = styled(WidgetOverlayOutlet)`
1206
+ z-index: 11;
1207
+ top: auto;
1208
+ height: 65%;
1209
+ background-color: #ffffff;
1210
+ display: flex;
1211
+ flex-direction: column;
1212
+ border-top-right-radius: ${(p) => {
1213
+ var _a;
1214
+ return (_a = p.theme.sizes) == null ? void 0 : _a.large;
1215
+ }};
1216
+ border-top-left-radius: ${(p) => {
1217
+ var _a;
1218
+ return (_a = p.theme.sizes) == null ? void 0 : _a.large;
1219
+ }};
1220
+ `;
1221
+ const ConversationOverlayHead = styled.div`
1222
+ display: flex;
1223
+ flex-direction: column;
1224
+ justify-content: center;
1225
+ align-items: center;
1226
+ gap: ${(p) => {
1227
+ var _a;
1228
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
1229
+ }};
1230
+ padding: ${(p) => {
1231
+ var _a;
1232
+ return (_a = p.theme.sizes) == null ? void 0 : _a.normal;
1233
+ }};
1234
+ ${(p) => p.theme.border && `border-bottom: ${p.theme.border};`}
1235
+ `;
1236
+ const ConversationOverlayHeader = styled(Typography)`
1237
+ font-size: ${(p) => {
1238
+ var _a;
1239
+ return (_a = p.theme.fonts) == null ? void 0 : _a.medium;
1240
+ }};
1241
+ color: ${(p) => {
1242
+ var _a;
1243
+ return (_a = p.theme.colors) == null ? void 0 : _a.text;
1244
+ }};
1245
+ margin: 0;
1246
+ `;
1247
+ const ConversationOverlayHeadButton = styled(Button)`
1248
+ display: flex;
1249
+ align-items: center;
1250
+ justify-content: center;
1251
+ padding: ${(p) => {
1252
+ var _a;
1253
+ return (_a = p.theme.sizes) == null ? void 0 : _a.small;
1254
+ }} ${(p) => {
1255
+ var _a;
1256
+ return (_a = p.theme.sizes) == null ? void 0 : _a.medium;
1257
+ }};
1258
+ ${(p) => p.theme.borderRadius && `border-radius: ${p.theme.borderRadius};`}
1259
+
1260
+ &:focus {
1261
+ ${(p) => {
1262
+ var _a;
1263
+ return ((_a = p.theme.accessibility) == null ? void 0 : _a.isTabbing) && borderTabStyle;
1264
+ }};
1265
+ }
1266
+
1267
+ svg line {
1268
+ stroke: ${(p) => {
1269
+ var _a;
1270
+ return (_a = p.theme.colors) == null ? void 0 : _a.text;
1271
+ }};
1272
+ }
1273
+ `;
1274
+ const Conversation = ({ className }) => {
1275
+ const {
1276
+ overlay,
1277
+ overlayConversationHeader,
1278
+ overlayConversationCloseLabel
1279
+ } = useProperties();
1280
+ const dispatch = useDispatch();
1281
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Wrapper, {
1282
+ className: appendClassNames(className, "humany-conversation-component")
1283
+ }, /* @__PURE__ */ React.createElement(ConversationContent, null)), overlay && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(OverlayOutlet, {
1284
+ dispatch
1285
+ }), overlay.conversation && /* @__PURE__ */ React.createElement(ConversationOverlayOutlet, {
1286
+ dispatch,
1287
+ header: overlayConversationHeader,
1288
+ buttonLabel: overlayConversationCloseLabel
1289
+ })));
1290
+ };
1291
+ const Wrapper = styled.div`
1292
+ position: absolute;
1293
+ right: 0;
1294
+ left: 0;
1295
+ bottom: 0;
1296
+ top: 0;
1297
+ overflow: hidden;
1298
+ display: flex;
1299
+ flex-direction: column;
1300
+ `;
557
1301
  export { Conversation as default };
558
1302
  //# sourceMappingURL=conversation.js.map