GuXSs commited on
Commit
39b18a9
·
verified ·
1 Parent(s): 99863fa

Fix infinite input grow: fixed textarea height, fill_height off, pin via JS

Browse files
Files changed (3) hide show
  1. app.py +9 -6
  2. static/app.css +72 -10
  3. static/app.js +33 -0
app.py CHANGED
@@ -277,7 +277,7 @@ def make_chatbot():
277
  common = dict(
278
  value=[],
279
  elem_id="nyra-chatbot",
280
- height=520,
281
  render_markdown=True,
282
  show_label=False,
283
  layout="bubble",
@@ -297,9 +297,10 @@ def build_app() -> gr.Blocks:
297
  default_lang = "pt"
298
  t0 = UI[default_lang]
299
 
 
300
  blocks_kwargs = dict(
301
  title="Nyra Chat",
302
- fill_height=True,
303
  analytics_enabled=False,
304
  elem_id="nyra-root",
305
  theme=build_theme(),
@@ -313,7 +314,7 @@ def build_app() -> gr.Blocks:
313
  except TypeError:
314
  ctx = gr.Blocks(
315
  title="Nyra Chat",
316
- fill_height=True,
317
  analytics_enabled=False,
318
  elem_id="nyra-root",
319
  )
@@ -381,16 +382,18 @@ def build_app() -> gr.Blocks:
381
 
382
  chatbot = make_chatbot()
383
 
384
- with gr.Row(elem_id="nyra-input-row"):
385
  msg = gr.Textbox(
386
  elem_id="nyra-input",
387
  placeholder=t0["placeholder"],
388
  show_label=False,
389
- lines=2,
390
- max_lines=8,
391
  scale=6,
392
  container=False,
393
  autofocus=True,
 
 
394
  )
395
  send_btn = gr.Button(
396
  t0["send"],
 
277
  common = dict(
278
  value=[],
279
  elem_id="nyra-chatbot",
280
+ height=420,
281
  render_markdown=True,
282
  show_label=False,
283
  layout="bubble",
 
297
  default_lang = "pt"
298
  t0 = UI[default_lang]
299
 
300
+ # fill_height=False: avoids flex feedback loop that makes the input grow forever
301
  blocks_kwargs = dict(
302
  title="Nyra Chat",
303
+ fill_height=False,
304
  analytics_enabled=False,
305
  elem_id="nyra-root",
306
  theme=build_theme(),
 
314
  except TypeError:
315
  ctx = gr.Blocks(
316
  title="Nyra Chat",
317
+ fill_height=False,
318
  analytics_enabled=False,
319
  elem_id="nyra-root",
320
  )
 
382
 
383
  chatbot = make_chatbot()
384
 
385
+ with gr.Row(elem_id="nyra-input-row", equal_height=True):
386
  msg = gr.Textbox(
387
  elem_id="nyra-input",
388
  placeholder=t0["placeholder"],
389
  show_label=False,
390
+ lines=1,
391
+ max_lines=1,
392
  scale=6,
393
  container=False,
394
  autofocus=True,
395
+ # Prevent Gradio auto-grow height thrashing
396
+ interactive=True,
397
  )
398
  send_btn = gr.Button(
399
  t0["send"],
static/app.css CHANGED
@@ -196,12 +196,14 @@ body::before {
196
  }
197
  }
198
 
199
- /* Sidebar */
200
  #nyra-sidebar {
201
  background: var(--nyra-graphite) !important;
202
  border-right: 1px solid var(--nyra-hairline) !important;
203
- min-height: calc(100vh - 56px);
 
204
  padding: 1rem 0.85rem !important;
 
205
  }
206
 
207
  #nyra-sidebar .gr-button,
@@ -210,11 +212,18 @@ body::before {
210
  gap: 0.5rem;
211
  }
212
 
213
- /* Main column */
214
  #nyra-main {
215
  padding: 0.5rem 1rem 1.25rem !important;
216
  max-width: calc(var(--nyra-max-chat) + 4rem);
217
  margin: 0 auto;
 
 
 
 
 
 
 
218
  }
219
 
220
  /* Empty state hero */
@@ -296,7 +305,17 @@ body::before {
296
  }
297
 
298
  #nyra-chatbot {
299
- min-height: 42vh;
 
 
 
 
 
 
 
 
 
 
300
  }
301
 
302
  /* Hide Gradio's default "Chatbot" floating label */
@@ -382,11 +401,12 @@ body::before {
382
  background: transparent;
383
  }
384
 
385
- /* Input dock */
386
  #nyra-input-row {
387
  max-width: var(--nyra-max-chat);
388
- margin: 0.5rem auto 0;
389
- padding: 0.35rem;
 
390
  border-radius: var(--nyra-radius-input);
391
  background: rgba(18, 18, 24, 0.72) !important;
392
  border: 1px solid var(--nyra-hairline) !important;
@@ -394,6 +414,14 @@ body::before {
394
  backdrop-filter: blur(16px);
395
  -webkit-backdrop-filter: blur(16px);
396
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
 
 
 
 
 
 
 
 
397
  }
398
 
399
  #nyra-input-row:focus-within {
@@ -401,23 +429,57 @@ body::before {
401
  box-shadow: var(--nyra-shadow), 0 0 0 3px rgba(245, 166, 35, 0.12);
402
  }
403
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
  #nyra-input textarea,
405
  #nyra-input input,
406
- #nyra-input .scroll-hide textarea {
 
407
  background: transparent !important;
408
  border: none !important;
409
  box-shadow: none !important;
410
  color: var(--nyra-starlight) !important;
411
  font-size: 0.98rem !important;
412
  font-family: var(--nyra-font-body) !important;
413
- padding: 0.85rem 1rem !important;
414
- min-height: 52px !important;
 
 
 
 
 
 
 
 
415
  }
416
 
417
  #nyra-input textarea::placeholder {
418
  color: var(--nyra-silver) !important;
419
  }
