botframework-webchat-fluent-theme 4.17.0-main.20240411.ff34969 → 4.17.0-main.20240416.4ff01ae

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 (47) hide show
  1. package/dist/botframework-webchat-fluent-theme.development.css.map +1 -0
  2. package/dist/botframework-webchat-fluent-theme.development.js +384 -2081
  3. package/dist/botframework-webchat-fluent-theme.development.js.map +1 -1
  4. package/dist/botframework-webchat-fluent-theme.production.min.css.map +1 -0
  5. package/dist/botframework-webchat-fluent-theme.production.min.js +1 -3
  6. package/dist/botframework-webchat-fluent-theme.production.min.js.map +1 -1
  7. package/dist/index.css.map +1 -0
  8. package/dist/index.d.mts +27 -0
  9. package/dist/index.d.ts +27 -0
  10. package/dist/index.js +360 -648
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +1076 -0
  13. package/dist/index.mjs.map +1 -1
  14. package/package.json +9 -8
  15. package/src/components/Theme.module.css +60 -0
  16. package/src/components/Theme.tsx +4 -64
  17. package/src/components/dropZone/index.module.css +23 -0
  18. package/src/components/dropZone/index.tsx +6 -31
  19. package/src/components/sendbox/AddAttachmentButton.module.css +10 -0
  20. package/src/components/sendbox/AddAttachmentButton.tsx +5 -17
  21. package/src/components/sendbox/Attachments.module.css +7 -0
  22. package/src/components/sendbox/Attachments.tsx +3 -12
  23. package/src/components/sendbox/ErrorMessage.module.css +9 -0
  24. package/src/components/sendbox/ErrorMessage.tsx +2 -13
  25. package/src/components/sendbox/TelephoneKeypadToolbarButton.tsx +1 -1
  26. package/src/components/sendbox/TextArea.module.css +61 -0
  27. package/src/components/sendbox/TextArea.tsx +9 -70
  28. package/src/components/sendbox/Toolbar.module.css +49 -0
  29. package/src/components/sendbox/Toolbar.tsx +4 -55
  30. package/src/components/sendbox/index.module.css +58 -0
  31. package/src/components/sendbox/index.tsx +16 -81
  32. package/src/components/suggestedActions/SuggestedAction.module.css +34 -0
  33. package/src/components/suggestedActions/SuggestedAction.tsx +5 -47
  34. package/src/components/suggestedActions/index.module.css +23 -0
  35. package/src/components/suggestedActions/index.tsx +18 -23
  36. package/src/components/telephoneKeypad/private/Button.module.css +62 -0
  37. package/src/components/telephoneKeypad/private/Button.tsx +5 -67
  38. package/src/components/telephoneKeypad/private/TelephoneKeypad.module.css +30 -0
  39. package/src/components/telephoneKeypad/private/TelephoneKeypad.tsx +4 -35
  40. package/src/env.d.ts +7 -0
  41. package/src/index.ts +3 -0
  42. package/src/styles/injectStyle.ts +9 -0
  43. package/src/styles/useStyles.ts +19 -0
  44. package/src/styles.ts +4 -0
  45. package/src/tsconfig.json +2 -1
  46. package/src/private/useStyleToEmotionObject.ts +0 -32
  47. package/src/styles/index.ts +0 -15
@@ -3,7 +3,6 @@ import cx from 'classnames';
3
3
  import React, { memo, useCallback, useRef, useState, type FormEventHandler, type MouseEventHandler } from 'react';
4
4
  import { useRefFrom } from 'use-ref-from';
5
5
  import { SendIcon } from '../../icons/SendIcon';
6
- import { useStyles } from '../../styles';
7
6
  import testIds from '../../testIds';
8
7
  import DropZone from '../DropZone';
9
8
  import SuggestedActions from '../SuggestedActions';
@@ -16,70 +15,11 @@ import TextArea from './TextArea';
16
15
  import { Toolbar, ToolbarButton, ToolbarSeparator } from './Toolbar';
17
16
  import useSubmitError from './private/useSubmitError';
18
17
  import useUniqueId from './private/useUniqueId';
18
+ import styles from './index.module.css';
19
+ import { useStyles } from '../../styles';
19
20
 
