@gradio/dataframe 0.23.1 → 0.23.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.
@@ -8,20 +8,87 @@ export function create_column_measurement(opts) {
8
8
  let header_height = $state(0);
9
9
  // use offsets (not just widths) avoids accumulated subpixel rounding errors
10
10
  let col_lefts = $state([]);
11
+ function resolve_user_width(raw, vw) {
12
+ if (!raw || raw === "auto")
13
+ return null;
14
+ if (raw.endsWith("%")) {
15
+ const pct = parseFloat(raw);
16
+ if (!isFinite(pct) || vw <= 0)
17
+ return null;
18
+ return (pct / 100) * vw;
19
+ }
20
+ if (raw.endsWith("px")) {
21
+ const n = parseFloat(raw);
22
+ return isFinite(n) ? n : null;
23
+ }
24
+ const n = parseFloat(raw);
25
+ return isFinite(n) ? n : null;
26
+ }
27
+ function clear_pin(el) {
28
+ if (el.style.width)
29
+ el.style.width = "";
30
+ if (el.style.minWidth)
31
+ el.style.minWidth = "";
32
+ if (el.style.maxWidth)
33
+ el.style.maxWidth = "";
34
+ }
35
+ function pin(el, target) {
36
+ if (el.style.width !== target)
37
+ el.style.width = target;
38
+ if (el.style.minWidth !== target)
39
+ el.style.minWidth = target;
40
+ if (el.style.maxWidth !== target)
41
+ el.style.maxWidth = target;
42
+ }
11
43
  function measure() {
12
44
  const current_row_el = opts.header_row_el();
13
45
  const current_table_el = opts.header_table_el();
14
- if (!current_row_el)
46
+ if (!current_row_el || !current_table_el)
15
47
  return;
16
- const cells = current_row_el.querySelectorAll(".header-cell");
17
- const table_rect = current_table_el?.getBoundingClientRect();
18
- const table_left = table_rect?.left ?? 0;
19
- col_lefts = Array.from(cells).map((c) => c.getBoundingClientRect().left - table_left);
20
- col_widths = Array.from(cells).map((c) => c.getBoundingClientRect().width);
21
- if (current_table_el) {
22
- total_header_width = table_rect?.width ?? 0;
23
- header_height = table_rect?.height ?? 0;
48
+ const cells = Array.from(current_row_el.querySelectorAll(".header-cell"));
49
+ // sizing-body mirrors the data columns to give auto-layout a read on
50
+ // body-content widths. we also pin its cells so user widths are
51
+ // honored exactly (otherwise the sizing row's nowrap min-content
52
+ // forces the column wider than the user asked for).
53
+ const sizing_tds_all = Array.from(current_table_el.querySelectorAll(".sizing-body > tr > td"));
54
+ const sizing_data_tds = opts.show_row_numbers()
55
+ ? sizing_tds_all.slice(1)
56
+ : sizing_tds_all;
57
+ cells.forEach(clear_pin);
58
+ sizing_data_tds.forEach(clear_pin);
59
+ current_table_el.style.width = "auto";
60
+ current_table_el.getBoundingClientRect(); // force layout flush
61
+ const vw = opts.viewport_width();
62
+ const user_widths = opts.column_widths();
63
+ const next_widths = cells.map((cell, i) => {
64
+ const resolved = resolve_user_width(user_widths[i], vw);
65
+ if (resolved != null)
66
+ return resolved;
67
+ // cap auto-sized columns at the viewport so a single column
68
+ // can never be wider than the visible scroll area
69
+ const measured = cell.getBoundingClientRect().width;
70
+ return vw > 0 ? Math.min(measured, vw) : measured;
71
+ });
72
+ cells.forEach((cell, i) => pin(cell, `${next_widths[i]}px`));
73
+ sizing_data_tds.forEach((cell, i) => {
74
+ if (next_widths[i] == null)
75
+ return;
76
+ pin(cell, `${next_widths[i]}px`);
77
+ });
78
+ // set the table width to the sum of columns so auto-layout
79
+ // has no extra space to redistribute
80
+ let table_w = next_widths.reduce((a, b) => a + b, 0);
81
+ if (opts.show_row_numbers()) {
82
+ const rn = current_row_el.querySelector(".row-number-header");
83
+ if (rn)
84
+ table_w += rn.getBoundingClientRect().width;
24
85
  }
86
+ current_table_el.style.width = `${table_w}px`;
87
+ const after_rect = current_table_el.getBoundingClientRect();
88
+ col_lefts = cells.map((c) => c.getBoundingClientRect().left - after_rect.left);
89
+ col_widths = next_widths;
90
+ total_header_width = after_rect.width;
91
+ header_height = after_rect.height;
25
92
  opts.on_resize?.();
26
93
  }
27
94
  $effect(() => {
@@ -40,6 +107,11 @@ export function create_column_measurement(opts) {
40
107
  cells.forEach((cell) => ro.observe(cell));
41
108
  return () => ro.disconnect();
42
109
  });
110
+ $effect(() => {
111
+ opts.viewport_width();
112
+ opts.column_widths();
113
+ measure();
114
+ });
43
115
  let row_num_width = $derived.by(() => {
44
116
  if (!opts.show_row_numbers())
45
117
  return 0;
@@ -53,10 +125,11 @@ export function create_column_measurement(opts) {
53
125
  if (col_widths[index] !== undefined) {
54
126
  return `width: ${col_widths[index]}px; flex: 0 0 ${col_widths[index]}px;`;
55
127
  }
56
- const user_widths = opts.column_widths();
57
- if (user_widths[index])
58
- return `width: ${user_widths[index]};`;
59
- return "width: 150px;";
128
+ const resolved = resolve_user_width(opts.column_widths()[index], opts.viewport_width());
129
+ if (resolved != null) {
130
+ return `width: ${resolved}px; flex: 0 0 ${resolved}px;`;
131
+ }
132
+ return "width: 150px; flex: 0 0 150px;";
60
133
  }
61
134
  return {
62
135
  get col_widths() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradio/dataframe",
3
- "version": "0.23.1",
3
+ "version": "0.23.2",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
@@ -15,15 +15,15 @@
15
15
  "dequal": "^2.0.3",
16
16
  "@tanstack/table-core": "^8.21.3",
17
17
  "@tanstack/virtual-core": "^3.13.6",
18
- "@gradio/atoms": "^0.23.1",
19
- "@gradio/checkbox": "^0.6.7",
18
+ "@gradio/atoms": "^0.24.0",
19
+ "@gradio/checkbox": "^0.7.0",
20
20
  "@gradio/client": "^2.2.0",
21
- "@gradio/icons": "^0.15.1",
22
21
  "@gradio/button": "^0.6.6",
22
+ "@gradio/icons": "^0.15.1",
23
23
  "@gradio/markdown-code": "^0.7.0",
24
- "@gradio/statustracker": "^0.14.0",
25
- "@gradio/upload": "^0.17.8",
26
- "@gradio/utils": "^0.12.2"
24
+ "@gradio/statustracker": "^0.14.1",
25
+ "@gradio/utils": "^0.12.2",
26
+ "@gradio/upload": "^0.17.9"
27
27
  },
28
28
  "exports": {
29
29
  ".": {
@@ -34,7 +34,6 @@
34
34
  justify-content: center;
35
35
  width: min-content;
36
36
  height: var(--size-full);
37
- margin: 0 auto;
38
37
  }
39
38
 
40
39
  .bool-cell :global(input:disabled) {
@@ -20,6 +20,7 @@
20
20
  show_menu_button = false,
21
21
  show_selection_buttons = false,
22
22
  is_first_column = false,
23
+ is_solo = false,
23
24
  latex_delimiters,
24
25
  line_breaks = true,
25
26
  editable = true,
@@ -50,6 +51,7 @@
50
51
  show_menu_button?: boolean;
51
52
  show_selection_buttons?: boolean;
52
53
  is_first_column?: boolean;
54
+ is_solo?: boolean;
53
55
  latex_delimiters: { left: string; right: string; display: boolean }[];
54
56
  line_breaks?: boolean;
55
57
  editable?: boolean;
@@ -71,21 +73,38 @@
71
73
  } = $props();
72
74
 
73
75
  let is_selected = $derived(selection_classes !== "");
76
+
77
+ // lock the cell-wrap's height to its pre-selection value so the
78
+ // row doesn't shift when the span goes position: absolute.
79
+ let wrap_el: HTMLDivElement | undefined = $state();
80
+ let locked_height = $state("");
81
+
82
+ // pre is weird but runs _before_ DOM updates
83
+ $effect.pre(() => {
84
+ if (is_solo && wrap_el) {
85
+ locked_height = `height: ${wrap_el.offsetHeight}px;`;
86
+ } else {
87
+ locked_height = "";
88
+ }
89
+ });
74
90
  </script>
75
91
 
76
92
  <div
77
93
  class="body-cell {selection_classes}"
78
94
  class:flash={is_flash}
79
95
  class:first-column={is_first_column}
96
+ class:static={is_static}
97
+ class:cell-solo={is_solo}
80
98
  data-row={row_idx}
81
99
  data-col={col_idx}
82
100
  data-testid={`cell-${row_idx}-${col_idx}`}
101
+ tabindex={is_static ? -1 : undefined}
83
102
  {onmousedown}
84
103
  {ondblclick}
85
104
  {oncontextmenu}
86
105
  style="{col_style} {cell_style}"
87
106
  >
88
- <div class="cell-wrap">
107
+ <div class="cell-wrap" bind:this={wrap_el} style={locked_height}>
89
108
  <EditableCell
90
109
  {value}
91
110
  {display_value}
@@ -105,6 +124,7 @@
105
124
  {on_select_row}
106
125
  {is_dragging}
107
126
  {wrap_text}
127
+ expanded={is_solo}
108
128
  />
109
129
  {#if show_menu_button}
110
130
  <CellMenuButton on_click={on_menu_click} />
@@ -120,8 +140,14 @@
120
140
  inset 1px 0 0 var(--border-color-primary),
121
141
  inset 0 0 0 1px var(--ring-color);
122
142
  padding: 0;
123
- overflow: visible;
143
+ overflow: hidden;
124
144
  box-sizing: border-box;
145
+ user-select: none;
146
+ min-width: 0;
147
+ }
148
+
149
+ .body-cell.static {
150
+ user-select: text;
125
151
  }
126
152
 
127
153
  .body-cell.first-column {
@@ -145,6 +171,65 @@
145
171
  position: relative;
146
172
  }
147
173
 
174
+ .body-cell.cell-solo {
175
+ z-index: 10;
176
+ overflow: visible;
177
+ }
178
+
179
+ .body-cell.cell-solo .cell-wrap {
180
+ overflow: visible;
181
+ }
182
+
183
+ .body-cell.cell-solo :global(.cell-wrap > span) {
184
+ position: absolute;
185
+ top: 0;
186
+ left: 0;
187
+ width: 100%;
188
+ min-height: 100%;
189
+ padding: var(--size-2);
190
+ box-sizing: border-box;
191
+ white-space: normal;
192
+ overflow: visible;
193
+ text-overflow: clip;
194
+ overflow-wrap: break-word;
195
+ word-break: break-word;
196
+ background: var(--background-fill-primary);
197
+ box-shadow:
198
+ inset 0 2px 0 0 var(--color-accent),
199
+ inset 0 -2px 0 0 var(--color-accent),
200
+ inset 2px 0 0 0 var(--color-accent),
201
+ inset -2px 0 0 0 var(--color-accent),
202
+ 0 6px 12px -4px rgba(0, 0, 0, 0.22);
203
+ z-index: 1;
204
+ }
205
+
206
+ .body-cell.cell-solo :global(.cell-wrap > textarea) {
207
+ position: absolute;
208
+ top: 0;
209
+ left: 0;
210
+ width: 100%;
211
+ min-height: 100%;
212
+ padding: var(--size-2);
213
+ padding-left: var(--size-2);
214
+ margin: 0;
215
+ box-sizing: border-box;
216
+ transform: none;
217
+ background: var(--background-fill-primary);
218
+ box-shadow:
219
+ inset 0 2px 0 0 var(--color-accent),
220
+ inset 0 -2px 0 0 var(--color-accent),
221
+ inset 2px 0 0 0 var(--color-accent),
222
+ inset -2px 0 0 0 var(--color-accent),
223
+ 0 6px 12px -4px rgba(0, 0, 0, 0.22);
224
+ z-index: 2;
225
+ field-sizing: content;
226
+ height: auto;
227
+ }
228
+
229
+ .body-cell.cell-solo :global(.selection-button) {
230
+ z-index: 3;
231
+ }
232
+
148
233
  .body-cell.cell-selected.no-top {
149
234
  --sel-top: inset 0 0 0 0 transparent;
150
235
  }
@@ -182,7 +267,7 @@
182
267
  padding: var(--size-2);
183
268
  box-sizing: border-box;
184
269
  gap: var(--size-1);
185
- overflow: visible;
270
+ overflow: hidden;
186
271
  min-width: 0;
187
272
  height: 100%;
188
273
  }
@@ -21,13 +21,15 @@
21
21
  i18n,
22
22
  is_dragging = false,
23
23
  wrap_text = false,
24
+ expanded = false,
24
25
  show_selection_buttons = false,
25
26
  coords,
26
27
  on_select_column = null,
27
28
  on_select_row = null,
28
29
  el = $bindable(null),
29
30
  onblur,
30
- onkeydown
31
+ onkeydown,
32
+ pad_left = false
31
33
  }: {
32
34
  edit: boolean;
33
35
  value?: CellValue;
@@ -55,6 +57,7 @@
55
57
  i18n: I18nFormatter;
56
58
  is_dragging?: boolean;
57
59
  wrap_text?: boolean;
60
+ expanded?: boolean;
58
61
  show_selection_buttons?: boolean;
59
62
  coords: [number, number];
60
63
  on_select_column?: ((col: number) => void) | null;
@@ -65,6 +68,7 @@
65
68
  coords: [number, number];
66
69
  }) => void;
67
70
  onkeydown?: (event: KeyboardEvent) => void;
71
+ pad_left: boolean;
68
72
  } = $props();
69
73
 
70
74
  function truncate_text(
@@ -79,7 +83,9 @@
79
83
  return str.slice(0, max_length) + "...";
80
84
  }
81
85
 
82
- let should_truncate = $derived(!edit && max_chars !== null && max_chars > 0);
86
+ let should_truncate = $derived(
87
+ !edit && !expanded && max_chars !== null && max_chars > 0
88
+ );
83
89
 
84
90
  let display_content = $derived(
85
91
  editable ? value : display_value !== null ? display_value : value
@@ -99,6 +105,22 @@
99
105
  return {};
100
106
  }
101
107
 
108
+ // grow the edit-mode textarea to fit its content so the overlay
109
+ // expands the same way the display span does.
110
+ function use_autosize(node: HTMLTextAreaElement): any {
111
+ function resize(): void {
112
+ node.style.height = "auto";
113
+ node.style.height = `${node.scrollHeight}px`;
114
+ }
115
+ node.addEventListener("input", resize);
116
+ requestAnimationFrame(resize);
117
+ return {
118
+ destroy() {
119
+ node.removeEventListener("input", resize);
120
+ }
121
+ };
122
+ }
123
+
102
124
  function handle_blur(event: FocusEvent): void {
103
125
  onblur?.({
104
126
  blur_event: event,
@@ -114,10 +136,12 @@
114
136
  handle_blur({ target: { value } } as unknown as FocusEvent);
115
137
  }
116
138
 
139
+ // returning cleanup from the effect fires the blur only when leaving edit mode, not on every render
117
140
  $effect(() => {
118
- if (!edit) {
119
- // Shim blur on removal for Safari and Firefox
120
- handle_blur({ target: { value } } as unknown as FocusEvent);
141
+ if (edit) {
142
+ return () => {
143
+ handle_blur({ target: { value } } as unknown as FocusEvent);
144
+ };
121
145
  }
122
146
  });
123
147
  </script>
@@ -135,7 +159,9 @@
135
159
  onmousedown={(e: MouseEvent) => e.stopPropagation()}
136
160
  onclick={(e: MouseEvent) => e.stopPropagation()}
137
161
  use:use_focus
162
+ use:use_autosize
138
163
  onkeydown={handle_keydown}
164
+ class:pad_left
139
165
  />
140
166
  {/if}
141
167
 
@@ -149,7 +175,7 @@
149
175
  role="button"
150
176
  class:edit
151
177
  class:expanded={edit}
152
- class:multiline={header}
178
+ class:header
153
179
  onfocus={(e) => e.preventDefault()}
154
180
  style={styling}
155
181
  data-editable={editable}
@@ -205,7 +231,7 @@
205
231
  textarea {
206
232
  position: absolute;
207
233
  flex: 1 1 0%;
208
- transform: translateX(-0.1px);
234
+ transform: translate(0.2px, -0.5px);
209
235
  outline: none;
210
236
  border: none;
211
237
  background: transparent;
@@ -217,24 +243,33 @@
217
243
  font-size: inherit;
218
244
  font-weight: inherit;
219
245
  line-height: var(--line-lg);
246
+ left: var(--size-2);
247
+ user-select: text;
220
248
  }
221
249
 
222
250
  textarea:focus {
223
251
  outline: none;
224
252
  }
225
253
 
254
+ textarea.pad_left {
255
+ margin-left: var(--size-7);
256
+ }
257
+
226
258
  span {
227
259
  flex: 1 1 0%;
228
260
  position: relative;
229
261
  display: block;
230
262
  outline: none;
231
- -webkit-user-select: text;
232
- -moz-user-select: text;
233
- -ms-user-select: text;
234
- user-select: text;
235
263
  cursor: text;
236
264
  width: 100%;
237
- overflow-wrap: break-word;
265
+ min-width: 0;
266
+ white-space: nowrap;
267
+ overflow: hidden;
268
+ text-overflow: ellipsis;
269
+ }
270
+
271
+ .header {
272
+ font-weight: var(--weight-bold);
238
273
  }
239
274
 
240
275
  span.text.expanded {
@@ -245,21 +280,6 @@
245
280
  overflow: visible;
246
281
  }
247
282
 
248
- .multiline {
249
- white-space: pre;
250
- overflow: hidden;
251
- text-overflow: ellipsis;
252
- }
253
-
254
- .header {
255
- transform: translateX(0);
256
- font-weight: var(--weight-bold);
257
- white-space: nowrap;
258
- overflow: hidden;
259
- text-overflow: ellipsis;
260
- margin-left: var(--size-1);
261
- }
262
-
263
283
  .edit {
264
284
  opacity: 0;
265
285
  pointer-events: none;
@@ -267,6 +287,8 @@
267
287
 
268
288
  span :global(img) {
269
289
  max-height: 100px;
290
+ max-width: 100%;
291
+ height: auto;
270
292
  width: auto;
271
293
  object-fit: contain;
272
294
  }
@@ -278,8 +300,9 @@
278
300
  .wrap,
279
301
  .wrap.expanded {
280
302
  white-space: normal;
281
- word-wrap: break-word;
303
+ overflow: visible;
304
+ text-overflow: clip;
282
305
  overflow-wrap: break-word;
283
- word-wrap: break-word;
306
+ word-break: break-word;
284
307
  }
285
308
  </style>
@@ -5,6 +5,7 @@
5
5
  import FilterIcon from "./icons/FilterIcon.svelte";
6
6
  import SortButtonUp from "./icons/SortButtonUp.svelte";
7
7
  import SortButtonDown from "./icons/SortButtonDown.svelte";
8
+ import { BaseCheckbox } from "@gradio/checkbox";
8
9
  import type { I18nFormatter } from "js/core/src/gradio_helper";
9
10
  import type { SortDirection } from "./types";
10
11
 
@@ -14,6 +15,8 @@
14
15
  is_editing = false,
15
16
  is_selected = false,
16
17
  is_static = false,
18
+ is_bool = false,
19
+ select_all_state = "unchecked",
17
20
  sort_direction = null,
18
21
  sort_priority = null,
19
22
  multi_sort = false,
@@ -25,15 +28,19 @@
25
28
  editable = true,
26
29
  max_chars = undefined,
27
30
  i18n,
31
+ wrap_text = false,
28
32
  onclick,
29
33
  on_menu_click,
30
- on_end_edit
34
+ on_end_edit,
35
+ on_select_all
31
36
  }: {
32
37
  value: string;
33
38
  col_idx: number;
34
39
  is_editing?: boolean;
35
40
  is_selected?: boolean;
36
41
  is_static?: boolean;
42
+ is_bool?: boolean;
43
+ select_all_state?: "checked" | "unchecked" | "indeterminate";
37
44
  sort_direction?: SortDirection | null;
38
45
  sort_priority?: number | null;
39
46
  multi_sort?: boolean;
@@ -45,10 +52,16 @@
45
52
  editable?: boolean;
46
53
  max_chars?: number | undefined;
47
54
  i18n: I18nFormatter;
55
+ wrap_text?: boolean;
48
56
  onclick: (event: MouseEvent, col: number) => void;
49
57
  on_menu_click: (event: MouseEvent, col: number) => void;
50
58
  on_end_edit: (key: string) => void;
59
+ on_select_all?: (col: number, checked: boolean) => void;
51
60
  } = $props();
61
+
62
+ let show_select_all = $derived(
63
+ is_bool && editable && !is_static && !!on_select_all
64
+ );
52
65
  </script>
53
66
 
54
67
  <th
@@ -57,6 +70,7 @@
57
70
  class:sorted={sort_direction !== null}
58
71
  class:filtered={is_filtered}
59
72
  class:first-column={is_first_column}
73
+ data-heading={col_idx}
60
74
  onclick={(e) => onclick(e, col_idx)}
61
75
  onmousedown={(e) => {
62
76
  e.preventDefault();
@@ -66,6 +80,25 @@
66
80
  >
67
81
  <div class="cell-wrap">
68
82
  <div class="header-content">
83
+ {#if show_select_all}
84
+ <div
85
+ class="select-all-checkbox"
86
+ role="button"
87
+ tabindex="-1"
88
+ onclick={(e) => e.stopPropagation()}
89
+ onmousedown={(e) => e.stopPropagation()}
90
+ onkeydown={(e) => e.stopPropagation()}
91
+ >
92
+ <BaseCheckbox
93
+ value={select_all_state === "checked"}
94
+ indeterminate={select_all_state === "indeterminate"}
95
+ label={`Toggle all: ${value}`}
96
+ interactive={true}
97
+ on_select={() =>
98
+ on_select_all?.(col_idx, select_all_state !== "checked")}
99
+ />
100
+ </div>
101
+ {/if}
69
102
  <EditableCell
70
103
  {value}
71
104
  {latex_delimiters}
@@ -81,7 +114,9 @@
81
114
  {is_static}
82
115
  {i18n}
83
116
  {max_chars}
117
+ {wrap_text}
84
118
  coords={[col_idx, 0]}
119
+ pad_left={show_select_all ? true : false}
85
120
  />
86
121
  </div>
87
122
  {#if sort_direction || is_filtered || is_static}
@@ -129,6 +164,13 @@
129
164
  padding: 0;
130
165
  background: var(--table-even-background-fill) !important;
131
166
  font-weight: var(--weight-bold, 700);
167
+ outline: none;
168
+ box-shadow:
169
+ inset 1px 0 0 var(--border-color-primary),
170
+ inset 0 0 0 1px var(--ring-color);
171
+ padding: 0;
172
+ overflow: visible;
173
+ box-sizing: border-box;
132
174
  }
133
175
 
134
176
  .header-cell.first-column {
@@ -142,10 +184,14 @@
142
184
 
143
185
  .header-cell.focus {
144
186
  --ring-color: var(--color-accent);
187
+ --sel-top: inset 0 2px 0 0 var(--ring-color);
188
+ --sel-bottom: inset 0 -2px 0 0 var(--ring-color);
189
+ --sel-left: inset 2px 0 0 0 var(--ring-color);
190
+ --sel-right: inset -2px 0 0 0 var(--ring-color);
145
191
  box-shadow:
146
- inset 1px 0 0 var(--border-color-primary),
147
- inset 0 0 0 2px var(--ring-color);
148
- z-index: 4;
192
+ var(--sel-top), var(--sel-bottom), var(--sel-left), var(--sel-right);
193
+ z-index: 2;
194
+ position: relative;
149
195
  }
150
196
 
151
197
  .header-cell.focus.first-column {
@@ -155,7 +201,7 @@
155
201
  .header-content {
156
202
  display: flex;
157
203
  align-items: center;
158
- gap: var(--size-1);
204
+ gap: var(--size-3);
159
205
  overflow: hidden;
160
206
  min-width: 0;
161
207
  }
@@ -215,4 +261,20 @@
215
261
  overflow: visible;
216
262
  min-width: 0;
217
263
  }
264
+
265
+ .select-all-checkbox {
266
+ display: flex;
267
+ align-items: center;
268
+ justify-content: center;
269
+ flex-shrink: 0;
270
+ width: var(--size-4);
271
+ }
272
+
273
+ .select-all-checkbox :global(label) {
274
+ margin: 0;
275
+ }
276
+
277
+ .select-all-checkbox :global(span) {
278
+ display: none;
279
+ }
218
280
  </style>