@gradio/dataframe 0.13.1 → 0.15.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/CHANGELOG.md +28 -0
- package/Dataframe.stories.svelte +148 -2
- package/Index.svelte +4 -0
- package/dist/Index.svelte +4 -0
- package/dist/Index.svelte.d.ts +8 -0
- package/dist/shared/CellMenu.svelte +21 -9
- package/dist/shared/CellMenu.svelte.d.ts +4 -0
- package/dist/shared/CellMenuIcons.svelte +112 -0
- package/dist/shared/CellMenuIcons.svelte.d.ts +16 -0
- package/dist/shared/EditableCell.svelte +52 -7
- package/dist/shared/EditableCell.svelte.d.ts +1 -1
- package/dist/shared/Table.svelte +356 -270
- package/dist/shared/Table.svelte.d.ts +2 -0
- package/dist/shared/Toolbar.svelte +46 -6
- package/dist/shared/Toolbar.svelte.d.ts +2 -0
- package/dist/shared/selection_utils.d.ts +20 -0
- package/dist/shared/selection_utils.js +111 -0
- package/dist/shared/table_utils.d.ts +12 -0
- package/dist/shared/table_utils.js +113 -0
- package/dist/shared/types.d.ts +2 -0
- package/dist/shared/types.js +1 -0
- package/package.json +6 -6
- package/shared/CellMenu.svelte +21 -9
- package/shared/CellMenuIcons.svelte +113 -0
- package/shared/EditableCell.svelte +58 -7
- package/shared/Table.svelte +400 -341
- package/shared/Toolbar.svelte +48 -6
- package/shared/selection_utils.ts +188 -0
- package/shared/table_utils.ts +148 -0
- package/shared/types.ts +2 -0
- package/dist/shared/Arrow.svelte +0 -9
- package/dist/shared/Arrow.svelte.d.ts +0 -16
- package/shared/Arrow.svelte +0 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @gradio/dataframe
|
|
2
2
|
|
|
3
|
+
## 0.15.0
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- [#10456](https://github.com/gradio-app/gradio/pull/10456) [`8e40c15`](https://github.com/gradio-app/gradio/commit/8e40c15669ed1244d6f2288e55c2223279bd37a4) - Implement multiple cell selection. Thanks @hannahblair!
|
|
8
|
+
- [#10463](https://github.com/gradio-app/gradio/pull/10463) [`ed7a091`](https://github.com/gradio-app/gradio/commit/ed7a0919ab6b31184dc4d686b722dbeb013e9ce9) - Expand and collapse dataframe cells. Thanks @hannahblair!
|
|
9
|
+
- [#10478](https://github.com/gradio-app/gradio/pull/10478) [`afb96c6`](https://github.com/gradio-app/gradio/commit/afb96c64451e5a282bfee89445d831d1c87f9746) - Improve dataframe's upload accessibility. Thanks @hannahblair!
|
|
10
|
+
- [#10491](https://github.com/gradio-app/gradio/pull/10491) [`ff5f976`](https://github.com/gradio-app/gradio/commit/ff5f976bbb685fdd4f7c1faeda79e094f55a9f56) - Allow multiline headers in gr.Dataframe. Thanks @hannahblair!
|
|
11
|
+
- [#10494](https://github.com/gradio-app/gradio/pull/10494) [`10932a2`](https://github.com/gradio-app/gradio/commit/10932a291ac7f591bb1d56e4e353b51f10ecc6e3) - Ensure dataframe is not editable when `interactive` is False. Thanks @hannahblair!
|
|
12
|
+
|
|
13
|
+
### Dependency updates
|
|
14
|
+
|
|
15
|
+
- @gradio/client@1.11.0
|
|
16
|
+
- @gradio/upload@0.15.0
|
|
17
|
+
- @gradio/button@0.4.5
|
|
18
|
+
|
|
19
|
+
## 0.14.0
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
- [#10461](https://github.com/gradio-app/gradio/pull/10461) [`ca7c47e`](https://github.com/gradio-app/gradio/commit/ca7c47e5e50a309cd637c4f928ab90af6355b01d) - Add copy button to dataframe toolbar. Thanks @hannahblair!
|
|
24
|
+
- [#10420](https://github.com/gradio-app/gradio/pull/10420) [`a69b8e8`](https://github.com/gradio-app/gradio/commit/a69b8e83ad7c89c627db2bdd5d25b0142731aaac) - Support column/row deletion in `gr.DataFrame`. Thanks @abidlabs!
|
|
25
|
+
|
|
26
|
+
### Dependency updates
|
|
27
|
+
|
|
28
|
+
- @gradio/upload@0.14.8
|
|
29
|
+
- @gradio/button@0.4.4
|
|
30
|
+
|
|
3
31
|
## 0.13.1
|
|
4
32
|
|
|
5
33
|
### Features
|
package/Dataframe.stories.svelte
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
// @ts-nocheck
|
|
2
3
|
import { Meta, Template, Story } from "@storybook/addon-svelte-csf";
|
|
3
4
|
import Table from "./shared/Table.svelte";
|
|
4
5
|
import { within } from "@testing-library/dom";
|
|
@@ -10,6 +11,11 @@
|
|
|
10
11
|
<Meta
|
|
11
12
|
title="Components/DataFrame"
|
|
12
13
|
component={Table}
|
|
14
|
+
parameters={{
|
|
15
|
+
test: {
|
|
16
|
+
dangerouslyIgnoreUnhandledErrors: true // ignore fullscreen permission error
|
|
17
|
+
}
|
|
18
|
+
}}
|
|
13
19
|
argTypes={{
|
|
14
20
|
editable: {
|
|
15
21
|
control: [true, false],
|
|
@@ -87,6 +93,26 @@
|
|
|
87
93
|
row_count: [3, "dynamic"],
|
|
88
94
|
editable: false
|
|
89
95
|
}}
|
|
96
|
+
play={async ({ canvasElement }) => {
|
|
97
|
+
// tests that the cell is not editable
|
|
98
|
+
|
|
99
|
+
const canvas = within(canvasElement);
|
|
100
|
+
const cells = canvas.getAllByRole("cell");
|
|
101
|
+
const initial_value = cells[0].textContent;
|
|
102
|
+
|
|
103
|
+
await userEvent.click(cells[0]);
|
|
104
|
+
await userEvent.keyboard("new value");
|
|
105
|
+
|
|
106
|
+
const final_value = cells[0].textContent;
|
|
107
|
+
if (initial_value !== final_value) {
|
|
108
|
+
throw new Error("Cell content changed when it should be non-editable");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const inputs = canvas.queryAllByRole("textbox");
|
|
112
|
+
if (inputs.length > 0) {
|
|
113
|
+
throw new Error("Input field appeared when table should be non-editable");
|
|
114
|
+
}
|
|
115
|
+
}}
|
|
90
116
|
/>
|
|
91
117
|
|
|
92
118
|
<Story
|
|
@@ -194,9 +220,11 @@
|
|
|
194
220
|
const canvas = within(canvasElement);
|
|
195
221
|
|
|
196
222
|
const cell_400 = canvas.getAllByRole("cell")[5];
|
|
197
|
-
userEvent.click(cell_400);
|
|
223
|
+
await userEvent.click(cell_400);
|
|
198
224
|
|
|
199
|
-
const open_dialog_btn = within(cell_400).
|
|
225
|
+
const open_dialog_btn = await within(cell_400).findByRole("button", {
|
|
226
|
+
name: "⋮"
|
|
227
|
+
});
|
|
200
228
|
await userEvent.click(open_dialog_btn);
|
|
201
229
|
|
|
202
230
|
const add_row_btn = canvas.getByText("Add row above");
|
|
@@ -220,3 +248,121 @@
|
|
|
220
248
|
show_fullscreen_button: true
|
|
221
249
|
}}
|
|
222
250
|
/>
|
|
251
|
+
|
|
252
|
+
<Story
|
|
253
|
+
name="Dataframe with multiple selection interactions"
|
|
254
|
+
args={{
|
|
255
|
+
values: [
|
|
256
|
+
[1, 2, 3, 4],
|
|
257
|
+
[5, 6, 7, 8],
|
|
258
|
+
[9, 10, 11, 12],
|
|
259
|
+
[13, 14, 15, 16]
|
|
260
|
+
],
|
|
261
|
+
col_count: [4, "dynamic"],
|
|
262
|
+
row_count: [4, "dynamic"],
|
|
263
|
+
headers: ["A", "B", "C", "D"],
|
|
264
|
+
editable: true
|
|
265
|
+
}}
|
|
266
|
+
play={async ({ canvasElement }) => {
|
|
267
|
+
const canvas = within(canvasElement);
|
|
268
|
+
const cells = canvas.getAllByRole("cell");
|
|
269
|
+
const user = userEvent.setup();
|
|
270
|
+
|
|
271
|
+
// cmd+click to select non-contiguous cells
|
|
272
|
+
await user.keyboard("[MetaLeft>]");
|
|
273
|
+
await user.click(cells[4]);
|
|
274
|
+
await user.click(cells[6]);
|
|
275
|
+
await user.click(cells[2]);
|
|
276
|
+
await user.keyboard("[/MetaLeft]");
|
|
277
|
+
|
|
278
|
+
// shift+click to select a range
|
|
279
|
+
await user.keyboard("[ShiftLeft>]");
|
|
280
|
+
await user.click(cells[7]);
|
|
281
|
+
await user.click(cells[6]);
|
|
282
|
+
await user.keyboard("[/ShiftLeft]");
|
|
283
|
+
|
|
284
|
+
// clear selected cells
|
|
285
|
+
await user.keyboard("{Delete}");
|
|
286
|
+
|
|
287
|
+
// verify cells were cleared by clicking one
|
|
288
|
+
await user.click(cells[2]);
|
|
289
|
+
}}
|
|
290
|
+
/>
|
|
291
|
+
|
|
292
|
+
<Story
|
|
293
|
+
name="Dataframe toolbar interactions"
|
|
294
|
+
args={{
|
|
295
|
+
col_count: [3, "dynamic"],
|
|
296
|
+
row_count: [2, "dynamic"],
|
|
297
|
+
headers: ["Math", "Reading", "Writing"],
|
|
298
|
+
values: [
|
|
299
|
+
[800, 100, 400],
|
|
300
|
+
[200, 800, 700]
|
|
301
|
+
],
|
|
302
|
+
show_fullscreen_button: true,
|
|
303
|
+
show_copy_button: true
|
|
304
|
+
}}
|
|
305
|
+
play={async ({ canvasElement }) => {
|
|
306
|
+
const canvas = within(canvasElement);
|
|
307
|
+
|
|
308
|
+
const copy_button = canvas.getByRole("button", {
|
|
309
|
+
name: "Copy table data"
|
|
310
|
+
});
|
|
311
|
+
await userEvent.click(copy_button);
|
|
312
|
+
|
|
313
|
+
const fullscreen_button = canvas.getByRole("button", {
|
|
314
|
+
name: "Enter fullscreen"
|
|
315
|
+
});
|
|
316
|
+
await userEvent.click(fullscreen_button);
|
|
317
|
+
|
|
318
|
+
await userEvent.click(fullscreen_button);
|
|
319
|
+
}}
|
|
320
|
+
/>
|
|
321
|
+
|
|
322
|
+
<Story
|
|
323
|
+
name="Dataframe with truncated text"
|
|
324
|
+
args={{
|
|
325
|
+
values: [
|
|
326
|
+
[
|
|
327
|
+
"This is a very long text that should be truncated",
|
|
328
|
+
"Short text",
|
|
329
|
+
"Another very long text that needs truncation"
|
|
330
|
+
],
|
|
331
|
+
[
|
|
332
|
+
"Short",
|
|
333
|
+
"This text is also quite long and should be truncated as well",
|
|
334
|
+
"Medium length text here"
|
|
335
|
+
],
|
|
336
|
+
[
|
|
337
|
+
"Medium text",
|
|
338
|
+
"Brief",
|
|
339
|
+
"This is the longest text in the entire table and it should definitely be truncated"
|
|
340
|
+
]
|
|
341
|
+
],
|
|
342
|
+
headers: ["Column A", "Column B", "Column C"],
|
|
343
|
+
label: "Truncated Text Example",
|
|
344
|
+
max_chars: 20,
|
|
345
|
+
col_count: [3, "dynamic"],
|
|
346
|
+
row_count: [3, "dynamic"]
|
|
347
|
+
}}
|
|
348
|
+
/>
|
|
349
|
+
|
|
350
|
+
<Story
|
|
351
|
+
name="Dataframe with multiline headers"
|
|
352
|
+
args={{
|
|
353
|
+
values: [
|
|
354
|
+
[95, 92, 88],
|
|
355
|
+
[89, 90, 85],
|
|
356
|
+
[92, 88, 91]
|
|
357
|
+
],
|
|
358
|
+
headers: [
|
|
359
|
+
"Dataset A\nAccuracy",
|
|
360
|
+
"Dataset B\nPrecision",
|
|
361
|
+
"Dataset C\nRecall"
|
|
362
|
+
],
|
|
363
|
+
label: "Model Metrics",
|
|
364
|
+
col_count: [3, "dynamic"],
|
|
365
|
+
row_count: [3, "dynamic"],
|
|
366
|
+
editable: false
|
|
367
|
+
}}
|
|
368
|
+
/>
|
package/Index.svelte
CHANGED
|
@@ -49,6 +49,8 @@
|
|
|
49
49
|
export let loading_status: LoadingStatus;
|
|
50
50
|
export let interactive: boolean;
|
|
51
51
|
export let show_fullscreen_button = false;
|
|
52
|
+
export let max_chars: number | undefined = undefined;
|
|
53
|
+
export let show_copy_button = false;
|
|
52
54
|
|
|
53
55
|
$: _headers = [...(value.headers || headers)];
|
|
54
56
|
$: cell_values = value.data ? [...value.data] : [];
|
|
@@ -105,5 +107,7 @@
|
|
|
105
107
|
stream_handler={(...args) => gradio.client.stream(...args)}
|
|
106
108
|
bind:value_is_output
|
|
107
109
|
{show_fullscreen_button}
|
|
110
|
+
{max_chars}
|
|
111
|
+
{show_copy_button}
|
|
108
112
|
/>
|
|
109
113
|
</Block>
|
package/dist/Index.svelte
CHANGED
|
@@ -34,6 +34,8 @@ export let max_height = void 0;
|
|
|
34
34
|
export let loading_status;
|
|
35
35
|
export let interactive;
|
|
36
36
|
export let show_fullscreen_button = false;
|
|
37
|
+
export let max_chars = void 0;
|
|
38
|
+
export let show_copy_button = false;
|
|
37
39
|
$:
|
|
38
40
|
_headers = [...value.headers || headers];
|
|
39
41
|
$:
|
|
@@ -88,5 +90,7 @@ $:
|
|
|
88
90
|
stream_handler={(...args) => gradio.client.stream(...args)}
|
|
89
91
|
bind:value_is_output
|
|
90
92
|
{show_fullscreen_button}
|
|
93
|
+
{max_chars}
|
|
94
|
+
{show_copy_button}
|
|
91
95
|
/>
|
|
92
96
|
</Block>
|
package/dist/Index.svelte.d.ts
CHANGED
|
@@ -38,6 +38,8 @@ declare const __propDef: {
|
|
|
38
38
|
loading_status: LoadingStatus;
|
|
39
39
|
interactive: boolean;
|
|
40
40
|
show_fullscreen_button?: boolean | undefined;
|
|
41
|
+
max_chars?: number | undefined;
|
|
42
|
+
show_copy_button?: boolean | undefined;
|
|
41
43
|
};
|
|
42
44
|
events: {
|
|
43
45
|
[evt: string]: CustomEvent<any>;
|
|
@@ -135,4 +137,10 @@ export default class Index extends SvelteComponent<IndexProps, IndexEvents, Inde
|
|
|
135
137
|
get show_fullscreen_button(): boolean | undefined;
|
|
136
138
|
/**accessor*/
|
|
137
139
|
set show_fullscreen_button(_: boolean | undefined);
|
|
140
|
+
get max_chars(): number | undefined;
|
|
141
|
+
/**accessor*/
|
|
142
|
+
set max_chars(_: number | undefined);
|
|
143
|
+
get show_copy_button(): boolean | undefined;
|
|
144
|
+
/**accessor*/
|
|
145
|
+
set show_copy_button(_: boolean | undefined);
|
|
138
146
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script>import { onMount } from "svelte";
|
|
2
|
-
import
|
|
2
|
+
import CellMenuIcons from "./CellMenuIcons.svelte";
|
|
3
3
|
export let x;
|
|
4
4
|
export let y;
|
|
5
5
|
export let on_add_row_above;
|
|
@@ -9,6 +9,10 @@ export let on_add_column_right;
|
|
|
9
9
|
export let row;
|
|
10
10
|
export let col_count;
|
|
11
11
|
export let row_count;
|
|
12
|
+
export let on_delete_row;
|
|
13
|
+
export let on_delete_col;
|
|
14
|
+
export let can_delete_rows;
|
|
15
|
+
export let can_delete_cols;
|
|
12
16
|
export let i18n;
|
|
13
17
|
let menu_element;
|
|
14
18
|
$:
|
|
@@ -42,23 +46,35 @@ function position_menu() {
|
|
|
42
46
|
<div bind:this={menu_element} class="cell-menu">
|
|
43
47
|
{#if !is_header && can_add_rows}
|
|
44
48
|
<button on:click={() => on_add_row_above()}>
|
|
45
|
-
<
|
|
49
|
+
<CellMenuIcons icon="add-row-above" />
|
|
46
50
|
{i18n("dataframe.add_row_above")}
|
|
47
51
|
</button>
|
|
48
52
|
<button on:click={() => on_add_row_below()}>
|
|
49
|
-
<
|
|
53
|
+
<CellMenuIcons icon="add-row-below" />
|
|
50
54
|
{i18n("dataframe.add_row_below")}
|
|
51
55
|
</button>
|
|
56
|
+
{#if can_delete_rows}
|
|
57
|
+
<button on:click={on_delete_row} class="delete">
|
|
58
|
+
<CellMenuIcons icon="delete-row" />
|
|
59
|
+
{i18n("dataframe.delete_row")}
|
|
60
|
+
</button>
|
|
61
|
+
{/if}
|
|
52
62
|
{/if}
|
|
53
63
|
{#if can_add_columns}
|
|
54
64
|
<button on:click={() => on_add_column_left()}>
|
|
55
|
-
<
|
|
65
|
+
<CellMenuIcons icon="add-column-left" />
|
|
56
66
|
{i18n("dataframe.add_column_left")}
|
|
57
67
|
</button>
|
|
58
68
|
<button on:click={() => on_add_column_right()}>
|
|
59
|
-
<
|
|
69
|
+
<CellMenuIcons icon="add-column-right" />
|
|
60
70
|
{i18n("dataframe.add_column_right")}
|
|
61
71
|
</button>
|
|
72
|
+
{#if can_delete_cols}
|
|
73
|
+
<button on:click={on_delete_col} class="delete">
|
|
74
|
+
<CellMenuIcons icon="delete-column" />
|
|
75
|
+
{i18n("dataframe.delete_column")}
|
|
76
|
+
</button>
|
|
77
|
+
{/if}
|
|
62
78
|
{/if}
|
|
63
79
|
</div>
|
|
64
80
|
|
|
@@ -102,8 +118,4 @@ function position_menu() {
|
|
|
102
118
|
fill: currentColor;
|
|
103
119
|
transition: fill 0.2s;
|
|
104
120
|
}
|
|
105
|
-
|
|
106
|
-
.cell-menu button:hover :global(svg) {
|
|
107
|
-
fill: var(--color-accent);
|
|
108
|
-
}
|
|
109
121
|
</style>
|
|
@@ -11,6 +11,10 @@ declare const __propDef: {
|
|
|
11
11
|
row: number;
|
|
12
12
|
col_count: [number, "fixed" | "dynamic"];
|
|
13
13
|
row_count: [number, "fixed" | "dynamic"];
|
|
14
|
+
on_delete_row: () => void;
|
|
15
|
+
on_delete_col: () => void;
|
|
16
|
+
can_delete_rows: boolean;
|
|
17
|
+
can_delete_cols: boolean;
|
|
14
18
|
i18n: I18nFormatter;
|
|
15
19
|
};
|
|
16
20
|
events: {
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<script>export let icon;
|
|
2
|
+
</script>
|
|
3
|
+
|
|
4
|
+
{#if icon == "add-column-right"}
|
|
5
|
+
<svg viewBox="0 0 24 24" width="16" height="16">
|
|
6
|
+
<rect
|
|
7
|
+
x="4"
|
|
8
|
+
y="6"
|
|
9
|
+
width="4"
|
|
10
|
+
height="12"
|
|
11
|
+
stroke="currentColor"
|
|
12
|
+
stroke-width="2"
|
|
13
|
+
fill="none"
|
|
14
|
+
/>
|
|
15
|
+
<path
|
|
16
|
+
d="M12 12H19M16 8L19 12L16 16"
|
|
17
|
+
stroke="currentColor"
|
|
18
|
+
stroke-width="2"
|
|
19
|
+
fill="none"
|
|
20
|
+
stroke-linecap="round"
|
|
21
|
+
/>
|
|
22
|
+
</svg>
|
|
23
|
+
{:else if icon == "add-column-left"}
|
|
24
|
+
<svg viewBox="0 0 24 24" width="16" height="16">
|
|
25
|
+
<rect
|
|
26
|
+
x="16"
|
|
27
|
+
y="6"
|
|
28
|
+
width="4"
|
|
29
|
+
height="12"
|
|
30
|
+
stroke="currentColor"
|
|
31
|
+
stroke-width="2"
|
|
32
|
+
fill="none"
|
|
33
|
+
/>
|
|
34
|
+
<path
|
|
35
|
+
d="M12 12H5M8 8L5 12L8 16"
|
|
36
|
+
stroke="currentColor"
|
|
37
|
+
stroke-width="2"
|
|
38
|
+
fill="none"
|
|
39
|
+
stroke-linecap="round"
|
|
40
|
+
/>
|
|
41
|
+
</svg>
|
|
42
|
+
{:else if icon == "add-row-above"}
|
|
43
|
+
<svg viewBox="0 0 24 24" width="16" height="16">
|
|
44
|
+
<rect
|
|
45
|
+
x="6"
|
|
46
|
+
y="16"
|
|
47
|
+
width="12"
|
|
48
|
+
height="4"
|
|
49
|
+
stroke="currentColor"
|
|
50
|
+
stroke-width="2"
|
|
51
|
+
/>
|
|
52
|
+
<path
|
|
53
|
+
d="M12 12V5M8 8L12 5L16 8"
|
|
54
|
+
stroke="currentColor"
|
|
55
|
+
stroke-width="2"
|
|
56
|
+
fill="none"
|
|
57
|
+
stroke-linecap="round"
|
|
58
|
+
/>
|
|
59
|
+
</svg>
|
|
60
|
+
{:else if icon == "add-row-below"}
|
|
61
|
+
<svg viewBox="0 0 24 24" width="16" height="16">
|
|
62
|
+
<rect
|
|
63
|
+
x="6"
|
|
64
|
+
y="4"
|
|
65
|
+
width="12"
|
|
66
|
+
height="4"
|
|
67
|
+
stroke="currentColor"
|
|
68
|
+
stroke-width="2"
|
|
69
|
+
/>
|
|
70
|
+
<path
|
|
71
|
+
d="M12 12V19M8 16L12 19L16 16"
|
|
72
|
+
stroke="currentColor"
|
|
73
|
+
stroke-width="2"
|
|
74
|
+
fill="none"
|
|
75
|
+
stroke-linecap="round"
|
|
76
|
+
/>
|
|
77
|
+
</svg>
|
|
78
|
+
{:else if icon == "delete-row"}
|
|
79
|
+
<svg viewBox="0 0 24 24" width="16" height="16">
|
|
80
|
+
<rect
|
|
81
|
+
x="5"
|
|
82
|
+
y="10"
|
|
83
|
+
width="14"
|
|
84
|
+
height="4"
|
|
85
|
+
stroke="currentColor"
|
|
86
|
+
stroke-width="2"
|
|
87
|
+
/>
|
|
88
|
+
<path
|
|
89
|
+
d="M8 7L16 17M16 7L8 17"
|
|
90
|
+
stroke="currentColor"
|
|
91
|
+
stroke-width="2"
|
|
92
|
+
stroke-linecap="round"
|
|
93
|
+
/>
|
|
94
|
+
</svg>
|
|
95
|
+
{:else if icon == "delete-column"}
|
|
96
|
+
<svg viewBox="0 0 24 24" width="16" height="16">
|
|
97
|
+
<rect
|
|
98
|
+
x="10"
|
|
99
|
+
y="5"
|
|
100
|
+
width="4"
|
|
101
|
+
height="14"
|
|
102
|
+
stroke="currentColor"
|
|
103
|
+
stroke-width="2"
|
|
104
|
+
/>
|
|
105
|
+
<path
|
|
106
|
+
d="M7 8L17 16M17 8L7 16"
|
|
107
|
+
stroke="currentColor"
|
|
108
|
+
stroke-width="2"
|
|
109
|
+
stroke-linecap="round"
|
|
110
|
+
/>
|
|
111
|
+
</svg>
|
|
112
|
+
{/if}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
icon: string;
|
|
5
|
+
};
|
|
6
|
+
events: {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
};
|
|
9
|
+
slots: {};
|
|
10
|
+
};
|
|
11
|
+
export type CellMenuIconsProps = typeof __propDef.props;
|
|
12
|
+
export type CellMenuIconsEvents = typeof __propDef.events;
|
|
13
|
+
export type CellMenuIconsSlots = typeof __propDef.slots;
|
|
14
|
+
export default class CellMenuIcons extends SvelteComponent<CellMenuIconsProps, CellMenuIconsEvents, CellMenuIconsSlots> {
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -11,10 +11,20 @@ export let clear_on_focus = false;
|
|
|
11
11
|
export let line_breaks = true;
|
|
12
12
|
export let editable = true;
|
|
13
13
|
export let root;
|
|
14
|
+
export let max_chars = null;
|
|
14
15
|
const dispatch = createEventDispatcher();
|
|
16
|
+
let is_expanded = false;
|
|
15
17
|
export let el;
|
|
16
18
|
$:
|
|
17
19
|
_value = value;
|
|
20
|
+
function truncate_text(text, max_length = null) {
|
|
21
|
+
const str = String(text);
|
|
22
|
+
if (!max_length || str.length <= max_length)
|
|
23
|
+
return str;
|
|
24
|
+
return str.slice(0, max_length) + "...";
|
|
25
|
+
}
|
|
26
|
+
$:
|
|
27
|
+
display_text = is_expanded ? value : truncate_text(display_value || value, max_chars);
|
|
18
28
|
function use_focus(node) {
|
|
19
29
|
if (clear_on_focus) {
|
|
20
30
|
_value = "";
|
|
@@ -32,11 +42,20 @@ function handle_blur({
|
|
|
32
42
|
}
|
|
33
43
|
function handle_keydown(event) {
|
|
34
44
|
if (event.key === "Enter") {
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
if (edit) {
|
|
46
|
+
value = _value;
|
|
47
|
+
dispatch("blur");
|
|
48
|
+
} else if (!header) {
|
|
49
|
+
is_expanded = !is_expanded;
|
|
50
|
+
}
|
|
37
51
|
}
|
|
38
52
|
dispatch("keydown", event);
|
|
39
53
|
}
|
|
54
|
+
function handle_click() {
|
|
55
|
+
if (!edit && !header) {
|
|
56
|
+
is_expanded = !is_expanded;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
40
59
|
</script>
|
|
41
60
|
|
|
42
61
|
{#if edit}
|
|
@@ -56,27 +75,31 @@ function handle_keydown(event) {
|
|
|
56
75
|
{/if}
|
|
57
76
|
|
|
58
77
|
<span
|
|
59
|
-
on:
|
|
60
|
-
|
|
78
|
+
on:click={handle_click}
|
|
79
|
+
on:keydown={handle_keydown}
|
|
80
|
+
tabindex="0"
|
|
61
81
|
role="button"
|
|
62
82
|
class:edit
|
|
83
|
+
class:expanded={is_expanded}
|
|
84
|
+
class:multiline={header}
|
|
63
85
|
on:focus|preventDefault
|
|
64
86
|
style={styling}
|
|
65
87
|
class="table-cell-text"
|
|
88
|
+
data-editable={editable}
|
|
66
89
|
placeholder=" "
|
|
67
90
|
>
|
|
68
91
|
{#if datatype === "html"}
|
|
69
|
-
{@html
|
|
92
|
+
{@html display_text}
|
|
70
93
|
{:else if datatype === "markdown"}
|
|
71
94
|
<MarkdownCode
|
|
72
|
-
message={
|
|
95
|
+
message={display_text.toLocaleString()}
|
|
73
96
|
{latex_delimiters}
|
|
74
97
|
{line_breaks}
|
|
75
98
|
chatbot={false}
|
|
76
99
|
{root}
|
|
77
100
|
/>
|
|
78
101
|
{:else}
|
|
79
|
-
{editable ?
|
|
102
|
+
{editable ? display_text : display_value || display_text}
|
|
80
103
|
{/if}
|
|
81
104
|
</span>
|
|
82
105
|
|
|
@@ -97,6 +120,8 @@ function handle_keydown(event) {
|
|
|
97
120
|
|
|
98
121
|
span {
|
|
99
122
|
flex: 1 1 0%;
|
|
123
|
+
position: relative;
|
|
124
|
+
display: inline-block;
|
|
100
125
|
outline: none;
|
|
101
126
|
padding: var(--size-2);
|
|
102
127
|
-webkit-user-select: text;
|
|
@@ -104,11 +129,31 @@ function handle_keydown(event) {
|
|
|
104
129
|
-ms-user-select: text;
|
|
105
130
|
user-select: text;
|
|
106
131
|
cursor: text;
|
|
132
|
+
width: 100%;
|
|
133
|
+
height: 100%;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
input:where(:not(.header), [data-editable="true"]) {
|
|
137
|
+
width: calc(100% - var(--size-10));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
span.expanded {
|
|
141
|
+
height: auto;
|
|
142
|
+
min-height: 100%;
|
|
143
|
+
white-space: pre-wrap;
|
|
144
|
+
word-break: break-word;
|
|
145
|
+
white-space: normal;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.multiline {
|
|
149
|
+
white-space: pre-line;
|
|
107
150
|
}
|
|
108
151
|
|
|
109
152
|
.header {
|
|
110
153
|
transform: translateX(0);
|
|
111
154
|
font-weight: var(--weight-bold);
|
|
155
|
+
white-space: normal;
|
|
156
|
+
word-break: break-word;
|
|
112
157
|
}
|
|
113
158
|
|
|
114
159
|
.edit {
|
|
@@ -16,13 +16,13 @@ declare const __propDef: {
|
|
|
16
16
|
line_breaks?: boolean | undefined;
|
|
17
17
|
editable?: boolean | undefined;
|
|
18
18
|
root: string;
|
|
19
|
+
max_chars?: (number | null) | undefined;
|
|
19
20
|
el: HTMLInputElement | null;
|
|
20
21
|
};
|
|
21
22
|
events: {
|
|
22
23
|
mousedown: MouseEvent;
|
|
23
24
|
mouseup: MouseEvent;
|
|
24
25
|
click: MouseEvent;
|
|
25
|
-
dblclick: MouseEvent;
|
|
26
26
|
focus: FocusEvent;
|
|
27
27
|
blur: CustomEvent<any>;
|
|
28
28
|
keydown: CustomEvent<any>;
|