420
 
 
 
 
 
 
 
 
 
 
421
  /* Primary send button */
422
  #nyra-send,
423
  #nyra-send button {
 
196
  }
197
  }
198
 
199
+ /* Sidebar — no 100vh min-height (that stretches the whole page with fill flex) */
200
  #nyra-sidebar {
201
  background: var(--nyra-graphite) !important;
202
  border-right: 1px solid var(--nyra-hairline) !important;
203
+ min-height: 0 !important;
204
+ max-height: none !important;
205
  padding: 1rem 0.85rem !important;
206
+ flex: 0 0 auto !important;
207
  }
208
 
209
  #nyra-sidebar .gr-button,
 
212
  gap: 0.5rem;
213
  }
214
 
215
+ /* Main column — do not let flex children grow without bound */
216
  #nyra-main {
217
  padding: 0.5rem 1rem 1.25rem !important;
218
  max-width: calc(var(--nyra-max-chat) + 4rem);
219
  margin: 0 auto;
220
+ min-width: 0 !important;
221
+ overflow: hidden !important;
222
+ }
223
+
224
+ #nyra-main > .gap,
225
+ #nyra-main .form {
226
+ min-height: 0 !important;
227
  }
228
 
229
  /* Empty state hero */
 
305
  }
306
 
307
  #nyra-chatbot {
308
+ height: 420px !important;
309
+ max-height: 50vh !important;
310
+ min-height: 280px !important;
311
+ flex: 0 0 auto !important;
312
+ overflow: hidden !important;
313
+ }
314
+
315
+ #nyra-chatbot .wrapper,
316
+ #nyra-chatbot .bubble-wrap {
317
+ max-height: 100% !important;
318
+ overflow-y: auto !important;
319
  }
320
 
321
  /* Hide Gradio's default "Chatbot" floating label */
 
401
  background: transparent;
402
  }
403
 
404
+ /* Input dock — FIXED height; kill Gradio auto-grow infinite loop */
405
  #nyra-input-row {
406
  max-width: var(--nyra-max-chat);
407
+ width: 100%;
408
+ margin: 0.75rem auto 0 !important;
409
+ padding: 0.35rem 0.45rem !important;
410
  border-radius: var(--nyra-radius-input);
411
  background: rgba(18, 18, 24, 0.72) !important;
412
  border: 1px solid var(--nyra-hairline) !important;
 
414
  backdrop-filter: blur(16px);
415
  -webkit-backdrop-filter: blur(16px);
416
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
417
+ flex: 0 0 auto !important;
418
+ flex-grow: 0 !important;
419
+ flex-shrink: 0 !important;
420
+ align-items: center !important;
421
+ min-height: 0 !important;
422
+ max-height: 88px !important;
423
+ overflow: hidden !important;
424
+ align-self: center !important;
425
  }
426
 
427
  #nyra-input-row:focus-within {
 
429
  box-shadow: var(--nyra-shadow), 0 0 0 3px rgba(245, 166, 35, 0.12);
430
  }
431
 
