livechat 0.4.2 → 0.4.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f42dfde953e1643e5cc5fbfce81dc237376788709890a6254a4800bec927f51d
4
- data.tar.gz: 76e741f442b6b847d3aa4edd37432ee55f2fe6ac9d8d38a356bf716023f4e146
3
+ metadata.gz: fd6a72ade19436355c068f67d4c036f6f84b66e32cd163e36f3022619fa1587c
4
+ data.tar.gz: c7936d6b60c1bdc5f509f44e186a16e21368b1b2328d54ac7dc7918ee2ab7893
5
5
  SHA512:
6
- metadata.gz: 20ed071145a817ffa93933ea8db69585a64edc7bfd88931420126a2a82a5c096ff34b5b94fff2a12c3a092de20dd742e1df637355df20994f7d93c57965a0e7a
7
- data.tar.gz: d77df77a8b6c6a9bf050403fb05c791fa02dd5fa350aa663e0d23b2445d1269110690321c3f8f8f9593fecba1a9e3013cb30e4b6a5f3d9327f042ecba6b80ae7
6
+ metadata.gz: 44f6a47b5879c17554031dc0d0f5a1e92943c180aaa08c855edc803682b3a558a3b232ab9fac16982f6bf2423505a72ca83e3173ad4e07491dc618bda43e24ef
7
+ data.tar.gz: 9c025865ff9824eac83660af0775e74e08a508472056ca29dffc5c129f6b69f3c291db006a31a1f8b26a43ba0dfea9f29bdfb992eb0f30ee6a91b5db4cf1d8bd
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.4
4
+
5
+ - Expand / collapse the chat on desktop. A new header control grows the panel
6
+ to a roomier size (and back) for long threads and image-heavy chats; the
7
+ choice is remembered across Turbo visits. Hidden on phones, where the panel
8
+ is already full-screen. Translated across all 26 locales.
9
+ - Composer polish: dropped the doubled focus ring (one quiet accent border
10
+ now), and flattened Safari's default textarea bevel that showed as a second
11
+ box inside the composer.
12
+ - Fixed a message bubble bleeding over the header's bottom edge while scrolling
13
+ a long thread (a flexbox scroll-containment + stacking fix).
14
+
15
+ ## 0.4.3
16
+
17
+ - Unified composer. The message box, attach button and send button are now one
18
+ bordered container (the textarea on top, a toolbar row with the tools on the
19
+ left and a circular send on the right) that lights up on focus — instead of a
20
+ textarea flanked by loose buttons. Reads as a single control, closer to what
21
+ people expect from a chat composer. Pending-file chips ride inside the box.
22
+
3
23
  ## 0.4.2
4
24
 
5
25
  - Breathing room between the widget's pending-file chips and the composer —
@@ -20,6 +20,8 @@ ar:
20
20
  attach: "إرفاق ملفات"
21
21
  remove_file: "إزالة الملف"
22
22
  attachment_error: "تعذر إرسال بعض الملفات."
23
+ expand: "تكبير"
24
+ collapse: "تصغير"
23
25
  attachments:
24
26
  too_many: "ملفات كثيرة جدًا (بحد أقصى %{count})."
25
27
  too_large: "%{name} كبير جدًا."
@@ -20,6 +20,8 @@ bg:
20
20
  attach: "Прикачване на файлове"
21
21
  remove_file: "Премахване на файла"
22
22
  attachment_error: "Някои файлове не можаха да бъдат изпратени."
23
+ expand: "Уголеми"
24
+ collapse: "Смали"
23
25
  attachments:
24
26
  too_many: "Твърде много файлове (макс. %{count})."
25
27
  too_large: "%{name} е твърде голям."
@@ -20,6 +20,8 @@ bn:
20
20
  attach: "ফাইল সংযুক্ত করুন"
21
21
  remove_file: "ফাইল সরান"
22
22
  attachment_error: "কিছু ফাইল পাঠানো যায়নি।"
23
+ expand: "বড় করুন"
24
+ collapse: "ছোট করুন"
23
25
  attachments:
24
26
  too_many: "অনেক বেশি ফাইল (সর্বোচ্চ %{count})।"
25
27
  too_large: "%{name} খুব বড়।"
@@ -20,6 +20,8 @@ de:
20
20
  attach: "Dateien anhängen"
