@cognigy/chat-components-vue 0.1.0 → 0.2.0

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.
@@ -1,143 +1,114 @@
1
1
  <template>
2
2
  <ChatBubble
3
- v-if="hasAdaptiveCard"
4
- :class="['adaptivecard-wrapper', 'internal', $style.wrapper]"
5
- data-testid="adaptive-card-message"
3
+ v-if="hasAdaptiveCard"
4
+ :class="wrapperClasses"
5
+ data-testid="adaptive-card-message"
6
6
  >
7
- <div :class="$style.card">
8
- <!-- Card icon/indicator -->
9
- <div :class="$style.icon">
10
- <svg
11
- xmlns="http://www.w3.org/2000/svg"
12
- viewBox="0 0 24 24"
13
- :width="24"
14
- :height="24"
15
- fill="none"
16
- stroke="currentColor"
17
- stroke-width="2"
18
- stroke-linecap="round"
19
- stroke-linejoin="round"
20
- >
21
- <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
22
- <line x1="9" y1="9" x2="15" y2="9"></line>
23
- <line x1="9" y1="15" x2="15" y2="15"></line>
24
- </svg>
25
- </div>
26
-
27
- <!-- Card content -->
28
- <div :class="$style.content">
29
- <Typography
30
- variant="title1-semibold"
31
- component="div"
32
- :class="$style.title"
33
- >
34
- {{ cardTitle }}
35
- </Typography>
36
-
37
- <Typography
38
- v-if="cardBody"
39
- variant="body-regular"
40
- component="div"
41
- :class="$style.body"
42
- >
43
- {{ cardBody }}
44
- </Typography>
45
-
46
- <div v-if="hasActions" :class="$style.actions">
47
- <Typography variant="copy-medium" component="span" :class="$style.actionsLabel">
48
- {{ actionsLabel }}
49
- </Typography>
50
- </div>
51
- </div>
52
- </div>
7
+ <AdaptiveCardRenderer
8
+ :payload="cardPayload"
9
+ :host-config="adaptiveCardsHostConfig"
10
+ :readonly="isReadonly"
11
+ :input-data="submittedData"
12
+ />
53
13
  </ChatBubble>
54
14
  </template>
55
15
 
56
16
  <script setup lang="ts">
57
- import { computed } from 'vue'
17
+ /**
18
+ * AdaptiveCard - Message component for rendering Microsoft Adaptive Cards
19
+ *
20
+ * This component wraps the AdaptiveCardRenderer in a ChatBubble and handles
21
+ * payload extraction from the message context. It's designed for presentation-only
22
+ * mode (display only, no interactivity).
23
+ *
24
+ * The actual card rendering is handled by the AdaptiveCardRenderer component
25
+ * which uses Microsoft's adaptivecards library.
26
+ */
27
+ import { computed, useCssModule } from 'vue'
58
28
  import ChatBubble from '../common/ChatBubble.vue'
59
- import Typography from '../common/Typography.vue'
29
+ import AdaptiveCardRenderer from './AdaptiveCardRenderer.vue'
60
30
  import { useMessageContext } from '../../composables/useMessageContext'
61
- import { isAdaptiveCardPayload } from '../../types'
31
+ import type { IMessageDataExtended } from '../../types'
32
+
33
+ const styles = useCssModule()
34
+ const { message, config } = useMessageContext()
62
35
 
63
36
  /**
64
- * Simplified adaptive card structure for our rendering needs.
65
- * The full IAdaptiveCard type from 'adaptivecards' package is complex,
66
- * but we only need a subset for display purposes.
37
+ * Host configuration for Adaptive Cards styling
38
+ * Matches the React version's configuration
39
+ *
40
+ * Note: foregroundColors are applied as inline styles by the adaptivecards library,
41
+ * so we use actual color values here. For customization, consumers should use
42
+ * the CSS variables (--cc-adaptive-card-text-color) which override via !important.
43
+ *
44
+ * This is typed as a plain object (not Partial<HostConfig>) because the HostConfig
45
+ * constructor accepts plain objects and parses them internally.
67
46
  */
