@gradio/multimodaltextbox 0.5.7 → 0.6.0-beta.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,45 @@
1
1
  # @gradio/multimodaltextbox
2
2
 
3
+ ## 0.6.0-beta.2
4
+
5
+ ### Features
6
+
7
+ - [#8966](https://github.com/gradio-app/gradio/pull/8966) [`8e52b6a`](https://github.com/gradio-app/gradio/commit/8e52b6a3e75957462bc7fdbf6ff9c280084d5f08) - Chatbot Examples. Thanks @dawoodkhan82!
8
+ - [#9339](https://github.com/gradio-app/gradio/pull/9339) [`4c8c6f2`](https://github.com/gradio-app/gradio/commit/4c8c6f2fe603081941c5fdc43f48a0632b9f31ad) - Ssr part 2. Thanks @pngwn!
9
+ - [#9280](https://github.com/gradio-app/gradio/pull/9280) [`7122420`](https://github.com/gradio-app/gradio/commit/712242047fde3a594dfde7f48a44c7ea16239dc8) - Match style of textbox stop button to submit button. Thanks @freddyaboulton!
10
+
11
+ ### Fixes
12
+
13
+ - [#9393](https://github.com/gradio-app/gradio/pull/9393) [`53ed0f0`](https://github.com/gradio-app/gradio/commit/53ed0f030551ad876a1fea28a9db9015ba6ec33e) - Fix File Types for MultimodalTextbox. Thanks @dawoodkhan82!
14
+
15
+ ### Dependency updates
16
+
17
+ - @gradio/atoms@0.9.0-beta.2
18
+ - @gradio/upload@0.13.0-beta.2
19
+ - @gradio/client@1.6.0-beta.2
20
+ - @gradio/icons@0.8.0-beta.2
21
+ - @gradio/statustracker@0.8.0-beta.2
22
+ - @gradio/utils@0.7.0-beta.2
23
+ - @gradio/image@0.16.0-beta.2
24
+ - @gradio/video@0.11.0-beta.2
25
+
26
+ ## 0.6.0-beta.1
27
+
28
+ ### Features
29
+
30
+ - [#9235](https://github.com/gradio-app/gradio/pull/9235) [`f8b411f`](https://github.com/gradio-app/gradio/commit/f8b411fe282ff0316ed4abebc0a043b044bf4dd9) - Built-in submit and stop buttons in `gr.ChatInterface(multimodal=False)`, adding `submit_btn` and `stop_btn` props to `gr.Textbox()` and `gr.MultimodalText()`. Thanks @whitphx!
31
+
32
+ ### Dependency updates
33
+
34
+ - @gradio/video@0.11.0-beta.1
35
+ - @gradio/atoms@0.8.1-beta.1
36
+ - @gradio/icons@0.8.0-beta.1
37
+ - @gradio/statustracker@0.8.0-beta.1
38
+ - @gradio/utils@0.7.0-beta.1
39
+ - @gradio/client@1.6.0-beta.1
40
+ - @gradio/image@0.16.0-beta.1
41
+ - @gradio/upload@0.12.4-beta.1
42
+
3
43
  ## 0.5.7
4
44
 
5
45
  ### Fixes
package/Example.svelte CHANGED
@@ -42,7 +42,7 @@
42
42
  {#if file.mime_type && file.mime_type.includes("image")}
43
43
  <Image src={file.url} alt="" />
44
44
  {:else if file.mime_type && file.mime_type.includes("video")}
45
- <Video src={file.url} alt="" loop={true} />
45
+ <Video src={file.url} alt="" loop={true} is_stream={false} />
46
46
  {:else if file.mime_type && file.mime_type.includes("audio")}
47
47
  <audio src={file.url} controls />
48
48
  {:else}
package/Index.svelte CHANGED
@@ -16,6 +16,7 @@
16
16
  export let gradio: Gradio<{
17
17
  change: typeof value;
18
18
  submit: never;
19
+ stop: never;
19
20
  blur: never;
20
21
  select: SelectData;
21
22
  input: never;
@@ -40,7 +41,8 @@
40
41
  export let container = true;
41
42
  export let scale: number | null = null;
42
43
  export let min_width: number | undefined = undefined;
43
- export let submit_btn: string | null = null;
44
+ export let submit_btn: string | boolean | null = null;
45
+ export let stop_btn: string | boolean | null = null;
44
46
  export let loading_status: LoadingStatus | undefined = undefined;
45
47
  export let value_is_output = false;
46
48
  export let rtl = false;
@@ -88,6 +90,7 @@
88
90
  max_lines={!max_lines ? lines + 1 : max_lines}
89
91
  {placeholder}
90
92
  {submit_btn}
93
+ {stop_btn}
91
94
  {autofocus}
92
95
  {container}
93
96
  {autoscroll}
@@ -96,6 +99,7 @@
96
99
  on:change={() => gradio.dispatch("change", value)}
97
100
  on:input={() => gradio.dispatch("input")}
98
101
  on:submit={() => gradio.dispatch("submit")}
102
+ on:stop={() => gradio.dispatch("stop")}
99
103
  on:blur={() => gradio.dispatch("blur")}
100
104
  on:select={(e) => gradio.dispatch("select", e.detail)}
101
105
  on:focus={() => gradio.dispatch("focus")}
@@ -103,15 +107,7 @@
103
107
  gradio.dispatch("error", detail);
104
108
  }}
105
109
  disabled={!interactive}
106
- upload={gradio.client.upload}
107
- stream_handler={gradio.client.stream}
110
+ upload={(...args) => gradio.client.upload(...args)}
111
+ stream_handler={(...args) => gradio.client.stream(...args)}
108
112
  />
109
113
  </Block>
110
-
111
- <style>
112
- :global(.form .block.multimodal-textbox) {
113
- box-shadow: var(--block-shadow) !important;
114
- border-width: var(--block-border-width) !important;
115
- border-radius: var(--block-radius) !important;
116
- }
117
- </style>
@@ -37,7 +37,7 @@ onMount(() => {
37
37
  {#if file.mime_type && file.mime_type.includes("image")}
38
38
  <Image src={file.url} alt="" />
39
39
  {:else if file.mime_type && file.mime_type.includes("video")}
40
- <Video src={file.url} alt="" loop={true} />
40
+ <Video src={file.url} alt="" loop={true} is_stream={false} />
41
41
  {:else if file.mime_type && file.mime_type.includes("audio")}
42
42
  <audio src={file.url} controls />
43
43
  {:else}
package/dist/Index.svelte CHANGED
@@ -26,6 +26,7 @@ export let container = true;
26
26
  export let scale = null;
27
27
  export let min_width = void 0;
28
28
  export let submit_btn = null;
29
+ export let stop_btn = null;
29
30
  export let loading_status = void 0;
30
31
  export let value_is_output = false;
31
32
  export let rtl = false;
@@ -72,6 +73,7 @@ let dragging;
72
73
  max_lines={!max_lines ? lines + 1 : max_lines}
73
74
  {placeholder}
74
75
  {submit_btn}
76
+ {stop_btn}
75
77
  {autofocus}
76
78
  {container}
77
79
  {autoscroll}
@@ -80,6 +82,7 @@ let dragging;
80
82
  on:change={() => gradio.dispatch("change", value)}
81
83
  on:input={() => gradio.dispatch("input")}
82
84
  on:submit={() => gradio.dispatch("submit")}
85
+ on:stop={() => gradio.dispatch("stop")}
83
86
  on:blur={() => gradio.dispatch("blur")}
84
87
  on:select={(e) => gradio.dispatch("select", e.detail)}
85
88
  on:focus={() => gradio.dispatch("focus")}
@@ -87,15 +90,7 @@ let dragging;
87
90
  gradio.dispatch("error", detail);
88
91
  }}
89
92
  disabled={!interactive}
90
- upload={gradio.client.upload}
91
- stream_handler={gradio.client.stream}
93
+ upload={(...args) => gradio.client.upload(...args)}
94
+ stream_handler={(...args) => gradio.client.stream(...args)}
92
95
  />
93
96
  </Block>
94
-
95
- <style>
96
- :global(.form .block.multimodal-textbox) {
97
- box-shadow: var(--block-shadow) !important;
98
- border-width: var(--block-border-width) !important;
99
- border-radius: var(--block-radius) !important;
100
- }
101
- </style>
@@ -12,6 +12,7 @@ declare const __propDef: {
12
12
  files: FileData[];
13
13
  };
14
14
  submit: never;
15
+ stop: never;
15
16
  blur: never;
16
17
  select: SelectData;
17
18
  input: never;
@@ -36,7 +37,8 @@ declare const __propDef: {
36
37
  container?: boolean | undefined;
37
38
  scale?: (number | null) | undefined;
38
39
  min_width?: number | undefined;
39
- submit_btn?: (string | null) | undefined;
40
+ submit_btn?: (string | boolean | null) | undefined;
41
+ stop_btn?: (string | boolean | null) | undefined;
40
42
  loading_status?: LoadingStatus | undefined;
41
43
  value_is_output?: boolean | undefined;
42
44
  rtl?: boolean | undefined;
@@ -62,6 +64,7 @@ export default class Index extends SvelteComponent<IndexProps, IndexEvents, Inde
62
64
  files: FileData[];
63
65
  };
64
66
  submit: never;
67
+ stop: never;
65
68
  blur: never;
66
69
  select: SelectData;
67
70
  input: never;
@@ -76,6 +79,7 @@ export default class Index extends SvelteComponent<IndexProps, IndexEvents, Inde
76
79
  files: FileData[];
77
80
  };
78
81
  submit: never;
82
+ stop: never;
79
83
  blur: never;
80
84
  select: SelectData;
81
85
  input: never;
@@ -131,9 +135,12 @@ export default class Index extends SvelteComponent<IndexProps, IndexEvents, Inde
131
135
  get min_width(): number | undefined;
132
136
  /**accessor*/
133
137
  set min_width(_: number | undefined);
134
- get submit_btn(): string | null | undefined;
138
+ get submit_btn(): string | boolean | null | undefined;
135
139
  /**accessor*/
136
- set submit_btn(_: string | null | undefined);
140
+ set submit_btn(_: string | boolean | null | undefined);
141
+ get stop_btn(): string | boolean | null | undefined;
142
+ /**accessor*/
143
+ set stop_btn(_: string | boolean | null | undefined);
137
144
  get loading_status(): LoadingStatus | undefined;
138
145
  /**accessor*/
139
146
  set loading_status(_: LoadingStatus | undefined);
@@ -8,7 +8,15 @@ import { text_area_resize, resize } from "../shared/utils";
8
8
  import { BlockTitle } from "@gradio/atoms";
9
9
  import { Upload } from "@gradio/upload";
10
10
  import { Image } from "@gradio/image/shared";
11
- import { Clear, File, Music, Paperclip, Video, Send } from "@gradio/icons";
11
+ import {
12
+ Clear,
13
+ File,
14
+ Music,
15
+ Paperclip,
16
+ Video,
17
+ Send,
18
+ Square
19
+ } from "@gradio/icons";
12
20
  export let value = {
13
21
  text: "",
14
22
  files: []
@@ -23,6 +31,7 @@ export let show_label = true;
23
31
  export let container = true;
24
32
  export let max_lines;
25
33
  export let submit_btn = null;
34
+ export let stop_btn = null;
26
35
  export let rtl = false;
27
36
  export let autofocus = false;
28
37
  export let text_align = void 0;
@@ -50,18 +59,6 @@ $:
50
59
  dispatch("change", value);
51
60
  oldValue = value.text;
52
61
  }
53
- let accept_file_types;
54
- if (file_types == null) {
55
- accept_file_types = null;
56
- } else {
57
- file_types = file_types.map((x) => {
58
- if (x.startsWith(".")) {
59
- return x;
60
- }
61
- return x + "/*";
62
- });
63
- accept_file_types = file_types.join(", ");
64
- }
65
62
  $:
66
63
  if (value === null)
67
64
  value = { text: "", files: [] };
@@ -152,7 +149,10 @@ function handle_upload_click() {
152
149
  hidden_upload.click();
153
150
  }
154
151
  }
155
- async function handle_submit() {
152
+ function handle_stop() {
153
+ dispatch("stop");
154
+ }
155
+ function handle_submit() {
156
156
  dispatch("submit");
157
157
  }
158
158
  function handle_paste(event) {
@@ -249,6 +249,7 @@ function handle_drop(event) {
249
249
  bind:this={upload_component}
250
250
  on:load={handle_upload}
251
251
  {file_count}
252
+ filetype={file_types}
252
253
  {root}
253
254
  {max_file_size}
254
255
  bind:dragging
@@ -274,6 +275,7 @@ function handle_drop(event) {
274
275
  max_lines: max_lines
275
276
  }}
276
277
  class="scroll-hide"
278
+ class:no-label={!show_label}
277
279
  dir={rtl ? "rtl" : "ltr"}
278
280
  bind:value={value.text}
279
281
  bind:this={el}
@@ -298,7 +300,20 @@ function handle_drop(event) {
298
300
  {#if submit_btn === true}
299
301
  <Send />
300
302
  {:else}
301
- Hello World
303
+ {submit_btn}
304
+ {/if}
305
+ </button>
306
+ {/if}
307
+ {#if stop_btn}
308
+ <button
309
+ class="stop-button"
310
+ class:padded-button={stop_btn !== true}
311
+ on:click={handle_stop}
312
+ >
313
+ {#if stop_btn === true}
314
+ <Square fill={"none"} stroke_width={2.5} />
315
+ {:else}
316
+ {stop_btn}
302
317
  {/if}
303
318
  </button>
304
319
  {/if}
@@ -344,6 +359,10 @@ function handle_drop(event) {
344
359
  position: relative;
345
360
  z-index: 1;
346
361
  }
362
+ textarea.no-label {
363
+ padding-top: 5px;
364
+ padding-bottom: 5px;
365
+ }
347
366
 
348
367
  textarea:disabled {
349
368
  -webkit-opacity: 1;
@@ -355,9 +374,8 @@ function handle_drop(event) {
355
374
  }
356
375
 
357
376
  .upload-button,
358
- .submit-button {
359
- background: var(--button-secondary-background-fill);
360
- color: var(--button-secondary-text-color);
377
+ .submit-button,
378
+ .stop-button {
361
379
  border: none;
362
380
  text-align: center;
363
381
  text-decoration: none;
@@ -370,18 +388,25 @@ function handle_drop(event) {
370
388
  display: flex;
371
389
  justify-content: center;
372
390
  align-items: center;
373
- margin-bottom: 5px;
374
391
  z-index: var(--layer-1);
375
392
  }
376
393
  .padded-button {
377
394
  padding: 0 10px;
378
395
  }
379
396
 
397
+ .stop-button,
398
+ .upload-button,
399
+ .submit-button {
400
+ background: var(--button-secondary-background-fill);
401
+ }
402
+
403
+ .stop-button:hover,
380
404
  .upload-button:hover,
381
405
  .submit-button:hover {
382
406
  background: var(--button-secondary-background-fill-hover);
383
407
  }
384
408
 
409
+ .stop-button:active,
385
410
  .upload-button:active,
386
411
  .submit-button:active {
387
412
  box-shadow: var(--button-shadow-active);
@@ -396,6 +421,11 @@ function handle_drop(event) {
396
421
  width: 17px;
397
422
  }
398
423
 
424
+ .stop-button :global(svg) {
425
+ height: 16px;
426
+ width: 16px;
427
+ }
428
+
399
429
  .loader {
400
430
  display: flex;
401
431
  justify-content: center;
@@ -432,6 +462,7 @@ function handle_drop(event) {
432
462
  gap: var(--spacing-lg);
433
463
  overflow-x: scroll;
434
464
  padding-top: var(--spacing-sm);
465
+ margin-bottom: 6px;
435
466
  }
436
467
 
437
468
  .thumbnail-item {
@@ -17,6 +17,7 @@ declare const __propDef: {
17
17
  container?: boolean | undefined;
18
18
  max_lines: number;
19
19
  submit_btn?: (string | boolean | null) | undefined;
20
+ stop_btn?: (string | boolean | null) | undefined;
20
21
  rtl?: boolean | undefined;
21
22
  autofocus?: boolean | undefined;
22
23
  text_align?: "left" | "right" | undefined;
@@ -39,6 +40,7 @@ declare const __propDef: {
39
40
  files: FileData[];
40
41
  }>;
41
42
  submit: CustomEvent<undefined>;
43
+ stop: CustomEvent<undefined>;
42
44
  select: CustomEvent<SelectData>;
43
45
  input: CustomEvent<undefined>;
44
46
  drag: CustomEvent<boolean>;
@@ -3,12 +3,14 @@ export async function resize(target, lines, max_lines) {
3
3
  await tick();
4
4
  if (lines === max_lines)
5
5
  return;
6
+ const computed_styles = window.getComputedStyle(target);
7
+ const padding_top = parseFloat(computed_styles.paddingTop);
8
+ const padding_bottom = parseFloat(computed_styles.paddingBottom);
9
+ const line_height = parseFloat(computed_styles.lineHeight);
6
10
  let max = max_lines === undefined
7
11
  ? false
8
- : max_lines === undefined // default
9
- ? 21 * 11
10
- : 21 * (max_lines + 1);
11
- let min = 21 * (lines + 1);
12
+ : padding_top + padding_bottom + line_height * max_lines;
13
+ let min = padding_top + padding_bottom + lines * line_height;
12
14
  target.style.height = "1px";
13
15
  let scroll_height;
14
16
  if (max && target.scrollHeight > max) {
@@ -26,11 +28,14 @@ export function text_area_resize(_el, _value) {
26
28
  if (_value.lines === _value.max_lines)
27
29
  return;
28
30
  _el.style.overflowY = "scroll";
29
- _el.addEventListener("input", (event) => resize(event.target, _value.lines, _value.max_lines));
31
+ function handle_input(event) {
32
+ resize(event.target, _value.lines, _value.max_lines);
33
+ }
34
+ _el.addEventListener("input", handle_input);
30
35
  if (!_value.text.trim())
31
36
  return;
32
37
  resize(_el, _value.lines, _value.max_lines);
33
38
  return {
34
- destroy: () => _el.removeEventListener("input", (e) => resize(e.target, _value.lines, _value.max_lines))
39
+ destroy: () => _el.removeEventListener("input", handle_input)
35
40
  };
36
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradio/multimodaltextbox",
3
- "version": "0.5.7",
3
+ "version": "0.6.0-beta.2",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
@@ -22,14 +22,14 @@
22
22
  "./package.json": "./package.json"
23
23
  },
24
24
  "dependencies": {
25
- "@gradio/atoms": "^0.8.1",
26
- "@gradio/icons": "^0.7.2",
27
- "@gradio/statustracker": "^0.7.6",
28
- "@gradio/utils": "^0.6.1",
29
- "@gradio/upload": "^0.12.4",
30
- "@gradio/image": "^0.15.1",
31
- "@gradio/video": "^0.10.4",
32
- "@gradio/client": "^1.5.2"
25
+ "@gradio/atoms": "^0.9.0-beta.2",
26
+ "@gradio/statustracker": "^0.8.0-beta.2",
27
+ "@gradio/utils": "^0.7.0-beta.2",
28
+ "@gradio/upload": "^0.13.0-beta.2",
29
+ "@gradio/icons": "^0.8.0-beta.2",
30
+ "@gradio/video": "^0.11.0-beta.2",
31
+ "@gradio/client": "^1.6.0-beta.2",
32
+ "@gradio/image": "^0.16.0-beta.2"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@gradio/preview": "^0.11.1"
@@ -10,7 +10,15 @@
10
10
  import { Upload } from "@gradio/upload";
11
11
  import { Image } from "@gradio/image/shared";
12
12
  import type { FileData, Client } from "@gradio/client";
13
- import { Clear, File, Music, Paperclip, Video, Send } from "@gradio/icons";
13
+ import {
14
+ Clear,
15
+ File,
16
+ Music,
17
+ Paperclip,
18
+ Video,
19
+ Send,
20
+ Square
21
+ } from "@gradio/icons";
14
22
  import type { SelectData } from "@gradio/utils";
15
23
 
16
24
  export let value: { text: string; files: FileData[] } = {
@@ -28,6 +36,7 @@
28
36
  export let container = true;
29
37
  export let max_lines: number;
30
38
  export let submit_btn: string | boolean | null = null;
39
+ export let stop_btn: string | boolean | null = null;
31
40
  export let rtl = false;
32
41
  export let autofocus = false;
33
42
  export let text_align: "left" | "right" | undefined = undefined;
@@ -56,18 +65,6 @@
56
65
  dispatch("change", value);
57
66
  oldValue = value.text;
58
67
  }
59
- let accept_file_types: string | null;
60
- if (file_types == null) {
61
- accept_file_types = null;
62
- } else {
63
- file_types = file_types.map((x) => {
64
- if (x.startsWith(".")) {
65
- return x;
66
- }
67
- return x + "/*";
68
- });
69
- accept_file_types = file_types.join(", ");
70
- }
71
68
 
72
69
  $: if (value === null) value = { text: "", files: [] };
73
70
  $: value, el && lines !== max_lines && resize(el, lines, max_lines);
@@ -75,6 +72,7 @@
75
72
  const dispatch = createEventDispatcher<{
76
73
  change: typeof value;
77
74
  submit: undefined;
75
+ stop: undefined;
78
76
  blur: undefined;
79
77
  select: SelectData;
80
78
  input: undefined;
@@ -188,7 +186,11 @@
188
186
  }
189
187
  }
190
188
 
191
- async function handle_submit(): Promise<void> {
189
+ function handle_stop(): void {
190
+ dispatch("stop");
191
+ }
192
+
193
+ function handle_submit(): void {
192
194
  dispatch("submit");
193
195
  }
194
196
 
@@ -292,6 +294,7 @@
292
294
  bind:this={upload_component}
293
295
  on:load={handle_upload}
294
296
  {file_count}
297
+ filetype={file_types}
295
298
  {root}
296
299
  {max_file_size}
297
300
  bind:dragging
@@ -317,6 +320,7 @@
317
320
  max_lines: max_lines
318
321
  }}
319
322
  class="scroll-hide"
323
+ class:no-label={!show_label}
320
324
  dir={rtl ? "rtl" : "ltr"}
321
325
  bind:value={value.text}
322
326
  bind:this={el}
@@ -341,7 +345,20 @@
341
345
  {#if submit_btn === true}
342
346
  <Send />
343
347
  {:else}
344
- Hello World
348
+ {submit_btn}
349
+ {/if}
350
+ </button>
351
+ {/if}
352
+ {#if stop_btn}
353
+ <button
354
+ class="stop-button"
355
+ class:padded-button={stop_btn !== true}
356
+ on:click={handle_stop}
357
+ >
358
+ {#if stop_btn === true}
359
+ <Square fill={"none"} stroke_width={2.5} />
360
+ {:else}
361
+ {stop_btn}
345
362
  {/if}
346
363
  </button>
347
364
  {/if}
@@ -387,6 +404,10 @@
387
404
  position: relative;
388
405
  z-index: 1;
389
406
  }
407
+ textarea.no-label {
408
+ padding-top: 5px;
409
+ padding-bottom: 5px;
410
+ }
390
411
 
391
412
  textarea:disabled {
392
413
  -webkit-opacity: 1;
@@ -398,9 +419,8 @@
398
419
  }
399
420
 
400
421
  .upload-button,
401
- .submit-button {
402
- background: var(--button-secondary-background-fill);
403
- color: var(--button-secondary-text-color);
422
+ .submit-button,
423
+ .stop-button {
404
424
  border: none;
405
425
  text-align: center;
406
426
  text-decoration: none;
@@ -413,18 +433,25 @@
413
433
  display: flex;
414
434
  justify-content: center;
415
435
  align-items: center;
416
- margin-bottom: 5px;
417
436
  z-index: var(--layer-1);
418
437
  }
419
438
  .padded-button {
420
439
  padding: 0 10px;
421
440
  }
422
441
 
442
+ .stop-button,
443
+ .upload-button,
444
+ .submit-button {
445
+ background: var(--button-secondary-background-fill);
446
+ }
447
+
448
+ .stop-button:hover,
423
449
  .upload-button:hover,
424
450
  .submit-button:hover {
425
451
  background: var(--button-secondary-background-fill-hover);
426
452
  }
427
453
 
454
+ .stop-button:active,
428
455
  .upload-button:active,
429
456
  .submit-button:active {
430
457
  box-shadow: var(--button-shadow-active);
@@ -439,6 +466,11 @@
439
466
  width: 17px;
440
467
  }
441
468
 
469
+ .stop-button :global(svg) {
470
+ height: 16px;
471
+ width: 16px;
472
+ }
473
+
442
474
  .loader {
443
475
  display: flex;
444
476
  justify-content: center;
@@ -475,6 +507,7 @@
475
507
  gap: var(--spacing-lg);
476
508
  overflow-x: scroll;
477
509
  padding-top: var(--spacing-sm);
510
+ margin-bottom: 6px;
478
511
  }
479
512
 
480
513
  .thumbnail-item {
package/shared/utils.ts CHANGED
@@ -14,13 +14,16 @@ export async function resize(
14
14
  await tick();
15
15
  if (lines === max_lines) return;
16
16
 
17
+ const computed_styles = window.getComputedStyle(target);
18
+ const padding_top = parseFloat(computed_styles.paddingTop);
19
+ const padding_bottom = parseFloat(computed_styles.paddingBottom);
20
+ const line_height = parseFloat(computed_styles.lineHeight);
21
+
17
22
  let max =
18
23
  max_lines === undefined
19
24
  ? false
20
- : max_lines === undefined // default
21
- ? 21 * 11
22
- : 21 * (max_lines + 1);
23
- let min = 21 * (lines + 1);
25
+ : padding_top + padding_bottom + line_height * max_lines;
26
+ let min = padding_top + padding_bottom + lines * line_height;
24
27
 
25
28
  target.style.height = "1px";
26
29
 
@@ -42,17 +45,16 @@ export function text_area_resize(
42
45
  ): any | undefined {
43
46
  if (_value.lines === _value.max_lines) return;
44
47
  _el.style.overflowY = "scroll";
45
- _el.addEventListener("input", (event: Event) =>
46
- resize(event.target as HTMLTextAreaElement, _value.lines, _value.max_lines)
47
- );
48
+
49
+ function handle_input(event: Event): void {
50
+ resize(event.target as HTMLTextAreaElement, _value.lines, _value.max_lines);
51
+ }
52
+ _el.addEventListener("input", handle_input);
48
53
 
49
54
  if (!_value.text.trim()) return;
50
55
  resize(_el, _value.lines, _value.max_lines);
51
56
 
52
57
  return {
53
- destroy: () =>
54
- _el.removeEventListener("input", (e: Event) =>
55
- resize(e.target as HTMLTextAreaElement, _value.lines, _value.max_lines)
56
- )
58
+ destroy: () => _el.removeEventListener("input", handle_input)
57
59
  };
58
60
  }