20
21
  const { useStyleOptions, useMakeThumbnail, useLocalizer, useSendBoxAttachments, useSendMessage } = hooks;
21
22
 
22
- const styles = {
23
- 'webchat-fluent__sendbox': {
24
- color: 'var(--webchat-colorNeutralForeground1)',
25
- fontFamily: 'var(--webchat-fontFamilyBase)',
26
- padding: '0 10px 10px',
27
- textRendering: 'optimizeLegibility'
28
- },
29
-
30
- 'webchat-fluent__sendbox__sendbox': {
31
- backgroundColor: 'var(--webchat-colorNeutralBackground1)',
32
- border: '1px solid var(--webchat-colorNeutralStroke1)',
33
- borderRadius: 'var(--webchat-borderRadiusLarge)',
34
- display: 'grid',
35
- fontFamily: 'var(--webchat-fontFamilyBase)',
36
- fontSize: '14px',
37
- gap: '6px',
38
- lineHeight: '20px',
39
- padding: '8px',
40
- position: 'relative',
41
-
42
- '&:focus-within': {
43
- borderColor: 'var(--webchat-colorNeutralStroke1Selected)',
44
- // TODO clarify with design the color:
45
- // - Teams is using colorCompoundBrandForeground1
46
- // - Fluent is using colorCompoundBrandStroke
47
- // - we are using colorCompoundBrandForeground1Hover
48
- boxShadow: 'inset 0 -6px 0 -3px var(--webchat-colorCompoundBrandForeground1Hover)'
49
- }
50
- },
51
-
52
- 'webchat-fluent__sendbox__sendbox-text': {
53
- backgroundColor: 'transparent',
54
- border: 'none',
55
- flex: 'auto',
56
- fontFamily: 'var(--webchat-fontFamilyBase)',
57
- fontSize: '14px',
58
- lineHeight: '20px',
59
- outline: 'none',
60
- padding: '4px 4px 0',
61
- resize: 'none'
62
- },
63
-
64
- 'webchat-fluent__sendbox__sendbox-controls': {
65
- alignItems: 'center',
66
- display: 'flex',
67
- paddingInlineStart: '4px'
68
- },
69
-
70
- 'webchat-fluent__sendbox__text-counter': {
71
- color: 'var(--webchat-colorNeutralForeground4)',
72
- cursor: 'default',
73
- fontFamily: 'var(--webchat-fontFamilyNumeric)',
74
- fontSize: '10px',
75
- lineHeight: '14px'
76
- },
77
-
78
- 'webchat-fluent__sendbox__text-counter--error': {
79
- color: 'var(--webchat-colorStatusDangerForeground1)'
80
- }
81
- };
82
-
83
23
  function SendBox(
84
24
  props: Readonly<{
85
25
  className?: string | undefined;
@@ -89,15 +29,15 @@ function SendBox(
89
29
  const inputRef = useRef<HTMLTextAreaElement>(null);
90
30
  const [message, setMessage] = useState('');
91
31
  const [attachments, setAttachments] = useSendBoxAttachments();
92
- const [{ maxMessageLength }] = useStyleOptions();
32
+ const [{ hideTelephoneKeypadButton, hideUploadButton, maxMessageLength }] = useStyleOptions();
93
33
  const isMessageLengthExceeded = !!maxMessageLength && message.length > maxMessageLength;
94
34
  const classNames = useStyles(styles);
95
35
  const localize = useLocalizer();
96
36
  const sendMessage = useSendMessage();
97
37
  const makeThumbnail = useMakeThumbnail();
98
- const errorMessageId = useUniqueId('webchat-fluent__sendbox__error-message-id');
38
+ const errorMessageId = useUniqueId('sendbox__error-message-id');
99
39
  const [errorRef, errorMessage] = useSubmitError({ message, attachments });
100
- const [telephoneKeypadShown, setTelephoneKeypadShown] = useTelephoneKeypadShown();
40
+ const [telephoneKeypadShown] = useTelephoneKeypadShown();
101
41
 
102
42
  const attachmentsRef = useRefFrom(attachments);
103
43
  const messageRef = useRefFrom(message);
@@ -162,14 +102,9 @@ function SendBox(
162
102
  );
163
103
 
164
104
  const handleTelephoneKeypadButtonClick = useCallback(
165
- (dtmf: DTMF) => {
166
- // TODO: We need more official way of sending DTMF.
167
- sendMessage(`/DTMF ${dtmf}`);
168
-
169
- // TODO: In the future when we work on input modality, it should manage the focus in a better way.
170
- setTelephoneKeypadShown(false);
171
- },
172
- [sendMessage, setTelephoneKeypadShown]
105
+ // TODO: We need more official way of sending DTMF.
106
+ (dtmf: DTMF) => sendMessage(`/DTMF ${dtmf}`),
107
+ [sendMessage]
173
108
  );
174
109
 
175
110
  const aria = {
@@ -181,9 +116,9 @@ function SendBox(
181
116
  };
182
117
 
183
118
  return (
184
- <form {...aria} className={cx(classNames['webchat-fluent__sendbox'], props.className)} onSubmit={handleFormSubmit}>
119
+ <form {...aria} className={cx(classNames['sendbox'], props.className)} onSubmit={handleFormSubmit}>
185
120
  <SuggestedActions />
186
- <div className={cx(classNames['webchat-fluent__sendbox__sendbox'])} onClickCapture={handleSendBoxClick}>
121
+ <div className={cx(classNames['sendbox__sendbox'])} onClickCapture={handleSendBoxClick}>
187
122
  <TelephoneKeypadSurrogate
188
123
  autoFocus={true}
189
124
  isHorizontal={false}
@@ -191,7 +126,7 @@ function SendBox(
191
126
  />
192
127
  <TextArea
193
128
  aria-label={isMessageLengthExceeded ? localize('TEXT_INPUT_LENGTH_EXCEEDED_ALT') : localize('TEXT_INPUT_ALT')}
194
- className={classNames['webchat-fluent__sendbox__sendbox-text']}
129
+ className={classNames['sendbox__sendbox-text']}
195
130
  data-testid={testIds.sendBoxTextBox}
196
131
  hidden={telephoneKeypadShown}
197
132
  onInput={handleMessageChange}
@@ -200,19 +135,19 @@ function SendBox(
200
135
  value={message}
201
136
  />
202
137
  <Attachments attachments={attachments} />
203
- <div className={cx(classNames['webchat-fluent__sendbox__sendbox-controls'])}>
138
+ <div className={cx(classNames['sendbox__sendbox-controls'])}>
204
139
  {maxMessageLength && (
205
140
  <div
206
- className={cx(classNames['webchat-fluent__sendbox__text-counter'], {
207
- [classNames['webchat-fluent__sendbox__text-counter--error']]: isMessageLengthExceeded
141
+ className={cx(classNames['sendbox__text-counter'], {
142
+ [classNames['sendbox__text-counter--error']]: isMessageLengthExceeded
208
143
  })}
209
144
  >
210
145
  {`${message.length}/${maxMessageLength}`}
211
146
  </div>
212
147
  )}
213
148
  <Toolbar>
214
- <TelephoneKeypadToolbarButton />
215
- <AddAttachmentButton onFilesAdded={handleAddFiles} />
149
+ {!hideTelephoneKeypadButton && <TelephoneKeypadToolbarButton />}
150
+ {!hideUploadButton && <AddAttachmentButton onFilesAdded={handleAddFiles} />}
216
151
  <ToolbarSeparator />
217
152
  <ToolbarButton
218
153
  aria-label={localize('TEXT_INPUT_SEND_BUTTON_ALT')}
@@ -0,0 +1,34 @@
1
+ :global(.webchat-fluent) .suggested-action {
2
+ align-items: center;
3
+ background: transparent;
4
+ border-radius: 8px;
5
+ border: 1px solid var(--webchat-colorBrandStroke2);
6
+ cursor: pointer;
7
+ display: flex;
8
+ font-size: 12px;
9
+ gap: 4px;
10
+ padding: 4px 8px 4px;
11
+ text-align: start;
12
+ transition: all .15s ease-out;
13
+
14
+ @media (hover: hover) {
15
+ &:not([aria-disabled="true"]):hover {
16
+ background-color: var(--webchat-colorBrandBackground2Hover);
17
+ color: var(--webchat-colorBrandForeground2Hover)
18
+ }
19
+ }
20
+ &:not([aria-disabled="true"]):active {
21
+ background-color: var(--webchat-colorBrandBackground2Pressed);
22
+ color: var(--webchat-colorBrandForeground2Pressed)
23
+ }
24
+ &[aria-disabled="true"] {
25
+ color: var(--webchat-colorNeutralForegroundDisabled);
26
+ cursor: not-allowed
27
+ }
28
+ }
29
+
30
+ :global(.webchat-fluent) .suggested-action__image {
31
+ font-size: 12px;
32
+ height: 1em;
33
+ width: 1em;
34
+ }
@@ -2,10 +2,11 @@ import { hooks } from 'botframework-webchat-component';
2
2
  import { type DirectLineCardAction } from 'botframework-webchat-core';
3
3
  import cx from 'classnames';
4
4
  import React, { MouseEventHandler, memo, useCallback, useRef } from 'react';
5
- import AccessibleButton from './AccessibleButton';
5
+ import styles from './SuggestedAction.module.css';
6
6
  import { useStyles } from '../../styles';
7
+ import AccessibleButton from './AccessibleButton';
7
8
 
8
- const { useScrollToEnd, useStyleSet, usePerformCardAction, useFocus, useSuggestedActions, useDisabled } = hooks;
9
+ const { useDisabled, useFocus, usePerformCardAction, useScrollToEnd, useStyleSet, useSuggestedActions } = hooks;
9
10
 
10
11
  type SuggestedActionProps = Readonly<{
11
12
  buttonText: string | undefined;
@@ -29,45 +30,6 @@ type SuggestedActionProps = Readonly<{
29
30
  value?: any;
30
31
  }>;
31
32
 
32
- const styles = {
33
- 'webchat-fluent__suggested-action': {
34
- background: 'transparent',
35
- border: '1px solid var(--webchat-colorBrandStroke2)',
36
- borderRadius: '8px',
37
- cursor: 'pointer',
38
- fontSize: '12px',
39
- lineHeight: '14px',
40
- padding: '6px 8px 4px',
41
- textAlign: 'start',
42
- display: 'flex',
43
- gap: '4px',
44
- alignItems: 'center',
45
- transition: 'all .15s ease-out',
46
-
47
- '@media (hover: hover)': {
48
- '&:not([aria-disabled="true"]):hover': {
49
- backgroundColor: 'var(--webchat-colorBrandBackground2Hover)',
50
- color: 'var(--webchat-colorBrandForeground2Hover)'
51
- }
52
- },
53
- '&:not([aria-disabled="true"]):active': {
54
- backgroundColor: 'var(--webchat-colorBrandBackground2Pressed)',
55
- color: 'var(--webchat-colorBrandForeground2Pressed)'
56
- },
57
- '&[aria-disabled="true"]': {
58
- color: ' var(--webchat-colorNeutralForegroundDisabled)',
59
- cursor: 'not-allowed'
60
- }
61
- },
62
-
63
- 'webchat-fluent__suggested-action__image': {
64
- width: '1em',
65
- height: '1em',
66
- fontSize: '20px',
67
- translate: '0 -1px'
68
- }
69
- };
70
-
71
33
  function SuggestedAction({
72
34
  buttonText,
73
35
  className,
@@ -110,17 +72,13 @@ function SuggestedAction({
110
72
 
111
73
  return (
112
74
  <AccessibleButton
113
- className={cx(
114
- classNames['webchat-fluent__suggested-action'],
115
- suggestedActionStyleSet + '',
116
- (className || '') + ''
117
- )}
75
+ className={cx(classNames['suggested-action'], suggestedActionStyleSet + '', (className || '') + '')}
118
76
  disabled={disabled}
119
77
  onClick={handleClick}
120
78
  ref={focusRef}
121
79
  type="button"
122
80
  >
123
- {image && <img alt={imageAlt} className={classNames['webchat-fluent__suggested-action__image']} src={image} />}
81
+ {image && <img alt={imageAlt} className={classNames['suggested-action__image']} src={image} />}
124
82
  <span>{buttonText}</span>
125
83
  </AccessibleButton>
126
84
  );
@@ -0,0 +1,23 @@
1
+
2
+ :global(.webchat-fluent) .suggested-actions {
3
+ align-items: flex-end;
4
+ align-self: flex-end;
5
+ display: flex;
6
+ flex-direction: column;
7
+ gap: 8px;
8
+
9
+ &:not(:empty) {
10
+ padding-block-end: 8px;
11
+ padding-inline-start: 4px
12
+ }
13
+
14
+ &.suggested-actions--flow {
15
+ flex-direction: row;
16
+ flex-wrap: wrap;
17
+ justify-content: flex-end;
18
+ }
19
+
20
+ &.suggested-actions--stacked {
21
+ flex-direction: column
22
+ }
23
+ }
@@ -1,34 +1,21 @@
1
1
  import { hooks } from 'botframework-webchat-component';
2
2
  import cx from 'classnames';
3
3
  import React, { memo, type ReactNode } from 'react';
4
- import { useStyles } from '../../styles';
5
- import computeSuggestedActionText from './private/computeSuggestedActionText';
6
4
  import SuggestedAction from './SuggestedAction';
5
+ import computeSuggestedActionText from './private/computeSuggestedActionText';
6
+ import styles from './index.module.css';
7
+ import { useStyles } from '../../styles';
7
8
 
8
- const { useLocalizer, useStyleSet, useSuggestedActions } = hooks;
9
-
10
- const styles = {
11
- 'webchat-fluent__suggested-actions': {
12
- alignItems: 'flex-end',
13
- alignSelf: 'flex-end',
14
- display: 'flex',
15
- flexDirection: 'column',
16
- gap: '8px',
17
-
18
- '&:not(:empty)': {
19
- paddingBlockEnd: '8px',
20
- paddingInlineStart: '4px'
21
- }
22
- }
23
- };
9
+ const { useLocalizer, useStyleOptions, useStyleSet, useSuggestedActions } = hooks;
24
10
 
25
- function SuggestedActionStackedContainer(
11
+ function SuggestedActionStackedOrFlowContainer(
26
12
  props: Readonly<{
27
13
  'aria-label'?: string | undefined;
28
14
  children?: ReactNode | undefined;
29
15
  className?: string | undefined;
30
16
  }>
31
17
  ) {
18
+ const [{ suggestedActionLayout }] = useStyleOptions();
32
19
  const [{ suggestedActions: suggestedActionsStyleSet }] = useStyleSet();
33
20
  const classNames = useStyles(styles);
34
21
 
@@ -37,7 +24,15 @@ function SuggestedActionStackedContainer(
37
24
  aria-label={props['aria-label']}
38
25
  aria-live="polite"
39
26
  aria-orientation="vertical"
40
- className={cx(classNames['webchat-fluent__suggested-actions'], suggestedActionsStyleSet + '', props.className)}
27
+ className={cx(
28
+ classNames['suggested-actions'],
29
+ suggestedActionsStyleSet + '',
30
+ {
31
+ [classNames['suggested-actions--flow']]: suggestedActionLayout === 'flow',
32
+ [classNames['suggested-actions--stacked']]: suggestedActionLayout !== 'flow'
33
+ },
34
+ props.className
35
+ )}
41
36
  role="toolbar"
42
37
  >
43
38
  {!!props.children && !!React.Children.count(props.children) && props.children}
@@ -91,12 +86,12 @@ function SuggestedActions() {
91
86
  );
92
87
  });
93
88
  return (
94
- <SuggestedActionStackedContainer
89
+ <SuggestedActionStackedOrFlowContainer
95
90
  aria-label={localize('SUGGESTED_ACTIONS_LABEL_ALT')}
96
- className={classNames['webchat-fluent__suggested-actions']}
91
+ className={classNames['suggested-actions']}
97
92
  >
98
93
  {children}
99
- </SuggestedActionStackedContainer>
94
+ </SuggestedActionStackedOrFlowContainer>
100
95
  );
101
96
  }
102
97
 
@@ -0,0 +1,62 @@
1
+
2
+ :global(.webchat-fluent) .telephone-keypad__button {
3
+ -webkit-user-select: none;
4
+ align-items: center;
5
+ appearance: none;
6
+ /* backgroundColor: isDarkTheme() || isHighContrastTheme() ? black : white, */
7
+ background-color: White;
8
+ border-radius: 100%;
9
+
10
+ /* Whitelabel styles */
11
+ /* border: `solid 1px ${isHighContrastTheme() ? white : isDarkTheme() ? gray160 : gray40}`, */
12
+ /* color: inherit; */
13
+
14
+ border: solid 1px var(--webchat-colorNeutralStroke1);
15
+ color: var(--webchat-colorGray200);
16
+ font-weight: var(--webchat-fontWeightSemibold);
17
+
18
+ cursor: pointer;
19
+ display: flex;
20
+ flex-direction: column;
21
+ height: 60px;
22
+ opacity: 0.7;
23
+ padding: 0;
24
+ position: relative;
25
+ touch-action: none;
26
+ user-select: none;
27
+ width: 60px;
28
+
29
+ &:hover {
30
+ /* backgroundColor: isHighContrastTheme() ? gray210 : isDarkTheme() ? gray150 : gray30 */
31
+ background-color: var(--webchat-colorGray30)
32
+ }
33
+ }
34
+
35
+ :global(.webchat-fluent) .telephone-keypad__button__ruby {
36
+ /* color: isHighContrastTheme() ? white : isDarkTheme() ? gray40 : gray160, */
37
+ color: var(--webchat-colorGray190);
38
+ font-size: 10px;
39
+ }
40
+
41
+ :global(.webchat-fluent) .telephone-keypad__button__text {
42
+ font-size: 24px;
43
+ margin-top: 8px;
44
+ }
45
+
46
+ :global(.webchat-fluent) .telephone-keypad--horizontal {
47
+ & .telephone-keypad__button {
48
+ height: 32px;
49
+ justify-content: center;
50
+ margin: 8px 4px;
51
+ width: 32px;
52
+ };
53
+
54
+ .telephone-keypad__button__ruby {
55
+ display: none;
56
+ }
57
+
58
+ & .telephone-keypad__button__text {
59
+ font-size: 20px;
60
+ margin-top: 0;
61
+ }
62
+ }
@@ -2,72 +2,10 @@ import React, { forwardRef, memo, useCallback, type Ref } from 'react';
2
2
 
3
3
  import { useRefFrom } from 'use-ref-from';
4
4
 
5
- import { useStyles } from '../../../styles';
6
5
  import { type DTMF } from '../types';
7
6
 
8
- const styles = {
9
- 'webchat__telephone-keypad__button': {
10
- '-webkit-user-select': 'none',
11
- alignItems: 'center',
12
- appearance: 'none',
13
- // backgroundColor: isDarkTheme() || isHighContrastTheme() ? black : white,
14
- backgroundColor: 'White',
15
- borderRadius: '100%',
16
-
17
- // Whitelabel styles
18
- // border: `solid 1px ${isHighContrastTheme() ? white : isDarkTheme() ? gray160 : gray40}`,
19
- // color: 'inherit',
20
-
21
- border: 'solid 1px var(--webchat-colorNeutralStroke1)',
22
- color: 'var(--webchat-colorNeutralForeground1)',
23
- fontWeight: 'var(--webchat-fontWeightSemibold)',
24
-
25
- cursor: 'pointer',
26
- display: 'flex',
27
- flexDirection: 'column',
28
- height: 60,
29
- opacity: 0.7,
30
- padding: 0,
31
- position: 'relative',
32
- touchAction: 'none',
33
- userSelect: 'none',
34
- width: 60,
35
-
36
- '&:hover': {
37
- // backgroundColor: isHighContrastTheme() ? gray210 : isDarkTheme() ? gray150 : gray30
38
- backgroundColor: 'var(--webchat-colorGray30)'
39
- }
40
- },
41
-
42
- 'webchat__telephone-keypad__button__ruby': {
43
- // color: isHighContrastTheme() ? white : isDarkTheme() ? gray40 : gray160,
44
- color: 'var(--webchat-colorGray160)',
45
- fontSize: 10
46
- },
47
-
48
- 'webchat__telephone-keypad__button__text': {
49
- fontSize: 24,
50
- marginTop: 8
51
- },
52
-
53
- 'webchat__telephone-keypad--horizontal': {
54
- '& .webchat__telephone-keypad__button': {
55
- height: 32,
56
- width: 32,
57
- margin: '8px 4px',
58
- justifyContent: 'center'
59
- },
60
-
61
- 'webchat__telephone-keypad__button__ruby': {
62
- display: 'none'
63
- },
64
-
65
- '& .webchat__telephone-keypad__button__text': {
66
- fontSize: 20,
67
- marginTop: 0
68
- }
69
- }
70
- };
7
+ import styles from './Button.module.css';
8
+ import { useStyles } from '../../../styles';
71
9
 
72
10
  type Props = Readonly<{
73
11
  button: DTMF;
@@ -87,16 +25,16 @@ const Button = memo(
87
25
 
88
26
  return (
89
27
  <button
90
- className={classNames['webchat__telephone-keypad__button']}
28
+ className={classNames['telephone-keypad__button']}
91
29
  data-testid={dataTestId}
92
30
  onClick={handleClick}
93
31
  ref={ref}
94
32
  type="button"
95
33
  >
96
- <span className={classNames['webchat__telephone-keypad__button__text']}>
34
+ <span className={classNames['telephone-keypad__button__text']}>
97
35
  {button === 'star' ? '\u2217' : button === 'pound' ? '#' : button}
98
36
  </span>
99
- {!!ruby && <ruby className={classNames['webchat__telephone-keypad__button__ruby']}>{ruby}</ruby>}
37
+ {!!ruby && <ruby className={classNames['telephone-keypad__button__ruby']}>{ruby}</ruby>}
100
38
  </button>
101
39
  );
102
40
  })
@@ -0,0 +1,30 @@
1
+
2
+ :global(.webchat-fluent) .telephone-keypad {
3
+ /* Commented out whitelabel styles for now. */
4
+ /* background: getHighContrastDarkThemeColor(highContrastColor: black, darkThemeColor: gray190, string, defaultColor: gray10), */
5
+ /* borderRadius: '8px 8px 0px 0px; */
6
+ /* boxShadow: '-3px 0px 7px 0px rgba(0, 0, 0, 0.13), -0.6px 0px 1.8px 0px rgba(0, 0, 0, 0.10)', */
7
+
8
+ align-items: center;
9
+ background: var(--webchat-colorNeutralBackground1);
10
+ /* border: isHighContrastTheme() ? `1px solid ${white}` : none; */
11
+ border: none;
12
+ border-radius: var(--webchat-borderRadiusXLarge);
13
+ /* boxShadow: var(--shadow16); */
14
+ display: flex;
15
+ flex-direction: column;
16
+ font-family: var(--webchat-fontFamilyBase);
17
+ justify-content: center;
18
+ /* margin: var(--spacingHorizontalMNudge)' */
19
+ }
20
+
21
+ :global(.webchat-fluent) .telephone-keypad__box {
22
+ box-sizing: border-box;
23
+ display: grid;
24
+ gap: 16px;
25
+ grid-template-columns: repeat(3, 1fr);
26
+ grid-template-rows: repeat(4, 1fr);
27
+ justify-items: center;
28
+ padding: 16px;
29
+ width: 100%;
30
+ }
@@ -1,44 +1,13 @@
1
1
  import React, { KeyboardEventHandler, memo, useCallback, useEffect, useRef, type ReactNode } from 'react';
2
2
  import { useRefFrom } from 'use-ref-from';
3
3
 
4
- import { useStyles } from '../../../styles';
5
4
  import Button from './Button';
6
5
  // import HorizontalDialPadController from './HorizontalDialPadController';
7
6
  import testIds from '../../../testIds';
8
7
  import { type DTMF } from '../types';
9
8
  import useShown from '../useShown';
10
-
11
- const styles = {
12
- 'webchat__telephone-keypad': {
13
- /* Commented out whitelabel styles for now. */
14
- // background: getHighContrastDarkThemeColor(highContrastColor: black, darkThemeColor: gray190, string, defaultColor: gray10),
15
- // borderRadius: '8px 8px 0px 0px',
16
- // boxShadow: '-3px 0px 7px 0px rgba(0, 0, 0, 0.13), -0.6px 0px 1.8px 0px rgba(0, 0, 0, 0.10)',
17
-
18
- alignItems: 'center',
19
- background: 'var(--webchat-colorNeutralBackground1)',
20
- // border: isHighContrastTheme() ? `1px solid ${white}` : 'none',
21
- border: 'none',
22
- borderRadius: 'var(--webchat-borderRadiusXLarge)',
23
- // boxShadow: 'var(--shadow16)',
24
- display: 'flex',
25
- flexDirection: 'column',
26
- fontFamily: 'var(--webchat-fontFamilyBase)',
27
- justifyContent: 'center'
28
- // margin: 'var(--spacingHorizontalMNudge)'
29
- },
30
-
31
- 'webchat__telephone-keypad__box': {
32
- boxSizing: 'border-box',
33
- display: 'grid',
34
- gap: '16px',
35
- gridTemplateColumns: 'repeat(3, 1fr)',
36
- gridTemplateRows: 'repeat(4, 1fr)',
37
- justifyItems: 'center',
38
- padding: '16px',
39
- width: '100%'
40
- }
41
- };
9
+ import styles from './TelephoneKeypad.module.css';
10
+ import { useStyles } from '../../../styles';
42
11
 
43
12
  type Props = Readonly<{
44
13
  autoFocus?: boolean | undefined;
@@ -54,7 +23,7 @@ const Orientation = memo(
54
23
  // <HorizontalDialPadController>{children}</HorizontalDialPadController>
55
24
  false
56
25
  ) : (
57
- <div className={classNames['webchat__telephone-keypad__box']}>{children}</div>
26
+ <div className={classNames['telephone-keypad__box']}>{children}</div>
58
27
  );
59
28
  }
60
29
  );
@@ -95,7 +64,7 @@ const TelephoneKeypad = memo(({ autoFocus, onButtonClick, isHorizontal }: Props)
95
64
  }, [autoFocusRef, firstButtonRef]);
96
65
 
97
66
  return (
98
- <div className={classNames['webchat__telephone-keypad']} onKeyDown={handleKeyDown}>
67
+ <div className={classNames['telephone-keypad']} onKeyDown={handleKeyDown}>
99
68
  <Orientation isHorizontal={isHorizontal}>
100
69
  <Button
101
70
  button="1"
package/src/env.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ // CSS modules
2
+ type CSSModuleClasses = { readonly [key: string]: any };
3
+
4
+ declare module '*.module.css' {
5
+ const classes: CSSModuleClasses;
6
+ export default classes;
7
+ }
package/src/index.ts CHANGED
@@ -2,9 +2,12 @@ import { injectMetaTag } from 'inject-meta-tag';
2
2
 
3
3
  import FluentThemeProvider from './private/FluentThemeProvider';
4
4
  import testIds from './testIds';
5
+ import { injectStyle } from './styles';
5
6
 
6
7
  declare const NPM_PACKAGE_VERSION: string;
7
8
 
8
9
  injectMetaTag('botframework-webchat-fluent-theme:version', NPM_PACKAGE_VERSION);
9
10
 
11
+ injectStyle();
12
+
10
13
  export { FluentThemeProvider, testIds };
@@ -0,0 +1,9 @@
1
+ export const injectedStyles = '@--INJECTED-STYLES-CONTENT--@';
2
+
3
+ export default function injectStyles() {
4
+ if (globalThis.document) {
5
+ const style = document.createElement('style');
6
+ style.append(document.createTextNode(injectedStyles));
7
+ document.head.appendChild(style);
8
+ }
9
+ }
@@ -0,0 +1,19 @@
1
+ import { useMemo } from 'react';
2
+
3
+ function useStyles<T extends CSSModuleClasses>(styles: T): T {
4
+ // @ts-expect-error: entries/fromEntries don't allow to specify keys type
5
+ return useMemo(
6
+ () =>
7
+ Object.freeze(
8
+ Object.fromEntries(
9
+ Object.entries(styles).map(([baseClassName, resultClassName]) => [
10
+ baseClassName,
11
+ `${baseClassName} ${resultClassName}`
12
+ ])
13
+ )
14
+ ),
15
+ [styles]
16
+ );
17
+ }
18
+
19
+ export default useStyles;