68
- interface AdaptiveCardData {
69
- title?: string
70
- body?: unknown[]
71
- actions?: unknown[]
72
- speak?: string
47
+ const adaptiveCardsHostConfig = {
48
+ fontFamily: 'inherit',
49
+ fontSizes: {
50
+ small: 10,
51
+ default: 14,
52
+ medium: 16,
53
+ large: 18,
54
+ extraLarge: 34,
55
+ },
56
+ fontWeights: {
57
+ lighter: 300,
58
+ default: 400,
59
+ bolder: 600,
60
+ },
61
+ lineHeights: {
62
+ small: 12,
63
+ default: 18.2,
64
+ medium: 22.4,
65
+ large: 23.4,
66
+ extraLarge: 40.8,
67
+ },
68
+ containerStyles: {
69
+ default: {
70
+ backgroundColor: '#fff',
71
+ foregroundColors: {
72
+ default: {
73
+ default: '#333333',
74
+ subtle: '#666666',
75
+ },
76
+ },
77
+ },
78
+ },
73
79
  }
74
80
 
75
81
  /**
76
- * Adaptive card sources from different payload locations
82
+ * Type-safe access to extended message data
77
83
  */
78
- interface AdaptiveCardSources {
79
- webchat: AdaptiveCardData | undefined
80
- defaultPreview: AdaptiveCardData | undefined
81
- plugin: AdaptiveCardData | undefined
82
- }
84
+ const messageData = computed<IMessageDataExtended | undefined>(() => {
85
+ return message?.data as IMessageDataExtended | undefined
86
+ })
83
87
 
84
88
  /**
85
- * Extract adaptive card from various message payload locations.
86
- *
87
- * Note on types: The socket-client types have limitations:
88
- * - _defaultPreview is typed as `any`
89
- * - _plugin.data is `any` for adaptivecards type
90
- * We use runtime type guards to safely access these properties.
89
+ * Check if this message has an adaptive card payload
91
90
  */
92
- function getAdaptiveCardSources(message: ReturnType<typeof useMessageContext>['message']): AdaptiveCardSources {
93
- const cognigyData = message?.data?._cognigy
94
- const pluginData = message?.data?._plugin
95
-
96
- // _webchat can be IWebchatMessage | IAdaptiveCardMessage - use type guard
97
- const webchatPayload = cognigyData?._webchat
98
- const webchat = isAdaptiveCardPayload(webchatPayload)
99
- ? (webchatPayload.adaptiveCard as AdaptiveCardData)
100
- : undefined
101
-
102
- // _defaultPreview is typed as `any` in socket-client (upstream limitation)
103
- // We safely check for adaptiveCard property
104
- const defaultPreviewPayload = cognigyData?._defaultPreview
105
- const defaultPreview = isAdaptiveCardPayload(defaultPreviewPayload)
106
- ? (defaultPreviewPayload.adaptiveCard as AdaptiveCardData)
107
- : undefined
108
-
109
- // Plugin data can come in two formats:
110
- // 1. Typed format: { type: 'adaptivecards', data: cardData }
111
- // 2. Legacy format: { payload: cardData }
112
- let plugin: AdaptiveCardData | undefined
113
- if (pluginData) {
114
- if (pluginData.type === 'adaptivecards' && 'data' in pluginData) {
115
- plugin = pluginData.data as AdaptiveCardData
116
- } else if ('payload' in pluginData) {
117
- plugin = (pluginData as { payload?: unknown }).payload as AdaptiveCardData
118
- }
119
- }
120
-
121
- return { webchat, defaultPreview, plugin }
122
- }
123
-
124
- // Message context
125
- const { message, config } = useMessageContext()
126
-
127
- // Get all adaptive card sources
128
- const cardSources = computed(() => getAdaptiveCardSources(message))
129
-
130
- // Check if this message has an adaptive card
131
91
  const hasAdaptiveCard = computed(() => {
132
- const { webchat, defaultPreview, plugin } = cardSources.value
92
+ const data = messageData.value
93
+ const webchat = data?._cognigy?._webchat?.adaptiveCard
94
+ const defaultPreview = data?._cognigy?._defaultPreview?.adaptiveCard
95
+ const plugin = data?._plugin?.payload
96
+
133
97
  return !!(webchat || defaultPreview || plugin)
134
98
  })
135
99
 
136
- // Get card payload based on configuration
137
- const cardPayload = computed((): AdaptiveCardData | undefined => {
138
- const { webchat, defaultPreview, plugin } = cardSources.value
100
+ /**
101
+ * Extract the card payload from the message
102
+ * Follows the same priority logic as the React version
103
+ */
104
+ const cardPayload = computed(() => {
105
+ const data = messageData.value
106
+ const webchat = data?._cognigy?._webchat?.adaptiveCard
107
+ const defaultPreview = data?._cognigy?._defaultPreview?.adaptiveCard
108
+ const plugin = data?._plugin?.payload
139
109
  const defaultPreviewEnabled = config?.settings?.widgetSettings?.enableDefaultPreview
140
110
 
111
+ // Priority: webchat over defaultPreview (unless defaultPreview is enabled)
141
112
  if (webchat && defaultPreview && !defaultPreviewEnabled) {
142
113
  return webchat
143
114
  }
@@ -148,145 +119,271 @@ const cardPayload = computed((): AdaptiveCardData | undefined => {
148
119
  })
149
120
 
150
121
  /**
151
- * Adaptive card body element (simplified type for our use case)
122
+ * Compute wrapper classes
152
123
  */
153
- interface AdaptiveCardElement {
154
- type: string
155
- text?: string
156
- size?: string
157
- }
124
+ const wrapperClasses = computed(() => [
125
+ styles.adaptivecardWrapper,
126
+ 'adaptivecard-wrapper',
127
+ 'internal',
128
+ ])
158
129
 
159
130
  /**
160
- * Check if an item is a TextBlock element
131
+ * Extract submitted data from the message
132
+ * This data will be used to pre-fill input fields in the card
133
+ * Checks multiple locations where Cognigy might store the submitted data
161
134
  */
162
- function isTextBlock(item: unknown): item is AdaptiveCardElement & { type: 'TextBlock'; text: string } {
163
- return (
164
- typeof item === 'object' &&
165
- item !== null &&
166
- (item as AdaptiveCardElement).type === 'TextBlock' &&
167
- typeof (item as AdaptiveCardElement).text === 'string'
168
- )
169
- }
170
-
171
- // Extract card title
172
- const cardTitle = computed(() => {
173
- const card = cardPayload.value
174
- if (!card) return 'Adaptive Card'
175
-
176
- // Try to get title from card property (custom extension)
177
- if ('title' in card && typeof card.title === 'string') {
178
- return card.title
179
- }
180
-
181
- // Try to get from body elements
182
- const body = card.body
183
- if (body && Array.isArray(body)) {
184
- // Look for large text block (likely a title)
185
- const titleElement = body.find(
186
- (item): item is AdaptiveCardElement =>
187
- isTextBlock(item) && item.size === 'large'
188
- )
189
- if (titleElement?.text) {
190
- return titleElement.text
191
- }
192
-
193
- // Fallback to first TextBlock
194
- const firstText = body.find(isTextBlock)
195
- if (firstText?.text) {
196
- return firstText.text
197
- }
135
+ const submittedData = computed<Record<string, unknown> | undefined>(() => {
136
+ const data = messageData.value
137
+ const webchatData = data?._cognigy?._webchat
138
+
139
+ // Check various locations where submitted data might be stored
140
+ // Priority: request.value > adaptiveCardData > data > formData
141
+ const submittedValue =
142
+ data?.request?.value ||
143
+ webchatData?.adaptiveCardData ||
144
+ webchatData?.data ||
145
+ webchatData?.formData ||
146
+ data?.adaptiveCardData ||
147
+ data?.data ||
148
+ data?.formData
149
+
150
+ if (submittedValue && typeof submittedValue === 'object' && !Array.isArray(submittedValue)) {
151
+ return submittedValue
198
152
  }
199
153
 
200
- // Fallback to speak text or generic title
201
- if (card.speak) {
202
- return card.speak.substring(0, 50)
203
- }
154
+ return undefined
155
+ })
204
156
 
205
- return 'Adaptive Card'
157
+ /**
158
+ * Determine if the card should be rendered in readonly mode
159
+ *
160
+ * Readonly when:
161
+ * - config.settings.behavior.adaptiveCardsReadonly is true (forced presentation mode)
162
+ * - OR submitted data exists (card was already submitted, showing history)
163
+ */
164
+ const isReadonly = computed(() => {
165
+ const configReadonly = config?.settings?.behavior?.adaptiveCardsReadonly
166
+ return configReadonly === true || submittedData.value !== undefined
206
167
  })
168
+ </script>
207
169
 
208
- // Extract card body text
209
- const cardBody = computed(() => {
210
- const body = cardPayload.value?.body
211
- if (!body || !Array.isArray(body)) {
212
- return null
213
- }
170
+ <style module>
171
+ /* Main wrapper styles - match React version */
172
+ .adaptivecardWrapper {
173
+ width: 100%;
174
+ box-sizing: border-box;
175
+ max-width: 100%;
176
+ padding: 16px !important;
177
+ }
214
178
 
215
- // Get text from body elements (skip the title)
216
- const titleText = cardTitle.value
217
- const bodyTexts = body
218
- .filter((item): item is AdaptiveCardElement & { text: string } =>
219
- isTextBlock(item) && item.text !== titleText
220
- )
221
- .map(item => item.text)
222
- .slice(0, 2) // Limit to first 2 text blocks
179
+ .adaptivecardWrapper > *:focus {
180
+ outline: 1px solid var(--cc-primary-color-focus, #0b3694);
181
+ border-color: var(--cc-primary-color-focus, #0b3694);
182
+ }
223
183
 
224
- return bodyTexts.length > 0 ? bodyTexts.join(' ') : null
225
- })
184
+ /* Button styles */
185
+ .adaptivecardWrapper :global(button) {
186
+ appearance: none;
187
+ background: var(--cc-primary-color, #0b3694);
188
+ border-radius: 10px;
189
+ border: none;
190
+ color: var(--cc-primary-contrast-color, white);
191
+ cursor: pointer;
192
+ font-size: 14px !important;
193
+ font-weight: 600;
194
+ line-height: 160% !important;
195
+ min-width: 100%;
196
+ padding-block: 11px;
197
+ width: 100%;
198
+ }
226
199
 
227
- // Check if card has actions
228
- const hasActions = computed(() => {
229
- return cardPayload.value?.actions && Array.isArray(cardPayload.value.actions) && cardPayload.value.actions.length > 0
230
- })
200
+ .adaptivecardWrapper :global(button:hover) {
201
+ background: var(--cc-primary-color-hover, #092d7a);
202
+ }
231
203
 
232
- // Actions label
233
- const actionsLabel = computed(() => {
234
- const actions = cardPayload.value?.actions
235
- if (!actions || !Array.isArray(actions) || actions.length === 0) return ''
204
+ .adaptivecardWrapper :global(button:focus-visible) {
205
+ outline: 2px solid var(--cc-primary-color-focus, #0b3694);
206
+ outline-offset: 2px;
207
+ }
236
208
 
237
- const count = actions.length
238
- return count === 1 ? '1 action available' : `${count} actions available`
239
- })
240
- </script>
209
+ .adaptivecardWrapper :global(button:disabled) {
210
+ background: var(--cc-primary-color-disabled, #999);
211
+ }
241
212
 
242
- <style module>
243
- .wrapper {
244
- max-width: 400px;
213
+ /* Text styles - use CSS variable for customizable font color */
214
+ .adaptivecardWrapper :global(.ac-textRun) {
215
+ color: var(--cc-adaptive-card-text-color, #333) !important;
216
+ font-size: 12px !important;
217
+ line-height: 140%;
218
+ }
219
+
220
+ /* Container styles */
221
+ .adaptivecardWrapper :global(.ac-container) {
222
+ border-radius: 15px;
245
223
  }
246
224
 
247
- .card {
248
- display: flex;
249
- gap: 12px;
250
- padding: 16px;
251
- background-color: var(--cc-white, #ffffff);
252
- border-radius: var(--cc-bubble-border-radius, 15px);
225
+ /* Input styles - use CSS variables for customizable colors */
226
+ .adaptivecardWrapper :global(input),
227
+ .adaptivecardWrapper :global(textarea),
228
+ .adaptivecardWrapper :global(select) {
229
+ align-self: stretch;
230
+ background-position: right 12px center;
231
+ background-repeat: no-repeat;
232
+ background: var(--cc-adaptive-card-input-background, #fff);
233
+ border-radius: 10px;
234
+ border: 1px solid var(--cc-adaptive-card-input-border, #ccc);
235
+ color: var(--cc-adaptive-card-input-color, #333) !important;
236
+ font-size: 14px !important;
237
+ gap: 10px;
238
+ line-height: 140%;
239
+ padding: 8px 12px 8px 12px;
240
+ resize: none;
241
+ }
242
+
243
+ @media screen and (max-width: 575px) {
244
+ .adaptivecardWrapper :global(input),
245
+ .adaptivecardWrapper :global(textarea),
246
+ .adaptivecardWrapper :global(select) {
247
+ font-size: 16px !important;
248
+ }
253
249
  }
254
250
 
255
- .icon {
256
- flex-shrink: 0;
257
- color: var(--cc-primary-color, #1976d2);
258
- display: flex;
259
- align-items: flex-start;
260
- padding-top: 2px;
251
+ .adaptivecardWrapper :global(textarea) {
252
+ min-height: 98px;
261
253
  }
262
254
 
263
- .content {
264
- flex: 1;
265
- display: flex;
266
- flex-direction: column;
255
+ :global(.ac-horizontal-separator) {
256
+ height: 16px !important;
257
+ }
258
+
259
+ .adaptivecardWrapper :global(textarea::-webkit-scrollbar) {
260
+ width: 27px;
261
+ }
262
+
263
+ .adaptivecardWrapper :global(textarea::-webkit-scrollbar-track) {
264
+ background: transparent;
265
+ }
266
+
267
+ .adaptivecardWrapper :global(textarea::-webkit-scrollbar-thumb) {
268
+ background-color: var(--cc-black-80, rgba(0, 0, 0, 0.8));
269
+ border-radius: 10px;
270
+ border: 12px solid var(--cc-white, #fff);
271
+ border-block: none;
272
+ }
273
+
274
+ .adaptivecardWrapper :global(input:focus),
275
+ .adaptivecardWrapper :global(textarea:focus),
276
+ .adaptivecardWrapper :global(select:focus) {
277
+ outline: 1px solid var(--cc-primary-color-focus, #0b3694);
278
+ border-color: var(--cc-primary-color-focus, #0b3694);
279
+ }
280
+
281
+ .adaptivecardWrapper :global(input:focus-visible),
282
+ .adaptivecardWrapper :global(textarea:focus-visible),
283
+ .adaptivecardWrapper :global(select:focus-visible) {
284
+ outline: 2px solid var(--cc-primary-color-focus, #0b3694);
285
+ border-color: var(--cc-primary-color-focus, #0b3694);
286
+ }
287
+
288
+ /* Action set styles */
289
+ .adaptivecardWrapper :global(.ac-actionSet) {
290
+ flex-wrap: wrap;
267
291
  gap: 8px;
268
- min-width: 0;
269
292
  }
270
293
 
271
- .title {
272
- color: var(--cc-black-10, rgba(0, 0, 0, 0.1));
273
- margin: 0;
294
+ /* Card container styles */
295
+ .adaptivecardWrapper > * {
296
+ background-color: white;
297
+ border-radius: 15px;
298
+ box-shadow: none;
299
+ padding: 0;
300
+ border: 1px solid var(--cc-black-80, #ccc);
301
+ margin: -17px;
302
+ }
303
+
304
+ /* Checkbox styles */
305
+ .adaptivecardWrapper :global([type='checkbox']) {
306
+ appearance: none;
307
+ background-color: var(--cc-white, #fff);
308
+ border: 1px solid var(--cc-black-60, #666);
309
+ border-radius: 1px;
310
+ width: 16px;
311
+ height: 16px;
312
+ }
313
+
314
+ .adaptivecardWrapper :global([type='checkbox']:checked) {
315
+ background-color: var(--cc-primary-color, #0b3694);
316
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M12.5172 4.4569C12.8172 4.74256 12.8288 5.2173 12.5431 5.51724L7.19089 11.1371C6.69828 11.6543 5.87315 11.6543 5.38054 11.1371L3.4569 9.11724C3.17123 8.8173 3.18281 8.34256 3.48276 8.0569C3.78271 7.77123 4.25744 7.78281 4.5431 8.08276L6.28572 9.9125L11.4569 4.48276C11.7426 4.18281 12.2173 4.17123 12.5172 4.4569Z' fill='white'/%3E%3C/svg%3E");
317
+ background-position: -1px -1px;
318
+ }
319
+
320
+ .adaptivecardWrapper :global([type='checkbox']:active) {
321
+ background-color: var(--cc-primary-color-hover, #092d7a);
322
+ border-color: var(--cc-primary-color-hover, #092d7a);
323
+ }
324
+
325
+ .adaptivecardWrapper :global([type='checkbox']:checked:hover) {
326
+ background-color: var(--cc-primary-color-hover, #092d7a);
327
+ border-color: var(--cc-primary-color-hover, #092d7a);
328
+ }
329
+
330
+ .adaptivecardWrapper :global(input:invalid) {
331
+ border-color: red;
332
+ }
333
+
334
+ /* Date/Time picker icons */
335
+ .adaptivecardWrapper :global([type='date']::-webkit-calendar-picker-indicator),
336
+ .adaptivecardWrapper :global([type='time']::-webkit-calendar-picker-indicator) {
337
+ background: none;
338
+ }
339
+
340
+ .adaptivecardWrapper :global([type='date']),
341
+ .adaptivecardWrapper :global([type='time']) {
342
+ background-repeat: no-repeat;
343
+ background-position: right 12px center;
344
+ }
345
+
346
+ .adaptivecardWrapper :global([type='date']) {
347
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M3 0.75C3 0.335786 3.33579 0 3.75 0C4.16421 0 4.5 0.335786 4.5 0.75V3H11V0.75C11 0.335786 11.3358 0 11.75 0C12.1642 0 12.5 0.335786 12.5 0.75V3H14C15.1046 3 16 3.89543 16 5V14C16 15.1046 15.1046 16 14 16H2C0.895431 16 0 15.1046 0 14V5C0 3.89543 0.895431 3 2 3H3V0.75ZM1.5 6H14.5V14C14.5 14.2761 14.2761 14.5 14 14.5H2C1.72386 14.5 1.5 14.2761 1.5 14V6Z' fill='%232455E6'/%3E%3C/svg%3E");
348
+ }
349
+
350
+ .adaptivecardWrapper :global([type='time']) {
351
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 14.5C11.5899 14.5 14.5 11.5899 14.5 8C14.5 4.41015 11.5899 1.5 8 1.5C4.41015 1.5 1.5 4.41015 1.5 8C1.5 11.5899 4.41015 14.5 8 14.5ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z' fill='%232455E6'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11.0303 12.0303C10.7374 12.3232 10.2626 12.3232 9.96967 12.0303L7.25 9.31066L7.25 4C7.25 3.58579 7.58578 3.25 8 3.25C8.41421 3.25 8.75 3.58579 8.75 4L8.75 8.68934L11.0303 10.9697C11.3232 11.2626 11.3232 11.7374 11.0303 12.0303Z' fill='%232455E6'/%3E%3C/svg%3E");
352
+ }
353
+
354
+ /* Select dropdown styles */
355
+ .adaptivecardWrapper :global(select) {
356
+ appearance: none;
357
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M1.34923 4.24022C1.76855 3.8808 2.39985 3.92936 2.75927 4.34869L8.00002 10.4629L13.2408 4.34869C13.6002 3.92936 14.2315 3.8808 14.6508 4.24022C15.0701 4.59965 15.1187 5.23095 14.7593 5.65027L9.51853 11.7645C8.72034 12.6957 7.2797 12.6957 6.4815 11.7645L1.24076 5.65027C0.881339 5.23095 0.929901 4.59965 1.34923 4.24022Z' fill='%232455E6'/%3E%3C/svg%3E");
358
+ background-repeat: no-repeat;
359
+ background-position: right 12px center;
360
+ }
361
+
362
+ .adaptivecardWrapper :global(select::-ms-expand) {
363
+ display: none;
364
+ }
365
+
366
+ .adaptivecardWrapper :global(select option) {
367
+ color: var(--cc-adaptive-card-input-color, #333);
368
+ border-bottom: 1px solid var(--cc-black-80, #ccc);
274
369
  }
275
370
 
276
- .body {
277
- color: var(--cc-black-20, rgba(0, 0, 0, 0.2));
278
- margin: 0;
279
- overflow-wrap: break-word;
371
+ /* Readonly/disabled state styles */
372
+ .adaptivecardWrapper :global(.ac-readonly) input:disabled,
373
+ .adaptivecardWrapper :global(.ac-readonly) textarea:disabled,
374
+ .adaptivecardWrapper :global(.ac-readonly) select:disabled {
375
+ background-color: var(--cc-black-95, #f5f5f5);
376
+ cursor: not-allowed;
377
+ opacity: 0.8;
280
378
  }
281
379
 
282
- .actions {
283
- margin-top: 4px;
284
- padding-top: 8px;
285
- border-top: 1px solid var(--cc-black-80, rgba(0, 0, 0, 0.8));
380
+ .adaptivecardWrapper :global(.ac-readonly) button:disabled {
381
+ cursor: not-allowed;
382
+ opacity: 0.6;
286
383
  }
287
384
 
288
- .actionsLabel {
289
- color: var(--cc-black-40, rgba(0, 0, 0, 0.4));
290
- font-style: italic;
385
+ .adaptivecardWrapper :global(.ac-readonly) [type='checkbox']:disabled {
386
+ cursor: not-allowed;
387
+ opacity: 0.6;
291
388
  }
292
389
  </style>