432
+ /* Pin the textbox block so it cannot expand the page forever */
433
+ #nyra-input,
434
+ #nyra-input.block,
435
+ #nyra-input .form,
436
+ #nyra-input label,
437
+ #nyra-input .input-container {
438
+ flex: 1 1 auto !important;
439
+ min-height: 0 !important;
440
+ max-height: 72px !important;
441
+ height: auto !important;
442
+ overflow: hidden !important;
443
+ background: transparent !important;
444
+ border: none !important;
445
+ box-shadow: none !important;
446
+ }
447
+
448
  #nyra-input textarea,
449
  #nyra-input input,
450
+ #nyra-input .scroll-hide textarea,
451
+ #nyra-input textarea.scroll-hide {
452
  background: transparent !important;
453
  border: none !important;
454
  box-shadow: none !important;
455
  color: var(--nyra-starlight) !important;
456
  font-size: 0.98rem !important;
457
  font-family: var(--nyra-font-body) !important;
458
+ padding: 0.75rem 1rem !important;
459
+ /* CRITICAL: fixed height — Gradio auto-resize otherwise grows forever */
460
+ height: 48px !important;
461
+ min-height: 48px !important;
462
+ max-height: 48px !important;
463
+ line-height: 1.4 !important;
464
+ resize: none !important;
465
+ overflow-y: auto !important;
466
+ overflow-x: hidden !important;
467
+ field-sizing: fixed !important;
468
  }
469
 
470
  #nyra-input textarea::placeholder {
471
  color: var(--nyra-silver) !important;
472
  }
473
 
474
+ /* Send button stays aligned, never stretched */
475
+ #nyra-send,
476
+ #nyra-input-row > #nyra-send {
477
+ align-self: center !important;
478
+ flex: 0 0 auto !important;
479
+ height: 44px !important;
480
+ max-height: 44px !important;
481
+ }
482
+
483
  /* Primary send button */
484
  #nyra-send,
485
  #nyra-send button {
static/app.js CHANGED
@@ -27,17 +27,50 @@
27
  document.body.classList.toggle("nyra-has-messages", !!has);
28
  }
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  function boot() {
31
  hydrateLucide();
32
  updateEmptyState();
 
33
  var bot = document.querySelector("#nyra-chatbot");
34
  if (bot && !bot.dataset.nyraObserved) {
35
  bot.dataset.nyraObserved = "1";
36
  new MutationObserver(function () {
37
  updateEmptyState();
38
  hydrateLucide();
 
39
  }).observe(bot, { childList: true, subtree: true });
40
  }
 
 
 
 
 
 
 
 
 
 
41
  }
42
 
43
  if (document.readyState === "loading") {
 
27
  document.body.classList.toggle("nyra-has-messages", !!has);
28
  }
29
 
30
+ function pinInputHeight() {
31
+ // Gradio sometimes rewrites textarea height inline → force a fixed size
32
+ var nodes = document.querySelectorAll(
33
+ "#nyra-input textarea, #nyra-input input"
34
+ );
35
+ nodes.forEach(function (el) {
36
+ el.style.height = "48px";
37
+ el.style.minHeight = "48px";
38
+ el.style.maxHeight = "48px";
39
+ el.style.resize = "none";
40
+ el.style.overflowY = "auto";
41
+ // Stop auto-resize listeners from expanding forever
42
+ el.setAttribute("rows", "1");
43
+ });
44
+ var row = document.getElementById("nyra-input-row");
45
+ if (row) {
46
+ row.style.maxHeight = "88px";
47
+ row.style.flexGrow = "0";
48
+ }
49
+ }
50
+
51
  function boot() {
52
  hydrateLucide();
53
  updateEmptyState();
54
+ pinInputHeight();
55
  var bot = document.querySelector("#nyra-chatbot");
56
  if (bot && !bot.dataset.nyraObserved) {
57
  bot.dataset.nyraObserved = "1";
58
  new MutationObserver(function () {
59
  updateEmptyState();
60
  hydrateLucide();
61
+ pinInputHeight();
62
  }).observe(bot, { childList: true, subtree: true });
63
  }
64
+ var input = document.querySelector("#nyra-input");
65
+ if (input && !input.dataset.nyraPin) {
66
+ input.dataset.nyraPin = "1";
67
+ new MutationObserver(pinInputHeight).observe(input, {
68
+ attributes: true,
69
+ childList: true,
70
+ subtree: true,
71
+ attributeFilter: ["style", "rows"],
72
+ });
73
+ }
74
  }
75
 
76
  if (document.readyState === "loading") {