21
21
  remove_file: "Datei entfernen"
22
22
  attachment_error: "Einige Dateien konnten nicht gesendet werden."
23
+ expand: "Vergrößern"
24
+ collapse: "Verkleinern"
23
25
  attachments:
24
26
  too_many: "Zu viele Dateien (max. %{count})."
25
27
  too_large: "%{name} ist zu groß."
@@ -20,6 +20,8 @@ el:
20
20
  attach: "Επισύναψη αρχείων"
21
21
  remove_file: "Αφαίρεση αρχείου"
22
22
  attachment_error: "Ορισμένα αρχεία δεν ήταν δυνατό να σταλούν."
23
+ expand: "Μεγέθυνση"
24
+ collapse: "Σμίκρυνση"
23
25
  attachments:
24
26
  too_many: "Πάρα πολλά αρχεία (έως %{count})."
25
27
  too_large: "Το %{name} είναι πολύ μεγάλο."
@@ -20,6 +20,8 @@ en:
20
20
  attach: "Attach files"
21
21
  remove_file: "Remove file"
22
22
  attachment_error: "Some files could not be sent."
23
+ expand: "Expand"
24
+ collapse: "Collapse"
23
25
  attachments:
24
26
  too_many: "Too many files (max %{count})."
25
27
  too_large: "%{name} is too large."
@@ -20,6 +20,8 @@ es:
20
20
  attach: "Adjuntar archivos"
21
21
  remove_file: "Quitar archivo"
22
22
  attachment_error: "No se pudieron enviar algunos archivos."
23
+ expand: "Ampliar"
24
+ collapse: "Reducir"
23
25
  attachments:
24
26
  too_many: "Demasiados archivos (máx. %{count})."
25
27
  too_large: "%{name} es demasiado grande."
@@ -20,6 +20,8 @@ fr:
20
20
  attach: "Joindre des fichiers"
21
21
  remove_file: "Retirer le fichier"
22
22
  attachment_error: "Certains fichiers n'ont pas pu être envoyés."
23
+ expand: "Agrandir"
24
+ collapse: "Réduire"
23
25
  attachments:
24
26
  too_many: "Trop de fichiers (max %{count})."
25
27
  too_large: "%{name} est trop volumineux."
@@ -20,6 +20,8 @@ hi:
20
20
  attach: "फ़ाइलें संलग्न करें"
21
21
  remove_file: "फ़ाइल हटाएं"
22
22
  attachment_error: "कुछ फ़ाइलें भेजी नहीं जा सकीं।"
23
+ expand: "बड़ा करें"
24
+ collapse: "छोटा करें"
23
25
  attachments:
24
26
  too_many: "बहुत सारी फ़ाइलें (अधिकतम %{count})।"
25
27
  too_large: "%{name} बहुत बड़ी है।"
@@ -20,6 +20,8 @@ hr:
20
20
  attach: "Priloži datoteke"
21
21
  remove_file: "Ukloni datoteku"
22
22
  attachment_error: "Neke datoteke nije bilo moguće poslati."
23
+ expand: "Povećaj"
24
+ collapse: "Smanji"
23
25
  attachments:
24
26
  too_many: "Previše datoteka (najviše %{count})."
25
27
  too_large: "%{name} je prevelika."
@@ -20,6 +20,8 @@ id:
20
20
  attach: "Lampirkan file"
21
21
  remove_file: "Hapus file"
22
22
  attachment_error: "Beberapa file tidak dapat dikirim."
23
+ expand: "Perbesar"
24
+ collapse: "Perkecil"
23
25
  attachments:
24
26
  too_many: "Terlalu banyak file (maks. %{count})."
25
27
  too_large: "%{name} terlalu besar."
@@ -20,6 +20,8 @@ it:
20
20
  attach: "Allega file"
21
21
  remove_file: "Rimuovi file"
22
22
  attachment_error: "Non è stato possibile inviare alcuni file."
23
+ expand: "Ingrandisci"
24
+ collapse: "Riduci"
23
25
  attachments:
24
26
  too_many: "Troppi file (max %{count})."
25
27
  too_large: "%{name} è troppo grande."
@@ -20,6 +20,8 @@ ja:
20
20
  attach: "ファイルを添付"
21
21
  remove_file: "ファイルを削除"
22
22
  attachment_error: "一部のファイルを送信できませんでした。"
