botframework-webchat-fluent-theme 4.18.1-main.20250325.438c779 → 4.18.1-main.20250423.8c9cf52

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botframework-webchat-fluent-theme",
3
- "version": "4.18.1-main.20250325.438c779",
3
+ "version": "4.18.1-main.20250423.8c9cf52",
4
4
  "description": "Fluent theme for Bot Framework Web Chat",
5
5
  "main": "./dist/botframework-webchat-fluent-theme.js",
6
6
  "types": "./dist/botframework-webchat-fluent-theme.d.ts",
@@ -72,15 +72,15 @@
72
72
  "@types/math-random": "^1.0.2",
73
73
  "@types/node": "^22.13.4",
74
74
  "@types/react": "^16.14.62",
75
- "botframework-webchat-base": "4.18.1-main.20250325.438c779",
76
- "botframework-webchat-styles": "4.18.1-main.20250325.438c779",
75
+ "botframework-webchat-base": "4.18.1-main.20250423.8c9cf52",
76
+ "botframework-webchat-styles": "4.18.1-main.20250423.8c9cf52",
77
77
  "tsup": "^8.3.6",
78
78
  "typescript": "^5.7.3"
79
79
  },
80
80
  "dependencies": {
81
- "botframework-webchat-api": "4.18.1-main.20250325.438c779",
82
- "botframework-webchat-component": "4.18.1-main.20250325.438c779",
83
- "botframework-webchat-core": "4.18.1-main.20250325.438c779",
81
+ "botframework-webchat-api": "4.18.1-main.20250423.8c9cf52",
82
+ "botframework-webchat-component": "4.18.1-main.20250423.8c9cf52",
83
+ "botframework-webchat-core": "4.18.1-main.20250423.8c9cf52",
84
84
  "classnames": "2.5.1",
85
85
  "inject-meta-tag": "0.0.1",
86
86
  "math-random": "2.0.1",
package/src/bundle.ts CHANGED
@@ -1,8 +1,10 @@
1
+ import { SendBox as FluentSendBox } from './components/sendBox/index';
1
2
  import { FluentThemeProvider, testIds } from './index';
2
3
 
3
4
  (globalThis as any).WebChat = {
4
5
  ...(globalThis as any).WebChat,
5
6
  FluentThemeProvider,
7
+ FluentSendBox,
6
8
  testIds: {
7
9
  ...(globalThis as any).WebChat?.testIds,
8
10
  ...testIds
@@ -85,7 +85,7 @@
85
85
  font-size: 14px;
86
86
  line-height: 20px;
87
87
  outline: none;
88
- padding: 4px 4px 0;
88
+ margin: var(--webchat-spacingVerticalXS) var(--webchat-spacingHorizontalXS) var(--webchat-spacingVerticalNone);
89
89
  resize: none;
90
90
 
91
91
  /* Prevent zoom on focus on iOS */
@@ -1,6 +1,14 @@
1
1
  import { hooks, type SendBoxFocusOptions } from 'botframework-webchat-component';
2
2
  import cx from 'classnames';
3
- import React, { memo, useCallback, useRef, useState, type FormEventHandler, type MouseEventHandler } from 'react';
3
+ import React, {
4
+ memo,
5
+ ReactNode,
6
+ useCallback,
7
+ useRef,
8
+ useState,
9
+ type FormEventHandler,
10
+ type MouseEventHandler
11
+ } from 'react';
4
12
  import { useRefFrom } from 'use-ref-from';
5
13
  import { SendIcon } from '../../icons';
6
14
  import { useStyles, useVariantClassName } from '../../styles';
@@ -33,6 +41,7 @@ const {
33
41
 
34
42
  type Props = Readonly<{
35
43
  className?: string | undefined;
44
+ completion?: ReactNode | undefined;
36
45
  isPrimary?: boolean | undefined;
37
46
  placeholder?: string | undefined;
38
47
  }>;
@@ -198,6 +207,7 @@ function SendBox(props: Props) {
198
207
  <TextArea
199
208
  aria-label={isMessageLengthExceeded ? localize('TEXT_INPUT_LENGTH_EXCEEDED_ALT') : localize('TEXT_INPUT_ALT')}
200
209
  className={cx(classNames['sendbox__sendbox-text'], classNames['sendbox__text-area--in-grid'])}
210
+ completion={props.completion}
201
211
  data-testid={testIds.sendBoxTextBox}
202
212
  hidden={shouldShowTelephoneKeypad}
203
213
  onInput={handleMessageChange}
@@ -2,7 +2,8 @@
2
2
  display: grid;
3
3
  grid-template-areas: 'main';
4
4
  max-height: 200px;
5
- overflow: hidden;
5
+ overflow: auto;
6
+ scrollbar-gutter: stable;
6
7
  }
7
8
 
8
9
  :global(.webchat-fluent) .sendbox__text-area--hidden {
@@ -11,6 +12,22 @@
11
12
  visibility: collapse;
12
13
  }
13
14
 
15
+ :global(.webchat-fluent) .sendbox__text-area--in-completion {
16
+ .sendbox__text-area-doppelganger {
17
+ visibility: visible;
18
+ }
19
+
20
+ .sendbox__text-area-input {
21
+ background-color: transparent;
22
+ caret-color: var(--webchat-colorNeutralForeground1);
23
+ color: transparent;
24
+ }
25
+
26
+ textarea::placeholder {
27
+ color: transparent;
28
+ }
29
+ }
30
+
14
31
  :global(.webchat-fluent) .sendbox__text-area-shared {
15
32
  border: none;
16
33
  font: inherit;
@@ -18,11 +35,12 @@
18
35
  outline: inherit;
19
36
  overflow-wrap: anywhere;
20
37
  resize: inherit;
21
- scrollbar-gutter: stable;
22
38
  }
23
39
 
24
40
  :global(.webchat-fluent) .sendbox__text-area-doppelganger {
25
- overflow: hidden;
41
+ overflow: visible;
42
+ pointer-events: none;
43
+ user-select: none;
26
44
  visibility: hidden;
27
45
  white-space: pre-wrap;
28
46
  }
@@ -30,11 +48,12 @@
30
48
  :global(.webchat-fluent) .sendbox__text-area-input {
31
49
  background-color: inherit;
32
50
  color: currentColor;
33
- height: 100%;
51
+ contain: size;
52
+ overflow: hidden;
34
53
  padding: 0;
35
54
  }
36
55
 
37
- :global(.webchat-fluent) .sendbox__text-area-input--scroll {
56
+ :global(.webchat-fluent) .sendbox__text-area--scroll {
38
57
  /* Edge uses -webkit-scrollbar if scrollbar-* is not set */
39
58
  scrollbar-color: unset;
40
59
  scrollbar-width: unset;
@@ -1,6 +1,14 @@
1
1
  import { hooks } from 'botframework-webchat-api';
2
2
  import cx from 'classnames';
3
- import React, { forwardRef, Fragment, useCallback, type FormEventHandler, type KeyboardEventHandler } from 'react';
3
+ import React, {
4
+ forwardRef,
5
+ Fragment,
6
+ useCallback,
7
+ useRef,
8
+ type FormEventHandler,
9
+ type KeyboardEventHandler,
10
+ type ReactNode
11
+ } from 'react';
4
12
  import { useStyles } from '../../styles';
5
13
  import styles from './TextArea.module.css';
6
14
 
@@ -11,6 +19,7 @@ const TextArea = forwardRef<
11
19
  Readonly<{
12
20
  'aria-label'?: string | undefined;
13
21
  className?: string | undefined;
22
+ completion?: ReactNode | undefined;
14
23
  'data-testid'?: string | undefined;
15
24
 
16
25
  /**
@@ -30,13 +39,22 @@ const TextArea = forwardRef<
30
39
  >((props, ref) => {
31
40
  const [uiState] = useUIState();
32
41
  const classNames = useStyles(styles);
42
+ const isInCompositionRef = useRef<boolean>(false);
33
43
 
34
44
  const disabled = uiState === 'disabled';
35
45
 
46
+ const handleCompositionEnd = useCallback(() => {
47
+ isInCompositionRef.current = false;
48
+ }, [isInCompositionRef]);
49
+
50
+ const handleCompositionStart = useCallback(() => {
51
+ isInCompositionRef.current = true;
52
+ }, [isInCompositionRef]);
53
+
36
54
  const handleKeyDown = useCallback<KeyboardEventHandler<HTMLTextAreaElement>>(event => {
37
55
  // Shift+Enter adds a new line
38
56
  // Enter requests related form submission
39
- if (!event.shiftKey && event.key === 'Enter') {
57
+ if (!event.shiftKey && event.key === 'Enter' && !isInCompositionRef.current) {
40
58
  event.preventDefault();
41
59
 
42
60
  if ('form' in event.target && event.target.form instanceof HTMLFormElement) {
@@ -49,41 +67,29 @@ const TextArea = forwardRef<
49
67
  <div
50
68
  className={cx(
51
69
  classNames['sendbox__text-area'],
70
+ classNames['sendbox__text-area--scroll'],
52
71
  { [classNames['sendbox__text-area--hidden']]: props.hidden },
72
+ { [classNames['sendbox__text-area--in-completion']]: props.completion },
53
73
  props.className
54
74
  )}
55
75
  role={props.hidden ? 'hidden' : undefined}
56
76
  >
57
77
  {uiState === 'blueprint' ? (
58
- <div
59
- className={cx(
60
- classNames['sendbox__text-area-doppelganger'],
61
- classNames['sendbox__text-area-input--scroll'],
62
- classNames['sendbox__text-area-shared']
63
- )}
64
- >
78
+ <div className={cx(classNames['sendbox__text-area-doppelganger'], classNames['sendbox__text-area-shared'])}>
65
79
  {' '}
66
80
  </div>
67
81
  ) : (
68
82
  <Fragment>
69
- <div
70
- className={cx(
71
- classNames['sendbox__text-area-doppelganger'],
72
- classNames['sendbox__text-area-input--scroll'],
73
- classNames['sendbox__text-area-shared']
74
- )}
75
- >
76
- {props.value || props.placeholder}{' '}
83
+ <div className={cx(classNames['sendbox__text-area-doppelganger'], classNames['sendbox__text-area-shared'])}>
84
+ {props.completion ? props.completion : props.value || props.placeholder}{' '}
77
85
  </div>
78
86
  <textarea
79
87
  aria-disabled={disabled}
80
88
  aria-label={props['aria-label']}
81
- className={cx(
82
- classNames['sendbox__text-area-input'],
83
- classNames['sendbox__text-area-input--scroll'],
84
- classNames['sendbox__text-area-shared']
85
- )}
89
+ className={cx(classNames['sendbox__text-area-input'], classNames['sendbox__text-area-shared'])}
86
90
  data-testid={props['data-testid']}
91
+ onCompositionEnd={handleCompositionEnd}
92
+ onCompositionStart={handleCompositionStart}
87
93
  onInput={props.onInput}
88
94
  onKeyDown={handleKeyDown}
89
95
  placeholder={props.placeholder}
@@ -21,6 +21,8 @@
21
21
  --webchat-colorNeutralForeground4: var(--colorNeutralForeground4, #707070);
22
22
  --webchat-colorNeutralForeground5: var(--colorNeutralForeground5, #7e7e7e);
23
23
 
24
+ --webchat-colorNeutralForegroundOnBrand: var(--colorNeutralForegroundOnBrand, #fff);
25
+
24
26
  --webchat-colorNeutralBackgroundDisabled: var(--colorNeutralBackgroundDisabled, #f0f0f0);
25
27
  --webchat-colorNeutralBackground1: var(--colorNeutralBackground1, #ffffff);
26
28
  --webchat-colorNeutralBackground1Hover: var(--colorNeutralBackground1Hover, #f5f5f5);
@@ -61,6 +63,9 @@
61
63
  --webchat-colorBrandForegroundLinkPressed: var(--colorBrandForegroundLinkPressed, #014259);
62
64
  --webchat-colorBrandForegroundLinkSelected: var(--colorBrandForegroundLinkSelected, #01678c);
63
65
 
66
+ --webchat-colorBrandBackground: var(--colorBrandBackground, #077fab);
67
+ --webchat-colorBrandBackgroundHover: var(--colorBrandBackgroundHover, #06729a);
68
+ --webchat-colorBrandBackgroundPressed: var(--colorBrandBackgroundPressed, #044760);
64
69
  --webchat-colorBrandBackground2: var(--colorBrandBackground2, #def2fc);
65
70
  --webchat-colorBrandBackground2Hover: var(--colorBrandBackground2Hover, #bee7fa);
66
71
  --webchat-colorBrandBackground2Pressed: var(--colorBrandBackground2Pressed, #7fd2f5);
@@ -206,7 +211,6 @@
206
211
  --webchat__padding--regular: var(--webchat-spacingVerticalS);
207
212
  --webchat__padding--sendbox: var(--webchat-spacingVerticalNone) var(--webchat-spacingHorizontalMNudge)
208
213
  var(--webchat-spacingHorizontalMNudge);
209
-
210
214
  --webchat__border-animation--color-1: #464feb;
211
215
  --webchat__border-animation--color-2: #47cffa;
212
216
  --webchat__border-animation--color-3: #b47cf8;
@@ -231,6 +235,7 @@
231
235
  :global(.webchat-fluent).theme :global(.webchat__basic-transcript .webchat__basic-transcript__scrollable),
232
236
  :global(.webchat-fluent).theme :global(.webchat__view-code-dialog__code-body),
233
237
  :global(.webchat-fluent).theme :global(.webchat__render-markdown [data-math-type='block']),
238
+ :global(.webchat-fluent).theme :global(.webchat__feedback-form-text-area-input--scroll),
234
239
  :global(.webchat-fluent).theme :global(.webchat__view-code-dialog__body) {
235
240
  /* Edge uses -webkit-scrollbar if scrollbar-* is not set */
236
241
  scrollbar-color: unset;
@@ -623,3 +628,99 @@
623
628
  padding: var(--webchat-spacingVerticalSNudge) var(--webchat-spacingHorizontalM);
624
629
  transition: opacity var(--webchat-durationNormal) var(--webchat-curveDecelerateMid);
625
630
  }
631
+
632
+ /* Feedback Form */
633
+ :global(.webchat-fluent).theme :global(.webchat__feedback-form__body1) {
634
+ font-family: var(--webchat-fontFamilyBase);
635
+ color: var(--webchat-colorNeutralForeground1);
636
+ font-size: var(--webchat-fontSizeBase300);
637
+ font-weight: var(--webchat-fontWeightRegular);
638
+ line-height: var(--webchat-lineHeightBase300);
639
+ }
640
+
641
+ :global(.webchat-fluent).theme :global(.webchat__feedback-form__caption1) {
642
+ font-family: var(--webchat-fontFamilyBase);
643
+ color: var(--webchat-colorNeutralForeground1);
644
+ font-size: var(--webchat-fontSizeBase100);
645
+ font-weight: var(--webchat-fontWeightRegular);
646
+ line-height: var(--webchat-lineHeightBase200);
647
+ }
648
+
649
+ :global(.webchat-fluent).theme :global(.webchat__feedback-form__button__submit) {
650
+ background-color: var(--webchat-colorBrandBackground);
651
+ border: var(--webchat-strokeWidthThin) solid var(--webchat-colorBrandBackground);
652
+ border-radius: var(--webchat-borderRadiusMedium);
653
+ color: var(--webchat-colorNeutralForegroundOnBrand);
654
+ cursor: pointer;
655
+ font-family: var(--webchat-fontFamilyBase);
656
+ font-size: var(--webchat-fontSizeBase300);
657
+ padding: var(--webchat-spacingVerticalNone) var(--webchat-spacingHorizontalS);
658
+ transition: background-color var(--webchat-durationNormal) var(--webchat-curveDecelerateMid);
659
+
660
+ &:hover {
661
+ background-color: var(--webchat-colorBrandBackgroundHover);
662
+ border: var(--webchat-strokeWidthThin) solid var(--webchat-colorBrandBackgroundHover);
663
+ }
664
+
665
+ &:focus-visible {
666
+ outline: var(--webchat-strokeWidthThick) solid var(--webchat-colorStrokeFocus2);
667
+ outline-offset: calc(var(--webchat-strokeWidthThin) * -1);
668
+ }
669
+
670
+ &:active {
671
+ background-color: var(--webchat-colorBrandBackgroundPressed);
672
+ border: var(--webchat-strokeWidthThin) solid var(--webchat-colorBrandBackgroundPressed);
673
+ }
674
+ }
675
+
676
+ :global(.webchat-fluent).theme :global(.webchat__feedback-form__button__cancel) {
677
+ background-color: var(--webchat-colorNeutralBackground1);
678
+ border: var(--webchat-strokeWidthThin) solid var(--webchat-colorNeutralStroke1);
679
+ border-radius: var(--webchat-borderRadiusMedium);
680
+ color: var(--webchat-colorNeutralForeground1);
681
+ cursor: pointer;
682
+ font-family: var(--webchat-fontFamilyBase);
683
+ font-size: var(--webchat-fontSizeBase300);
684
+ padding: var(--webchat-spacingVerticalNone) var(--webchat-spacingHorizontalS);
685
+ transition: background-color var(--webchat-durationNormal) var(--webchat-curveDecelerateMid);
686
+
687
+ &:hover {
688
+ background-color: var(--webchat-colorNeutralBackground1Hover);
689
+ border: var(--webchat-strokeWidthThin) solid var(--webchat-colorNeutralStroke1Hover);
690
+ }
691
+
692
+ &:focus-visible {
693
+ outline: var(--webchat-strokeWidthThick) solid var(--webchat-colorStrokeFocus2);
694
+ outline-offset: calc(var(--webchat-strokeWidthThin) * -1);
695
+ }
696
+
697
+ &:active {
698
+ background-color: var(--webchat-colorNeutralBackground1Pressed);
699
+ border: var(--webchat-strokeWidthThin) solid var(--webchat-colorNeutralStroke1Pressed);
700
+ }
701
+ }
702
+
703
+ :global(.webchat-fluent).theme :global(.webchat__feedback-form-text-area) {
704
+ background-color: var(--webchat-colorNeutralBackground1);
705
+ border-radius: var(--webchat-borderRadiusMedium);
706
+ border: var(--webchat-strokeWidthThin) solid var(--webchat-colorNeutralStroke1);
707
+ font-family: var(--webchat-fontFamilyBase);
708
+ font-size: var(--webchat-fontSizeBase300);
709
+ line-height: var(--webchat-lineHeightBase300);
710
+ gap: var(--webchat-spacingVerticalSNudge);
711
+ padding: var(--webchat-spacingVerticalS) var(--webchat-spacingHorizontalM);
712
+ &::after {
713
+ border-bottom-left-radius: var(--webchat-borderRadiusMedium);
714
+ border-bottom-right-radius: var(--webchat-borderRadiusMedium);
715
+ border-bottom: var(--webchat-strokeWidthThicker) solid var(--webchat-colorBrandForeground1);
716
+ clip-path: inset(calc(100% - var(--webchat-strokeWidthThicker)) 50% 0 50%);
717
+ transition: clip-path var(--webchat-durationNormal) var(--webchat-curveDecelerateMid);
718
+ }
719
+ &:focus-within {
720
+ border: var(--webchat-strokeWidthThin) solid var(--webchat-colorNeutralStroke1);
721
+ }
722
+ &:focus-within::after {
723
+ clip-path: inset(calc(100% - var(--webchat-strokeWidthThicker)) 0 0 0);
724
+ transition: clip-path var(--webchat-durationNormal) var(--webchat-curveDecelerateMid);
725
+ }
726
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { injectMetaTag } from 'inject-meta-tag';
2
2
 
3
+ import { SendBox as FluentSendBox } from './components/sendBox/index';
3
4
  import FluentThemeProvider from './private/FluentThemeProvider';
4
5
  import testIds from './testIds';
5
6
 
@@ -14,4 +15,4 @@ injectMetaTag(
14
15
  `version=${process.env['npm_package_version']}; build-tool=${process.env['build_tool']}; module-format=${process.env['module_format']}`
15
16
  );
16
17
 
17
- export { FluentThemeProvider, buildInfo, testIds };
18
+ export { FluentThemeProvider, FluentSendBox, buildInfo, testIds };