@gradio/code 0.15.1-dev.0 → 0.16.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 +40 -0
- package/Index.svelte +45 -59
- package/dist/Example.svelte +11 -9
- package/dist/Example.svelte.d.ts +20 -18
- package/dist/Index.svelte +63 -61
- package/dist/Index.svelte.d.ts +3 -42
- package/dist/shared/Code.svelte +281 -225
- package/dist/shared/Code.svelte.d.ts +36 -33
- package/dist/shared/Copy.svelte +27 -22
- package/dist/shared/Copy.svelte.d.ts +19 -16
- package/dist/shared/Download.svelte +54 -45
- package/dist/shared/Download.svelte.d.ts +20 -17
- package/dist/shared/Widgets.svelte +7 -5
- package/dist/shared/Widgets.svelte.d.ts +19 -17
- package/dist/types.d.ts +16 -0
- package/dist/types.js +1 -0
- package/package.json +22 -22
- package/shared/Code.svelte +22 -5
- package/types.ts +17 -0
package/dist/shared/Code.svelte
CHANGED
|
@@ -1,228 +1,284 @@
|
|
|
1
|
-
<script
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export let
|
|
20
|
-
export let
|
|
21
|
-
export let
|
|
22
|
-
export let
|
|
23
|
-
export let
|
|
24
|
-
export let
|
|
25
|
-
export let
|
|
26
|
-
export let
|
|
27
|
-
export let
|
|
28
|
-
export let
|
|
29
|
-
export let
|
|
30
|
-
|
|
31
|
-
let
|
|
32
|
-
let
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
function
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
function
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
function
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
function
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createEventDispatcher, onMount } from "svelte";
|
|
3
|
+
import {
|
|
4
|
+
EditorView,
|
|
5
|
+
ViewUpdate,
|
|
6
|
+
keymap,
|
|
7
|
+
placeholder as placeholderExt,
|
|
8
|
+
lineNumbers
|
|
9
|
+
} from "@codemirror/view";
|
|
10
|
+
import { StateEffect, EditorState, type Extension } from "@codemirror/state";
|
|
11
|
+
import { indentWithTab } from "@codemirror/commands";
|
|
12
|
+
import { autocompletion, acceptCompletion } from "@codemirror/autocomplete";
|
|
13
|
+
|
|
14
|
+
import { basicDark } from "cm6-theme-basic-dark";
|
|
15
|
+
import { basicLight } from "cm6-theme-basic-light";
|
|
16
|
+
import { basicSetup } from "./extensions";
|
|
17
|
+
import { getLanguageExtension } from "./language";
|
|
18
|
+
|
|
19
|
+
export let class_names = "";
|
|
20
|
+
export let value = "";
|
|
21
|
+
export let dark_mode: boolean;
|
|
22
|
+
export let basic = true;
|
|
23
|
+
export let language: string;
|
|
24
|
+
export let lines = 5;
|
|
25
|
+
export let max_lines: number | null = null;
|
|
26
|
+
export let extensions: Extension[] = [];
|
|
27
|
+
export let use_tab = true;
|
|
28
|
+
export let readonly = false;
|
|
29
|
+
export let placeholder: string | HTMLElement | null | undefined = undefined;
|
|
30
|
+
export let wrap_lines = false;
|
|
31
|
+
export let show_line_numbers = true;
|
|
32
|
+
export let autocomplete = false;
|
|
33
|
+
|
|
34
|
+
const dispatch = createEventDispatcher<{
|
|
35
|
+
change: string;
|
|
36
|
+
blur: undefined;
|
|
37
|
+
focus: undefined;
|
|
38
|
+
input: undefined;
|
|
39
|
+
}>();
|
|
40
|
+
let lang_extension: Extension | undefined;
|
|
41
|
+
let element: HTMLDivElement;
|
|
42
|
+
let view: EditorView;
|
|
43
|
+
|
|
44
|
+
$: get_lang(language);
|
|
45
|
+
|
|
46
|
+
async function get_lang(val: string): Promise<void> {
|
|
47
|
+
const ext = await getLanguageExtension(val);
|
|
48
|
+
lang_extension = ext;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
$: (reconfigure(), lang_extension, readonly);
|
|
52
|
+
$: set_doc(value);
|
|
53
|
+
$: update_lines();
|
|
54
|
+
|
|
55
|
+
function set_doc(new_doc: string): void {
|
|
56
|
+
if (view && new_doc !== view.state.doc.toString()) {
|
|
57
|
+
view.dispatch({
|
|
58
|
+
changes: {
|
|
59
|
+
from: 0,
|
|
60
|
+
to: view.state.doc.length,
|
|
61
|
+
insert: new_doc
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function update_lines(): void {
|
|
68
|
+
if (view) {
|
|
69
|
+
view.requestMeasure({ read: resize });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function create_editor_view(): EditorView {
|
|
74
|
+
const editorView = new EditorView({
|
|
75
|
+
parent: element,
|
|
76
|
+
state: create_editor_state(value)
|
|
77
|
+
});
|
|
78
|
+
editorView.dom.addEventListener("focus", handle_focus, true);
|
|
79
|
+
editorView.dom.addEventListener("blur", handle_blur, true);
|
|
80
|
+
return editorView;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function handle_focus(): void {
|
|
84
|
+
dispatch("focus");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function handle_blur(): void {
|
|
88
|
+
dispatch("blur");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function getGutterLineHeight(_view: EditorView): string | null {
|
|
92
|
+
let elements = _view.dom.querySelectorAll<HTMLElement>(".cm-gutterElement");
|
|
93
|
+
if (elements.length === 0) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
for (var i = 0; i < elements.length; i++) {
|
|
97
|
+
let node = elements[i];
|
|
98
|
+
let height = getComputedStyle(node)?.height ?? "0px";
|
|
99
|
+
if (height != "0px") {
|
|
100
|
+
return height;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function resize(_view: EditorView): any {
|
|
107
|
+
let scroller = _view.dom.querySelector<HTMLElement>(".cm-scroller");
|
|
108
|
+
if (!scroller) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const lineHeight = getGutterLineHeight(_view);
|
|
112
|
+
if (!lineHeight) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const minLines = lines == 1 ? 1 : lines + 1;
|
|
117
|
+
scroller.style.minHeight = `calc(${lineHeight} * ${minLines})`;
|
|
118
|
+
if (max_lines)
|
|
119
|
+
scroller.style.maxHeight = `calc(${lineHeight} * ${max_lines + 1})`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
import { Transaction } from "@codemirror/state";
|
|
123
|
+
|
|
124
|
+
function is_user_input(update: ViewUpdate): boolean {
|
|
125
|
+
return update.transactions.some(
|
|
126
|
+
(tr) => tr.annotation(Transaction.userEvent) != null
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function handle_change(vu: ViewUpdate): void {
|
|
131
|
+
if (!vu.docChanged) return;
|
|
132
|
+
|
|
133
|
+
const doc = vu.state.doc;
|
|
134
|
+
const text = doc.toString();
|
|
135
|
+
value = text;
|
|
136
|
+
|
|
137
|
+
const user_change = is_user_input(vu);
|
|
138
|
+
if (user_change) {
|
|
139
|
+
dispatch("change", text);
|
|
140
|
+
dispatch("input");
|
|
141
|
+
} else {
|
|
142
|
+
dispatch("change", text);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
view.requestMeasure({ read: resize });
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function get_extensions(): Extension[] {
|
|
149
|
+
const stateExtensions = [
|
|
150
|
+
...get_base_extensions(
|
|
151
|
+
basic,
|
|
152
|
+
use_tab,
|
|
153
|
+
placeholder,
|
|
154
|
+
readonly,
|
|
155
|
+
lang_extension,
|
|
156
|
+
show_line_numbers
|
|
157
|
+
),
|
|
158
|
+
FontTheme,
|
|
159
|
+
...get_theme(),
|
|
160
|
+
...extensions
|
|
161
|
+
];
|
|
162
|
+
return stateExtensions;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const FontTheme = EditorView.theme({
|
|
166
|
+
"&": {
|
|
167
|
+
fontSize: "var(--text-sm)",
|
|
168
|
+
backgroundColor: "var(--border-color-secondary)"
|
|
169
|
+
},
|
|
170
|
+
".cm-content": {
|
|
171
|
+
paddingTop: "5px",
|
|
172
|
+
paddingBottom: "5px",
|
|
173
|
+
color: "var(--body-text-color)",
|
|
174
|
+
fontFamily: "var(--font-mono)",
|
|
175
|
+
minHeight: "100%"
|
|
176
|
+
},
|
|
177
|
+
".cm-gutterElement": {
|
|
178
|
+
marginRight: "var(--spacing-xs)"
|
|
179
|
+
},
|
|
180
|
+
".cm-gutters": {
|
|
181
|
+
marginRight: "1px",
|
|
182
|
+
borderRight: "1px solid var(--border-color-primary)",
|
|
183
|
+
backgroundColor: "var(--block-background-fill);",
|
|
184
|
+
color: "var(--body-text-color-subdued)"
|
|
185
|
+
},
|
|
186
|
+
".cm-focused": {
|
|
187
|
+
outline: "none"
|
|
188
|
+
},
|
|
189
|
+
".cm-scroller": {
|
|
190
|
+
height: "auto"
|
|
191
|
+
},
|
|
192
|
+
".cm-cursor": {
|
|
193
|
+
borderLeftColor: "var(--body-text-color)"
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const AutocompleteTheme = EditorView.theme({
|
|
198
|
+
".cm-tooltip-autocomplete": {
|
|
199
|
+
"& > ul": {
|
|
200
|
+
backgroundColor: "var(--background-fill-primary)",
|
|
201
|
+
color: "var(--body-text-color)"
|
|
202
|
+
},
|
|
203
|
+
"& > ul > li[aria-selected]": {
|
|
204
|
+
backgroundColor: "var(--color-accent-soft)",
|
|
205
|
+
color: "var(--body-text-color)"
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
function create_editor_state(_value: string | null | undefined): EditorState {
|
|
211
|
+
return EditorState.create({
|
|
212
|
+
doc: _value ?? undefined,
|
|
213
|
+
extensions: get_extensions()
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function get_base_extensions(
|
|
218
|
+
basic: boolean,
|
|
219
|
+
use_tab: boolean,
|
|
220
|
+
placeholder: string | HTMLElement | null | undefined,
|
|
221
|
+
readonly: boolean,
|
|
222
|
+
lang: Extension | null | undefined,
|
|
223
|
+
show_line_numbers: boolean
|
|
224
|
+
): Extension[] {
|
|
225
|
+
const extensions: Extension[] = [
|
|
226
|
+
EditorView.editable.of(!readonly),
|
|
227
|
+
EditorState.readOnly.of(readonly),
|
|
228
|
+
EditorView.contentAttributes.of({ "aria-label": "Code input container" })
|
|
229
|
+
];
|
|
230
|
+
|
|
231
|
+
if (basic) {
|
|
232
|
+
extensions.push(basicSetup);
|
|
233
|
+
}
|
|
234
|
+
if (use_tab) {
|
|
235
|
+
extensions.push(
|
|
236
|
+
keymap.of([{ key: "Tab", run: acceptCompletion }, indentWithTab])
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
if (placeholder) {
|
|
240
|
+
extensions.push(placeholderExt(placeholder));
|
|
241
|
+
}
|
|
242
|
+
if (lang) {
|
|
243
|
+
extensions.push(lang);
|
|
244
|
+
}
|
|
245
|
+
if (show_line_numbers) {
|
|
246
|
+
extensions.push(lineNumbers());
|
|
247
|
+
}
|
|
248
|
+
if (autocomplete) {
|
|
249
|
+
extensions.push(autocompletion());
|
|
250
|
+
extensions.push(AutocompleteTheme);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
extensions.push(EditorView.updateListener.of(handle_change));
|
|
254
|
+
if (wrap_lines) {
|
|
255
|
+
extensions.push(EditorView.lineWrapping);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return extensions;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function get_theme(): Extension[] {
|
|
262
|
+
const extensions: Extension[] = [];
|
|
263
|
+
|
|
264
|
+
if (dark_mode) {
|
|
265
|
+
extensions.push(basicDark);
|
|
266
|
+
} else {
|
|
267
|
+
extensions.push(basicLight);
|
|
268
|
+
}
|
|
269
|
+
return extensions;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function reconfigure(): void {
|
|
273
|
+
view?.dispatch({
|
|
274
|
+
effects: StateEffect.reconfigure.of(get_extensions())
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
onMount(() => {
|
|
279
|
+
view = create_editor_view();
|
|
280
|
+
return () => view?.destroy();
|
|
281
|
+
});
|
|
226
282
|
</script>
|
|
227
283
|
|
|
228
284
|
<div class="wrap">
|
|
@@ -1,36 +1,39 @@
|
|
|
1
|
-
import { SvelteComponent } from "svelte";
|
|
2
1
|
import { type Extension } from "@codemirror/state";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
use_tab?: boolean;
|
|
14
|
-
readonly?: boolean;
|
|
15
|
-
placeholder?: string | HTMLElement | null | undefined;
|
|
16
|
-
wrap_lines?: boolean;
|
|
17
|
-
show_line_numbers?: boolean;
|
|
18
|
-
autocomplete?: boolean;
|
|
2
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
+
$$bindings?: Bindings;
|
|
5
|
+
} & Exports;
|
|
6
|
+
(internal: unknown, props: Props & {
|
|
7
|
+
$$events?: Events;
|
|
8
|
+
$$slots?: Slots;
|
|
9
|
+
}): Exports & {
|
|
10
|
+
$set?: any;
|
|
11
|
+
$on?: any;
|
|
19
12
|
};
|
|
20
|
-
|
|
21
|
-
change: CustomEvent<string>;
|
|
22
|
-
blur: CustomEvent<undefined>;
|
|
23
|
-
focus: CustomEvent<undefined>;
|
|
24
|
-
} & {
|
|
25
|
-
[evt: string]: CustomEvent<any>;
|
|
26
|
-
};
|
|
27
|
-
slots: {};
|
|
28
|
-
exports?: {} | undefined;
|
|
29
|
-
bindings?: string | undefined;
|
|
30
|
-
};
|
|
31
|
-
export type CodeProps = typeof __propDef.props;
|
|
32
|
-
export type CodeEvents = typeof __propDef.events;
|
|
33
|
-
export type CodeSlots = typeof __propDef.slots;
|
|
34
|
-
export default class Code extends SvelteComponent<CodeProps, CodeEvents, CodeSlots> {
|
|
13
|
+
z_$$bindings?: Bindings;
|
|
35
14
|
}
|
|
36
|
-
|
|
15
|
+
declare const Code: $$__sveltets_2_IsomorphicComponent<{
|
|
16
|
+
class_names?: string;
|
|
17
|
+
value?: string;
|
|
18
|
+
dark_mode: boolean;
|
|
19
|
+
basic?: boolean;
|
|
20
|
+
language: string;
|
|
21
|
+
lines?: number;
|
|
22
|
+
max_lines?: number | null;
|
|
23
|
+
extensions?: Extension[];
|
|
24
|
+
use_tab?: boolean;
|
|
25
|
+
readonly?: boolean;
|
|
26
|
+
placeholder?: string | HTMLElement | null | undefined;
|
|
27
|
+
wrap_lines?: boolean;
|
|
28
|
+
show_line_numbers?: boolean;
|
|
29
|
+
autocomplete?: boolean;
|
|
30
|
+
}, {
|
|
31
|
+
change: CustomEvent<string>;
|
|
32
|
+
blur: CustomEvent<undefined>;
|
|
33
|
+
focus: CustomEvent<undefined>;
|
|
34
|
+
input: CustomEvent<undefined>;
|
|
35
|
+
} & {
|
|
36
|
+
[evt: string]: CustomEvent<any>;
|
|
37
|
+
}, {}, {}, string>;
|
|
38
|
+
type Code = InstanceType<typeof Code>;
|
|
39
|
+
export default Code;
|
package/dist/shared/Copy.svelte
CHANGED
|
@@ -1,25 +1,30 @@
|
|
|
1
|
-
<script
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onDestroy } from "svelte";
|
|
3
|
+
import { Copy, Check } from "@gradio/icons";
|
|
4
|
+
import { IconButton } from "@gradio/atoms";
|
|
5
|
+
|
|
6
|
+
let copied = false;
|
|
7
|
+
export let value: string;
|
|
8
|
+
let timer: NodeJS.Timeout;
|
|
9
|
+
|
|
10
|
+
function copy_feedback(): void {
|
|
11
|
+
copied = true;
|
|
12
|
+
if (timer) clearTimeout(timer);
|
|
13
|
+
timer = setTimeout(() => {
|
|
14
|
+
copied = false;
|
|
15
|
+
}, 2000);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function handle_copy(): Promise<void> {
|
|
19
|
+
if ("clipboard" in navigator) {
|
|
20
|
+
await navigator.clipboard.writeText(value);
|
|
21
|
+
copy_feedback();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
onDestroy(() => {
|
|
26
|
+
if (timer) clearTimeout(timer);
|
|
27
|
+
});
|
|
23
28
|
</script>
|
|
24
29
|
|
|
25
30
|
<IconButton Icon={copied ? Check : Copy} on:click={handle_copy} />
|