23
+ expand: "拡大"
24
+ collapse: "縮小"
23
25
  attachments:
24
26
  too_many: "ファイルが多すぎます(最大%{count}件)。"
25
27
  too_large: "%{name}が大きすぎます。"
@@ -20,6 +20,8 @@ ko:
20
20
  attach: "파일 첨부"
21
21
  remove_file: "파일 제거"
22
22
  attachment_error: "일부 파일을 보내지 못했습니다."
23
+ expand: "확대"
24
+ collapse: "축소"
23
25
  attachments:
24
26
  too_many: "파일이 너무 많습니다 (최대 %{count}개)."
25
27
  too_large: "%{name}이(가) 너무 큽니다."
@@ -20,6 +20,8 @@ lb:
20
20
  attach: "Dateien uschléissen"
21
21
  remove_file: "Datei ewechhuelen"
22
22
  attachment_error: "E puer Dateie konnten net geschéckt ginn."
23
+ expand: "Vergréisseren"
24
+ collapse: "Verklengeren"
23
25
  attachments:
24
26
  too_many: "Ze vill Dateien (max %{count})."
25
27
  too_large: "%{name} ass ze grouss."
@@ -20,6 +20,8 @@ nl:
20
20
  attach: "Bestanden bijvoegen"
21
21
  remove_file: "Bestand verwijderen"
22
22
  attachment_error: "Sommige bestanden konden niet worden verzonden."
23
+ expand: "Vergroten"
24
+ collapse: "Verkleinen"
23
25
  attachments:
24
26
  too_many: "Te veel bestanden (max. %{count})."
25
27
  too_large: "%{name} is te groot."
@@ -20,6 +20,8 @@ pl:
20
20
  attach: "Załącz pliki"
21
21
  remove_file: "Usuń plik"
22
22
  attachment_error: "Nie udało się wysłać niektórych plików."
23
+ expand: "Powiększ"
24
+ collapse: "Zmniejsz"
23
25
  attachments:
24
26
  too_many: "Zbyt wiele plików (maks. %{count})."
25
27
  too_large: "%{name} jest za duży."
@@ -20,6 +20,8 @@ pt:
20
20
  attach: "Anexar arquivos"
21
21
  remove_file: "Remover arquivo"
22
22
  attachment_error: "Não foi possível enviar alguns arquivos."
23
+ expand: "Ampliar"
24
+ collapse: "Reduzir"
23
25
  attachments:
24
26
  too_many: "Muitos arquivos (máx. %{count})."
25
27
  too_large: "%{name} é muito grande."
@@ -20,6 +20,8 @@ ro:
20
20
  attach: "Atașează fișiere"
21
21
  remove_file: "Elimină fișierul"
22
22
  attachment_error: "Unele fișiere nu au putut fi trimise."
23
+ expand: "Mărește"
24
+ collapse: "Micșorează"
23
25
  attachments:
24
26
  too_many: "Prea multe fișiere (max. %{count})."
25
27
  too_large: "%{name} este prea mare."
@@ -20,6 +20,8 @@ ru:
20
20
  attach: "Прикрепить файлы"
21
21
  remove_file: "Удалить файл"
22
22
  attachment_error: "Некоторые файлы не удалось отправить."
23
+ expand: "Развернуть"
24
+ collapse: "Свернуть"
23
25
  attachments:
24
26
  too_many: "Слишком много файлов (макс. %{count})."
25
27
  too_large: "%{name} слишком большой."
@@ -20,6 +20,8 @@ th:
20
20
  attach: "แนบไฟล์"
21
21
  remove_file: "นำไฟล์ออก"
22
22
  attachment_error: "ไม่สามารถส่งไฟล์บางไฟล์ได้"
23
+ expand: "ขยาย"
24
+ collapse: "ย่อ"
23
25
  attachments:
24
26
  too_many: "ไฟล์มากเกินไป (สูงสุด %{count})"
25
27
  too_large: "%{name} มีขนาดใหญ่เกินไป"
@@ -20,6 +20,8 @@ tr:
20
20
  attach: "Dosya ekle"
21
21
  remove_file: "Dosyayı kaldır"
22
22
  attachment_error: "Bazı dosyalar gönderilemedi."
23
+ expand: "Büyüt"
24
+ collapse: "Küçült"
23
25
  attachments:
