@hh.ru/magritte-ui-chat-input 1.1.18 → 1.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.
package/index.css CHANGED
@@ -1,6 +1,8 @@
1
1
  :root{
2
2
  --magritte-color-background-primary-v25-1-0:#ffffff;
3
+ --magritte-color-background-secondary-v25-1-0:#F1F4F9;
3
4
  --magritte-color-stroke-neutral-v25-1-0:#DCE3EB;
5
+ --magritte-color-stroke-phantom-v25-1-0:#DCE3EB;
4
6
  --magritte-color-stroke-state-focused-accessible-v25-1-0:#0070ff7a;
5
7
  --magritte-color-stroke-state-neutral-hovered-v25-1-0:#DCE3EB;
6
8
  --magritte-color-text-primary-v25-1-0:#000000;
@@ -22,7 +24,9 @@
22
24
 
23
25
  .magritte-night-theme{
24
26
  --magritte-color-background-primary-v25-1-0:#1B1B1B;
27
+ --magritte-color-background-secondary-v25-1-0:#303030;
25
28
  --magritte-color-stroke-neutral-v25-1-0:#303030;
29
+ --magritte-color-stroke-phantom-v25-1-0:#30303000;
26
30
  --magritte-color-stroke-state-neutral-hovered-v25-1-0:#303030;
27
31
  --magritte-color-text-primary-v25-1-0:#ffffff;
28
32
  --magritte-color-text-secondary-v25-1-0:#ABABAB;
@@ -31,116 +35,127 @@
31
35
  --magritte-gradient-component-chat-input-background-fade-v25-1-0:#1b1b1b00 0%, #1b1b1b 100%;
32
36
  --magritte-shadow-level-1-color-v25-1-0:#00000029;
33
37
  }
34
- .magritte-chat-input___P69oN_1-1-18{
38
+ .magritte-chat-input___P69oN_1-2-0{
35
39
  --chat-input-stroke-color:var(--magritte-color-stroke-neutral-v25-1-0);
36
40
  --chat-input-focus-shadow:0 0 0 transparent;
37
- box-shadow:inset 0 0 0 1px var(--chat-input-stroke-color), var(--chat-input-focus-shadow);
41
+ position:relative;
42
+ isolation:isolate;
43
+ box-shadow:var(--chat-input-focus-shadow);
38
44
  border-radius:24px;
39
45
  padding:12px;
40
46
  overflow:hidden;
41
47
  background-color:var(--magritte-color-background-primary-v25-1-0);
42
48
  --magritte-ui-scrollbar-offset-right:-12px;
43
49
  }
44
- .magritte-chat-input___P69oN_1-1-18.magritte-no-background___eiIY1_1-1-18{
50
+ .magritte-chat-input___P69oN_1-2-0::after{
51
+ content:'';
52
+ position:absolute;
53
+ z-index:1;
54
+ inset:0;
55
+ border-radius:inherit;
56
+ box-shadow:inset 0 0 0 1px var(--chat-input-stroke-color);
57
+ pointer-events:none;
58
+ }
59
+ .magritte-chat-input___P69oN_1-2-0.magritte-no-background___eiIY1_1-2-0{
45
60
  background:none;
46
61
  --chat-input-stroke-color:transparent !important;
47
62
  }
48
- .magritte-chat-input___P69oN_1-1-18:has(*:focus){
63
+ .magritte-chat-input___P69oN_1-2-0:has(*:focus){
49
64
  --chat-input-focus-shadow:var(--magritte-shadow-level-1-x-v25-1-0) var(--magritte-shadow-level-1-y-v25-1-0) var(--magritte-shadow-level-1-blur-v25-1-0) var(--magritte-shadow-level-1-spread-v25-1-0) var(--magritte-shadow-level-1-color-v25-1-0);
50
65
  }
51
- .magritte-chat-input___P69oN_1-1-18:has(.magritte-text-input-focused___TfyLu_1-1-18){
66
+ .magritte-chat-input___P69oN_1-2-0:has(.magritte-text-input-focused___TfyLu_1-2-0){
52
67
  outline:4px solid var(--magritte-color-stroke-state-focused-accessible-v25-1-0);
53
68
  }
54
69
  @media (min-width: 1020px){
55
- body.magritte-old-layout .magritte-chat-input___P69oN_1-1-18:hover{
70
+ body.magritte-old-layout .magritte-chat-input___P69oN_1-2-0:hover{
56
71
  --chat-input-stroke-color:var(--magritte-color-stroke-state-neutral-hovered-v25-1-0);
57
72
  }
58
73
  }
59
74
  @media (min-width: 1024px){
60
- body:not(.magritte-old-layout) .magritte-chat-input___P69oN_1-1-18:hover{
75
+ body:not(.magritte-old-layout) .magritte-chat-input___P69oN_1-2-0:hover{
61
76
  --chat-input-stroke-color:var(--magritte-color-stroke-state-neutral-hovered-v25-1-0);
62
77
  }
63
78
  }
64
- .magritte-content-grid___g03sT_1-1-18{
79
+ .magritte-content-grid___g03sT_1-2-0{
65
80
  display:grid;
66
81
  grid-template-columns:auto minmax(0, 1fr) auto;
67
82
  }
68
- .magritte-content-grid___g03sT_1-1-18 .magritte-preview___baXKi_1-1-18{
83
+ .magritte-content-grid___g03sT_1-2-0 .magritte-preview___baXKi_1-2-0{
69
84
  grid-area:1 / 1 / 2 / -1;
70
85
  }
71
- .magritte-content-grid___g03sT_1-1-18 .magritte-left___7JZYp_1-1-18{
86
+ .magritte-content-grid___g03sT_1-2-0 .magritte-left___7JZYp_1-2-0{
72
87
  grid-area:3 / 1;
73
88
  align-self:end;
74
89
  }
75
- .magritte-content-grid___g03sT_1-1-18 .magritte-central___zkguj_1-1-18{
90
+ .magritte-content-grid___g03sT_1-2-0 .magritte-central___zkguj_1-2-0{
76
91
  grid-area:3 / 2;
77
92
  align-self:center;
78
93
  }
79
- .magritte-content-grid___g03sT_1-1-18 .magritte-right___-tGcO_1-1-18{
94
+ .magritte-content-grid___g03sT_1-2-0 .magritte-right___-tGcO_1-2-0{
80
95
  grid-area:3 / 3;
81
96
  align-self:end;
82
97
  }
83
- .magritte-content-grid___g03sT_1-1-18 .magritte-scrollbar-cell___--M2x_1-1-18{
98
+ .magritte-content-grid___g03sT_1-2-0 .magritte-scrollbar-cell___--M2x_1-2-0{
84
99
  grid-area:2 / 1 / 3 / -1;
85
100
  position:relative;
86
101
  pointer-events:none;
87
102
  }
88
- .magritte-content-grid___g03sT_1-1-18 .magritte-scrollbar-cell___--M2x_1-1-18 > div{
103
+ .magritte-content-grid___g03sT_1-2-0 .magritte-scrollbar-cell___--M2x_1-2-0 > div{
89
104
  pointer-events:auto;
90
105
  }
91
- .magritte-content-grid___g03sT_1-1-18 .magritte-text-input___3AFO4_1-1-18{
106
+ .magritte-content-grid___g03sT_1-2-0 .magritte-text-input___3AFO4_1-2-0{
92
107
  grid-area:3 / 2;
93
108
  }
94
- .magritte-content-grid___g03sT_1-1-18 .magritte-text-input___3AFO4_1-1-18.magritte-layout-vertical___mVTr-_1-1-18,
95
- .magritte-content-grid___g03sT_1-1-18.magritte-has-central___VRZik_1-1-18 .magritte-text-input___3AFO4_1-1-18{
109
+ .magritte-content-grid___g03sT_1-2-0 .magritte-text-input___3AFO4_1-2-0.magritte-layout-vertical___mVTr-_1-2-0,
110
+ .magritte-content-grid___g03sT_1-2-0.magritte-has-central___VRZik_1-2-0 .magritte-text-input___3AFO4_1-2-0{
96
111
  grid-area:2 / 1 / 3 / -1;
97
112
  }
98
- .magritte-content-grid___g03sT_1-1-18.magritte-no-left-controls___7r6yy_1-1-18:not(.magritte-has-central___VRZik_1-1-18) .magritte-text-input___3AFO4_1-1-18{
113
+ .magritte-content-grid___g03sT_1-2-0.magritte-no-left-controls___7r6yy_1-2-0:not(.magritte-has-central___VRZik_1-2-0) .magritte-text-input___3AFO4_1-2-0{
99
114
  grid-area:2 / 1 / 4 / 3;
100
115
  }
101
- .magritte-content-grid___g03sT_1-1-18.magritte-no-right-controls___HBSag_1-1-18:not(.magritte-has-central___VRZik_1-1-18) .magritte-text-input___3AFO4_1-1-18{
116
+ .magritte-content-grid___g03sT_1-2-0.magritte-no-right-controls___HBSag_1-2-0:not(.magritte-has-central___VRZik_1-2-0) .magritte-text-input___3AFO4_1-2-0{
102
117
  grid-area:2 / 2 / 4 / -1;
103
118
  }
104
- .magritte-content-grid___g03sT_1-1-18.magritte-no-left-controls___7r6yy_1-1-18:not(.magritte-has-central___VRZik_1-1-18){
119
+ .magritte-content-grid___g03sT_1-2-0.magritte-no-left-controls___7r6yy_1-2-0:not(.magritte-has-central___VRZik_1-2-0){
105
120
  grid-template-rows:auto minmax(0, 1fr) auto;
106
121
  }
107
- .magritte-right___-tGcO_1-1-18,
108
- .magritte-left___7JZYp_1-1-18{
122
+ .magritte-right___-tGcO_1-2-0,
123
+ .magritte-left___7JZYp_1-2-0{
109
124
  display:flex;
110
125
  gap:8px;
111
126
  }
112
- .magritte-chips___gLao5_1-1-18{
127
+ .magritte-chips___gLao5_1-2-0{
113
128
  display:flex;
114
129
  flex-wrap:nowrap;
115
130
  width:max-content;
116
131
  gap:8px;
117
132
  }
118
- .magritte-chips-container___-bS5O_1-1-18{
133
+ .magritte-chips-container___-bS5O_1-2-0{
119
134
  padding:0 12px;
120
135
  }
121
- .magritte-no-left-controls___7r6yy_1-1-18 .magritte-chips-container___-bS5O_1-1-18{
136
+ .magritte-no-left-controls___7r6yy_1-2-0 .magritte-chips-container___-bS5O_1-2-0{
122
137
  padding-left:0;
123
138
  }
124
- .magritte-no-right-controls___HBSag_1-1-18 .magritte-chips-container___-bS5O_1-1-18{
139
+ .magritte-no-right-controls___HBSag_1-2-0 .magritte-chips-container___-bS5O_1-2-0{
125
140
  padding-right:0;
126
141
  }
127
- .magritte-preview-block___iiPdS_1-1-18{
142
+ .magritte-preview-block___iiPdS_1-2-0{
128
143
  display:flex;
129
144
  align-items:center;
130
145
  gap:12px;
131
146
  padding-bottom:8px;
132
147
  }
133
- .magritte-preview-side___ymR-u_1-1-18{
148
+ .magritte-preview-side___ymR-u_1-2-0{
134
149
  display:flex;
135
150
  flex-shrink:0;
136
151
  }
137
- .magritte-preview-content___ZgyBD_1-1-18{
152
+ .magritte-preview-content___ZgyBD_1-2-0{
138
153
  display:flex;
139
154
  flex:1;
140
155
  flex-direction:column;
141
156
  min-width:0;
142
157
  }
143
- .magritte-preview-title___SkFeZ_1-1-18{
158
+ .magritte-preview-title___SkFeZ_1-2-0{
144
159
  font-family:"hh sans";
145
160
  font-weight:500;
146
161
  line-height:18px;
@@ -151,7 +166,7 @@
151
166
  text-decoration:none;
152
167
  color:var(--magritte-color-text-primary-v25-1-0);
153
168
  }
154
- .magritte-preview-subtitle___58qfR_1-1-18{
169
+ .magritte-preview-subtitle___58qfR_1-2-0{
155
170
  font-family:"hh sans";
156
171
  font-weight:400;
157
172
  line-height:20px;
@@ -165,10 +180,87 @@
165
180
  white-space:nowrap;
166
181
  text-overflow:ellipsis;
167
182
  }
168
- .magritte-text-input-wrapper___TPbwC_1-1-18{
183
+ .magritte-files-container___zOkRK_1-2-0{
184
+ padding-bottom:8px;
185
+ }
186
+ .magritte-files___j2q5K_1-2-0{
187
+ display:flex;
188
+ flex-wrap:nowrap;
189
+ align-items:flex-start;
190
+ width:max-content;
191
+ gap:8px;
192
+ }
193
+ .magritte-file___lz9Ll_1-2-0{
194
+ position:relative;
195
+ }
196
+ .magritte-file-card___hn5C9_1-2-0::after,
197
+ .magritte-file-tile___OVlh3_1-2-0::after{
198
+ content:'';
199
+ position:absolute;
200
+ inset:0;
201
+ border:1px solid;
202
+ border-radius:inherit;
203
+ pointer-events:none;
204
+ }
205
+ .magritte-file-card___hn5C9_1-2-0{
206
+ position:relative;
207
+ box-sizing:border-box;
208
+ width:280px;
209
+ padding:8px;
210
+ border-radius:12px;
211
+ background-color:var(--magritte-color-background-primary-v25-1-0);
212
+ }
213
+ .magritte-file-card___hn5C9_1-2-0::after{
214
+ border-color:var(--magritte-color-stroke-neutral-v25-1-0);
215
+ }
216
+ .magritte-file-card-removable___GkxUe_1-2-0{
217
+ padding-right:32px;
218
+ }
219
+ .magritte-file-tile___OVlh3_1-2-0{
220
+ position:relative;
221
+ display:flex;
222
+ align-items:center;
223
+ justify-content:center;
224
+ width:64px;
225
+ height:64px;
226
+ overflow:hidden;
227
+ border-radius:12px;
228
+ }
229
+ .magritte-file-tile___OVlh3_1-2-0::after{
230
+ border-color:var(--magritte-color-stroke-phantom-v25-1-0);
231
+ }
232
+ .magritte-file-tile-placeholder___yxLuR_1-2-0{
233
+ background-color:var(--magritte-color-background-secondary-v25-1-0);
234
+ }
235
+ .magritte-file-tile-image___cZFgL_1-2-0{
236
+ display:block;
237
+ width:100%;
238
+ height:100%;
239
+ object-fit:cover;
240
+ }
241
+ .magritte-file-remove___S0WB9_1-2-0{
242
+ position:absolute;
243
+ top:4px;
244
+ right:4px;
245
+ display:flex;
246
+ }
247
+ .magritte-file-name___L03-O_1-2-0{
248
+ display:flex;
249
+ min-width:0;
250
+ }
251
+ .magritte-file-name-base___ojdp6_1-2-0{
252
+ overflow:hidden;
253
+ white-space:nowrap;
254
+ text-overflow:ellipsis;
255
+ }
256
+ .magritte-file-name-extension___3QZtS_1-2-0{
257
+ flex-shrink:0;
258
+ white-space:nowrap;
259
+ }
260
+ .magritte-text-input-wrapper___TPbwC_1-2-0{
169
261
  display:contents;
170
262
  }
171
- .magritte-text-input___3AFO4_1-1-18{
263
+ .magritte-text-input___3AFO4_1-2-0{
172
264
  box-sizing:content-box;
173
265
  padding:0 12px;
174
266
  border:none;
@@ -192,32 +284,32 @@
192
284
  text-decoration:none;
193
285
  color:var(--magritte-color-text-primary-v25-1-0);
194
286
  }
195
- .magritte-text-input___3AFO4_1-1-18::placeholder{
287
+ .magritte-text-input___3AFO4_1-2-0::placeholder{
196
288
  color:var(--magritte-color-text-tertiary-v25-1-0);
197
289
  opacity:1;
198
290
  }
199
- .magritte-text-input___3AFO4_1-1-18:focus,
200
- .magritte-text-input___3AFO4_1-1-18:focus-visible{
291
+ .magritte-text-input___3AFO4_1-2-0:focus,
292
+ .magritte-text-input___3AFO4_1-2-0:focus-visible{
201
293
  border:none;
202
294
  outline:none;
203
295
  }
204
- .magritte-text-input___3AFO4_1-1-18.magritte-with-top-fade___okgqo_1-1-18,
205
- .magritte-text-input___3AFO4_1-1-18.magritte-with-bottom-fade___82gr8_1-1-18{
296
+ .magritte-text-input___3AFO4_1-2-0.magritte-with-top-fade___okgqo_1-2-0,
297
+ .magritte-text-input___3AFO4_1-2-0.magritte-with-bottom-fade___82gr8_1-2-0{
206
298
  -webkit-mask:var(--fade-top) top / 100% 16px no-repeat, linear-gradient(#000, #000) center / 100% calc(100% - 32px) no-repeat, var(--fade-bottom) bottom / 100% 16px no-repeat;
207
299
  mask:var(--fade-top) top / 100% 16px no-repeat, linear-gradient(#000, #000) center / 100% calc(100% - 32px) no-repeat, var(--fade-bottom) bottom / 100% 16px no-repeat;
208
300
  }
209
- .magritte-text-input___3AFO4_1-1-18.magritte-with-top-fade___okgqo_1-1-18{
301
+ .magritte-text-input___3AFO4_1-2-0.magritte-with-top-fade___okgqo_1-2-0{
210
302
  --fade-top:linear-gradient(180deg, var(--magritte-gradient-component-chat-input-background-fade-v25-1-0));
211
303
  }
212
- .magritte-text-input___3AFO4_1-1-18.magritte-with-bottom-fade___82gr8_1-1-18{
304
+ .magritte-text-input___3AFO4_1-2-0.magritte-with-bottom-fade___82gr8_1-2-0{
213
305
  --fade-bottom:linear-gradient(0deg, var(--magritte-gradient-component-chat-input-background-fade-v25-1-0));
214
306
  }
215
- .magritte-text-input___3AFO4_1-1-18.magritte-measure___xNKc0_1-1-18{
307
+ .magritte-text-input___3AFO4_1-2-0.magritte-measure___xNKc0_1-2-0{
216
308
  height:20px !important;
217
309
  padding:0 !important;
218
310
  margin:0 !important;
219
311
  }
220
- .magritte-voice-record___p64PV_1-1-18{
312
+ .magritte-voice-record___p64PV_1-2-0{
221
313
  display:flex;
222
314
  align-items:center;
223
315
  justify-content:space-between;
@@ -227,45 +319,45 @@
227
319
  min-height:40px;
228
320
  gap:8px;
229
321
  }
230
- .magritte-voice-record-left___njEt-_1-1-18{
322
+ .magritte-voice-record-left___njEt-_1-2-0{
231
323
  display:flex;
232
324
  align-items:center;
233
325
  gap:8px;
234
326
  min-width:0;
235
327
  }
236
- .magritte-voice-record-right___UTv-U_1-1-18{
328
+ .magritte-voice-record-right___UTv-U_1-2-0{
237
329
  display:flex;
238
330
  align-items:center;
239
331
  gap:8px;
240
332
  }
241
- .magritte-voice-record-right___UTv-U_1-1-18.magritte-voice-processing___C0xnX_1-1-18{
333
+ .magritte-voice-record-right___UTv-U_1-2-0.magritte-voice-processing___C0xnX_1-2-0{
242
334
  padding:8px;
243
335
  }
244
- .magritte-voice-record-indicator___V8ybb_1-1-18{
336
+ .magritte-voice-record-indicator___V8ybb_1-2-0{
245
337
  display:flex;
246
338
  flex-shrink:0;
247
339
  align-items:center;
248
340
  gap:2px;
249
341
  }
250
- .magritte-voice-record-indicator-bar___jgyqz_1-1-18{
342
+ .magritte-voice-record-indicator-bar___jgyqz_1-2-0{
251
343
  width:2px;
252
344
  min-height:2px;
253
345
  max-height:2px;
254
346
  border-radius:1000px;
255
347
  background-color:var(--magritte-color-icon-tertiary-v25-1-0);
256
348
  transition:max-height var(--magritte-semantic-animation-time-s-duration-v25-1-0) var(--magritte-semantic-animation-ease-base-timing-function-v25-1-0);
257
- animation:magritte-voice-record-indicator-wave___4VsyE_1-1-18 400ms linear infinite alternate paused;
349
+ animation:magritte-voice-record-indicator-wave___4VsyE_1-2-0 400ms linear infinite alternate paused;
258
350
  }
259
- .magritte-voice-record-indicator-has-sound___67t5g_1-1-18 .magritte-voice-record-indicator-bar___jgyqz_1-1-18{
351
+ .magritte-voice-record-indicator-has-sound___67t5g_1-2-0 .magritte-voice-record-indicator-bar___jgyqz_1-2-0{
260
352
  max-height:27px;
261
353
  animation-play-state:running;
262
354
  }
263
355
  @media (prefers-reduced-motion: reduce){
264
- .magritte-voice-record-indicator-has-sound___67t5g_1-1-18 .magritte-voice-record-indicator-bar___jgyqz_1-1-18{
356
+ .magritte-voice-record-indicator-has-sound___67t5g_1-2-0 .magritte-voice-record-indicator-bar___jgyqz_1-2-0{
265
357
  animation-play-state:paused;
266
358
  }
267
359
  }
268
- @keyframes magritte-voice-record-indicator-wave___4VsyE_1-1-18{
360
+ @keyframes magritte-voice-record-indicator-wave___4VsyE_1-2-0{
269
361
  from{
270
362
  height:calc(var(--target-height) * 0.62px);
271
363
  }
@@ -273,12 +365,12 @@
273
365
  height:calc(var(--target-height) * 1.22px);
274
366
  }
275
367
  }
276
- .magritte-mode-container___nATVD_1-1-18{
368
+ .magritte-mode-container___nATVD_1-2-0{
277
369
  position:relative;
278
370
  display:grid;
279
371
  align-content:end;
280
372
  }
281
- .magritte-voice-overlay___LbxAI_1-1-18{
373
+ .magritte-voice-overlay___LbxAI_1-2-0{
282
374
  position:absolute;
283
375
  right:0;
284
376
  bottom:0;
package/index.d.ts CHANGED
@@ -2,6 +2,9 @@ export { ChatInput } from '@hh.ru/magritte-ui-chat-input/public/ChatInput';
2
2
  export { type ChatInputProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInput';
3
3
  export { type ChatInputVoiceRecordConfig } from '@hh.ru/magritte-ui-chat-input/types';
4
4
  export { type ChatInputChipsProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputChips';
5
+ export { type ChatInputFileProps, type ChatInputFileState, type ChatInputFileType, } from '@hh.ru/magritte-ui-chat-input/public/ChatInputFile';
6
+ export { getChatInputFileType } from '@hh.ru/magritte-ui-chat-input/public/getChatInputFileType';
7
+ export { type ChatInputFilesProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputFiles';
5
8
  export { type ChatInputPreviewProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputPreview';
6
9
  export { type ChatInputSendButtonProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputSendButton';
7
10
  export { type ChatInputVoiceButtonProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputVoiceButton';
package/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import './index.css';
2
2
  export { ChatInput } from './public/ChatInput.js';
3
+ export { getChatInputFileType } from './public/getChatInputFileType.js';
3
4
  import 'react/jsx-runtime';
4
5
  import 'react';
5
6
  import 'classnames';
@@ -9,7 +10,7 @@ import './internal/ChatInputContext.js';
9
10
  import './internal/ModeTransition.js';
10
11
  import 'motion/react';
11
12
  import '@hh.ru/magritte-design-tokens/core-tokens';
12
- import './styles-x_6MfT-u.js';
13
+ import './styles-BHWYKmPT.js';
13
14
  import './internal/TextInput.js';
14
15
  import './internal/useSendOnEnter.js';
15
16
  import '@hh.ru/magritte-common-keyboard';
@@ -28,8 +29,14 @@ import './internal/useVoiceRecordSession.js';
28
29
  import './internal/voiceSlotRegistry.js';
29
30
  import '@hh.ru/magritte-internal-slot-registry';
30
31
  import './public/ChatInputChips.js';
32
+ import './internal/flattenFragments.js';
31
33
  import '@hh.ru/magritte-ui-chips';
32
34
  import '@hh.ru/magritte-ui-scrollable-container';
35
+ import './public/ChatInputFile.js';
36
+ import '@hh.ru/magritte-ui-cell';
37
+ import './internal/useObjectUrl.js';
38
+ import '@hh.ru/magritte-ui-link';
39
+ import './public/ChatInputFiles.js';
33
40
  import './public/ChatInputPreview.js';
34
41
  import '@hh.ru/magritte-ui-icon';
35
42
  import './public/ChatInputSendButton.js';
package/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/index.mock.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export { type ChatInputProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInput';
2
2
  export { type ChatInputVoiceRecordConfig } from '@hh.ru/magritte-ui-chat-input/types';
3
3
  export { type ChatInputChipsProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputChips';
4
+ export { type ChatInputFileProps, type ChatInputFileState, type ChatInputFileType, } from '@hh.ru/magritte-ui-chat-input/public/ChatInputFile';
5
+ export { getChatInputFileType } from '@hh.ru/magritte-ui-chat-input/public/getChatInputFileType';
6
+ export { type ChatInputFilesProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputFiles';
4
7
  export { type ChatInputPreviewProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputPreview';
5
8
  export { type ChatInputSendButtonProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputSendButton';
6
9
  export { type ChatInputVoiceButtonProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputVoiceButton';
package/index.mock.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import './index.css';
2
+ export { getChatInputFileType } from './public/getChatInputFileType.js';
2
3
  import { jsxs, jsx } from 'react/jsx-runtime';
3
4
  import { forwardRef } from 'react';
4
5
 
@@ -35,6 +36,10 @@ const staticProps = {
35
36
  Chips: mockComponent('Chips', undefined, {
36
37
  withChildren: true,
37
38
  }),
39
+ File: mockComponent('File'),
40
+ Files: mockComponent('Files', undefined, {
41
+ withChildren: true,
42
+ }),
38
43
  Preview: mockComponent('Preview'),
39
44
  SendButton: mockComponent('SendButton'),
40
45
  VoiceButton: mockComponent('VoiceButton'),
package/index.mock.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.mock.js","sources":["../mock-component/lib/setupMockComponent.js","src/index.mock.ts"],"sourcesContent":["import { jsxs, jsx } from 'react/jsx-runtime';\nimport { forwardRef } from 'react';\n\nfunction enhance(mockComponent, staticProps) {\n // удаляем внутренний свойства реакта, чтобы не перезаписать ими mockComponent\n delete staticProps.type;\n delete staticProps.$$typeof;\n delete staticProps.render;\n for (const prop in staticProps) {\n mockComponent[prop] = staticProps[prop];\n }\n}\nconst MockComponent = ({ style, ...props }) => (\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\n// eslint-disable-next-line react/jsx-no-undef\njsx(\"magritte-component-mock\", { \"style-data\": style, ...props }));\nconst MockComponentRenderProp = ({ style, ...props }) => (\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\n// eslint-disable-next-line react/jsx-no-undef\njsx(\"magritte-component-mock-render-prop\", { \"style-data\": style, ...props }));\n/**\n * Возвращает mock React компонента\n */\nconst mockComponent = (componentName, staticProps = {}, { withChildren, innerDependence, WrapperComponent } = {}) => {\n const mockWrapper = forwardRef(({ children, ...props }, ref) => {\n const mock = (\n // eslint-disable-next-line react/jsx-no-undef\n jsxs(MockComponent, { ...props, _component: componentName, children: [innerDependence ? innerDependence(props, ref) : null, withChildren ? children : null] }));\n return WrapperComponent ? jsx(WrapperComponent, { ...props, children: mock }) : mock;\n });\n staticProps && enhance(mockWrapper, staticProps);\n mockWrapper.displayName = 'magritte-ref';\n return mockWrapper;\n};\n/**\n * Возвращает mock React компонента, который рендерит переданный в него пропс render\n *\n * @param {String} componentName наименование компонента\n * @param {Object} [staticProps] объект со свойствами, которыми необходимо усилить mock\n * @param {Object} [options] параметры мока\n * @param {boolean} [options.withChildren] флаг отвечает за рендеринг children компонента\n * @param {React.Component} [options.innerDependence] Реакт компонент, который рендерится внутри мока.\n * Необходим, когда mock компоненту требуется иметь\n * дополнительные элементы\n */\nconst mockComponentRenderProp = (componentName, staticProps, { withChildren, innerDependence, renderArguments } = { renderArguments: [] }) => {\n const mockWrapper = ({ render, children, ...props }) => (jsxs(MockComponentRenderProp, { ...props, _component: componentName, children: [innerDependence ? innerDependence(props) : null, withChildren ? children : null, render?.(...(renderArguments || []))] }));\n staticProps && enhance(mockWrapper, staticProps);\n mockWrapper.displayName = 'magritte-component-mock-render-prop';\n return mockWrapper;\n};\n\nexport { mockComponent, mockComponentRenderProp };\n//# sourceMappingURL=setupMockComponent.js.map\n","import { mockComponent } from '@hh.ru/magritte-ui-mock-component';\n\nexport { type ChatInputProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInput';\nexport { type ChatInputVoiceRecordConfig } from '@hh.ru/magritte-ui-chat-input/types';\nexport { type ChatInputChipsProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputChips';\nexport { type ChatInputPreviewProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputPreview';\nexport { type ChatInputSendButtonProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputSendButton';\nexport { type ChatInputVoiceButtonProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputVoiceButton';\n\nconst staticProps = {\n Chips: mockComponent('Chips', undefined, {\n withChildren: true,\n }),\n Preview: mockComponent('Preview'),\n SendButton: mockComponent('SendButton'),\n VoiceButton: mockComponent('VoiceButton'),\n};\n\nexport const ChatInput = mockComponent('ChatInput', staticProps, {\n withChildren: true,\n});\n"],"names":[],"mappings":";;;AAGA,SAAS,OAAO,CAAC,aAAa,EAAE,WAAW,EAAE;AAC7C;AACA,IAAI,OAAO,WAAW,CAAC,IAAI,CAAC;AAC5B,IAAI,OAAO,WAAW,CAAC,QAAQ,CAAC;AAChC,IAAI,OAAO,WAAW,CAAC,MAAM,CAAC;AAC9B,IAAI,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE;AACpC,QAAQ,aAAa,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;AAChD,KAAK;AACL,CAAC;AACD,MAAM,aAAa,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE;AAC1C;AACA;AACA;AACA,GAAG,CAAC,yBAAyB,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC;AAMnE;AACA;AACA;AACA,MAAM,aAAa,GAAG,CAAC,aAAa,EAAE,WAAW,GAAG,EAAE,EAAE,EAAE,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,GAAG,EAAE,KAAK;AACrH,IAAI,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,KAAK;AACpE,QAAQ,MAAM,IAAI;AAClB;AACA,QAAQ,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,eAAe,GAAG,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,YAAY,GAAG,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;AACxK,QAAQ,OAAO,gBAAgB,GAAG,GAAG,CAAC,gBAAgB,EAAE,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;AAC7F,KAAK,CAAC,CAAC;AACP,IAAI,WAAW,IAAI,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AACrD,IAAI,WAAW,CAAC,WAAW,GAAG,cAAc,CAAC;AAC7C,IAAI,OAAO,WAAW,CAAC;AACvB,CAAC;;AC1BD,MAAM,WAAW,GAAG;AAChB,IAAA,KAAK,EAAE,aAAa,CAAC,OAAO,EAAE,SAAS,EAAE;AACrC,QAAA,YAAY,EAAE,IAAI;KACrB,CAAC;AACF,IAAA,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC;AACjC,IAAA,UAAU,EAAE,aAAa,CAAC,YAAY,CAAC;AACvC,IAAA,WAAW,EAAE,aAAa,CAAC,aAAa,CAAC;CAC5C,CAAC;MAEW,SAAS,GAAG,aAAa,CAAC,WAAW,EAAE,WAAW,EAAE;AAC7D,IAAA,YAAY,EAAE,IAAI;AACrB,CAAA;;;;"}
1
+ {"version":3,"file":"index.mock.js","sources":["../mock-component/lib/setupMockComponent.js","src/index.mock.ts"],"sourcesContent":["import { jsxs, jsx } from 'react/jsx-runtime';\nimport { forwardRef } from 'react';\n\nfunction enhance(mockComponent, staticProps) {\n // удаляем внутренний свойства реакта, чтобы не перезаписать ими mockComponent\n delete staticProps.type;\n delete staticProps.$$typeof;\n delete staticProps.render;\n for (const prop in staticProps) {\n mockComponent[prop] = staticProps[prop];\n }\n}\nconst MockComponent = ({ style, ...props }) => (\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\n// eslint-disable-next-line react/jsx-no-undef\njsx(\"magritte-component-mock\", { \"style-data\": style, ...props }));\nconst MockComponentRenderProp = ({ style, ...props }) => (\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\n// eslint-disable-next-line react/jsx-no-undef\njsx(\"magritte-component-mock-render-prop\", { \"style-data\": style, ...props }));\n/**\n * Возвращает mock React компонента\n */\nconst mockComponent = (componentName, staticProps = {}, { withChildren, innerDependence, WrapperComponent } = {}) => {\n const mockWrapper = forwardRef(({ children, ...props }, ref) => {\n const mock = (\n // eslint-disable-next-line react/jsx-no-undef\n jsxs(MockComponent, { ...props, _component: componentName, children: [innerDependence ? innerDependence(props, ref) : null, withChildren ? children : null] }));\n return WrapperComponent ? jsx(WrapperComponent, { ...props, children: mock }) : mock;\n });\n staticProps && enhance(mockWrapper, staticProps);\n mockWrapper.displayName = 'magritte-ref';\n return mockWrapper;\n};\n/**\n * Возвращает mock React компонента, который рендерит переданный в него пропс render\n *\n * @param {String} componentName наименование компонента\n * @param {Object} [staticProps] объект со свойствами, которыми необходимо усилить mock\n * @param {Object} [options] параметры мока\n * @param {boolean} [options.withChildren] флаг отвечает за рендеринг children компонента\n * @param {React.Component} [options.innerDependence] Реакт компонент, который рендерится внутри мока.\n * Необходим, когда mock компоненту требуется иметь\n * дополнительные элементы\n */\nconst mockComponentRenderProp = (componentName, staticProps, { withChildren, innerDependence, renderArguments } = { renderArguments: [] }) => {\n const mockWrapper = ({ render, children, ...props }) => (jsxs(MockComponentRenderProp, { ...props, _component: componentName, children: [innerDependence ? innerDependence(props) : null, withChildren ? children : null, render?.(...(renderArguments || []))] }));\n staticProps && enhance(mockWrapper, staticProps);\n mockWrapper.displayName = 'magritte-component-mock-render-prop';\n return mockWrapper;\n};\n\nexport { mockComponent, mockComponentRenderProp };\n//# sourceMappingURL=setupMockComponent.js.map\n","import { mockComponent } from '@hh.ru/magritte-ui-mock-component';\n\nexport { type ChatInputProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInput';\nexport { type ChatInputVoiceRecordConfig } from '@hh.ru/magritte-ui-chat-input/types';\nexport { type ChatInputChipsProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputChips';\nexport {\n type ChatInputFileProps,\n type ChatInputFileState,\n type ChatInputFileType,\n} from '@hh.ru/magritte-ui-chat-input/public/ChatInputFile';\nexport { getChatInputFileType } from '@hh.ru/magritte-ui-chat-input/public/getChatInputFileType';\nexport { type ChatInputFilesProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputFiles';\nexport { type ChatInputPreviewProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputPreview';\nexport { type ChatInputSendButtonProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputSendButton';\nexport { type ChatInputVoiceButtonProps } from '@hh.ru/magritte-ui-chat-input/public/ChatInputVoiceButton';\n\nconst staticProps = {\n Chips: mockComponent('Chips', undefined, {\n withChildren: true,\n }),\n File: mockComponent('File'),\n Files: mockComponent('Files', undefined, {\n withChildren: true,\n }),\n Preview: mockComponent('Preview'),\n SendButton: mockComponent('SendButton'),\n VoiceButton: mockComponent('VoiceButton'),\n};\n\nexport const ChatInput = mockComponent('ChatInput', staticProps, {\n withChildren: true,\n});\n"],"names":[],"mappings":";;;;AAGA,SAAS,OAAO,CAAC,aAAa,EAAE,WAAW,EAAE;AAC7C;AACA,IAAI,OAAO,WAAW,CAAC,IAAI,CAAC;AAC5B,IAAI,OAAO,WAAW,CAAC,QAAQ,CAAC;AAChC,IAAI,OAAO,WAAW,CAAC,MAAM,CAAC;AAC9B,IAAI,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE;AACpC,QAAQ,aAAa,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;AAChD,KAAK;AACL,CAAC;AACD,MAAM,aAAa,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE;AAC1C;AACA;AACA;AACA,GAAG,CAAC,yBAAyB,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC;AAMnE;AACA;AACA;AACA,MAAM,aAAa,GAAG,CAAC,aAAa,EAAE,WAAW,GAAG,EAAE,EAAE,EAAE,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,GAAG,EAAE,KAAK;AACrH,IAAI,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,KAAK;AACpE,QAAQ,MAAM,IAAI;AAClB;AACA,QAAQ,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,eAAe,GAAG,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,YAAY,GAAG,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;AACxK,QAAQ,OAAO,gBAAgB,GAAG,GAAG,CAAC,gBAAgB,EAAE,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;AAC7F,KAAK,CAAC,CAAC;AACP,IAAI,WAAW,IAAI,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AACrD,IAAI,WAAW,CAAC,WAAW,GAAG,cAAc,CAAC;AAC7C,IAAI,OAAO,WAAW,CAAC;AACvB,CAAC;;ACnBD,MAAM,WAAW,GAAG;AAChB,IAAA,KAAK,EAAE,aAAa,CAAC,OAAO,EAAE,SAAS,EAAE;AACrC,QAAA,YAAY,EAAE,IAAI;KACrB,CAAC;AACF,IAAA,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC;AAC3B,IAAA,KAAK,EAAE,aAAa,CAAC,OAAO,EAAE,SAAS,EAAE;AACrC,QAAA,YAAY,EAAE,IAAI;KACrB,CAAC;AACF,IAAA,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC;AACjC,IAAA,UAAU,EAAE,aAAa,CAAC,YAAY,CAAC;AACvC,IAAA,WAAW,EAAE,aAAa,CAAC,aAAa,CAAC;CAC5C,CAAC;MAEW,SAAS,GAAG,aAAa,CAAC,WAAW,EAAE,WAAW,EAAE;AAC7D,IAAA,YAAY,EAAE,IAAI;AACrB,CAAA;;;;"}
@@ -2,7 +2,7 @@ import './../index.css';
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
3
  import { useReducedMotion, motion } from 'motion/react';
4
4
  import CoreTokens from '@hh.ru/magritte-design-tokens/core-tokens';
5
- import { s as styles } from '../styles-x_6MfT-u.js';
5
+ import { s as styles } from '../styles-BHWYKmPT.js';
6
6
 
7
7
  const EASE_BASE = [
8
8
  CoreTokens['magritte-semantic-animation-ease-base'].x1,
@@ -5,7 +5,7 @@ import classNames from 'classnames';
5
5
  import { useMultipleRefs } from '@hh.ru/magritte-common-use-multiple-refs';
6
6
  import { useSendOnEnter } from './useSendOnEnter.js';
7
7
  import { useScrollbar, Scrollbar } from '@hh.ru/magritte-ui-scrollbar';
8
- import { s as styles } from '../styles-x_6MfT-u.js';
8
+ import { s as styles } from '../styles-BHWYKmPT.js';
9
9
  import '@hh.ru/magritte-common-keyboard';
10
10
 
11
11
  const MIN_HEIGHT = 20;
@@ -9,7 +9,7 @@ import { FOCUS_PRIORITY } from './focusGroup.js';
9
9
  import { CrossOutlinedSize24, CheckOutlinedSize24 } from '@hh.ru/magritte-ui-icon/icon';
10
10
  import { Loader } from '@hh.ru/magritte-ui-loader';
11
11
  import { Text } from '@hh.ru/magritte-ui-typography';
12
- import { s as styles } from '../styles-x_6MfT-u.js';
12
+ import { s as styles } from '../styles-BHWYKmPT.js';
13
13
  import './useHasSound.js';
14
14
 
15
15
  const formatDuration = (totalSeconds) => {
@@ -2,7 +2,7 @@ import './../index.css';
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
  import classNames from 'classnames';
4
4
  import { useHasSound } from './useHasSound.js';
5
- import { s as styles } from '../styles-x_6MfT-u.js';
5
+ import { s as styles } from '../styles-BHWYKmPT.js';
6
6
  import 'react';
7
7
 
8
8
  const TARGET_HEIGHT = [2, 11, 22, 22, 22, 11, 22, 11, 6, 2];
@@ -0,0 +1,6 @@
1
+ import { type ReactNode } from 'react';
2
+ /** Раскрывает фрагменты в плоский список детей. Children.toArray сохраняет ключи детей —
3
+ * их можно перенести на обёртку, чтобы удаление элемента из середины не сдвигало стейт соседей.
4
+ * Внутренний Children.toArray нумерует детей фрагмента заново (.0, .1), поэтому к их ключам
5
+ * добавляется ключ фрагмента — иначе они совпадут с ключами соседей фрагмента */
6
+ export declare const flattenFragments: (children: ReactNode, keyPrefix?: string) => ReactNode[];
@@ -0,0 +1,20 @@
1
+ import './../index.css';
2
+ import { Children, isValidElement, Fragment, cloneElement } from 'react';
3
+
4
+ /** Раскрывает фрагменты в плоский список детей. Children.toArray сохраняет ключи детей —
5
+ * их можно перенести на обёртку, чтобы удаление элемента из середины не сдвигало стейт соседей.
6
+ * Внутренний Children.toArray нумерует детей фрагмента заново (.0, .1), поэтому к их ключам
7
+ * добавляется ключ фрагмента — иначе они совпадут с ключами соседей фрагмента */
8
+ const flattenFragments = (children, keyPrefix = '') => Children.toArray(children).flatMap((child) => {
9
+ if (!isValidElement(child)) {
10
+ return child;
11
+ }
12
+ const key = `${keyPrefix}${child.key}`;
13
+ if (child.type === Fragment) {
14
+ return flattenFragments(child.props.children, key);
15
+ }
16
+ return keyPrefix ? cloneElement(child, { key }) : child;
17
+ });
18
+
19
+ export { flattenFragments };
20
+ //# sourceMappingURL=flattenFragments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flattenFragments.js","sources":["src/internal/flattenFragments.ts"],"sourcesContent":["import { Children, cloneElement, Fragment, isValidElement, type PropsWithChildren, type ReactNode } from 'react';\n\n/** Раскрывает фрагменты в плоский список детей. Children.toArray сохраняет ключи детей —\n * их можно перенести на обёртку, чтобы удаление элемента из середины не сдвигало стейт соседей.\n * Внутренний Children.toArray нумерует детей фрагмента заново (.0, .1), поэтому к их ключам\n * добавляется ключ фрагмента — иначе они совпадут с ключами соседей фрагмента */\nexport const flattenFragments = (children: ReactNode, keyPrefix = ''): ReactNode[] =>\n Children.toArray(children).flatMap((child) => {\n if (!isValidElement(child)) {\n return child;\n }\n const key = `${keyPrefix}${child.key}`;\n if (child.type === Fragment) {\n return flattenFragments((child.props as PropsWithChildren).children, key);\n }\n return keyPrefix ? cloneElement(child, { key }) : child;\n });\n"],"names":[],"mappings":";;AAEA;;;AAGiF;AACpE,MAAA,gBAAgB,GAAG,CAAC,QAAmB,EAAE,SAAS,GAAG,EAAE,KAChE,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,KAAI;AACzC,IAAA,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE;AACxB,QAAA,OAAO,KAAK,CAAC;KAChB;IACD,MAAM,GAAG,GAAG,CAAG,EAAA,SAAS,GAAG,KAAK,CAAC,GAAG,CAAA,CAAE,CAAC;AACvC,IAAA,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE;QACzB,OAAO,gBAAgB,CAAE,KAAK,CAAC,KAA2B,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;KAC7E;AACD,IAAA,OAAO,SAAS,GAAG,YAAY,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,KAAK,CAAC;AAC5D,CAAC;;;;"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Url для отображения картинки: строку возвращает как есть, для Blob/File создаёт локальный object URL
3
+ * и отзывает его при смене источника и размонтировании. Blob с известным не-image типом пропускаем.
4
+ * URL создаётся в эффекте (не в рендере), поэтому StrictMode и SSR его не теряют и не плодят
5
+ */
6
+ export declare const useObjectUrl: (source: string | Blob | undefined) => string | undefined;
@@ -0,0 +1,30 @@
1
+ import './../index.css';
2
+ import { useState, useEffect } from 'react';
3
+
4
+ const isImageBlob = (blob) => !blob.type || blob.type.startsWith('image/');
5
+ /**
6
+ * Url для отображения картинки: строку возвращает как есть, для Blob/File создаёт локальный object URL
7
+ * и отзывает его при смене источника и размонтировании. Blob с известным не-image типом пропускаем.
8
+ * URL создаётся в эффекте (не в рендере), поэтому StrictMode и SSR его не теряют и не плодят
9
+ */
10
+ const useObjectUrl = (source) => {
11
+ const blob = source instanceof Blob && isImageBlob(source) ? source : undefined;
12
+ const [objectUrl, setObjectUrl] = useState();
13
+ useEffect(() => {
14
+ if (!blob) {
15
+ setObjectUrl(undefined);
16
+ return undefined;
17
+ }
18
+ const url = URL.createObjectURL(blob);
19
+ setObjectUrl({ blob, url });
20
+ return () => URL.revokeObjectURL(url);
21
+ }, [blob]);
22
+ if (typeof source === 'string') {
23
+ return source;
24
+ }
25
+ // url от предыдущего Blob уже отозван — до эффекта для нового ничего не отдаём
26
+ return objectUrl && objectUrl.blob === blob ? objectUrl.url : undefined;
27
+ };
28
+
29
+ export { useObjectUrl };
30
+ //# sourceMappingURL=useObjectUrl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useObjectUrl.js","sources":["src/internal/useObjectUrl.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\nconst isImageBlob = (blob: Blob): boolean => !blob.type || blob.type.startsWith('image/');\n\n/**\n * Url для отображения картинки: строку возвращает как есть, для Blob/File создаёт локальный object URL\n * и отзывает его при смене источника и размонтировании. Blob с известным не-image типом пропускаем.\n * URL создаётся в эффекте (не в рендере), поэтому StrictMode и SSR его не теряют и не плодят\n */\nexport const useObjectUrl = (source: string | Blob | undefined): string | undefined => {\n const blob = source instanceof Blob && isImageBlob(source) ? source : undefined;\n const [objectUrl, setObjectUrl] = useState<{ blob: Blob; url: string }>();\n\n useEffect(() => {\n if (!blob) {\n setObjectUrl(undefined);\n return undefined;\n }\n const url = URL.createObjectURL(blob);\n setObjectUrl({ blob, url });\n return () => URL.revokeObjectURL(url);\n }, [blob]);\n\n if (typeof source === 'string') {\n return source;\n }\n // url от предыдущего Blob уже отозван — до эффекта для нового ничего не отдаём\n return objectUrl && objectUrl.blob === blob ? objectUrl.url : undefined;\n};\n"],"names":[],"mappings":";;AAEA,MAAM,WAAW,GAAG,CAAC,IAAU,KAAc,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AAE1F;;;;AAIG;AACU,MAAA,YAAY,GAAG,CAAC,MAAiC,KAAwB;AAClF,IAAA,MAAM,IAAI,GAAG,MAAM,YAAY,IAAI,IAAI,WAAW,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC;IAChF,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,EAA+B,CAAC;IAE1E,SAAS,CAAC,MAAK;QACX,IAAI,CAAC,IAAI,EAAE;YACP,YAAY,CAAC,SAAS,CAAC,CAAC;AACxB,YAAA,OAAO,SAAS,CAAC;SACpB;QACD,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;AACtC,QAAA,YAAY,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5B,OAAO,MAAM,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;AAC1C,KAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AAEX,IAAA,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AAC5B,QAAA,OAAO,MAAM,CAAC;KACjB;;AAED,IAAA,OAAO,SAAS,IAAI,SAAS,CAAC,IAAI,KAAK,IAAI,GAAG,SAAS,CAAC,GAAG,GAAG,SAAS,CAAC;AAC5E;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hh.ru/magritte-ui-chat-input",
3
- "version": "1.1.18",
3
+ "version": "1.2.0",
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "sideEffects": [
@@ -30,15 +30,17 @@
30
30
  "@hh.ru/magritte-common-keyboard": "4.3.5",
31
31
  "@hh.ru/magritte-common-use-disabled": "1.0.15",
32
32
  "@hh.ru/magritte-common-use-multiple-refs": "1.1.11",
33
- "@hh.ru/magritte-common-use-translation": "3.5.0",
33
+ "@hh.ru/magritte-common-use-translation": "3.6.0",
34
34
  "@hh.ru/magritte-design-tokens": "25.1.0",
35
35
  "@hh.ru/magritte-internal-slot-registry": "1.1.0",
36
- "@hh.ru/magritte-ui-chips": "7.0.42",
36
+ "@hh.ru/magritte-ui-cell": "7.3.0",
37
+ "@hh.ru/magritte-ui-chips": "7.0.44",
37
38
  "@hh.ru/magritte-ui-icon": "15.1.2",
39
+ "@hh.ru/magritte-ui-link": "7.2.3",
38
40
  "@hh.ru/magritte-ui-loader": "4.1.3",
39
- "@hh.ru/magritte-ui-scrollable-container": "6.4.10",
41
+ "@hh.ru/magritte-ui-scrollable-container": "6.5.0",
40
42
  "@hh.ru/magritte-ui-scrollbar": "1.0.36",
41
43
  "@hh.ru/magritte-ui-typography": "5.3.13"
42
44
  },
43
- "gitHead": "37c822e9d543ad23d6aec07b4a18c6d2d2b3ee3a"
45
+ "gitHead": "4420819c71c2d263ef47b3208c47942e9f0a1d30"
44
46
  }
@@ -1,5 +1,7 @@
1
1
  import { type ChangeEventHandler, type ForwardedRef, type ForwardRefExoticComponent, type ReactNode, type RefAttributes, type TextareaHTMLAttributes } from 'react';
2
2
  import { ChatInputChips } from '@hh.ru/magritte-ui-chat-input/public/ChatInputChips';
3
+ import { ChatInputFile } from '@hh.ru/magritte-ui-chat-input/public/ChatInputFile';
4
+ import { ChatInputFiles } from '@hh.ru/magritte-ui-chat-input/public/ChatInputFiles';
3
5
  import { ChatInputPreview } from '@hh.ru/magritte-ui-chat-input/public/ChatInputPreview';
4
6
  import { ChatInputSendButton } from '@hh.ru/magritte-ui-chat-input/public/ChatInputSendButton';
5
7
  import { ChatInputVoiceButton } from '@hh.ru/magritte-ui-chat-input/public/ChatInputVoiceButton';
@@ -39,6 +41,8 @@ interface ChatInputOwnProps {
39
41
  export type ChatInputProps = ChatInputOwnProps & Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, keyof ChatInputOwnProps | 'defaultValue'>;
40
42
  interface ChatInputComponents {
41
43
  Chips: typeof ChatInputChips;
44
+ File: typeof ChatInputFile;
45
+ Files: typeof ChatInputFiles;
42
46
  Preview: typeof ChatInputPreview;
43
47
  SendButton: typeof ChatInputSendButton;
44
48
  VoiceButton: typeof ChatInputVoiceButton;
@@ -13,11 +13,13 @@ import { useRovingFocusGroup } from '../internal/useRovingFocusGroup.js';
13
13
  import { useVoiceRecordSession } from '../internal/useVoiceRecordSession.js';
14
14
  import { ChatInputVoiceSlotProvider, useVoiceConfig } from '../internal/voiceSlotRegistry.js';
15
15
  import { ChatInputChips } from './ChatInputChips.js';
16
+ import { ChatInputFile } from './ChatInputFile.js';
17
+ import { ChatInputFiles } from './ChatInputFiles.js';
16
18
  import { ChatInputPreview } from './ChatInputPreview.js';
17
19
  import { ChatInputSendButton } from './ChatInputSendButton.js';
18
20
  import { ChatInputVoiceButton } from './ChatInputVoiceButton.js';
19
21
  import { IconDefaultPropsContext } from '@hh.ru/magritte-ui-icon';
20
- import { s as styles } from '../styles-x_6MfT-u.js';
22
+ import { s as styles } from '../styles-BHWYKmPT.js';
21
23
  import 'motion/react';
22
24
  import '@hh.ru/magritte-design-tokens/core-tokens';
23
25
  import '../internal/useSendOnEnter.js';
@@ -31,8 +33,12 @@ import '@hh.ru/magritte-ui-icon/icon';
31
33
  import '@hh.ru/magritte-ui-loader';
32
34
  import '@hh.ru/magritte-ui-typography';
33
35
  import '@hh.ru/magritte-internal-slot-registry';
36
+ import '../internal/flattenFragments.js';
34
37
  import '@hh.ru/magritte-ui-chips';
35
38
  import '@hh.ru/magritte-ui-scrollable-container';
39
+ import '@hh.ru/magritte-ui-cell';
40
+ import '../internal/useObjectUrl.js';
41
+ import '@hh.ru/magritte-ui-link';
36
42
  import '../internal/ChatInputSlotButton.js';
37
43
 
38
44
  const DEFAULT_ICON_PROPS = {
@@ -114,6 +120,8 @@ const ChatInputComponent = (props, ref) => (jsx(ChatInputVoiceSlotProvider, { ch
114
120
  const ChatInput = forwardRef(ChatInputComponent);
115
121
  ChatInput.displayName = 'ChatInput';
116
122
  ChatInput.Chips = ChatInputChips;
123
+ ChatInput.File = ChatInputFile;
124
+ ChatInput.Files = ChatInputFiles;
117
125
  ChatInput.Preview = ChatInputPreview;
118
126
  ChatInput.SendButton = ChatInputSendButton;
119
127
  ChatInput.VoiceButton = ChatInputVoiceButton;
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInput.js","sources":["src/public/ChatInput.tsx"],"sourcesContent":["import {\n type ChangeEventHandler,\n type FC,\n type ForwardedRef,\n forwardRef,\n type ForwardRefExoticComponent,\n type ReactNode,\n type RefAttributes,\n type TextareaHTMLAttributes,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport classNames from 'classnames';\n\nimport { DisabledContext, useDisabled } from '@hh.ru/magritte-common-use-disabled';\nimport { useMultipleRefs } from '@hh.ru/magritte-common-use-multiple-refs';\nimport { ChatInputContextProvider } from '@hh.ru/magritte-ui-chat-input/internal/ChatInputContext';\nimport { ModeTransition } from '@hh.ru/magritte-ui-chat-input/internal/ModeTransition';\nimport { TextInput } from '@hh.ru/magritte-ui-chat-input/internal/TextInput';\nimport { VoiceRecord } from '@hh.ru/magritte-ui-chat-input/internal/VoiceRecord';\nimport { FOCUS_PRIORITY, focusPriorityProps } from '@hh.ru/magritte-ui-chat-input/internal/focusGroup';\nimport { useRovingFocusGroup } from '@hh.ru/magritte-ui-chat-input/internal/useRovingFocusGroup';\nimport { useVoiceRecordSession } from '@hh.ru/magritte-ui-chat-input/internal/useVoiceRecordSession';\nimport { ChatInputVoiceSlotProvider, useVoiceConfig } from '@hh.ru/magritte-ui-chat-input/internal/voiceSlotRegistry';\nimport { ChatInputChips } from '@hh.ru/magritte-ui-chat-input/public/ChatInputChips';\nimport { ChatInputPreview } from '@hh.ru/magritte-ui-chat-input/public/ChatInputPreview';\nimport { ChatInputSendButton } from '@hh.ru/magritte-ui-chat-input/public/ChatInputSendButton';\nimport { ChatInputVoiceButton } from '@hh.ru/magritte-ui-chat-input/public/ChatInputVoiceButton';\nimport { IconDefaultPropsContext } from '@hh.ru/magritte-ui-icon';\n\nimport styles from '../styles.less';\n\ninterface ChatInputOwnProps {\n /** Левый слот */\n leftActions?: ReactNode;\n /** Правый слот */\n rightActions?: ReactNode;\n /** Центральный нижний слот */\n centralActions?: ReactNode;\n /** Верхний слот для блока превью */\n preview?: ReactNode;\n /** Максимальная высота поля ввода в пикселях. Если не задан — высота не ограничена. */\n maxHeight?: number;\n /**\n * Раскладка поля ввода.\n * `horizontal` — ввод стоит в ряду контролов, пока содержимое помещается в одну строку,\n * и сам переезжает на свой ряд, когда перестаёт влезать.\n * `vertical` — ввод всегда на своём ряду; в горизонтальный слот его не ставим.\n * @default horizontal\n */\n layout?: 'vertical' | 'horizontal';\n /** Хендлер отправки: вызывается по Enter (Shift+Enter — перенос строки) */\n onSend?: VoidFunction;\n /** Значение поля ввода. Компонент работает только в controlled-режиме */\n value: string;\n /** Обработчик изменения значения */\n onChange: ChangeEventHandler<HTMLTextAreaElement>;\n /** Реф на корневую обёртку — для измерения размеров/позиционирования.\n * Реф на textarea (фокус и т.п.) прокидывается обычным `ref`, как у Input/TextArea */\n wrapperRef?: ForwardedRef<HTMLDivElement>;\n /** Отключает фон и обводку компонента */\n noBackground?: boolean;\n disabled?: boolean;\n 'data-qa'?: string;\n}\n\n// defaultValue исключён: компонент только controlled, uncontrolled-режим не поддерживается\nexport type ChatInputProps = ChatInputOwnProps &\n Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, keyof ChatInputOwnProps | 'defaultValue'>;\n\nconst DEFAULT_ICON_PROPS = {\n borderRadius: 12,\n padding: 8,\n initialColor: 'secondary',\n} as const;\n\ninterface ChatInputComponents {\n Chips: typeof ChatInputChips;\n Preview: typeof ChatInputPreview;\n SendButton: typeof ChatInputSendButton;\n VoiceButton: typeof ChatInputVoiceButton;\n}\n\ntype ChatInputInnerProps = ChatInputProps & {\n /** Реф на textarea, переданный через forwardRef внешней обёртки */\n textareaRef: ForwardedRef<HTMLTextAreaElement>;\n};\n\nconst ChatInputInner: FC<ChatInputInnerProps> = ({\n leftActions,\n rightActions,\n centralActions,\n preview,\n maxHeight,\n layout = 'horizontal',\n onSend,\n wrapperRef,\n textareaRef,\n noBackground = false,\n disabled = false,\n 'data-qa': dataQa = 'chat-input',\n ...textareaProps\n}) => {\n const outerDisabled = useDisabled();\n const isDisabled = disabled || outerDisabled;\n const rootRef = useRef<HTMLDivElement>(null);\n const rootRefCallback = useMultipleRefs(rootRef, wrapperRef);\n // реф textarea — для возврата фокуса при выходе из режима записи\n const textareaLocalRef = useRef<HTMLTextAreaElement>(null);\n const textareaRefCallback = useMultipleRefs(textareaLocalRef, textareaRef);\n const [containerWidth, setContainerWidth] = useState<number>();\n useLayoutEffect(() => {\n const root = rootRef.current;\n if (!root) {\n return undefined;\n }\n const observer = new ResizeObserver((entries) => {\n const width = Math.round(entries[0]?.contentRect.width ?? 0);\n setContainerWidth((prev) => (prev === width ? prev : width));\n });\n observer.observe(root);\n return () => observer.disconnect();\n }, []);\n\n // конфиг записи регистрирует ChatInput.VoiceButton через slot-registry. Кнопка живёт в\n // text-гриде, который на время записи не размонтируется (ModeTransition лишь прячет его), —\n // поэтому регистрация и колбэки остаются живыми всю сессию, латч не нужен\n const voiceConfig = useVoiceConfig();\n\n const voiceSession = useVoiceRecordSession(voiceConfig ?? {});\n\n const contextValue = useMemo(\n () => ({\n onSend,\n startVoiceRecord: voiceSession.start,\n voiceRecordStatus: voiceSession.status,\n }),\n [onSend, voiceSession.start, voiceSession.status]\n );\n\n // режим ведём по статусу сессии, а не по наличию конфига: даже если приложение уберёт кнопку\n // по ходу записи, запись продолжается. Без кнопки запись не стартует, так что статус сам остаётся idle\n const isVoiceMode = voiceSession.status === 'recording' || voiceSession.status === 'processing';\n\n // roving-группа кнопок: один tab stop на все кнопки, внутри — стрелки по приоритетам\n const { focusStop } = useRovingFocusGroup(rootRef);\n\n // при входе в запись фокус на стоп группы (после смены слоя это галочка — первый приоритет\n // слоя записи), при возврате в текст — в textarea с курсором в конце. Фокус ставим в rAF:\n // слой режима к этому моменту уже видим (motion применил visibility), иначе focus()\n // на visibility:hidden не сработает\n const prevVoiceModeRef = useRef(isVoiceMode);\n useEffect(() => {\n const wasVoiceMode = prevVoiceModeRef.current;\n prevVoiceModeRef.current = isVoiceMode;\n if (wasVoiceMode === isVoiceMode) {\n return undefined;\n }\n const frameId = requestAnimationFrame(() => {\n if (isVoiceMode) {\n focusStop();\n return;\n }\n const textarea = textareaLocalRef.current;\n if (textarea) {\n textarea.focus();\n const caret = textarea.value.length;\n textarea.setSelectionRange(caret, caret);\n }\n });\n return () => cancelAnimationFrame(frameId);\n }, [isVoiceMode, focusStop]);\n\n return (\n <DisabledContext.Provider value={isDisabled}>\n <ChatInputContextProvider value={contextValue}>\n <div\n ref={rootRefCallback}\n className={classNames(styles.chatInput, { [styles.noBackground]: noBackground })}\n data-qa={dataQa}\n >\n <ModeTransition\n mode={isVoiceMode ? 'voice' : 'text'}\n voice={\n <VoiceRecord\n mode={voiceSession.status === 'processing' ? 'processing' : 'recording'}\n stream={voiceSession.stream}\n startedAt={voiceSession.startedAt}\n processingLabel={voiceConfig?.processingLabel}\n onComplete={voiceSession.stop}\n onCancel={voiceSession.cancel}\n completeButtonProps={voiceConfig?.completeButtonProps}\n cancelButtonProps={voiceConfig?.cancelButtonProps}\n data-qa=\"chat-input-voice-record\"\n />\n }\n text={\n <div\n className={classNames(styles.contentGrid, {\n [styles.noLeftControls]: !leftActions,\n [styles.noRightControls]: !rightActions,\n [styles.hasCentral]: !!centralActions,\n })}\n >\n {/* textarea в DOM первым намеренно: Tab снаружи входит сначала в него.\n Раскладку держит grid-area (от порядка не зависит). Кнопки слотов —\n одна roving-группа (useRovingFocusGroup): Tab видит только текущий\n стоп, внутри группы фокус ходит стрелками по приоритетам слотов */}\n <TextInput\n {...textareaProps}\n ref={textareaRefCallback}\n layout={layout}\n onSend={onSend}\n maxHeight={maxHeight}\n containerWidth={containerWidth}\n hasCentral={!!centralActions}\n disabled={isDisabled}\n hasBothSideControls={!!leftActions && !!rightActions}\n />\n {!!rightActions && (\n <IconDefaultPropsContext props={DEFAULT_ICON_PROPS}>\n <div className={styles.right} {...focusPriorityProps(FOCUS_PRIORITY.rightSlot)}>\n {rightActions}\n </div>\n </IconDefaultPropsContext>\n )}\n {!!leftActions && (\n <IconDefaultPropsContext props={DEFAULT_ICON_PROPS}>\n <div className={styles.left} {...focusPriorityProps(FOCUS_PRIORITY.leftSlot)}>\n {leftActions}\n </div>\n </IconDefaultPropsContext>\n )}\n {!!centralActions && (\n <div className={styles.central} {...focusPriorityProps(FOCUS_PRIORITY.centralSlot)}>\n {centralActions}\n </div>\n )}\n {!!preview && (\n <div className={styles.preview} {...focusPriorityProps(FOCUS_PRIORITY.previewSlot)}>\n {preview}\n </div>\n )}\n </div>\n }\n />\n </div>\n </ChatInputContextProvider>\n </DisabledContext.Provider>\n );\n};\n\n// внешняя обёртка держит slot-registry для конфига записи: кнопка (внутри слота) регистрирует\n// конфиг, ChatInputInner (ниже провайдера) читает его. forwardRef-реф на textarea прокидываем\n// вниз обычным пропом\nconst ChatInputComponent = (props: ChatInputProps, ref: ForwardedRef<HTMLTextAreaElement>) => (\n <ChatInputVoiceSlotProvider>\n <ChatInputInner {...props} textareaRef={ref} />\n </ChatInputVoiceSlotProvider>\n);\n\nconst ChatInput = forwardRef(ChatInputComponent) as ForwardRefExoticComponent<\n ChatInputProps & RefAttributes<HTMLTextAreaElement>\n> &\n ChatInputComponents;\n\nChatInput.displayName = 'ChatInput';\n\nChatInput.Chips = ChatInputChips;\nChatInput.Preview = ChatInputPreview;\nChatInput.SendButton = ChatInputSendButton;\nChatInput.VoiceButton = ChatInputVoiceButton;\n\nexport { ChatInput };\n"],"names":["_jsx","_jsxs"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyEA,MAAM,kBAAkB,GAAG;AACvB,IAAA,YAAY,EAAE,EAAE;AAChB,IAAA,OAAO,EAAE,CAAC;AACV,IAAA,YAAY,EAAE,WAAW;CACnB,CAAC;AAcX,MAAM,cAAc,GAA4B,CAAC,EAC7C,WAAW,EACX,YAAY,EACZ,cAAc,EACd,OAAO,EACP,SAAS,EACT,MAAM,GAAG,YAAY,EACrB,MAAM,EACN,UAAU,EACV,WAAW,EACX,YAAY,GAAG,KAAK,EACpB,QAAQ,GAAG,KAAK,EAChB,SAAS,EAAE,MAAM,GAAG,YAAY,EAChC,GAAG,aAAa,EACnB,KAAI;AACD,IAAA,MAAM,aAAa,GAAG,WAAW,EAAE,CAAC;AACpC,IAAA,MAAM,UAAU,GAAG,QAAQ,IAAI,aAAa,CAAC;AAC7C,IAAA,MAAM,OAAO,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC7C,MAAM,eAAe,GAAG,eAAe,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;;AAE7D,IAAA,MAAM,gBAAgB,GAAG,MAAM,CAAsB,IAAI,CAAC,CAAC;IAC3D,MAAM,mBAAmB,GAAG,eAAe,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;IAC3E,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,EAAU,CAAC;IAC/D,eAAe,CAAC,MAAK;AACjB,QAAA,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,IAAI,EAAE;AACP,YAAA,OAAO,SAAS,CAAC;SACpB;QACD,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,CAAC,OAAO,KAAI;AAC5C,YAAA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;YAC7D,iBAAiB,CAAC,CAAC,IAAI,MAAM,IAAI,KAAK,KAAK,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC;AACjE,SAAC,CAAC,CAAC;AACH,QAAA,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACvB,QAAA,OAAO,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC;KACtC,EAAE,EAAE,CAAC,CAAC;;;;AAKP,IAAA,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,MAAM,YAAY,GAAG,qBAAqB,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;AAE9D,IAAA,MAAM,YAAY,GAAG,OAAO,CACxB,OAAO;QACH,MAAM;QACN,gBAAgB,EAAE,YAAY,CAAC,KAAK;QACpC,iBAAiB,EAAE,YAAY,CAAC,MAAM;AACzC,KAAA,CAAC,EACF,CAAC,MAAM,EAAE,YAAY,CAAC,KAAK,EAAE,YAAY,CAAC,MAAM,CAAC,CACpD,CAAC;;;AAIF,IAAA,MAAM,WAAW,GAAG,YAAY,CAAC,MAAM,KAAK,WAAW,IAAI,YAAY,CAAC,MAAM,KAAK,YAAY,CAAC;;IAGhG,MAAM,EAAE,SAAS,EAAE,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;;;;;AAMnD,IAAA,MAAM,gBAAgB,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IAC7C,SAAS,CAAC,MAAK;AACX,QAAA,MAAM,YAAY,GAAG,gBAAgB,CAAC,OAAO,CAAC;AAC9C,QAAA,gBAAgB,CAAC,OAAO,GAAG,WAAW,CAAC;AACvC,QAAA,IAAI,YAAY,KAAK,WAAW,EAAE;AAC9B,YAAA,OAAO,SAAS,CAAC;SACpB;AACD,QAAA,MAAM,OAAO,GAAG,qBAAqB,CAAC,MAAK;YACvC,IAAI,WAAW,EAAE;AACb,gBAAA,SAAS,EAAE,CAAC;gBACZ,OAAO;aACV;AACD,YAAA,MAAM,QAAQ,GAAG,gBAAgB,CAAC,OAAO,CAAC;YAC1C,IAAI,QAAQ,EAAE;gBACV,QAAQ,CAAC,KAAK,EAAE,CAAC;AACjB,gBAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;AACpC,gBAAA,QAAQ,CAAC,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;aAC5C;AACL,SAAC,CAAC,CAAC;AACH,QAAA,OAAO,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC/C,KAAC,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;AAE7B,IAAA,QACIA,GAAA,CAAC,eAAe,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,UAAU,EAAA,QAAA,EACvCA,GAAC,CAAA,wBAAwB,IAAC,KAAK,EAAE,YAAY,EAAA,QAAA,EACzCA,GACI,CAAA,KAAA,EAAA,EAAA,GAAG,EAAE,eAAe,EACpB,SAAS,EAAE,UAAU,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,GAAG,YAAY,EAAE,CAAC,EACvE,SAAA,EAAA,MAAM,EAEf,QAAA,EAAAA,GAAA,CAAC,cAAc,EAAA,EACX,IAAI,EAAE,WAAW,GAAG,OAAO,GAAG,MAAM,EACpC,KAAK,EACDA,GAAC,CAAA,WAAW,EACR,EAAA,IAAI,EAAE,YAAY,CAAC,MAAM,KAAK,YAAY,GAAG,YAAY,GAAG,WAAW,EACvE,MAAM,EAAE,YAAY,CAAC,MAAM,EAC3B,SAAS,EAAE,YAAY,CAAC,SAAS,EACjC,eAAe,EAAE,WAAW,EAAE,eAAe,EAC7C,UAAU,EAAE,YAAY,CAAC,IAAI,EAC7B,QAAQ,EAAE,YAAY,CAAC,MAAM,EAC7B,mBAAmB,EAAE,WAAW,EAAE,mBAAmB,EACrD,iBAAiB,EAAE,WAAW,EAAE,iBAAiB,EACzC,SAAA,EAAA,yBAAyB,EACnC,CAAA,EAEN,IAAI,EACAC,IAAA,CAAA,KAAA,EAAA,EACI,SAAS,EAAE,UAAU,CAAC,MAAM,CAAC,WAAW,EAAE;AACtC,4BAAA,CAAC,MAAM,CAAC,cAAc,GAAG,CAAC,WAAW;AACrC,4BAAA,CAAC,MAAM,CAAC,eAAe,GAAG,CAAC,YAAY;AACvC,4BAAA,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC,cAAc;AACxC,yBAAA,CAAC,aAMFD,GAAC,CAAA,SAAS,EACF,EAAA,GAAA,aAAa,EACjB,GAAG,EAAE,mBAAmB,EACxB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,cAAc,EAC9B,UAAU,EAAE,CAAC,CAAC,cAAc,EAC5B,QAAQ,EAAE,UAAU,EACpB,mBAAmB,EAAE,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,YAAY,EAAA,CACtD,EACD,CAAC,CAAC,YAAY,KACXA,GAAC,CAAA,uBAAuB,EAAC,EAAA,KAAK,EAAE,kBAAkB,EAAA,QAAA,EAC9CA,GAAK,CAAA,KAAA,EAAA,EAAA,SAAS,EAAE,MAAM,CAAC,KAAK,EAAA,GAAM,kBAAkB,CAAC,cAAc,CAAC,SAAS,CAAC,EACzE,QAAA,EAAA,YAAY,GACX,EACgB,CAAA,CAC7B,EACA,CAAC,CAAC,WAAW,KACVA,GAAC,CAAA,uBAAuB,EAAC,EAAA,KAAK,EAAE,kBAAkB,EAAA,QAAA,EAC9CA,GAAK,CAAA,KAAA,EAAA,EAAA,SAAS,EAAE,MAAM,CAAC,IAAI,EAAA,GAAM,kBAAkB,CAAC,cAAc,CAAC,QAAQ,CAAC,EACvE,QAAA,EAAA,WAAW,EACV,CAAA,EAAA,CACgB,CAC7B,EACA,CAAC,CAAC,cAAc,KACbA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,OAAO,EAAA,GAAM,kBAAkB,CAAC,cAAc,CAAC,WAAW,CAAC,EAAA,QAAA,EAC7E,cAAc,EACb,CAAA,CACT,EACA,CAAC,CAAC,OAAO,KACNA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,OAAO,KAAM,kBAAkB,CAAC,cAAc,CAAC,WAAW,CAAC,EAAA,QAAA,EAC7E,OAAO,EAAA,CACN,CACT,CACC,EAAA,CAAA,EAAA,CAEZ,GACA,EACiB,CAAA,EAAA,CACJ,EAC7B;AACN,CAAC,CAAC;AAEF;AACA;AACA;AACA,MAAM,kBAAkB,GAAG,CAAC,KAAqB,EAAE,GAAsC,MACrFA,GAAC,CAAA,0BAA0B,cACvBA,GAAC,CAAA,cAAc,EAAK,EAAA,GAAA,KAAK,EAAE,WAAW,EAAE,GAAG,EAAA,CAAI,EACtB,CAAA,CAChC,CAAC;AAEF,MAAM,SAAS,GAAG,UAAU,CAAC,kBAAkB,EAGvB;AAExB,SAAS,CAAC,WAAW,GAAG,WAAW,CAAC;AAEpC,SAAS,CAAC,KAAK,GAAG,cAAc,CAAC;AACjC,SAAS,CAAC,OAAO,GAAG,gBAAgB,CAAC;AACrC,SAAS,CAAC,UAAU,GAAG,mBAAmB,CAAC;AAC3C,SAAS,CAAC,WAAW,GAAG,oBAAoB;;;;"}
1
+ {"version":3,"file":"ChatInput.js","sources":["src/public/ChatInput.tsx"],"sourcesContent":["import {\n type ChangeEventHandler,\n type FC,\n type ForwardedRef,\n forwardRef,\n type ForwardRefExoticComponent,\n type ReactNode,\n type RefAttributes,\n type TextareaHTMLAttributes,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport classNames from 'classnames';\n\nimport { DisabledContext, useDisabled } from '@hh.ru/magritte-common-use-disabled';\nimport { useMultipleRefs } from '@hh.ru/magritte-common-use-multiple-refs';\nimport { ChatInputContextProvider } from '@hh.ru/magritte-ui-chat-input/internal/ChatInputContext';\nimport { ModeTransition } from '@hh.ru/magritte-ui-chat-input/internal/ModeTransition';\nimport { TextInput } from '@hh.ru/magritte-ui-chat-input/internal/TextInput';\nimport { VoiceRecord } from '@hh.ru/magritte-ui-chat-input/internal/VoiceRecord';\nimport { FOCUS_PRIORITY, focusPriorityProps } from '@hh.ru/magritte-ui-chat-input/internal/focusGroup';\nimport { useRovingFocusGroup } from '@hh.ru/magritte-ui-chat-input/internal/useRovingFocusGroup';\nimport { useVoiceRecordSession } from '@hh.ru/magritte-ui-chat-input/internal/useVoiceRecordSession';\nimport { ChatInputVoiceSlotProvider, useVoiceConfig } from '@hh.ru/magritte-ui-chat-input/internal/voiceSlotRegistry';\nimport { ChatInputChips } from '@hh.ru/magritte-ui-chat-input/public/ChatInputChips';\nimport { ChatInputFile } from '@hh.ru/magritte-ui-chat-input/public/ChatInputFile';\nimport { ChatInputFiles } from '@hh.ru/magritte-ui-chat-input/public/ChatInputFiles';\nimport { ChatInputPreview } from '@hh.ru/magritte-ui-chat-input/public/ChatInputPreview';\nimport { ChatInputSendButton } from '@hh.ru/magritte-ui-chat-input/public/ChatInputSendButton';\nimport { ChatInputVoiceButton } from '@hh.ru/magritte-ui-chat-input/public/ChatInputVoiceButton';\nimport { IconDefaultPropsContext } from '@hh.ru/magritte-ui-icon';\n\nimport styles from '../styles.less';\n\ninterface ChatInputOwnProps {\n /** Левый слот */\n leftActions?: ReactNode;\n /** Правый слот */\n rightActions?: ReactNode;\n /** Центральный нижний слот */\n centralActions?: ReactNode;\n /** Верхний слот для блока превью */\n preview?: ReactNode;\n /** Максимальная высота поля ввода в пикселях. Если не задан — высота не ограничена. */\n maxHeight?: number;\n /**\n * Раскладка поля ввода.\n * `horizontal` — ввод стоит в ряду контролов, пока содержимое помещается в одну строку,\n * и сам переезжает на свой ряд, когда перестаёт влезать.\n * `vertical` — ввод всегда на своём ряду; в горизонтальный слот его не ставим.\n * @default horizontal\n */\n layout?: 'vertical' | 'horizontal';\n /** Хендлер отправки: вызывается по Enter (Shift+Enter — перенос строки) */\n onSend?: VoidFunction;\n /** Значение поля ввода. Компонент работает только в controlled-режиме */\n value: string;\n /** Обработчик изменения значения */\n onChange: ChangeEventHandler<HTMLTextAreaElement>;\n /** Реф на корневую обёртку — для измерения размеров/позиционирования.\n * Реф на textarea (фокус и т.п.) прокидывается обычным `ref`, как у Input/TextArea */\n wrapperRef?: ForwardedRef<HTMLDivElement>;\n /** Отключает фон и обводку компонента */\n noBackground?: boolean;\n disabled?: boolean;\n 'data-qa'?: string;\n}\n\n// defaultValue исключён: компонент только controlled, uncontrolled-режим не поддерживается\nexport type ChatInputProps = ChatInputOwnProps &\n Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, keyof ChatInputOwnProps | 'defaultValue'>;\n\nconst DEFAULT_ICON_PROPS = {\n borderRadius: 12,\n padding: 8,\n initialColor: 'secondary',\n} as const;\n\ninterface ChatInputComponents {\n Chips: typeof ChatInputChips;\n File: typeof ChatInputFile;\n Files: typeof ChatInputFiles;\n Preview: typeof ChatInputPreview;\n SendButton: typeof ChatInputSendButton;\n VoiceButton: typeof ChatInputVoiceButton;\n}\n\ntype ChatInputInnerProps = ChatInputProps & {\n /** Реф на textarea, переданный через forwardRef внешней обёртки */\n textareaRef: ForwardedRef<HTMLTextAreaElement>;\n};\n\nconst ChatInputInner: FC<ChatInputInnerProps> = ({\n leftActions,\n rightActions,\n centralActions,\n preview,\n maxHeight,\n layout = 'horizontal',\n onSend,\n wrapperRef,\n textareaRef,\n noBackground = false,\n disabled = false,\n 'data-qa': dataQa = 'chat-input',\n ...textareaProps\n}) => {\n const outerDisabled = useDisabled();\n const isDisabled = disabled || outerDisabled;\n const rootRef = useRef<HTMLDivElement>(null);\n const rootRefCallback = useMultipleRefs(rootRef, wrapperRef);\n // реф textarea — для возврата фокуса при выходе из режима записи\n const textareaLocalRef = useRef<HTMLTextAreaElement>(null);\n const textareaRefCallback = useMultipleRefs(textareaLocalRef, textareaRef);\n const [containerWidth, setContainerWidth] = useState<number>();\n useLayoutEffect(() => {\n const root = rootRef.current;\n if (!root) {\n return undefined;\n }\n const observer = new ResizeObserver((entries) => {\n const width = Math.round(entries[0]?.contentRect.width ?? 0);\n setContainerWidth((prev) => (prev === width ? prev : width));\n });\n observer.observe(root);\n return () => observer.disconnect();\n }, []);\n\n // конфиг записи регистрирует ChatInput.VoiceButton через slot-registry. Кнопка живёт в\n // text-гриде, который на время записи не размонтируется (ModeTransition лишь прячет его), —\n // поэтому регистрация и колбэки остаются живыми всю сессию, латч не нужен\n const voiceConfig = useVoiceConfig();\n\n const voiceSession = useVoiceRecordSession(voiceConfig ?? {});\n\n const contextValue = useMemo(\n () => ({\n onSend,\n startVoiceRecord: voiceSession.start,\n voiceRecordStatus: voiceSession.status,\n }),\n [onSend, voiceSession.start, voiceSession.status]\n );\n\n // режим ведём по статусу сессии, а не по наличию конфига: даже если приложение уберёт кнопку\n // по ходу записи, запись продолжается. Без кнопки запись не стартует, так что статус сам остаётся idle\n const isVoiceMode = voiceSession.status === 'recording' || voiceSession.status === 'processing';\n\n // roving-группа кнопок: один tab stop на все кнопки, внутри — стрелки по приоритетам\n const { focusStop } = useRovingFocusGroup(rootRef);\n\n // при входе в запись фокус на стоп группы (после смены слоя это галочка — первый приоритет\n // слоя записи), при возврате в текст — в textarea с курсором в конце. Фокус ставим в rAF:\n // слой режима к этому моменту уже видим (motion применил visibility), иначе focus()\n // на visibility:hidden не сработает\n const prevVoiceModeRef = useRef(isVoiceMode);\n useEffect(() => {\n const wasVoiceMode = prevVoiceModeRef.current;\n prevVoiceModeRef.current = isVoiceMode;\n if (wasVoiceMode === isVoiceMode) {\n return undefined;\n }\n const frameId = requestAnimationFrame(() => {\n if (isVoiceMode) {\n focusStop();\n return;\n }\n const textarea = textareaLocalRef.current;\n if (textarea) {\n textarea.focus();\n const caret = textarea.value.length;\n textarea.setSelectionRange(caret, caret);\n }\n });\n return () => cancelAnimationFrame(frameId);\n }, [isVoiceMode, focusStop]);\n\n return (\n <DisabledContext.Provider value={isDisabled}>\n <ChatInputContextProvider value={contextValue}>\n <div\n ref={rootRefCallback}\n className={classNames(styles.chatInput, { [styles.noBackground]: noBackground })}\n data-qa={dataQa}\n >\n <ModeTransition\n mode={isVoiceMode ? 'voice' : 'text'}\n voice={\n <VoiceRecord\n mode={voiceSession.status === 'processing' ? 'processing' : 'recording'}\n stream={voiceSession.stream}\n startedAt={voiceSession.startedAt}\n processingLabel={voiceConfig?.processingLabel}\n onComplete={voiceSession.stop}\n onCancel={voiceSession.cancel}\n completeButtonProps={voiceConfig?.completeButtonProps}\n cancelButtonProps={voiceConfig?.cancelButtonProps}\n data-qa=\"chat-input-voice-record\"\n />\n }\n text={\n <div\n className={classNames(styles.contentGrid, {\n [styles.noLeftControls]: !leftActions,\n [styles.noRightControls]: !rightActions,\n [styles.hasCentral]: !!centralActions,\n })}\n >\n {/* textarea в DOM первым намеренно: Tab снаружи входит сначала в него.\n Раскладку держит grid-area (от порядка не зависит). Кнопки слотов —\n одна roving-группа (useRovingFocusGroup): Tab видит только текущий\n стоп, внутри группы фокус ходит стрелками по приоритетам слотов */}\n <TextInput\n {...textareaProps}\n ref={textareaRefCallback}\n layout={layout}\n onSend={onSend}\n maxHeight={maxHeight}\n containerWidth={containerWidth}\n hasCentral={!!centralActions}\n disabled={isDisabled}\n hasBothSideControls={!!leftActions && !!rightActions}\n />\n {!!rightActions && (\n <IconDefaultPropsContext props={DEFAULT_ICON_PROPS}>\n <div className={styles.right} {...focusPriorityProps(FOCUS_PRIORITY.rightSlot)}>\n {rightActions}\n </div>\n </IconDefaultPropsContext>\n )}\n {!!leftActions && (\n <IconDefaultPropsContext props={DEFAULT_ICON_PROPS}>\n <div className={styles.left} {...focusPriorityProps(FOCUS_PRIORITY.leftSlot)}>\n {leftActions}\n </div>\n </IconDefaultPropsContext>\n )}\n {!!centralActions && (\n <div className={styles.central} {...focusPriorityProps(FOCUS_PRIORITY.centralSlot)}>\n {centralActions}\n </div>\n )}\n {!!preview && (\n <div className={styles.preview} {...focusPriorityProps(FOCUS_PRIORITY.previewSlot)}>\n {preview}\n </div>\n )}\n </div>\n }\n />\n </div>\n </ChatInputContextProvider>\n </DisabledContext.Provider>\n );\n};\n\n// внешняя обёртка держит slot-registry для конфига записи: кнопка (внутри слота) регистрирует\n// конфиг, ChatInputInner (ниже провайдера) читает его. forwardRef-реф на textarea прокидываем\n// вниз обычным пропом\nconst ChatInputComponent = (props: ChatInputProps, ref: ForwardedRef<HTMLTextAreaElement>) => (\n <ChatInputVoiceSlotProvider>\n <ChatInputInner {...props} textareaRef={ref} />\n </ChatInputVoiceSlotProvider>\n);\n\nconst ChatInput = forwardRef(ChatInputComponent) as ForwardRefExoticComponent<\n ChatInputProps & RefAttributes<HTMLTextAreaElement>\n> &\n ChatInputComponents;\n\nChatInput.displayName = 'ChatInput';\n\nChatInput.Chips = ChatInputChips;\nChatInput.File = ChatInputFile;\nChatInput.Files = ChatInputFiles;\nChatInput.Preview = ChatInputPreview;\nChatInput.SendButton = ChatInputSendButton;\nChatInput.VoiceButton = ChatInputVoiceButton;\n\nexport { ChatInput };\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
@@ -1,14 +1,12 @@
1
1
  import './../index.css';
2
2
  import { jsx } from 'react/jsx-runtime';
3
- import { isValidElement, Children, Fragment } from 'react';
3
+ import { isValidElement } from 'react';
4
+ import { flattenFragments } from '../internal/flattenFragments.js';
4
5
  import { ChipDefaultPropsContext } from '@hh.ru/magritte-ui-chips';
5
6
  import { ScrollableContainer } from '@hh.ru/magritte-ui-scrollable-container';
6
- import { s as styles } from '../styles-x_6MfT-u.js';
7
+ import { s as styles } from '../styles-BHWYKmPT.js';
7
8
 
8
9
  const CHIP_DEFAULT_PROPS = { size: 'extra-small' };
9
- const flattenFragments = (children) => Children.toArray(children).flatMap((child) => isValidElement(child) && child.type === Fragment
10
- ? flattenFragments(child.props.children)
11
- : child);
12
10
  const ChatInputChips = ({ children }) => (jsx("div", { className: styles.chipsContainer, children: jsx(ChipDefaultPropsContext, { props: CHIP_DEFAULT_PROPS, children: jsx(ScrollableContainer, { children: jsx(ScrollableContainer.DefaultLayout, { size: "small", fadeOnMobile: true, children: jsx(ScrollableContainer.Gallery, { children: jsx("div", { className: styles.chips, children: flattenFragments(children).map((child, index) => (jsx(ScrollableContainer.Item, { children: child }, (isValidElement(child) && child.key) || index))) }) }) }) }) }) }));
13
11
  ChatInputChips.displayName = 'ChatInputChips';
14
12
 
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInputChips.js","sources":["src/public/ChatInputChips.tsx"],"sourcesContent":["import { Children, Fragment, isValidElement, type FC, type PropsWithChildren, type ReactNode } from 'react';\n\nimport { ChipDefaultPropsContext } from '@hh.ru/magritte-ui-chips';\nimport { ScrollableContainer } from '@hh.ru/magritte-ui-scrollable-container';\n\nimport styles from '../styles.less';\n\nexport interface ChatInputChipsProps {\n /** Чипсы, размещаются в один ряд с возможностью горизонтального скролла */\n children: ReactNode;\n}\n\nconst CHIP_DEFAULT_PROPS = { size: 'extra-small' } as const;\n\nconst flattenFragments = (children: ReactNode): ReactNode[] =>\n Children.toArray(children).flatMap((child) =>\n isValidElement(child) && child.type === Fragment\n ? flattenFragments((child.props as PropsWithChildren).children)\n : child\n );\n\nexport const ChatInputChips: FC<ChatInputChipsProps> = ({ children }) => (\n <div className={styles.chipsContainer}>\n <ChipDefaultPropsContext props={CHIP_DEFAULT_PROPS}>\n <ScrollableContainer>\n <ScrollableContainer.DefaultLayout size=\"small\" fadeOnMobile>\n <ScrollableContainer.Gallery>\n <div className={styles.chips}>\n {/* Children.toArray сохраняет ключи детей — переносим их на обёртку,\n чтобы удаление чипса из середины не сдвигало стейт соседей */}\n {flattenFragments(children).map((child, index) => (\n <ScrollableContainer.Item key={(isValidElement(child) && child.key) || index}>\n {child}\n </ScrollableContainer.Item>\n ))}\n </div>\n </ScrollableContainer.Gallery>\n </ScrollableContainer.DefaultLayout>\n </ScrollableContainer>\n </ChipDefaultPropsContext>\n </div>\n);\n\nChatInputChips.displayName = 'ChatInputChips';\n"],"names":["_jsx"],"mappings":";;;;;;AAYA,MAAM,kBAAkB,GAAG,EAAE,IAAI,EAAE,aAAa,EAAW,CAAC;AAE5D,MAAM,gBAAgB,GAAG,CAAC,QAAmB,KACzC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,KACrC,cAAc,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;MAC1C,gBAAgB,CAAE,KAAK,CAAC,KAA2B,CAAC,QAAQ,CAAC;MAC7D,KAAK,CACd,CAAC;MAEO,cAAc,GAA4B,CAAC,EAAE,QAAQ,EAAE,MAChEA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,cAAc,EAAA,QAAA,EACjCA,GAAC,CAAA,uBAAuB,EAAC,EAAA,KAAK,EAAE,kBAAkB,EAAA,QAAA,EAC9CA,IAAC,mBAAmB,EAAA,EAAA,QAAA,EAChBA,IAAC,mBAAmB,CAAC,aAAa,EAAC,EAAA,IAAI,EAAC,OAAO,EAAC,YAAY,EACxD,IAAA,EAAA,QAAA,EAAAA,GAAA,CAAC,mBAAmB,CAAC,OAAO,EACxB,EAAA,QAAA,EAAAA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,KAAK,YAGvB,gBAAgB,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,MACzCA,GAAC,CAAA,mBAAmB,CAAC,IAAI,EACpB,EAAA,QAAA,EAAA,KAAK,IADqB,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,CAEjD,CAC9B,CAAC,EACA,CAAA,EAAA,CACoB,GACE,EAClB,CAAA,EAAA,CACA,EACxB,CAAA,EACR;AAEF,cAAc,CAAC,WAAW,GAAG,gBAAgB;;;;"}
1
+ {"version":3,"file":"ChatInputChips.js","sources":["src/public/ChatInputChips.tsx"],"sourcesContent":["import { isValidElement, type FC, type ReactNode } from 'react';\n\nimport { flattenFragments } from '@hh.ru/magritte-ui-chat-input/internal/flattenFragments';\nimport { ChipDefaultPropsContext } from '@hh.ru/magritte-ui-chips';\nimport { ScrollableContainer } from '@hh.ru/magritte-ui-scrollable-container';\n\nimport styles from '../styles.less';\n\nexport interface ChatInputChipsProps {\n /** Чипсы, размещаются в один ряд с возможностью горизонтального скролла */\n children: ReactNode;\n}\n\nconst CHIP_DEFAULT_PROPS = { size: 'extra-small' } as const;\n\nexport const ChatInputChips: FC<ChatInputChipsProps> = ({ children }) => (\n <div className={styles.chipsContainer}>\n <ChipDefaultPropsContext props={CHIP_DEFAULT_PROPS}>\n <ScrollableContainer>\n <ScrollableContainer.DefaultLayout size=\"small\" fadeOnMobile>\n <ScrollableContainer.Gallery>\n <div className={styles.chips}>\n {/* Children.toArray сохраняет ключи детей — переносим их на обёртку,\n чтобы удаление чипса из середины не сдвигало стейт соседей */}\n {flattenFragments(children).map((child, index) => (\n <ScrollableContainer.Item key={(isValidElement(child) && child.key) || index}>\n {child}\n </ScrollableContainer.Item>\n ))}\n </div>\n </ScrollableContainer.Gallery>\n </ScrollableContainer.DefaultLayout>\n </ScrollableContainer>\n </ChipDefaultPropsContext>\n </div>\n);\n\nChatInputChips.displayName = 'ChatInputChips';\n"],"names":["_jsx"],"mappings":";;;;;;;AAaA,MAAM,kBAAkB,GAAG,EAAE,IAAI,EAAE,aAAa,EAAW,CAAC;MAE/C,cAAc,GAA4B,CAAC,EAAE,QAAQ,EAAE,MAChEA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,cAAc,EAAA,QAAA,EACjCA,GAAC,CAAA,uBAAuB,EAAC,EAAA,KAAK,EAAE,kBAAkB,EAAA,QAAA,EAC9CA,IAAC,mBAAmB,EAAA,EAAA,QAAA,EAChBA,IAAC,mBAAmB,CAAC,aAAa,EAAC,EAAA,IAAI,EAAC,OAAO,EAAC,YAAY,EACxD,IAAA,EAAA,QAAA,EAAAA,GAAA,CAAC,mBAAmB,CAAC,OAAO,EACxB,EAAA,QAAA,EAAAA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,KAAK,YAGvB,gBAAgB,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,MACzCA,GAAC,CAAA,mBAAmB,CAAC,IAAI,EACpB,EAAA,QAAA,EAAA,KAAK,IADqB,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,CAEjD,CAC9B,CAAC,EACA,CAAA,EAAA,CACoB,GACE,EAClB,CAAA,EAAA,CACA,EACxB,CAAA,EACR;AAEF,cAAc,CAAC,WAAW,GAAG,gBAAgB;;;;"}
@@ -0,0 +1,43 @@
1
+ import { type HTMLAttributes, type MouseEventHandler, type ReactNode } from 'react';
2
+ import { type ChatInputButtonAria } from '@hh.ru/magritte-ui-chat-input/types';
3
+ export type ChatInputFileState = 'loading' | 'loaded' | 'invalid';
4
+ export type ChatInputFileType = 'doc' | 'video' | 'image';
5
+ export interface ChatInputFileProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'className'> {
6
+ /** Имя файла. Если передана строка, при нехватке места обрезается основа имени, а расширение
7
+ * остаётся видимым целиком */
8
+ name?: ReactNode;
9
+ /**
10
+ * Строка под именем (например, для размера файла или текста ошибки).
11
+ * Для `type="image"` не отображается
12
+ */
13
+ description?: ReactNode;
14
+ /**
15
+ * Состояние файла
16
+ * @default loaded
17
+ */
18
+ state?: ChatInputFileState;
19
+ /**
20
+ * Тип файла: `doc` и `video` — карточка с иконкой и именем, `image` — квадратное превью
21
+ * @default doc
22
+ */
23
+ type?: ChatInputFileType;
24
+ /**
25
+ * Превью, показывается для `type="image"` в состоянии `loaded`: url картинки или сам файл (`File`/`Blob`).
26
+ * Для файла компонент локально создаёт object URL и сам его отзывает — загружать файл на сервер
27
+ * ради превью не нужно
28
+ */
29
+ preview?: string | Blob;
30
+ /** Alt превью. По умолчанию — имя файла, если оно строка */
31
+ previewAlt?: string;
32
+ /** Обработчик удаления файла. Без него кнопка удаления файла не показывается */
33
+ onRemove?: MouseEventHandler<HTMLButtonElement>;
34
+ /** aria/data-qa пропсы кнопки удаления файла. Своя `aria-label` перекрывает дефолтную */
35
+ removeButtonProps?: ChatInputButtonAria;
36
+ /**
37
+ * Значение data-qa
38
+ * @default chat-input-file
39
+ */
40
+ 'data-qa'?: string;
41
+ }
42
+ /** Приложенный к сообщению файл */
43
+ export declare const ChatInputFile: import("react").ForwardRefExoticComponent<ChatInputFileProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,74 @@
1
+ import './../index.css';
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import { forwardRef, useState } from 'react';
4
+ import classNames from 'classnames';
5
+ import { useTranslation } from '@hh.ru/magritte-common-use-translation';
6
+ import { Cell, CellText } from '@hh.ru/magritte-ui-cell';
7
+ import { useObjectUrl } from '../internal/useObjectUrl.js';
8
+ import { CheckCircleOutlinedSize16, ExclamationTriangleOutlinedSize16, ImageOutlinedSize24, CrossOutlinedSize16, VideocameraOutlinedSize24, DocumentOutlinedSize24 } from '@hh.ru/magritte-ui-icon/icon';
9
+ import { LinkDefaultPropsContext } from '@hh.ru/magritte-ui-link';
10
+ import { Loader } from '@hh.ru/magritte-ui-loader';
11
+ import { TextDefaultPropsContext } from '@hh.ru/magritte-ui-typography';
12
+ import { s as styles } from '../styles-BHWYKmPT.js';
13
+
14
+ const splitFileName = (name) => {
15
+ const dotIndex = name.lastIndexOf('.');
16
+ // точка в начале (.gitignore) или в конце (file.) — расширения нет, имя целиком
17
+ if (dotIndex <= 0 || dotIndex === name.length - 1) {
18
+ return { base: name, extension: '' };
19
+ }
20
+ return { base: name.slice(0, dotIndex), extension: name.slice(dotIndex) };
21
+ };
22
+ const FileName = ({ name }) => {
23
+ if (typeof name !== 'string') {
24
+ return jsx(Fragment, { children: name });
25
+ }
26
+ const { base, extension } = splitFileName(name);
27
+ // основа сжимается с многоточием, расширение не сжимается; типографику даёт CellText.
28
+ // имя без расширения обрезается так же, целиком
29
+ return (jsxs("span", { className: styles.fileName, children: [jsx("span", { className: styles.fileNameBase, children: base }), extension && jsx("span", { className: styles.fileNameExtension, children: extension })] }));
30
+ };
31
+ const STATUS_ICON = {
32
+ loading: jsx(Loader, { size: 16 }),
33
+ loaded: jsx(CheckCircleOutlinedSize16, { initialColor: "positive" }),
34
+ invalid: jsx(ExclamationTriangleOutlinedSize16, { initialColor: "negative" }),
35
+ };
36
+ const LINK_DEFAULT_PROPS = { typography: 'label-3-regular', inline: true };
37
+ // строку оформляет CellText, а Text, переданный пользователем в name/description, получает те же дефолты.
38
+ // ellipsis — для Text: блочный элемент не обрезается text-overflow родителя
39
+ const NAME_TEXT_PROPS = { typography: 'label-3-regular', style: 'primary', ellipsis: true };
40
+ const DESCRIPTION_TEXT_PROPS = { typography: 'label-3-regular', style: 'secondary', ellipsis: true };
41
+ /** Приложенный к сообщению файл */
42
+ const ChatInputFile = forwardRef(({ 'data-qa': dataQa = 'chat-input-file', description, name, onRemove, preview, previewAlt, removeButtonProps, state = 'loaded', type = 'doc', ...props }, ref) => {
43
+ const removeLabel = useTranslation('ChatInput', 'removeFile');
44
+ const isImage = type === 'image';
45
+ // object URL создаём только для плитки картинки — карточкам он не нужен
46
+ const previewSrc = useObjectUrl(isImage ? preview : undefined);
47
+ // битая картинка — показываем заглушку; сбрасывается сменой src или уходом из loaded,
48
+ // чтобы тот же url (например, ещё не готовое серверное превью) загрузился повторно
49
+ const [failedSrc, setFailedSrc] = useState();
50
+ if (state !== 'loaded' && failedSrc !== undefined) {
51
+ setFailedSrc(undefined);
52
+ }
53
+ let content;
54
+ if (isImage) {
55
+ const showPreview = state === 'loaded' && !!previewSrc && previewSrc !== failedSrc;
56
+ let placeholder = null;
57
+ if (state === 'loading') {
58
+ placeholder = jsx(Loader, { size: 24 });
59
+ }
60
+ else if (!showPreview) {
61
+ placeholder = jsx(ImageOutlinedSize24, { initialColor: "tertiary" });
62
+ }
63
+ content = (jsx("div", { className: classNames(styles.fileTile, { [styles.fileTilePlaceholder]: !showPreview }), children: showPreview ? (jsx("img", { className: styles.fileTileImage, src: previewSrc, alt: previewAlt ?? (typeof name === 'string' ? name : ''), onError: () => setFailedSrc(previewSrc) })) : (placeholder) }));
64
+ }
65
+ else {
66
+ const Icon = type === 'video' ? VideocameraOutlinedSize24 : DocumentOutlinedSize24;
67
+ content = (jsx("div", { className: classNames(styles.fileCard, { [styles.fileCardRemovable]: !!onRemove }), children: jsxs(Cell, { align: "center", horPadding: false, vertPadding: false, left: jsx(Icon, { initialColor: "secondary", backgroundStyle: "secondary", padding: 12, borderRadius: 8 }), children: [!!name && (jsx(CellText, { type: "title", typography: "label-3-regular", style: "primary", maxLines: 1, "data-qa": "chat-input-file-name", children: jsx(TextDefaultPropsContext, { props: NAME_TEXT_PROPS, children: jsx(FileName, { name: name }) }) })), !!description && (jsx(CellText, { type: "subtitle", style: "secondary", maxLines: 1, left: STATUS_ICON[state], "data-qa": "chat-input-file-description", children: jsx(TextDefaultPropsContext, { props: DESCRIPTION_TEXT_PROPS, children: jsx(LinkDefaultPropsContext, { props: LINK_DEFAULT_PROPS, children: description }) }) }))] }) }));
68
+ }
69
+ return (jsxs("div", { ...props, className: styles.file, "data-qa": dataQa, ref: ref, children: [content, onRemove && (jsx("span", { className: styles.fileRemove, children: jsx(CrossOutlinedSize16, { "data-qa": "chat-input-file-remove", ...removeButtonProps, "aria-label": removeButtonProps?.['aria-label'] ?? removeLabel, initialColor: "primary", backgroundStyle: "secondary", borderRadius: 8, padding: 2, onClick: onRemove }) }))] }));
70
+ });
71
+ ChatInputFile.displayName = 'ChatInputFile';
72
+
73
+ export { ChatInputFile };
74
+ //# sourceMappingURL=ChatInputFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatInputFile.js","sources":["src/public/ChatInputFile.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes, type MouseEventHandler, type ReactNode, useState } from 'react';\nimport classNames from 'classnames';\n\nimport { useTranslation } from '@hh.ru/magritte-common-use-translation';\nimport { Cell, CellText } from '@hh.ru/magritte-ui-cell';\nimport { useObjectUrl } from '@hh.ru/magritte-ui-chat-input/internal/useObjectUrl';\nimport { type ChatInputButtonAria } from '@hh.ru/magritte-ui-chat-input/types';\nimport {\n CheckCircleOutlinedSize16,\n CrossOutlinedSize16,\n DocumentOutlinedSize24,\n ExclamationTriangleOutlinedSize16,\n ImageOutlinedSize24,\n VideocameraOutlinedSize24,\n} from '@hh.ru/magritte-ui-icon/icon';\nimport { LinkDefaultPropsContext } from '@hh.ru/magritte-ui-link';\nimport { Loader } from '@hh.ru/magritte-ui-loader';\nimport { TextDefaultPropsContext } from '@hh.ru/magritte-ui-typography';\n\nimport styles from '../styles.less';\n\nexport type ChatInputFileState = 'loading' | 'loaded' | 'invalid';\n\nexport type ChatInputFileType = 'doc' | 'video' | 'image';\n\nexport interface ChatInputFileProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'className'> {\n /** Имя файла. Если передана строка, при нехватке места обрезается основа имени, а расширение\n * остаётся видимым целиком */\n name?: ReactNode;\n /**\n * Строка под именем (например, для размера файла или текста ошибки).\n * Для `type=\"image\"` не отображается\n */\n description?: ReactNode;\n /**\n * Состояние файла\n * @default loaded\n */\n state?: ChatInputFileState;\n /**\n * Тип файла: `doc` и `video` — карточка с иконкой и именем, `image` — квадратное превью\n * @default doc\n */\n type?: ChatInputFileType;\n /**\n * Превью, показывается для `type=\"image\"` в состоянии `loaded`: url картинки или сам файл (`File`/`Blob`).\n * Для файла компонент локально создаёт object URL и сам его отзывает — загружать файл на сервер\n * ради превью не нужно\n */\n preview?: string | Blob;\n /** Alt превью. По умолчанию — имя файла, если оно строка */\n previewAlt?: string;\n /** Обработчик удаления файла. Без него кнопка удаления файла не показывается */\n onRemove?: MouseEventHandler<HTMLButtonElement>;\n /** aria/data-qa пропсы кнопки удаления файла. Своя `aria-label` перекрывает дефолтную */\n removeButtonProps?: ChatInputButtonAria;\n /**\n * Значение data-qa\n * @default chat-input-file\n */\n 'data-qa'?: string;\n}\n\nconst splitFileName = (name: string): { base: string; extension: string } => {\n const dotIndex = name.lastIndexOf('.');\n // точка в начале (.gitignore) или в конце (file.) — расширения нет, имя целиком\n if (dotIndex <= 0 || dotIndex === name.length - 1) {\n return { base: name, extension: '' };\n }\n return { base: name.slice(0, dotIndex), extension: name.slice(dotIndex) };\n};\n\nconst FileName = ({ name }: { name: ReactNode }) => {\n if (typeof name !== 'string') {\n return <>{name}</>;\n }\n const { base, extension } = splitFileName(name);\n // основа сжимается с многоточием, расширение не сжимается; типографику даёт CellText.\n // имя без расширения обрезается так же, целиком\n return (\n <span className={styles.fileName}>\n <span className={styles.fileNameBase}>{base}</span>\n {extension && <span className={styles.fileNameExtension}>{extension}</span>}\n </span>\n );\n};\n\nconst STATUS_ICON: Record<ChatInputFileState, ReactNode> = {\n loading: <Loader size={16} />,\n loaded: <CheckCircleOutlinedSize16 initialColor=\"positive\" />,\n invalid: <ExclamationTriangleOutlinedSize16 initialColor=\"negative\" />,\n};\n\nconst LINK_DEFAULT_PROPS = { typography: 'label-3-regular', inline: true } as const;\n\n// строку оформляет CellText, а Text, переданный пользователем в name/description, получает те же дефолты.\n// ellipsis — для Text: блочный элемент не обрезается text-overflow родителя\nconst NAME_TEXT_PROPS = { typography: 'label-3-regular', style: 'primary', ellipsis: true } as const;\nconst DESCRIPTION_TEXT_PROPS = { typography: 'label-3-regular', style: 'secondary', ellipsis: true } as const;\n\n/** Приложенный к сообщению файл */\nexport const ChatInputFile = forwardRef<HTMLDivElement, ChatInputFileProps>(\n (\n {\n 'data-qa': dataQa = 'chat-input-file',\n description,\n name,\n onRemove,\n preview,\n previewAlt,\n removeButtonProps,\n state = 'loaded',\n type = 'doc',\n ...props\n },\n ref\n ) => {\n const removeLabel = useTranslation('ChatInput', 'removeFile');\n const isImage = type === 'image';\n // object URL создаём только для плитки картинки — карточкам он не нужен\n const previewSrc = useObjectUrl(isImage ? preview : undefined);\n // битая картинка — показываем заглушку; сбрасывается сменой src или уходом из loaded,\n // чтобы тот же url (например, ещё не готовое серверное превью) загрузился повторно\n const [failedSrc, setFailedSrc] = useState<string>();\n if (state !== 'loaded' && failedSrc !== undefined) {\n setFailedSrc(undefined);\n }\n\n let content: ReactNode;\n if (isImage) {\n const showPreview = state === 'loaded' && !!previewSrc && previewSrc !== failedSrc;\n let placeholder: ReactNode = null;\n if (state === 'loading') {\n placeholder = <Loader size={24} />;\n } else if (!showPreview) {\n placeholder = <ImageOutlinedSize24 initialColor=\"tertiary\" />;\n }\n content = (\n <div className={classNames(styles.fileTile, { [styles.fileTilePlaceholder]: !showPreview })}>\n {showPreview ? (\n <img\n className={styles.fileTileImage}\n src={previewSrc}\n alt={previewAlt ?? (typeof name === 'string' ? name : '')}\n onError={() => setFailedSrc(previewSrc)}\n />\n ) : (\n placeholder\n )}\n </div>\n );\n } else {\n const Icon = type === 'video' ? VideocameraOutlinedSize24 : DocumentOutlinedSize24;\n content = (\n <div className={classNames(styles.fileCard, { [styles.fileCardRemovable]: !!onRemove })}>\n <Cell\n align=\"center\"\n horPadding={false}\n vertPadding={false}\n left={\n <Icon initialColor=\"secondary\" backgroundStyle=\"secondary\" padding={12} borderRadius={8} />\n }\n >\n {!!name && (\n <CellText\n type=\"title\"\n typography=\"label-3-regular\"\n style=\"primary\"\n maxLines={1}\n data-qa=\"chat-input-file-name\"\n >\n <TextDefaultPropsContext props={NAME_TEXT_PROPS}>\n <FileName name={name} />\n </TextDefaultPropsContext>\n </CellText>\n )}\n {!!description && (\n <CellText\n type=\"subtitle\"\n style=\"secondary\"\n maxLines={1}\n left={STATUS_ICON[state]}\n data-qa=\"chat-input-file-description\"\n >\n <TextDefaultPropsContext props={DESCRIPTION_TEXT_PROPS}>\n <LinkDefaultPropsContext props={LINK_DEFAULT_PROPS}>\n {description}\n </LinkDefaultPropsContext>\n </TextDefaultPropsContext>\n </CellText>\n )}\n </Cell>\n </div>\n );\n }\n\n return (\n <div {...props} className={styles.file} data-qa={dataQa} ref={ref}>\n {content}\n {onRemove && (\n <span className={styles.fileRemove}>\n <CrossOutlinedSize16\n data-qa=\"chat-input-file-remove\"\n {...removeButtonProps}\n aria-label={removeButtonProps?.['aria-label'] ?? removeLabel}\n initialColor=\"primary\"\n backgroundStyle=\"secondary\"\n borderRadius={8}\n padding={2}\n onClick={onRemove}\n />\n </span>\n )}\n </div>\n );\n }\n);\n\nChatInputFile.displayName = 'ChatInputFile';\n"],"names":["_jsx","_Fragment","_jsxs"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type FC, type ReactNode } from 'react';
2
+ export interface ChatInputFilesProps {
3
+ /** Файлы (`ChatInput.File`), размещаются в один ряд с возможностью горизонтального скролла */
4
+ children: ReactNode;
5
+ }
6
+ export declare const ChatInputFiles: FC<ChatInputFilesProps>;
@@ -0,0 +1,12 @@
1
+ import './../index.css';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { isValidElement } from 'react';
4
+ import { flattenFragments } from '../internal/flattenFragments.js';
5
+ import { ScrollableContainer } from '@hh.ru/magritte-ui-scrollable-container';
6
+ import { s as styles } from '../styles-BHWYKmPT.js';
7
+
8
+ const ChatInputFiles = ({ children }) => (jsx("div", { className: styles.filesContainer, "data-qa": "chat-input-files", children: jsx(ScrollableContainer, { correction: 11, children: jsx(ScrollableContainer.DefaultLayout, { size: "small", noFadeOnDesktop: true, buttonsOffset: 8, buttonsOnHover: true, children: jsx(ScrollableContainer.Gallery, { children: jsx("div", { className: styles.files, children: flattenFragments(children).map((child, index) => (jsx(ScrollableContainer.Item, { scrollToItemOnFocus: true, children: child }, (isValidElement(child) && child.key) || index))) }) }) }) }) }));
9
+ ChatInputFiles.displayName = 'ChatInputFiles';
10
+
11
+ export { ChatInputFiles };
12
+ //# sourceMappingURL=ChatInputFiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatInputFiles.js","sources":["src/public/ChatInputFiles.tsx"],"sourcesContent":["import { isValidElement, type FC, type ReactNode } from 'react';\n\nimport { flattenFragments } from '@hh.ru/magritte-ui-chat-input/internal/flattenFragments';\nimport { ScrollableContainer } from '@hh.ru/magritte-ui-scrollable-container';\n\nimport styles from '../styles.less';\n\nexport interface ChatInputFilesProps {\n /** Файлы (`ChatInput.File`), размещаются в один ряд с возможностью горизонтального скролла */\n children: ReactNode;\n}\n\nexport const ChatInputFiles: FC<ChatInputFilesProps> = ({ children }) => (\n <div className={styles.filesContainer} data-qa=\"chat-input-files\">\n {/* область прокрутки выходит за паддинг ChatInput (12px) до его обводки (1px), чтобы файлы\n обрезались краем компонента, но не перекрывали обводку; в крайних положениях контент отступает\n от краёв на те же 12px */}\n <ScrollableContainer correction={11}>\n {/* в макете у ряда файлов нет краевых фейдов: на десктопе оставляем только кнопки листания,\n на мобильных фейды и так выключены по умолчанию. Кнопки — на 8px внутрь от края ряда\n (20px от края ChatInput) и появляются только при наведении на ряд */}\n <ScrollableContainer.DefaultLayout size=\"small\" noFadeOnDesktop buttonsOffset={8} buttonsOnHover>\n <ScrollableContainer.Gallery>\n <div className={styles.files}>\n {/* ключи детей переносим на обёртку, чтобы удаление файла из середины\n не сдвигало стейт соседей; при фокусе внутри файла (крестик, с клавиатуры)\n подскролливаем к нему */}\n {flattenFragments(children).map((child, index) => (\n <ScrollableContainer.Item\n key={(isValidElement(child) && child.key) || index}\n scrollToItemOnFocus\n >\n {child}\n </ScrollableContainer.Item>\n ))}\n </div>\n </ScrollableContainer.Gallery>\n </ScrollableContainer.DefaultLayout>\n </ScrollableContainer>\n </div>\n);\n\nChatInputFiles.displayName = 'ChatInputFiles';\n"],"names":["_jsx"],"mappings":";;;;;;MAYa,cAAc,GAA4B,CAAC,EAAE,QAAQ,EAAE,MAChEA,GAAK,CAAA,KAAA,EAAA,EAAA,SAAS,EAAE,MAAM,CAAC,cAAc,EAAU,SAAA,EAAA,kBAAkB,EAI7D,QAAA,EAAAA,GAAA,CAAC,mBAAmB,EAAA,EAAC,UAAU,EAAE,EAAE,YAI/BA,GAAC,CAAA,mBAAmB,CAAC,aAAa,EAAA,EAAC,IAAI,EAAC,OAAO,EAAC,eAAe,EAAC,IAAA,EAAA,aAAa,EAAE,CAAC,EAAE,cAAc,kBAC5FA,GAAC,CAAA,mBAAmB,CAAC,OAAO,EACxB,EAAA,QAAA,EAAAA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,KAAK,EAAA,QAAA,EAIvB,gBAAgB,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,MACzCA,GAAA,CAAC,mBAAmB,CAAC,IAAI,EAAA,EAErB,mBAAmB,EAElB,IAAA,EAAA,QAAA,EAAA,KAAK,IAHD,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,CAI3B,CAC9B,CAAC,EAAA,CACA,GACoB,EACE,CAAA,EAAA,CAClB,EACpB,CAAA,EACR;AAEF,cAAc,CAAC,WAAW,GAAG,gBAAgB;;;;"}
@@ -1,13 +1,18 @@
1
1
  import './../index.css';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
3
  import { IconDefaultPropsContext } from '@hh.ru/magritte-ui-icon';
4
- import { s as styles } from '../styles-x_6MfT-u.js';
4
+ import { TextDefaultPropsContext } from '@hh.ru/magritte-ui-typography';
5
+ import { s as styles } from '../styles-BHWYKmPT.js';
5
6
 
6
7
  const DEFAULT_ICON_PROPS = {
7
8
  initialColor: 'secondary',
8
9
  padding: 8,
9
10
  };
10
- const ChatInputPreview = ({ title, subtitle, leftActions, rightActions }) => (jsx(IconDefaultPropsContext, { props: DEFAULT_ICON_PROPS, children: jsxs("div", { className: styles.previewBlock, children: [!!leftActions && jsx("div", { className: styles.previewSide, children: leftActions }), jsxs("div", { className: styles.previewContent, children: [!!title && jsx("div", { className: styles.previewTitle, children: title }), !!subtitle && jsx("div", { className: styles.previewSubtitle, children: subtitle })] }), !!rightActions && jsx("div", { className: styles.previewSide, children: rightActions })] }) }));
11
+ // строку оформляют стили слота, а Text, переданный пользователем в title/subtitle, получает те же дефолты.
12
+ // ellipsis — для Text: блочный элемент не обрезается text-overflow родителя
13
+ const TITLE_TEXT_PROPS = { typography: 'subtitle-3-semibold', style: 'primary' };
14
+ const SUBTITLE_TEXT_PROPS = { typography: 'label-3-regular', style: 'secondary', ellipsis: true };
15
+ const ChatInputPreview = ({ title, subtitle, leftActions, rightActions }) => (jsx(IconDefaultPropsContext, { props: DEFAULT_ICON_PROPS, children: jsxs("div", { className: styles.previewBlock, children: [!!leftActions && jsx("div", { className: styles.previewSide, children: leftActions }), jsxs("div", { className: styles.previewContent, children: [!!title && (jsx(TextDefaultPropsContext, { props: TITLE_TEXT_PROPS, children: jsx("div", { className: styles.previewTitle, children: title }) })), !!subtitle && (jsx(TextDefaultPropsContext, { props: SUBTITLE_TEXT_PROPS, children: jsx("div", { className: styles.previewSubtitle, children: subtitle }) }))] }), !!rightActions && jsx("div", { className: styles.previewSide, children: rightActions })] }) }));
11
16
  ChatInputPreview.displayName = 'ChatInputPreview';
12
17
 
13
18
  export { ChatInputPreview };
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInputPreview.js","sources":["src/public/ChatInputPreview.tsx"],"sourcesContent":["import { type FC, type ReactNode } from 'react';\n\nimport { IconDefaultPropsContext } from '@hh.ru/magritte-ui-icon';\n\nimport styles from '../styles.less';\n\nexport interface ChatInputPreviewProps {\n /** Заголовок в центральной секции, типографика subtitle-3-semibold */\n title?: ReactNode;\n /** Подзаголовок под title, типографика label-3-regular; обрезается многоточием */\n subtitle?: ReactNode;\n /** Слот левой секции, обычно иконка */\n leftActions?: ReactNode;\n /** Слот правой секции, обычно иконка */\n rightActions?: ReactNode;\n}\n\nconst DEFAULT_ICON_PROPS = {\n initialColor: 'secondary',\n padding: 8,\n} as const;\n\nexport const ChatInputPreview: FC<ChatInputPreviewProps> = ({ title, subtitle, leftActions, rightActions }) => (\n <IconDefaultPropsContext props={DEFAULT_ICON_PROPS}>\n <div className={styles.previewBlock}>\n {!!leftActions && <div className={styles.previewSide}>{leftActions}</div>}\n <div className={styles.previewContent}>\n {!!title && <div className={styles.previewTitle}>{title}</div>}\n {!!subtitle && <div className={styles.previewSubtitle}>{subtitle}</div>}\n </div>\n {!!rightActions && <div className={styles.previewSide}>{rightActions}</div>}\n </div>\n </IconDefaultPropsContext>\n);\n\nChatInputPreview.displayName = 'ChatInputPreview';\n"],"names":["_jsx","_jsxs"],"mappings":";;;;AAiBA,MAAM,kBAAkB,GAAG;AACvB,IAAA,YAAY,EAAE,WAAW;AACzB,IAAA,OAAO,EAAE,CAAC;CACJ,CAAC;MAEE,gBAAgB,GAA8B,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,MACtGA,GAAA,CAAC,uBAAuB,EAAA,EAAC,KAAK,EAAE,kBAAkB,EAC9C,QAAA,EAAAC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,YAAY,EAAA,QAAA,EAAA,CAC9B,CAAC,CAAC,WAAW,IAAID,aAAK,SAAS,EAAE,MAAM,CAAC,WAAW,YAAG,WAAW,EAAA,CAAO,EACzEC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,cAAc,aAChC,CAAC,CAAC,KAAK,IAAID,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,YAAY,EAAA,QAAA,EAAG,KAAK,EAAO,CAAA,EAC7D,CAAC,CAAC,QAAQ,IAAIA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,eAAe,YAAG,QAAQ,EAAA,CAAO,IACrE,EACL,CAAC,CAAC,YAAY,IAAIA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,WAAW,EAAA,QAAA,EAAG,YAAY,EAAO,CAAA,CAAA,EAAA,CACzE,EACgB,CAAA,EAC5B;AAEF,gBAAgB,CAAC,WAAW,GAAG,kBAAkB;;;;"}
1
+ {"version":3,"file":"ChatInputPreview.js","sources":["src/public/ChatInputPreview.tsx"],"sourcesContent":["import { type FC, type ReactNode } from 'react';\n\nimport { IconDefaultPropsContext } from '@hh.ru/magritte-ui-icon';\nimport { TextDefaultPropsContext } from '@hh.ru/magritte-ui-typography';\n\nimport styles from '../styles.less';\n\nexport interface ChatInputPreviewProps {\n /** Заголовок в центральной секции, типографика subtitle-3-semibold */\n title?: ReactNode;\n /** Подзаголовок под title, типографика label-3-regular; обрезается многоточием */\n subtitle?: ReactNode;\n /** Слот левой секции, обычно иконка */\n leftActions?: ReactNode;\n /** Слот правой секции, обычно иконка */\n rightActions?: ReactNode;\n}\n\nconst DEFAULT_ICON_PROPS = {\n initialColor: 'secondary',\n padding: 8,\n} as const;\n\n// строку оформляют стили слота, а Text, переданный пользователем в title/subtitle, получает те же дефолты.\n// ellipsis — для Text: блочный элемент не обрезается text-overflow родителя\nconst TITLE_TEXT_PROPS = { typography: 'subtitle-3-semibold', style: 'primary' } as const;\nconst SUBTITLE_TEXT_PROPS = { typography: 'label-3-regular', style: 'secondary', ellipsis: true } as const;\n\nexport const ChatInputPreview: FC<ChatInputPreviewProps> = ({ title, subtitle, leftActions, rightActions }) => (\n <IconDefaultPropsContext props={DEFAULT_ICON_PROPS}>\n <div className={styles.previewBlock}>\n {!!leftActions && <div className={styles.previewSide}>{leftActions}</div>}\n <div className={styles.previewContent}>\n {!!title && (\n <TextDefaultPropsContext props={TITLE_TEXT_PROPS}>\n <div className={styles.previewTitle}>{title}</div>\n </TextDefaultPropsContext>\n )}\n {!!subtitle && (\n <TextDefaultPropsContext props={SUBTITLE_TEXT_PROPS}>\n <div className={styles.previewSubtitle}>{subtitle}</div>\n </TextDefaultPropsContext>\n )}\n </div>\n {!!rightActions && <div className={styles.previewSide}>{rightActions}</div>}\n </div>\n </IconDefaultPropsContext>\n);\n\nChatInputPreview.displayName = 'ChatInputPreview';\n"],"names":["_jsx","_jsxs"],"mappings":";;;;;AAkBA,MAAM,kBAAkB,GAAG;AACvB,IAAA,YAAY,EAAE,WAAW;AACzB,IAAA,OAAO,EAAE,CAAC;CACJ,CAAC;AAEX;AACA;AACA,MAAM,gBAAgB,GAAG,EAAE,UAAU,EAAE,qBAAqB,EAAE,KAAK,EAAE,SAAS,EAAW,CAAC;AAC1F,MAAM,mBAAmB,GAAG,EAAE,UAAU,EAAE,iBAAiB,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAW,CAAC;AAE9F,MAAA,gBAAgB,GAA8B,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,MACtGA,GAAC,CAAA,uBAAuB,EAAC,EAAA,KAAK,EAAE,kBAAkB,EAC9C,QAAA,EAAAC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,YAAY,EAC9B,QAAA,EAAA,CAAA,CAAC,CAAC,WAAW,IAAID,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,WAAW,EAAA,QAAA,EAAG,WAAW,EAAA,CAAO,EACzEC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,cAAc,EAAA,QAAA,EAAA,CAChC,CAAC,CAAC,KAAK,KACJD,GAAA,CAAC,uBAAuB,EAAC,EAAA,KAAK,EAAE,gBAAgB,EAC5C,QAAA,EAAAA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,YAAY,EAAA,QAAA,EAAG,KAAK,EAAA,CAAO,GAC5B,CAC7B,EACA,CAAC,CAAC,QAAQ,KACPA,GAAA,CAAC,uBAAuB,EAAA,EAAC,KAAK,EAAE,mBAAmB,EAAA,QAAA,EAC/CA,aAAK,SAAS,EAAE,MAAM,CAAC,eAAe,EAAA,QAAA,EAAG,QAAQ,EAAA,CAAO,EAClC,CAAA,CAC7B,CACC,EAAA,CAAA,EACL,CAAC,CAAC,YAAY,IAAIA,GAAK,CAAA,KAAA,EAAA,EAAA,SAAS,EAAE,MAAM,CAAC,WAAW,EAAG,QAAA,EAAA,YAAY,EAAO,CAAA,CAAA,EAAA,CACzE,EACgB,CAAA,EAC5B;AAEF,gBAAgB,CAAC,WAAW,GAAG,kBAAkB;;;;"}
@@ -0,0 +1,5 @@
1
+ import { type ChatInputFileType } from '@hh.ru/magritte-ui-chat-input/public/ChatInputFile';
2
+ /**
3
+ * Тип `ChatInput.File` по MIME-типу файла: `image/*` — `image`, `video/*` — `video`, остальное — `doc`
4
+ */
5
+ export declare const getChatInputFileType: (file: Blob) => ChatInputFileType;
@@ -0,0 +1,16 @@
1
+ import './../index.css';
2
+ /**
3
+ * Тип `ChatInput.File` по MIME-типу файла: `image/*` — `image`, `video/*` — `video`, остальное — `doc`
4
+ */
5
+ const getChatInputFileType = (file) => {
6
+ if (file.type.startsWith('image/')) {
7
+ return 'image';
8
+ }
9
+ if (file.type.startsWith('video/')) {
10
+ return 'video';
11
+ }
12
+ return 'doc';
13
+ };
14
+
15
+ export { getChatInputFileType };
16
+ //# sourceMappingURL=getChatInputFileType.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getChatInputFileType.js","sources":["src/public/getChatInputFileType.ts"],"sourcesContent":["import { type ChatInputFileType } from '@hh.ru/magritte-ui-chat-input/public/ChatInputFile';\n\n/**\n * Тип `ChatInput.File` по MIME-типу файла: `image/*` — `image`, `video/*` — `video`, остальное — `doc`\n */\nexport const getChatInputFileType = (file: Blob): ChatInputFileType => {\n if (file.type.startsWith('image/')) {\n return 'image';\n }\n if (file.type.startsWith('video/')) {\n return 'video';\n }\n return 'doc';\n};\n"],"names":[],"mappings":"AAEA;;AAEG;AACU,MAAA,oBAAoB,GAAG,CAAC,IAAU,KAAuB;IAClE,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;AAChC,QAAA,OAAO,OAAO,CAAC;KAClB;IACD,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;AAChC,QAAA,OAAO,OAAO,CAAC;KAClB;AACD,IAAA,OAAO,KAAK,CAAC;AACjB;;;;"}
@@ -0,0 +1,5 @@
1
+ import './index.css';
2
+ var styles = {"chat-input":"magritte-chat-input___P69oN_1-2-0","chatInput":"magritte-chat-input___P69oN_1-2-0","no-background":"magritte-no-background___eiIY1_1-2-0","noBackground":"magritte-no-background___eiIY1_1-2-0","text-input-focused":"magritte-text-input-focused___TfyLu_1-2-0","textInputFocused":"magritte-text-input-focused___TfyLu_1-2-0","content-grid":"magritte-content-grid___g03sT_1-2-0","contentGrid":"magritte-content-grid___g03sT_1-2-0","preview":"magritte-preview___baXKi_1-2-0","left":"magritte-left___7JZYp_1-2-0","central":"magritte-central___zkguj_1-2-0","right":"magritte-right___-tGcO_1-2-0","scrollbar-cell":"magritte-scrollbar-cell___--M2x_1-2-0","scrollbarCell":"magritte-scrollbar-cell___--M2x_1-2-0","text-input":"magritte-text-input___3AFO4_1-2-0","textInput":"magritte-text-input___3AFO4_1-2-0","layout-vertical":"magritte-layout-vertical___mVTr-_1-2-0","layoutVertical":"magritte-layout-vertical___mVTr-_1-2-0","has-central":"magritte-has-central___VRZik_1-2-0","hasCentral":"magritte-has-central___VRZik_1-2-0","no-left-controls":"magritte-no-left-controls___7r6yy_1-2-0","noLeftControls":"magritte-no-left-controls___7r6yy_1-2-0","no-right-controls":"magritte-no-right-controls___HBSag_1-2-0","noRightControls":"magritte-no-right-controls___HBSag_1-2-0","chips":"magritte-chips___gLao5_1-2-0","chips-container":"magritte-chips-container___-bS5O_1-2-0","chipsContainer":"magritte-chips-container___-bS5O_1-2-0","preview-block":"magritte-preview-block___iiPdS_1-2-0","previewBlock":"magritte-preview-block___iiPdS_1-2-0","preview-side":"magritte-preview-side___ymR-u_1-2-0","previewSide":"magritte-preview-side___ymR-u_1-2-0","preview-content":"magritte-preview-content___ZgyBD_1-2-0","previewContent":"magritte-preview-content___ZgyBD_1-2-0","preview-title":"magritte-preview-title___SkFeZ_1-2-0","previewTitle":"magritte-preview-title___SkFeZ_1-2-0","preview-subtitle":"magritte-preview-subtitle___58qfR_1-2-0","previewSubtitle":"magritte-preview-subtitle___58qfR_1-2-0","files-container":"magritte-files-container___zOkRK_1-2-0","filesContainer":"magritte-files-container___zOkRK_1-2-0","files":"magritte-files___j2q5K_1-2-0","file":"magritte-file___lz9Ll_1-2-0","file-card":"magritte-file-card___hn5C9_1-2-0","fileCard":"magritte-file-card___hn5C9_1-2-0","file-tile":"magritte-file-tile___OVlh3_1-2-0","fileTile":"magritte-file-tile___OVlh3_1-2-0","file-card-removable":"magritte-file-card-removable___GkxUe_1-2-0","fileCardRemovable":"magritte-file-card-removable___GkxUe_1-2-0","file-tile-placeholder":"magritte-file-tile-placeholder___yxLuR_1-2-0","fileTilePlaceholder":"magritte-file-tile-placeholder___yxLuR_1-2-0","file-tile-image":"magritte-file-tile-image___cZFgL_1-2-0","fileTileImage":"magritte-file-tile-image___cZFgL_1-2-0","file-remove":"magritte-file-remove___S0WB9_1-2-0","fileRemove":"magritte-file-remove___S0WB9_1-2-0","file-name":"magritte-file-name___L03-O_1-2-0","fileName":"magritte-file-name___L03-O_1-2-0","file-name-base":"magritte-file-name-base___ojdp6_1-2-0","fileNameBase":"magritte-file-name-base___ojdp6_1-2-0","file-name-extension":"magritte-file-name-extension___3QZtS_1-2-0","fileNameExtension":"magritte-file-name-extension___3QZtS_1-2-0","text-input-wrapper":"magritte-text-input-wrapper___TPbwC_1-2-0","textInputWrapper":"magritte-text-input-wrapper___TPbwC_1-2-0","with-top-fade":"magritte-with-top-fade___okgqo_1-2-0","withTopFade":"magritte-with-top-fade___okgqo_1-2-0","with-bottom-fade":"magritte-with-bottom-fade___82gr8_1-2-0","withBottomFade":"magritte-with-bottom-fade___82gr8_1-2-0","measure":"magritte-measure___xNKc0_1-2-0","voice-record":"magritte-voice-record___p64PV_1-2-0","voiceRecord":"magritte-voice-record___p64PV_1-2-0","voice-record-left":"magritte-voice-record-left___njEt-_1-2-0","voiceRecordLeft":"magritte-voice-record-left___njEt-_1-2-0","voice-record-right":"magritte-voice-record-right___UTv-U_1-2-0","voiceRecordRight":"magritte-voice-record-right___UTv-U_1-2-0","voice-processing":"magritte-voice-processing___C0xnX_1-2-0","voiceProcessing":"magritte-voice-processing___C0xnX_1-2-0","voice-record-indicator":"magritte-voice-record-indicator___V8ybb_1-2-0","voiceRecordIndicator":"magritte-voice-record-indicator___V8ybb_1-2-0","voice-record-indicator-bar":"magritte-voice-record-indicator-bar___jgyqz_1-2-0","voiceRecordIndicatorBar":"magritte-voice-record-indicator-bar___jgyqz_1-2-0","voice-record-indicator-wave":"magritte-voice-record-indicator-wave___4VsyE_1-2-0","voiceRecordIndicatorWave":"magritte-voice-record-indicator-wave___4VsyE_1-2-0","voice-record-indicator-has-sound":"magritte-voice-record-indicator-has-sound___67t5g_1-2-0","voiceRecordIndicatorHasSound":"magritte-voice-record-indicator-has-sound___67t5g_1-2-0","mode-container":"magritte-mode-container___nATVD_1-2-0","modeContainer":"magritte-mode-container___nATVD_1-2-0","voice-overlay":"magritte-voice-overlay___LbxAI_1-2-0","voiceOverlay":"magritte-voice-overlay___LbxAI_1-2-0"};
3
+
4
+ export { styles as s };
5
+ //# sourceMappingURL=styles-BHWYKmPT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles-BHWYKmPT.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -1,5 +0,0 @@
1
- import './index.css';
2
- var styles = {"chat-input":"magritte-chat-input___P69oN_1-1-18","chatInput":"magritte-chat-input___P69oN_1-1-18","no-background":"magritte-no-background___eiIY1_1-1-18","noBackground":"magritte-no-background___eiIY1_1-1-18","text-input-focused":"magritte-text-input-focused___TfyLu_1-1-18","textInputFocused":"magritte-text-input-focused___TfyLu_1-1-18","content-grid":"magritte-content-grid___g03sT_1-1-18","contentGrid":"magritte-content-grid___g03sT_1-1-18","preview":"magritte-preview___baXKi_1-1-18","left":"magritte-left___7JZYp_1-1-18","central":"magritte-central___zkguj_1-1-18","right":"magritte-right___-tGcO_1-1-18","scrollbar-cell":"magritte-scrollbar-cell___--M2x_1-1-18","scrollbarCell":"magritte-scrollbar-cell___--M2x_1-1-18","text-input":"magritte-text-input___3AFO4_1-1-18","textInput":"magritte-text-input___3AFO4_1-1-18","layout-vertical":"magritte-layout-vertical___mVTr-_1-1-18","layoutVertical":"magritte-layout-vertical___mVTr-_1-1-18","has-central":"magritte-has-central___VRZik_1-1-18","hasCentral":"magritte-has-central___VRZik_1-1-18","no-left-controls":"magritte-no-left-controls___7r6yy_1-1-18","noLeftControls":"magritte-no-left-controls___7r6yy_1-1-18","no-right-controls":"magritte-no-right-controls___HBSag_1-1-18","noRightControls":"magritte-no-right-controls___HBSag_1-1-18","chips":"magritte-chips___gLao5_1-1-18","chips-container":"magritte-chips-container___-bS5O_1-1-18","chipsContainer":"magritte-chips-container___-bS5O_1-1-18","preview-block":"magritte-preview-block___iiPdS_1-1-18","previewBlock":"magritte-preview-block___iiPdS_1-1-18","preview-side":"magritte-preview-side___ymR-u_1-1-18","previewSide":"magritte-preview-side___ymR-u_1-1-18","preview-content":"magritte-preview-content___ZgyBD_1-1-18","previewContent":"magritte-preview-content___ZgyBD_1-1-18","preview-title":"magritte-preview-title___SkFeZ_1-1-18","previewTitle":"magritte-preview-title___SkFeZ_1-1-18","preview-subtitle":"magritte-preview-subtitle___58qfR_1-1-18","previewSubtitle":"magritte-preview-subtitle___58qfR_1-1-18","text-input-wrapper":"magritte-text-input-wrapper___TPbwC_1-1-18","textInputWrapper":"magritte-text-input-wrapper___TPbwC_1-1-18","with-top-fade":"magritte-with-top-fade___okgqo_1-1-18","withTopFade":"magritte-with-top-fade___okgqo_1-1-18","with-bottom-fade":"magritte-with-bottom-fade___82gr8_1-1-18","withBottomFade":"magritte-with-bottom-fade___82gr8_1-1-18","measure":"magritte-measure___xNKc0_1-1-18","voice-record":"magritte-voice-record___p64PV_1-1-18","voiceRecord":"magritte-voice-record___p64PV_1-1-18","voice-record-left":"magritte-voice-record-left___njEt-_1-1-18","voiceRecordLeft":"magritte-voice-record-left___njEt-_1-1-18","voice-record-right":"magritte-voice-record-right___UTv-U_1-1-18","voiceRecordRight":"magritte-voice-record-right___UTv-U_1-1-18","voice-processing":"magritte-voice-processing___C0xnX_1-1-18","voiceProcessing":"magritte-voice-processing___C0xnX_1-1-18","voice-record-indicator":"magritte-voice-record-indicator___V8ybb_1-1-18","voiceRecordIndicator":"magritte-voice-record-indicator___V8ybb_1-1-18","voice-record-indicator-bar":"magritte-voice-record-indicator-bar___jgyqz_1-1-18","voiceRecordIndicatorBar":"magritte-voice-record-indicator-bar___jgyqz_1-1-18","voice-record-indicator-wave":"magritte-voice-record-indicator-wave___4VsyE_1-1-18","voiceRecordIndicatorWave":"magritte-voice-record-indicator-wave___4VsyE_1-1-18","voice-record-indicator-has-sound":"magritte-voice-record-indicator-has-sound___67t5g_1-1-18","voiceRecordIndicatorHasSound":"magritte-voice-record-indicator-has-sound___67t5g_1-1-18","mode-container":"magritte-mode-container___nATVD_1-1-18","modeContainer":"magritte-mode-container___nATVD_1-1-18","voice-overlay":"magritte-voice-overlay___LbxAI_1-1-18","voiceOverlay":"magritte-voice-overlay___LbxAI_1-1-18"};
3
-
4
- export { styles as s };
5
- //# sourceMappingURL=styles-x_6MfT-u.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"styles-x_6MfT-u.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}