@gradio/core 1.0.0-dev.0 → 1.0.0-dev.3
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 +79 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/src/Blocks.svelte +518 -1001
- package/dist/src/Blocks.svelte.d.ts +31 -45
- package/dist/src/Embed.svelte +82 -55
- package/dist/src/Embed.svelte.d.ts +39 -30
- package/dist/src/Login.svelte +33 -29
- package/dist/src/Login.svelte.d.ts +21 -19
- package/dist/src/MountComponents.svelte +19 -25
- package/dist/src/MountComponents.svelte.d.ts +5 -28
- package/dist/src/{init.d.ts → _init.d.ts} +5 -4
- package/dist/src/{init.js → _init.js} +31 -108
- package/dist/src/api_docs/ApiBanner.svelte +12 -8
- package/dist/src/api_docs/ApiBanner.svelte.d.ts +22 -20
- package/dist/src/api_docs/ApiDocs.svelte +337 -245
- package/dist/src/api_docs/ApiDocs.svelte.d.ts +26 -24
- package/dist/src/api_docs/ApiRecorder.svelte +9 -3
- package/dist/src/api_docs/ApiRecorder.svelte.d.ts +19 -17
- package/dist/src/api_docs/CodeSnippet.svelte +60 -30
- package/dist/src/api_docs/CodeSnippet.svelte.d.ts +27 -24
- package/dist/src/api_docs/CopyButton.svelte +69 -13
- package/dist/src/api_docs/CopyButton.svelte.d.ts +18 -16
- package/dist/src/api_docs/CopyMarkdown.svelte +734 -0
- package/dist/src/api_docs/CopyMarkdown.svelte.d.ts +37 -0
- package/dist/src/api_docs/EndpointDetail.svelte +8 -6
- package/dist/src/api_docs/EndpointDetail.svelte.d.ts +20 -18
- package/dist/src/api_docs/IconArrowUpRight.svelte +34 -0
- package/dist/src/api_docs/IconArrowUpRight.svelte.d.ts +20 -0
- package/dist/src/api_docs/IconCaret.svelte +39 -0
- package/dist/src/api_docs/IconCaret.svelte.d.ts +20 -0
- package/dist/src/api_docs/IconHuggingChat.svelte +62 -0
- package/dist/src/api_docs/IconHuggingChat.svelte.d.ts +20 -0
- package/dist/src/api_docs/InputPayload.svelte +17 -11
- package/dist/src/api_docs/InputPayload.svelte.d.ts +25 -23
- package/dist/src/api_docs/InstallSnippet.svelte +9 -6
- package/dist/src/api_docs/InstallSnippet.svelte.d.ts +18 -16
- package/dist/src/api_docs/MCPSnippet.svelte +119 -99
- package/dist/src/api_docs/MCPSnippet.svelte.d.ts +59 -58
- package/dist/src/api_docs/NoApi.svelte +7 -4
- package/dist/src/api_docs/NoApi.svelte.d.ts +20 -18
- package/dist/src/api_docs/ParametersSnippet.svelte +8 -6
- package/dist/src/api_docs/ParametersSnippet.svelte.d.ts +21 -19
- package/dist/src/api_docs/RecordingSnippet.svelte +124 -110
- package/dist/src/api_docs/RecordingSnippet.svelte.d.ts +24 -22
- package/dist/src/api_docs/ResponseSnippet.svelte +7 -5
- package/dist/src/api_docs/ResponseSnippet.svelte.d.ts +21 -19
- package/dist/src/api_docs/Settings.svelte +73 -62
- package/dist/src/api_docs/Settings.svelte.d.ts +25 -23
- package/dist/src/api_docs/SettingsBanner.svelte +11 -8
- package/dist/src/api_docs/SettingsBanner.svelte.d.ts +20 -18
- package/dist/src/api_docs/TryButton.svelte +5 -3
- package/dist/src/api_docs/TryButton.svelte.d.ts +19 -17
- package/dist/src/api_docs/img/IconCheck.svelte +33 -0
- package/dist/src/api_docs/img/IconCheck.svelte.d.ts +26 -0
- package/dist/src/api_docs/img/IconCopy.svelte +40 -0
- package/dist/src/api_docs/img/IconCopy.svelte.d.ts +26 -0
- package/dist/src/api_docs/img/clear.svelte.d.ts +22 -21
- package/dist/src/dependency.d.ts +142 -0
- package/dist/src/dependency.js +653 -0
- package/dist/src/init.svelte.d.ts +78 -0
- package/dist/src/init.svelte.js +469 -0
- package/dist/src/init_utils.d.ts +32 -0
- package/dist/src/init_utils.js +73 -0
- package/dist/src/lang/en.json +10 -1
- package/dist/src/lang/get_lang_names.js +0 -3
- package/dist/src/lang/ru.json +10 -1
- package/dist/src/stores.d.ts +0 -21
- package/dist/src/stories/I18nMultiLanguageTestComponent.svelte +5 -3
- package/dist/src/stories/I18nMultiLanguageTestComponent.svelte.d.ts +16 -14
- package/dist/src/stories/I18nTestSetup.svelte +14 -10
- package/dist/src/stories/I18nTestSetup.svelte.d.ts +18 -16
- package/dist/src/types.d.ts +30 -26
- package/index.ts +1 -1
- package/package.json +59 -59
- package/src/Blocks.svelte +344 -1063
- package/src/MountComponents.svelte +17 -27
- package/src/{init.ts → _init.ts} +49 -126
- package/src/api_docs/ApiDocs.svelte +65 -60
- package/src/api_docs/ApiRecorder.svelte +3 -0
- package/src/api_docs/CodeSnippet.svelte +20 -5
- package/src/api_docs/CopyButton.svelte +61 -7
- package/src/api_docs/CopyMarkdown.svelte +734 -0
- package/src/api_docs/IconArrowUpRight.svelte +34 -0
- package/src/api_docs/IconCaret.svelte +39 -0
- package/src/api_docs/IconHuggingChat.svelte +62 -0
- package/src/api_docs/MCPSnippet.svelte +24 -46
- package/src/api_docs/ParametersSnippet.svelte +1 -1
- package/src/api_docs/ResponseSnippet.svelte +1 -1
- package/src/api_docs/Settings.svelte +11 -11
- package/src/api_docs/img/IconCheck.svelte +33 -0
- package/src/api_docs/img/IconCopy.svelte +40 -0
- package/src/dependency.ts +880 -0
- package/src/init.svelte.ts +717 -0
- package/src/init_utils.ts +99 -0
- package/src/lang/en.json +10 -1
- package/src/lang/get_lang_names.js +0 -3
- package/src/lang/ru.json +10 -1
- package/src/stores.ts +22 -22
- package/src/types.ts +54 -43
- package/dist/src/Render.svelte +0 -105
- package/dist/src/Render.svelte.d.ts +0 -31
- package/dist/src/RenderComponent.svelte +0 -72
- package/dist/src/RenderComponent.svelte.d.ts +0 -33
- package/src/Render.svelte +0 -126
- package/src/RenderComponent.svelte +0 -91
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { ComponentMeta, ProcessedComponentMeta, LayoutNode, Dependency, AppConfig, ServerFunctions } from "./types";
|
|
2
|
+
import type { SharedProps } from "@gradio/utils";
|
|
3
|
+
import { Client } from "@gradio/client";
|
|
4
|
+
type client_return = Awaited<ReturnType<typeof Client.connect>>;
|
|
5
|
+
type set_data_type = (data: Record<string, unknown>) => void;
|
|
6
|
+
type get_data_type = () => Promise<Record<string, unknown>>;
|
|
7
|
+
type visitor<T> = (node: T) => ProcessedComponentMeta;
|
|
8
|
+
type Tab = {
|
|
9
|
+
label: string;
|
|
10
|
+
id: string;
|
|
11
|
+
visible: boolean;
|
|
12
|
+
interactive: boolean;
|
|
13
|
+
elem_id: string | undefined;
|
|
14
|
+
scale: number | null;
|
|
15
|
+
order?: number;
|
|
16
|
+
};
|
|
17
|
+
export declare class AppTree {
|
|
18
|
+
#private;
|
|
19
|
+
/** Need this to set i18n in re-render */
|
|
20
|
+
reactive_formatter: (str: string) => string;
|
|
21
|
+
client: client_return;
|
|
22
|
+
/** the root node of the processed layout tree */
|
|
23
|
+
root: ProcessedComponentMeta | undefined;
|
|
24
|
+
component_ids: number[];
|
|
25
|
+
initial_tabs: Record<number, Tab[]>;
|
|
26
|
+
components_to_register: Set<number>;
|
|
27
|
+
ready: Promise<void>;
|
|
28
|
+
ready_resolve: () => void;
|
|
29
|
+
resolved: boolean;
|
|
30
|
+
constructor(components: ComponentMeta[], layout: LayoutNode, dependencies: Dependency[], config: AppConfig, app: client_return, reactive_formatter: (str: string) => string);
|
|
31
|
+
reload(components: ComponentMeta[], layout: LayoutNode, dependencies: Dependency[], config: AppConfig): void;
|
|
32
|
+
/**
|
|
33
|
+
* Registers a component with its ID and data callbacks
|
|
34
|
+
* @param id the ID of the component
|
|
35
|
+
* @param _set_data the set data callback
|
|
36
|
+
* @param _get_data the get data callback
|
|
37
|
+
*/
|
|
38
|
+
register_component(id: number, _set_data: set_data_type, _get_data: get_data_type): void;
|
|
39
|
+
/**
|
|
40
|
+
* Preprocess the payloads to get the correct state read to build the tree
|
|
41
|
+
*/
|
|
42
|
+
prepare(): void;
|
|
43
|
+
/** Processes the layout payload into a tree of components */
|
|
44
|
+
process(): void;
|
|
45
|
+
postprocess(tree: ProcessedComponentMeta): void;
|
|
46
|
+
find_attached_events(node: ProcessedComponentMeta, dependencies: Dependency[]): ProcessedComponentMeta;
|
|
47
|
+
/**
|
|
48
|
+
* Traverses the layout tree and applies a callback to each node
|
|
49
|
+
* @param node the current layout node
|
|
50
|
+
* @param visit the callback to apply to each node
|
|
51
|
+
* @returns the return value of the callback, with a `children` property added for any child nodes
|
|
52
|
+
*/
|
|
53
|
+
traverse<T extends LayoutNode | ProcessedComponentMeta>(node: T, visit: visitor<T> | visitor<T>[]): ProcessedComponentMeta;
|
|
54
|
+
/**
|
|
55
|
+
* Creates a processed component node from a layout node
|
|
56
|
+
* @param opts the layout node options
|
|
57
|
+
* @param root whether this is the root node
|
|
58
|
+
* @returns the processed component node
|
|
59
|
+
*/
|
|
60
|
+
create_node(opts: LayoutNode, component_map: Map<number, ComponentMeta>, root?: boolean, reactive_formatter?: (str: string) => string): ProcessedComponentMeta;
|
|
61
|
+
rerender(components: ComponentMeta[], layout: LayoutNode): void;
|
|
62
|
+
update_state(id: number, new_state: Partial<SharedProps> & Record<string, unknown>, check_visibility?: boolean): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Gets the current state of a component by its ID
|
|
65
|
+
* @param id the ID of the component to get the state of
|
|
66
|
+
* @returns the current state of the component, or null if not found
|
|
67
|
+
*/
|
|
68
|
+
get_state(id: number): Promise<Record<string, unknown> | null>;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Process the server function names and return a dictionary of functions
|
|
72
|
+
* @param id the component id
|
|
73
|
+
* @param server_fns the server function names
|
|
74
|
+
* @param app the client instance
|
|
75
|
+
* @returns the actual server functions
|
|
76
|
+
*/
|
|
77
|
+
export declare function process_server_fn(id: number, server_fns: string[] | undefined, app: client_return): ServerFunctions;
|
|
78
|
+
export {};
|
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import { determine_interactivity, get_component, get_inputs_outputs } from "./init_utils";
|
|
2
|
+
import { translate_if_needed } from "./i18n";
|
|
3
|
+
import { tick } from "svelte";
|
|
4
|
+
import { allowed_shared_props } from "@gradio/utils";
|
|
5
|
+
import { Client } from "@gradio/client";
|
|
6
|
+
const type_map = {
|
|
7
|
+
walkthrough: "tabs",
|
|
8
|
+
walkthroughstep: "tabitem"
|
|
9
|
+
};
|
|
10
|
+
export class AppTree {
|
|
11
|
+
/** the raw component structure received from the backend */
|
|
12
|
+
#component_payload;
|
|
13
|
+
/** the raw layout node structure received from the backend */
|
|
14
|
+
#layout_payload;
|
|
15
|
+
/** the raw dependency structure received from the backend */
|
|
16
|
+
#dependency_payload;
|
|
17
|
+
/** Need this to set i18n in re-render */
|
|
18
|
+
reactive_formatter = (str) => str;
|
|
19
|
+
/** the config for the app */
|
|
20
|
+
#config;
|
|
21
|
+
client;
|
|
22
|
+
/** the root node of the processed layout tree */
|
|
23
|
+
root = $state();
|
|
24
|
+
/** a set of all component IDs that are inputs to dependencies */
|
|
25
|
+
#input_ids = new Set();
|
|
26
|
+
/** a set of all component IDs that are outputs of dependencies */
|
|
27
|
+
#output_ids = new Set();
|
|
28
|
+
/** A list of components that are currently loading */
|
|
29
|
+
#pending_components = [];
|
|
30
|
+
#get_callbacks = new Map();
|
|
31
|
+
#set_callbacks = new Map();
|
|
32
|
+
component_ids;
|
|
33
|
+
initial_tabs = {};
|
|
34
|
+
components_to_register = new Set();
|
|
35
|
+
ready;
|
|
36
|
+
ready_resolve;
|
|
37
|
+
resolved = false;
|
|
38
|
+
constructor(components, layout, dependencies, config, app, reactive_formatter) {
|
|
39
|
+
this.ready = new Promise((resolve) => {
|
|
40
|
+
this.ready_resolve = resolve;
|
|
41
|
+
});
|
|
42
|
+
this.reactive_formatter = reactive_formatter;
|
|
43
|
+
this.#config = config;
|
|
44
|
+
this.#component_payload = components;
|
|
45
|
+
this.#layout_payload = layout;
|
|
46
|
+
this.#dependency_payload = dependencies;
|
|
47
|
+
this.root = this.create_node({ id: layout.id, children: [] }, new Map(), true);
|
|
48
|
+
for (const comp of components) {
|
|
49
|
+
if (comp.props.visible != false)
|
|
50
|
+
this.components_to_register.add(comp.id);
|
|
51
|
+
}
|
|
52
|
+
this.client = app;
|
|
53
|
+
this.prepare();
|
|
54
|
+
const component_map = components.reduce((map, comp) => {
|
|
55
|
+
map.set(comp.id, comp);
|
|
56
|
+
return map;
|
|
57
|
+
}, new Map());
|
|
58
|
+
this.root.children = this.#layout_payload.children.map((node) => this.traverse(node, (node) => {
|
|
59
|
+
const new_node = this.create_node(node, component_map, false, this.reactive_formatter);
|
|
60
|
+
return new_node;
|
|
61
|
+
}));
|
|
62
|
+
this.component_ids = components.map((c) => c.id);
|
|
63
|
+
this.initial_tabs = {};
|
|
64
|
+
gather_initial_tabs(this.root, this.initial_tabs);
|
|
65
|
+
this.postprocess(this.root);
|
|
66
|
+
}
|
|
67
|
+
reload(components, layout, dependencies, config) {
|
|
68
|
+
this.#layout_payload = layout;
|
|
69
|
+
this.#component_payload = components;
|
|
70
|
+
this.#config = config;
|
|
71
|
+
this.#dependency_payload = dependencies;
|
|
72
|
+
this.root = this.create_node({ id: layout.id, children: [] }, new Map(), true);
|
|
73
|
+
for (const comp of components) {
|
|
74
|
+
if (comp.props.visible != false)
|
|
75
|
+
this.components_to_register.add(comp.id);
|
|
76
|
+
}
|
|
77
|
+
this.prepare();
|
|
78
|
+
const component_map = components.reduce((map, comp) => {
|
|
79
|
+
map.set(comp.id, comp);
|
|
80
|
+
return map;
|
|
81
|
+
}, new Map());
|
|
82
|
+
this.root.children = this.#layout_payload.children.map((node) => this.traverse(node, (node) => {
|
|
83
|
+
const new_node = this.create_node(node, component_map, false, this.reactive_formatter);
|
|
84
|
+
return new_node;
|
|
85
|
+
}));
|
|
86
|
+
this.component_ids = components.map((c) => c.id);
|
|
87
|
+
this.initial_tabs = {};
|
|
88
|
+
gather_initial_tabs(this.root, this.initial_tabs);
|
|
89
|
+
this.postprocess(this.root);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Registers a component with its ID and data callbacks
|
|
93
|
+
* @param id the ID of the component
|
|
94
|
+
* @param _set_data the set data callback
|
|
95
|
+
* @param _get_data the get data callback
|
|
96
|
+
*/
|
|
97
|
+
register_component(id, _set_data, _get_data) {
|
|
98
|
+
this.#set_callbacks.set(id, _set_data);
|
|
99
|
+
this.#get_callbacks.set(id, _get_data);
|
|
100
|
+
this.components_to_register.delete(id);
|
|
101
|
+
if (this.components_to_register.size === 0 && !this.resolved) {
|
|
102
|
+
this.resolved = true;
|
|
103
|
+
this.ready_resolve();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Preprocess the payloads to get the correct state read to build the tree
|
|
108
|
+
*/
|
|
109
|
+
prepare() {
|
|
110
|
+
const [inputs, outputs] = get_inputs_outputs(this.#dependency_payload);
|
|
111
|
+
this.#input_ids = inputs;
|
|
112
|
+
this.#output_ids = outputs;
|
|
113
|
+
}
|
|
114
|
+
/** Processes the layout payload into a tree of components */
|
|
115
|
+
process() { }
|
|
116
|
+
postprocess(tree) {
|
|
117
|
+
this.root = this.traverse(tree, [
|
|
118
|
+
(node) => handle_visibility(node, this.#config.root),
|
|
119
|
+
(node) => untrack_children_of_invisible_parents(node, this.#config.root, this.components_to_register),
|
|
120
|
+
(node) => handle_empty_forms(node, this.#config.root, this.components_to_register),
|
|
121
|
+
(node) => translate_props(node, this.#config.root),
|
|
122
|
+
(node) => apply_initial_tabs(node, this.#config.root, this.initial_tabs),
|
|
123
|
+
(node) => this.find_attached_events(node, this.#dependency_payload)
|
|
124
|
+
]);
|
|
125
|
+
}
|
|
126
|
+
find_attached_events(node, dependencies) {
|
|
127
|
+
const attached_events = dependencies
|
|
128
|
+
.filter((dep) => dep.targets.find(([id]) => id === node.id))
|
|
129
|
+
.map((dep) => {
|
|
130
|
+
const target = dep.targets.find(([id]) => id === node.id);
|
|
131
|
+
return target ? target[1] : null;
|
|
132
|
+
})
|
|
133
|
+
.filter(Boolean);
|
|
134
|
+
node.props.shared_props.attached_events = attached_events;
|
|
135
|
+
return node;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Traverses the layout tree and applies a callback to each node
|
|
139
|
+
* @param node the current layout node
|
|
140
|
+
* @param visit the callback to apply to each node
|
|
141
|
+
* @returns the return value of the callback, with a `children` property added for any child nodes
|
|
142
|
+
*/
|
|
143
|
+
traverse(node, visit) {
|
|
144
|
+
function single_visit(node, visit, traverse_fn) {
|
|
145
|
+
const result = visit(node);
|
|
146
|
+
if ("children" in node && node.children.length > 0) {
|
|
147
|
+
result.children =
|
|
148
|
+
node.children?.map((child) => traverse_fn(child, visit)) || [];
|
|
149
|
+
}
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
if (Array.isArray(visit)) {
|
|
153
|
+
let result = node;
|
|
154
|
+
for (const v of visit) {
|
|
155
|
+
result = single_visit(result, v, this.traverse.bind(this));
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
return single_visit(node, visit, this.traverse.bind(this));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Creates a processed component node from a layout node
|
|
165
|
+
* @param opts the layout node options
|
|
166
|
+
* @param root whether this is the root node
|
|
167
|
+
* @returns the processed component node
|
|
168
|
+
*/
|
|
169
|
+
create_node(opts, component_map, root = false, reactive_formatter) {
|
|
170
|
+
let component;
|
|
171
|
+
if (!root) {
|
|
172
|
+
component = component_map.get(opts.id);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
component = {
|
|
176
|
+
type: "column",
|
|
177
|
+
id: opts.id,
|
|
178
|
+
// @ts-ignore
|
|
179
|
+
props: {
|
|
180
|
+
visible: true,
|
|
181
|
+
root: "",
|
|
182
|
+
theme_mode: "light"
|
|
183
|
+
},
|
|
184
|
+
component_class_id: "column",
|
|
185
|
+
key: null
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
if (!component) {
|
|
189
|
+
throw new Error(`Component with ID ${opts.id} not found`);
|
|
190
|
+
}
|
|
191
|
+
if (reactive_formatter) {
|
|
192
|
+
component.props.i18n = reactive_formatter;
|
|
193
|
+
}
|
|
194
|
+
const processed_props = gather_props(opts.id, component.props, [this.#input_ids, this.#output_ids], this.client, { ...this.#config });
|
|
195
|
+
const type = type_map[component.type] || component.type;
|
|
196
|
+
const node = {
|
|
197
|
+
id: opts.id,
|
|
198
|
+
type: type,
|
|
199
|
+
props: processed_props,
|
|
200
|
+
children: [],
|
|
201
|
+
show_progress_on: null,
|
|
202
|
+
component_class_id: component.component_class_id || component.type,
|
|
203
|
+
component: processed_props.shared_props.visible !== false
|
|
204
|
+
? get_component(component.type, component.component_class_id, this.#config.root || "")
|
|
205
|
+
: null,
|
|
206
|
+
key: component.key,
|
|
207
|
+
rendered_in: component.rendered_in,
|
|
208
|
+
documentation: component.documentation
|
|
209
|
+
};
|
|
210
|
+
return node;
|
|
211
|
+
}
|
|
212
|
+
rerender(components, layout) {
|
|
213
|
+
const component_map = components.reduce((map, comp) => {
|
|
214
|
+
map.set(comp.id, comp);
|
|
215
|
+
return map;
|
|
216
|
+
}, new Map());
|
|
217
|
+
const subtree = this.traverse(layout, (node) => {
|
|
218
|
+
const new_node = this.create_node(node, component_map, false, this.reactive_formatter);
|
|
219
|
+
return new_node;
|
|
220
|
+
});
|
|
221
|
+
const n = find_node_by_id(this.root, subtree.id);
|
|
222
|
+
if (!n) {
|
|
223
|
+
throw new Error("Rerender failed: root node not found in current tree");
|
|
224
|
+
}
|
|
225
|
+
n.children = subtree.children;
|
|
226
|
+
}
|
|
227
|
+
/*
|
|
228
|
+
* Updates the state of a component by its ID
|
|
229
|
+
* @param id the ID of the component to update
|
|
230
|
+
* @param new_state the new state to set
|
|
231
|
+
* */
|
|
232
|
+
async update_state(id, new_state, check_visibility = true) {
|
|
233
|
+
// Visibility is tricky 😅
|
|
234
|
+
// If the component is not visible, it has not been rendered
|
|
235
|
+
// and so it has no _set_data callback
|
|
236
|
+
// Therefore, we need to traverse the tree and set the visible prop to true
|
|
237
|
+
// and then render it and its children. After that, we can call the _set_data callback
|
|
238
|
+
const node = find_node_by_id(this.root, id);
|
|
239
|
+
let already_updated_visibility = false;
|
|
240
|
+
if (check_visibility && !node?.component) {
|
|
241
|
+
await tick();
|
|
242
|
+
this.root = this.traverse(this.root, [
|
|
243
|
+
//@ts-ignore
|
|
244
|
+
(n) => set_visibility_for_updated_node(n, id, new_state.visible),
|
|
245
|
+
(n) => handle_visibility(n, this.#config.root)
|
|
246
|
+
]);
|
|
247
|
+
already_updated_visibility = true;
|
|
248
|
+
}
|
|
249
|
+
const _set_data = this.#set_callbacks.get(id);
|
|
250
|
+
if (!_set_data)
|
|
251
|
+
return;
|
|
252
|
+
_set_data(new_state);
|
|
253
|
+
if (!check_visibility || already_updated_visibility)
|
|
254
|
+
return;
|
|
255
|
+
// need to let the UI settle before traversing again
|
|
256
|
+
// otherwise there could be
|
|
257
|
+
await tick();
|
|
258
|
+
this.root = this.traverse(this.root, (n) => handle_visibility(n, this.#config.root));
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Gets the current state of a component by its ID
|
|
262
|
+
* @param id the ID of the component to get the state of
|
|
263
|
+
* @returns the current state of the component, or null if not found
|
|
264
|
+
*/
|
|
265
|
+
async get_state(id) {
|
|
266
|
+
const _get_data = this.#get_callbacks.get(id);
|
|
267
|
+
const component = this.#component_payload.find((c) => c.id === id);
|
|
268
|
+
if (!_get_data && !component)
|
|
269
|
+
return null;
|
|
270
|
+
if (_get_data)
|
|
271
|
+
return await _get_data();
|
|
272
|
+
if (component)
|
|
273
|
+
return Promise.resolve({ value: component.props.value });
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Process the server function names and return a dictionary of functions
|
|
279
|
+
* @param id the component id
|
|
280
|
+
* @param server_fns the server function names
|
|
281
|
+
* @param app the client instance
|
|
282
|
+
* @returns the actual server functions
|
|
283
|
+
*/
|
|
284
|
+
export function process_server_fn(id, server_fns, app) {
|
|
285
|
+
if (!server_fns) {
|
|
286
|
+
return {};
|
|
287
|
+
}
|
|
288
|
+
return server_fns.reduce((acc, fn) => {
|
|
289
|
+
acc[fn] = async (...args) => {
|
|
290
|
+
if (args.length === 1) {
|
|
291
|
+
args = args[0];
|
|
292
|
+
}
|
|
293
|
+
const result = await app.component_server(id, fn, args);
|
|
294
|
+
return result;
|
|
295
|
+
};
|
|
296
|
+
return acc;
|
|
297
|
+
}, {});
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Gathers the props for a component
|
|
301
|
+
* @param id the ID of the component
|
|
302
|
+
* @param props the props of the component
|
|
303
|
+
* @param dependencies the component's dependencies
|
|
304
|
+
* @param additional any additional props to include
|
|
305
|
+
* @returns the gathered props as an object with `shared_props` and `props` keys
|
|
306
|
+
*/
|
|
307
|
+
function gather_props(id, props, dependencies, client, additional = {}) {
|
|
308
|
+
const _shared_props = {};
|
|
309
|
+
const _props = {};
|
|
310
|
+
for (const key in props) {
|
|
311
|
+
// For Tabs (or any component that already has an id prop)
|
|
312
|
+
// Set the id to the props so that it doesn't get overwritten
|
|
313
|
+
if (key === "id" || key === "autoscroll") {
|
|
314
|
+
_props[key] = props[key];
|
|
315
|
+
}
|
|
316
|
+
else if (allowed_shared_props.includes(key)) {
|
|
317
|
+
const _key = key;
|
|
318
|
+
_shared_props[_key] = props[key];
|
|
319
|
+
if (_key === "server_fns") {
|
|
320
|
+
_shared_props.server = process_server_fn(id, props.server_fns, client);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
_props[key] = props[key];
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
for (const key in additional) {
|
|
328
|
+
if (allowed_shared_props.includes(key)) {
|
|
329
|
+
const _key = key;
|
|
330
|
+
_shared_props[_key] = additional[key];
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
_props[key] = additional[key];
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
_shared_props.client = client;
|
|
337
|
+
_shared_props.id = id;
|
|
338
|
+
_shared_props.interactive = determine_interactivity(id, _shared_props.interactive, _props.value, dependencies);
|
|
339
|
+
_shared_props.load_component = (name, variant) => get_component(name, "", _shared_props.root || "", variant);
|
|
340
|
+
_shared_props.visible =
|
|
341
|
+
_shared_props.visible === undefined ? true : _shared_props.visible;
|
|
342
|
+
_shared_props.loading_status = {};
|
|
343
|
+
return { shared_props: _shared_props, props: _props };
|
|
344
|
+
}
|
|
345
|
+
function handle_visibility(node, root) {
|
|
346
|
+
// Check if the node is visible
|
|
347
|
+
if (node.props.shared_props.visible && !node.component) {
|
|
348
|
+
const result = {
|
|
349
|
+
...node,
|
|
350
|
+
component: get_component(node.type, node.component_class_id, root),
|
|
351
|
+
children: []
|
|
352
|
+
};
|
|
353
|
+
if (node.children) {
|
|
354
|
+
result.children = node.children.map((child) => handle_visibility(child, root));
|
|
355
|
+
}
|
|
356
|
+
return result;
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
return node;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function set_visibility_for_updated_node(node, id, visible) {
|
|
363
|
+
if (node.id == id) {
|
|
364
|
+
node.props.shared_props.visible = visible;
|
|
365
|
+
}
|
|
366
|
+
return node;
|
|
367
|
+
}
|
|
368
|
+
function _untrack(node, components_to_register) {
|
|
369
|
+
components_to_register.delete(node.id);
|
|
370
|
+
if (node.children) {
|
|
371
|
+
node.children.forEach((child) => _untrack(child, components_to_register));
|
|
372
|
+
}
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
function untrack_children_of_invisible_parents(node, root, components_to_register) {
|
|
376
|
+
// Check if the node is visible
|
|
377
|
+
if (node.props.shared_props.visible !== true) {
|
|
378
|
+
_untrack(node, components_to_register);
|
|
379
|
+
}
|
|
380
|
+
return node;
|
|
381
|
+
}
|
|
382
|
+
function handle_empty_forms(node, root, components_to_register) {
|
|
383
|
+
// Check if the node is visible
|
|
384
|
+
if (node.type === "form") {
|
|
385
|
+
const all_children_invisible = node.children.every((child) => child.props.shared_props.visible === false);
|
|
386
|
+
if (all_children_invisible) {
|
|
387
|
+
node.props.shared_props.visible = false;
|
|
388
|
+
components_to_register.delete(node.id);
|
|
389
|
+
return node;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return node;
|
|
393
|
+
}
|
|
394
|
+
function translate_props(node, root) {
|
|
395
|
+
const supported_props = [
|
|
396
|
+
"description",
|
|
397
|
+
"info",
|
|
398
|
+
"title",
|
|
399
|
+
"placeholder",
|
|
400
|
+
"value",
|
|
401
|
+
"label"
|
|
402
|
+
];
|
|
403
|
+
for (const attr of Object.keys(node.props.shared_props)) {
|
|
404
|
+
if (supported_props.includes(attr)) {
|
|
405
|
+
// @ts-ignore
|
|
406
|
+
node.props.shared_props[attr] = translate_if_needed(node.props.shared_props[attr]);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
for (const attr of Object.keys(node.props.props)) {
|
|
410
|
+
if (supported_props.includes(attr)) {
|
|
411
|
+
node.props.props[attr] = translate_if_needed(node.props.props[attr]);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return node;
|
|
415
|
+
}
|
|
416
|
+
function apply_initial_tabs(node, root, initial_tabs) {
|
|
417
|
+
if (node.type === "tabs" && node.id in initial_tabs) {
|
|
418
|
+
const tabs = initial_tabs[node.id].sort((a, b) => a.order - b.order);
|
|
419
|
+
node.props.props.initial_tabs = tabs;
|
|
420
|
+
}
|
|
421
|
+
return node;
|
|
422
|
+
}
|
|
423
|
+
function _gather_initial_tabs(node, initial_tabs, parent_tab_id, order) {
|
|
424
|
+
if (parent_tab_id !== null && node.type === "tabitem") {
|
|
425
|
+
if (!(parent_tab_id in initial_tabs)) {
|
|
426
|
+
initial_tabs[parent_tab_id] = [];
|
|
427
|
+
}
|
|
428
|
+
if (!("id" in node.props.props)) {
|
|
429
|
+
node.props.props.id = node.id;
|
|
430
|
+
}
|
|
431
|
+
initial_tabs[parent_tab_id].push({
|
|
432
|
+
label: node.props.shared_props.label,
|
|
433
|
+
id: node.props.props.id,
|
|
434
|
+
elem_id: node.props.shared_props.elem_id,
|
|
435
|
+
visible: node.props.shared_props.visible,
|
|
436
|
+
interactive: node.props.shared_props.interactive,
|
|
437
|
+
scale: node.props.shared_props.scale || null
|
|
438
|
+
});
|
|
439
|
+
node.props.props.order = order;
|
|
440
|
+
}
|
|
441
|
+
if (node.children) {
|
|
442
|
+
node.children.forEach((child, i) => {
|
|
443
|
+
_gather_initial_tabs(child, initial_tabs, node.type === "tabs" ? node.id : null, node.type === "tabs" ? i : null);
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
function gather_initial_tabs(node, initial_tabs) {
|
|
449
|
+
function single_visit(node) {
|
|
450
|
+
if ("children" in node && node.children.length > 0) {
|
|
451
|
+
node.children?.forEach((child) => _gather_initial_tabs(child, initial_tabs, node.type === "tabs" ? node.id : null, null));
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return single_visit(node);
|
|
455
|
+
}
|
|
456
|
+
function find_node_by_id(tree, id) {
|
|
457
|
+
if (tree.id === id) {
|
|
458
|
+
return tree;
|
|
459
|
+
}
|
|
460
|
+
if (tree.children) {
|
|
461
|
+
for (const child of tree.children) {
|
|
462
|
+
const result = find_node_by_id(child, id);
|
|
463
|
+
if (result) {
|
|
464
|
+
return result;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Dependency, LoadingComponent } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Load a component given its type and class_id without awaiting it
|
|
4
|
+
* @param type
|
|
5
|
+
* @param class_id
|
|
6
|
+
* @param root
|
|
7
|
+
* @returns the loading component
|
|
8
|
+
*/
|
|
9
|
+
export declare function get_component(type: string, class_id: string, root: string, variant?: "component" | "example" | "base"): LoadingComponent;
|
|
10
|
+
/**
|
|
11
|
+
* Get all component ids that are an input dependency and all that are an output dependency
|
|
12
|
+
* @param dep the dependency
|
|
13
|
+
* @param inputs the set of inputs
|
|
14
|
+
* @param outputs the set of outputs
|
|
15
|
+
* @returns a tuple of the inputs and outputs
|
|
16
|
+
*/
|
|
17
|
+
export declare function get_inputs_outputs(dependencies: Dependency[]): [Set<number>, Set<number>];
|
|
18
|
+
/**
|
|
19
|
+
* Determines if a component is interactive
|
|
20
|
+
* explicitly set interactive prop takes precedence
|
|
21
|
+
* if not set, then if the component is an input to a dependency, it is interactive
|
|
22
|
+
* if not an input, but has no outputs and no default value, it is interactive (for dev)
|
|
23
|
+
* everything else is not interactive
|
|
24
|
+
* @param id component id
|
|
25
|
+
* @param interactive_prop value of the interactive prop
|
|
26
|
+
* @param value the main value of the component
|
|
27
|
+
* @param dependencies a tuple of sets of input and output component ids
|
|
28
|
+
* @returns if the component is interactive
|
|
29
|
+
*/
|
|
30
|
+
export declare function determine_interactivity(id: number, interactive_prop: boolean | undefined, value: any, dependencies: [Set<number>, Set<number>]): boolean;
|
|
31
|
+
/** An async version of 'new Function' */
|
|
32
|
+
export declare const AsyncFunction: new (...args: string[]) => (...args: any[]) => Promise<any>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { load_component } from "virtual:component-loader";
|
|
2
|
+
/**
|
|
3
|
+
* Load a component given its type and class_id without awaiting it
|
|
4
|
+
* @param type
|
|
5
|
+
* @param class_id
|
|
6
|
+
* @param root
|
|
7
|
+
* @returns the loading component
|
|
8
|
+
*/
|
|
9
|
+
export function get_component(type, class_id, root, variant = "component") {
|
|
10
|
+
if (type === "api")
|
|
11
|
+
type = "state";
|
|
12
|
+
return load_component({
|
|
13
|
+
api_url: root,
|
|
14
|
+
name: type,
|
|
15
|
+
id: class_id,
|
|
16
|
+
variant
|
|
17
|
+
}).component;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get all component ids that are an input dependency and all that are an output dependency
|
|
21
|
+
* @param dep the dependency
|
|
22
|
+
* @param inputs the set of inputs
|
|
23
|
+
* @param outputs the set of outputs
|
|
24
|
+
* @returns a tuple of the inputs and outputs
|
|
25
|
+
*/
|
|
26
|
+
export function get_inputs_outputs(dependencies) {
|
|
27
|
+
const inputs = new Set();
|
|
28
|
+
const outputs = new Set();
|
|
29
|
+
for (const dep of dependencies) {
|
|
30
|
+
dep.inputs.forEach((input) => inputs.add(input));
|
|
31
|
+
dep.outputs.forEach((output) => outputs.add(output));
|
|
32
|
+
}
|
|
33
|
+
return [inputs, outputs];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Determines if a component is interactive
|
|
37
|
+
* explicitly set interactive prop takes precedence
|
|
38
|
+
* if not set, then if the component is an input to a dependency, it is interactive
|
|
39
|
+
* if not an input, but has no outputs and no default value, it is interactive (for dev)
|
|
40
|
+
* everything else is not interactive
|
|
41
|
+
* @param id component id
|
|
42
|
+
* @param interactive_prop value of the interactive prop
|
|
43
|
+
* @param value the main value of the component
|
|
44
|
+
* @param dependencies a tuple of sets of input and output component ids
|
|
45
|
+
* @returns if the component is interactive
|
|
46
|
+
*/
|
|
47
|
+
export function determine_interactivity(id, interactive_prop, value, dependencies) {
|
|
48
|
+
const [inputs, outputs] = dependencies;
|
|
49
|
+
if (interactive_prop === false) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
else if (interactive_prop === true) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
else if (inputs.has(id) ||
|
|
56
|
+
(!outputs.has(id) && has_no_default_value(value))) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if a value is not a default value
|
|
63
|
+
* @param value the value to check
|
|
64
|
+
* @returns default value boolean
|
|
65
|
+
*/
|
|
66
|
+
function has_no_default_value(value) {
|
|
67
|
+
return ((Array.isArray(value) && value.length === 0) ||
|
|
68
|
+
value === "" ||
|
|
69
|
+
value === 0 ||
|
|
70
|
+
!value);
|
|
71
|
+
}
|
|
72
|
+
/** An async version of 'new Function' */
|
|
73
|
+
export const AsyncFunction = Object.getPrototypeOf(async function () { }).constructor;
|
package/dist/src/lang/en.json
CHANGED
|
@@ -36,7 +36,16 @@
|
|
|
36
36
|
"cancel": "Cancel",
|
|
37
37
|
"like": "Like",
|
|
38
38
|
"dislike": "Dislike",
|
|
39
|
-
"clear": "Clear"
|
|
39
|
+
"clear": "Clear",
|
|
40
|
+
"copy_message": "Copy message",
|
|
41
|
+
"copied_message": "Copied message"
|
|
42
|
+
},
|
|
43
|
+
"chat_interface": {
|
|
44
|
+
"new_chat": "New chat",
|
|
45
|
+
"message_placeholder": "Type a message...",
|
|
46
|
+
"additional_inputs": "Additional inputs",
|
|
47
|
+
"chatbot": "Chatbot",
|
|
48
|
+
"conversation": "Conversation"
|
|
40
49
|
},
|
|
41
50
|
"checkbox": {
|
|
42
51
|
"checkbox": "Checkbox",
|