24
26
  too_many: "Çok fazla dosya (en fazla %{count})."
25
27
  too_large: "%{name} çok büyük."
@@ -20,6 +20,8 @@ uk:
20
20
  attach: "Прикріпити файли"
21
21
  remove_file: "Видалити файл"
22
22
  attachment_error: "Деякі файли не вдалося надіслати."
23
+ expand: "Розгорнути"
24
+ collapse: "Згорнути"
23
25
  attachments:
24
26
  too_many: "Забагато файлів (максимум %{count})."
25
27
  too_large: "%{name} завеликий."
@@ -20,6 +20,8 @@ ur:
20
20
  attach: "فائلیں منسلک کریں"
21
21
  remove_file: "فائل ہٹائیں"
22
22
  attachment_error: "کچھ فائلیں نہیں بھیجی جا سکیں۔"
23
+ expand: "بڑا کریں"
24
+ collapse: "چھوٹا کریں"
23
25
  attachments:
24
26
  too_many: "بہت زیادہ فائلیں (زیادہ سے زیادہ %{count})۔"
25
27
  too_large: "%{name} بہت بڑی ہے۔"
@@ -20,6 +20,8 @@ vi:
20
20
  attach: "Đính kèm tệp"
21
21
  remove_file: "Xóa tệp"
22
22
  attachment_error: "Không thể gửi một số tệp."
23
+ expand: "Mở rộng"
24
+ collapse: "Thu gọn"
23
25
  attachments:
24
26
  too_many: "Quá nhiều tệp (tối đa %{count})."
25
27
  too_large: "%{name} quá lớn."
@@ -20,6 +20,8 @@
20
20
  attach: "附加文件"
21
21
  remove_file: "移除文件"
22
22
  attachment_error: "部分文件无法发送。"
23
+ expand: "放大"
24
+ collapse: "缩小"
23
25
  attachments:
24
26
  too_many: "文件过多(最多 %{count} 个)。"
25
27
  too_large: "%{name} 太大。"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Livechat
4
- VERSION = '0.4.2'
4
+ VERSION = '0.4.4'
5
5
  end
@@ -39,6 +39,10 @@
39
39
  var pendingFiles = [];
40
40
  var isOpen = false;
41
41
  var lastFocused = null;
42
+ var expandBtnEl = null;
43
+ // Desktop-only: a bigger panel, remembered across Turbo visits. Never
44
+ // applied on phones, where the panel is already full-screen.
45
+ var expanded = false;
42
46
  // On phones the panel is a full-screen modal (focus trapped, page scroll
43
47
  // locked); on desktop it stays a non-modal popover you can chat alongside.
44
48
  var mobileModal = window.matchMedia ? window.matchMedia("(max-width: 480px)") : null;
@@ -70,6 +74,7 @@
70
74
  }
71
75
 
72
76
  ready(function () {
77
+ expanded = sessionGet("livechat_expanded") === "1";
73
78
  document.addEventListener("keydown", function (event) {
74
79
  if (event.key === "Escape" && isOpen) closePanel();
75
80
  });
@@ -100,6 +105,7 @@
100
105
  injectStyles();
101
106
  mount();
102
107
  applyBrandColor();
108
+ applyExpanded(); // a Turbo swap makes a fresh root — restore the size class
103
109
  syncOpenerBadges(); // a Turbo visit brings fresh openers — restamp them
104
110
 
105
111
  if (sessionGet("livechat_open") === "1") {
@@ -206,14 +212,27 @@
206
212
  titles.appendChild(subtitle);
207
213
  header.appendChild(titles);
208
214
 
215
+ var actions = document.createElement("div");
216
+ actions.id = "lvc-actions";
217
+
218
+ // Grow/shrink the desktop panel. Hidden on phones (already full-screen).
219
+ expandBtnEl = document.createElement("button");
220
+ expandBtnEl.type = "button";
221
+ expandBtnEl.id = "lvc-expand";
222
+ expandBtnEl.addEventListener("click", toggleExpand);
223
+ actions.appendChild(expandBtnEl);
224
+
209
225
  var close = document.createElement("button");
210
226
  close.type = "button";
211
227
  close.id = "lvc-close";
212
228
  close.setAttribute("aria-label", config.labels.close);
213
229
  close.innerHTML = "×";
214
230
  close.addEventListener("click", closePanel);
215
- header.appendChild(close);
231
+ actions.appendChild(close);
232
+
233
+ header.appendChild(actions);
216
234
  panel.appendChild(header);
235
+ applyExpanded(); // set the panel size + the button's icon/label
217
236
 
218
237
  listEl = document.createElement("div");
219
238
  listEl.id = "lvc-list";
@@ -245,9 +264,22 @@
245
264
  emailRowEl = buildEmailRow();
246
265
  panel.appendChild(emailRowEl);
247
266
 
267
+ // The composer is one bordered box: the textarea on top, a toolbar row
268
+ // (tools on the left, send on the right) below — so it reads as a single
269
+ // control, not a textarea flanked by loose buttons.
248
270
  formEl = document.createElement("form");
249
271
  formEl.id = "lvc-form";
272
+
273
+ // Pending-file chips sit at the top of the box, inside the border.
274
+ if (config.attachments) {
275
+ filesBarEl = document.createElement("div");
276
+ filesBarEl.id = "lvc-files";
277
+ filesBarEl.hidden = true;
278
+ formEl.appendChild(filesBarEl);
279
+ }
280
+
250
281
  inputEl = document.createElement("textarea");
282
+ inputEl.id = "lvc-input";
251
283
  inputEl.rows = 1;
252
284
  inputEl.placeholder = config.labels.placeholder;
253
285
  inputEl.setAttribute("aria-label", config.labels.placeholder);
@@ -258,32 +290,15 @@
258
290
  send();
259
291
  }
260
292
  });
261
- var sendButton = document.createElement("button");
262
- sendButton.type = "submit";
263
- sendButton.setAttribute("aria-label", config.labels.send);
264
- sendButton.title = config.labels.send;
265
- // Paper airplane (Heroicons, MIT). CSS mirrors it for RTL.
266
- sendButton.innerHTML =
267
- '<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">' +
268
- '<path fill="currentColor" d="M3.478 2.404a.75.75 0 0 0-.926.941l2.432 ' +
269
- "7.905H13.5a.75.75 0 0 1 0 1.5H4.984l-2.432 7.905a.75.75 0 0 0 .926.94 " +
270
- "60.519 60.519 0 0 0 18.445-8.986.75.75 0 0 0 0-1.218A60.517 60.517 0 0 " +
271
- '0 3.478 2.404Z"/></svg>';
272
293
  formEl.appendChild(inputEl);
273
- formEl.appendChild(sendButton);
274
- formEl.addEventListener("submit", function (event) {
275
- event.preventDefault();
276
- send();
277
- });
278
294
 
279
- // Attachments: a paperclip that opens the file picker, plus a bar of
280
- // chips for the files waiting to be sent. Only when the host has them on.
281
- if (config.attachments) {
282
- filesBarEl = document.createElement("div");
283
- filesBarEl.id = "lvc-files";
284
- filesBarEl.hidden = true;
285
- panel.appendChild(filesBarEl);
295
+ var toolbar = document.createElement("div");
296
+ toolbar.id = "lvc-toolbar";
297
+ var tools = document.createElement("div");
298
+ tools.id = "lvc-tools";
286
299
 
300
+ // Attachments: a paperclip in the toolbar that opens the file picker.
301
+ if (config.attachments) {
287
302
  fileInputEl = document.createElement("input");
288
303
  fileInputEl.type = "file";
289
304
  fileInputEl.multiple = true;
@@ -296,18 +311,40 @@
296
311
  var attach = document.createElement("button");
297
312
  attach.type = "button";
298
313
  attach.id = "lvc-attach";
314
+ attach.className = "lvc-tool";
299
315
  attach.setAttribute("aria-label", config.labels.attach);
300
316
  attach.title = config.labels.attach;
301
317
  // Paperclip (Heroicons, MIT).
302
318
  attach.innerHTML =
303
- '<svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">' +
319
+ '<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">' +
304
320
  '<path fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" ' +
305
321
  'stroke-linejoin="round" d="M18.4 8.6 9.9 17a3.5 3.5 0 0 1-5-5l8.5-8.4a2.3 2.3 0 0 1 ' +
306
322
  '3.3 3.3l-8.5 8.4a1.1 1.1 0 0 1-1.6-1.6l7.8-7.8"/></svg>';
307
323
  attach.addEventListener("click", function () { fileInputEl.click(); });
308
- formEl.insertBefore(attach, inputEl);
324
+ tools.appendChild(attach);
309
325
  formEl.appendChild(fileInputEl);
310
326
  }
327
+ toolbar.appendChild(tools);
328
+
329
+ var sendButton = document.createElement("button");
330
+ sendButton.type = "submit";
331
+ sendButton.id = "lvc-send";
332
+ sendButton.setAttribute("aria-label", config.labels.send);
333
+ sendButton.title = config.labels.send;
334
+ // Paper airplane (Heroicons, MIT). CSS mirrors it for RTL.
335
+ sendButton.innerHTML =
336
+ '<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">' +
337
+ '<path fill="currentColor" d="M3.478 2.404a.75.75 0 0 0-.926.941l2.432 ' +
338
+ "7.905H13.5a.75.75 0 0 1 0 1.5H4.984l-2.432 7.905a.75.75 0 0 0 .926.94 " +
339
+ "60.519 60.519 0 0 0 18.445-8.986.75.75 0 0 0 0-1.218A60.517 60.517 0 0 " +
340
+ '0 3.478 2.404Z"/></svg>';
341
+ toolbar.appendChild(sendButton);
342
+
343
+ formEl.appendChild(toolbar);
344
+ formEl.addEventListener("submit", function (event) {
345
+ event.preventDefault();
346
+ send();
347
+ });
311
348
 
312
349
  panel.appendChild(formEl);
313
350
 
@@ -447,6 +484,38 @@
447
484
  return !!(mobileModal && mobileModal.matches);
448
485
  }
449
486
 
487
+ // --- expand / collapse (desktop) --------------------------------------------
488
+
489
+ var EXPAND_ICON =
490
+ '<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" ' +
491
+ 'stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
492
+ '<polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/>' +
493
+ '<line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>';
494
+ var COLLAPSE_ICON =
495
+ '<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" ' +
496
+ 'stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
497
+ '<polyline points="4 14 10 14 10 20"/><polyline points="20 10 14 10 14 4"/>' +
498
+ '<line x1="14" y1="10" x2="21" y2="3"/><line x1="10" y1="14" x2="3" y2="21"/></svg>';
499
+
500
+ function toggleExpand() {
501
+ if (isMobileModal()) return;
502
+ expanded = !expanded;
503
+ sessionSet("livechat_expanded", expanded ? "1" : "");
504
+ applyExpanded();
505
+ }
506
+
507
+ // Reflect the current state onto the panel and the header button. A no-op on
508
+ // phones — the class is never added there, so the full-screen panel stands.
509
+ function applyExpanded() {
510
+ var on = expanded && !isMobileModal();
511
+ if (root) root.classList.toggle("lvc-expanded", on);
512
+ if (!expandBtnEl) return;
513
+ var label = on ? config.labels.collapse : config.labels.expand;
514
+ expandBtnEl.setAttribute("aria-label", label);
515
+ expandBtnEl.title = label;
516
+ expandBtnEl.innerHTML = on ? COLLAPSE_ICON : EXPAND_ICON;
517
+ }
518
+
450
519
  // Tab cycles inside the panel only while it is the full-screen mobile
451
520
  // modal; the desktop popover deliberately lets focus reach the page.
452
521
  function trapFocus(event) {
@@ -785,14 +854,28 @@
785
854
  "#lvc-panel[hidden]{display:none}" +
786
855
  "#lvc-root[dir=rtl] #lvc-panel{right:auto;left:20px}" +
787
856
  "#lvc-root.lvc-no-launcher #lvc-panel{bottom:20px;max-height:calc(100dvh - 40px)}" +
788
- "#lvc-header{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;" +
789
- "padding:14px 16px;background:var(--lvc-accent);color:var(--lvc-accent-text)}" +
857
+ // position/z-index keep the header above the scrolling list, and
858
+ // flex-shrink:0 stops it collapsing — together they stop a message
859
+ // bubble from bleeding over the header's rounded bottom edge.
860
+ "#lvc-header{position:relative;z-index:2;flex-shrink:0;display:flex;align-items:flex-start;" +
861
+ "justify-content:space-between;gap:8px;padding:14px 16px;background:var(--lvc-accent);" +
862
+ "color:var(--lvc-accent-text)}" +
790
863
  "#lvc-header strong{display:block;font-size:15px}" +
791
864
  "#lvc-header span{display:block;font-size:12px;opacity:.85;margin-top:2px}" +
865
+ "#lvc-actions{display:flex;align-items:center;gap:2px}" +
792
866
  "#lvc-close{border:none;background:none;color:var(--lvc-accent-text);font-size:22px;" +
793
867
  "line-height:1;cursor:pointer;padding:2px 6px;border-radius:6px}" +
794
868
  "#lvc-close:hover{background:rgba(255,255,255,.15)}" +
795
- "#lvc-list{flex:1;overflow-y:auto;overscroll-behavior:contain;padding:14px;" +
869
+ "#lvc-root #lvc-expand{border:none;background:none;color:var(--lvc-accent-text);cursor:pointer;" +
870
+ "padding:5px 6px;border-radius:6px;display:flex;align-items:center;justify-content:center;opacity:.9}" +
871
+ "#lvc-root #lvc-expand:hover{background:rgba(255,255,255,.15);opacity:1}" +
872
+ // Desktop only: a roomier panel for long threads and image-heavy chats.
873
+ // Guarded by min-width so it can never shrink the full-screen mobile panel.
874
+ "@media(min-width:481px){#lvc-root.lvc-expanded #lvc-panel{width:min(460px,92vw);" +
875
+ "height:min(680px,88dvh);max-height:88dvh}}" +
876
+ // min-height:0 lets this flex child actually scroll within the panel
877
+ // instead of overflowing it (the classic flexbox scroll gotcha).
878
+ "#lvc-list{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:14px;" +
796
879
  "background:var(--lvc-bg);display:flex;flex-direction:column;gap:4px}" +
797
880
  // Class rules carry the #lvc-root prefix so they outrank the
798
881
  // id-level `#lvc-root *` reset above.
@@ -818,25 +901,31 @@
818
901
  "background:var(--lvc-bg);color:var(--lvc-text);font:inherit}" +
819
902
  "#lvc-email button{padding:6px 10px;border:1px solid var(--lvc-border);border-radius:8px;" +
820
903
  "background:var(--lvc-surface);color:var(--lvc-text);font:inherit;cursor:pointer}" +
821
- "#lvc-form{display:flex;gap:8px;padding:10px 12px;border-top:1px solid var(--lvc-border);" +
822
- "background:var(--lvc-surface)}" +
823
- "#lvc-form textarea{flex:1;resize:none;border:1px solid var(--lvc-border);border-radius:10px;" +
824
- "padding:8px 10px;font:inherit;background:var(--lvc-bg);color:var(--lvc-text);max-height:120px}" +
825
- "#lvc-form textarea:focus{outline:2px solid var(--lvc-accent);outline-offset:-1px}" +
826
- "#lvc-form button{border:none;border-radius:10px;background:var(--lvc-accent);" +
827
- "color:var(--lvc-accent-text);width:40px;min-width:40px;height:40px;align-self:flex-end;" +
828
- "display:flex;align-items:center;justify-content:center;cursor:pointer}" +
829
- "#lvc-form button:disabled{opacity:.6;cursor:default}" +
830
- "#lvc-root[dir=rtl] #lvc-form button svg{transform:scaleX(-1)}" +
831
- // Attach button sits alongside the send button, quieter (it's secondary).
832
- // Selector repeats the id twice so the quiet look outranks the shared
833
- // `#lvc-form button` accent-fill rule (else the paperclip goes solid blue).
834
- "#lvc-root #lvc-attach{border:none;background:none;color:var(--lvc-muted);width:38px;min-width:38px;" +
835
- "height:40px;align-self:flex-end;display:flex;align-items:center;justify-content:center;" +
836
- "cursor:pointer;border-radius:10px}" +
837
- "#lvc-root #lvc-attach:hover{background:var(--lvc-bg);color:var(--lvc-text)}" +
838
- // Pending-file chips above the composer.
839
- "#lvc-files{display:flex;flex-wrap:wrap;gap:6px;padding:10px 12px}" +
904
+ // The composer is one bordered box (Intercom-style): textarea on top, a
905
+ // toolbar row below. focus-within lights the whole box, so it reads as a
906
+ // single control.
907
+ "#lvc-form{display:flex;flex-direction:column;gap:6px;margin:10px 12px;padding:8px 10px;" +
908
+ "border:1px solid var(--lvc-border);border-radius:16px;background:var(--lvc-bg)}" +
909
+ // A single, quiet accent border on focus — no extra ring.
910
+ "#lvc-form:focus-within{border-color:var(--lvc-accent)}" +
911
+ // appearance:none flattens Safari's default textarea bevel, which would
912
+ // otherwise show as a second inset box inside the composer.
913
+ "#lvc-root #lvc-input{-webkit-appearance:none;appearance:none;border:none;background:none;" +
914
+ "resize:none;font:inherit;color:var(--lvc-text);padding:4px 4px 0;max-height:120px;outline:none}" +
915
+ "#lvc-toolbar{display:flex;align-items:center;justify-content:space-between;gap:8px}" +
916
+ "#lvc-tools{display:flex;align-items:center;gap:2px}" +
917
+ // Tool buttons (attach, and room for more) are quiet — the accent is the
918
+ // send button's alone.
919
+ "#lvc-root .lvc-tool{border:none;background:none;color:var(--lvc-muted);width:32px;height:32px;" +
920
+ "display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;padding:0}" +
921
+ "#lvc-root .lvc-tool:hover{background:var(--lvc-border);color:var(--lvc-text)}" +
922
+ "#lvc-send{border:none;border-radius:50%;background:var(--lvc-accent);color:var(--lvc-accent-text);" +
923
+ "width:32px;height:32px;min-width:32px;display:flex;align-items:center;justify-content:center;" +
924
+ "cursor:pointer;padding:0}" +
925
+ "#lvc-send:disabled{opacity:.5;cursor:default}" +
926
+ "#lvc-root[dir=rtl] #lvc-send svg{transform:scaleX(-1)}" +
927
+ // Pending-file chips ride at the top of the composer box.
928
+ "#lvc-files{display:flex;flex-wrap:wrap;gap:6px;padding:2px 2px 0}" +
840
929
  "#lvc-files[hidden]{display:none}" +
841
930
  "#lvc-root .lvc-chip{display:inline-flex;align-items:center;gap:6px;max-width:100%;" +
842
931
  "padding:4px 6px 4px 10px;border:1px solid var(--lvc-border);border-radius:999px;" +
@@ -861,10 +950,12 @@
861
950
  "#lvc-root #lvc-panel,#lvc-root[dir=rtl] #lvc-panel,#lvc-root.lvc-no-launcher #lvc-panel" +
862
951
  "{left:0;right:0;top:0;bottom:0;width:100%;max-width:100%;height:100dvh;max-height:100dvh;" +
863
952
  "border-radius:0;border:none}" +
953
+ // The panel is already full-screen here, so there's nothing to expand.
954
+ "#lvc-expand{display:none}" +
864
955
  // 16px stops iOS Safari from zoom-jumping into focused fields.
865
- "#lvc-root #lvc-form textarea,#lvc-root #lvc-email input{font-size:16px}" +
866
- // Keep the composer above the iPhone home indicator.
867
- "#lvc-root #lvc-form{padding-bottom:calc(10px + env(safe-area-inset-bottom))}" +
956
+ "#lvc-root #lvc-input,#lvc-root #lvc-email input{font-size:16px}" +
957
+ // Keep the composer box above the iPhone home indicator.
958
+ "#lvc-root #lvc-form{margin-bottom:calc(10px + env(safe-area-inset-bottom))}" +
868
959
  "}" +
869
960
  // Lives in host DOM (on data-livechat-open elements), so no #lvc-root prefix.
870
961
  ".lvc-opener-badge{display:inline-flex;min-width:18px;height:18px;padding:0 5px;" +
@@ -104,7 +104,9 @@ module Livechat
104
104
  unreadAria: t(:unread_aria, 'unread messages'),
105
105
  attach: t(:attach, 'Attach files'),
106
106
  removeFile: t(:remove_file, 'Remove file'),
107
- attachmentError: t(:attachment_error, 'Some files could not be sent.')
107
+ attachmentError: t(:attachment_error, 'Some files could not be sent.'),
108
+ expand: t(:expand, 'Expand'),
109
+ collapse: t(:collapse, 'Collapse')
108
110
  }
109
111
  end
110
112
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: livechat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yaroslav Shmarov